diff --git a/sormas-api/pom.xml b/sormas-api/pom.xml index 87264eb1037..6bc0bb92ab1 100644 --- a/sormas-api/pom.xml +++ b/sormas-api/pom.xml @@ -2,7 +2,7 @@ de.symeda.sormas sormas-base - 0.2.0 + 0.3.0 ../sormas-base 4.0.0 diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java index e6333e3daa2..a54dba641ac 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/caze/CaseDataDto.java @@ -37,7 +37,6 @@ public class CaseDataDto extends CaseReferenceDto { public static final String INVESTIGATED_DATE = "investigatedDate"; public static final String SURVEILLANCE_OFFICER = "surveillanceOfficer"; public static final String CASE_OFFICER = "caseOfficer"; - public static final String CONTACT_OFFICER = "contactOfficer"; public static final String SYMPTOMS = "symptoms"; public static final String HOSPITALIZATION = "hospitalization"; public static final String EPI_DATA = "epiData"; @@ -77,7 +76,6 @@ public class CaseDataDto extends CaseReferenceDto { private UserReferenceDto surveillanceOfficer; private UserReferenceDto caseOfficer; - private UserReferenceDto contactOfficer; public CaseClassification getCaseClassification() { return caseClassification; @@ -159,14 +157,6 @@ public void setCaseOfficer(UserReferenceDto caseOfficer) { this.caseOfficer = caseOfficer; } - public UserReferenceDto getContactOfficer() { - return contactOfficer; - } - - public void setContactOfficer(UserReferenceDto contactOfficer) { - this.contactOfficer = contactOfficer; - } - public SymptomsDto getSymptoms() { return symptoms; } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java index 1757b355fc7..22a740c5397 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/contact/ContactFacade.java @@ -33,4 +33,6 @@ public interface ContactFacade { ContactReferenceDto getReferenceByUuid(String uuid); List getAllUuids(String userUuid); + + void generateContactFollowUpTasks(); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleDto.java index 702efc307be..ab81301d9d6 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleDto.java @@ -22,7 +22,6 @@ public class SampleDto extends SampleReferenceDto { public static final String SAMPLE_MATERIAL_TEXT = "sampleMaterialText"; public static final String LAB = "lab"; public static final String OTHER_LAB = "otherLab"; - public static final String SHIPMENT_STATUS = "shipmentStatus"; public static final String SHIPMENT_DATE = "shipmentDate"; public static final String SHIPMENT_DETAILS = "shipmentDetails"; public static final String RECEIVED_DATE = "receivedDate"; @@ -31,6 +30,9 @@ public class SampleDto extends SampleReferenceDto { public static final String COMMENT = "comment"; public static final String SAMPLE_SOURCE = "sampleSource"; public static final String SUGGESTED_TYPE_OF_TEST = "suggestedTypeOfTest"; + public static final String REFERRED_TO = "referredTo"; + public static final String SHIPPED = "shipped"; + public static final String RECEIVED = "received"; private CaseReferenceDto associatedCase; private String sampleCode; @@ -42,7 +44,6 @@ public class SampleDto extends SampleReferenceDto { private String sampleMaterialText; private FacilityReferenceDto lab; private FacilityReferenceDto otherLab; - private ShipmentStatus shipmentStatus; private Date shipmentDate; private String shipmentDetails; private Date receivedDate; @@ -51,6 +52,9 @@ public class SampleDto extends SampleReferenceDto { private String comment; private SampleSource sampleSource; private SampleTestType suggestedTypeOfTest; + private SampleReferenceDto referredTo; + private boolean shipped; + private boolean received; public CaseReferenceDto getAssociatedCase() { return associatedCase; @@ -112,12 +116,6 @@ public FacilityReferenceDto getOtherLab() { public void setOtherLab(FacilityReferenceDto otherLab) { this.otherLab = otherLab; } - public ShipmentStatus getShipmentStatus() { - return shipmentStatus; - } - public void setShipmentStatus(ShipmentStatus shipmentStatus) { - this.shipmentStatus = shipmentStatus; - } public Date getShipmentDate() { return shipmentDate; } @@ -166,5 +164,23 @@ public SampleTestType getSuggestedTypeOfTest() { public void setSuggestedTypeOfTest(SampleTestType suggestedTypeOfTest) { this.suggestedTypeOfTest = suggestedTypeOfTest; } + public SampleReferenceDto getReferredTo() { + return referredTo; + } + public void setReferredTo(SampleReferenceDto referredTo) { + this.referredTo = referredTo; + } + public boolean isShipped() { + return shipped; + } + public void setShipped(boolean shipped) { + this.shipped = shipped; + } + public boolean isReceived() { + return received; + } + public void setReceived(boolean received) { + this.received = received; + } } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleFacade.java b/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleFacade.java index 087cfa8cb1e..466ef778d38 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleFacade.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleFacade.java @@ -23,6 +23,8 @@ public interface SampleFacade { SampleDto saveSample(SampleDto dto); SampleReferenceDto getReferenceByUuid(String uuid); + + SampleReferenceDto getReferredFrom(String sampleUuid); List getAllUuids(String userUuid); diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleIndexDto.java b/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleIndexDto.java index 7c293314536..9ace5a03121 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleIndexDto.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/sample/SampleIndexDto.java @@ -18,7 +18,6 @@ public class SampleIndexDto extends SampleReferenceDto { public static final String DISEASE = "disease"; public static final String SAMPLE_CODE = "sampleCode"; public static final String LAB_SAMPLE_ID = "labSampleID"; - public static final String SHIPMENT_STATUS = "shipmentStatus"; public static final String LGA = "lga"; public static final String SHIPMENT_DATE = "shipmentDate"; public static final String RECEIVED_DATE = "receivedDate"; @@ -29,12 +28,14 @@ public class SampleIndexDto extends SampleReferenceDto { public static final String TEST_RESULT = "testResult"; public static final String SPECIMEN_CONDITION = "specimenCondition"; public static final String NO_TEST_POSSIBLE_REASON = "noTestPossibleReason"; + public static final String REFERRED_TO = "referredTo"; + public static final String SHIPPED = "shipped"; + public static final String RECEIVED = "received"; private CaseReferenceDto associatedCase; private Disease disease; private String sampleCode; private String labSampleID; - private ShipmentStatus shipmentStatus; private DistrictReferenceDto lga; private Date shipmentDate; private Date receivedDate; @@ -45,6 +46,9 @@ public class SampleIndexDto extends SampleReferenceDto { private SampleTestResultType testResult; private SpecimenCondition specimenCondition; private String noTestPossibleReason; + private SampleReferenceDto referredTo; + private boolean shipped; + private boolean received; public CaseReferenceDto getAssociatedCase() { return associatedCase; @@ -70,12 +74,6 @@ public String getLabSampleID() { public void setLabSampleID(String labSampleID) { this.labSampleID = labSampleID; } - public ShipmentStatus getShipmentStatus() { - return shipmentStatus; - } - public void setShipmentStatus(ShipmentStatus shipmentStatus) { - this.shipmentStatus = shipmentStatus; - } public DistrictReferenceDto getLga() { return lga; } @@ -135,6 +133,24 @@ public String getNoTestPossibleReason() { } public void setNoTestPossibleReason(String noTestPossibleReason) { this.noTestPossibleReason = noTestPossibleReason; + } + public SampleReferenceDto getReferredTo() { + return referredTo; + } + public void setReferredTo(SampleReferenceDto referredTo) { + this.referredTo = referredTo; + } + public boolean isShipped() { + return shipped; + } + public void setShipped(boolean shipped) { + this.shipped = shipped; + } + public boolean isReceived() { + return received; + } + public void setReceived(boolean received) { + this.received = received; } } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/sample/ShipmentStatus.java b/sormas-api/src/main/java/de/symeda/sormas/api/sample/ShipmentStatus.java deleted file mode 100644 index d3159c2cae4..00000000000 --- a/sormas-api/src/main/java/de/symeda/sormas/api/sample/ShipmentStatus.java +++ /dev/null @@ -1,17 +0,0 @@ -package de.symeda.sormas.api.sample; - -import de.symeda.sormas.api.I18nProperties; - -public enum ShipmentStatus { - - NOT_SHIPPED, - SHIPPED, - RECEIVED, - REFERRED_OTHER_LAB, - ; - - public String toString() { - return I18nProperties.getEnumCaption(this); - } - -} diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsHelper.java b/sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsHelper.java index 5da1c49436a..f77ae6e9240 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsHelper.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsHelper.java @@ -1,6 +1,7 @@ package de.symeda.sormas.api.symptoms; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; public final class SymptomsHelper { @@ -17,4 +18,32 @@ public static String getTemperatureString(float value) { return String.format("%.1f °C", value); } + public static void updateIsSymptomatic(SymptomsDto dto) { + if (dto == null) { + return; + } + + if (dto.getTemperature() != null && dto.getTemperature() >= 38.0f) { + dto.setSymptomatic(true); + return; + } + + List unconditionalSymptoms = Arrays.asList(dto.getFever(), dto.getVomiting(), dto.getDiarrhea(), dto.getBloodInStool(), + dto.getNausea(), dto.getAbdominalPain(), dto.getHeadache(), dto.getMusclePain(), dto.getFatigueWeakness(), dto.getSkinRash(), + dto.getNeckStiffness(), dto.getSoreThroat(), dto.getCough(), dto.getRunnyNose(), dto.getDifficultyBreathing(), + dto.getChestPain(), dto.getConfusedDisoriented(), dto.getSeizures(), dto.getAlteredConsciousness(), dto.getConjunctivitis(), + dto.getEyePainLightSensitive(), dto.getKopliksSpots(), dto.getThrobocytopenia(), dto.getOtitisMedia(), dto.getHearingloss(), + dto.getDehydration(), dto.getAnorexiaAppetiteLoss(), dto.getRefusalFeedorDrink(), dto.getJointPain(), dto.getShock(), + dto.getHiccups(), dto.getUnexplainedBleeding(), dto.getOtherNonHemorrhagicSymptoms()); + + for (SymptomState symptom : unconditionalSymptoms) { + if (symptom == SymptomState.YES) { + dto.setSymptomatic(true); + return; + } + } + + dto.setSymptomatic(false); + } + } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskHelper.java b/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskHelper.java index 7fd009d50e2..edde0fb1aad 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskHelper.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskHelper.java @@ -35,6 +35,8 @@ else if (UserRole.SURVEILLANCE_OFFICER.equals(userRole) } else if (UserRole.INFORMANT.equals(userRole)) { switch (currentStatus) { + case PENDING: + return Arrays.asList(TaskStatus.DONE, TaskStatus.NOT_EXECUTABLE); default: return Collections.emptyList(); } diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskType.java b/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskType.java index a3aaca5e45e..0d09cbd8fd6 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskType.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/task/TaskType.java @@ -16,6 +16,7 @@ public enum TaskType { CASE_MANAGEMENT(TaskContext.CASE), CASE_BURIAL(TaskContext.CASE), CONTACT_TRACING(TaskContext.CASE), + SAMPLE_COLLECTION(TaskContext.CASE), CONTACT_INVESTIGATION(TaskContext.CONTACT), CONTACT_FOLLOW_UP(TaskContext.CONTACT), ANIMAL_TESTING(TaskContext.EVENT), diff --git a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRole.java b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRole.java index 6963db7de87..140e010a40e 100644 --- a/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRole.java +++ b/sormas-api/src/main/java/de/symeda/sormas/api/user/UserRole.java @@ -24,6 +24,19 @@ public enum UserRole { LAB_USER(false, false), ; + public static final String _SYSTEM = "SYSTEM"; + public static final String _USER = "USER"; + public static final String _ADMIN = "ADMIN"; + public static final String _SURVEILLANCE_SUPERVISOR = "SURVEILLANCE_SUPERVISOR"; + public static final String _SURVEILLANCE_OFFICER = "SURVEILLANCE_OFFICER"; + public static final String _INFORMANT = "INFORMANT"; + public static final String _CASE_SUPERVISOR = "CASE_SUPERVISOR"; + public static final String _CASE_OFFICER = "CASE_OFFICER"; + public static final String _CONTACT_SUPERVISOR = "CONTACT_SUPERVISOR"; + public static final String _CONTACT_OFFICER = "CONTACT_OFFICER"; + public static final String _RUMOR_MANAGER = "RUMOR_MANAGER"; + public static final String _LAB_USER = "LAB_USER"; + private final boolean supervisor; private final boolean officer; diff --git a/sormas-api/src/main/resources/enum.properties b/sormas-api/src/main/resources/enum.properties index 744822692bb..9a146137116 100644 --- a/sormas-api/src/main/resources/enum.properties +++ b/sormas-api/src/main/resources/enum.properties @@ -176,6 +176,7 @@ TaskType.ANIMAL_DEPOPULATION = depopulation of animals TaskType.OTHER = other task as described in comments TaskType.DAILY_REPORT_GENERATION = generate daily report TaskType.SURVEILLANCE_REPORT_GENERATION = generate surveillance report +TaskType.SAMPLE_COLLECTION = sample collection TemperatureSource.AXILLARY=axillary TemperatureSource.ORAL=oral diff --git a/sormas-api/src/main/resources/fieldCaptions.properties b/sormas-api/src/main/resources/fieldCaptions.properties index b2b97e43edc..904c0e6297c 100644 --- a/sormas-api/src/main/resources/fieldCaptions.properties +++ b/sormas-api/src/main/resources/fieldCaptions.properties @@ -16,8 +16,9 @@ CaseData.healthFacilityDetails=Health facility name & description CaseData.facilityDetails=Health facility name & description CaseData.reportingUser=Reporting user CaseData.reportDate=Date of report +CaseData.reportInfoLoc = Report date & user CaseData.investigatedDate=Date of investigation -CaseData.surveillanceOfficer = Surveillance officer +CaseData.surveillanceOfficer = Responsible surveillance officer CaseData.caseOfficer = Case officer CaseData.contactOfficer = Contact officer CaseData.region = State @@ -39,7 +40,6 @@ CaseData.measlesDoses = How many doses CaseData.vaccinationInfoSource = Source of vaccination information CaseData.measlesVaccinationInfoSource = Source of vaccination information CaseData.epiData = Epidemiological data -CaseData.reportInfoLoc = Report date & user CaseData.epidNumber = EPID number # captions for caseData-tabs @@ -369,7 +369,6 @@ Sample.sampleMaterial = Sample material Sample.sampleMaterialText = Specify other material Sample.shipmentDate = Date of shipment Sample.shipmentDetails = Shipment details -Sample.shipmentStatus = Shipment status Sample.lab = Laboratory Sample.otherLab = Referral laboratory Sample.lga = LGA @@ -395,6 +394,8 @@ Sample.testResult = Test result Sample.comment = Comment Sample.sampleSource = Sample source Sample.suggestedTypeOfTest = Suggested type of test +Sample.shipped = Shipped +Sample.received = Received SampleTest = Sample test SampleTest.testType = Type of test diff --git a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/TestEntityCreator.java b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/TestEntityCreator.java index bdf9c5d90f0..b4fcb279e07 100644 --- a/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/TestEntityCreator.java +++ b/sormas-app/app/src/androidTest/java/de/symeda/sormas/app/TestEntityCreator.java @@ -1,7 +1,5 @@ package de.symeda.sormas.app; -import android.provider.ContactsContract; - import java.util.Date; import de.symeda.sormas.api.Disease; @@ -13,7 +11,6 @@ import de.symeda.sormas.api.sample.SampleTestResultType; import de.symeda.sormas.api.sample.SampleTestType; import de.symeda.sormas.api.utils.DateHelper; -import de.symeda.sormas.api.utils.YesNoUnknown; import de.symeda.sormas.app.backend.caze.Case; import de.symeda.sormas.app.backend.common.DaoException; import de.symeda.sormas.app.backend.common.DatabaseHelper; @@ -43,7 +40,7 @@ public class TestEntityCreator { public static Person createPerson(String firstName, String lastName) { - Person person = DatabaseHelper.getPersonDao().create(); + Person person = DatabaseHelper.getPersonDao().build(); person.setFirstName(firstName); person.setLastName(lastName); @@ -66,7 +63,7 @@ public static Case createCase() { CaseClassification caseClassification = CaseClassification.SUSPECT; InvestigationStatus investigationStatus = InvestigationStatus.PENDING; - Case caze = DatabaseHelper.getCaseDao().create(createPerson("Salomon", "Kalou")); + Case caze = DatabaseHelper.getCaseDao().build(createPerson("Salomon", "Kalou")); caze.setDisease(disease); caze.setRegion(region); caze.setDistrict(district); @@ -89,7 +86,7 @@ public static Contact createContact() { Person person = createPerson("Thierry", "Henry"); Case caze = createCase(); - Contact contact = DatabaseHelper.getContactDao().create(); + Contact contact = DatabaseHelper.getContactDao().build(); contact.setPerson(person); contact.setCaze(caze); @@ -112,7 +109,7 @@ public static Event createEvent() { String srcLastName = "Mpenza"; String srcTelNo = "0150123123123"; - Event event = DatabaseHelper.getEventDao().create(); + Event event = DatabaseHelper.getEventDao().build(); event.setEventType(eventType); event.setEventDesc(eventDesc); event.setEventDate(eventDate); @@ -137,7 +134,7 @@ public static Sample createSample() { Facility lab = DatabaseHelper.getFacilityDao().queryForAll().get(0); SampleMaterial material = SampleMaterial.BLOOD; - Sample sample = DatabaseHelper.getSampleDao().create(caze); + Sample sample = DatabaseHelper.getSampleDao().build(caze); sample.setSampleDateTime(sampleDateTime); sample.setLab(lab); sample.setSampleMaterial(material); @@ -153,7 +150,7 @@ public static Sample createSample() { } public static PreviousHospitalization createPreviousHospitalization(Case caze) { - PreviousHospitalization prevHosp = DatabaseHelper.getPreviousHospitalizationDao().create(); + PreviousHospitalization prevHosp = DatabaseHelper.getPreviousHospitalizationDao().build(); prevHosp.setHospitalization(caze.getHospitalization()); try { @@ -167,7 +164,7 @@ public static PreviousHospitalization createPreviousHospitalization(Case caze) { } public static EpiDataBurial createEpiDataBurial(Case caze) { - EpiDataBurial burial = DatabaseHelper.getEpiDataBurialDao().create(); + EpiDataBurial burial = DatabaseHelper.getEpiDataBurialDao().build(); burial.setEpiData(caze.getEpiData()); try { @@ -181,7 +178,7 @@ public static EpiDataBurial createEpiDataBurial(Case caze) { } public static EpiDataGathering createEpiDataGathering(Case caze) { - EpiDataGathering gathering = DatabaseHelper.getEpiDataGatheringDao().create(); + EpiDataGathering gathering = DatabaseHelper.getEpiDataGatheringDao().build(); gathering.setEpiData(caze.getEpiData()); try { @@ -195,7 +192,7 @@ public static EpiDataGathering createEpiDataGathering(Case caze) { } public static EpiDataTravel createEpiDataTravel(Case caze) { - EpiDataTravel travel = DatabaseHelper.getEpiDataTravelDao().create(); + EpiDataTravel travel = DatabaseHelper.getEpiDataTravelDao().build(); travel.setEpiData(caze.getEpiData()); try { @@ -209,9 +206,9 @@ public static EpiDataTravel createEpiDataTravel(Case caze) { } public static Visit createVisit(Contact contact) throws DaoException { - Visit visit = DatabaseHelper.getVisitDao().create(contact.getUuid()); - Symptoms symptoms = DatabaseHelper.getSymptomsDao().create(); - Location illLocation = DatabaseHelper.getLocationDao().create(); + Visit visit = DatabaseHelper.getVisitDao().build(contact.getUuid()); + Symptoms symptoms = DatabaseHelper.getSymptomsDao().build(); + Location illLocation = DatabaseHelper.getLocationDao().build(); symptoms.setIllLocation(illLocation); visit.setSymptoms(symptoms); visit.setVisitUser(ConfigProvider.getUser()); @@ -225,7 +222,7 @@ public static Visit createVisit(Contact contact) throws DaoException { public static EventParticipant createEventParticipant(Event event) { Person person = createPerson("Demba", "Ba"); - EventParticipant eventParticipant = DatabaseHelper.getEventParticipantDao().create(); + EventParticipant eventParticipant = DatabaseHelper.getEventParticipantDao().build(); eventParticipant.setEvent(event); eventParticipant.setPerson(person); @@ -244,7 +241,7 @@ public static SampleTest createSampleTest(Sample sample) { SampleTestResultType sampleTestResultType = SampleTestResultType.NEGATIVE; Date sampleTestDateTime = new Date(); - SampleTest sampleTest = DatabaseHelper.getSampleTestDao().create(); + SampleTest sampleTest = DatabaseHelper.getSampleTestDao().build(); sampleTest.setSample(sample); sampleTest.setTestType(sampleTestType); sampleTest.setTestResult(sampleTestResultType); diff --git a/sormas-app/app/src/main/AndroidManifest.xml b/sormas-app/app/src/main/AndroidManifest.xml index cc476ac18ea..39d4d875b6f 100644 --- a/sormas-app/app/src/main/AndroidManifest.xml +++ b/sormas-app/app/src/main/AndroidManifest.xml @@ -18,6 +18,7 @@ android:launchMode="singleTop"> @@ -27,6 +28,7 @@ @@ -36,9 +38,11 @@ @@ -47,6 +51,7 @@ @@ -55,6 +60,7 @@ android:launchMode="singleTop" /> @@ -68,6 +74,7 @@ android:launchMode="singleTop" /> @@ -77,6 +84,7 @@ @@ -86,6 +94,7 @@ @@ -98,6 +107,7 @@ android:launchMode="singleTop" /> @@ -107,6 +117,7 @@ @@ -124,6 +136,7 @@ @@ -137,6 +150,7 @@ android:launchMode="singleTop" /> diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/AbstractTabActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/AbstractTabActivity.java index 8a028910f7a..27ab10f9a73 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/AbstractTabActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/AbstractTabActivity.java @@ -17,12 +17,15 @@ import java.net.ConnectException; +import de.symeda.sormas.app.backend.common.AbstractDomainObject; import de.symeda.sormas.app.backend.common.DatabaseHelper; import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.backend.synclog.SyncLogDao; +import de.symeda.sormas.app.caze.CaseEditTabs; import de.symeda.sormas.app.component.SyncLogDialog; import de.symeda.sormas.app.rest.RetroProvider; import de.symeda.sormas.app.rest.SynchronizeDataAsync; +import de.symeda.sormas.app.util.FormTab; import de.symeda.sormas.app.util.SlidingTabLayout; import de.symeda.sormas.app.util.SyncCallback; @@ -68,6 +71,23 @@ public void onPageSelected(int position) { }); } + + public AbstractDomainObject getData(int position) { + FormTab tab = getTabByPosition(position); + if (tab != null) { + return tab.getData(); + } + return null; + } + + public FormTab getTabByPosition(int position) { + Object item = pager.getAdapter().instantiateItem(pager, position); + if (item instanceof FormTab) { + return (FormTab)item; + } + return null; + } + public void setCurrentTab(int currentTab) { this.currentTab = currentTab; } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/Case.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/Case.java index 3ec05959e97..e18fd010082 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/Case.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/Case.java @@ -94,8 +94,6 @@ public class Case extends AbstractDomainObject { private User surveillanceOfficer; @DatabaseField(foreign = true, foreignAutoRefresh = true, maxForeignAutoRefreshLevel = 1) private User caseOfficer; - @DatabaseField(foreign = true, foreignAutoRefresh = true, maxForeignAutoRefreshLevel = 1) - private User contactOfficer; @Enumerated(EnumType.STRING) private YesNoUnknown pregnant; @@ -118,6 +116,9 @@ public class Case extends AbstractDomainObject { @DatabaseField(foreign = true, foreignAutoRefresh = true) private EpiData epiData; + @Column + private Long contactOfficer_id; + public Person getPerson() { return person; } @@ -223,13 +224,6 @@ public void setCaseOfficer(User caseOfficer) { this.caseOfficer = caseOfficer; } - public User getContactOfficer() { - return contactOfficer; - } - public void setContactOfficer(User contactOfficer) { - this.contactOfficer = contactOfficer; - } - public InvestigationStatus getInvestigationStatus() { return investigationStatus; } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseDao.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseDao.java index a0c2f8a2656..2c1306864d3 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseDao.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/caze/CaseDao.java @@ -23,15 +23,10 @@ import de.symeda.sormas.app.backend.common.DaoException; import de.symeda.sormas.app.backend.common.DatabaseHelper; import de.symeda.sormas.app.backend.config.ConfigProvider; -import de.symeda.sormas.app.backend.epidata.EpiData; -import de.symeda.sormas.app.backend.hospitalization.Hospitalization; -import de.symeda.sormas.app.backend.location.Location; import de.symeda.sormas.app.backend.person.Person; import de.symeda.sormas.app.backend.symptoms.Symptoms; import de.symeda.sormas.app.backend.user.User; -import de.symeda.sormas.app.backend.visit.Visit; import de.symeda.sormas.app.caze.CaseEditActivity; -import de.symeda.sormas.app.util.DataUtils; public class CaseDao extends AbstractAdoDao { @@ -73,7 +68,7 @@ public Date getLatestChangeDate() { return date; } - // TODO #69 create some date filter for finding the right case (this is implemented in CaseService.java too) + // TODO #69 build some date filter for finding the right case (this is implemented in CaseService.java too) public Case getByPersonAndDisease(Person person, Disease disease) { try { QueryBuilder builder = queryBuilder(); @@ -91,25 +86,25 @@ public Case getByPersonAndDisease(Person person, Disease disease) { } @Override - public Case create() { - throw new UnsupportedOperationException("Use create(Person) instead"); + public Case build() { + throw new UnsupportedOperationException("Use build(Person) instead"); } - public Case create(Person person) { - Case caze = super.create(); + public Case build(Person person) { + Case caze = super.build(); caze.setPerson(person); caze.setReportDate(new Date()); caze.setReportingUser(ConfigProvider.getUser()); // Symptoms - caze.setSymptoms(DatabaseHelper.getSymptomsDao().create()); + caze.setSymptoms(DatabaseHelper.getSymptomsDao().build()); // Hospitalization - caze.setHospitalization(DatabaseHelper.getHospitalizationDao().create()); + caze.setHospitalization(DatabaseHelper.getHospitalizationDao().build()); // Epi Data - caze.setEpiData(DatabaseHelper.getEpiDataDao().create()); + caze.setEpiData(DatabaseHelper.getEpiDataDao().build()); // Location User currentUser = ConfigProvider.getUser(); @@ -162,4 +157,5 @@ public Case mergeOrCreate(Case source) throws DaoException { } return mergedCase; } + } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/AbstractAdoDao.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/AbstractAdoDao.java index 00f2715ceee..d0f98eb7c63 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/AbstractAdoDao.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/AbstractAdoDao.java @@ -186,7 +186,7 @@ public ADO saveAndSnapshot(ADO ado) throws DaoException { ADO snapshot; boolean snapshotNeeded = ado.getId() != null && !ado.isModified(); if (snapshotNeeded) { - // we need to create a snapshot of the unmodified version, so we can use it for comparison when merging + // we need to build a snapshot of the unmodified version, so we can use it for comparison when merging snapshot = queryForId(ado.getId()); snapshot.setId(null); snapshot.setSnapshot(true); @@ -233,7 +233,7 @@ public ADO saveAndSnapshot(ADO ado) throws DaoException { } if (ado.getId() == null) { - // create the new entity and take note that it has been create in the app (modified) + // build the new entity and take note that it has been build in the app (modified) ado.setModified(true); create(ado); } @@ -259,7 +259,7 @@ public ADO saveAndSnapshot(ADO ado) throws DaoException { ado.setModified(true); update(ado); - // now really create the cloneCascading + // now really build the cloneCascading create(snapshot); } } @@ -326,7 +326,7 @@ public ADO deleteWithSnapshot(ADO ado) throws DaoException { ADO snapshot; boolean snapshotNeeded = !ado.isModified(); if (snapshotNeeded) { - // we need to create a cloneCascading of the unmodified version, so we can use it for comparison when merging + // we need to build a cloneCascading of the unmodified version, so we can use it for comparison when merging snapshot = queryForId(ado.getId()); snapshot.setId(null); snapshot.setSnapshot(true); @@ -772,7 +772,7 @@ public int updateWithCast(AbstractDomainObject ado) { return update((ADO)ado); } - public ADO create() { + public ADO build() { try { ADO ado = getAdoClass().newInstance(); ado.setUuid(DataHelper.createUuid()); @@ -780,7 +780,7 @@ public ADO create() { ado.setCreationDate(now); ado.setChangeDate(now); - // create all embedded entities + // build all embedded entities // ignore parent property EmbeddedAdo annotation = ado.getClass().getAnnotation(EmbeddedAdo.class); @@ -794,8 +794,8 @@ public ADO create() { if (parentProperty.equals(property.getName())) continue; - // create embedded - AbstractDomainObject embeddedAdo = DatabaseHelper.getAdoDao((Class)property.getPropertyType()).create(); + // build embedded + AbstractDomainObject embeddedAdo = DatabaseHelper.getAdoDao((Class)property.getPropertyType()).build(); if (embeddedAdo == null) { throw new IllegalArgumentException("No embedded entity was created for " + property.getName()); @@ -891,6 +891,19 @@ public List queryForEq(String fieldName, Object value) { } } + public List queryForNotNull(String fieldName) { + try { + QueryBuilder builder = queryBuilder(); + Where where = builder.where(); + where.isNotNull(fieldName); + where.and().eq(AbstractDomainObject.SNAPSHOT, false).query(); + return builder.query(); + } catch (SQLException e) { + Log.e(getTableName(), "queryForNotNull threw exception on: " + fieldName, e); + throw new RuntimeException(e); + } + } + /** * @see Dao#queryBuilder() */ @@ -905,7 +918,7 @@ public int create(ADO data) { try { return dao.create(data); } catch (SQLException e) { - Log.e(getTableName(), "create threw exception on: " + data, e); + Log.e(getTableName(), "build threw exception on: " + data, e); throw new RuntimeException(e); } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java index 58879ccdcf9..8eb734fe924 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/common/DatabaseHelper.java @@ -72,7 +72,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { // name of the database file for your application -- change to something appropriate for your app private static final String DATABASE_NAME = "sormas.db"; // any time you make changes to your database objects, you may have to increase the database version - private static final int DATABASE_VERSION = 93; + private static final int DATABASE_VERSION = 97; private static DatabaseHelper instance = null; public static void init(Context context) { @@ -146,7 +146,7 @@ public static void clearTables(boolean clearInfrastructure) { } /** - * This is called when the database is first created. Usually you should call createTable statements here to create + * This is called when the database is first created. Usually you should call createTable statements here to build * the tables that will store your data. */ @Override @@ -178,7 +178,7 @@ public void onCreate(SQLiteDatabase db, ConnectionSource connectionSource) { TableUtils.createTable(connectionSource, EpiDataTravel.class); TableUtils.createTable(connectionSource, SyncLog.class); } catch (SQLException e) { - Log.e(DatabaseHelper.class.getName(), "Can't create database", e); + Log.e(DatabaseHelper.class.getName(), "Can't build database", e); throw new RuntimeException(e); } } @@ -206,6 +206,24 @@ public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int case 92: currentVersion = 92; getDao(District.class).executeRaw("ALTER TABLE region ADD COLUMN epidCode varchar(255);"); + case 93: + currentVersion = 93; + getDao(Symptoms.class).executeRaw("ALTER TABLE symptoms ADD COLUMN symptomatic boolean;"); + case 94: + currentVersion = 94; + // nothing + case 95: + currentVersion = 95; + getDao(Sample.class).executeRaw("ALTER TABLE samples ADD COLUMN referredTo_id bigint REFERENCES samples(id);"); + case 96: + currentVersion = 96; + getDao(Sample.class).executeRaw("ALTER TABLE samples ADD COLUMN shipped boolean;"); + getDao(Sample.class).executeRaw("ALTER TABLE samples ADD COLUMN received boolean;"); + getDao(Sample.class).executeRaw("UPDATE samples SET shipped='true' WHERE shipmentStatus = 'SHIPPED' OR shipmentStatus = 'RECEIVED' OR shipmentStatus = 'REFERRED_OTHER_LAB';"); + getDao(Sample.class).executeRaw("UPDATE samples SET received='true' WHERE shipmentStatus = 'RECEIVED' OR shipmentStatus = 'REFERRED_OTHER_LAB';"); + getDao(Sample.class).executeRaw("UPDATE samples SET shipped='false' WHERE shipmentStatus = 'NOT_SHIPPED';"); + getDao(Sample.class).executeRaw("UPDATE samples SET received='false' WHERE shipmentStatus = 'NOT_SHIPPED' OR shipmentStatus = 'SHIPPED';"); + // ATTENTION: break should only be done after last version break; @@ -248,7 +266,7 @@ private void upgradeFromUnupgradableVersion(SQLiteDatabase db, ConnectionSource if (oldVersion < 30) { TableUtils.dropTable(connectionSource, Config.class, true); } - // after we drop the old databases, we create the new ones + // after we drop the old databases, we build the new ones onCreate(db, connectionSource); } catch (SQLException e) { Log.e(DatabaseHelper.class.getName(), "Can't drop databases", e); @@ -260,7 +278,7 @@ public AbstractAdoDao getAdoDaoInner(Cla if (!adoDaos.containsKey(type)) { - // create dao + // build dao AbstractAdoDao dao; Dao innerDao; @@ -318,7 +336,7 @@ public AbstractAdoDao getAdoDaoInner(Cla adoDaos.put(type, dao); } catch (SQLException e) { - Log.e(DatabaseHelper.class.getName(), "Can't create dao", e); + Log.e(DatabaseHelper.class.getName(), "Can't build dao", e); throw new RuntimeException(e); } } @@ -343,7 +361,7 @@ public static ConfigDao getConfigDao() { try { instance.configDao = new ConfigDao((Dao) instance.getDao(Config.class)); } catch (SQLException e) { - Log.e(DatabaseHelper.class.getName(), "Can't create ConfigDao", e); + Log.e(DatabaseHelper.class.getName(), "Can't build ConfigDao", e); throw new RuntimeException(e); } } @@ -359,7 +377,7 @@ public static SyncLogDao getSyncLogDao() { try { instance.syncLogDao = new SyncLogDao((Dao) instance.getDao(SyncLog.class)); } catch (SQLException e) { - Log.e(DatabaseHelper.class.getName(), "Can't create SyncLogDao", e); + Log.e(DatabaseHelper.class.getName(), "Can't build SyncLogDao", e); throw new RuntimeException(e); } } @@ -456,7 +474,6 @@ public static EpiDataTravelDao getEpiDataTravelDao() { return (EpiDataTravelDao) getAdoDao(EpiDataTravel.class); } - /** * Close the database connections and clear any cached DAOs. */ diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/ContactDao.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/ContactDao.java index 100ebfba3b8..64434dde807 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/ContactDao.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/contact/ContactDao.java @@ -14,12 +14,6 @@ import de.symeda.sormas.app.backend.common.AbstractDomainObject; import de.symeda.sormas.app.backend.common.DatabaseHelper; import de.symeda.sormas.app.backend.config.ConfigProvider; -import de.symeda.sormas.app.backend.event.Event; -import de.symeda.sormas.app.backend.person.Person; -import de.symeda.sormas.app.backend.region.District; -import de.symeda.sormas.app.backend.region.Region; - -import static android.R.attr.value; /** * Created by Stefan Szczesny on 29.11.2016. @@ -59,9 +53,9 @@ public List getByCase(Case caze) { } @Override - public Contact create() { + public Contact build() { - Contact contact = super.create(); + Contact contact = super.build(); contact.setReportDateTime(new Date()); contact.setReportingUser(ConfigProvider.getUser()); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/EventDao.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/EventDao.java index e394fffe971..799586f0fb9 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/EventDao.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/event/EventDao.java @@ -7,12 +7,8 @@ import de.symeda.sormas.api.event.EventStatus; import de.symeda.sormas.app.backend.common.AbstractAdoDao; -import de.symeda.sormas.app.backend.common.DaoException; -import de.symeda.sormas.app.backend.common.DatabaseHelper; import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.backend.location.Location; -import de.symeda.sormas.app.backend.person.Person; -import de.symeda.sormas.app.util.DataUtils; public class EventDao extends AbstractAdoDao { @@ -46,9 +42,9 @@ public Date getLatestChangeDate() { } @Override - public Event create() { + public Event build() { - Event event = super.create(); + Event event = super.build(); event.setReportDateTime(new Date()); event.setReportingUser(ConfigProvider.getUser()); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/sample/Sample.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/sample/Sample.java index 4f7bc45d3ff..c5a38c7ba5b 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/sample/Sample.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/sample/Sample.java @@ -14,9 +14,7 @@ import de.symeda.sormas.api.sample.SampleMaterial; import de.symeda.sormas.api.sample.SampleSource; import de.symeda.sormas.api.sample.SampleTestType; -import de.symeda.sormas.api.sample.ShipmentStatus; import de.symeda.sormas.api.sample.SpecimenCondition; -import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.app.backend.caze.Case; import de.symeda.sormas.app.backend.common.AbstractDomainObject; @@ -36,9 +34,11 @@ public class Sample extends AbstractDomainObject { public static final String TABLE_NAME = "samples"; public static final String I18N_PREFIX = "Sample"; - public static final String SHIPMENT_STATUS = "shipmentStatus"; public static final String SAMPLE_DATE_TIME = "sampleDateTime"; public static final String ASSOCIATED_CASE = "associatedCase"; + public static final String REFERRED_TO = "referredTo"; + public static final String SHIPPED = "shipped"; + public static final String RECEIVED = "received"; @DatabaseField(foreign = true, foreignAutoRefresh = true, canBeNull = false) private Case associatedCase; @@ -71,10 +71,6 @@ public class Sample extends AbstractDomainObject { @DatabaseField(foreign = true, foreignAutoRefresh = true, maxForeignAutoRefreshLevel = 3) private Facility otherLab; - @Enumerated(EnumType.STRING) - @Column(nullable = false) - private ShipmentStatus shipmentStatus; - @DatabaseField(dataType = DataType.DATE_LONG) private Date shipmentDate; @@ -99,6 +95,18 @@ public class Sample extends AbstractDomainObject { @Enumerated(EnumType.STRING) private SampleTestType suggestedTypeOfTest; + @DatabaseField(foreign = true, foreignAutoRefresh = true) + private Sample referredTo; + + @DatabaseField + private boolean shipped; + + @DatabaseField + private boolean received; + + @DatabaseField(defaultValue = "", canBeNull = false) + private String shipmentStatus; + public Case getAssociatedCase() { return associatedCase; } @@ -179,14 +187,6 @@ public void setOtherLab(Facility otherLab) { this.otherLab = otherLab; } - public ShipmentStatus getShipmentStatus() { - return shipmentStatus; - } - - public void setShipmentStatus(ShipmentStatus shipmentStatus) { - this.shipmentStatus = shipmentStatus; - } - public Date getShipmentDate() { return shipmentDate; } @@ -251,6 +251,30 @@ public void setSuggestedTypeOfTest(SampleTestType suggestedTypeOfTest) { this.suggestedTypeOfTest = suggestedTypeOfTest; } + public Sample getReferredTo() { + return referredTo; + } + + public void setReferredTo(Sample referredTo) { + this.referredTo = referredTo; + } + + public boolean isShipped() { + return shipped; + } + + public void setShipped(boolean shipped) { + this.shipped = shipped; + } + + public boolean isReceived() { + return received; + } + + public void setReceived(boolean received) { + this.received = received; + } + @Override public String getI18nPrefix() { return I18N_PREFIX; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/sample/SampleDao.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/sample/SampleDao.java index 0aadbffb9f6..84578dcf651 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/sample/SampleDao.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/sample/SampleDao.java @@ -1,21 +1,15 @@ package de.symeda.sormas.app.backend.sample; import com.j256.ormlite.dao.Dao; -import com.j256.ormlite.dao.RuntimeExceptionDao; -import com.j256.ormlite.logger.Log; -import com.j256.ormlite.logger.Logger; -import com.j256.ormlite.logger.LoggerFactory; import java.sql.SQLException; import java.util.Date; import java.util.List; -import de.symeda.sormas.api.sample.ShipmentStatus; import de.symeda.sormas.app.backend.caze.Case; import de.symeda.sormas.app.backend.common.AbstractAdoDao; import de.symeda.sormas.app.backend.common.AbstractDomainObject; import de.symeda.sormas.app.backend.config.ConfigProvider; -import de.symeda.sormas.app.util.DataUtils; /** * Created by Mate Strysewske on 06.02.2017. @@ -33,16 +27,15 @@ protected Class getAdoClass() { } @Override - public Sample create() { + public Sample build() { throw new UnsupportedOperationException(); } - public Sample create(Case associatedCase) { - Sample sample = super.create(); + public Sample build(Case associatedCase) { + Sample sample = super.build(); sample.setAssociatedCase(associatedCase); sample.setReportDateTime(new Date()); sample.setReportingUser(ConfigProvider.getUser()); - sample.setShipmentStatus(ShipmentStatus.NOT_SHIPPED); return sample; } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/sample/SampleDtoHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/sample/SampleDtoHelper.java index 2b389e74e6c..21be1bc694b 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/sample/SampleDtoHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/sample/SampleDtoHelper.java @@ -57,7 +57,6 @@ public void fillInnerFromDto(Sample target, SampleDto source) { target.setSampleDateTime(source.getSampleDateTime()); target.setSampleMaterial(source.getSampleMaterial()); target.setSampleMaterialText(source.getSampleMaterialText()); - target.setShipmentStatus(source.getShipmentStatus()); target.setShipmentDate(source.getShipmentDate()); target.setShipmentDetails(source.getShipmentDetails()); target.setReceivedDate(source.getReceivedDate()); @@ -66,6 +65,9 @@ public void fillInnerFromDto(Sample target, SampleDto source) { target.setComment(source.getComment()); target.setSampleSource(source.getSampleSource()); target.setSuggestedTypeOfTest(source.getSuggestedTypeOfTest()); + target.setReferredTo(DatabaseHelper.getSampleDao().getByReferenceDto(source.getReferredTo())); + target.setShipped(source.isShipped()); + target.setReceived(source.isReceived()); } @Override @@ -98,13 +100,19 @@ public void fillInnerFromAdo(SampleDto dto, Sample ado) { dto.setOtherLab(null); } + if (ado.getReferredTo() != null) { + Sample referredSample = DatabaseHelper.getSampleDao().queryForId(ado.getReferredTo().getId()); + dto.setReferredTo(SampleDtoHelper.toReferenceDto(referredSample)); + } else { + dto.setReferredTo(null); + } + dto.setSampleCode(ado.getSampleCode()); dto.setLabSampleID(ado.getLabSampleID()); dto.setSampleDateTime(ado.getSampleDateTime()); dto.setReportDateTime(ado.getReportDateTime()); dto.setSampleMaterial(ado.getSampleMaterial()); dto.setSampleMaterialText(ado.getSampleMaterialText()); - dto.setShipmentStatus(ado.getShipmentStatus()); dto.setShipmentDate(ado.getShipmentDate()); dto.setShipmentDetails(ado.getShipmentDetails()); dto.setReceivedDate(ado.getReceivedDate()); @@ -113,6 +121,8 @@ public void fillInnerFromAdo(SampleDto dto, Sample ado) { dto.setComment(ado.getComment()); dto.setSampleSource(ado.getSampleSource()); dto.setSuggestedTypeOfTest(ado.getSuggestedTypeOfTest()); + dto.setShipped(ado.isShipped()); + dto.setReceived(ado.isReceived()); } public static SampleReferenceDto toReferenceDto(Sample ado) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/symptoms/Symptoms.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/symptoms/Symptoms.java index 2b0ae89473f..28bcd4adcd3 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/symptoms/Symptoms.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/symptoms/Symptoms.java @@ -33,6 +33,7 @@ public class Symptoms extends AbstractDomainObject { private String onsetSymptom; @Column(length = 255) private String symptomsComments; + @DatabaseField private Boolean symptomatic; @DatabaseField(foreign = true, foreignAutoRefresh = true, maxForeignAutoRefreshLevel = 2) diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/symptoms/SymptomsDao.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/symptoms/SymptomsDao.java index 05f5c17f459..f50390e81b2 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/symptoms/SymptomsDao.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/symptoms/SymptomsDao.java @@ -4,6 +4,8 @@ import java.sql.SQLException; +import de.symeda.sormas.api.symptoms.SymptomsDto; +import de.symeda.sormas.api.symptoms.SymptomsHelper; import de.symeda.sormas.app.backend.common.AbstractAdoDao; import de.symeda.sormas.app.backend.common.DaoException; import de.symeda.sormas.app.backend.common.DatabaseHelper; @@ -26,4 +28,24 @@ protected Class getAdoClass() { public String getTableName() { return Symptoms.TABLE_NAME; } + + public void updateIsSymptomatic(Symptoms symptoms) { + SymptomsDtoHelper symptomsDtoHelper = new SymptomsDtoHelper(); + SymptomsDto symptomsDto = new SymptomsDto(); + symptomsDtoHelper.fillInnerFromAdo(symptomsDto, symptoms); + SymptomsHelper.updateIsSymptomatic(symptomsDto); + symptoms.setSymptomatic(symptomsDto.getSymptomatic()); + } + + @Override + public Symptoms saveAndSnapshot(Symptoms symptoms) throws DaoException { + // If new symptoms are created, updateIsSymptomatic has to be called after the initial save + if (symptoms.getId() == null) { + super.saveAndSnapshot(symptoms); + updateIsSymptomatic(symptoms); + } + + return super.saveAndSnapshot(symptoms); + } + } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/synclog/SyncLogDao.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/synclog/SyncLogDao.java index 851ee2d959c..748d13cc49b 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/synclog/SyncLogDao.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/synclog/SyncLogDao.java @@ -88,7 +88,7 @@ public int create(SyncLog data) { try { return dao.create(data); } catch (SQLException e) { - Log.e(getClass().getName(), "create threw exception on: " + data, e); + Log.e(getClass().getName(), "build threw exception on: " + data, e); throw new RuntimeException(e); } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/visit/Visit.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/visit/Visit.java index 566665bcd9f..67b2871d1f4 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/visit/Visit.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/visit/Visit.java @@ -101,7 +101,7 @@ public void setVisitRemarks(String visitRemarks) { } /** - * return the symptoms, if null create new in service layer + * return the symptoms, if null build new in service layer * @return */ public Symptoms getSymptoms() { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/visit/VisitDao.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/visit/VisitDao.java index 5da8a3ca246..2c7446828f4 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/visit/VisitDao.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/backend/visit/VisitDao.java @@ -85,7 +85,7 @@ public Date getLatestChangeDate() { } @Override - public Visit create() { + public Visit build() { throw new UnsupportedOperationException(); } @@ -97,9 +97,9 @@ public Visit create() { * @throws InstantiationException */ @NonNull - public Visit create(String contactUuid) { + public Visit build(String contactUuid) { Contact contact = DatabaseHelper.getContactDao().queryUuid(contactUuid); - Visit visit = super.create(); + Visit visit = super.build(); visit.setPerson(contact.getPerson()); visit.setDisease(contact.getCaze().getDisease()); visit.setVisitDateTime(new Date()); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditActivity.java index 88b8be0af7f..108ea29a67a 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditActivity.java @@ -116,6 +116,7 @@ protected void onResume() { Case currentEntity = DatabaseHelper.getCaseDao().queryUuid(caseUuid); if (currentEntity.isUnreadOrChildUnread()) { // Resetting the adapter will reload the form and therefore also override any unsaved changes + DatabaseHelper.getCaseDao().markAsRead(currentEntity); setAdapter(); final Snackbar snackbar = Snackbar.make(findViewById(R.id.base_layout), String.format(getResources().getString(R.string.snackbar_entity_overridden), getResources().getString(R.string.entity_case)), Snackbar.LENGTH_INDEFINITE); @@ -127,8 +128,6 @@ public void onClick(View view) { }); snackbar.show(); } - - DatabaseHelper.getCaseDao().markAsRead(currentEntity); } @Override @@ -199,7 +198,7 @@ public boolean onPrepareOptionsMenu(Menu menu) { public boolean onOptionsItemSelected(MenuItem item) { setCurrentTab(pager.getCurrentItem()); CaseEditTabs tab = CaseEditTabs.values()[currentTab]; - Case caze = (Case) adapter.getData(CaseEditTabs.CASE_DATA.ordinal()); + Case caze = (Case) getData(CaseEditTabs.CASE_DATA.ordinal()); CaseDao caseDao = DatabaseHelper.getCaseDao(); switch (item.getItemId()) { // Respond to the action bar's Up/Home button @@ -285,26 +284,27 @@ public boolean onOptionsItemSelected(MenuItem item) { // PATIENT LocationDao locLocationDao = DatabaseHelper.getLocationDao(); PersonDao personDao = DatabaseHelper.getPersonDao(); - Person person = (Person) adapter.getData(CaseEditTabs.PATIENT.ordinal()); + Person person = (Person) getData(CaseEditTabs.PATIENT.ordinal()); // SYMPTOMS - Symptoms symptoms = (Symptoms) adapter.getData(CaseEditTabs.SYMPTOMS.ordinal()); - SymptomsEditForm symptomsEditForm = (SymptomsEditForm) adapter.getTabByPosition(CaseEditTabs.SYMPTOMS.ordinal()); + Symptoms symptoms = (Symptoms) getData(CaseEditTabs.SYMPTOMS.ordinal()); // HOSPITALIZATION - Hospitalization hospitalization = (Hospitalization) adapter.getData(CaseEditTabs.HOSPITALIZATION.ordinal()); + Hospitalization hospitalization = (Hospitalization) getData(CaseEditTabs.HOSPITALIZATION.ordinal()); // EPI DATA - EpiData epiData = (EpiData) adapter.getData(CaseEditTabs.EPIDATA.ordinal()); + EpiData epiData = (EpiData) getData(CaseEditTabs.EPIDATA.ordinal()); // CASE_DATA - caze = (Case) adapter.getData(CaseEditTabs.CASE_DATA.ordinal()); + caze = (Case) getData(CaseEditTabs.CASE_DATA.ordinal()); // Validations have to be processed from last tab to first to make sure that the user will be re-directed // to the first tab with a validation error - CaseDataFragmentLayoutBinding caseDataBinding = ((CaseEditDataForm)adapter.getTabByPosition(CaseEditTabs.CASE_DATA.ordinal())).getBinding(); - PersonEditFragmentLayoutBinding personBinding = ((PersonEditForm)adapter.getTabByPosition(CaseEditTabs.PATIENT.ordinal())).getBinding(); - CaseSymptomsFragmentLayoutBinding symptomsBinding = ((SymptomsEditForm)adapter.getTabByPosition(CaseEditTabs.SYMPTOMS.ordinal())).getBinding(); + + + CaseDataFragmentLayoutBinding caseDataBinding = ((CaseEditDataForm)getTabByPosition(CaseEditTabs.CASE_DATA.ordinal())).getBinding(); + PersonEditFragmentLayoutBinding personBinding = ((PersonEditForm)getTabByPosition(CaseEditTabs.PATIENT.ordinal())).getBinding(); + CaseSymptomsFragmentLayoutBinding symptomsBinding = ((SymptomsEditForm)getTabByPosition(CaseEditTabs.SYMPTOMS.ordinal())).getBinding(); // Necessary because the entry could've been automatically set, in which case the setValue method of the // custom field has not been called diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditDataForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditDataForm.java index 48763bbed47..495c1175356 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditDataForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditDataForm.java @@ -53,7 +53,7 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, final String caseUuid = (String) getArguments().getString(Case.UUID); final CaseDao caseDao = DatabaseHelper.getCaseDao(); - final Case caze = caseDao.queryUuid(caseUuid); + Case caze = caseDao.queryUuid(caseUuid); binding.setCaze(caze); final List emptyList = new ArrayList<>(); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditPagerAdapter.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditPagerAdapter.java index 0d44b376720..721ecdabdac 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditPagerAdapter.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseEditPagerAdapter.java @@ -27,14 +27,7 @@ public class CaseEditPagerAdapter extends FragmentStatePagerAdapter { - private CharSequence titles[]; // This will Store the titles of the Tabs which are Going to be passed when ViewPagerAdapter is created private Bundle caseEditBundle; // this bundle contains the uuids - private CaseEditDataForm caseEditDataForm; - private PersonEditForm personEditForm; - private SymptomsEditForm symptomsEditForm; - private HospitalizationForm hospitalizationForm; - private EpiDataForm epiDataForm; - // Build a Constructor and assign the passed Values to appropriate values in the class public CaseEditPagerAdapter(FragmentManager fm, String caseUuid) { @@ -43,7 +36,7 @@ public CaseEditPagerAdapter(FragmentManager fm, String caseUuid) { caseEditBundle.putString(Case.UUID, caseUuid); } - //This method return the fragment for the every position in the View Pager + // This method return the fragment for the every position in the View Pager @Override public Fragment getItem(int position) { Fragment frag = null; @@ -51,31 +44,26 @@ public Fragment getItem(int position) { Case caze = null; switch (tab) { case CASE_DATA: - caseEditDataForm = new CaseEditDataForm(); - caseEditDataForm.setArguments(caseEditBundle); - frag = caseEditDataForm; + frag = new CaseEditDataForm(); + frag.setArguments(caseEditBundle); break; case PATIENT: - personEditForm = new PersonEditForm(); + frag = new PersonEditForm(); Bundle personEditBundle = new Bundle(); caze = DatabaseHelper.getCaseDao().queryUuid(caseEditBundle.getString(Case.UUID)); personEditBundle.putString(Person.UUID, caze.getPerson().getUuid()); personEditBundle.putSerializable(Case.DISEASE, caze.getDisease()); - - personEditForm.setArguments(personEditBundle); - frag = personEditForm; + frag.setArguments(personEditBundle); break; case SYMPTOMS: - symptomsEditForm = new SymptomsEditForm(); + frag = new SymptomsEditForm(); Bundle symptomsEditBundle = new Bundle(); caze = DatabaseHelper.getCaseDao().queryUuid(caseEditBundle.getString(Case.UUID)); symptomsEditBundle.putString(Symptoms.UUID, caze.getSymptoms().getUuid()); symptomsEditBundle.putSerializable(Case.DISEASE, caze.getDisease()); - - symptomsEditForm.setArguments(symptomsEditBundle); - frag = symptomsEditForm; + frag.setArguments(symptomsEditBundle); break; case CONTACTS: ContactsListFragment contactsListTab = new ContactsListFragment(); @@ -97,26 +85,22 @@ public Fragment getItem(int position) { frag = samplesListTab; break; case HOSPITALIZATION: - hospitalizationForm = new HospitalizationForm(); + frag = new HospitalizationForm(); Bundle hospitalizationBundle = new Bundle(); caze = DatabaseHelper.getCaseDao().queryUuid(caseEditBundle.getString(Case.UUID)); hospitalizationBundle.putString(HospitalizationForm.KEY_CASE_UUID, caze.getUuid()); hospitalizationBundle.putString(Hospitalization.UUID, caze.getHospitalization().getUuid()); - - hospitalizationForm.setArguments(hospitalizationBundle); - frag = hospitalizationForm; + frag.setArguments(hospitalizationBundle); break; case EPIDATA: - epiDataForm = new EpiDataForm(); + frag = new EpiDataForm(); Bundle epiDataBundle = new Bundle(); caze = DatabaseHelper.getCaseDao().queryUuid(caseEditBundle.getString(Case.UUID)); epiDataBundle.putSerializable(Case.DISEASE, caze.getDisease()); epiDataBundle.putString(EpiData.UUID, caze.getEpiData().getUuid()); - - epiDataForm.setArguments(epiDataBundle); - frag = epiDataForm; + frag.setArguments(epiDataBundle); break; } return frag; @@ -133,38 +117,4 @@ public CharSequence getPageTitle(int position) { public int getCount() { return CaseEditTabs.values().length; } - - public AbstractDomainObject getData(int position) { - CaseEditTabs tab = CaseEditTabs.fromInt(position); - switch (tab) { - case CASE_DATA: - return caseEditDataForm.getData(); - case PATIENT: - return personEditForm.getData(); - case HOSPITALIZATION: - return hospitalizationForm.getData(); - case SYMPTOMS: - return symptomsEditForm.getData(); - case EPIDATA: - return epiDataForm.getData(); - } - return null; - } - - public FormTab getTabByPosition(int position) { - CaseEditTabs tab = CaseEditTabs.fromInt(position); - switch (tab) { - case CASE_DATA: - return caseEditDataForm; - case PATIENT: - return personEditForm; - case HOSPITALIZATION: - return hospitalizationForm; - case SYMPTOMS: - return symptomsEditForm; - case EPIDATA: - return epiDataForm; - } - return null; - } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseNewActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseNewActivity.java index 05e0f863e25..c4429c98b02 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseNewActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseNewActivity.java @@ -147,7 +147,7 @@ public void accept(Object parameter) { caze.setPerson((Person) parameter); savePersonAndCase(caze); } catch (DaoException e) { - Log.e(getClass().getName(), "Error while trying to create case", e); + Log.e(getClass().getName(), "Error while trying to build case", e); Snackbar.make(findViewById(R.id.fragment_frame), String.format(getResources().getString(R.string.snackbar_create_error), getResources().getString(R.string.entity_case)), Snackbar.LENGTH_LONG).show(); ErrorReportingHelper.sendCaughtException(tracker, e, null, true); } @@ -162,7 +162,7 @@ public void accept(Object parameter) { } } } catch (DaoException e) { - Log.e(getClass().getName(), "Error while trying to create case", e); + Log.e(getClass().getName(), "Error while trying to build case", e); Snackbar.make(findViewById(R.id.fragment_frame), String.format(getResources().getString(R.string.snackbar_create_error), getResources().getString(R.string.entity_case)), Snackbar.LENGTH_LONG).show(); ErrorReportingHelper.sendCaughtException(tracker, e, null, true); } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseNewForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseNewForm.java index fb3fee442aa..a61e6432b73 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseNewForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CaseNewForm.java @@ -44,9 +44,9 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, person = (Person) arguments.get(CaseNewActivity.PERSON); disease = (Disease) arguments.get(CaseNewActivity.DISEASE); } else { - person = DatabaseHelper.getPersonDao().create(); + person = DatabaseHelper.getPersonDao().build(); } - caze = DatabaseHelper.getCaseDao().create(person); + caze = DatabaseHelper.getCaseDao().build(person); binding = DataBindingUtil.inflate(inflater, R.layout.case_new_fragment_layout, container, false); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CasesListArrayAdapter.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CasesListArrayAdapter.java index 1e8d72262de..40a706dca8e 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CasesListArrayAdapter.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CasesListArrayAdapter.java @@ -65,9 +65,8 @@ public View getView(int position, View convertView, ViewGroup parent) { TextView caseStatus = (TextView) convertView.findViewById(R.id.cli_case_satus); if (!(ConfigProvider.getUser().getUserRole() == UserRole.INFORMANT && caze.getCaseClassification() == CaseClassification.NOT_CLASSIFIED)) { caseStatus.setText(caze.getCaseClassification() != null ? caze.getCaseClassification().toString() : null); - caseStatus.setVisibility(View.VISIBLE); } else { - caseStatus.setVisibility(View.GONE); + caseStatus.setText(""); } TextView person = (TextView) convertView.findViewById(R.id.cli_person); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CasesListFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CasesListFragment.java index d7df64567d3..bbff17298b1 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CasesListFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/CasesListFragment.java @@ -3,7 +3,6 @@ import android.content.Intent; import android.os.Bundle; -import android.support.design.widget.Snackbar; import android.support.v4.app.ListFragment; import android.support.v4.widget.SwipeRefreshLayout; import android.view.LayoutInflater; @@ -15,14 +14,11 @@ import java.util.List; import de.symeda.sormas.api.caze.InvestigationStatus; -import de.symeda.sormas.app.AbstractRootTabActivity; import de.symeda.sormas.app.AbstractTabActivity; import de.symeda.sormas.app.R; import de.symeda.sormas.app.backend.caze.Case; import de.symeda.sormas.app.backend.common.DatabaseHelper; -import de.symeda.sormas.app.rest.RetroProvider; import de.symeda.sormas.app.rest.SynchronizeDataAsync; -import de.symeda.sormas.app.util.SyncCallback; /** * Created by Martin on 13.08.2016. @@ -55,8 +51,8 @@ public void onResume() { listAdapter.addAll(cases); if (listAdapter.getCount() == 0) { - this.getView().findViewById(R.id.empty_list_hint).setVisibility(View.VISIBLE); this.getView().findViewById(android.R.id.list).setVisibility(View.GONE); + this.getView().findViewById(R.id.empty_list_hint).setVisibility(View.VISIBLE); } else { this.getView().findViewById(R.id.empty_list_hint).setVisibility(View.GONE); this.getView().findViewById(android.R.id.list).setVisibility(View.VISIBLE); @@ -79,7 +75,7 @@ public void onActivityCreated(Bundle savedInstanceState) { CasesListArrayAdapter adapter = new CasesListArrayAdapter( this.getActivity(), // Context for the activity. - R.layout.cases_list_item); // Layout to use (create) + R.layout.cases_list_item); // Layout to use (build) setListAdapter(adapter); getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/SymptomsEditForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/SymptomsEditForm.java index 6039d7a5b54..10fa0b8f04d 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/SymptomsEditForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/caze/SymptomsEditForm.java @@ -3,14 +3,14 @@ import android.databinding.DataBindingUtil; import android.os.Bundle; import android.support.annotation.Nullable; +import android.text.format.DateUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.ViewTreeObserver; import android.widget.ArrayAdapter; import android.widget.Button; -import com.google.android.gms.analytics.Tracker; - import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -22,11 +22,9 @@ import de.symeda.sormas.api.symptoms.TemperatureSource; import de.symeda.sormas.api.utils.Diseases; import de.symeda.sormas.app.R; -import de.symeda.sormas.app.SormasApplication; import de.symeda.sormas.app.backend.caze.Case; import de.symeda.sormas.app.backend.common.AbstractDomainObject; import de.symeda.sormas.app.backend.common.DatabaseHelper; -import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.backend.location.Location; import de.symeda.sormas.app.backend.symptoms.Symptoms; import de.symeda.sormas.app.component.FieldHelper; @@ -36,10 +34,8 @@ import de.symeda.sormas.app.databinding.CaseSymptomsFragmentLayoutBinding; import de.symeda.sormas.app.util.Consumer; import de.symeda.sormas.app.util.DataUtils; -import de.symeda.sormas.app.util.ErrorReportingHelper; import de.symeda.sormas.app.util.FormTab; import de.symeda.sormas.app.util.Item; -import de.symeda.sormas.app.util.ValidationFailedException; import de.symeda.sormas.app.validation.SymptomsValidator; @@ -53,11 +49,13 @@ public class SymptomsEditForm extends FormTab { public static final String NEW_SYMPTOMS = "newSymptoms"; public static final String FOR_VISIT = "forVisit"; public static final String VISIT_COOPERATIVE = "visitCooperative"; + private CaseSymptomsFragmentLayoutBinding binding; private List nonConditionalSymptoms; private List conditionalBleedingSymptoms; - private boolean listenersForRequiredCalled; + private boolean forVisit; + private boolean visitCooperative; @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { @@ -68,9 +66,9 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, final Disease disease = (Disease) getArguments().getSerializable(Case.DISEASE); - // create a new visit from contact data + // build a new visit from contact data if(getArguments().getBoolean(NEW_SYMPTOMS)) { - symptoms = DatabaseHelper.getSymptomsDao().create(); + symptoms = DatabaseHelper.getSymptomsDao().build(); } // open the given visit else { @@ -78,6 +76,13 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, symptoms = DatabaseHelper.getSymptomsDao().queryUuid(symptomsUuid); } + if (getArguments().getBoolean(FOR_VISIT)) { + forVisit = true; + if (getArguments().getBoolean(VISIT_COOPERATIVE)) { + visitCooperative = true; + } + } + binding.setSymptoms(symptoms); binding.symptomsOnsetDate.initialize(this); @@ -97,18 +102,33 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Override public void onChange(PropertyField field) { toggleUnexplainedBleedingFields(); + if (forVisit) { + SymptomsValidator.setRequiredHintsForVisitSymptoms(visitCooperative, binding); + } else { + SymptomsValidator.setRequiredHintsForCaseSymptoms(binding); + } } }); binding.symptomsOtherHemorrhagicSymptoms.addValueChangedListener(new PropertyField.ValueChangeListener() { @Override public void onChange(PropertyField field) { visibilityOtherHemorrhagicSymptoms(); + if (forVisit) { + SymptomsValidator.setRequiredHintsForVisitSymptoms(visitCooperative, binding); + } else { + SymptomsValidator.setRequiredHintsForCaseSymptoms(binding); + } } }); binding.symptomsOtherNonHemorrhagicSymptoms.addValueChangedListener(new PropertyField.ValueChangeListener() { @Override public void onChange(PropertyField field) { visibilityOtherNonHemorrhagicSymptoms(); + if (forVisit) { + SymptomsValidator.setRequiredHintsForVisitSymptoms(visitCooperative, binding); + } else { + SymptomsValidator.setRequiredHintsForCaseSymptoms(binding); + } } }); @@ -134,9 +154,7 @@ public void onChange(PropertyField field) { binding.symptomsDigestedBloodVomit, binding.symptomsCoughingBlood, binding.symptomsBleedingVagina, binding.symptomsSkinBruising1, binding.symptomsBloodUrine, binding.symptomsOtherHemorrhagicSymptoms); - List onsetSymptoms = new ArrayList<>(); - onsetSymptoms.add(new Item("",null)); - FieldHelper.initOnsetSymptomSpinnerField(binding.symptomsOnsetSymptom1, onsetSymptoms); + FieldHelper.initSpinnerField(binding.symptomsOnsetSymptom1, DataUtils.toItems(null, true)); addListenerForOnsetSymptom(); Button clearAllBtn = binding.symptomsClearAll; @@ -149,6 +167,12 @@ public void onClick(View v) { for (SymptomStateField symptom : conditionalBleedingSymptoms) { symptom.setValue(null); } + + if (forVisit) { + SymptomsValidator.setRequiredHintsForVisitSymptoms(visitCooperative, binding); + } else { + SymptomsValidator.setRequiredHintsForCaseSymptoms(binding); + } } }); @@ -166,10 +190,16 @@ public void onClick(View v) { symptom.setValue(SymptomState.NO); } } + + if (forVisit) { + SymptomsValidator.setRequiredHintsForVisitSymptoms(visitCooperative, binding); + } else { + SymptomsValidator.setRequiredHintsForCaseSymptoms(binding); + } } }); - if (!getArguments().getBoolean(FOR_VISIT)) { + if (!forVisit) { binding.symptomsIllLocationLayout.setVisibility(View.VISIBLE); // ==================== IllLocation =============== LocationDialog.addLocationField(getActivity(), symptoms.getIllLocation(), binding.symptomsIllLocation, binding.formCpBtnAddress, new Consumer() { @@ -184,9 +214,34 @@ public void accept(Object parameter) { binding.symptomsIllLocationFrom.initialize(this); binding.symptomsIllLocationTo.initialize(this); + SymptomsValidator.setRequiredHintsForCaseSymptoms(binding); } else { binding.symptomsIllLocationLayout.setVisibility(View.GONE); + SymptomsValidator.setRequiredHintsForVisitSymptoms(visitCooperative, binding); } + + // Add listeners to symptom state fields; OnWindowFocusChangeListener is used to make sure that these + // listeners aren't called when the view is being built. + binding.caseSymptomsForm.getViewTreeObserver().addOnWindowFocusChangeListener( + new ViewTreeObserver.OnWindowFocusChangeListener() { + @Override + public void onWindowFocusChanged(boolean b) { + binding.caseSymptomsForm.getViewTreeObserver().removeOnWindowFocusChangeListener(this); + for (SymptomStateField symptom : nonConditionalSymptoms) { + symptom.addValueChangedListener(new PropertyField.ValueChangeListener() { + @Override + public void onChange(PropertyField field) { + if (forVisit) { + SymptomsValidator.setRequiredHintsForVisitSymptoms(visitCooperative, binding); + } else { + SymptomsValidator.setRequiredHintsForCaseSymptoms(binding); + } + } + }); + } + } + }); + //view.requestFocus(); return view; } @@ -262,21 +317,15 @@ private void addListenerForOnsetSymptom() { symptom.addValueChangedListener(new PropertyField.ValueChangeListener() { @Override public void onChange(PropertyField field) { + Item item = new Item(field.getCaption(), field.getCaption()); + int position = binding.symptomsOnsetSymptom1.getPositionOf(item); if (field.getValue() == SymptomState.YES) { - Item item = new Item(field.getCaption(), field.getCaption()); - // Workaround for Android bug (see https://issuetracker.google.com/issues/36910520) - // Only continue when the item is not in the list yet, otherwise it will be added again - // when calling clearAll - if (binding.symptomsOnsetSymptom1.getPositionOf(item) == -1) { - adapter.remove(adapter.getItem(adapter.getCount())); + if (position == -1) { adapter.add(item); - adapter.add(new Item("Select entry", null)); } } else { - Item item = new Item(field.getCaption(), field.getCaption()); - if (binding.symptomsOnsetSymptom1.getPositionOf(item) != -1) { - adapter.remove((Item) binding.symptomsOnsetSymptom1.getItemAtPosition( - binding.symptomsOnsetSymptom1.getPositionOf(new Item(field.getCaption(), field.getCaption())))); + if (position != -1) { + adapter.remove(adapter.getItem(position)); } } } @@ -287,21 +336,15 @@ public void onChange(PropertyField field) { symptom.addValueChangedListener(new PropertyField.ValueChangeListener() { @Override public void onChange(PropertyField field) { + Item item = new Item(field.getCaption(), field.getCaption()); + int position = binding.symptomsOnsetSymptom1.getPositionOf(item); if (field.getValue() == SymptomState.YES) { - Item item = new Item(field.getCaption(), field.getCaption()); - // Workaround for Android bug (see https://issuetracker.google.com/issues/36910520) - // Only continue when the item is not in the list yet, otherwise it will be added again - // when calling clearAll - if (binding.symptomsOnsetSymptom1.getPositionOf(item) == -1) { - adapter.remove(adapter.getItem(adapter.getCount())); + if (position == -1) { adapter.add(item); - adapter.add(new Item("Select entry", null)); } } else { - Item item = new Item(field.getCaption(), field.getCaption()); - if (binding.symptomsOnsetSymptom1.getPositionOf(item) != -1) { - adapter.remove((Item) binding.symptomsOnsetSymptom1.getItemAtPosition( - binding.symptomsOnsetSymptom1.getPositionOf(new Item(field.getCaption(), field.getCaption())))); + if (position != -1) { + adapter.remove(adapter.getItem(position)); } } } @@ -318,4 +361,9 @@ public CaseSymptomsFragmentLayoutBinding getBinding() { return binding; } + public void changeVisitCooperative(boolean cooperative) { + visitCooperative = cooperative; + SymptomsValidator.setRequiredHintsForVisitSymptoms(visitCooperative, binding); + } + } \ No newline at end of file diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/component/CheckBoxField.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/component/CheckBoxField.java new file mode 100644 index 00000000000..26254efda90 --- /dev/null +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/component/CheckBoxField.java @@ -0,0 +1,104 @@ +package de.symeda.sormas.app.component; + +import android.content.Context; +import android.databinding.BindingAdapter; +import android.databinding.InverseBindingAdapter; +import android.databinding.InverseBindingListener; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.CheckBox; +import android.widget.CompoundButton; + +import de.symeda.sormas.app.R; + +/** + * Created by Mate Strysewske on 10.08.2017. + */ +public class CheckBoxField extends PropertyField { + + protected CheckBox checkBox; + protected InverseBindingListener inverseBindingListener; + private CompoundButton.OnCheckedChangeListener additionalListener; + + public CheckBoxField(Context context) { + super(context); + initializeViews(context); + } + + public CheckBoxField(Context context, AttributeSet attrs) { + super(context, attrs); + initializeViews(context); + } + + public CheckBoxField(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + initializeViews(context); + } + + @Override + public void setValue(Boolean value) { + checkBox.setChecked(value); + } + + @Override + public Boolean getValue() { + return checkBox.isChecked(); + } + + @BindingAdapter("android:value") + public static void setValue(CheckBoxField view, boolean value) { + view.setValue(value); + } + + @InverseBindingAdapter(attribute = "android:value", event = "android:valueAttrChanged") + public static boolean getValue(CheckBoxField view) { + return view.getValue(); + } + + @BindingAdapter("android:valueAttrChanged") + public static void setListener(CheckBoxField view, InverseBindingListener listener) { + view.inverseBindingListener = listener; + } + + private void initializeViews(Context context) { + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + inflater.inflate(R.layout.field_checkbox_field, this); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + checkBox = (CheckBox) this.findViewById(R.id.check_box); + checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean b) { + if (inverseBindingListener != null) { + inverseBindingListener.onChange(); + } + onValueChanged(); + + if (additionalListener != null) { + additionalListener.onCheckedChanged(compoundButton, b); + } + } + }); + checkBox.setText(getCaption()); + } + + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + checkBox.setEnabled(enabled); + } + + @Override + protected void requestFocusForContentView(View nextView) { + ((CheckBoxField) nextView).checkBox.requestFocus(); + } + + public void setAdditionalListener(CompoundButton.OnCheckedChangeListener additionalListener) { + this.additionalListener = additionalListener; + } +} diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/component/FieldHelper.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/component/FieldHelper.java index 9e62b3da833..727e6dbabb7 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/component/FieldHelper.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/component/FieldHelper.java @@ -40,16 +40,6 @@ public static SpinnerField initSpinnerField(SpinnerField spinnerField, List items) { - spinnerField.initializeForOnsetSymptom(items); - return spinnerField; - } - - public static SpinnerField initMonthSpinnerField(SpinnerField spinnerField, List items, final AdapterView.OnItemSelectedListener ...moreListeners) { - spinnerField.initializeForMonth(items, moreListeners); - return spinnerField; - } - public static SpinnerField initRegionSpinnerField(SpinnerField spinnerField, final AdapterView.OnItemSelectedListener ...moreListeners) { RegionDao regionDao = DatabaseHelper.getRegionDao(); List items = DataUtils.toItems(regionDao.queryForAll(Region.NAME, true)); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/component/PropertyField.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/component/PropertyField.java index d8fc4e1d1b0..94b6f062709 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/component/PropertyField.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/component/PropertyField.java @@ -46,8 +46,8 @@ public String getDescription() { } public void setError(String errorText) { - caption.requestFocus(); caption.setError(errorText); + caption.requestFocus(); } public void setErrorWithoutFocus(String errorText) { @@ -84,21 +84,32 @@ public void addValueChangedListener(ValueChangeListener listener) { } public void addCaptionOnClickListener() { + caption.setOnFocusChangeListener(new OnFocusChangeListener() { + @Override + public void onFocusChange(View view, boolean b) { + if (caption != null && b) { + if (caption.getError() == null && getDescription() != null && !getDescription().isEmpty()) { + HelpDialog helpDialog = new HelpDialog(getContext()); + helpDialog.setMessage(getDescription()); + helpDialog.show(); + } + } + } + }); + caption.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (caption != null) { - if (getDescription() != null && !getDescription().isEmpty()) { - HelpDialog helpDialog = new HelpDialog(getContext()); - helpDialog.setMessage(getDescription()); - helpDialog.show(); - } - } - if (caption.getError() != null) { caption.clearFocus(); + } else if (getDescription() != null && !getDescription().isEmpty()) { + HelpDialog helpDialog = new HelpDialog(getContext()); + helpDialog.setMessage(getDescription()); + helpDialog.show(); } } + } }); // if(getDescription() != null && !getDescription().isEmpty()) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/component/RadioGroupField.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/component/RadioGroupField.java index 952b1ad1f0a..3d694f42904 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/component/RadioGroupField.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/component/RadioGroupField.java @@ -23,7 +23,7 @@ * Created by Mate Strysewske on 07.12.2016. */ -public class RadioGroupField extends PropertyField { +public class RadioGroupField extends PropertyField { public static final String SHOW_CAPTION = "showCaption"; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/component/SelectOrCreatePersonDialogBuilder.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/component/SelectOrCreatePersonDialogBuilder.java index 9930d0be7b0..7e569bf8417 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/component/SelectOrCreatePersonDialogBuilder.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/component/SelectOrCreatePersonDialogBuilder.java @@ -130,7 +130,7 @@ public void onClick(View v) { } }); - // create a new person with the entered details (displays an error if the details are incomplete) + // build a new person with the entered details (displays an error if the details are incomplete) dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/component/SpinnerField.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/component/SpinnerField.java index f2cfcdbbc71..2b803aeded8 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/component/SpinnerField.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/component/SpinnerField.java @@ -8,6 +8,7 @@ import android.databinding.InverseBindingListener; import android.graphics.Color; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.text.Editable; import android.text.TextWatcher; import android.util.AttributeSet; @@ -101,18 +102,6 @@ public void registerListener(OnItemSelectedListener listener) { spinnerFieldListener.registerListener(listener); } - public Spinner getSpinnerElement() { - return spinnerElement; - } - -// public void setOnItemSelectedListener(OnItemSelectedListener listener) { -// spinnerElement.setOnItemSelectedListener(listener); -// } -// -// public OnItemSelectedListener getOnItemSelectedListener() { -// return spinnerElement.getOnItemSelectedListener(); -// } - public void setSpinnerAdapter(List items) { ArrayAdapter adapter = new ArrayAdapter( getContext(), @@ -122,96 +111,17 @@ public void setSpinnerAdapter(List items) { @Override public View getView(int position, View convertView, ViewGroup parent) { View v = super.getView(position, convertView, parent); - if (position == getCount()) { - ((TextView) v.findViewById(android.R.id.text1)).setText(""); - ((TextView) v.findViewById(android.R.id.text1)).setHint(getItem(getCount()).getKey()); - ((TextView) v.findViewById(android.R.id.text1)).setHintTextColor(Color.LTGRAY); + TextView textView = (TextView) v.findViewById(android.R.id.text1); + if (textView != null && (textView.getText() == null || textView.getText().length() == 0)) { + textView.setHint(this.getContext().getString(R.string.hint_select_entry)); + textView.setHintTextColor(Color.LTGRAY); } - return v; } - - @Override - public int getCount() { - return super.getCount() - 1; - } }; - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - adapter.add(new Item(this.getContext().getString(R.string.hint_select_entry), null)); - spinnerElement.setAdapter(adapter); - spinnerElement.setSelection(adapter.getCount()); - } - - public void setOnsetSymptomSpinnerAdapter(List items) { - ArrayAdapter adapter = new ArrayAdapter( - getContext(), - android.R.layout.simple_spinner_item, - items) { - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - View v = super.getView(position, convertView, parent); - if (position == getCount()) { - ((TextView) v.findViewById(android.R.id.text1)).setText(""); - ((TextView) v.findViewById(android.R.id.text1)).setHint(getItem(getCount()).getKey()); - ((TextView) v.findViewById(android.R.id.text1)).setHintTextColor(Color.LTGRAY); - } - - return v; - } - @Override - public int getCount() { - return super.getCount() - 1; - } - }; - - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - adapter.add(new Item(this.getContext().getString(R.string.hint_select_entry), null)); - spinnerElement.setAdapter(adapter); - spinnerElement.setSelection(adapter.getCount()); - } - - public void setMonthSpinnerAdapter(List items) { - ArrayAdapter adapter = new ArrayAdapter( - getContext(), - android.R.layout.simple_spinner_item, - items) { - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - View v = super.getView(position, convertView, parent); - if (position == getCount()) { - ((TextView) v.findViewById(android.R.id.text1)).setText(""); - ((TextView) v.findViewById(android.R.id.text1)).setHint(getItem(getCount()).getKey()); - ((TextView) v.findViewById(android.R.id.text1)).setHintTextColor(Color.LTGRAY); - } else if (position > 0) { - TextView tv = ((TextView) v); - tv.setText(I18nProperties.getEnumCaption(Month.values()[position - 1])); - } - return v; - } - - @Override - public View getDropDownView(int position, View convertView, ViewGroup parent) { - View v = super.getDropDownView(position, convertView, parent); - if (position > 0 && position < getCount()) { - TextView tv = ((TextView) v); - tv.setText(I18nProperties.getEnumCaption(Month.values()[position - 1])); - } - - return v; - } - - @Override - public int getCount() { - return super.getCount() - 1; - } - }; adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - adapter.add(new Item(this.getContext().getString(R.string.hint_select_entry), null)); spinnerElement.setAdapter(adapter); - spinnerElement.setSelection(adapter.getCount()); } public void initialize(List items, final AdapterView.OnItemSelectedListener[] moreListeners) { @@ -221,17 +131,6 @@ public void initialize(List items, final AdapterView.OnItemSelectedListene } } - public void initializeForOnsetSymptom(List items) { - this.setOnsetSymptomSpinnerAdapter(items); - } - - public void initializeForMonth(List items, final AdapterView.OnItemSelectedListener[] moreListeners) { - this.setMonthSpinnerAdapter(items); - for (AdapterView.OnItemSelectedListener listener : moreListeners) { - this.registerListener(listener); - } - } - /** * Update the spinner list and set selected value. * @param selectedItem @@ -281,16 +180,16 @@ public void onNothingSelected(AdapterView adapterView) { spinnerElement.setOnFocusChangeListener(new OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { - if(hasFocus) { - if (spinnerElement.getSelectedItemPosition() == spinnerElement.getAdapter().getCount()) { + if (hasFocus) { + if (getValue() == null) { spinnerElement.setSelection(indexOnOpen); } InputMethodManager inputMethodManager = (InputMethodManager) getContext().getSystemService(Activity.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(v.getWindowToken(), 0); - spinnerElement.performClick(); - } else { - if (spinnerElement.getSelectedItemPosition() == 0) { - spinnerElement.setSelection(spinnerElement.getAdapter().getCount()); + + if (spinnerElement.isShown()) { + // open selection slider + spinnerElement.performClick(); } } } @@ -327,17 +226,13 @@ public int getPositionOf(Item item) { return -1; } - public void selectLastEntry() { - spinnerElement.setSelection(spinnerElement.getCount()); - } - public Item getSelectedItem() { return (Item) spinnerElement.getSelectedItem(); } private void setSelectedItem(Object selectedItem) { if (selectedItem == null) { - spinnerElement.setSelection(spinnerElement.getAdapter().getCount()); + spinnerElement.setSelection(-1); } else { for (int i = 0; i < spinnerElement.getAdapter().getCount(); i++) { if (selectedItem.equals(((Item) spinnerElement.getAdapter().getItem(i)).getValue())) { @@ -352,5 +247,4 @@ private void setSelectedItem(Object selectedItem) { protected void requestFocusForContentView(View nextView) { ((SpinnerField) nextView).spinnerElement.requestFocus(); } - } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactEditActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactEditActivity.java index ad729639617..9447e367a4b 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactEditActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactEditActivity.java @@ -113,6 +113,7 @@ protected void onResume() { Contact currentEntity = DatabaseHelper.getContactDao().queryUuid(contactUuid); if (currentEntity.isUnreadOrChildUnread()) { // Resetting the adapter will reload the form and therefore also override any unsaved changes + DatabaseHelper.getContactDao().markAsRead(currentEntity); setAdapter(); final Snackbar snackbar = Snackbar.make(findViewById(R.id.base_layout), String.format(getResources().getString(R.string.snackbar_entity_overridden), getResources().getString(R.string.entity_contact)), Snackbar.LENGTH_INDEFINITE); snackbar.setAction(R.string.snackbar_okay, new View.OnClickListener() { @@ -123,8 +124,6 @@ public void onClick(View view) { }); snackbar.show(); } - - DatabaseHelper.getContactDao().markAsRead(currentEntity); } @Override @@ -187,8 +186,8 @@ public boolean onPrepareOptionsMenu(Menu menu) { public boolean onOptionsItemSelected(MenuItem item) { currentTab = pager.getCurrentItem(); ContactEditTabs tab = ContactEditTabs.values()[currentTab]; - Contact contact = (Contact) adapter.getData(ContactEditTabs.CONTACT_DATA.ordinal()); - Person person = (Person) adapter.getData(ContactEditTabs.PERSON.ordinal()); + Contact contact = (Contact) getData(ContactEditTabs.CONTACT_DATA.ordinal()); + Person person = (Person) getData(ContactEditTabs.PERSON.ordinal()); switch (item.getItemId()) { // Respond to the action bar's Up/Home button @@ -250,8 +249,8 @@ public boolean onOptionsItemSelected(MenuItem item) { ContactDao contactDao = DatabaseHelper.getContactDao(); // Validation - ContactDataFragmentLayoutBinding contactDataBinding = ((ContactEditDataForm)adapter.getTabByPosition(ContactEditTabs.CONTACT_DATA.ordinal())).getBinding(); - PersonEditFragmentLayoutBinding personBinding = ((PersonEditForm)adapter.getTabByPosition(ContactEditTabs.PERSON.ordinal())).getBinding(); + ContactDataFragmentLayoutBinding contactDataBinding = ((ContactEditDataForm)getTabByPosition(ContactEditTabs.CONTACT_DATA.ordinal())).getBinding(); + PersonEditFragmentLayoutBinding personBinding = ((PersonEditForm)getTabByPosition(ContactEditTabs.PERSON.ordinal())).getBinding(); ContactValidator.clearErrorsForContactData(contactDataBinding); PersonValidator.clearErrors(personBinding); @@ -298,7 +297,7 @@ public boolean onOptionsItemSelected(MenuItem item) { case R.id.action_add: switch (tab) { case VISITS: - // only contact officer is allowd to create visits + // only contact officer is allowd to build visits // if(UserRole.CONTACT_OFFICER.equals(ConfigProvider.getUser().getUserRoleName())) { Bundle visitBundle = new Bundle(); visitBundle.putString(KEY_CONTACT_UUID, contactUuid); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactEditDataForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactEditDataForm.java index 619eece3e39..c7e27dfc20b 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactEditDataForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactEditDataForm.java @@ -43,7 +43,7 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, final String contactUuid = (String) getArguments().getString(Contact.UUID); final ContactDao contactDao = DatabaseHelper.getContactDao(); - final Contact contact = contactDao.queryUuid(contactUuid); + Contact contact = contactDao.queryUuid(contactUuid); binding.setContact(contact); binding.contactLastContactDate.initialize(this); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactEditPagerAdapter.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactEditPagerAdapter.java index cfc76a4d8f9..c8a5cab90b6 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactEditPagerAdapter.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactEditPagerAdapter.java @@ -23,8 +23,6 @@ public class ContactEditPagerAdapter extends FragmentStatePagerAdapter { private Bundle contactEditBundle; // this contactEditBundle contains the uuids - private ContactEditDataForm contactEditDataForm; - private PersonEditForm personEditForm; // Build a Constructor and assign the passed Values to appropriate values in the class @@ -41,21 +39,18 @@ public Fragment getItem(int position) { ContactEditTabs tab = ContactEditTabs.values()[position]; switch (tab) { case CONTACT_DATA: - contactEditDataForm = new ContactEditDataForm(); - contactEditDataForm.setArguments(contactEditBundle); - frag = contactEditDataForm; + frag = new ContactEditDataForm(); + frag.setArguments(contactEditBundle); break; case PERSON: - personEditForm = new PersonEditForm(); + frag = new PersonEditForm(); Bundle personEditBundle = new Bundle(); Contact contact = DatabaseHelper.getContactDao().queryUuid(contactEditBundle.getString(Contact.UUID)); personEditBundle.putString(Person.UUID, contact.getPerson().getUuid()); personEditBundle.putSerializable(Case.DISEASE, contact.getCaze().getDisease()); - - personEditForm.setArguments(personEditBundle); - frag = personEditForm; + frag.setArguments(personEditBundle); break; case VISITS: @@ -85,32 +80,4 @@ public CharSequence getPageTitle(int position) { public int getCount() { return ContactEditTabs.values().length; } - - public AbstractDomainObject getData(int position) { - ContactEditTabs tab = ContactEditTabs.values()[position]; - AbstractDomainObject ado = null; - switch (tab) { - case CONTACT_DATA: - ado= contactEditDataForm.getData(); - break; - case PERSON: - ado = personEditForm.getData(); - break; - case VISITS: - ado = null; - break; - } - return ado; - } - - public FormTab getTabByPosition(int position) { - ContactEditTabs tab = ContactEditTabs.fromInt(position); - switch (tab) { - case CONTACT_DATA: - return contactEditDataForm; - case PERSON: - return personEditForm; - } - return null; - } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactNewActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactNewActivity.java index c86a42100b8..7793b387644 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactNewActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactNewActivity.java @@ -136,7 +136,7 @@ public void accept(Object parameter) { contact.setPerson((Person) parameter); savePersonAndContact(contact); } catch (DaoException e) { - Log.e(getClass().getName(), "Error while trying to create contact", e); + Log.e(getClass().getName(), "Error while trying to build contact", e); Snackbar.make(findViewById(R.id.fragment_frame), String.format(getResources().getString(R.string.snackbar_create_error), getResources().getString(R.string.entity_contact)), Snackbar.LENGTH_LONG).show(); ErrorReportingHelper.sendCaughtException(tracker, e, null, true); } @@ -150,7 +150,7 @@ public void accept(Object parameter) { savePersonAndContact(contact); } } catch (DaoException e) { - Log.e(getClass().getName(), "Error while trying to create contact", e); + Log.e(getClass().getName(), "Error while trying to build contact", e); Snackbar.make(findViewById(R.id.fragment_frame), String.format(getResources().getString(R.string.snackbar_create_error), getResources().getString(R.string.entity_contact)), Snackbar.LENGTH_LONG).show(); ErrorReportingHelper.sendCaughtException(tracker, e, null, true); } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactNewForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactNewForm.java index 02db769ee02..45625d2f873 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactNewForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactNewForm.java @@ -2,7 +2,6 @@ import android.databinding.DataBindingUtil; import android.os.Bundle; -import android.provider.ContactsContract; import android.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; @@ -13,13 +12,11 @@ import de.symeda.sormas.api.contact.ContactProximity; import de.symeda.sormas.api.contact.ContactRelation; import de.symeda.sormas.app.R; -import de.symeda.sormas.app.SormasApplication; import de.symeda.sormas.app.backend.common.DatabaseHelper; import de.symeda.sormas.app.backend.contact.Contact; import de.symeda.sormas.app.backend.person.Person; import de.symeda.sormas.app.component.FieldHelper; import de.symeda.sormas.app.databinding.ContactNewFragmentLayoutBinding; -import de.symeda.sormas.app.util.DataUtils; import de.symeda.sormas.app.util.FormTab; import de.symeda.sormas.app.validation.ContactValidator; @@ -34,8 +31,8 @@ public class ContactNewForm extends FormTab { @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - person = DatabaseHelper.getPersonDao().create(); - contact = DatabaseHelper.getContactDao().create(); + person = DatabaseHelper.getPersonDao().build(); + contact = DatabaseHelper.getContactDao().build(); contact.setPerson(person); contact.setReportDateTime(new Date()); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactsListFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactsListFragment.java index 228607d3846..c008b8a21a4 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactsListFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/contact/ContactsListFragment.java @@ -97,7 +97,7 @@ public void onActivityCreated(Bundle savedInstanceState) { ContactsListArrayAdapter adapter = new ContactsListArrayAdapter( this.getActivity(), // Context for the activity. - R.layout.contacts_list_item); // Layout to use (create) + R.layout.contacts_list_item); // Layout to use (build) setListAdapter(adapter); getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpiDataForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpiDataForm.java index 1f3a6266f4a..b348583dfad 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpiDataForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/epidata/EpiDataForm.java @@ -7,22 +7,15 @@ import android.view.View; import android.view.ViewGroup; -import com.google.android.gms.analytics.Tracker; - -import java.util.Arrays; -import java.util.List; - import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.utils.YesNoUnknown; import de.symeda.sormas.api.epidata.EpiDataDto; import de.symeda.sormas.api.epidata.WaterSource; import de.symeda.sormas.api.utils.Diseases; import de.symeda.sormas.app.R; -import de.symeda.sormas.app.SormasApplication; import de.symeda.sormas.app.backend.caze.Case; import de.symeda.sormas.app.backend.common.AbstractDomainObject; import de.symeda.sormas.app.backend.common.DatabaseHelper; -import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.backend.epidata.EpiData; import de.symeda.sormas.app.backend.epidata.EpiDataBurial; import de.symeda.sormas.app.backend.epidata.EpiDataGathering; @@ -32,8 +25,6 @@ import de.symeda.sormas.app.component.PropertyField; import de.symeda.sormas.app.databinding.CaseEpidataFragmentLayoutBinding; import de.symeda.sormas.app.util.Consumer; -import de.symeda.sormas.app.util.DataUtils; -import de.symeda.sormas.app.util.ErrorReportingHelper; import de.symeda.sormas.app.util.FormTab; /** @@ -69,7 +60,7 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Override public void accept(Object burial) { if (burial == null) { - burial = DatabaseHelper.getEpiDataBurialDao().create(); + burial = DatabaseHelper.getEpiDataBurialDao().build(); } EpiDataBurialForm burialTab = new EpiDataBurialForm(); burialTab.initialize( @@ -110,7 +101,7 @@ public void accept(Object burialDialog) { @Override public void accept(Object gathering) { if (gathering == null) { - gathering = DatabaseHelper.getEpiDataGatheringDao().create(); + gathering = DatabaseHelper.getEpiDataGatheringDao().build(); } EpiDataGatheringForm gatheringTab = new EpiDataGatheringForm(); gatheringTab.initialize( @@ -151,7 +142,7 @@ public void accept(Object gatheringDialog) { @Override public void accept(Object travel) { if (travel == null) { - travel = DatabaseHelper.getEpiDataTravelDao().create(); + travel = DatabaseHelper.getEpiDataTravelDao().build(); } EpiDataTravelForm travelTab = new EpiDataTravelForm(); travelTab.initialize( diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventEditActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventEditActivity.java index 7bf20b15f74..08725cc4476 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventEditActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventEditActivity.java @@ -103,6 +103,7 @@ protected void onResume() { Event currentEntity = DatabaseHelper.getEventDao().queryUuid(eventUuid); if (currentEntity.isUnreadOrChildUnread()) { // Resetting the adapter will reload the form and therefore also override any unsaved changes + DatabaseHelper.getEventDao().markAsRead(currentEntity); setAdapter(); final Snackbar snackbar = Snackbar.make(findViewById(R.id.base_layout), String.format(getResources().getString(R.string.snackbar_entity_overridden), getResources().getString(R.string.entity_alert)), Snackbar.LENGTH_INDEFINITE); snackbar.setAction(R.string.snackbar_okay, new View.OnClickListener() { @@ -113,8 +114,6 @@ public void onClick(View view) { }); snackbar.show(); } - - DatabaseHelper.getEventDao().markAsRead(currentEntity); } } @@ -169,7 +168,7 @@ public boolean onPrepareOptionsMenu(Menu menu) { public boolean onOptionsItemSelected(MenuItem item) { currentTab = pager.getCurrentItem(); EventEditTabs tab = EventEditTabs.values()[currentTab]; - Event event = (Event) adapter.getData(EventEditTabs.EVENT_DATA.ordinal()); + Event event = (Event) getData(EventEditTabs.EVENT_DATA.ordinal()); switch (item.getItemId()) { // Respond to the action bar's Up/Home button @@ -234,7 +233,7 @@ public boolean onOptionsItemSelected(MenuItem item) { // contact data tab case EVENT_DATA: // Validation - EventDataFragmentLayoutBinding binding = ((EventEditDataForm)adapter.getTabByPosition(EventEditTabs.EVENT_DATA.ordinal())).getBinding(); + EventDataFragmentLayoutBinding binding = ((EventEditDataForm)getTabByPosition(EventEditTabs.EVENT_DATA.ordinal())).getBinding(); EventValidator.clearErrorsForEventData(binding); int validationErrorTab = -1; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventEditDataForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventEditDataForm.java index 3e132280b81..123d530faf3 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventEditDataForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventEditDataForm.java @@ -6,18 +6,13 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Toast; - -import com.google.android.gms.analytics.Tracker; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.event.EventType; import de.symeda.sormas.api.event.TypeOfPlace; import de.symeda.sormas.app.R; -import de.symeda.sormas.app.SormasApplication; import de.symeda.sormas.app.backend.common.AbstractDomainObject; import de.symeda.sormas.app.backend.common.DatabaseHelper; -import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.backend.event.Event; import de.symeda.sormas.app.backend.event.EventDao; import de.symeda.sormas.app.backend.location.Location; @@ -25,8 +20,6 @@ import de.symeda.sormas.app.component.LocationDialog; import de.symeda.sormas.app.component.PropertyField; import de.symeda.sormas.app.databinding.EventDataFragmentLayoutBinding; -import de.symeda.sormas.app.util.DataUtils; -import de.symeda.sormas.app.util.ErrorReportingHelper; import de.symeda.sormas.app.util.FormTab; import de.symeda.sormas.app.util.Consumer; import de.symeda.sormas.app.validation.EventValidator; @@ -47,8 +40,8 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Event event; if (eventUuid==null) { - // create a new event for empty uuid - event = DatabaseHelper.getEventDao().create(); + // build a new event for empty uuid + event = DatabaseHelper.getEventDao().build(); } else { // open the given event final EventDao eventDao = DatabaseHelper.getEventDao(); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventEditPagerAdapter.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventEditPagerAdapter.java index 7c774e10ac2..48a9c3c8e7d 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventEditPagerAdapter.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventEditPagerAdapter.java @@ -19,8 +19,6 @@ public class EventEditPagerAdapter extends FragmentStatePagerAdapter { private Bundle eventEditBundle; // this bundle contains the uuids - private EventEditDataForm eventEditDataForm; - private PersonEditForm personEditForm; // Build a Constructor and assign the passed Values to appropriate values in the class public EventEditPagerAdapter(FragmentManager fm, String eventUuid) { @@ -36,9 +34,8 @@ public Fragment getItem(int position) { EventEditTabs tab = EventEditTabs.values()[position]; switch (tab) { case EVENT_DATA: - eventEditDataForm = new EventEditDataForm(); - eventEditDataForm.setArguments(eventEditBundle); - frag = eventEditDataForm; + frag = new EventEditDataForm(); + frag.setArguments(eventEditBundle); break; case EVENT_PERSONS: @@ -73,27 +70,4 @@ public int getCount() { return 1; // this is a hotfix to make sure that the event persons tab is not displayed when creating a new event and should be replaced asap } } - - public AbstractDomainObject getData(int position) { - EventEditTabs tab = EventEditTabs.values()[position]; - AbstractDomainObject ado = null; - switch (tab) { - case EVENT_DATA: - ado= eventEditDataForm.getData(); - break; -// case EVENT_PERSONS: -// ado = personEditForm.getData(); -// break; - } - return ado; - } - - public FormTab getTabByPosition(int position) { - EventEditTabs tab = EventEditTabs.fromInt(position); - switch (tab) { - case EVENT_DATA: - return eventEditDataForm; - } - return null; - } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventNewActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventNewActivity.java index 6abc2c3b9af..183c372076c 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventNewActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventNewActivity.java @@ -131,7 +131,7 @@ public void call(boolean syncFailed) { finish(); } } catch (DaoException e) { - Log.e(getClass().getName(), "Error while trying to create alert", e); + Log.e(getClass().getName(), "Error while trying to build alert", e); Snackbar.make(findViewById(R.id.base_layout), String.format(getResources().getString(R.string.snackbar_save_error), getResources().getString(R.string.entity_alert)), Snackbar.LENGTH_LONG).show(); ErrorReportingHelper.sendCaughtException(tracker, e, event, true); } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventParticipantDataForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventParticipantDataForm.java index 38fe59c8fac..75e62968b04 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventParticipantDataForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventParticipantDataForm.java @@ -6,20 +6,14 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Toast; - -import com.google.android.gms.analytics.Tracker; import de.symeda.sormas.app.R; -import de.symeda.sormas.app.SormasApplication; import de.symeda.sormas.app.backend.common.AbstractDomainObject; import de.symeda.sormas.app.backend.common.DatabaseHelper; -import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.backend.event.EventParticipant; import de.symeda.sormas.app.backend.event.EventParticipantDao; import de.symeda.sormas.app.backend.person.Person; import de.symeda.sormas.app.databinding.EventParticipantFragmentLayoutBinding; -import de.symeda.sormas.app.util.ErrorReportingHelper; import de.symeda.sormas.app.util.FormTab; import de.symeda.sormas.app.validation.EventParticipantValidator; @@ -40,7 +34,7 @@ public void onResume() { EventParticipantDao eventParticipantDao = DatabaseHelper.getEventParticipantDao(); EventParticipant eventParticipant = eventParticipantDao.queryUuid(personUuid); if (eventParticipant == null) { - eventParticipant = eventParticipantDao.create(); + eventParticipant = eventParticipantDao.build(); } EventParticipantValidator.setRequiredHintsForEventParticipantData(binding); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventParticipantEditActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventParticipantEditActivity.java index 0516eeac23c..7f2ae171f1c 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventParticipantEditActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventParticipantEditActivity.java @@ -87,6 +87,7 @@ protected void onResume() { EventParticipant currentEntity = DatabaseHelper.getEventParticipantDao().queryUuid(eventParticipantUuid); if (currentEntity.isUnreadOrChildUnread()) { // Resetting the adapter will reload the form and therefore also override any unsaved changes + DatabaseHelper.getEventParticipantDao().markAsRead(currentEntity); setAdapter(); final Snackbar snackbar = Snackbar.make(findViewById(R.id.base_layout), String.format(getResources().getString(R.string.snackbar_entity_overridden), getResources().getString(R.string.entity_alert_person)), Snackbar.LENGTH_INDEFINITE); snackbar.setAction(R.string.snackbar_okay, new View.OnClickListener() { @@ -97,8 +98,6 @@ public void onClick(View view) { }); snackbar.show(); } - - DatabaseHelper.getEventParticipantDao().markAsRead(currentEntity); } @Override diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventParticipantNewActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventParticipantNewActivity.java index f06cd305480..48b106a9175 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventParticipantNewActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventParticipantNewActivity.java @@ -127,7 +127,7 @@ public void accept(Object parameter) { eventParticipant.setPerson((Person) parameter); savePersonAndEventParticipant(eventParticipant); } catch (DaoException e) { - Log.e(getClass().getName(), "Error while trying to create alert person", e); + Log.e(getClass().getName(), "Error while trying to build alert person", e); Snackbar.make(findViewById(R.id.fragment_frame), String.format(getResources().getString(R.string.snackbar_create_error), getResources().getString(R.string.entity_alert_person)), Snackbar.LENGTH_LONG).show(); ErrorReportingHelper.sendCaughtException(tracker, e, null, true); } @@ -142,7 +142,7 @@ public void accept(Object parameter) { savePersonAndEventParticipant(eventParticipant); } } catch (DaoException e) { - Log.e(getClass().getName(), "Error while trying to create alert person", e); + Log.e(getClass().getName(), "Error while trying to build alert person", e); Snackbar.make(findViewById(R.id.fragment_frame), String.format(getResources().getString(R.string.snackbar_create_error), getResources().getString(R.string.entity_alert_person)), Snackbar.LENGTH_LONG).show(); ErrorReportingHelper.sendCaughtException(tracker, e, null, true); } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventParticipantNewPersonForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventParticipantNewPersonForm.java index 99475687c88..4d36a5d23dc 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventParticipantNewPersonForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventParticipantNewPersonForm.java @@ -25,8 +25,8 @@ public class EventParticipantNewPersonForm extends FormTab { @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - Person person = DatabaseHelper.getPersonDao().create(); - eventParticipant = DatabaseHelper.getEventParticipantDao().create(); + Person person = DatabaseHelper.getPersonDao().build(); + eventParticipant = DatabaseHelper.getEventParticipantDao().build(); eventParticipant.setPerson(person); binding = DataBindingUtil.inflate(inflater, R.layout.event_participant_new_fragment_layout, container, false); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventParticipantsListFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventParticipantsListFragment.java index eea707cc774..4b08c407559 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventParticipantsListFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/event/EventParticipantsListFragment.java @@ -60,7 +60,7 @@ public void onActivityCreated(Bundle savedInstanceState) { EventParticipantsListArrayAdapter adapter = new EventParticipantsListArrayAdapter( this.getActivity(), // Context for the activity. - R.layout.event_participants_list_item); // Layout to use (create) + R.layout.event_participants_list_item); // Layout to use (build) setListAdapter(adapter); getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/hospitalization/HospitalizationForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/hospitalization/HospitalizationForm.java index 2865215a234..6fee98492ee 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/hospitalization/HospitalizationForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/hospitalization/HospitalizationForm.java @@ -7,15 +7,11 @@ import android.view.View; import android.view.ViewGroup; -import com.google.android.gms.analytics.Tracker; - import de.symeda.sormas.api.utils.YesNoUnknown; import de.symeda.sormas.app.R; -import de.symeda.sormas.app.SormasApplication; import de.symeda.sormas.app.backend.caze.Case; import de.symeda.sormas.app.backend.common.AbstractDomainObject; import de.symeda.sormas.app.backend.common.DatabaseHelper; -import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.backend.hospitalization.Hospitalization; import de.symeda.sormas.app.backend.hospitalization.PreviousHospitalization; import de.symeda.sormas.app.component.LabelField; @@ -23,8 +19,6 @@ import de.symeda.sormas.app.component.PropertyField; import de.symeda.sormas.app.databinding.CaseHospitalizationFragmentLayoutBinding; import de.symeda.sormas.app.util.Consumer; -import de.symeda.sormas.app.util.DataUtils; -import de.symeda.sormas.app.util.ErrorReportingHelper; import de.symeda.sormas.app.util.FormTab; public class HospitalizationForm extends FormTab { @@ -64,7 +58,7 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Override public void accept(Object prevHosp) { if (prevHosp == null) { - prevHosp = DatabaseHelper.getPreviousHospitalizationDao().create(); + prevHosp = DatabaseHelper.getPreviousHospitalizationDao().build(); } PreviousHospitalizationForm previousHospitalizationForm = new PreviousHospitalizationForm(); previousHospitalizationForm.initialize( diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/person/PersonEditForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/person/PersonEditForm.java index b23613aca88..b8085ba1e3b 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/person/PersonEditForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/person/PersonEditForm.java @@ -80,7 +80,7 @@ public void onItemSelected(AdapterView parent, View view, int position, long public void onNothingSelected(AdapterView parent) { } }); - FieldHelper.initMonthSpinnerField(binding.personBirthdateMM, DataUtils.toItems(DateHelper.getMonthsInYear(),true), new AdapterView.OnItemSelectedListener() { + FieldHelper.initSpinnerField(binding.personBirthdateMM, DataUtils.getMonthItems(), new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { updateApproximateAgeField(); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SampleEditActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SampleEditActivity.java index c0763216439..ff9451d4f96 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SampleEditActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SampleEditActivity.java @@ -5,20 +5,15 @@ import android.os.Bundle; import android.support.design.widget.Snackbar; import android.support.v4.app.FragmentTransaction; -import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.widget.CheckBox; - -import com.google.android.gms.analytics.Tracker; import java.util.Date; -import de.symeda.sormas.api.sample.ShipmentStatus; import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.app.AbstractSormasActivity; import de.symeda.sormas.app.R; @@ -109,6 +104,7 @@ protected void onResume() { Sample currentEntity = DatabaseHelper.getSampleDao().queryUuid(sampleUuid); if (currentEntity.isUnreadOrChildUnread()) { // Resetting the adapter will reload the form and therefore also override any unsaved changes + DatabaseHelper.getSampleDao().markAsRead(currentEntity); setAdapter(); final Snackbar snackbar = Snackbar.make(findViewById(R.id.base_layout), String.format(getResources().getString(R.string.snackbar_entity_overridden), getResources().getString(R.string.entity_sample)), Snackbar.LENGTH_INDEFINITE); snackbar.setAction(R.string.snackbar_okay, new View.OnClickListener() { @@ -119,8 +115,6 @@ public void onClick(View view) { }); snackbar.show(); } - - DatabaseHelper.getSampleDao().markAsRead(currentEntity); } } @@ -171,15 +165,6 @@ public boolean onOptionsItemSelected(MenuItem item) { case R.id.action_save: SampleDao sampleDao = DatabaseHelper.getSampleDao(); sample = (Sample) sampleTab.getData(); - CheckBox shipped = (CheckBox) findViewById(R.id.sample_shipmentStatus); - if (shipped.isEnabled()) { - if (shipped.isChecked()) { - sample.setShipmentStatus(ShipmentStatus.SHIPPED); - } else { - sample.setShipmentStatus(ShipmentStatus.NOT_SHIPPED); - sample.setShipmentDate(null); - } - } if (sample.getReportingUser() == null) { sample.setReportingUser(ConfigProvider.getUser()); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SampleEditForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SampleEditForm.java index c003641e10a..f07a5ccae9f 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SampleEditForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SampleEditForm.java @@ -1,8 +1,11 @@ package de.symeda.sormas.app.sample; +import android.content.Intent; import android.databinding.DataBindingUtil; +import android.graphics.Paint; import android.os.Bundle; import android.support.annotation.Nullable; +import android.support.v4.content.ContextCompat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -16,12 +19,12 @@ import de.symeda.sormas.api.sample.SampleMaterial; import de.symeda.sormas.api.sample.SampleSource; import de.symeda.sormas.api.sample.SampleTestType; -import de.symeda.sormas.api.sample.ShipmentStatus; import de.symeda.sormas.api.sample.SpecimenCondition; import de.symeda.sormas.app.R; import de.symeda.sormas.app.backend.caze.Case; import de.symeda.sormas.app.backend.common.AbstractDomainObject; import de.symeda.sormas.app.backend.common.DatabaseHelper; +import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.backend.sample.Sample; import de.symeda.sormas.app.backend.sample.SampleDao; import de.symeda.sormas.app.backend.sample.SampleTest; @@ -52,30 +55,21 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, if (sampleUuid == null) { final String caseUuid = getArguments().getString(SampleEditActivity.KEY_CASE_UUID); final Case associatedCase = DatabaseHelper.getCaseDao().queryUuid(caseUuid); - sample = DatabaseHelper.getSampleDao().create(associatedCase); + sample = DatabaseHelper.getSampleDao().build(associatedCase); } else { sample = sampleDao.queryUuid(sampleUuid); } binding.setSample(sample); - ShipmentStatus shipmentStatus = binding.getSample().getShipmentStatus(); - if (shipmentStatus == ShipmentStatus.NOT_SHIPPED) { - binding.sampleShipmentStatus.setChecked(false); - binding.sampleShipmentDate.setVisibility(View.INVISIBLE); - binding.sampleShipmentDetails.setVisibility(View.GONE); - } else if (shipmentStatus == ShipmentStatus.SHIPPED) { - binding.sampleShipmentStatus.setChecked(true); - } else { - binding.sampleShipmentStatus.setChecked(true); - binding.sampleShipmentStatus.setText(binding.getSample().getShipmentStatus().toString()); - binding.sampleShipmentStatus.setEnabled(false); - binding.sampleShipmentDate.setEnabled(false); - } - binding.sampleShipmentDate.initialize(this); - binding.sampleShipmentStatus.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + // Visibility initialization of shipment details + if (!binding.sampleShipped.getValue()) { + binding.sampleShipmentDate.setVisibility(View.GONE); + binding.sampleShipmentDetails.setVisibility(View.GONE); + } + binding.sampleShipped.setAdditionalListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { @@ -83,7 +77,7 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { binding.sampleShipmentDetails.setVisibility(View.VISIBLE); binding.sampleShipmentDate.setValue(new Date()); } else { - binding.sampleShipmentDate.setVisibility(View.INVISIBLE); + binding.sampleShipmentDate.setVisibility(View.GONE); binding.sampleShipmentDetails.setVisibility(View.GONE); } } @@ -120,38 +114,69 @@ public void onNothingSelected(AdapterView parent) { final List laboratories = DataUtils.toItems(DatabaseHelper.getFacilityDao().getLaboratories()); FieldHelper.initSpinnerField(binding.sampleLab, laboratories); + + // only show received fields when sample has been received binding.sampleReceivedDate.initialize(this); binding.sampleReceivedDate.setEnabled(false); - binding.sampleLabSampleID.setEnabled(false); - if (binding.getSample().getShipmentStatus() != ShipmentStatus.RECEIVED) { - binding.sampleReceivedDate.setVisibility(View.GONE); - binding.sampleLabSampleID.setVisibility(View.GONE); + FieldHelper.initSpinnerField(binding.sampleSpecimenCondition, SpecimenCondition.class); + binding.sampleSpecimenCondition.setEnabled(false); + if (sampleUuid != null) { + if (binding.getSample().isReceived()) { + binding.sampleReceivedLayout.setVisibility(View.VISIBLE); + } } // recent test should only be displayed when an existing sample is viewed, not // when a new one is created if (sampleUuid != null) { - if (binding.getSample().getSpecimenCondition() == SpecimenCondition.NOT_ADEQUATE) { - binding.sampleTypeOfTest.setVisibility(View.GONE); - binding.sampleTestResult.setVisibility(View.GONE); - binding.sampleNoRecentTestText.setVisibility(View.GONE); - } else { + if (binding.getSample().getSpecimenCondition() != SpecimenCondition.NOT_ADEQUATE) { + binding.recentTestLayout.setVisibility(View.VISIBLE); SampleTest mostRecentTest = DatabaseHelper.getSampleTestDao().queryMostRecentBySample(binding.getSample()); - binding.sampleNoTestPossibleText.setVisibility(View.GONE); - binding.sampleNoTestPossibleReason.setVisibility(View.GONE); if (mostRecentTest != null) { - binding.sampleNoRecentTestText.setVisibility(View.GONE); + binding.sampleTypeOfTest.setVisibility(View.VISIBLE); + binding.sampleTestResult.setVisibility(View.VISIBLE); } else { - binding.sampleTypeOfTest.setVisibility(View.GONE); - binding.sampleTestResult.setVisibility(View.GONE); + binding.sampleNoRecentTestText.setVisibility(View.VISIBLE); } } - } else { - binding.recentTestLayout.setVisibility(View.GONE); + } + + // only show referred to field when there is a referred sample + if (sampleUuid != null) { + if (binding.getSample().getReferredTo() != null) { + final Sample referredSample = binding.getSample().getReferredTo(); + binding.sampleReferredTo.setVisibility(View.VISIBLE); + binding.sampleReferredTo.setText(getActivity().getResources().getString(R.string.sample_referred_to) + " " + referredSample.getLab().toString() + " " + "\u279D"); + binding.sampleReferredTo.setPaintFlags(binding.sampleReferredTo.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); + binding.sampleReferredTo.setTextColor(ContextCompat.getColor(getContext(), R.color.colorPrimary)); + binding.sampleReferredTo.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(getActivity(), SampleEditActivity.class); + intent.putExtra(SampleEditActivity.KEY_SAMPLE_UUID, referredSample.getUuid()); + startActivity(intent); + } + }); + } } SampleValidator.setRequiredHintsForSampleData(binding); + if (sampleUuid != null) { + if (!ConfigProvider.getUser().getUuid().equals(binding.getSample().getReportingUser().getUuid())) { + binding.sampleSampleCode.setEnabled(false); + binding.sampleDateTime.setEnabled(false); + binding.sampleMaterial.setEnabled(false); + binding.sampleMaterialText.setEnabled(false); + binding.sampleSuggestedTypeOfTest.setEnabled(false); + binding.sampleLab.setEnabled(false); + binding.sampleSampleCode.setEnabled(false); + binding.sampleShipped.setEnabled(false); + binding.sampleShipmentDate.setEnabled(false); + binding.sampleShipmentDetails.setEnabled(false); + } + } + return binding.getRoot(); } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SamplesListArrayAdapter.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SamplesListArrayAdapter.java index 0cad8138657..58b1d4fa170 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SamplesListArrayAdapter.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SamplesListArrayAdapter.java @@ -51,7 +51,15 @@ public View getView(int position, View convertView, ViewGroup parent) { disease.setText(sample.getAssociatedCase().getDisease().toShortString()); TextView shipmentStatus = (TextView) convertView.findViewById(R.id.sample_shipment_status_li); - shipmentStatus.setText(sample.getShipmentStatus().toString()); + if (sample.getReferredTo() != null) { + shipmentStatus.setText(R.string.sample_referred); + } else if (sample.isReceived()) { + shipmentStatus.setText(R.string.sample_received); + } else if (sample.isShipped()) { + shipmentStatus.setText(R.string.sample_shipped); + } else { + shipmentStatus.setText(R.string.sample_not_shipped); + } TextView casePerson = (TextView) convertView.findViewById(R.id.sample_case_person_li); casePerson.setText(sample.getAssociatedCase().getPerson().toString()); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SamplesListFilterAdapter.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SamplesListFilterAdapter.java index 1c933c1b411..ecd6030efbf 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SamplesListFilterAdapter.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SamplesListFilterAdapter.java @@ -5,9 +5,6 @@ import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; -import de.symeda.sormas.api.sample.ShipmentStatus; -import de.symeda.sormas.app.event.EventsListFragment; - /** * Created by Mate Strysewske on 06.02.2017. */ diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SamplesListFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SamplesListFragment.java index a6ec4118cf6..6ea73e7e6ae 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SamplesListFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/SamplesListFragment.java @@ -2,7 +2,6 @@ import android.content.Intent; import android.os.Bundle; -import android.support.design.widget.Snackbar; import android.support.v4.app.ListFragment; import android.support.v4.widget.SwipeRefreshLayout; import android.view.LayoutInflater; @@ -14,17 +13,13 @@ import java.util.ArrayList; import java.util.List; -import de.symeda.sormas.api.sample.ShipmentStatus; -import de.symeda.sormas.app.AbstractRootTabActivity; import de.symeda.sormas.app.AbstractTabActivity; import de.symeda.sormas.app.R; import de.symeda.sormas.app.backend.caze.Case; import de.symeda.sormas.app.backend.caze.CaseDao; import de.symeda.sormas.app.backend.common.DatabaseHelper; import de.symeda.sormas.app.backend.sample.Sample; -import de.symeda.sormas.app.rest.RetroProvider; import de.symeda.sormas.app.rest.SynchronizeDataAsync; -import de.symeda.sormas.app.util.SyncCallback; /** * Created by Mate Strysewske on 06.02.2017. @@ -51,7 +46,36 @@ public void onResume() { Bundle arguments = getArguments(); if (arguments.containsKey(ARG_FILTER_STATUS)) { ShipmentStatus filterStatus = (ShipmentStatus)arguments.getSerializable(ARG_FILTER_STATUS); - samples = DatabaseHelper.getSampleDao().queryForEq(Sample.SHIPMENT_STATUS, filterStatus); + if (filterStatus == ShipmentStatus.NOT_SHIPPED) { + samples = DatabaseHelper.getSampleDao().queryForEq(Sample.SHIPPED, false); + List samplesToRemove = new ArrayList<>(); + for (Sample sample : samples) { + if (sample.isReceived() || sample.getReferredTo() != null) { + samplesToRemove.add(sample); + } + } + samples.removeAll(samplesToRemove); + } else if (filterStatus == ShipmentStatus.SHIPPED) { + samples = DatabaseHelper.getSampleDao().queryForEq(Sample.SHIPPED, true); + List samplesToRemove = new ArrayList<>(); + for (Sample sample : samples) { + if (sample.isReceived() || sample.getReferredTo() != null) { + samplesToRemove.add(sample); + } + } + samples.removeAll(samplesToRemove); + } else if (filterStatus == ShipmentStatus.RECEIVED) { + samples = DatabaseHelper.getSampleDao().queryForEq(Sample.RECEIVED, true); + List samplesToRemove = new ArrayList<>(); + for (Sample sample : samples) { + if (sample.getReferredTo() != null) { + samplesToRemove.add(sample); + } + } + samples.removeAll(samplesToRemove); + } else { + samples = DatabaseHelper.getSampleDao().queryForNotNull(Sample.REFERRED_TO + "_id"); + } } else { if(arguments.containsKey(KEY_CASE_UUID)) { parentCaseUuid = (String) arguments.get(KEY_CASE_UUID); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/ShipmentStatus.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/ShipmentStatus.java new file mode 100644 index 00000000000..b197577128b --- /dev/null +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/sample/ShipmentStatus.java @@ -0,0 +1,20 @@ +package de.symeda.sormas.app.sample; + +import de.symeda.sormas.api.I18nProperties; + +/** + * Created by Mate Strysewske on 10.08.2017. + */ + +public enum ShipmentStatus { + + NOT_SHIPPED, + SHIPPED, + RECEIVED, + REFERRED_OTHER_LAB; + + public String toString() { + return I18nProperties.getEnumCaption(this); + } + +} diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/settings/SettingsActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/settings/SettingsActivity.java index ae9a13180b7..dcdc4e64a06 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/settings/SettingsActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/settings/SettingsActivity.java @@ -2,6 +2,7 @@ import android.app.AlertDialog; import android.content.Intent; +import android.database.SQLException; import android.os.Bundle; import android.support.v4.app.FragmentTransaction; import android.view.Menu; @@ -16,6 +17,9 @@ import de.symeda.sormas.app.LoginActivity; import de.symeda.sormas.app.R; import de.symeda.sormas.app.SormasApplication; +import de.symeda.sormas.app.backend.caze.Case; +import de.symeda.sormas.app.backend.caze.CaseDao; +import de.symeda.sormas.app.backend.common.DatabaseHelper; import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.AbstractRootTabActivity; import de.symeda.sormas.app.component.SyncLogDialog; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TaskEditActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TaskEditActivity.java index 16ec0c2d1b6..1a4e054b87b 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TaskEditActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TaskEditActivity.java @@ -104,6 +104,7 @@ protected void onResume() { Task currentEntity = DatabaseHelper.getTaskDao().queryUuid(taskUuid); if (currentEntity.isUnreadOrChildUnread()) { // Resetting the adapter will reload the form and therefore also override any unsaved changes + DatabaseHelper.getTaskDao().markAsRead(currentEntity); setAdapter(); final Snackbar snackbar = Snackbar.make(findViewById(R.id.base_layout), String.format(getResources().getString(R.string.snackbar_entity_overridden), getResources().getString(R.string.entity_task)), Snackbar.LENGTH_INDEFINITE); snackbar.setAction(R.string.snackbar_okay, new View.OnClickListener() { @@ -114,8 +115,6 @@ public void onClick(View view) { }); snackbar.show(); } - - DatabaseHelper.getTaskDao().markAsRead(currentEntity); } @Override diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TasksListFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TasksListFragment.java index 458b5a9e78c..0c9fd1f668a 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TasksListFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/task/TasksListFragment.java @@ -120,7 +120,7 @@ public void onActivityCreated(Bundle savedInstanceState) { TasksListArrayAdapter adapter = new TasksListArrayAdapter( this.getActivity(), // Context for the activity. - R.layout.tasks_list_item); // Layout to use (create) + R.layout.tasks_list_item); // Layout to use (build) setListAdapter(adapter); getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() { diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/util/DataUtils.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/util/DataUtils.java index 6e3a7746ef0..c627b930c06 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/util/DataUtils.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/util/DataUtils.java @@ -12,6 +12,8 @@ import java.util.Date; import java.util.List; +import de.symeda.sormas.api.I18nProperties; +import de.symeda.sormas.api.Month; import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.app.R; @@ -44,13 +46,24 @@ public static List toItems(List listIn) { return toItems(listIn, true); } + public static List getMonthItems() { + List listOut = new ArrayList<>(); + listOut.add(new Item("", null)); + for (Month month : Month.values()) { + listOut.add(new Item(I18nProperties.getEnumCaption(month), month.ordinal())); + } + return listOut; + } + public static List toItems(List listIn, boolean withNull) { List listOut = new ArrayList<>(); if (withNull) { listOut.add(new Item("", null)); } - for (E listInEntry : listIn) { - listOut.add(new Item(String.valueOf(listInEntry), listInEntry)); + if (listIn != null) { + for (E listInEntry : listIn) { + listOut.add(new Item(String.valueOf(listInEntry), listInEntry)); + } } return listOut; } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/util/FormTab.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/util/FormTab.java index 4e1d3fa9c88..695440a1044 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/util/FormTab.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/util/FormTab.java @@ -1,21 +1,8 @@ package de.symeda.sormas.app.util; -import android.databinding.BindingAdapter; -import android.graphics.Color; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentTransaction; -import android.support.v7.app.AlertDialog; import android.view.View; -import android.widget.CheckBox; -import android.widget.ImageButton; - -import de.symeda.sormas.api.sample.ShipmentStatus; -import de.symeda.sormas.app.R; -import de.symeda.sormas.app.backend.common.DatabaseHelper; -import de.symeda.sormas.app.backend.location.Location; -import de.symeda.sormas.app.component.LabelField; -import de.symeda.sormas.app.component.LocationDialog; -import de.symeda.sormas.app.component.TextField; public abstract class FormTab extends DialogFragment implements FormFragment { @@ -56,9 +43,4 @@ protected void reloadFragment() { ft.detach(this).attach(this).commit(); } - @BindingAdapter("sampleShipped") - public static void setShipmentStatus(CheckBox checkBox, ShipmentStatus shipmentStatus) { - checkBox.setChecked(true); - } - } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/validation/SampleValidator.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/validation/SampleValidator.java index 59d9c76522d..13e68eebfca 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/validation/SampleValidator.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/validation/SampleValidator.java @@ -6,7 +6,6 @@ import java.util.List; import de.symeda.sormas.api.sample.SampleMaterial; -import de.symeda.sormas.api.sample.ShipmentStatus; import de.symeda.sormas.app.R; import de.symeda.sormas.app.backend.common.DatabaseHelper; import de.symeda.sormas.app.backend.sample.Sample; @@ -24,8 +23,8 @@ public static boolean validateSampleData(Sample sample, SampleDataFragmentLayout boolean success = true; - // Shipment status - if (!sample.getShipmentStatus().equals(ShipmentStatus.NOT_SHIPPED)) { + // Shipped + if (sample.isShipped()) { if (sample.getShipmentDate() == null) { binding.sampleShipmentDate.setError(resources.getString(R.string.validation_sample_shipment_date)); success = false; diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/validation/SymptomsValidator.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/validation/SymptomsValidator.java index 5d1820836e4..03dd3426b8e 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/validation/SymptomsValidator.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/validation/SymptomsValidator.java @@ -224,9 +224,15 @@ private static List getConditionalBleedingSymptoms(CaseSympto binding.symptomsSkinBruising1, binding.symptomsBloodUrine, binding.symptomsOtherHemorrhagicSymptoms); } + public static boolean isSymptomatic(CaseSymptomsFragmentLayoutBinding binding) { + return isAnySymptomSetTo(SymptomState.YES, getNonConditionalSymptoms(binding)) || + (binding.symptomsTemperature.getValue() != null && (Float) binding.symptomsTemperature.getValue() >= 38.0f); + } + private static List> getOtherSymptomsFields(CaseSymptomsFragmentLayoutBinding binding) { return Arrays.asList(binding.symptomsOnsetDate, binding.symptomsOnsetSymptom1, - binding.symptomsOther1HemorrhagicSymptomsText, binding.symptomsOther1NonHemorrhagicSymptomsText); + binding.symptomsOther1HemorrhagicSymptomsText, binding.symptomsOther1NonHemorrhagicSymptomsText, + binding.symptomsTemperature, binding.symptomsTemperatureSource); } /** diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/VisitEditActivity.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/VisitEditActivity.java index f9a6f00ee15..f95e5c13880 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/VisitEditActivity.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/VisitEditActivity.java @@ -3,6 +3,7 @@ import android.app.AlertDialog; import android.os.Bundle; import android.support.design.widget.Snackbar; +import android.support.v4.view.ViewPager; import android.support.v7.widget.Toolbar; import android.text.Html; import android.util.Log; @@ -12,6 +13,7 @@ import android.view.View; import android.widget.LinearLayout; +import de.symeda.sormas.api.visit.VisitStatus; import de.symeda.sormas.app.R; import de.symeda.sormas.app.backend.common.DaoException; import de.symeda.sormas.app.backend.common.DatabaseHelper; @@ -23,6 +25,7 @@ import de.symeda.sormas.app.caze.SymptomsEditForm; import de.symeda.sormas.app.AbstractEditTabActivity; import de.symeda.sormas.app.component.HelpDialog; +import de.symeda.sormas.app.component.PropertyField; import de.symeda.sormas.app.component.UserReportDialog; import de.symeda.sormas.app.databinding.CaseSymptomsFragmentLayoutBinding; import de.symeda.sormas.app.databinding.VisitDataFragmentLayoutBinding; @@ -90,6 +93,7 @@ protected void onResume() { Visit currentEntity = DatabaseHelper.getVisitDao().queryUuid(visitUuid); if (currentEntity.isUnreadOrChildUnread()) { // Resetting the adapter will reload the form and therefore also override any unsaved changes + DatabaseHelper.getVisitDao().markAsRead(currentEntity); setAdapter(); final Snackbar snackbar = Snackbar.make(findViewById(R.id.base_layout), String.format(getResources().getString(R.string.snackbar_entity_overridden), getResources().getString(R.string.entity_visit)), Snackbar.LENGTH_INDEFINITE); snackbar.setAction(R.string.snackbar_okay, new View.OnClickListener() { @@ -100,8 +104,6 @@ public void onClick(View view) { }); snackbar.show(); } - - DatabaseHelper.getVisitDao().markAsRead(currentEntity); } } @@ -123,7 +125,7 @@ public boolean onPrepareOptionsMenu(Menu menu) { case SYMPTOMS: updateActionBarGroups(menu, true, false, true, false, true); - break; + break; } @@ -158,7 +160,7 @@ public boolean onOptionsItemSelected(MenuItem item) { // Report problem button case R.id.action_report: - Visit visit = (Visit) adapter.getData(VisitEditTabs.VISIT_DATA.ordinal()); + Visit visit = (Visit) getData(VisitEditTabs.VISIT_DATA.ordinal()); UserReportDialog userReportDialog = new UserReportDialog(this, this.getClass().getSimpleName() + ":" + tab.toString(), visit.getUuid()); AlertDialog dialog = userReportDialog.create(); @@ -168,12 +170,12 @@ public boolean onOptionsItemSelected(MenuItem item) { // Save button case R.id.action_save: - visit = (Visit) adapter.getData(VisitEditTabs.VISIT_DATA.ordinal()); - Symptoms symptoms = (Symptoms)adapter.getData(VisitEditTabs.SYMPTOMS.ordinal()); - SymptomsEditForm symptomsEditForm = (SymptomsEditForm) adapter.getTabByPosition(VisitEditTabs.SYMPTOMS.ordinal()); + visit = (Visit) getData(VisitEditTabs.VISIT_DATA.ordinal()); + Symptoms symptoms = (Symptoms)getData(VisitEditTabs.SYMPTOMS.ordinal()); + SymptomsEditForm symptomsEditForm = (SymptomsEditForm) getTabByPosition(VisitEditTabs.SYMPTOMS.ordinal()); Contact contact = DatabaseHelper.getContactDao().queryUuid(contactUuid); - VisitDataFragmentLayoutBinding visitDataBinding = ((VisitEditDataForm)adapter.getTabByPosition(VisitEditTabs.VISIT_DATA.ordinal())).getBinding(); + VisitDataFragmentLayoutBinding visitDataBinding = ((VisitEditDataForm)getTabByPosition(VisitEditTabs.VISIT_DATA.ordinal())).getBinding(); CaseSymptomsFragmentLayoutBinding symptomsBinding = symptomsEditForm.getBinding(); // Necessary because the entry could've been automatically set, in which case the setValue method of the @@ -231,6 +233,11 @@ public void call(boolean syncFailed) { return super.onOptionsItemSelected(item); } + public void notifyVisitStatusChange(boolean cooperative) { + SymptomsEditForm symptomsEditForm = (SymptomsEditForm) getTabByPosition(VisitEditTabs.SYMPTOMS.ordinal()); + symptomsEditForm.changeVisitCooperative(cooperative); + } + private void setAdapter() { adapter = new VisitEditPagerAdapter(getSupportFragmentManager(), params); createTabViews(adapter); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/VisitEditDataForm.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/VisitEditDataForm.java index cd8c827b905..aef97a3cd2f 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/VisitEditDataForm.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/VisitEditDataForm.java @@ -6,19 +6,14 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Toast; - -import com.google.android.gms.analytics.Tracker; import de.symeda.sormas.api.visit.VisitStatus; import de.symeda.sormas.app.R; -import de.symeda.sormas.app.SormasApplication; import de.symeda.sormas.app.backend.common.AbstractDomainObject; import de.symeda.sormas.app.backend.common.DatabaseHelper; -import de.symeda.sormas.app.backend.config.ConfigProvider; import de.symeda.sormas.app.backend.visit.Visit; +import de.symeda.sormas.app.component.PropertyField; import de.symeda.sormas.app.databinding.VisitDataFragmentLayoutBinding; -import de.symeda.sormas.app.util.ErrorReportingHelper; import de.symeda.sormas.app.util.FormTab; import de.symeda.sormas.app.validation.VisitValidator; @@ -35,10 +30,10 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Visit visit; - // create a new visit from contact data + // build a new visit from contact data if(getArguments().getBoolean(NEW_VISIT)) { String keyContactUuid = getArguments().getString(KEY_CONTACT_UUID); - visit = DatabaseHelper.getVisitDao().create(keyContactUuid); + visit = DatabaseHelper.getVisitDao().build(keyContactUuid); } // open the given visit else { @@ -50,6 +45,12 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, binding.visitVisitDateTime.initialize(this); binding.visitVisitStatus.initialize(VisitStatus.class); + binding.visitVisitStatus.addValueChangedListener(new PropertyField.ValueChangeListener() { + @Override + public void onChange(PropertyField field) { + ((VisitEditActivity) VisitEditDataForm.this.getActivity()).notifyVisitStatusChange(field.getValue() == VisitStatus.COOPERATIVE); + } + }); VisitValidator.setRequiredHintsForVisitData(binding); diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/VisitEditPagerAdapter.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/VisitEditPagerAdapter.java index ae266a9451c..22cf72fcaca 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/VisitEditPagerAdapter.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/VisitEditPagerAdapter.java @@ -21,9 +21,6 @@ public class VisitEditPagerAdapter extends FragmentStatePagerAdapter { private Bundle visitEditBundle; - private VisitEditDataForm visitEditDataForm; - private SymptomsEditForm symptomsEditForm; - // Build a Constructor and assign the passed Values to appropriate values in the class public VisitEditPagerAdapter(FragmentManager fm, Bundle visitBundle) { @@ -38,24 +35,21 @@ public Fragment getItem(int position) { VisitEditTabs tab = VisitEditTabs.values()[position]; switch (tab) { case VISIT_DATA: - visitEditDataForm = new VisitEditDataForm(); - visitEditDataForm.setArguments(visitEditBundle); - frag = visitEditDataForm; + frag = new VisitEditDataForm(); + frag.setArguments(visitEditBundle); break; case SYMPTOMS: - symptomsEditForm = new SymptomsEditForm(); + frag = new SymptomsEditForm(); Bundle symptomsEditBundle = new Bundle(); - // create new symptoms for new visit + // build new symptoms for new visit if(visitEditBundle.getBoolean(VisitEditDataForm.NEW_VISIT)) { String keyContactUuid = visitEditBundle.getString(VisitEditDataForm.KEY_CONTACT_UUID); Contact contact = DatabaseHelper.getContactDao().queryUuid(keyContactUuid); symptomsEditBundle.putSerializable(Visit.DISEASE, contact.getCaze().getDisease()); symptomsEditBundle.putBoolean(SymptomsEditForm.NEW_SYMPTOMS, true); symptomsEditBundle.putBoolean(SymptomsEditForm.FOR_VISIT, true); - symptomsEditBundle.putBoolean(SymptomsEditForm.VISIT_COOPERATIVE, - visitEditDataForm.getBinding().visitVisitStatus.getValue() == VisitStatus.COOPERATIVE); } // edit symptoms for given visit else { @@ -68,8 +62,7 @@ public Fragment getItem(int position) { visit.getVisitStatus() == VisitStatus.COOPERATIVE); } - symptomsEditForm.setArguments(symptomsEditBundle); - frag = symptomsEditForm; + frag.setArguments(symptomsEditBundle); break; } return frag; @@ -86,29 +79,4 @@ public CharSequence getPageTitle(int position) { public int getCount() { return VisitEditTabs.values().length; } - - public AbstractDomainObject getData(int position) { - VisitEditTabs tab = VisitEditTabs.values()[position]; - AbstractDomainObject ado = null; - switch (tab) { - case VISIT_DATA: - ado= visitEditDataForm.getData(); - break; - case SYMPTOMS: - ado = symptomsEditForm.getData(); - break; - } - return ado; - } - - public FormTab getTabByPosition(int position) { - VisitEditTabs tab = VisitEditTabs.values()[position]; - switch(tab) { - case VISIT_DATA: - return visitEditDataForm; - case SYMPTOMS: - return symptomsEditForm; - } - return null; - } } diff --git a/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/VisitsListFragment.java b/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/VisitsListFragment.java index ebe6810aa72..47e084a6c4f 100644 --- a/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/VisitsListFragment.java +++ b/sormas-app/app/src/main/java/de/symeda/sormas/app/visit/VisitsListFragment.java @@ -61,7 +61,7 @@ public void onActivityCreated(Bundle savedInstanceState) { VisitsListArrayAdapter adapter = new VisitsListArrayAdapter( this.getActivity(), // Context for the activity. - R.layout.visits_list_item); // Layout to use (create) + R.layout.visits_list_item); // Layout to use (build) setListAdapter(adapter); getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() { diff --git a/sormas-app/app/src/main/res/layout/case_data_fragment_layout.xml b/sormas-app/app/src/main/res/layout/case_data_fragment_layout.xml index 2b29c08293b..892772254f0 100644 --- a/sormas-app/app/src/main/res/layout/case_data_fragment_layout.xml +++ b/sormas-app/app/src/main/res/layout/case_data_fragment_layout.xml @@ -230,38 +230,14 @@ android:paddingBottom="@dimen/field_padding" android:value="@={caze.measlesVaccinationInfoSource}"/> - - - - - - - - - - - + android:paddingBottom="@dimen/field_padding" + app:user="@{caze.surveillanceOfficer}"/> diff --git a/sormas-app/app/src/main/res/layout/field_checkbox_field.xml b/sormas-app/app/src/main/res/layout/field_checkbox_field.xml new file mode 100644 index 00000000000..a602eaa79ac --- /dev/null +++ b/sormas-app/app/src/main/res/layout/field_checkbox_field.xml @@ -0,0 +1,19 @@ + + + + + + + + \ No newline at end of file diff --git a/sormas-app/app/src/main/res/layout/field_date_field.xml b/sormas-app/app/src/main/res/layout/field_date_field.xml index a789fb61543..873cda3add1 100644 --- a/sormas-app/app/src/main/res/layout/field_date_field.xml +++ b/sormas-app/app/src/main/res/layout/field_date_field.xml @@ -17,7 +17,7 @@ android:layout_marginLeft="@dimen/field_caption_margin_left" /> diff --git a/sormas-app/app/src/main/res/layout/field_date_time_field.xml b/sormas-app/app/src/main/res/layout/field_date_time_field.xml index 3abfe4bb05f..1e9939d2b99 100644 --- a/sormas-app/app/src/main/res/layout/field_date_time_field.xml +++ b/sormas-app/app/src/main/res/layout/field_date_time_field.xml @@ -23,14 +23,14 @@ diff --git a/sormas-app/app/src/main/res/layout/field_text_field.xml b/sormas-app/app/src/main/res/layout/field_text_field.xml index be5e8526852..bb7440655ce 100644 --- a/sormas-app/app/src/main/res/layout/field_text_field.xml +++ b/sormas-app/app/src/main/res/layout/field_text_field.xml @@ -17,7 +17,7 @@ android:layout_marginLeft="@dimen/field_caption_margin_left" /> - - + android:layout_height="wrap_content"> + android:layout_height="wrap_content"> - + - + - + \ No newline at end of file diff --git a/sormas-app/app/src/main/res/layout/sample_data_fragment_layout.xml b/sormas-app/app/src/main/res/layout/sample_data_fragment_layout.xml index 12a29027038..dba7319cc5f 100644 --- a/sormas-app/app/src/main/res/layout/sample_data_fragment_layout.xml +++ b/sormas-app/app/src/main/res/layout/sample_data_fragment_layout.xml @@ -89,7 +89,7 @@ android:layout_weight="0.5" android:paddingTop="@dimen/field_padding" android:paddingBottom="@dimen/field_padding" - android:nextFocusForward="@+id/sample_comment" + android:nextFocusForward="@+id/sample_suggestedTypeOfTest" android:value="@={sample.sampleMaterialText}"/> @@ -102,15 +102,6 @@ android:paddingBottom="@dimen/field_padding" android:value="@={sample.sampleSource}"/> - - + android:layout_height="wrap_content" + android:layout_marginTop="20dp"> - - - + android:value="@={sample.shipped}"/> @@ -178,37 +160,101 @@ android:paddingBottom="@dimen/field_padding" android:value="@={sample.shipmentDetails}"/> + + + android:layout_height="wrap_content" + android:visibility="gone"> - + android:textAppearance="?android:attr/textAppearanceLarge" + android:text="@string/headline_sample_received" + android:id="@+id/sample_received_headline" + android:textColor="@android:color/tab_indicator_text" + android:textSize="@dimen/abc_text_size_body_1_material" + android:textStyle="bold" + android:paddingTop="30dp" + android:paddingBottom="10dp" /> - + android:layout_height="wrap_content"> + + + + + + + + + + + + + + + + + android:layout_height="wrap_content" + android:visibility="gone"> - - - - - - + app:sampleTypeOfTest="@{sample.uuid}" + android:visibility="gone"/> + app:sampleTestResult="@{sample.uuid}" + android:visibility="gone"/> @@ -271,7 +299,8 @@ android:id="@+id/sample_no_recent_test_text" android:textColor="@android:color/tab_indicator_text" android:textSize="@dimen/field_caption_size" - android:paddingBottom="10dp" /> + android:paddingBottom="10dp" + android:visibility="gone" /> diff --git a/sormas-app/app/src/main/res/layout/user_login_activity_layout.xml b/sormas-app/app/src/main/res/layout/user_login_activity_layout.xml index 895dce0364c..0f9d5b76372 100644 --- a/sormas-app/app/src/main/res/layout/user_login_activity_layout.xml +++ b/sormas-app/app/src/main/res/layout/user_login_activity_layout.xml @@ -44,7 +44,7 @@ diff --git a/sormas-app/app/src/main/res/values/strings.xml b/sormas-app/app/src/main/res/values/strings.xml index 15a0f979c61..9af444ec141 100644 --- a/sormas-app/app/src/main/res/values/strings.xml +++ b/sormas-app/app/src/main/res/values/strings.xml @@ -84,6 +84,7 @@ Sample data Create new sample Recent test + Received Check sormas task Case disease has changed Create new contact @@ -138,10 +139,14 @@ Body not touched Shipment status + Not shipped Shipped + Received + Referred to another laboratory + Referred to Specimen condition not adequate - No test yet + Sample has not been tested yet isolated Add a new entry by pressing the "+" symbol in the top right. diff --git a/sormas-app/pom.xml b/sormas-app/pom.xml index 431f35b16c7..6ee4edf6293 100644 --- a/sormas-app/pom.xml +++ b/sormas-app/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 0.2.0 + 0.3.0 ../sormas-base 4.0.0 diff --git a/sormas-backend/pom.xml b/sormas-backend/pom.xml index 24500148b1c..6a3fb06e4e4 100644 --- a/sormas-backend/pom.xml +++ b/sormas-backend/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 0.2.0 + 0.3.0 ../sormas-base 4.0.0 diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java index 641a4d68071..86180122f8e 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/Case.java @@ -53,7 +53,6 @@ public class Case extends AbstractDomainObject { public static final String INVESTIGATED_DATE = "investigatedDate"; public static final String SURVEILLANCE_OFFICER = "surveillanceOfficer"; public static final String CASE_OFFICER = "caseOfficer"; - public static final String CONTACT_OFFICER = "contactOfficer"; public static final String SYMPTOMS = "symptoms"; public static final String TASKS = "tasks"; public static final String REGION = "region"; @@ -93,7 +92,6 @@ public class Case extends AbstractDomainObject { private User surveillanceOfficer; private User caseOfficer; - private User contactOfficer; private Symptoms symptoms; @@ -246,14 +244,6 @@ public void setCaseOfficer(User caseOfficer) { this.caseOfficer = caseOfficer; } - @ManyToOne(cascade = {}) - public User getContactOfficer() { - return contactOfficer; - } - public void setContactOfficer(User contactOfficer) { - this.contactOfficer = contactOfficer; - } - @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) public Symptoms getSymptoms() { if (symptoms == null) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java index 15ed194e293..27525b9eaad 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseFacadeEjb.java @@ -12,10 +12,12 @@ import javax.validation.constraints.NotNull; import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.caze.CaseDataDto; import de.symeda.sormas.api.caze.CaseFacade; import de.symeda.sormas.api.caze.CaseReferenceDto; import de.symeda.sormas.api.caze.InvestigationStatus; +import de.symeda.sormas.api.contact.ContactDto; import de.symeda.sormas.api.task.TaskContext; import de.symeda.sormas.api.task.TaskHelper; import de.symeda.sormas.api.task.TaskPriority; @@ -23,6 +25,7 @@ import de.symeda.sormas.api.task.TaskType; import de.symeda.sormas.api.user.UserReferenceDto; import de.symeda.sormas.api.user.UserRole; +import de.symeda.sormas.backend.contact.ContactFacadeEjb.ContactFacadeEjbLocal; import de.symeda.sormas.backend.epidata.EpiDataFacadeEjb; import de.symeda.sormas.backend.epidata.EpiDataFacadeEjb.EpiDataFacadeEjbLocal; import de.symeda.sormas.backend.facility.FacilityFacadeEjb; @@ -79,6 +82,8 @@ public class CaseFacadeEjb implements CaseFacade { private HospitalizationFacadeEjbLocal hospitalizationFacade; @EJB private EpiDataFacadeEjbLocal epiDataFacade; + @EJB + private ContactFacadeEjbLocal contactFacade; @Override public List getAllCasesAfter(Date date, String userUuid) { @@ -164,11 +169,23 @@ public CaseReferenceDto getReferenceByUuid(String uuid) { @Override public CaseDataDto saveCase(CaseDataDto dto) { - + Case currentCaze = caseService.getByUuid(dto.getUuid()); + Disease currentDisease = null; + if (currentCaze != null) { + currentDisease = currentCaze.getDisease(); + } + Case caze = fromCaseDataDto(dto); - caseService.ensurePersisted(caze); + caseService.ensurePersisted(caze); updateCaseInvestigationProcess(caze); + + // Update follow-up until and status of all contacts of this case if the disease has changed + if (currentDisease != null && caze.getDisease() != currentDisease) { + for (ContactDto contact : contactFacade.getAllByCase(getReferenceByUuid(caze.getUuid()))) { + contactFacade.updateFollowUpUntilAndStatus(contact); + } + } return toCaseDataDto(caze); } @@ -209,7 +226,6 @@ public Case fromCaseDataDto(@NotNull CaseDataDto source) { target.setSurveillanceOfficer(userService.getByReferenceDto(source.getSurveillanceOfficer())); target.setCaseOfficer(userService.getByReferenceDto(source.getCaseOfficer())); - target.setContactOfficer(userService.getByReferenceDto(source.getContactOfficer())); target.setSymptoms(symptomsFacade.fromDto(source.getSymptoms())); target.setPregnant(source.getPregnant()); @@ -257,7 +273,6 @@ public static CaseDataDto toCaseDataDto(Case source) { target.setSurveillanceOfficer(UserFacadeEjb.toReferenceDto(source.getSurveillanceOfficer())); target.setCaseOfficer(UserFacadeEjb.toReferenceDto(source.getCaseOfficer())); - target.setContactOfficer(UserFacadeEjb.toReferenceDto(source.getContactOfficer())); target.setSymptoms(SymptomsFacadeEjb.toDto(source.getSymptoms())); target.setPregnant(source.getPregnant()); diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java index 8bfd77ee790..2a1d9730775 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/caze/CaseService.java @@ -188,7 +188,6 @@ public Predicate createUserFilter(CriteriaBuilder cb, CriteriaQuery cq, From implements AdoService { - @Resource private SessionContext context; @@ -156,34 +154,25 @@ public void doFlush() { } /** - * Achtung: Für korrekte Funktion muss die aufrufende Klasse {@link Permission#_SYSTEM_ROLE} in {@link DeclareRoles} definiert - * haben. - * - * @return {@code true}, wenn das System selbst der ausführende Benutzer ist. + * @return {@code true}, if the system itself is the executing user. */ protected boolean isSystem() { - return context.isCallerInRole(Permission._SYSTEM_ROLE); + return context.isCallerInRole(UserRole._SYSTEM); } /** - * Achtung: Für korrekte Funktion muss die aufrufende Klasse {@link Permission#_ADMIN} in {@link DeclareRoles} definiert - * haben. - * - * @return {@code true}, wenn der ausführende Benutzer {@link Permission#ADMIN} hat. + * @return {@code true}, if the executing user is {@link UserRole#ADMIN}. */ protected boolean isAdmin() { - return hasPermission(Permission.ADMIN); + return hasUserRole(UserRole.ADMIN); } /** - * Achtung: Für korrekte Funktion muss die aufrufende Klasse die entsprechende Permission in {@link DeclareRoles} definiert - * haben. - * * @param permission - * @return {@code true}, wenn der ausführende Benutzer die angegebene {@code permission} hat. + * @return {@code true}, if the executing user is {@code userRole}. */ - protected boolean hasPermission(Permission permission) { - return context.isCallerInRole(permission.name()); + protected boolean hasUserRole(UserRole userRole) { + return context.isCallerInRole(userRole.name()); } protected Timestamp requestTransactionDate() { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CronService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CronService.java new file mode 100644 index 00000000000..1b7eeeb6715 --- /dev/null +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/CronService.java @@ -0,0 +1,23 @@ +package de.symeda.sormas.backend.common; + +import javax.annotation.security.RunAs; +import javax.ejb.EJB; +import javax.ejb.Schedule; +import javax.ejb.Singleton; + +import de.symeda.sormas.api.user.UserRole; +import de.symeda.sormas.backend.contact.ContactFacadeEjb.ContactFacadeEjbLocal; + +@Singleton +@RunAs(UserRole._SYSTEM) +public class CronService { + + @EJB + private ContactFacadeEjbLocal contactFacade; + + @Schedule(hour = "4", minute = "00", second = "0", persistent=false) + public void runEveryNight() { + + contactFacade.generateContactFollowUpTasks(); + } +} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/StartupShutdownService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/StartupShutdownService.java index 566bbdbc92d..44b37f9cd7f 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/common/StartupShutdownService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/common/StartupShutdownService.java @@ -23,7 +23,6 @@ import de.symeda.sormas.backend.region.DistrictService; import de.symeda.sormas.backend.region.Region; import de.symeda.sormas.backend.region.RegionService; -import de.symeda.sormas.backend.user.Permission; import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.user.UserService; import de.symeda.sormas.backend.util.InfrastructureDataImporter; @@ -31,7 +30,7 @@ @Singleton(name = "StartupShutdownService") @Startup -@RunAs(Permission._SYSTEM_ROLE) +@RunAs(UserRole._SYSTEM) @TransactionManagement(TransactionManagementType.CONTAINER) public class StartupShutdownService { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java index a4abd0fb60c..768eb584878 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactFacadeEjb.java @@ -1,17 +1,22 @@ package de.symeda.sormas.backend.contact; import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.stream.Collectors; +import javax.annotation.security.RolesAllowed; import javax.ejb.EJB; +import javax.ejb.LocalBean; import javax.ejb.Stateless; import javax.validation.ValidationException; import javax.validation.constraints.NotNull; -import org.joda.time.LocalDate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.caze.CaseReferenceDto; @@ -19,7 +24,10 @@ import de.symeda.sormas.api.contact.ContactFacade; import de.symeda.sormas.api.contact.ContactIndexDto; import de.symeda.sormas.api.contact.ContactReferenceDto; +import de.symeda.sormas.api.task.TaskContext; +import de.symeda.sormas.api.task.TaskType; import de.symeda.sormas.api.user.UserReferenceDto; +import de.symeda.sormas.api.user.UserRole; import de.symeda.sormas.api.visit.VisitStatus; import de.symeda.sormas.backend.caze.Case; import de.symeda.sormas.backend.caze.CaseFacadeEjb; @@ -27,9 +35,14 @@ import de.symeda.sormas.backend.person.PersonFacadeEjb; import de.symeda.sormas.backend.person.PersonService; import de.symeda.sormas.backend.region.DistrictFacadeEjb; +import de.symeda.sormas.backend.region.Region; +import de.symeda.sormas.backend.task.Task; +import de.symeda.sormas.backend.task.TaskCriteria; +import de.symeda.sormas.backend.task.TaskService; import de.symeda.sormas.backend.user.User; import de.symeda.sormas.backend.user.UserFacadeEjb; import de.symeda.sormas.backend.user.UserService; +import de.symeda.sormas.backend.util.DateHelper8; import de.symeda.sormas.backend.util.DtoHelper; import de.symeda.sormas.backend.visit.Visit; import de.symeda.sormas.backend.visit.VisitService; @@ -37,6 +50,8 @@ @Stateless(name = "ContactFacade") public class ContactFacadeEjb implements ContactFacade { + private final Logger logger = LoggerFactory.getLogger(getClass()); + @EJB private ContactService contactService; @EJB @@ -47,6 +62,8 @@ public class ContactFacadeEjb implements ContactFacade { private UserService userService; @EJB private VisitService visitService; + @EJB + private TaskService taskService; @Override public List getAllUuids(String userUuid) { @@ -173,7 +190,7 @@ public Contact fromDto(@NotNull ContactDto source) { target.setReportDateTime(source.getReportDateTime()); // use only date, not time - target.setLastContactDate(new LocalDate(source.getLastContactDate()).toDate()); + target.setLastContactDate(DateHelper8.toDate(DateHelper8.toLocalDate(source.getLastContactDate()))); if (target.getLastContactDate() != null && target.getLastContactDate().after(target.getReportDateTime())) { throw new ValidationException(Contact.LAST_CONTACT_DATE + " has to be before " + Contact.REPORT_DATE_TIME); } @@ -259,4 +276,58 @@ public ContactIndexDto toIndexDto(Contact source) { return target; } + + @RolesAllowed(UserRole._SYSTEM) + public void generateContactFollowUpTasks() { + + // get all contacts that are followed up + LocalDateTime fromDateTime = LocalDate.now().atStartOfDay(); + LocalDateTime toDateTime = fromDateTime.plusDays(1); + List contacts = contactService.getFollowUpBetween(DateHelper8.toDate(fromDateTime), DateHelper8.toDate(toDateTime), null, null); + + for (Contact contact : contacts) { + // find already existing tasks + TaskCriteria taskCriteria = new TaskCriteria() + .contactEquals(contact) + .taskTypeEquals(TaskType.CONTACT_FOLLOW_UP) + .dueDateBetween(DateHelper8.toDate(fromDateTime), DateHelper8.toDate(toDateTime)); + List tasks = taskService.findBy(taskCriteria); + + if (tasks.isEmpty()) { + // none found -> create the task + Task task = taskService.buildTask(null); + task.setTaskContext(TaskContext.CONTACT); + task.setContact(contact); + task.setTaskType(TaskType.CONTACT_FOLLOW_UP); + task.setSuggestedStart(DateHelper8.toDate(fromDateTime)); + task.setDueDate(DateHelper8.toDate(toDateTime.minusMinutes(1))); + // assign responsible user + if (contact.getContactOfficer() != null) { + // A. contact officer + task.setAssigneeUser(contact.getContactOfficer()); + } else { + // use region where contact person lifes + Region region = contact.getPerson().getAddress().getRegion(); + if (region == null) { + // fallback: use region of related caze + region = contact.getCaze().getRegion(); + } + // B. contact supervisor + List users = userService.getAllByRegionAndUserRoles(region, UserRole.CONTACT_SUPERVISOR); + if (!users.isEmpty()) { + task.setAssigneeUser(users.get(0)); + } else { + logger.warn("Could not assign responsible user to contact follow-up task: " + task.getUuid()); + } + } + taskService.ensurePersisted(task); + } + } + } + + + @LocalBean + @Stateless + public static class ContactFacadeEjbLocal extends ContactFacadeEjb { + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java index de65248efa3..d37a84101b6 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/contact/ContactService.java @@ -14,6 +14,7 @@ import javax.persistence.criteria.JoinType; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; +import javax.validation.constraints.NotNull; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.contact.FollowUpStatus; @@ -85,30 +86,33 @@ public List getAllAfter(Date date, User user) { return resultList; } - public List getFollowUpBetween(Date fromDate, Date toDate, Disease disease, User user) { + /** + * + * @param fromDate inclusive + * @param toDate exclusive + * @param disease optional + * @param user optional + * @return + */ + public List getFollowUpBetween(@NotNull Date fromDate, @NotNull Date toDate, Disease disease, User user) { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(getElementClass()); Root from = cq.from(getElementClass()); - Predicate filter = createUserFilter(cb, cq, from, user); - Predicate followUpFilter = cb.isNotNull(from.get(Contact.FOLLOW_UP_UNTIL)); - followUpFilter = cb.and(followUpFilter, cb.greaterThanOrEqualTo(from.get(Contact.FOLLOW_UP_UNTIL), fromDate)); - followUpFilter = cb.and(followUpFilter, cb.lessThanOrEqualTo(from.get(Contact.LAST_CONTACT_DATE), toDate)); - - if (filter != null) { - filter = cb.and(filter, followUpFilter); - } else { - filter = followUpFilter; - } + Predicate filter = cb.isNotNull(from.get(Contact.FOLLOW_UP_UNTIL)); + filter = cb.and(filter, cb.greaterThanOrEqualTo(from.get(Contact.FOLLOW_UP_UNTIL), fromDate)); + filter = cb.and(filter, cb.lessThan(from.get(Contact.LAST_CONTACT_DATE), toDate)); + + if (user != null) { + filter = cb.and(filter, createUserFilter(cb, cq, from, user)); + } - if (filter != null && disease != null) { + if (disease != null) { Join caze = from.join(Contact.CAZE); filter = cb.and(filter, cb.equal(caze.get(Case.DISEASE), disease)); } - if (filter != null) { - cq.where(filter); - } + cq.where(filter); List resultList = em.createQuery(cq).getResultList(); return resultList; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/Sample.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/Sample.java index abc9e6f4fc2..3756dfc37d5 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/Sample.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/Sample.java @@ -10,6 +10,7 @@ import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; +import javax.persistence.OneToOne; import javax.persistence.Temporal; import javax.persistence.TemporalType; @@ -17,7 +18,6 @@ import de.symeda.sormas.api.sample.SampleMaterial; import de.symeda.sormas.api.sample.SampleSource; import de.symeda.sormas.api.sample.SampleTestType; -import de.symeda.sormas.api.sample.ShipmentStatus; import de.symeda.sormas.api.sample.SpecimenCondition; import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.backend.caze.Case; @@ -41,7 +41,6 @@ public class Sample extends AbstractDomainObject { public static final String SAMPLE_MATERIAL_TEXT = "sampleMaterialText"; public static final String LAB = "lab"; public static final String OTHER_LAB = "otherLab"; - public static final String SHIPMENT_STATUS = "shipmentStatus"; public static final String SHIPMENT_DATE = "shipmentDate"; public static final String SHIPMENT_DETAILS = "shipmentDetails"; public static final String RECEIVED_DATE = "receivedDate"; @@ -49,6 +48,9 @@ public class Sample extends AbstractDomainObject { public static final String COMMENT = "comment"; public static final String SAMPLE_SOURCE = "sampleSource"; public static final String SUGGESTED_TYPE_OF_TEST = "suggestedTypeOfTest"; + public static final String REFERRED_TO = "referredTo"; + public static final String SHIPPED = "shipped"; + public static final String RECEIVED = "received"; private Case associatedCase; private String sampleCode; @@ -60,7 +62,6 @@ public class Sample extends AbstractDomainObject { private String sampleMaterialText; private Facility lab; private Facility otherLab; - private ShipmentStatus shipmentStatus; private Date shipmentDate; private String shipmentDetails; private Date receivedDate; @@ -69,6 +70,9 @@ public class Sample extends AbstractDomainObject { private String comment; private SampleSource sampleSource; private SampleTestType suggestedTypeOfTest; + private Sample referredTo; + private boolean shipped; + private boolean received; private List sampleTests; @@ -158,15 +162,6 @@ public void setOtherLab(Facility otherLab) { this.otherLab = otherLab; } - @Enumerated(EnumType.STRING) - @Column(nullable=false) - public ShipmentStatus getShipmentStatus() { - return shipmentStatus; - } - public void setShipmentStatus(ShipmentStatus shipmentStatus) { - this.shipmentStatus = shipmentStatus; - } - @Temporal(TemporalType.TIMESTAMP) public Date getShipmentDate() { return shipmentDate; @@ -238,6 +233,31 @@ public SampleTestType getSuggestedTypeOfTest() { public void setSuggestedTypeOfTest(SampleTestType suggestedTypeOfTest) { this.suggestedTypeOfTest = suggestedTypeOfTest; } + + @OneToOne(cascade = {}) + @JoinColumn(nullable = true) + public Sample getReferredTo() { + return referredTo; + } + public void setReferredTo(Sample referredTo) { + this.referredTo = referredTo; + } + + @Column + public boolean isShipped() { + return shipped; + } + public void setShipped(boolean shipped) { + this.shipped = shipped; + } + + @Column + public boolean isReceived() { + return received; + } + public void setReceived(boolean received) { + this.received = received; + } @Override public String toString() { @@ -246,4 +266,5 @@ public String toString() { return materialString + " " + sampleString + " for case " + DataHelper.getShortUuid(associatedCase.getUuid()); } + } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java index 982ac338679..16dd24f7e48 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleFacadeEjb.java @@ -118,6 +118,11 @@ public List getIndexListByCase(CaseReferenceDto caseRef) { .collect(Collectors.toList()); } + @Override + public SampleReferenceDto getReferredFrom(String sampleUuid) { + return toReferenceDto(sampleService.getReferredFrom(sampleUuid)); + } + public Sample fromSampleDto(@NotNull SampleDto source) { Sample target = sampleService.getByUuid(source.getUuid()); @@ -140,7 +145,6 @@ public Sample fromSampleDto(@NotNull SampleDto source) { target.setSampleMaterialText(source.getSampleMaterialText()); target.setLab(facilityService.getByReferenceDto(source.getLab())); target.setOtherLab(facilityService.getByReferenceDto(source.getOtherLab())); - target.setShipmentStatus(source.getShipmentStatus()); target.setShipmentDate(source.getShipmentDate()); target.setShipmentDetails(source.getShipmentDetails()); target.setReceivedDate(source.getReceivedDate()); @@ -149,6 +153,9 @@ public Sample fromSampleDto(@NotNull SampleDto source) { target.setComment(source.getComment()); target.setSampleSource(source.getSampleSource()); target.setSuggestedTypeOfTest(source.getSuggestedTypeOfTest()); + target.setReferredTo(sampleService.getByReferenceDto(source.getReferredTo())); + target.setShipped(source.isShipped()); + target.setReceived(source.isReceived()); return target; } @@ -170,7 +177,6 @@ public static SampleDto toSampleDto(Sample source) { target.setSampleMaterialText(source.getSampleMaterialText()); target.setLab(FacilityFacadeEjb.toReferenceDto(source.getLab())); target.setOtherLab(FacilityFacadeEjb.toReferenceDto(source.getOtherLab())); - target.setShipmentStatus(source.getShipmentStatus()); target.setShipmentDate(source.getShipmentDate()); target.setShipmentDetails(source.getShipmentDetails()); target.setReceivedDate(source.getReceivedDate()); @@ -179,6 +185,9 @@ public static SampleDto toSampleDto(Sample source) { target.setComment(source.getComment()); target.setSampleSource(source.getSampleSource()); target.setSuggestedTypeOfTest(source.getSuggestedTypeOfTest()); + target.setReferredTo(SampleFacadeEjb.toReferenceDto(source.getReferredTo())); + target.setShipped(source.isShipped()); + target.setReceived(source.isReceived()); return target; } @@ -206,11 +215,13 @@ public SampleIndexDto toIndexDto(Sample source) { target.setShipmentDate(source.getShipmentDate()); target.setReceivedDate(source.getReceivedDate()); target.setSampleMaterial(source.getSampleMaterial()); - target.setShipmentStatus(source.getShipmentStatus()); target.setLab(FacilityFacadeEjb.toReferenceDto(source.getLab())); target.setSpecimenCondition(source.getSpecimenCondition()); target.setNoTestPossibleReason(source.getNoTestPossibleReason()); target.setLga(DistrictFacadeEjb.toReferenceDto(source.getAssociatedCase().getDistrict())); + target.setReferredTo(SampleFacadeEjb.toReferenceDto(source.getReferredTo())); + target.setShipped(source.isShipped()); + target.setReceived(source.isReceived()); SampleTest latestSampleTest = null; for(SampleTest sampleTest : source.getSampleTests()) { diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleService.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleService.java index 03192d463a0..c3a10bb9df5 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleService.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/sample/SampleService.java @@ -6,6 +6,7 @@ import javax.ejb.EJB; import javax.ejb.LocalBean; import javax.ejb.Stateless; +import javax.persistence.NoResultException; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.From; @@ -71,15 +72,34 @@ public List getAllByCase(Case caze) { return resultList; } + /** + * Returns the sample that refers to the sample identified by the sampleUuid. + * + * @param sampleUuid The UUID of the sample to get the referral for. + * @return The sample that refers to this sample, or null if none is found. + */ + public Sample getReferredFrom(String sampleUuid) { + CriteriaBuilder cb = em.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(getElementClass()); + Root from = cq.from(getElementClass()); + + cq.where(cb.equal(from.get(Sample.REFERRED_TO), getByUuid(sampleUuid))); + try { + return em.createQuery(cq).getSingleResult(); + } catch (NoResultException e) { + return null; + } + } + /** * @see /sormas-backend/doc/UserDataAccess.md */ @Override + @SuppressWarnings("unchecked") public Predicate createUserFilter(CriteriaBuilder cb, CriteriaQuery cq, From samplePath, User user) { // whoever created the case the sample is associated with or is assigned to it // is allowed to access it Path casePath = samplePath.get(Sample.ASSOCIATED_CASE); - @SuppressWarnings("unchecked") Predicate filter = caseService.createUserFilter(cb, cq, (From)casePath, user); // user that reported it is not able to access it. Otherwise they would also need to access the case @@ -89,10 +109,9 @@ public Predicate createUserFilter(CriteriaBuilder cb, CriteriaQuery cq, From - * Gruppierte Rechte wie bearbeitbar, einsehbar usw. müssen einen bestimmten - * Suffix haben, der Präfix wird zum Erstellen der Gruppen genutzt. Innerhalb - * der Gruppen müssen die Rechte über die Child-Hierarchie geordnet sein. - * Es sind alle Suffixe erlaubt, die durch {@link SubPermission} abgebildet werden. - * ACHTUNG: Permissions müssen in die glassfish-ejb-jar.xml des ejb-Projekts eingetragen werden. - * Siehe PermissionIllustrator im test-Bereich. - * - * @RolesAllowed-Annotation an EJB verwendet.
- */ -public enum Permission - implements - Cloneable { - - // TODO add Permissions - - // ########### System permissions - ADMIN(), - USER(),; - - /* - * ACHTUNG: Zum Pflegen der Konstanten: {@link PermissionIllustrator} - */ - - public static final String _ADMIN = "ADMIN"; - public static final String _USER = "USER"; - - // ########### Zusätzliche Rechte - public static final String _SYSTEM_ROLE = "SYSTEM_ROLE"; - - private static final Permission[] SIMPLE_PERMISSIONS = { - ADMIN, }; - - private final Permission[] children; - private Permission[] transitivePermissions = null; - - Permission(Permission... includedPermissions) { - this.children = includedPermissions; - } - - /** - * Simple Rechte, die nicht Teil anderer Rechte sind und die auch keine - * anderen Rechte beinhalten - * - * @return - */ - public static Permission[] getSimplePermissions() { - return SIMPLE_PERMISSIONS; - } - - /** - * Wandelt die übergebenen Permissions in ein Set inkl. der transitiven Permissions. - * - * @param selectedPermissions - * Die aktuell ausgewählten/zugewiesenen Permissions. - * @return {@code selectedPermissions} und daraus folgenden transitiven Permissions als {@link Set}. - */ - public static Set convertWithTransitivePermissions(Permission... selectedPermissions) { - - return convertWithTransitivePermissions(Arrays.asList(selectedPermissions)); - } - - /** - * Wandelt die übergebenen Permissions in ein Set inkl. der transitiven Permissions. - * - * @param selectedPermissions - * Die aktuell ausgewählten/zugewiesenen Permissions. - * @return {@code selectedPermissions} und daraus folgenden transitiven Permissions als {@link Set}. - */ - public static Set convertWithTransitivePermissions(Iterable selectedPermissions) { - - final Set permissionsSet = new LinkedHashSet<>(); - for (Permission permission : selectedPermissions) { - // Direkte Permission - permissionsSet.add(permission); - - // Transitive Permissions - permissionsSet.addAll(Arrays.asList(permission.getTransitivePermissions())); - } - - return permissionsSet; - } - - public String getName() { - return toString(); - } - - public Permission[] getChildren() { - return children.clone(); - } - - /** - * @return Permissions, die aufgrund dieser Permission eingeschlossen sind. - */ - public Permission[] getTransitivePermissions() { - return transitivePermissions; - } - - - private static Permission[] calculateTransitivePermissions(Permission permission) { - - if (permission.transitivePermissions != null) { - return permission.transitivePermissions; - } - EnumSet set; - if (permission.children.length == 0) { - set = EnumSet.noneOf(Permission.class); - } else { - set = EnumSet.copyOf(Arrays.asList(permission.children)); - } - for (Permission child : permission.children) { - Permission[] childPermissions = calculateTransitivePermissions(child); - set.addAll(Arrays.asList(childPermissions)); - } - Permission[] array = set.toArray(new Permission[set.size()]); - Arrays.sort(array); - permission.transitivePermissions = array; - return array; - } - - private static void calculateTransitiveClosure() { - for (Permission permission : Permission.values()) { - calculateTransitivePermissions(permission); - } - } - - /* - * Die transitive Hülle kann erst berechet werden nachdem das Enum - * initialisiert wurde. - */ - static { - calculateTransitiveClosure(); - } -} diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/util/DateHelper8.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/util/DateHelper8.java index 5c480cb408f..09d54607ea2 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/util/DateHelper8.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/util/DateHelper8.java @@ -2,6 +2,7 @@ import java.time.Instant; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; @@ -15,4 +16,7 @@ public static Date toDate(LocalDate date) { return Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant()); } + public static Date toDate(LocalDateTime dateTime) { + return Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant()); + } } diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/util/PasswordHelper.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/util/PasswordHelper.java index 6609a7c27da..4a0ea962052 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/util/PasswordHelper.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/util/PasswordHelper.java @@ -6,18 +6,19 @@ import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; -public class PasswordHelper { +import javax.validation.ValidationException; -// private static Logger logger = LoggerFactory -// .getLogger(PasswordHelper.class); +public class PasswordHelper { - private static final char[] PASSWORD_CHARS = new char[25 + 25 + 10]; + private static final char[] PASSWORD_CHARS = new char[26-2 + 26-3 + 8]; static { int i = 0; for (char ch = 'a'; ch <= 'z'; ch++) { switch (ch) { case 'l': continue; + case 'v': + continue; default: PASSWORD_CHARS[i++] = ch; } @@ -26,15 +27,21 @@ public class PasswordHelper { switch (ch) { case 'I': continue; -// case 'O': -// continue; + case 'O': + continue; + case 'V': + continue; default: PASSWORD_CHARS[i++] = ch; } } - for (char ch = '0'; ch <= '9'; ch++) { + for (char ch = '2'; ch <= '9'; ch++) { PASSWORD_CHARS[i++] = ch; } + + if (i != PASSWORD_CHARS.length) { + throw new ValidationException("Size of password char array does not match defined values."); + } } private static final Charset UTF8_CHARSET; diff --git a/sormas-backend/src/main/java/de/symeda/sormas/backend/visit/VisitFacadeEjb.java b/sormas-backend/src/main/java/de/symeda/sormas/backend/visit/VisitFacadeEjb.java index 9f3d8d5901d..6bae86fcee9 100644 --- a/sormas-backend/src/main/java/de/symeda/sormas/backend/visit/VisitFacadeEjb.java +++ b/sormas-backend/src/main/java/de/symeda/sormas/backend/visit/VisitFacadeEjb.java @@ -12,6 +12,7 @@ import de.symeda.sormas.api.contact.ContactReferenceDto; import de.symeda.sormas.api.person.PersonReferenceDto; +import de.symeda.sormas.api.symptoms.SymptomsHelper; import de.symeda.sormas.api.visit.VisitDto; import de.symeda.sormas.api.visit.VisitFacade; import de.symeda.sormas.api.visit.VisitReferenceDto; @@ -100,6 +101,7 @@ public VisitReferenceDto getReferenceByUuid(String uuid) { @Override public VisitDto saveVisit(VisitDto dto) { + SymptomsHelper.updateIsSymptomatic(dto.getSymptoms()); Visit entity = fromDto(dto); visitService.ensurePersisted(entity); contactService.updateFollowUpUntilAndStatusByVisit(entity); diff --git a/sormas-backend/src/main/resources/META-INF/glassfish-ejb-jar.xml b/sormas-backend/src/main/resources/META-INF/glassfish-ejb-jar.xml index fdb9101346a..79c2e7722e3 100644 --- a/sormas-backend/src/main/resources/META-INF/glassfish-ejb-jar.xml +++ b/sormas-backend/src/main/resources/META-INF/glassfish-ejb-jar.xml @@ -13,8 +13,8 @@ - SYSTEM_ROLE - SYSTEM_ROLE + SYSTEM + SYSTEM diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java new file mode 100644 index 00000000000..bc66425b77b --- /dev/null +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/caze/CaseFacadeEjbTest.java @@ -0,0 +1,110 @@ +package de.symeda.sormas.backend.caze; + +import static org.junit.Assert.assertEquals; + +import java.time.LocalDate; +import java.util.Arrays; +import java.util.Date; +import java.util.HashSet; + +import org.junit.Before; +import org.junit.Test; + +import de.symeda.sormas.api.Disease; +import de.symeda.sormas.api.caze.CaseClassification; +import de.symeda.sormas.api.caze.CaseDataDto; +import de.symeda.sormas.api.caze.CaseFacade; +import de.symeda.sormas.api.caze.InvestigationStatus; +import de.symeda.sormas.api.contact.ContactDto; +import de.symeda.sormas.api.contact.ContactFacade; +import de.symeda.sormas.api.contact.FollowUpStatus; +import de.symeda.sormas.api.person.PersonDto; +import de.symeda.sormas.api.person.PersonFacade; +import de.symeda.sormas.api.user.UserDto; +import de.symeda.sormas.api.user.UserFacade; +import de.symeda.sormas.api.user.UserRole; +import de.symeda.sormas.api.utils.DataHelper; +import de.symeda.sormas.backend.MockProducer; +import de.symeda.sormas.backend.caze.CaseFacadeEjb.CaseFacadeEjbLocal; +import de.symeda.sormas.backend.contact.ContactFacadeEjb.ContactFacadeEjbLocal; +import de.symeda.sormas.backend.person.PersonFacadeEjb; +import de.symeda.sormas.backend.user.UserFacadeEjb.UserFacadeEjbLocal; +import de.symeda.sormas.backend.util.DateHelper8; +import info.novatec.beantest.api.BaseBeanTest; + +public class CaseFacadeEjbTest extends BaseBeanTest { + + /** + * Resets mocks to their initial state so that mock configurations are not shared between tests. + */ + @Before + public void resetMocks() { + MockProducer.resetMocks(); + } + + @Test + public void testDiseaseChangeUpdatesContacts() { + + // TODO create provider for facades (probably best to add a SormasBeanTest class) + UserFacade userFacade = getBean(UserFacadeEjbLocal.class); + CaseFacade caseFacade = getBean(CaseFacadeEjbLocal.class); + PersonFacade personFacade = getBean(PersonFacadeEjb.class); + ContactFacade contactFacade = getBean(ContactFacadeEjbLocal.class); + + // TODO handle user creation at a central place + UserDto user = new UserDto(); + user.setUuid(DataHelper.createUuid()); + user.setFirstName("Admin"); + user.setLastName("Symeda"); + user.setUserName("AdminSymeda"); + user.setUserRoles(new HashSet(Arrays.asList(UserRole.SURVEILLANCE_SUPERVISOR))); + user = userFacade.saveUser(user); + + // TODO add create method to PersonFacade + PersonDto cazePerson = new PersonDto(); + cazePerson.setUuid(DataHelper.createUuid()); + cazePerson.setFirstName("Tim"); + cazePerson.setLastName("Kunsen"); + cazePerson = personFacade.savePerson(cazePerson); + + // TODO add create method to CaseFacade that takes a person + CaseDataDto caze = new CaseDataDto(); + caze.setPerson(cazePerson); + caze.setReportDate(new Date()); + caze.setReportingUser(user); + caze.setDisease(Disease.EVD); + caze.setCaseClassification(CaseClassification.PROBABLE); + caze.setInvestigationStatus(InvestigationStatus.PENDING); + caze = caseFacade.saveCase(caze); + + PersonDto contactPerson = new PersonDto(); + cazePerson.setUuid(DataHelper.createUuid()); + contactPerson.setFirstName("Steff"); + contactPerson.setLastName("Hansen"); + contactPerson = personFacade.savePerson(contactPerson); + + ContactDto contact = new ContactDto(); + contact.setUuid(DataHelper.createUuid()); + contact.setReportDateTime(new Date()); + contact.setReportingUser(user); + contact.setContactOfficer(user); + contact.setPerson(contactPerson); + contact.setCaze(caze); + contact.setLastContactDate(new Date()); + contact = contactFacade.saveContact(contact); + + // Follow-up status and duration should be set to the requirements for EVD + assertEquals(FollowUpStatus.FOLLOW_UP, contact.getFollowUpStatus()); + assertEquals(LocalDate.now().plusDays(21), DateHelper8.toLocalDate(contact.getFollowUpUntil())); + + caze.setDisease(Disease.MEASLES); + caze = caseFacade.saveCase(caze); + + // Follow-up status and duration should be set to no follow-up and null respectively because + // Measles does not require a follow-up + contact = contactFacade.getContactByUuid(contact.getUuid()); + assertEquals(FollowUpStatus.NO_FOLLOW_UP, contact.getFollowUpStatus()); + assertEquals(null, contact.getFollowUpUntil()); + } + +} diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java index 5c131668bca..a8e444fc255 100644 --- a/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/contact/ContactFacadeEjbTest.java @@ -6,6 +6,7 @@ import java.util.Arrays; import java.util.Date; import java.util.HashSet; +import java.util.List; import org.apache.commons.lang3.time.DateUtils; import org.junit.Before; @@ -21,6 +22,10 @@ import de.symeda.sormas.api.contact.FollowUpStatus; import de.symeda.sormas.api.person.PersonDto; import de.symeda.sormas.api.person.PersonFacade; +import de.symeda.sormas.api.task.TaskDto; +import de.symeda.sormas.api.task.TaskFacade; +import de.symeda.sormas.api.task.TaskStatus; +import de.symeda.sormas.api.task.TaskType; import de.symeda.sormas.api.user.UserDto; import de.symeda.sormas.api.user.UserFacade; import de.symeda.sormas.api.user.UserRole; @@ -30,7 +35,9 @@ import de.symeda.sormas.api.visit.VisitStatus; import de.symeda.sormas.backend.MockProducer; import de.symeda.sormas.backend.caze.CaseFacadeEjb.CaseFacadeEjbLocal; +import de.symeda.sormas.backend.contact.ContactFacadeEjb.ContactFacadeEjbLocal; import de.symeda.sormas.backend.person.PersonFacadeEjb; +import de.symeda.sormas.backend.task.TaskFacadeEjb; import de.symeda.sormas.backend.user.UserFacadeEjb.UserFacadeEjbLocal; import de.symeda.sormas.backend.util.DateHelper8; import de.symeda.sormas.backend.visit.VisitFacadeEjb; @@ -51,7 +58,7 @@ public void testUpdateFollowUpUntil() { // TODO create provider for facades (probably best to add a SormasBeanTest class) UserFacade userFacade = getBean(UserFacadeEjbLocal.class); - ContactFacade contactFacade = getBean(ContactFacadeEjb.class); + ContactFacade contactFacade = getBean(ContactFacadeEjbLocal.class); PersonFacade personFacade = getBean(PersonFacadeEjb.class); CaseFacade caseFacade = getBean(CaseFacadeEjbLocal.class); VisitFacade visitFacade = getBean(VisitFacadeEjb.class); @@ -122,4 +129,72 @@ public void testUpdateFollowUpUntil() { assertEquals(FollowUpStatus.COMPLETED, contact.getFollowUpStatus()); assertEquals(LocalDate.now().plusDays(21), DateHelper8.toLocalDate(contact.getFollowUpUntil())); } + + @Test + public void testGenerateContactFollowUpTasks() { + + // TODO create provider for facades (probably best to add a SormasBeanTest class) + UserFacade userFacade = getBean(UserFacadeEjbLocal.class); + ContactFacade contactFacade = getBean(ContactFacadeEjbLocal.class); + PersonFacade personFacade = getBean(PersonFacadeEjb.class); + CaseFacade caseFacade = getBean(CaseFacadeEjbLocal.class); + TaskFacade taskFacade = getBean(TaskFacadeEjb.class); + + // TODO handle user creation at a central place + UserDto user = new UserDto(); + user.setUuid(DataHelper.createUuid()); + user.setFirstName("Admin"); + user.setLastName("Symeda"); + user.setUserName("AdminSymeda"); + user.setUserRoles(new HashSet(Arrays.asList(UserRole.SURVEILLANCE_SUPERVISOR))); + user = userFacade.saveUser(user); + + // TODO add create method to PersonFacde + PersonDto cazePerson = new PersonDto(); + cazePerson.setUuid(DataHelper.createUuid()); + cazePerson.setFirstName("Tim"); + cazePerson.setLastName("Kunsen"); + cazePerson = personFacade.savePerson(cazePerson); + + // TODO add create method to CaseFacade that takes a person + CaseDataDto caze = new CaseDataDto(); + caze.setPerson(cazePerson); + caze.setReportDate(new Date()); + caze.setReportingUser(user); + caze.setDisease(Disease.EVD); + caze.setCaseClassification(CaseClassification.PROBABLE); + caze.setInvestigationStatus(InvestigationStatus.PENDING); + caze = caseFacade.saveCase(caze); + + PersonDto contactPerson = new PersonDto(); + cazePerson.setUuid(DataHelper.createUuid()); + contactPerson.setFirstName("Steff"); + contactPerson.setLastName("Hansen"); + contactPerson = personFacade.savePerson(contactPerson); + + ContactDto contact = new ContactDto(); + contact.setUuid(DataHelper.createUuid()); + contact.setReportDateTime(new Date()); + contact.setReportingUser(user); + contact.setContactOfficer(user); + contact.setPerson(contactPerson); + contact.setCaze(caze); + contact.setLastContactDate(new Date()); + contact = contactFacade.saveContact(contact); + + contactFacade.generateContactFollowUpTasks(); + + // task should have been generated + List tasks = taskFacade.getAllByContact(contact); + assertEquals(1, tasks.size()); + TaskDto task = tasks.get(0); + assertEquals(TaskType.CONTACT_FOLLOW_UP, task.getTaskType()); + assertEquals(TaskStatus.PENDING, task.getTaskStatus()); + assertEquals(LocalDate.now(), DateHelper8.toLocalDate(task.getDueDate())); + + // task should not be generated multiple times + contactFacade.generateContactFollowUpTasks(); + tasks = taskFacade.getAllByContact(contact); + assertEquals(1, tasks.size()); + } } diff --git a/sormas-backend/src/test/java/de/symeda/sormas/backend/util/PasswordHelperTest.java b/sormas-backend/src/test/java/de/symeda/sormas/backend/util/PasswordHelperTest.java new file mode 100644 index 00000000000..d95d6c0c95c --- /dev/null +++ b/sormas-backend/src/test/java/de/symeda/sormas/backend/util/PasswordHelperTest.java @@ -0,0 +1,35 @@ +package de.symeda.sormas.backend.util; + +import static org.junit.Assert.*; + +import org.junit.Test; + +/** + * @see PasswordHelper + */ +public class PasswordHelperTest { + + private static final int LENGTH = 20; + + private static final String[] FORBIDDEN = { + "0", + "1", + "O", + "I", + "V", + "l", + "v" }; + + @Test + public void testCreatePass() { + + for (int i = 0; i < 100; i++) { + + String password = PasswordHelper.createPass(LENGTH); + assertEquals("Unerwartete Passwortlänge", LENGTH, password.length()); + for (int j = 0; j < FORBIDDEN.length; j++) { + assertFalse("Unerlaubtes Zeichen " + FORBIDDEN[j] + " enthalten: " + password, password.contains(FORBIDDEN[j])); + } + } + } +} \ No newline at end of file diff --git a/sormas-base/dependencies/bundles.pom b/sormas-base/dependencies/bundles.pom index 9562c704a9c..c7d47f9512a 100644 --- a/sormas-base/dependencies/bundles.pom +++ b/sormas-base/dependencies/bundles.pom @@ -9,7 +9,7 @@ sormas-base de.symeda.sormas - 0.2.0 + 0.3.0 ../ diff --git a/sormas-base/dependencies/gf-modules.pom b/sormas-base/dependencies/gf-modules.pom index 84fae7c5a98..cfa47f43c6d 100644 --- a/sormas-base/dependencies/gf-modules.pom +++ b/sormas-base/dependencies/gf-modules.pom @@ -8,7 +8,7 @@ sormas-base de.symeda.sormas - 0.2.0 + 0.3.0 ../ diff --git a/sormas-base/dependencies/serverlibs.pom b/sormas-base/dependencies/serverlibs.pom index 9d644f0ea3c..2ded8c1bf89 100644 --- a/sormas-base/dependencies/serverlibs.pom +++ b/sormas-base/dependencies/serverlibs.pom @@ -8,7 +8,7 @@ sormas-base de.symeda.sormas - 0.2.0 + 0.3.0 ../ diff --git a/sormas-base/pom.xml b/sormas-base/pom.xml index aa9037f7426..47a7872e4e1 100644 --- a/sormas-base/pom.xml +++ b/sormas-base/pom.xml @@ -5,7 +5,7 @@ de.symeda.sormas sormas-base pom - 0.2.0 + 0.3.0 3.0 diff --git a/sormas-base/sql/sormas_schema.sql b/sormas-base/sql/sormas_schema.sql index 971d0d14386..6538b75e1d5 100644 --- a/sormas-base/sql/sormas_schema.sql +++ b/sormas-base/sql/sormas_schema.sql @@ -1581,3 +1581,27 @@ UPDATE public.district SET changedate=now(); UPDATE public.region SET changedate=now(); INSERT INTO schema_version (version_number, comment) VALUES (54, 'Split EPID code'); + +-- 2017-08-07 Remove contact officer from case #267 +ALTER TABLE cases DROP COLUMN contactofficer_id; + +INSERT INTO schema_version (version_number, comment) VALUES (55, 'Remove contact officer from case'); + +-- 2017-08-07 Add referredTo field to sample #255 +ALTER TABLE samples ADD COLUMN referredto_id bigint; +ALTER TABLE samples ADD CONSTRAINT fk_samples_referredto_id FOREIGN KEY (referredto_id) REFERENCES samples (id); + +INSERT INTO schema_version (version_number, comment) VALUES (56, 'Add referredTo field to sample'); + +-- 2017-08-10 Replace ShipmentStatus with shipped and received booleans #229 +ALTER TABLE samples ADD COLUMN shipped boolean; +ALTER TABLE samples ADD COLUMN received boolean; +UPDATE samples SET shipped=true WHERE shipmentstatus = 'SHIPPED' OR shipmentstatus = 'RECEIVED' OR shipmentstatus = 'REFERRED_OTHER_LAB'; +UPDATE samples SET received=true WHERE shipmentstatus = 'RECEIVED' OR shipmentstatus = 'REFERRED_OTHER_LAB'; +UPDATE samples SET shipped=false WHERE shipmentstatus = 'NOT_SHIPPED'; +UPDATE samples SET received=false WHERE shipmentstatus = 'NOT_SHIPPED' OR shipmentstatus = 'SHIPPED'; +ALTER TABLE samples DROP COLUMN shipmentstatus; +ALTER TABLE samples_history DROP COLUMN shipmentstatus; +ALTER TABLE cases_history DROP COLUMN contactofficer_id; + +INSERT INTO schema_version (version_number, comment) VALUES (57, 'Replace ShipmentStatus with shipped and received booleans'); \ No newline at end of file diff --git a/sormas-ear/pom.xml b/sormas-ear/pom.xml index 2ca20a23d1a..dfce45b6e4f 100644 --- a/sormas-ear/pom.xml +++ b/sormas-ear/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 0.2.0 + 0.3.0 ../sormas-base diff --git a/sormas-rest/pom.xml b/sormas-rest/pom.xml index 63fb515fbde..4a89011c3af 100644 --- a/sormas-rest/pom.xml +++ b/sormas-rest/pom.xml @@ -3,7 +3,7 @@ de.symeda.sormas sormas-base - 0.2.0 + 0.3.0 ../sormas-base diff --git a/sormas-ui/pom.xml b/sormas-ui/pom.xml index a21c07929b1..b54a868adbd 100644 --- a/sormas-ui/pom.xml +++ b/sormas-ui/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 0.2.0 + 0.3.0 ../sormas-base 4.0.0 diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java index ed051cf5dbd..11213eaa1b9 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseController.java @@ -226,14 +226,7 @@ public CommitDiscardWrapperComponent getCaseDataEditComponent(fina public void onCommit() { if (!caseEditForm.getFieldGroup().isModified()) { final CaseDataDto cazeDto = caseEditForm.getValue(); - final CaseDataDto currentCazeDto = findCase(cazeDto.getUuid()); saveCase(cazeDto); - - if (cazeDto.getDisease() != currentCazeDto.getDisease()) { - for (ContactDto contact : FacadeProvider.getContactFacade().getAllByCase(FacadeProvider.getCaseFacade().getReferenceByUuid(cazeDto.getUuid()))) { - FacadeProvider.getContactFacade().updateFollowUpUntilAndStatus(contact); - } - } } } }); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java index 8f7b64192dc..46f09be22de 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/caze/CaseDataForm.java @@ -8,6 +8,8 @@ import com.vaadin.data.validator.RegexpValidator; import com.vaadin.data.validator.StringLengthValidator; import com.vaadin.shared.ui.label.ContentMode; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.ComboBox; import com.vaadin.ui.Label; import com.vaadin.ui.NativeSelect; @@ -62,17 +64,14 @@ public class CaseDataForm extends AbstractEditForm { LayoutUtil.fluidRowLocs(CaseDataDto.EPID_NUMBER, CaseDataDto.DISEASE) + LayoutUtil.fluidRowLocs(CaseDataDto.REGION, CaseDataDto.DISTRICT) + LayoutUtil.fluidRowLocs(CaseDataDto.COMMUNITY, CaseDataDto.HEALTH_FACILITY) + - LayoutUtil.fluidRowLocs("", CaseDataDto.HEALTH_FACILITY_DETAILS)) + LayoutUtil.fluidRowLocs("", CaseDataDto.HEALTH_FACILITY_DETAILS) + + LayoutUtil.fluidRowLocs(CaseDataDto.SURVEILLANCE_OFFICER, "")) )+ LayoutUtil.loc(MEDICAL_INFORMATION_LOC) + LayoutUtil.fluidRow( LayoutUtil.fluidRowLocs(CaseDataDto.PREGNANT, "") + LayoutUtil.fluidRowLocs(CaseDataDto.MEASLES_VACCINATION, CaseDataDto.MEASLES_DOSES) + LayoutUtil.fluidRowLocs(CaseDataDto.MEASLES_VACCINATION_INFO_SOURCE, "") - )+ - LayoutUtil.h3(CssStyles.VSPACE3, "Responsible users")+ - LayoutUtil.divCss(CssStyles.VSPACE2, - LayoutUtil.fluidRowLocs(CaseDataDto.SURVEILLANCE_OFFICER, CaseDataDto.CONTACT_OFFICER) ); @@ -143,19 +142,14 @@ protected void addFields() { ComboBox surveillanceOfficerField = addField(CaseDataDto.SURVEILLANCE_OFFICER, ComboBox.class); surveillanceOfficerField.setNullSelectionAllowed(true); - ComboBox contactOfficerField = addField(CaseDataDto.CONTACT_OFFICER, ComboBox.class); - contactOfficerField.setNullSelectionAllowed(true); district.addValueChangeListener(e -> { List assignableSurveillanceOfficers = FacadeProvider.getUserFacade().getAssignableUsersByDistrict((DistrictReferenceDto) district.getValue(), false, UserRole.SURVEILLANCE_OFFICER); - List assignableContactOfficers = FacadeProvider.getUserFacade().getAssignableUsersByDistrict((DistrictReferenceDto) district.getValue(), false, UserRole.CONTACT_OFFICER); surveillanceOfficerField.removeAllItems(); surveillanceOfficerField.select(0); surveillanceOfficerField.addItems(assignableSurveillanceOfficers); - contactOfficerField.removeAllItems(); surveillanceOfficerField.select(0); - contactOfficerField.addItems(assignableContactOfficers); }); addField(CaseDataDto.PREGNANT, OptionGroup.class); @@ -246,7 +240,21 @@ private static class DiseaseChangeListener implements ValueChangeListener { public void valueChange(Property.ValueChangeEvent e) { if (diseaseField.getValue() != currentDisease) { - ConfirmationComponent confirmDiseaseChangeComponent = getConfirmDiseaseChangeComponent(diseaseField, currentDisease); + ConfirmationComponent confirmDiseaseChangeComponent = new ConfirmationComponent(false) { + private static final long serialVersionUID = 1L; + @Override + protected void onConfirm() { + diseaseField.removeValueChangeListener(DiseaseChangeListener.this); + } + @Override + protected void onCancel() { + diseaseField.setValue(currentDisease); + } + }; + confirmDiseaseChangeComponent.getConfirmButton().setCaption("Really change case disease?"); + confirmDiseaseChangeComponent.getCancelButton().setCaption("Cancel"); + confirmDiseaseChangeComponent.setMargin(true); + Window popupWindow = VaadinUiUtil.showPopupWindow(confirmDiseaseChangeComponent); CloseListener closeListener = new CloseListener() { @Override @@ -257,7 +265,6 @@ public void windowClose(CloseEvent e) { popupWindow.addCloseListener(closeListener); confirmDiseaseChangeComponent.addDoneListener(new DoneListener() { public void onDone() { - diseaseField.removeValueChangeListener(DiseaseChangeListener.this); popupWindow.removeCloseListener(closeListener); popupWindow.close(); } @@ -265,25 +272,5 @@ public void onDone() { popupWindow.setCaption("Change case disease"); } } - - private ConfirmationComponent getConfirmDiseaseChangeComponent(NativeSelect diseaseField, Disease currentDisease) { - ConfirmationComponent confirmDiseaseChangeComponent = new ConfirmationComponent(false) { - private static final long serialVersionUID = 1L; - @Override - protected void onConfirm() { - onDone(); - } - @Override - protected void onCancel() { - diseaseField.setValue(currentDisease); - onDone(); - } - }; - confirmDiseaseChangeComponent.getConfirmButton().setCaption("Really change case disease?"); - confirmDiseaseChangeComponent.getCancelButton().setCaption("Cancel"); - confirmDiseaseChangeComponent.setMargin(true); - return confirmDiseaseChangeComponent; - } - } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleController.java index 3e8d17dd10e..551118f4028 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleController.java @@ -5,52 +5,65 @@ import com.vaadin.navigator.Navigator; import com.vaadin.server.Sizeable.Unit; +import com.vaadin.shared.ui.label.ContentMode; +import com.vaadin.ui.Alignment; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Label; import com.vaadin.ui.Notification; import com.vaadin.ui.Notification.Type; +import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.Window; +import com.vaadin.ui.themes.ValoTheme; import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.caze.CaseReferenceDto; import de.symeda.sormas.api.sample.SampleDto; import de.symeda.sormas.api.sample.SampleFacade; import de.symeda.sormas.api.sample.SampleIndexDto; +import de.symeda.sormas.api.sample.SpecimenCondition; +import de.symeda.sormas.api.task.TaskContext; import de.symeda.sormas.api.user.UserDto; import de.symeda.sormas.api.utils.DataHelper; +import de.symeda.sormas.ui.ControllerProvider; import de.symeda.sormas.ui.SormasUI; import de.symeda.sormas.ui.login.LoginHelper; import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent; import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent.CommitListener; +import de.symeda.sormas.ui.utils.ConfirmationComponent; import de.symeda.sormas.ui.utils.VaadinUiUtil; public class SampleController { - + private SampleFacade sf = FacadeProvider.getSampleFacade(); - + public SampleController() { } - + public List getAllSamples() { UserDto user = LoginHelper.getCurrentUser(); return FacadeProvider.getSampleFacade().getIndexList(user.getUuid()); } - + public List getSamplesByCase(CaseReferenceDto caseRef) { return FacadeProvider.getSampleFacade().getIndexListByCase(caseRef); } - + public void registerViews(Navigator navigator) { navigator.addView(SamplesView.VIEW_NAME, SamplesView.class); navigator.addView(SampleDataView.VIEW_NAME, SampleDataView.class); } - + public void navigateToData(String sampleUuid) { String navigationState = SampleDataView.VIEW_NAME + "/" + sampleUuid; SormasUI.get().getNavigator().navigateTo(navigationState); } - + public void create(CaseReferenceDto caseRef, SampleGrid grid) { SampleCreateForm createForm = new SampleCreateForm(); createForm.setValue(createNewSample(caseRef)); final CommitDiscardWrapperComponent editView = new CommitDiscardWrapperComponent(createForm, createForm.getFieldGroup()); - + editView.addCommitListener(new CommitListener() { @Override public void onCommit() { @@ -61,41 +74,151 @@ public void onCommit() { } } }); - + VaadinUiUtil.showModalPopupWindow(editView, "Create new sample"); } - + + public void createReferral(SampleDto sample) { + SampleCreateForm createForm = new SampleCreateForm(); + SampleDto referralSample = createNewSample(sample.getAssociatedCase()); + referralSample.setSampleDateTime(sample.getSampleDateTime()); + referralSample.setSampleCode(sample.getSampleCode()); + referralSample.setSampleMaterial(sample.getSampleMaterial()); + referralSample.setSuggestedTypeOfTest(sample.getSuggestedTypeOfTest()); + createForm.setValue(referralSample); + final CommitDiscardWrapperComponent createView = new CommitDiscardWrapperComponent(createForm, createForm.getFieldGroup()); + + createView.addCommitListener(new CommitListener() { + @Override + public void onCommit() { + if (!createForm.getFieldGroup().isModified()) { + SampleDto newSample = createForm.getValue(); + FacadeProvider.getSampleFacade().saveSample(newSample); + sample.setReferredTo(FacadeProvider.getSampleFacade().getReferenceByUuid(newSample.getUuid())); + FacadeProvider.getSampleFacade().saveSample(sample); + navigateToData(newSample.getUuid()); + } + } + }); + + VaadinUiUtil.showModalPopupWindow(createView, "Refer sample to another laboratory"); + } + public CommitDiscardWrapperComponent getSampleEditComponent(final String sampleUuid) { SampleEditForm form = new SampleEditForm(); form.setWidth(form.getWidth() * 10/12, Unit.PIXELS); SampleDto dto = sf.getSampleByUuid(sampleUuid); form.setValue(dto); final CommitDiscardWrapperComponent editView = new CommitDiscardWrapperComponent(form, form.getFieldGroup()); - + editView.addCommitListener(new CommitListener() { @Override public void onCommit() { if (!form.getFieldGroup().isModified()) { SampleDto dto = form.getValue(); - dto = sf.saveSample(dto); - Notification.show("Sample data saved", Type.WARNING_MESSAGE); + SampleDto originalDto = sf.getSampleByUuid(dto.getUuid()); + sf.saveSample(dto); navigateToData(dto.getUuid()); + + if (dto.getSpecimenCondition() != originalDto.getSpecimenCondition() && + dto.getSpecimenCondition() == SpecimenCondition.NOT_ADEQUATE) { + requestSampleCollectionTaskCreation(dto, form); + } else { + Notification.show("Sample data saved", Type.WARNING_MESSAGE); + } } } }); - + + // Initialize 'Refer to another laboratory' button or link to referred sample + Button referOrLinkToOtherLabButton = new Button(); + referOrLinkToOtherLabButton.addStyleName(ValoTheme.BUTTON_LINK); + if (dto.getReferredTo() == null) { + referOrLinkToOtherLabButton.setCaption("Refer to another laboratory"); + referOrLinkToOtherLabButton.addClickListener(new ClickListener() { + private static final long serialVersionUID = 1L; + @Override + public void buttonClick(ClickEvent event) { + createReferral(dto); + } + }); + } else { + SampleDto referredDto = FacadeProvider.getSampleFacade().getSampleByUuid(dto.getReferredTo().getUuid()); + referOrLinkToOtherLabButton.setCaption("Referred to " + referredDto.getLab().toString()); + referOrLinkToOtherLabButton.addClickListener(new ClickListener() { + private static final long serialVersionUID = 1L; + @Override + public void buttonClick(ClickEvent event) { + navigateToData(dto.getReferredTo().getUuid()); + } + }); + } + + editView.getButtonsPanel().addComponentAsFirst(referOrLinkToOtherLabButton); + editView.getButtonsPanel().setComponentAlignment(referOrLinkToOtherLabButton, Alignment.BOTTOM_LEFT); + return editView; } - + + private void requestSampleCollectionTaskCreation(SampleDto dto, SampleEditForm form) { + VerticalLayout layout = new VerticalLayout(); + layout.setMargin(true); + + ConfirmationComponent requestTaskComponent = buildRequestTaskComponent(); + + Label description = new Label("You have set the specimen condition to not adequate.
Do you want to create a new sample collection task?"); + description.setContentMode(ContentMode.HTML); + description.setWidth(100, Unit.PERCENTAGE); + layout.addComponent(description); + layout.addComponent(requestTaskComponent); + layout.setComponentAlignment(requestTaskComponent, Alignment.BOTTOM_RIGHT); + layout.setSizeUndefined(); + layout.setSpacing(true); + + Window popupWindow = VaadinUiUtil.showPopupWindow(layout); + popupWindow.setSizeUndefined(); + popupWindow.setCaption("Create new task?"); + requestTaskComponent.getConfirmButton().addClickListener(new ClickListener() { + private static final long serialVersionUID = 1L; + @Override + public void buttonClick(ClickEvent event) { + popupWindow.close(); + ControllerProvider.getTaskController().createSampleCollectionTask(TaskContext.CASE, dto.getAssociatedCase(), dto); + } + }); + requestTaskComponent.getCancelButton().addClickListener(new ClickListener() { + private static final long serialVersionUID = 1L; + @Override + public void buttonClick(ClickEvent event) { + popupWindow.close(); + } + }); + } + private SampleDto createNewSample(CaseReferenceDto caseRef) { SampleDto sample = new SampleDto(); sample.setUuid(DataHelper.createUuid()); sample.setAssociatedCase(caseRef); sample.setReportingUser(LoginHelper.getCurrentUserAsReference()); sample.setReportDateTime(new Date()); - + return sample; - + + } + + private ConfirmationComponent buildRequestTaskComponent() { + ConfirmationComponent requestTaskComponent = new ConfirmationComponent(false) { + private static final long serialVersionUID = 1L; + @Override + protected void onConfirm() { + } + @Override + protected void onCancel() { + } + }; + requestTaskComponent.getConfirmButton().setCaption("Yes"); + requestTaskComponent.getCancelButton().setCaption("No"); + return requestTaskComponent; } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleCreateForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleCreateForm.java index b2af6f21593..b7afc485c1b 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleCreateForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleCreateForm.java @@ -3,9 +3,9 @@ import java.util.Arrays; import java.util.Date; +import com.vaadin.ui.CheckBox; import com.vaadin.ui.ComboBox; import com.vaadin.ui.DateField; -import com.vaadin.ui.OptionGroup; import com.vaadin.ui.TextArea; import com.vaadin.ui.TextField; @@ -14,7 +14,6 @@ import de.symeda.sormas.api.caze.CaseDataDto; import de.symeda.sormas.api.sample.SampleDto; import de.symeda.sormas.api.sample.SampleMaterial; -import de.symeda.sormas.api.sample.ShipmentStatus; import de.symeda.sormas.api.sample.SpecimenCondition; import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.ui.utils.AbstractEditForm; @@ -28,44 +27,21 @@ public class SampleCreateForm extends AbstractEditForm { private static final String HTML_LAYOUT = LayoutUtil.div( - LayoutUtil.fluidRowCss( - CssStyles.VSPACE4, - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.SAMPLE_CODE)), - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.LAB_SAMPLE_ID)) + LayoutUtil.div( + LayoutUtil.fluidRowLocs(SampleDto.SAMPLE_DATE_TIME, SampleDto.SAMPLE_CODE), + LayoutUtil.fluidRowLocs(SampleDto.SAMPLE_MATERIAL, SampleDto.SAMPLE_MATERIAL_TEXT), + LayoutUtil.fluidRowLocs(SampleDto.SAMPLE_SOURCE, ""), + LayoutUtil.fluidRowLocs(SampleDto.SUGGESTED_TYPE_OF_TEST, SampleDto.LAB) ), - LayoutUtil.fluidRowCss( - CssStyles.VSPACE4, - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.SAMPLE_DATE_TIME)), - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.SAMPLE_MATERIAL)), - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.SAMPLE_MATERIAL_TEXT)) + LayoutUtil.locCss(CssStyles.VSPACE_TOP_24, SampleDto.SHIPPED), + LayoutUtil.div( + LayoutUtil.fluidRowLocs(SampleDto.SHIPMENT_DATE, SampleDto.SHIPMENT_DETAILS) ), - LayoutUtil.fluidRow( - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.SAMPLE_SOURCE)) - ), - LayoutUtil.fluidRowCss( - CssStyles.VSPACE4, - LayoutUtil.twoOfThreeCol(LayoutUtil.loc(SampleDto.SHIPMENT_STATUS)), - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.SUGGESTED_TYPE_OF_TEST)) - ), - LayoutUtil.fluidRowCss( - CssStyles.VSPACE4, - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.SHIPMENT_DATE)), - LayoutUtil.twoOfThreeCol(LayoutUtil.loc(SampleDto.SHIPMENT_DETAILS)) - ), - LayoutUtil.fluidRowCss( - CssStyles.VSPACE4, - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.LAB)), - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.SPECIMEN_CONDITION)), - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.NO_TEST_POSSIBLE_REASON)) - ), - LayoutUtil.fluidRowCss( - CssStyles.VSPACE4, - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.RECEIVED_DATE)), - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.OTHER_LAB)) - ), - LayoutUtil.fluidRowCss( - CssStyles.VSPACE4, - LayoutUtil.loc(SampleDto.COMMENT) + LayoutUtil.locCss(CssStyles.VSPACE_TOP_24, SampleDto.RECEIVED), + LayoutUtil.div( + LayoutUtil.fluidRowLocs(SampleDto.RECEIVED_DATE, SampleDto.LAB_SAMPLE_ID), + LayoutUtil.fluidRowLocs(SampleDto.SPECIMEN_CONDITION, SampleDto.NO_TEST_POSSIBLE_REASON), + LayoutUtil.fluidRowLocs(SampleDto.COMMENT) ) ); @@ -77,63 +53,58 @@ public SampleCreateForm() { protected void addFields() { addField(SampleDto.SAMPLE_CODE, TextField.class); addField(SampleDto.LAB_SAMPLE_ID, TextField.class); - addField(SampleDto.SAMPLE_DATE_TIME, DateTimeField.class); - addField(SampleDto.REPORT_DATE_TIME, DateTimeField.class); - - addField(SampleDto.REPORTING_USER, ComboBox.class); addField(SampleDto.SAMPLE_MATERIAL, ComboBox.class); addField(SampleDto.SAMPLE_MATERIAL_TEXT, TextField.class); ComboBox sampleSource = addField(SampleDto.SAMPLE_SOURCE, ComboBox.class); DateField shipmentDate = addField(SampleDto.SHIPMENT_DATE, DateField.class); shipmentDate.setDateFormat(DateHelper.getShortDateFormat().toPattern()); addField(SampleDto.SHIPMENT_DETAILS, TextField.class); - OptionGroup shipmentStatus = addField(SampleDto.SHIPMENT_STATUS, OptionGroup.class); - addField(SampleDto.RECEIVED_DATE, DateField.class).setDateFormat(DateHelper.getShortDateFormat().toPattern()); + DateField receivedDate = addField(SampleDto.RECEIVED_DATE, DateField.class); + receivedDate.setDateFormat(DateHelper.getShortDateFormat().toPattern()); addField(SampleDto.SUGGESTED_TYPE_OF_TEST, ComboBox.class); ComboBox lab = addField(SampleDto.LAB, ComboBox.class); - ComboBox otherLab = addField(SampleDto.OTHER_LAB, ComboBox.class); + lab.addItems(FacadeProvider.getFacilityFacade().getAllLaboratories()); addField(SampleDto.SPECIMEN_CONDITION, ComboBox.class); addField(SampleDto.NO_TEST_POSSIBLE_REASON, TextField.class); addField(SampleDto.COMMENT, TextArea.class).setRows(2); - - lab.addItems(FacadeProvider.getFacilityFacade().getAllLaboratories()); - otherLab.addItems(FacadeProvider.getFacilityFacade().getAllLaboratories()); - - setReadOnly(true, SampleDto.REPORT_DATE_TIME, SampleDto.REPORTING_USER); + CheckBox shipped = addField(SampleDto.SHIPPED, CheckBox.class); + CheckBox received = addField(SampleDto.RECEIVED, CheckBox.class); FieldHelper.setVisibleWhen(getFieldGroup(), SampleDto.SAMPLE_MATERIAL_TEXT, SampleDto.SAMPLE_MATERIAL, Arrays.asList(SampleMaterial.OTHER), true); - FieldHelper.setVisibleWhen(getFieldGroup(), SampleDto.RECEIVED_DATE, SampleDto.SHIPMENT_STATUS, Arrays.asList(ShipmentStatus.RECEIVED), true); - FieldHelper.setVisibleWhen(getFieldGroup(), SampleDto.OTHER_LAB, SampleDto.SHIPMENT_STATUS, Arrays.asList(ShipmentStatus.REFERRED_OTHER_LAB), true); FieldHelper.setVisibleWhen(getFieldGroup(), SampleDto.NO_TEST_POSSIBLE_REASON, SampleDto.SPECIMEN_CONDITION, Arrays.asList(SpecimenCondition.NOT_ADEQUATE), true); - FieldHelper.setVisibleWhen(getFieldGroup(), Arrays.asList(SampleDto.SHIPMENT_DATE, SampleDto.SHIPMENT_DETAILS), SampleDto.SHIPMENT_STATUS, - Arrays.asList(ShipmentStatus.SHIPPED, ShipmentStatus.RECEIVED, ShipmentStatus.REFERRED_OTHER_LAB), true); FieldHelper.setRequiredWhen(getFieldGroup(), SampleDto.SAMPLE_MATERIAL, Arrays.asList(SampleDto.SAMPLE_MATERIAL_TEXT), Arrays.asList(SampleMaterial.OTHER)); - FieldHelper.setRequiredWhen(getFieldGroup(), SampleDto.SHIPMENT_STATUS, Arrays.asList(SampleDto.RECEIVED_DATE), Arrays.asList(ShipmentStatus.RECEIVED)); - FieldHelper.setRequiredWhen(getFieldGroup(), SampleDto.SHIPMENT_STATUS, Arrays.asList(SampleDto.OTHER_LAB), Arrays.asList(ShipmentStatus.REFERRED_OTHER_LAB)); FieldHelper.setRequiredWhen(getFieldGroup(), SampleDto.SPECIMEN_CONDITION, Arrays.asList(SampleDto.NO_TEST_POSSIBLE_REASON), Arrays.asList(SpecimenCondition.NOT_ADEQUATE)); - FieldHelper.setRequiredWhen(getFieldGroup(), SampleDto.SHIPMENT_STATUS, Arrays.asList(SampleDto.SHIPMENT_DATE), - Arrays.asList(ShipmentStatus.SHIPPED, ShipmentStatus.RECEIVED, ShipmentStatus.REFERRED_OTHER_LAB)); - FieldHelper.setRequiredWhen(getFieldGroup(), SampleDto.SHIPMENT_STATUS, Arrays.asList(SampleDto.SPECIMEN_CONDITION), Arrays.asList(ShipmentStatus.RECEIVED)); - setRequired(true, SampleDto.SAMPLE_DATE_TIME, SampleDto.REPORT_DATE_TIME, - SampleDto.REPORTING_USER, SampleDto.SAMPLE_MATERIAL, SampleDto.LAB, SampleDto.SHIPMENT_STATUS, - SampleDto.SHIPMENT_DATE); + setRequired(true, SampleDto.SAMPLE_DATE_TIME, SampleDto.SAMPLE_MATERIAL, SampleDto.LAB, SampleDto.SHIPMENT_DATE); addValueChangeListener(e -> { CaseDataDto caze = FacadeProvider.getCaseFacade().getCaseDataByUuid(getValue().getAssociatedCase().getUuid()); if (caze.getDisease() != Disease.AVIAN_INFLUENCA) { sampleSource.setVisible(false); } + + FieldHelper.setEnabledWhen(getFieldGroup(), shipped, Arrays.asList(true), Arrays.asList(SampleDto.SHIPMENT_DATE, SampleDto.SHIPMENT_DETAILS), true); + FieldHelper.setRequiredWhen(getFieldGroup(), shipped, Arrays.asList(SampleDto.SHIPMENT_DATE), Arrays.asList(true)); + FieldHelper.setRequiredWhen(getFieldGroup(), received, Arrays.asList(SampleDto.RECEIVED_DATE, SampleDto.SPECIMEN_CONDITION), Arrays.asList(true)); + FieldHelper.setEnabledWhen(getFieldGroup(), received, Arrays.asList(true), Arrays.asList(SampleDto.RECEIVED_DATE, SampleDto.LAB_SAMPLE_ID, SampleDto.SPECIMEN_CONDITION, SampleDto.NO_TEST_POSSIBLE_REASON), true); }); - shipmentStatus.addValueChangeListener(event -> { - if(event.getProperty().getValue() == ShipmentStatus.SHIPPED) { - if(shipmentDate.getValue() == null) { + shipped.addValueChangeListener(event -> { + if ((boolean) event.getProperty().getValue() == true) { + if (shipmentDate.getValue() == null) { shipmentDate.setValue(new Date()); } } }); + + received.addValueChangeListener(event -> { + if ((boolean) event.getProperty().getValue() == true) { + if (receivedDate.getValue() == null) { + receivedDate.setValue(new Date()); + } + } + }); } @Override diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleDataView.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleDataView.java index 130f12a7b56..669b97ae032 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleDataView.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleDataView.java @@ -7,7 +7,6 @@ import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.caze.CaseDataDto; import de.symeda.sormas.api.sample.SampleDto; -import de.symeda.sormas.api.sample.ShipmentStatus; import de.symeda.sormas.ui.ControllerProvider; import de.symeda.sormas.ui.caze.CaseInfoLayout; import de.symeda.sormas.ui.utils.CssStyles; @@ -39,7 +38,7 @@ public void enter(ViewChangeEvent event) { layout.addComponent(caseInfoLayout); addComponent(layout); - if (sampleDto.getShipmentStatus() != ShipmentStatus.NOT_SHIPPED && sampleDto.getShipmentStatus() != ShipmentStatus.SHIPPED) { + if (sampleDto.isReceived()) { SampleTestsComponent sampleTestsComponent = new SampleTestsComponent(getSampleRef()); sampleTestsComponent.addStyleName(CssStyles.SUBLIST_MARGIN); addComponent(sampleTestsComponent); diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleEditForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleEditForm.java index 1ba555b4bcc..76de7dff847 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleEditForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleEditForm.java @@ -3,24 +3,25 @@ import java.util.Arrays; import java.util.Date; -import com.vaadin.shared.ui.label.ContentMode; +import com.vaadin.ui.Button; +import com.vaadin.ui.CheckBox; import com.vaadin.ui.ComboBox; import com.vaadin.ui.DateField; import com.vaadin.ui.Label; -import com.vaadin.ui.OptionGroup; import com.vaadin.ui.TextArea; import com.vaadin.ui.TextField; +import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.FacadeProvider; -import de.symeda.sormas.api.I18nProperties; import de.symeda.sormas.api.caze.CaseDataDto; import de.symeda.sormas.api.sample.SampleDto; import de.symeda.sormas.api.sample.SampleMaterial; -import de.symeda.sormas.api.sample.ShipmentStatus; +import de.symeda.sormas.api.sample.SampleReferenceDto; import de.symeda.sormas.api.sample.SpecimenCondition; -import de.symeda.sormas.api.user.UserRole; import de.symeda.sormas.api.utils.DateHelper; +import de.symeda.sormas.ui.ControllerProvider; import de.symeda.sormas.ui.login.LoginHelper; import de.symeda.sormas.ui.utils.AbstractEditForm; import de.symeda.sormas.ui.utils.CssStyles; @@ -30,144 +31,129 @@ @SuppressWarnings("serial") public class SampleEditForm extends AbstractEditForm { - - private static final String REPORT_INFO = "reportInfo"; + private static final String REPORT_INFORMATION_LOC = "reportInformationLoc"; + private static final String HTML_LAYOUT = - LayoutUtil.h3(CssStyles.VSPACE3, "Laboratory sample") + + LayoutUtil.h3(null, "Laboratory sample") + LayoutUtil.div( - LayoutUtil.fluidRowCss(CssStyles.VSPACE4, - LayoutUtil.div( - LayoutUtil.fluidRow( - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.SAMPLE_CODE)), - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.LAB_SAMPLE_ID)), - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(REPORT_INFO)) - ), - LayoutUtil.fluidRow( - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.SAMPLE_DATE_TIME)), - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.SAMPLE_MATERIAL)), - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.SAMPLE_MATERIAL_TEXT)) - ), - LayoutUtil.fluidRow( - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.SAMPLE_SOURCE)) - ), - LayoutUtil.fluidRow( - LayoutUtil.twoOfThreeCol(LayoutUtil.loc(SampleDto.SHIPMENT_STATUS)), - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.SUGGESTED_TYPE_OF_TEST)) - ), - LayoutUtil.fluidRow( - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.SHIPMENT_DATE)), - LayoutUtil.twoOfThreeCol(LayoutUtil.loc(SampleDto.SHIPMENT_DETAILS)) - ), - LayoutUtil.fluidRow( - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.LAB)), - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.SPECIMEN_CONDITION)), - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.NO_TEST_POSSIBLE_REASON)) - ), - LayoutUtil.fluidRow( - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.RECEIVED_DATE)), - LayoutUtil.oneOfThreeCol(LayoutUtil.loc(SampleDto.OTHER_LAB)) - ), - LayoutUtil.fluidRowCss( - CssStyles.VSPACE4, - LayoutUtil.loc(SampleDto.COMMENT) - ) - ) - ) + LayoutUtil.locCss(CssStyles.VSPACE2, REPORT_INFORMATION_LOC) + + LayoutUtil.div( + LayoutUtil.fluidRowLocs(SampleDto.SAMPLE_DATE_TIME, SampleDto.SAMPLE_CODE), + LayoutUtil.fluidRowLocs(SampleDto.SAMPLE_MATERIAL, SampleDto.SAMPLE_MATERIAL_TEXT), + LayoutUtil.fluidRowLocs(SampleDto.SAMPLE_SOURCE, ""), + LayoutUtil.fluidRowLocs(SampleDto.SUGGESTED_TYPE_OF_TEST, SampleDto.LAB) + ), + LayoutUtil.locCss(CssStyles.VSPACE_TOP_24, SampleDto.SHIPPED), + LayoutUtil.div( + LayoutUtil.fluidRowLocs(SampleDto.SHIPMENT_DATE, SampleDto.SHIPMENT_DETAILS) + ), + LayoutUtil.locCss(CssStyles.VSPACE_TOP_24, SampleDto.RECEIVED), + LayoutUtil.div( + LayoutUtil.fluidRowLocs(SampleDto.RECEIVED_DATE, SampleDto.LAB_SAMPLE_ID), + LayoutUtil.fluidRowLocs(SampleDto.SPECIMEN_CONDITION, SampleDto.NO_TEST_POSSIBLE_REASON), + LayoutUtil.fluidRowLocs(SampleDto.COMMENT) + ) ); - - private Label reportInfoLabel; - + public SampleEditForm() { super(SampleDto.class, SampleDto.I18N_PREFIX); } - + @Override protected void addFields() { addField(SampleDto.SAMPLE_CODE, TextField.class); addField(SampleDto.LAB_SAMPLE_ID, TextField.class); - - DateTimeField sampleDate = addField(SampleDto.SAMPLE_DATE_TIME, DateTimeField.class); - addField(SampleDto.REPORT_DATE_TIME, DateTimeField.class); - - addField(SampleDto.REPORTING_USER, ComboBox.class); + addField(SampleDto.SAMPLE_DATE_TIME, DateTimeField.class); addField(SampleDto.SAMPLE_MATERIAL, ComboBox.class); addField(SampleDto.SAMPLE_MATERIAL_TEXT, TextField.class); ComboBox sampleSource = addField(SampleDto.SAMPLE_SOURCE, ComboBox.class); DateField shipmentDate = addField(SampleDto.SHIPMENT_DATE, DateField.class); shipmentDate.setDateFormat(DateHelper.getShortDateFormat().toPattern()); - addField(SampleDto.SHIPMENT_DETAILS, TextField.class); - OptionGroup shipmentStatus = addField(SampleDto.SHIPMENT_STATUS, OptionGroup.class); + addField(SampleDto.SHIPMENT_DETAILS, TextField.class); addField(SampleDto.SUGGESTED_TYPE_OF_TEST, ComboBox.class); - addField(SampleDto.RECEIVED_DATE, DateField.class).setDateFormat(DateHelper.getShortDateFormat().toPattern()); + DateField receivedDate = addField(SampleDto.RECEIVED_DATE, DateField.class); + receivedDate.setDateFormat(DateHelper.getShortDateFormat().toPattern()); ComboBox lab = addField(SampleDto.LAB, ComboBox.class); - ComboBox otherLab = addField(SampleDto.OTHER_LAB, ComboBox.class); + lab.addItems(FacadeProvider.getFacilityFacade().getAllLaboratories()); addField(SampleDto.SPECIMEN_CONDITION, ComboBox.class); addField(SampleDto.NO_TEST_POSSIBLE_REASON, TextField.class); addField(SampleDto.COMMENT, TextArea.class).setRows(2); - - lab.addItems(FacadeProvider.getFacilityFacade().getAllLaboratories()); - otherLab.addItems(FacadeProvider.getFacilityFacade().getAllLaboratories()); - - setReadOnly(true, SampleDto.REPORT_DATE_TIME, SampleDto.REPORTING_USER); - + CheckBox shipped = addField(SampleDto.SHIPPED, CheckBox.class); + CheckBox received = addField(SampleDto.RECEIVED, CheckBox.class); + FieldHelper.setVisibleWhen(getFieldGroup(), SampleDto.SAMPLE_MATERIAL_TEXT, SampleDto.SAMPLE_MATERIAL, Arrays.asList(SampleMaterial.OTHER), true); - FieldHelper.setVisibleWhen(getFieldGroup(), SampleDto.RECEIVED_DATE, SampleDto.SHIPMENT_STATUS, Arrays.asList(ShipmentStatus.RECEIVED), true); - FieldHelper.setVisibleWhen(getFieldGroup(), SampleDto.OTHER_LAB, SampleDto.SHIPMENT_STATUS, Arrays.asList(ShipmentStatus.REFERRED_OTHER_LAB), true); FieldHelper.setVisibleWhen(getFieldGroup(), SampleDto.NO_TEST_POSSIBLE_REASON, SampleDto.SPECIMEN_CONDITION, Arrays.asList(SpecimenCondition.NOT_ADEQUATE), true); - FieldHelper.setVisibleWhen(getFieldGroup(), Arrays.asList(SampleDto.SHIPMENT_DATE, SampleDto.SHIPMENT_DETAILS), SampleDto.SHIPMENT_STATUS, - Arrays.asList(ShipmentStatus.SHIPPED, ShipmentStatus.RECEIVED, ShipmentStatus.REFERRED_OTHER_LAB), true); FieldHelper.setRequiredWhen(getFieldGroup(), SampleDto.SAMPLE_MATERIAL, Arrays.asList(SampleDto.SAMPLE_MATERIAL_TEXT), Arrays.asList(SampleMaterial.OTHER)); - FieldHelper.setRequiredWhen(getFieldGroup(), SampleDto.SHIPMENT_STATUS, Arrays.asList(SampleDto.RECEIVED_DATE), Arrays.asList(ShipmentStatus.RECEIVED)); - FieldHelper.setRequiredWhen(getFieldGroup(), SampleDto.SHIPMENT_STATUS, Arrays.asList(SampleDto.OTHER_LAB), Arrays.asList(ShipmentStatus.REFERRED_OTHER_LAB)); FieldHelper.setRequiredWhen(getFieldGroup(), SampleDto.SPECIMEN_CONDITION, Arrays.asList(SampleDto.NO_TEST_POSSIBLE_REASON), Arrays.asList(SpecimenCondition.NOT_ADEQUATE)); - FieldHelper.setRequiredWhen(getFieldGroup(), SampleDto.SHIPMENT_STATUS, Arrays.asList(SampleDto.SHIPMENT_DATE), - Arrays.asList(ShipmentStatus.SHIPPED, ShipmentStatus.RECEIVED, ShipmentStatus.REFERRED_OTHER_LAB)); - FieldHelper.setRequiredWhen(getFieldGroup(), SampleDto.SHIPMENT_STATUS, Arrays.asList(SampleDto.SPECIMEN_CONDITION), Arrays.asList(ShipmentStatus.RECEIVED)); - - setRequired(true, SampleDto.SAMPLE_DATE_TIME, SampleDto.REPORT_DATE_TIME, - SampleDto.REPORTING_USER, SampleDto.SAMPLE_MATERIAL, SampleDto.LAB, SampleDto.SHIPMENT_STATUS, - SampleDto.SHIPMENT_DATE); - - reportInfoLabel = new Label(); - reportInfoLabel.setContentMode(ContentMode.HTML); - reportInfoLabel.setCaption(I18nProperties.getPrefixFieldCaption(SampleDto.I18N_PREFIX, REPORT_INFO)); - getContent().addComponent(reportInfoLabel, REPORT_INFO); - + addValueChangeListener(e -> { - updateReportInfo(); CaseDataDto caze = FacadeProvider.getCaseFacade().getCaseDataByUuid(getValue().getAssociatedCase().getUuid()); + + FieldHelper.setRequiredWhen(getFieldGroup(), received, Arrays.asList(SampleDto.RECEIVED_DATE, SampleDto.SPECIMEN_CONDITION), Arrays.asList(true)); + FieldHelper.setEnabledWhen(getFieldGroup(), received, Arrays.asList(true), Arrays.asList(SampleDto.RECEIVED_DATE, SampleDto.LAB_SAMPLE_ID, SampleDto.SPECIMEN_CONDITION, SampleDto.NO_TEST_POSSIBLE_REASON), true); + if (caze.getDisease() != Disease.AVIAN_INFLUENCA) { sampleSource.setVisible(false); } - if ((LoginHelper.getCurrentUser().getUserRoles().contains(UserRole.LAB_USER)) && getValue().getShipmentStatus() != ShipmentStatus.NOT_SHIPPED) { - shipmentStatus.setItemEnabled(ShipmentStatus.NOT_SHIPPED, false); - shipmentStatus.setItemEnabled(ShipmentStatus.SHIPPED, false); - shipmentDate.setEnabled(false); - sampleDate.setEnabled(false); + if ((LoginHelper.getCurrentUser().getUuid().equals(getValue().getReportingUser().getUuid()))) { + FieldHelper.setEnabledWhen(getFieldGroup(), shipped, Arrays.asList(true), Arrays.asList(SampleDto.SHIPMENT_DATE, SampleDto.SHIPMENT_DETAILS), true); + FieldHelper.setRequiredWhen(getFieldGroup(), shipped, Arrays.asList(SampleDto.SHIPMENT_DATE), Arrays.asList(true)); + setRequired(true, SampleDto.SAMPLE_DATE_TIME, SampleDto.SAMPLE_MATERIAL, SampleDto.LAB); + } else { + getField(SampleDto.SAMPLE_DATE_TIME).setEnabled(false); + getField(SampleDto.SAMPLE_CODE).setEnabled(false); + getField(SampleDto.SAMPLE_MATERIAL).setEnabled(false); + getField(SampleDto.SAMPLE_MATERIAL_TEXT).setEnabled(false); + getField(SampleDto.SUGGESTED_TYPE_OF_TEST).setEnabled(false); + getField(SampleDto.LAB).setEnabled(false); + getField(SampleDto.SHIPPED).setEnabled(false); + getField(SampleDto.SHIPMENT_DATE).setEnabled(false); + getField(SampleDto.SHIPMENT_DETAILS).setEnabled(false); + getField(SampleDto.SAMPLE_SOURCE).setEnabled(false); } - }); - - shipmentStatus.addValueChangeListener(event -> { - if(event.getProperty().getValue() == ShipmentStatus.SHIPPED) { - if(shipmentDate.getValue() == null) { - shipmentDate.setValue(new Date()); + + shipped.addValueChangeListener(event -> { + if ((boolean) event.getProperty().getValue() == true) { + if (shipmentDate.getValue() == null) { + shipmentDate.setValue(new Date()); + } } + }); + + received.addValueChangeListener(event -> { + if ((boolean) event.getProperty().getValue() == true) { + if (receivedDate.getValue() == null) { + receivedDate.setValue(new Date()); + } + } + }); + + // Initialize referral and report information + VerticalLayout reportInfoLayout = new VerticalLayout(); + + String reportInfoText = "Reported on " + DateHelper.formatDateTime(getValue().getReportDateTime()) + " by " + getValue().getReportingUser().toString(); + Label reportInfoLabel = new Label(reportInfoText); + reportInfoLabel.setEnabled(false); + reportInfoLayout.addComponent(reportInfoLabel); + + SampleReferenceDto referredFromRef = FacadeProvider.getSampleFacade().getReferredFrom(getValue().getUuid()); + if (referredFromRef != null) { + SampleDto referredFrom = FacadeProvider.getSampleFacade().getSampleByUuid(referredFromRef.getUuid()); + Button referredButton = new Button("Referred from " + referredFrom.getLab().toString()); + referredButton.addStyleName(ValoTheme.BUTTON_LINK); + referredButton.addStyleName(CssStyles.NO_MARGIN); + referredButton.addClickListener(s -> ControllerProvider.getSampleController().navigateToData(referredFrom.getUuid())); + reportInfoLayout.addComponent(referredButton); } + + getContent().addComponent(reportInfoLayout, REPORT_INFORMATION_LOC); }); } - - private void updateReportInfo() { - SampleDto sampleDto = getValue(); - StringBuilder sb = new StringBuilder(); - sb.append(DateHelper.formatShortDateTime(sampleDto.getReportDateTime()) + "
"); - sb.append(sampleDto.getReportingUser().toString()); - reportInfoLabel.setValue(sb.toString()); - } - + @Override protected String createHtmlLayout() { return HTML_LAYOUT; } - + } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleGrid.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleGrid.java index c5013e73885..d9f66db7c98 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleGrid.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleGrid.java @@ -9,6 +9,7 @@ import com.vaadin.data.util.MethodProperty; import com.vaadin.data.util.PropertyValueGenerator; import com.vaadin.data.util.filter.Compare.Equal; +import com.vaadin.data.util.filter.Not; import com.vaadin.data.util.filter.Or; import com.vaadin.data.util.filter.SimpleStringFilter; import com.vaadin.ui.Grid; @@ -20,12 +21,12 @@ import de.symeda.sormas.api.facility.FacilityReferenceDto; import de.symeda.sormas.api.region.DistrictReferenceDto; import de.symeda.sormas.api.sample.SampleIndexDto; -import de.symeda.sormas.api.sample.ShipmentStatus; import de.symeda.sormas.api.sample.SpecimenCondition; import de.symeda.sormas.api.user.UserRole; import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.ui.ControllerProvider; import de.symeda.sormas.ui.login.LoginHelper; +import de.symeda.sormas.ui.utils.BooleanRenderer; @SuppressWarnings("serial") public class SampleGrid extends Grid { @@ -74,12 +75,14 @@ public Class getType() { } }); - setColumns(SampleIndexDto.SAMPLE_CODE, SampleIndexDto.LAB_SAMPLE_ID, SampleIndexDto.SHIPMENT_STATUS, SampleIndexDto.ASSOCIATED_CASE, DISEASE_SHORT, - SampleIndexDto.LGA, SampleIndexDto.SHIPMENT_DATE, SampleIndexDto.RECEIVED_DATE, SampleIndexDto.LAB, SampleIndexDto.SAMPLE_MATERIAL, - SampleIndexDto.LAB_USER, SampleIndexDto.TEST_TYPE, TEST_RESULT_GEN); + setColumns(SampleIndexDto.SAMPLE_CODE, SampleIndexDto.LAB_SAMPLE_ID, SampleIndexDto.ASSOCIATED_CASE, DISEASE_SHORT, + SampleIndexDto.LGA, SampleIndexDto.SHIPPED, SampleIndexDto.RECEIVED, SampleIndexDto.SHIPMENT_DATE, SampleIndexDto.RECEIVED_DATE, SampleIndexDto.LAB, + SampleIndexDto.SAMPLE_MATERIAL, SampleIndexDto.LAB_USER, SampleIndexDto.TEST_TYPE, TEST_RESULT_GEN); getColumn(SampleIndexDto.SHIPMENT_DATE).setRenderer(new DateRenderer(DateHelper.getDateFormat())); getColumn(SampleIndexDto.RECEIVED_DATE).setRenderer(new DateRenderer(DateHelper.getDateFormat())); + getColumn(SampleIndexDto.SHIPPED).setRenderer(new BooleanRenderer()); + getColumn(SampleIndexDto.RECEIVED).setRenderer(new BooleanRenderer()); getColumn(SampleIndexDto.LAB).setMaximumWidth(200); for(Column column : getColumns()) { @@ -104,17 +107,42 @@ public SampleGrid(CaseReferenceDto caseRef) { removeColumn(SampleIndexDto.ASSOCIATED_CASE); removeColumn(DISEASE_SHORT); removeColumn(SampleIndexDto.LGA); - setShipmentStatusFilter(null); this.caseRef = caseRef; reload(); } - public void setShipmentStatusFilter(ShipmentStatus shipmentStatus) { - getContainer().removeContainerFilters(SampleIndexDto.SHIPMENT_STATUS); - if(shipmentStatus != null) { - Equal filter = new Equal(SampleIndexDto.SHIPMENT_STATUS, shipmentStatus); - getContainer().addContainerFilter(filter); - } + public void filterForNotShipped() { + clearShipmentFilters(); + Equal shippedFilter = new Equal(SampleIndexDto.SHIPPED, false); + Equal receivedFilter = new Equal(SampleIndexDto.RECEIVED, false); + Equal referredFilter = new Equal(SampleIndexDto.REFERRED_TO, null); + getContainer().addContainerFilter(shippedFilter); + getContainer().addContainerFilter(receivedFilter); + getContainer().addContainerFilter(referredFilter); + } + + public void filterForShipped() { + clearShipmentFilters(); + Equal shippedFilter = new Equal(SampleIndexDto.SHIPPED, true); + Equal receivedFilter = new Equal(SampleIndexDto.RECEIVED, false); + Equal referredFilter = new Equal(SampleIndexDto.REFERRED_TO, null); + getContainer().addContainerFilter(shippedFilter); + getContainer().addContainerFilter(receivedFilter); + getContainer().addContainerFilter(referredFilter); + } + + public void filterForReceived() { + clearShipmentFilters(); + Equal receivedFilter = new Equal(SampleIndexDto.RECEIVED, true); + Equal referredFilter = new Equal(SampleIndexDto.REFERRED_TO, null); + getContainer().addContainerFilter(receivedFilter); + getContainer().addContainerFilter(referredFilter); + } + + public void filterForReferred() { + clearShipmentFilters(); + Not referredFilter = new Not(new Equal(SampleIndexDto.REFERRED_TO, null)); + getContainer().addContainerFilter(referredFilter); } public void setDistrictFilter(DistrictReferenceDto district) { @@ -184,4 +212,10 @@ public void remove(SampleIndexDto sample) { getContainer().removeItem(sample); } + public void clearShipmentFilters() { + getContainer().removeContainerFilters(SampleIndexDto.SHIPPED); + getContainer().removeContainerFilters(SampleIndexDto.RECEIVED); + getContainer().removeContainerFilters(SampleIndexDto.REFERRED_TO); + } + } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleListComponent.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleListComponent.java index e104f864716..01e994d0914 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleListComponent.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/SampleListComponent.java @@ -19,7 +19,6 @@ import de.symeda.sormas.api.facility.FacilityReferenceDto; import de.symeda.sormas.api.region.DistrictReferenceDto; import de.symeda.sormas.api.sample.SampleIndexDto; -import de.symeda.sormas.api.sample.ShipmentStatus; import de.symeda.sormas.api.user.UserDto; import de.symeda.sormas.ui.ControllerProvider; import de.symeda.sormas.ui.login.LoginHelper; @@ -31,100 +30,114 @@ public class SampleListComponent extends AbstractView { public static final String LGA = "lga"; public static final String SEARCH_FIELD = "searchField"; - + private SampleGrid grid; - + private VerticalLayout gridLayout; - + public SampleListComponent() { setSizeFull(); addStyleName("crud-view"); - + grid = new SampleGrid(); - + gridLayout = new VerticalLayout(); gridLayout.addComponent(createTopBar()); gridLayout.addComponent(createFilterBar()); gridLayout.addComponent(grid); - + styleGridLayout(gridLayout); gridLayout.setMargin(true); - + addComponent(gridLayout); } - + public SampleListComponent(CaseReferenceDto caseRef) { setSizeFull(); addStyleName("crud-view"); - + grid = new SampleGrid(caseRef); grid.setHeightMode(HeightMode.ROW); - + gridLayout = new VerticalLayout(); gridLayout.addComponent(createTopBarForCase(caseRef)); gridLayout.addComponent(grid); - + gridLayout.setMargin(new MarginInfo(true, false, false, false)); styleGridLayout(gridLayout); - + addComponent(gridLayout); } - + public HorizontalLayout createTopBar() { HorizontalLayout topLayout = new HorizontalLayout(); topLayout.setSpacing(true); topLayout.setWidth(100, Unit.PERCENTAGE); topLayout.addStyleName(CssStyles.VSPACE3); - + Label header = new Label("Laboratory samples"); header.setSizeUndefined(); CssStyles.style(header, CssStyles.H2, CssStyles.NO_MARGIN); topLayout.addComponent(header); - + HorizontalLayout buttonFilterLayout = new HorizontalLayout(); { - Button statusAll = new Button("all", e -> grid.setShipmentStatusFilter(null)); + Button statusAll = new Button("all", e -> grid.clearShipmentFilters()); statusAll.setStyleName(ValoTheme.BUTTON_LINK); buttonFilterLayout.addComponent(statusAll); - for(ShipmentStatus status : ShipmentStatus.values()) { - Button statusButton = new Button(status.toString(), e -> grid.setShipmentStatusFilter(status)); - statusButton.setStyleName(ValoTheme.BUTTON_LINK); - buttonFilterLayout.addComponent(statusButton); - } + Button notShippedButton = new Button("not shipped", e -> grid.filterForNotShipped()); + notShippedButton.setStyleName(ValoTheme.BUTTON_LINK); + buttonFilterLayout.addComponent(notShippedButton); + Button shippedButton = new Button("shipped", e -> grid.filterForShipped()); + shippedButton.setStyleName(ValoTheme.BUTTON_LINK); + buttonFilterLayout.addComponent(shippedButton); + Button receivedButton = new Button("received", e -> grid.filterForReceived()); + receivedButton.setStyleName(ValoTheme.BUTTON_LINK); + buttonFilterLayout.addComponent(receivedButton); + Button referredButton = new Button("referred to other lab", e -> grid.filterForReferred()); + referredButton.setStyleName(ValoTheme.BUTTON_LINK); + buttonFilterLayout.addComponent(referredButton); } - + topLayout.addComponent(buttonFilterLayout); topLayout.setExpandRatio(buttonFilterLayout, 1); - + return topLayout; } - + public HorizontalLayout createTopBarForCase(CaseReferenceDto caseRef) { HorizontalLayout topLayout = new HorizontalLayout(); topLayout.setSpacing(true); topLayout.setWidth(100, Unit.PERCENTAGE); topLayout.addStyleName(CssStyles.VSPACE3); - + Label header = new Label("Laboratory samples"); header.setSizeUndefined(); CssStyles.style(header, CssStyles.H3, CssStyles.NO_MARGIN, CssStyles.SUBLIST_PADDING); topLayout.addComponent(header); - + HorizontalLayout buttonFilterLayout = new HorizontalLayout(); { - Button statusAll = new Button("all", e -> grid.setShipmentStatusFilter(null)); + Button statusAll = new Button("all", e -> grid.clearShipmentFilters()); statusAll.setStyleName(ValoTheme.BUTTON_LINK); buttonFilterLayout.addComponent(statusAll); - - for(ShipmentStatus status : ShipmentStatus.values()) { - Button statusButton = new Button(status.toString(), e -> grid.setShipmentStatusFilter(status)); - statusButton.setStyleName(ValoTheme.BUTTON_LINK); - buttonFilterLayout.addComponent(statusButton); - } + + Button notShippedButton = new Button("not shipped", e -> grid.filterForNotShipped()); + notShippedButton.setStyleName(ValoTheme.BUTTON_LINK); + buttonFilterLayout.addComponent(notShippedButton); + Button shippedButton = new Button("shipped", e -> grid.filterForShipped()); + shippedButton.setStyleName(ValoTheme.BUTTON_LINK); + buttonFilterLayout.addComponent(shippedButton); + Button receivedButton = new Button("received", e -> grid.filterForReceived()); + receivedButton.setStyleName(ValoTheme.BUTTON_LINK); + buttonFilterLayout.addComponent(receivedButton); + Button referredButton = new Button("referred to other lab", e -> grid.filterForReferred()); + referredButton.setStyleName(ValoTheme.BUTTON_LINK); + buttonFilterLayout.addComponent(referredButton); } topLayout.addComponent(buttonFilterLayout); - + Button createButton = new Button("New sample"); createButton.addStyleName(ValoTheme.BUTTON_PRIMARY); createButton.setIcon(FontAwesome.PLUS_CIRCLE); @@ -132,52 +145,52 @@ public HorizontalLayout createTopBarForCase(CaseReferenceDto caseRef) { topLayout.addComponent(createButton); topLayout.setComponentAlignment(createButton, Alignment.MIDDLE_RIGHT); topLayout.setExpandRatio(createButton, 1); - + return topLayout; } - + public HorizontalLayout createFilterBar() { HorizontalLayout filterLayout = new HorizontalLayout(); filterLayout.setSpacing(true); filterLayout.setSizeUndefined(); filterLayout.addStyleName(CssStyles.VSPACE3); - UserDto user = LoginHelper.getCurrentUser(); - if(user.getRegion() != null) { + UserDto user = LoginHelper.getCurrentUser(); + if(user.getRegion() != null) { ComboBox districtFilter = new ComboBox(); districtFilter.setWidth(200, Unit.PIXELS); districtFilter.setInputPrompt(I18nProperties.getPrefixFieldCaption(SampleIndexDto.I18N_PREFIX, LGA)); districtFilter.addItems(FacadeProvider.getDistrictFacade().getAllByRegion(user.getRegion().getUuid())); districtFilter.addValueChangeListener(e->grid.setDistrictFilter(((DistrictReferenceDto)e.getProperty().getValue()))); filterLayout.addComponent(districtFilter); - } - + } + ComboBox labFilter = new ComboBox(); labFilter.setWidth(200, Unit.PIXELS); labFilter.setInputPrompt(I18nProperties.getPrefixFieldCaption(SampleIndexDto.I18N_PREFIX, SampleIndexDto.LAB)); labFilter.addItems(FacadeProvider.getFacilityFacade().getAllLaboratories()); labFilter.addValueChangeListener(e->grid.setLabFilter(((FacilityReferenceDto)e.getProperty().getValue()))); filterLayout.addComponent(labFilter); - + TextField searchField = new TextField(); searchField.setWidth(200, Unit.PIXELS); searchField.setInputPrompt(I18nProperties.getPrefixFieldCaption(SampleIndexDto.I18N_PREFIX, SEARCH_FIELD)); searchField.addTextChangeListener(e->grid.filterByText(e.getText())); filterLayout.addComponent(searchField); - + return filterLayout; } - + @Override public void enter(ViewChangeEvent event) { grid.reload(); } - + private void styleGridLayout(VerticalLayout gridLayout) { gridLayout.setSpacing(false); gridLayout.setSizeFull(); gridLayout.setExpandRatio(grid, 1); gridLayout.setStyleName("crud-main-layout"); } - + } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java index ff3b04f86c0..65d1a0f8bb0 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/symptoms/SymptomsForm.java @@ -332,7 +332,7 @@ public void valueChange(com.vaadin.data.Property.ValueChangeEvent event) { * @return */ @SuppressWarnings("rawtypes") - private boolean isAnySymptomSetToYes(FieldGroup fieldGroup, List sourcePropertyIds, + public boolean isAnySymptomSetToYes(FieldGroup fieldGroup, List sourcePropertyIds, List sourceValues) { for(Object sourcePropertyId : sourcePropertyIds) { @@ -362,4 +362,8 @@ private void addListenerForOnsetSymptom(ComboBox onsetSymptom) { }); } } + + public List getUnconditionalSymptomFieldIds() { + return unconditionalSymptomFieldIds; + } } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/task/TaskController.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/task/TaskController.java index f9fe8ca714c..ffeae4497fb 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/task/TaskController.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/task/TaskController.java @@ -2,23 +2,27 @@ import java.util.Collections; import java.util.List; +import java.util.function.Consumer; import de.symeda.sormas.api.FacadeProvider; import de.symeda.sormas.api.ReferenceDto; import de.symeda.sormas.api.caze.CaseReferenceDto; import de.symeda.sormas.api.contact.ContactReferenceDto; import de.symeda.sormas.api.event.EventReferenceDto; +import de.symeda.sormas.api.sample.SampleDto; import de.symeda.sormas.api.task.TaskContext; import de.symeda.sormas.api.task.TaskDto; import de.symeda.sormas.api.task.TaskHelper; import de.symeda.sormas.api.task.TaskPriority; import de.symeda.sormas.api.task.TaskStatus; +import de.symeda.sormas.api.task.TaskType; import de.symeda.sormas.api.user.UserDto; import de.symeda.sormas.api.user.UserReferenceDto; import de.symeda.sormas.api.utils.DataHelper; import de.symeda.sormas.ui.login.LoginHelper; import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent; import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent.CommitListener; +import de.symeda.sormas.ui.utils.CommitDiscardWrapperComponent.DiscardListener; import de.symeda.sormas.ui.utils.VaadinUiUtil; public class TaskController { @@ -64,6 +68,28 @@ public void onCommit() { VaadinUiUtil.showModalPopupWindow(editView, "Create new task"); } + + public void createSampleCollectionTask(TaskContext context, ReferenceDto entityRef, SampleDto sample) { + TaskEditForm createForm = new TaskEditForm(); + TaskDto taskDto = createNewTask(context, entityRef); + taskDto.setTaskType(TaskType.SAMPLE_COLLECTION); + taskDto.setCreatorComment(sample.getNoTestPossibleReason()); + taskDto.setAssigneeUser(sample.getReportingUser()); + createForm.setValue(taskDto); + + final CommitDiscardWrapperComponent createView = new CommitDiscardWrapperComponent(createForm, createForm.getFieldGroup()); + createView.addCommitListener(new CommitListener() { + @Override + public void onCommit() { + if (!createForm.getFieldGroup().isModified()) { + TaskDto dto = createForm.getValue(); + FacadeProvider.getTaskFacade().saveTask(dto); + } + } + }); + + VaadinUiUtil.showModalPopupWindow(createView, "Create new task"); + } public void edit(TaskDto dto, TaskGrid grid) { // get fresh data diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/CssStyles.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/CssStyles.java index 257ac210433..12abade33e3 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/CssStyles.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/CssStyles.java @@ -25,6 +25,7 @@ public final class CssStyles { public static final String VSPACE5 = "vspace5"; public static final String VSPACE_NO_FILTERS = "vspace-no-filters"; public static final String VSPACETOP3 = "vspacetop3"; + public static final String VSPACE_TOP_24 = "vspace-top-24"; public static final String SELECTABLE = "selectable"; diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldHelper.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldHelper.java index cd42d947626..fffad8d78dc 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldHelper.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldHelper.java @@ -102,11 +102,16 @@ public static void setVisibleWhen(final FieldGroup fieldGroup, List targ }); } - @SuppressWarnings("rawtypes") public static void setRequiredWhen(FieldGroup fieldGroup, Object sourcePropertyId, List targetPropertyIds, final List sourceValues) { - Field sourceField = fieldGroup.getField(sourcePropertyId); + setRequiredWhen(fieldGroup, fieldGroup.getField(sourcePropertyId), targetPropertyIds, sourceValues); + } + + @SuppressWarnings("rawtypes") + public static void setRequiredWhen(FieldGroup fieldGroup, Field sourceField, + List targetPropertyIds, final List sourceValues) { + if(sourceField instanceof AbstractField) { ((AbstractField) sourceField).setImmediate(true); } @@ -163,6 +168,42 @@ public static void setRequiredWhen(FieldGroup fieldGroup, Field sourceField, } }); } + + /** + * Sets the target fields to enabled when the source field has a value that's contained + * in the sourceValues list. + */ + @SuppressWarnings("rawtypes") + public static void setEnabledWhen(FieldGroup fieldGroup, Field sourceField, final List sourceValues, + List targetPropertyIds, boolean clearOnDisabled) { + + if (sourceField instanceof AbstractField) { + ((AbstractField) sourceField).setImmediate(true); + } + + // initialize + { + boolean enabled = sourceValues.contains(sourceField.getValue()); + for (Object targetPropertyId : targetPropertyIds) { + Field targetField = fieldGroup.getField(targetPropertyId); + targetField.setEnabled(enabled); + if (!enabled && clearOnDisabled) { + targetField.clear(); + } + } + } + + sourceField.addValueChangeListener(event -> { + boolean enabled = sourceValues.contains(event.getProperty().getValue()); + for (Object targetPropertyId : targetPropertyIds) { + Field targetField = fieldGroup.getField(targetPropertyId); + targetField.setEnabled(enabled); + if (!enabled && clearOnDisabled) { + targetField.clear(); + } + } + }); + } public static void setFirstVisibleClearOthers(Field first, Field ...others) { if (first != null) { diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/visit/VisitEditForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/visit/VisitEditForm.java index 32ab3774880..924ee7bedcf 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/visit/VisitEditForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/visit/VisitEditForm.java @@ -26,6 +26,7 @@ public class VisitEditForm extends AbstractEditForm { private final Disease disease; private final ContactDto contact; + private SymptomsForm symptomsForm; public VisitEditForm(Disease disease, ContactDto contact) { super(VisitDto.class, VisitDto.I18N_PREFIX); @@ -57,7 +58,7 @@ protected void addFields() { addField(VisitDto.VISIT_STATUS, OptionGroup.class); addField(VisitDto.VISIT_REMARKS, TextField.class); - SymptomsForm symptomsForm = new SymptomsForm(disease, false); + symptomsForm = new SymptomsForm(disease, false); getFieldGroup().bind(symptomsForm, VisitDto.SYMPTOMS); getContent().addComponent(symptomsForm, VisitDto.SYMPTOMS); @@ -85,4 +86,9 @@ public void validate(Object value) throws InvalidValueException { protected String createHtmlLayout() { return HTML_LAYOUT; } + + public SymptomsForm getSymptomsForm() { + return symptomsForm; + } + } diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/visit/VisitGrid.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/visit/VisitGrid.java index f9eaba15cc6..12980501e7c 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/visit/VisitGrid.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/visit/VisitGrid.java @@ -16,6 +16,7 @@ import de.symeda.sormas.api.utils.DateHelper; import de.symeda.sormas.api.visit.VisitDto; import de.symeda.sormas.ui.ControllerProvider; +import de.symeda.sormas.ui.utils.BooleanRenderer; import de.symeda.sormas.ui.utils.VaadinUiUtil; @SuppressWarnings("serial") @@ -43,10 +44,11 @@ public VisitGrid() { setContainerDataSource(editContainer); setColumns(EDIT_BTN_ID, VisitDto.VISIT_DATE_TIME, VisitDto.VISIT_STATUS, VisitDto.VISIT_REMARKS, - VisitDto.DISEASE, SYMPTOMS_SYMPTOMATIC, SYMPTOMS_TEMPERATURE - ); + VisitDto.DISEASE, SYMPTOMS_SYMPTOMATIC, SYMPTOMS_TEMPERATURE); + getColumn(EDIT_BTN_ID).setRenderer(new HtmlRenderer()); getColumn(EDIT_BTN_ID).setWidth(60); + getColumn(SYMPTOMS_SYMPTOMATIC).setRenderer(new BooleanRenderer()); getColumn(VisitDto.VISIT_DATE_TIME).setRenderer(new DateRenderer(DateHelper.getDateTimeFormat())); diff --git a/sormas-ui/src/main/webapp/VAADIN/themes/sormastheme/sormastheme.scss b/sormas-ui/src/main/webapp/VAADIN/themes/sormastheme/sormastheme.scss index e25b1c17cfc..efa3a72d864 100644 --- a/sormas-ui/src/main/webapp/VAADIN/themes/sormastheme/sormastheme.scss +++ b/sormas-ui/src/main/webapp/VAADIN/themes/sormastheme/sormastheme.scss @@ -447,4 +447,8 @@ $v-layout-spacing-horizontal: round($v-unit-size / 1.8) !default; .vspace-no-filters { margin-bottom: 16px; } + + .vspace-top-24 { + margin-top: 24px; + } } diff --git a/sormas-ui/src/main/webapp/VAADIN/themes/sormastheme/styles.css b/sormas-ui/src/main/webapp/VAADIN/themes/sormastheme/styles.css index bcc153c00c5..bc9e9ff7eaa 100644 --- a/sormas-ui/src/main/webapp/VAADIN/themes/sormastheme/styles.css +++ b/sormas-ui/src/main/webapp/VAADIN/themes/sormastheme/styles.css @@ -13370,4 +13370,8 @@ div.v-layout.v-horizontal.v-widget { .sormastheme .vspace-no-filters { margin-bottom: 16px; +} + +.sormastheme .vspace-top-24 { + margin-top: 24px; } \ No newline at end of file diff --git a/sormas-widgetset/pom.xml b/sormas-widgetset/pom.xml index c8c7006caa8..6b5b0acfa17 100644 --- a/sormas-widgetset/pom.xml +++ b/sormas-widgetset/pom.xml @@ -3,7 +3,7 @@ sormas-base de.symeda.sormas - 0.2.0 + 0.3.0 ../sormas-base 4.0.0