1 package fr.ifremer.dali.service.observation;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 import com.google.common.collect.Lists;
27 import fr.ifremer.dali.config.DaliConfiguration;
28 import fr.ifremer.dali.dao.administration.user.DaliDepartmentDao;
29 import fr.ifremer.dali.dao.data.measurement.DaliMeasurementDao;
30 import fr.ifremer.dali.dao.data.photo.DaliPhotoDao;
31 import fr.ifremer.dali.dao.data.samplingoperation.DaliSamplingOperationDao;
32 import fr.ifremer.dali.dao.data.survey.DaliSurveyDao;
33 import fr.ifremer.dali.dto.DaliBeanFactory;
34 import fr.ifremer.dali.dto.DaliBeans;
35 import fr.ifremer.dali.dto.configuration.programStrategy.PmfmStrategyDTO;
36 import fr.ifremer.dali.dto.configuration.programStrategy.ProgStratDTO;
37 import fr.ifremer.dali.dto.configuration.programStrategy.ProgramDTO;
38 import fr.ifremer.dali.dto.data.measurement.MeasurementDTO;
39 import fr.ifremer.dali.dto.data.sampling.SamplingOperationDTO;
40 import fr.ifremer.dali.dto.data.survey.CampaignDTO;
41 import fr.ifremer.dali.dto.data.survey.SurveyDTO;
42 import fr.ifremer.dali.dto.data.survey.SurveyFilterDTO;
43 import fr.ifremer.dali.dto.enums.FilterTypeValues;
44 import fr.ifremer.dali.dto.enums.SearchDateValues;
45 import fr.ifremer.dali.dto.enums.SynchronizationStatusValues;
46 import fr.ifremer.dali.dto.referential.*;
47 import fr.ifremer.dali.dto.referential.pmfm.PmfmDTO;
48 import fr.ifremer.dali.dto.system.QualificationHistoryDTO;
49 import fr.ifremer.dali.dto.system.ValidationHistoryDTO;
50 import fr.ifremer.dali.service.DaliDataContext;
51 import fr.ifremer.dali.service.DaliTechnicalException;
52 import fr.ifremer.dali.service.StatusFilter;
53 import fr.ifremer.dali.service.administration.campaign.CampaignService;
54 import fr.ifremer.dali.service.administration.context.ContextService;
55 import fr.ifremer.dali.service.administration.program.ProgramStrategyService;
56 import fr.ifremer.dali.service.administration.user.UserService;
57 import fr.ifremer.dali.service.persistence.PersistenceService;
58 import fr.ifremer.dali.service.referential.ReferentialService;
59 import fr.ifremer.quadrige3.core.ProgressionCoreModel;
60 import fr.ifremer.quadrige3.core.dao.referential.QualityFlagCode;
61 import fr.ifremer.quadrige3.core.dao.technical.Assert;
62 import fr.ifremer.quadrige3.core.dao.technical.Dates;
63 import fr.ifremer.quadrige3.core.dao.technical.Times;
64 import fr.ifremer.quadrige3.core.security.SecurityContextHelper;
65 import org.apache.commons.collections4.CollectionUtils;
66 import org.apache.commons.lang3.StringUtils;
67 import org.apache.commons.logging.Log;
68 import org.apache.commons.logging.LogFactory;
69 import org.springframework.beans.factory.annotation.Autowired;
70 import org.springframework.stereotype.Service;
71
72 import javax.annotation.Resource;
73 import java.time.LocalDate;
74 import java.util.*;
75 import java.util.stream.Collectors;
76
77 import static org.nuiton.i18n.I18n.t;
78
79
80
81
82
83
84 @Service("daliSurveyService")
85 public class ObservationServiceImpl implements ObservationInternalService {
86
87 public static final Log LOG = LogFactory.getLog(ObservationServiceImpl.class);
88
89 @Resource(name = "daliSurveyService")
90 private ObservationInternalService loopBackService;
91
92 @Resource(name = "daliPersistenceService")
93 private PersistenceService persistenceService;
94
95 @Resource(name = "daliDataContext")
96 private DaliDataContext dataContext;
97
98 @Resource(name = "daliContextService")
99 private ContextService contextService;
100
101 @Resource(name = "daliReferentialService")
102 private ReferentialService referentialService;
103
104 @Resource(name = "daliUserService")
105 private UserService userService;
106
107 @Resource(name = "daliProgramStrategyService")
108 private ProgramStrategyService programStrategyService;
109
110 @Resource(name = "daliCampaignService")
111 private CampaignService campaignService;
112
113 @Resource(name = "daliSurveyDao")
114 private DaliSurveyDao surveyDao;
115
116 @Resource(name = "daliSamplingOperationDao")
117 private DaliSamplingOperationDao samplingOperationDao;
118
119 @Resource(name = "daliMeasurementDao")
120 private DaliMeasurementDao measurementDao;
121
122 @Resource(name = "daliPhotoDao")
123 private DaliPhotoDao photoDao;
124
125 @Resource(name = "daliDepartmentDao")
126 protected DaliDepartmentDao departmentDao;
127
128 @Autowired
129 protected DaliConfiguration config;
130
131
132
133
134 @Override
135 public List<SurveyDTO> getSurveys(SurveyFilterDTO surveyFilter) {
136 Integer campaignId = surveyFilter.getCampaignId();
137 String programCode = surveyFilter.getProgramCode();
138 Integer locationId = surveyFilter.getLocationId();
139 Integer stateId = surveyFilter.getStateId();
140 Integer synchronizationStatusId = surveyFilter.getShareId();
141 String name = surveyFilter.getName();
142 String comment = surveyFilter.getComment();
143 LocalDate startDate = null;
144 LocalDate endDate = null;
145 boolean strictDate = false;
146 if (surveyFilter.getSearchDateId() != null) {
147 SearchDateValues searchDateValue = SearchDateValues.values()[surveyFilter.getSearchDateId()];
148 switch (searchDateValue) {
149 case EQUALS:
150 startDate = surveyFilter.getDate1();
151 endDate = startDate;
152 strictDate = true;
153 break;
154 case BETWEEN:
155 startDate = surveyFilter.getDate1();
156 endDate = surveyFilter.getDate2();
157 break;
158 case BEFORE:
159 endDate = surveyFilter.getDate1();
160 strictDate = true;
161 break;
162 case BEFORE_OR_EQUALS:
163 endDate = surveyFilter.getDate1();
164 break;
165 case AFTER:
166 startDate = surveyFilter.getDate1();
167 strictDate = true;
168 break;
169 case AFTER_OR_EQUALS:
170 startDate = surveyFilter.getDate1();
171 break;
172 }
173 }
174 Collection<String> programCodes;
175
176 if (StringUtils.isBlank(programCode)) {
177 programCodes = programStrategyService.getWritableProgramCodesByQuserId(SecurityContextHelper.getQuadrigeUserId());
178 } else {
179 programCodes = Collections.singleton(programCode);
180 }
181
182 List<SurveyDTO> surveys = surveyDao.getSurveysByCriteria(
183 campaignId,
184 programCodes,
185 locationId,
186 name,
187 comment,
188 stateId,
189 synchronizationStatusId,
190 Dates.convertToDate(startDate, config.getDbTimezone()),
191 Dates.convertToDate(endDate, config.getDbTimezone()),
192 strictDate);
193
194
195 return filterSurveysByDepartmentHermetic(surveys);
196 }
197
198 private List<SurveyDTO> filterSurveysByDepartmentHermetic(List<SurveyDTO> surveys) {
199
200 Integer userId= dataContext.getRecorderPersonId();
201 Assert.notNull(userId);
202 Integer recDepId = dataContext.getRecorderDepartmentId();
203 Assert.notNull(recDepId);
204
205 List<ProgramDTO> managedPrograms = programStrategyService.getManagedProgramsByUser(userId);
206
207 return surveys.parallelStream().filter(survey -> {
208 ProgramDTO program = survey.getProgram();
209
210 if (program == null) return true;
211
212 if (program.isDepartmentHermetic() && !managedPrograms.contains(program)) {
213 return survey.getDepartment().getId().equals(recDepId);
214 }
215 return true;
216 }).collect(Collectors.toList());
217 }
218
219
220
221
222 @Override
223 public void loadSamplingOperationsFromSurvey(SurveyDTO survey, boolean withIndividualMeasurements) {
224
225 if (survey == null || survey.getId() == null) {
226 return;
227 }
228
229 if (!survey.isSamplingOperationsLoaded()) {
230
231
232 survey.setSamplingOperations(samplingOperationDao.getSamplingOperationsBySurveyId(survey.getId(), withIndividualMeasurements));
233 survey.setSamplingOperationsLoaded(true);
234
235 if (!survey.isSamplingOperationsEmpty()) {
236
237
238 for (SamplingOperationDTO samplingOperation : survey.getSamplingOperations()) {
239
240
241 if (samplingOperation.getPmfms() == null) {
242 samplingOperation.setPmfms(new ArrayList<>());
243 }
244
245 if (withIndividualMeasurements) {
246 if (samplingOperation.getIndividualPmfms() == null) {
247 samplingOperation.setIndividualPmfms(new ArrayList<>());
248 }
249 } else {
250
251 samplingOperation.setIndividualPmfms(null);
252 samplingOperation.setIndividualMeasurements(null);
253 samplingOperation.setIndividualMeasurementsLoaded(false);
254 }
255
256
257 DaliBeans.populatePmfmsFromMeasurements(samplingOperation);
258
259 }
260 }
261 }
262 }
263
264
265
266
267 @Override
268 public SamplingOperationDTO newSamplingOperation(SurveyDTO survey, List<PmfmDTO> pmfms) {
269 Assert.notNull(survey);
270 Assert.notNull(pmfms);
271
272 SamplingOperationDTO result = DaliBeanFactory.newSamplingOperationDTO();
273
274
275 for (final PmfmDTO pmfm : pmfms) {
276 final MeasurementDTO measurement = DaliBeanFactory.newMeasurementDTO();
277 measurement.setPmfm(pmfm);
278 result.addMeasurements(measurement);
279 }
280 result.addAllPmfms(pmfms);
281
282
283 result.setSamplingDepartment(programStrategyService.getSamplingDepartmentOfAppliedStrategyBySurvey(survey));
284
285 return result;
286 }
287
288
289
290
291 @Override
292 public SurveyDTO getSurvey(Integer surveyId) {
293 return getSurvey(surveyId, false);
294 }
295
296
297
298
299 @Override
300 public SurveyDTO getSurveyWithoutPmfmFiltering(Integer surveyId) {
301 return getSurvey(surveyId, true);
302 }
303
304
305
306
307 @Override
308 public void saveSurveys(Collection<? extends SurveyDTO> surveys, ProgressionCoreModel progressionModel) {
309
310 List<SurveyDTO> surveysToSave = surveys.stream().filter(SurveyDTO::isDirty).collect(Collectors.toList());
311 progressionModel.setTotal(surveysToSave.size());
312
313 for (SurveyDTO survey : surveysToSave) {
314 progressionModel.increments(t("dali.service.common.progression",
315 t("dali.service.observation.save"), progressionModel.getCurrent() + 1, progressionModel.getTotal()));
316
317 if (survey.getId() == null) {
318
319
320 if (survey.getDepartment() == null) {
321
322 Integer depId = dataContext.getRecorderDepartmentId();
323 if (depId == null) {
324 throw new DaliTechnicalException("no RecorderDepartmentId found in data context");
325 }
326 survey.setDepartment(departmentDao.getDepartmentById(depId));
327 }
328 }
329
330 saveSurvey(survey);
331 survey.setDirty(false);
332 }
333 }
334
335
336
337
338 @Override
339 public void saveSurvey(SurveyDTO survey) {
340
341 if (survey.isDirty() || survey.getControlDate() != null) {
342 survey.setControlDate(null);
343 }
344
345
346 applyDefaultAnalysisDepartment(survey);
347
348
349 surveyDao.save(survey);
350 }
351
352
353
354
355 @Override
356 public void deleteSurveys(List<Integer> surveyIds) {
357 if (CollectionUtils.isEmpty(surveyIds)) return;
358 Integer recorderUserId = dataContext.getRecorderPersonId();
359
360
361 surveyIds.stream().filter(Objects::nonNull).distinct().forEach(surveyId -> surveyDao.removeUsingDeletedItemHistory(surveyId, recorderUserId));
362 }
363
364
365
366
367 @Override
368 public SurveyDTO duplicateSurvey(SurveyDTO survey, boolean fullDuplication, boolean copyCoordinates) {
369
370
371 SurveyDTO duplicateSurvey = DaliBeans.clone(survey);
372
373 duplicateSurvey.setId(null);
374 duplicateSurvey.setDirty(true);
375
376
377 if (survey.isObserversEmpty() && survey.getId() != null) {
378 duplicateSurvey.setObservers(surveyDao.getObservers(survey.getId()));
379 } else {
380 duplicateSurvey.setObservers(DaliBeans.clone(survey.getObservers()));
381 }
382
383
384 duplicateSurvey.setPhotos(null);
385 duplicateSurvey.setPhotosLoaded(false);
386 duplicateSurvey.setMeasurements(null);
387 duplicateSurvey.setIndividualMeasurements(null);
388 duplicateSurvey.setMeasurementsLoaded(false);
389 duplicateSurvey.setPmfms(null);
390 duplicateSurvey.setIndividualPmfms(null);
391 duplicateSurvey.setComment(null);
392 duplicateSurvey.setQualificationComment(null);
393 duplicateSurvey.setValidationDate(null);
394 duplicateSurvey.setUpdateDate(null);
395 duplicateSurvey.setControlDate(null);
396 duplicateSurvey.setSynchronizationStatus(null);
397 duplicateSurvey.setErrors(null);
398
399 if (copyCoordinates) {
400 duplicateSurvey.setCoordinate(DaliBeans.clone(survey.getCoordinate()));
401
402 duplicateSurvey.setPositioning(survey.getPositioning());
403
404 duplicateSurvey.setPositioningComment(survey.getPositioningComment());
405 } else {
406 duplicateSurvey.setCoordinate(null);
407 duplicateSurvey.setPositioning(null);
408 duplicateSurvey.setPositioningComment(null);
409 }
410
411
412 if (survey.getOccasion() != null) {
413 duplicateSurvey.setOccasion(DaliBeans.clone(survey.getOccasion()));
414 duplicateSurvey.getOccasion().setId(null);
415 }
416
417 if (fullDuplication) {
418
419
420 loadSamplingOperationsFromSurvey(survey, true);
421
422
423 List<SamplingOperationDTO> duplicateSamplingOperations = Lists.newArrayList();
424 if (!survey.isSamplingOperationsEmpty()) {
425 for (SamplingOperationDTO samplingOperation : survey.getSamplingOperations()) {
426 SamplingOperationDTO duplicateSamplingOperation = DaliBeans.clone(samplingOperation);
427 duplicateSamplingOperation.setId(null);
428 duplicateSamplingOperation.setMeasurements(null);
429 duplicateSamplingOperation.setIndividualMeasurements(null);
430 duplicateSamplingOperation.setMeasurementsLoaded(false);
431 duplicateSamplingOperation.setIndividualMeasurementsLoaded(false);
432 duplicateSamplingOperation.setComment(null);
433 duplicateSamplingOperation.setErrors(null);
434
435 if (copyCoordinates) {
436 duplicateSamplingOperation.setCoordinate(samplingOperation.getCoordinate());
437 duplicateSamplingOperation.setPositioning(samplingOperation.getPositioning());
438 } else {
439 duplicateSamplingOperation.setCoordinate(null);
440 duplicateSamplingOperation.setPositioning(null);
441 }
442
443 duplicateSamplingOperations.add(duplicateSamplingOperation);
444 }
445 }
446
447 duplicateSurvey.setSamplingOperations(duplicateSamplingOperations);
448 duplicateSurvey.setSamplingOperationsLoaded(true);
449
450 } else {
451
452 duplicateSurvey.setSamplingOperations(null);
453 duplicateSurvey.setSamplingOperationsLoaded(false);
454 }
455
456 return duplicateSurvey;
457
458 }
459
460
461
462
463 @Override
464 public List<ProgramDTO> getAvailablePrograms(Integer locationId, LocalDate date, boolean forceNoContext) {
465 List<ProgramDTO> result;
466 if (dataContext.isContextFiltered(FilterTypeValues.PROGRAM) && !forceNoContext) {
467 result = contextService.getFilteredPrograms(dataContext.getContextId());
468
469 Set<String> writableProgramCodes = programStrategyService.getWritableProgramCodesByQuserId(dataContext.getPrincipalUserId());
470 result = result.stream().filter(programDTO -> writableProgramCodes.contains(programDTO.getCode())).collect(Collectors.toList());
471 } else {
472 result = programStrategyService.getWritablePrograms();
473 }
474
475
476 if (CollectionUtils.isNotEmpty(result) && locationId != null && date != null) {
477 List<ProgramDTO> filteredPrograms = programStrategyService.getWritableProgramsByLocationAndDate(
478 locationId,
479 Dates.convertToDate(date, config.getDbTimezone()));
480 return (List<ProgramDTO>) CollectionUtils.intersection(result, filteredPrograms);
481 }
482
483 return result;
484 }
485
486 @Override
487 public List<CampaignDTO> getAvailableCampaigns(LocalDate date, boolean forceNoContext) {
488 List<CampaignDTO> result;
489 if (dataContext.isContextFiltered(FilterTypeValues.CAMPAIGN) && !forceNoContext) {
490 result = contextService.getFilteredCampaigns(dataContext.getContextId());
491 } else {
492 result = new ArrayList<>(campaignService.getAllCampaigns());
493 }
494
495 if (CollectionUtils.isNotEmpty(result) && date != null) {
496 List<CampaignDTO> filteredCampaigns = campaignService.findCampaignsIncludingDate(Dates.convertToDate(date, config.getDbTimezone()));
497 return (List<CampaignDTO>) CollectionUtils.intersection(result, filteredCampaigns);
498 }
499
500 return result;
501 }
502
503
504
505
506 @Override
507 public List<AnalysisInstrumentDTO> getAvailableAnalysisInstruments(boolean forceNoContext) {
508 if (dataContext.isContextFiltered(FilterTypeValues.ANALYSIS_INSTRUMENT) && !forceNoContext) {
509 return contextService.getFilteredAnalysisInstruments(dataContext.getContextId());
510 } else {
511 return referentialService.getAnalysisInstruments(StatusFilter.ACTIVE);
512 }
513 }
514
515
516
517
518 @Override
519 public List<SamplingEquipmentDTO> getAvailableSamplingEquipments(boolean forceNoContext) {
520 if (dataContext.isContextFiltered(FilterTypeValues.SAMPLING_EQUIPMENT) && !forceNoContext) {
521 return contextService.getFilteredSamplingEquipments(dataContext.getContextId());
522 } else {
523 return referentialService.getSamplingEquipments(StatusFilter.ACTIVE);
524 }
525 }
526
527
528
529
530 @Override
531 public List<LocationDTO> getAvailableLocations(boolean forceNoContext) {
532 if (dataContext.isContextFiltered(FilterTypeValues.LOCATION) && !forceNoContext) {
533 return contextService.getFilteredLocations(dataContext.getContextId());
534 } else {
535 return referentialService.getLocations(StatusFilter.ACTIVE);
536 }
537 }
538
539
540
541
542 @Override
543 public List<LocationDTO> getAvailableLocations(Integer campaignId, String programCode, boolean forceNoContext) {
544 List<LocationDTO> locations = referentialService.getLocations(campaignId, programCode);
545 if (CollectionUtils.isNotEmpty(locations)) {
546 if (dataContext.isContextFiltered(FilterTypeValues.LOCATION) && !forceNoContext) {
547 List<LocationDTO> filteredLocations = contextService.getFilteredLocations(dataContext.getContextId());
548 if (CollectionUtils.isNotEmpty(filteredLocations)) {
549 return (List<LocationDTO>) CollectionUtils.intersection(locations, filteredLocations);
550 }
551 }
552 }
553 return locations;
554 }
555
556
557
558
559 @Override
560 public List<TaxonGroupDTO> getAvailableTaxonGroups(TaxonDTO taxon, boolean forceNoContext) {
561 List<TaxonGroupDTO> result;
562 if (taxon == null) {
563 return getAvailableTaxonGroups(forceNoContext);
564 } else {
565 result = taxon.getTaxonGroups();
566 if (CollectionUtils.isNotEmpty(result)) {
567 if (dataContext.isContextFiltered(FilterTypeValues.TAXON_GROUP) && !forceNoContext) {
568 List<TaxonGroupDTO> filteredTaxonGroups = contextService.getFilteredTaxonGroups(dataContext.getContextId());
569 if (CollectionUtils.isNotEmpty(filteredTaxonGroups)) {
570 result = (List<TaxonGroupDTO>) CollectionUtils.intersection(result, filteredTaxonGroups);
571 }
572 }
573 }
574 }
575 return referentialService.getFullTaxonGroups(result);
576 }
577
578
579
580
581 @Override
582 public List<TaxonDTO> getAvailableTaxons(TaxonGroupDTO taxonGroup, boolean forceNoContext) {
583 if (taxonGroup == null) {
584 return getAvailableTaxons(forceNoContext);
585 } else {
586
587 List<TaxonDTO> availableTaxons = referentialService.getTaxons(taxonGroup.getId());
588
589
590 availableTaxons = availableTaxons.stream().filter(taxon->!taxon.isObsolete()).collect(Collectors.toList());
591
592 if (CollectionUtils.isNotEmpty(availableTaxons)) {
593 if (dataContext.isContextFiltered(FilterTypeValues.TAXON) && !forceNoContext) {
594 List<TaxonDTO> filteredTaxons = contextService.getFilteredTaxons(dataContext.getContextId());
595 if (CollectionUtils.isNotEmpty(filteredTaxons)) {
596 availableTaxons = (List<TaxonDTO>) CollectionUtils.intersection(availableTaxons, filteredTaxons);
597 }
598 }
599 }
600 referentialService.fillReferentTaxons(availableTaxons);
601 return availableTaxons;
602 }
603 }
604
605
606
607
608 @Override
609 public List<PmfmDTO> getAvailablePmfms(boolean forceNoContext) {
610 if (dataContext.isContextFiltered(FilterTypeValues.PMFM) && !forceNoContext) {
611 return contextService.getFilteredPmfms(dataContext.getContextId());
612 } else {
613 return referentialService.getPmfms(StatusFilter.ACTIVE);
614 }
615 }
616
617
618
619
620 @Override
621 public List<DepartmentDTO> getAvailableDepartments(boolean forceNoContext) {
622 if (dataContext.isContextFiltered(FilterTypeValues.DEPARTMENT) && !forceNoContext) {
623 return contextService.getFilteredDepartments(dataContext.getContextId());
624 } else {
625 return referentialService.getDepartments(StatusFilter.ACTIVE);
626 }
627 }
628
629
630
631
632 @Override
633 public List<PersonDTO> getAvailableUsers(boolean forceNoFilter) {
634 if (dataContext.isContextFiltered(FilterTypeValues.USER) && !forceNoFilter) {
635 return contextService.getFilteredUsers(dataContext.getContextId());
636 } else {
637 return userService.getActiveUsers();
638 }
639 }
640
641
642
643
644 @Override
645 public void validateSurveys(Collection<? extends SurveyDTO> surveys, String validationComment, ProgressionCoreModel progressionModel) {
646
647 if (CollectionUtils.isEmpty(surveys)) return;
648
649
650 Date validationDate = new Date(System.currentTimeMillis());
651
652
653 List<SurveyDTO> surveysToValidate = surveys.stream()
654 .filter(survey -> !survey.isDirty() && survey.getControlDate() != null && survey.getValidationDate() == null)
655 .collect(Collectors.toList());
656
657
658 List<Integer> allSurveyIds = surveysToValidate.stream().map(SurveyDTO::getId).distinct().collect(Collectors.toList());
659 int chunkSize = config.getMassiveProcessChunkSize();
660 List<List<Integer>> chunkSurveyIds = Lists.partition(allSurveyIds, chunkSize);
661 boolean enableMassiveUpdate = chunkSurveyIds.size() > 1;
662
663 if (enableMassiveUpdate) {
664
665 persistenceService.enableMassiveUpdate();
666 }
667
668 long start = System.currentTimeMillis();
669 try {
670 progressionModel.setTotal(chunkSurveyIds.size());
671 for (int chunk = 0; chunk < chunkSurveyIds.size(); chunk++) {
672
673 List<Integer> surveyIds = chunkSurveyIds.get(chunk);
674 progressionModel.increments(t("dali.service.observation.validation.progression",
675 allSurveyIds.size(), chunk * chunkSize + 1, chunk * chunkSize + surveyIds.size()));
676 if (LOG.isDebugEnabled()) {
677 LOG.debug(String.format("Validating %s-%s of %s surveys", chunk * chunkSize + 1, chunk * chunkSize + surveyIds.size(), allSurveyIds.size()));
678 }
679 loopBackService.validateSurveys(surveyIds, validationDate, validationComment);
680 }
681
682 } finally {
683
684 if (enableMassiveUpdate) {
685
686 persistenceService.disableMassiveUpdate();
687 }
688 }
689
690
691 surveysToValidate.forEach(survey -> {
692
693
694 survey.setValidationDate(validationDate);
695 survey.setValidationComment(validationComment);
696
697
698 survey.setSynchronizationStatus(SynchronizationStatusValues.READY_TO_SYNCHRONIZE.toSynchronizationStatusDTO());
699
700
701 survey.setDirty(false);
702
703 });
704
705 if (LOG.isDebugEnabled()) {
706 LOG.debug(String.format("Validation total time = %s", Times.durationToString(System.currentTimeMillis() - start)));
707 }
708 }
709
710 @Override
711 public void validateSurveys(List<Integer> surveyIds, Date validationDate, String validationComment) {
712
713 Assert.notEmpty(surveyIds);
714 Assert.notNull(validationDate);
715
716
717 validationComment = StringUtils.trimToNull(validationComment);
718
719 Integer validatorId = dataContext.getRecorderPersonId();
720
721
722 Assert.isTrue(dataContext.isRecorderValidator(), String.format("Recorder %s does not have qualifier privilege", validatorId));
723
724 long start = System.currentTimeMillis();
725 for (Integer surveyId : surveyIds) {
726
727
728 surveyDao.validate(surveyId, validationComment, validationDate, validatorId, true);
729
730 }
731
732 if (LOG.isDebugEnabled()) {
733 LOG.debug(String.format("validation of %d survey(s) in %s",
734 surveyIds.size(), Times.durationToString(System.currentTimeMillis() - start)));
735 }
736
737 start = System.currentTimeMillis();
738 int nbSamplingOperations = samplingOperationDao.validateBySurveyIds(surveyIds, validationDate);
739 if (LOG.isDebugEnabled()) {
740 LOG.debug(String.format("validation of %d survey(s) in %s : %s sampling operations",
741 surveyIds.size(), Times.durationToString(System.currentTimeMillis() - start), nbSamplingOperations));
742 }
743
744 start = System.currentTimeMillis();
745 int nbMeasurements = measurementDao.validateAllMeasurementsBySurveyIds(surveyIds, validationDate);
746 if (LOG.isDebugEnabled()) {
747 LOG.debug(String.format("validation of %d survey(s) in %s : %s (taxon)measurements",
748 surveyIds.size(), Times.durationToString(System.currentTimeMillis() - start), nbMeasurements));
749 }
750
751 start = System.currentTimeMillis();
752 int nbPhotos = photoDao.validateBySurveyIds(surveyIds, validationDate);
753 if (LOG.isDebugEnabled()) {
754 LOG.debug(String.format("validation of %d survey(s) in %s : %s photos",
755 surveyIds.size(), Times.durationToString(System.currentTimeMillis() - start), nbPhotos));
756 }
757
758 }
759
760
761
762
763 @Override
764 public void unvalidateSurveys(Collection<? extends SurveyDTO> surveys, String unvalidationComment, ProgressionCoreModel progressionModel) {
765
766 if (CollectionUtils.isEmpty(surveys)) return;
767
768
769 Date unvalidationDate = new Date(System.currentTimeMillis());
770
771
772 List<SurveyDTO> surveysToUnvalidate = surveys.stream()
773 .filter(survey -> survey.getId() != null && survey.getValidationDate() != null)
774 .collect(Collectors.toList());
775
776
777 List<Integer> allSurveyIds = surveysToUnvalidate.stream().map(SurveyDTO::getId).distinct().collect(Collectors.toList());
778 int chunkSize = config.getMassiveProcessChunkSize();
779 List<List<Integer>> chunkSurveyIds = Lists.partition(allSurveyIds, chunkSize);
780 boolean enableMassiveUpdate = chunkSurveyIds.size() > 1;
781
782 if (enableMassiveUpdate) {
783
784 persistenceService.enableMassiveUpdate();
785 }
786
787 long start = System.currentTimeMillis();
788 try {
789 progressionModel.setTotal(chunkSurveyIds.size());
790 for (int chunk = 0; chunk < chunkSurveyIds.size(); chunk++) {
791
792 List<Integer> surveyIds = chunkSurveyIds.get(chunk);
793 progressionModel.increments(t("dali.service.observation.unvalidation.progression",
794 allSurveyIds.size(), chunk * chunkSize + 1, chunk * chunkSize + surveyIds.size()));
795 if (LOG.isDebugEnabled()) {
796 LOG.debug(String.format("Unvalidating %s-%s of %s surveys", chunk * chunkSize + 1, chunk * chunkSize + surveyIds.size(), allSurveyIds.size()));
797 }
798 loopBackService.unvalidateSurveys(surveyIds, unvalidationDate, unvalidationComment);
799 }
800
801 } finally {
802
803 if (enableMassiveUpdate) {
804
805 persistenceService.disableMassiveUpdate();
806 }
807 }
808
809
810 surveysToUnvalidate.forEach(survey -> {
811
812
813 survey.setValidationDate(null);
814 survey.setValidationComment(null);
815 survey.setQualificationDate(null);
816 survey.setQualificationComment(null);
817 survey.setQualityLevel(referentialService.getNotQualityLevel());
818
819
820 survey.setSynchronizationStatus(SynchronizationStatusValues.DIRTY.toSynchronizationStatusDTO());
821
822
823 survey.setDirty(false);
824
825 });
826
827 if (LOG.isDebugEnabled()) {
828 LOG.debug(String.format("Unvalidation total time = %s", Times.durationToString(System.currentTimeMillis() - start)));
829 }
830 }
831
832
833
834
835
836
837
838
839 @Override
840 public void unvalidateSurveys(List<Integer> surveyIds, Date unvalidationDate, String unvalidationComment) {
841
842 Assert.notEmpty(surveyIds);
843 Assert.notNull(unvalidationDate);
844 Assert.notBlank(unvalidationComment);
845
846
847 unvalidationComment = StringUtils.trimToNull(unvalidationComment);
848
849 Integer validatorId = dataContext.getRecorderPersonId();
850
851
852 Assert.isTrue((dataContext.isRecorderValidator()), String.format("Recorder %s does not have qualifier privilege", validatorId));
853
854 long start = System.currentTimeMillis();
855 for (Integer surveyId : surveyIds) {
856
857
858 surveyDao.unvalidate(surveyId, unvalidationComment, unvalidationDate, validatorId);
859
860 }
861 if (LOG.isDebugEnabled()) {
862 LOG.debug(String.format("unvalidation of %d survey(s) in %s",
863 surveyIds.size(), Times.durationToString(System.currentTimeMillis() - start)));
864 }
865
866 start = System.currentTimeMillis();
867 int nbSamplingOperations = samplingOperationDao.unvalidateBySurveyIds(surveyIds);
868 if (LOG.isDebugEnabled()) {
869 LOG.debug(String.format("unvalidation of %d survey(s) in %s : %s sampling operations",
870 surveyIds.size(), Times.durationToString(System.currentTimeMillis() - start), nbSamplingOperations));
871 }
872
873 start = System.currentTimeMillis();
874 int nbMeasurements = measurementDao.unvalidateAllMeasurementsBySurveyIds(surveyIds);
875 if (LOG.isDebugEnabled()) {
876 LOG.debug(String.format("unvalidation of %d survey(s) in %s : %s (taxon)measurements",
877 surveyIds.size(), Times.durationToString(System.currentTimeMillis() - start), nbMeasurements));
878 }
879
880 start = System.currentTimeMillis();
881 int nbPhotos = photoDao.unvalidateBySurveyIds(surveyIds);
882 if (LOG.isDebugEnabled()) {
883 LOG.debug(String.format("unvalidation of %d survey(s) in %s : %s photos",
884 surveyIds.size(), Times.durationToString(System.currentTimeMillis() - start), nbPhotos));
885 }
886
887 }
888
889 @Override
890 public void qualifySurveys(Collection<? extends SurveyDTO> surveys, String qualificationComment, QualityLevelDTO qualityLevel, ProgressionCoreModel progressionModel) {
891
892 if (CollectionUtils.isEmpty(surveys)) return;
893 Assert.notNull(qualityLevel);
894
895
896 Date qualificationDate = new Date(System.currentTimeMillis());
897
898
899 List<SurveyDTO> surveysToQualify = surveys.stream()
900 .filter(survey -> !survey.isDirty() && survey.getValidationDate() != null)
901 .collect(Collectors.toList());
902
903
904 List<Integer> allSurveyIds = surveysToQualify.stream().map(SurveyDTO::getId).distinct().collect(Collectors.toList());
905 int chunkSize = config.getMassiveProcessChunkSize();
906 List<List<Integer>> chunkSurveyIds = Lists.partition(allSurveyIds, chunkSize);
907 boolean enableMassiveUpdate = chunkSurveyIds.size() > 1;
908
909 if (enableMassiveUpdate) {
910
911 persistenceService.enableMassiveUpdate();
912 }
913
914 long start = System.currentTimeMillis();
915 try {
916 progressionModel.setTotal(chunkSurveyIds.size());
917 for (int chunk = 0; chunk < chunkSurveyIds.size(); chunk++) {
918
919 List<Integer> surveyIds = chunkSurveyIds.get(chunk);
920 progressionModel.increments(t("dali.service.observation.qualification.progression",
921 allSurveyIds.size(), chunk * chunkSize + 1, chunk * chunkSize + surveyIds.size()));
922 if (LOG.isDebugEnabled()) {
923 LOG.debug(String.format("Qualifying %s-%s of %s surveys", chunk * chunkSize + 1, chunk * chunkSize + surveyIds.size(), allSurveyIds.size()));
924 }
925 loopBackService.qualifySurveys(surveyIds, qualificationDate, qualificationComment, qualityLevel.getCode());
926 }
927
928 } finally {
929
930 if (enableMassiveUpdate) {
931
932 persistenceService.disableMassiveUpdate();
933 }
934 }
935
936
937 surveysToQualify.forEach(survey -> {
938
939
940 survey.setQualificationDate(qualificationDate);
941 survey.setQualificationComment(qualificationComment);
942 survey.setQualityLevel(qualityLevel);
943
944
945 survey.setDirty(false);
946
947 });
948
949 if (LOG.isDebugEnabled()) {
950 LOG.debug(String.format("Qualification total time = %s", Times.durationToString(System.currentTimeMillis() - start)));
951 }
952
953 }
954
955 @Override
956 public void qualifySurveys(List<Integer> surveyIds, Date qualificationDate, String qualificationComment, String qualityLevelCode) {
957
958 Assert.notEmpty(surveyIds);
959 Assert.notNull(qualificationDate);
960 Assert.notBlank(qualityLevelCode);
961
962 if (!QualityFlagCode.GOOD.getValue().equals(qualityLevelCode)) {
963 Assert.notBlank(qualificationComment);
964 }
965
966
967 qualificationComment = StringUtils.trimToNull(qualificationComment);
968
969 Integer qualifierId = dataContext.getRecorderPersonId();
970
971
972 Assert.isTrue(dataContext.isRecorderQualifier(), String.format("Recorder %s does not have qualifier privilege", qualifierId));
973
974 long start = System.currentTimeMillis();
975 for (Integer surveyId : surveyIds) {
976
977
978 surveyDao.qualify(surveyId, qualificationComment, qualificationDate, qualifierId, qualityLevelCode);
979
980 }
981
982 if (LOG.isDebugEnabled()) {
983 LOG.debug(String.format("qualification of %d survey(s) in %s",
984 surveyIds.size(), Times.durationToString(System.currentTimeMillis() - start)));
985 }
986
987 start = System.currentTimeMillis();
988 int nbSamplingOperations = samplingOperationDao.qualifyBySurveyIds(surveyIds, qualificationDate, qualityLevelCode);
989 if (LOG.isDebugEnabled()) {
990 LOG.debug(String.format("qualification of %d survey(s) in %s : %s sampling operations",
991 surveyIds.size(), Times.durationToString(System.currentTimeMillis() - start), nbSamplingOperations));
992 }
993
994 start = System.currentTimeMillis();
995 int nbMeasurements = measurementDao.qualifyAllMeasurementsBySurveyIds(surveyIds, qualificationDate);
996 if (LOG.isDebugEnabled()) {
997 LOG.debug(String.format("qualification of %d survey(s) in %s : %s (taxon)measurements",
998 surveyIds.size(), Times.durationToString(System.currentTimeMillis() - start), nbMeasurements));
999 }
1000
1001 start = System.currentTimeMillis();
1002 int nbPhotos = photoDao.qualifyBySurveyIds(surveyIds, qualificationDate);
1003 if (LOG.isDebugEnabled()) {
1004 LOG.debug(String.format("qualification of %d survey(s) in %s : %s photos",
1005 surveyIds.size(), Times.durationToString(System.currentTimeMillis() - start), nbPhotos));
1006 }
1007 }
1008
1009 @Override
1010 public List<ValidationHistoryDTO> getValidationHistory(int surveyId) {
1011 return surveyDao.getValidationHistory(surveyId);
1012 }
1013
1014 @Override
1015 public List<QualificationHistoryDTO> getQualificationHistory(int surveyId) {
1016 return surveyDao.getQualificationHistory(surveyId);
1017 }
1018
1019
1020
1021
1022
1023 @Override
1024 public long countSurveysWithProgramAndLocations(String programCode, List<Integer> locationIds) {
1025 Assert.notBlank(programCode);
1026
1027 return surveyDao.countSurveysWithProgramAndLocations(programCode, locationIds);
1028 }
1029
1030 @Override
1031 public long countSurveysWithProgramLocationAndOutsideDates(String programCode, int appliedStrategyId, int locationId, LocalDate startDate, LocalDate endDate) {
1032 Assert.notBlank(programCode);
1033 Assert.notNull(startDate);
1034 Assert.notNull(endDate);
1035
1036 return surveyDao.countSurveysWithProgramLocationAndOutsideDates(
1037 programCode,
1038 appliedStrategyId,
1039 locationId,
1040 Dates.convertToDate(startDate, config.getDbTimezone()),
1041 Dates.convertToDate(endDate, config.getDbTimezone()));
1042 }
1043
1044 @Override
1045 public long countSurveysWithProgramLocationAndInsideDates(String programCode, int appliedStrategyId, int locationId, LocalDate startDate, LocalDate endDate) {
1046 Assert.notBlank(programCode);
1047 Assert.notNull(startDate);
1048 Assert.notNull(endDate);
1049
1050 return surveyDao.countSurveysWithProgramLocationAndInsideDates(
1051 programCode,
1052 appliedStrategyId,
1053 locationId,
1054 Dates.convertToDate(startDate, config.getDbTimezone()),
1055 Dates.convertToDate(endDate, config.getDbTimezone()));
1056 }
1057
1058 @Override
1059 public long countSurveysWithProgramLocationAndOutsideDates(ProgStratDTO progStrat, int locationId) {
1060 Assert.notNull(progStrat);
1061
1062 return surveyDao.countSurveysWithProgramLocationAndOutsideDates(
1063 progStrat.getProgram().getCode(),
1064 progStrat.getAppliedStrategyId(),
1065 locationId,
1066 Dates.convertToDate(progStrat.getStartDate(), config.getDbTimezone()),
1067 Dates.convertToDate(progStrat.getEndDate(), config.getDbTimezone()));
1068 }
1069
1070 @Override
1071 public long countSurveysWithCampaign(int campaignId) {
1072
1073 return campaignService.countSurveysWithCampaign(campaignId);
1074 }
1075
1076 @Override
1077 public List<QualityLevelDTO> getQualityLevels() {
1078
1079
1080 List<QualityLevelDTO> result = new ArrayList<>(referentialService.getQualityLevels(StatusFilter.ACTIVE));
1081 result.remove(referentialService.getNotQualityLevel());
1082 return result;
1083 }
1084
1085
1086
1087
1088
1089 private SurveyDTO getSurvey(Integer surveyId, boolean withoutFilter) {
1090 Assert.notNull(surveyId);
1091
1092 SurveyDTO survey = surveyDao.getSurveyById(surveyId, withoutFilter);
1093
1094
1095 survey.setPmfmStrategies(programStrategyService.getPmfmStrategiesBySurvey(survey));
1096
1097 {
1098 List<PmfmDTO> pmfms = Lists.newArrayList();
1099 List<PmfmDTO> individualPmfms = Lists.newArrayList();
1100
1101
1102 for (PmfmStrategyDTO p : survey.getPmfmStrategies()) {
1103 if (p.isSurvey()) {
1104 if (p.isGrouping()) {
1105 individualPmfms.add(p.getPmfm());
1106 } else {
1107 pmfms.add(p.getPmfm());
1108 }
1109 }
1110 }
1111
1112
1113 survey.setPmfms(pmfms);
1114
1115
1116
1117 survey.setIndividualPmfms(individualPmfms);
1118 }
1119
1120
1121 DaliBeans.populatePmfmsFromMeasurements(survey);
1122
1123 if (!survey.isSamplingOperationsEmpty()) {
1124
1125
1126 List<PmfmDTO> pmfms = Lists.newArrayList();
1127 List<PmfmDTO> individualPmfms = Lists.newArrayList();
1128 for (PmfmStrategyDTO p : survey.getPmfmStrategies()) {
1129 if (p.isSampling()) {
1130 if (p.isGrouping()) {
1131 individualPmfms.add(p.getPmfm());
1132 } else {
1133 pmfms.add(p.getPmfm());
1134 }
1135 }
1136 }
1137
1138 for (SamplingOperationDTO samplingOperation : survey.getSamplingOperations()) {
1139
1140
1141 samplingOperation.setPmfms(pmfms);
1142 samplingOperation.setIndividualPmfms(individualPmfms);
1143
1144
1145 DaliBeans.populatePmfmsFromMeasurements(samplingOperation);
1146
1147 }
1148
1149 }
1150
1151 return survey;
1152
1153 }
1154
1155 private List<TaxonGroupDTO> getAvailableTaxonGroups(boolean forceNoContext) {
1156 if (dataContext.isContextFiltered(FilterTypeValues.TAXON_GROUP) && !forceNoContext) {
1157 return contextService.getFilteredTaxonGroups(dataContext.getContextId());
1158 } else {
1159 return referentialService.getTaxonGroups();
1160 }
1161 }
1162
1163 private List<TaxonDTO> getAvailableTaxons(boolean forceNoContext) {
1164 List<TaxonDTO> availableTaxons;
1165 if (dataContext.isContextFiltered(FilterTypeValues.TAXON) && !forceNoContext) {
1166 availableTaxons = contextService.getFilteredTaxons(dataContext.getContextId());
1167 } else {
1168 availableTaxons = referentialService.getTaxons(null);
1169 }
1170
1171
1172 availableTaxons = availableTaxons.stream().filter(taxon->!taxon.isObsolete()).collect(Collectors.toList());
1173
1174 referentialService.fillReferentTaxons(availableTaxons);
1175 return availableTaxons;
1176 }
1177
1178
1179
1180
1181
1182
1183 private void applyDefaultAnalysisDepartment(SurveyDTO survey) {
1184 Assert.notNull(survey);
1185
1186
1187 DepartmentDTO analysisDepartment = programStrategyService.getSamplingDepartmentOfAppliedStrategyBySurvey(survey);
1188
1189
1190 if (analysisDepartment == null) {
1191 return;
1192 }
1193
1194
1195 if (survey.isMeasurementsLoaded()) {
1196
1197 for (MeasurementDTO measurement : survey.getMeasurements()) {
1198 if (measurement.getAnalyst() == null) {
1199 measurement.setAnalyst(analysisDepartment);
1200 }
1201 }
1202
1203
1204 for (MeasurementDTO measurement : survey.getIndividualMeasurements()) {
1205 if (measurement.getAnalyst() == null) {
1206 measurement.setAnalyst(analysisDepartment);
1207 }
1208 }
1209 }
1210
1211
1212 if (survey.isSamplingOperationsLoaded()
1213 && CollectionUtils.isNotEmpty(survey.getSamplingOperations())) {
1214
1215
1216 for (SamplingOperationDTO samplingOperation : survey.getSamplingOperations()) {
1217 if (samplingOperation.isMeasurementsLoaded()) {
1218
1219 for (MeasurementDTO measurement : samplingOperation.getMeasurements()) {
1220 if (measurement.getAnalyst() == null) {
1221 measurement.setAnalyst(analysisDepartment);
1222 }
1223 }
1224 }
1225
1226 if (samplingOperation.isIndividualMeasurementsLoaded()) {
1227
1228 for (MeasurementDTO measurement : samplingOperation.getIndividualMeasurements()) {
1229 if (measurement.getAnalyst() == null) {
1230 measurement.setAnalyst(analysisDepartment);
1231 }
1232 }
1233 }
1234 }
1235 }
1236 }
1237
1238 }