Skip to content
This repository was archived by the owner on May 5, 2021. It is now read-only.

Commit 9b2d2a4

Browse files
author
Martin Wahnschaffe
authored
Merge pull request SORMAS-Foundation#3644 from hzi-braunschweig/feature-3005-campaign-data-import-duplicate-detection
Feature 3005 campaign data import duplicate detection
2 parents ad3e2f9 + 3c11d5e commit 9b2d2a4

14 files changed

Lines changed: 399 additions & 13 deletions

File tree

sormas-api/src/main/java/de/symeda/sormas/api/campaign/data/CampaignFormDataCriteria.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,24 @@
1515

1616
package de.symeda.sormas.api.campaign.data;
1717

18+
import java.io.Serializable;
19+
import java.util.Date;
20+
1821
import de.symeda.sormas.api.BaseCriteria;
1922
import de.symeda.sormas.api.campaign.CampaignReferenceDto;
2023
import de.symeda.sormas.api.campaign.form.CampaignFormMetaReferenceDto;
2124
import de.symeda.sormas.api.region.CommunityReferenceDto;
2225
import de.symeda.sormas.api.region.DistrictReferenceDto;
2326
import de.symeda.sormas.api.region.RegionReferenceDto;
2427

25-
import java.io.Serializable;
26-
2728
public class CampaignFormDataCriteria extends BaseCriteria implements Serializable {
2829

2930
public static final String CAMPAIGN = "campaign";
3031
public static final String CAMPAIGN_FORM_META = "campaignFormMeta";
3132
public static final String REGION = "region";
3233
public static final String DISTRICT = "district";
3334
public static final String COMMUNITY = "community";
35+
public static final String FORM_DATE = "formDate";
3436

3537
private static final long serialVersionUID = 8124072093160133408L;
3638

@@ -39,6 +41,7 @@ public class CampaignFormDataCriteria extends BaseCriteria implements Serializab
3941
private RegionReferenceDto region;
4042
private DistrictReferenceDto district;
4143
private CommunityReferenceDto community;
44+
private Date formDate;
4245

4346
public CampaignReferenceDto getCampaign() {
4447
return campaign;
@@ -104,4 +107,17 @@ public CampaignFormDataCriteria community(CommunityReferenceDto community) {
104107
this.community = community;
105108
return this;
106109
}
110+
111+
public Date getFormDate() {
112+
return formDate;
113+
}
114+
115+
public void setFormDate(Date formDate) {
116+
this.formDate = formDate;
117+
}
118+
119+
public CampaignFormDataCriteria formDate(Date formDate) {
120+
this.formDate = formDate;
121+
return this;
122+
}
107123
}

sormas-api/src/main/java/de/symeda/sormas/api/campaign/data/CampaignFormDataDto.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public class CampaignFormDataDto extends EntityDto {
4545
public static final String REGION = "region";
4646
public static final String DISTRICT = "district";
4747
public static final String COMMUNITY = "community";
48+
public static final String CREATING_USER = "creatingUser";
4849

4950
private List<CampaignFormDataEntry> formValues;
5051
private CampaignReferenceDto campaign;
@@ -144,5 +145,4 @@ public void setCreatingUser(UserReferenceDto creatingUser) {
144145
this.creatingUser = creatingUser;
145146
}
146147

147-
148148
}

sormas-api/src/main/java/de/symeda/sormas/api/campaign/data/CampaignFormDataEntry.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@
1818
import java.io.Serializable;
1919
import java.util.Collection;
2020
import java.util.Iterator;
21-
import java.util.List;
2221
import java.util.Objects;
2322

2423
import de.symeda.sormas.api.i18n.I18nProperties;
2524
import de.symeda.sormas.api.i18n.Strings;
25+
import de.symeda.sormas.api.utils.JsonDataEntry;
2626

27-
public class CampaignFormDataEntry implements Serializable {
27+
public class CampaignFormDataEntry implements Serializable, JsonDataEntry {
2828

2929
private static final long serialVersionUID = -3096020120349257398L;
3030

@@ -89,11 +89,12 @@ public static void removeNullValueEntries(Collection<CampaignFormDataEntry> entr
8989
*/
9090
@Override
9191
public boolean equals(Object o) {
92-
if (this == o) return true;
93-
if (o == null || getClass() != o.getClass()) return false;
92+
if (this == o)
93+
return true;
94+
if (o == null || getClass() != o.getClass())
95+
return false;
9496
CampaignFormDataEntry that = (CampaignFormDataEntry) o;
95-
return Objects.equals(id, that.id) &&
96-
Objects.equals(value, that.value);
97+
return Objects.equals(id, that.id) && Objects.equals(value, that.value);
9798
}
9899

99100
@Override

sormas-api/src/main/java/de/symeda/sormas/api/campaign/data/CampaignFormDataFacade.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ public interface CampaignFormDataFacade {
4949

5050
List<CampaignFormDataIndexDto> getIndexList(CampaignFormDataCriteria criteria, Integer first, Integer max, List<SortProperty> sortProperties);
5151

52+
CampaignFormDataDto getExistingData(CampaignFormDataCriteria criteria);
53+
5254
long count(CampaignFormDataCriteria criteria);
5355

5456
List<CampaignDiagramDataDto> getDiagramData(List<CampaignDiagramSeries> diagramSeries, CampaignDiagramCriteria campaignDiagramCriteria);
@@ -61,4 +63,6 @@ List<CampaignDiagramDataDto> getDiagramDataByAgeGroup(
6163
List<String> getAllActiveUuids();
6264

6365
List<CampaignFormDataDto> getAllActiveAfter(Date date);
66+
67+
void overwriteCampaignFormData(CampaignFormDataDto existingData, CampaignFormDataDto newData);
6468
}

sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public interface Captions {
6060
String actionNewForm = "actionNewForm";
6161
String actionNoActions = "actionNoActions";
6262
String actionOkay = "actionOkay";
63+
String actionOverwrite = "actionOverwrite";
6364
String actionPick = "actionPick";
6465
String actionReplyingLabel = "actionReplyingLabel";
6566
String actionResetFilters = "actionResetFilters";

sormas-api/src/main/java/de/symeda/sormas/api/i18n/Strings.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,9 @@ public interface Strings {
219219
String headingCampaignBasics = "headingCampaignBasics";
220220
String headingCampaignDashboard = "headingCampaignDashboard";
221221
String headingCampaignData = "headingCampaignData";
222+
String headingCampaignFormDataAlreadyExisting = "headingCampaignFormDataAlreadyExisting";
223+
String headingCampaignFormDataDuplicateExisting = "headingCampaignFormDataDuplicateExisting";
224+
String headingCampaignFormDataDuplicateNew = "headingCampaignFormDataDuplicateNew";
222225
String headingCaseComparison = "headingCaseComparison";
223226
String headingCaseData = "headingCaseData";
224227
String headingCaseImport = "headingCaseImport";
@@ -521,6 +524,7 @@ public interface Strings {
521524
String infoSelectOrCreatePersonForContactImport = "infoSelectOrCreatePersonForContactImport";
522525
String infoSelectOrCreatePersonForEventParticipant = "infoSelectOrCreatePersonForEventParticipant";
523526
String infoSelectOrCreatePersonForEventParticipantImport = "infoSelectOrCreatePersonForEventParticipantImport";
527+
String infoSkipOrOverrideDuplicateCampaignFormDataImport = "infoSkipOrOverrideDuplicateCampaignFormDataImport";
524528
String infoSpecificCaseSearch = "infoSpecificCaseSearch";
525529
String infoSpecificEventSearch = "infoSpecificEventSearch";
526530
String infoStatisticsDisclaimer = "infoStatisticsDisclaimer";
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* SORMAS® - Surveillance Outbreak Response Management & Analysis System
3+
* Copyright © 2016-2020 Helmholtz-Zentrum für Infektionsforschung GmbH (HZI)
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
* You should have received a copy of the GNU General Public License
13+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
14+
*/
15+
16+
package de.symeda.sormas.api.utils;
17+
18+
public interface JsonDataEntry {
19+
}

sormas-api/src/main/resources/captions.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ actionSaveChanges=Save changes
123123
actionBackToNationOverview=Back to Nation Overview
124124
actionSettings=Settings
125125
actionNewForm=New Form
126+
actionOverwrite=Overwrite
126127

127128
# AdditionalTest
128129
additionalTestNewTest=New test result

sormas-api/src/main/resources/strings.properties

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,9 @@ headingEpiDataSourceCaseContacts = Contacts with Source Case
482482
headingExposureDetails = Exposure Details
483483
headingAnimalContactDetails = Animal Contact Details
484484
headingBurialDetails = Burial Details
485+
headingCampaignFormDataDuplicateNew = New Campaign Form Data
486+
headingCampaignFormDataDuplicateExisting = Existing Campaign Form Data
487+
headingCampaignFormDataAlreadyExisting = Campaign Form Data Already Existing
485488

486489
# Info texts
487490
infoAddTestsToSample = To add a test result to this sample, it has to be marked as received first.
@@ -566,6 +569,7 @@ infoSelectOrCreatePersonForContact = The database already contains at least one
566569
infoSelectOrCreatePersonForContactImport = The database already contains at least one person that seems to be very similar to the personal details of the imported contact.<br/><br/>Please look through the list of persons. If you feel certain that one of those persons matches your contact person, select it and click on the <i>Save</i> button. Otherwise, click on <i>Create New Person</i> to create a new person for your contact.<br/><br/>If you are unsure, you can discard this window to remove the contact from the current import.
567570
infoSelectOrCreatePersonForEventParticipant = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.<br/><br/>Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the <i>Save</i> button. Otherwise, click on <i>Create New Person</i> to create a new event person for your event.<br/><br/>If you are unsure, you can discard this window and cancel the event participant creation process.
568571
infoSelectOrCreatePersonForEventParticipantImport = The database already contains at least one person that seems to be very similar to the personal details of the created event participant.<br/><br/>Please look through the list of persons. If you feel certain that one of those persons matches your event person, select it and click on the <i>Save</i> button. Otherwise, click on <i>Create New Person</i> to create a new event person for your event.<br/><br/>If you are unsure, you can discard this window to remove the event participant from the current import.
572+
infoSkipOrOverrideDuplicateCampaignFormDataImport = The database already contains a dataset for the form %s in the campaign %s for the specified community and date. Please have a look at the details for the existing dataset and choose <i>Skip</i> if you want to keep the existing data or <i>Overwrite</i> if you want to replace the existing data with the data you have imported.
569573
pseudonymizedCasesSelectedWarning = For the bulked-edited cases you have only limited access to the sensitive data. For those cases the value you put into "Place Description" will be ignored.
570574
infoPickOrCreateEventForCase = The list below contains all existing events having the same disease as the current case. Please check whether the event this case belongs to is already on this list or create a new one if it isn't.
571575
infoPickOrCreateEventForContact = The list below contains all existing events having the same disease as the current contact. Please check whether the event this contact belongs to is already on this list or create a new one if it isn't.

sormas-backend/src/main/java/de/symeda/sormas/backend/campaign/data/CampaignFormDataFacadeEjb.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import javax.ejb.LocalBean;
3333
import javax.ejb.Stateless;
3434
import javax.persistence.EntityManager;
35+
import javax.persistence.NoResultException;
3536
import javax.persistence.PersistenceContext;
3637
import javax.persistence.Query;
3738
import javax.persistence.criteria.CriteriaBuilder;
@@ -56,6 +57,8 @@
5657
import de.symeda.sormas.api.campaign.diagram.CampaignDiagramSeries;
5758
import de.symeda.sormas.api.campaign.form.CampaignFormElement;
5859
import de.symeda.sormas.api.campaign.form.CampaignFormElementType;
60+
import de.symeda.sormas.api.i18n.I18nProperties;
61+
import de.symeda.sormas.api.i18n.Validations;
5962
import de.symeda.sormas.api.infrastructure.PopulationDataCriteria;
6063
import de.symeda.sormas.api.infrastructure.PopulationDataDto;
6164
import de.symeda.sormas.api.region.AreaReferenceDto;
@@ -174,10 +177,25 @@ public CampaignFormDataDto saveCampaignFormData(CampaignFormDataDto campaignForm
174177

175178
CampaignFormData campaignFormData = fromDto(campaignFormDataDto);
176179
CampaignFormDataEntry.removeNullValueEntries(campaignFormData.getFormValues());
180+
181+
validate(campaignFormDataDto);
182+
177183
campaignFormDataService.ensurePersisted(campaignFormData);
178184
return toDto(campaignFormData);
179185
}
180186

187+
private void validate(CampaignFormDataDto campaignFormDataDto) {
188+
if (campaignFormDataDto.getRegion() == null) {
189+
throw new ValidationRuntimeException(I18nProperties.getValidationError(Validations.validRegion));
190+
}
191+
if (campaignFormDataDto.getDistrict() == null) {
192+
throw new ValidationRuntimeException(I18nProperties.getValidationError(Validations.validDistrict));
193+
}
194+
if (campaignFormDataDto.getCommunity() == null) {
195+
throw new ValidationRuntimeException(I18nProperties.getValidationError(Validations.validCommunity));
196+
}
197+
}
198+
181199
@Override
182200
public List<CampaignFormDataDto> getByUuids(List<String> uuids) {
183201
return campaignFormDataService.getByUuids(uuids).stream().map(c -> convertToDto(c)).collect(Collectors.toList());
@@ -226,12 +244,37 @@ public CampaignFormDataReferenceDto getReferenceByUuid(String uuid) {
226244
return toReferenceDto(campaignFormDataService.getByUuid(uuid));
227245
}
228246

247+
@Override
248+
public CampaignFormDataDto getExistingData(CampaignFormDataCriteria criteria) {
249+
CriteriaBuilder cb = em.getCriteriaBuilder();
250+
CriteriaQuery<CampaignFormData> cq = cb.createQuery(CampaignFormData.class);
251+
Root<CampaignFormData> root = cq.from(CampaignFormData.class);
252+
253+
Predicate filter = AbstractAdoService
254+
.and(cb, campaignFormDataService.createCriteriaFilter(criteria, cb, root), campaignFormDataService.createUserFilter(cb, cq, root));
255+
if (filter != null) {
256+
cq.where(filter);
257+
}
258+
259+
cq.orderBy(cb.desc(root.get(CampaignFormData.CHANGE_DATE)));
260+
261+
CampaignFormData resultEntity;
262+
try {
263+
resultEntity = em.createQuery(cq).setMaxResults(1).getSingleResult();
264+
} catch (NoResultException e) {
265+
resultEntity = null;
266+
}
267+
268+
return resultEntity != null ? toDto(resultEntity) : null;
269+
}
270+
229271
@Override
230272
public List<CampaignFormDataIndexDto> getIndexList(
231273
CampaignFormDataCriteria criteria,
232274
Integer first,
233275
Integer max,
234276
List<SortProperty> sortProperties) {
277+
235278
CriteriaBuilder cb = em.getCriteriaBuilder();
236279
CriteriaQuery<CampaignFormDataIndexDto> cq = cb.createQuery(CampaignFormDataIndexDto.class);
237280
Root<CampaignFormData> root = cq.from(CampaignFormData.class);
@@ -672,6 +715,12 @@ public long count(CampaignFormDataCriteria criteria) {
672715
return em.createQuery(cq).getSingleResult();
673716
}
674717

718+
@Override
719+
public void overwriteCampaignFormData(CampaignFormDataDto existingData, CampaignFormDataDto newData) {
720+
DtoHelper.fillDto(existingData, newData, true);
721+
saveCampaignFormData(existingData);
722+
}
723+
675724
private CampaignFormDataReferenceDto toReferenceDto(CampaignFormData source) {
676725
if (source == null) {
677726
return null;

0 commit comments

Comments
 (0)