blob: 8f8feaa10f302633b4c83848a397b16d664b83db [file] [log] [blame]
/*
*******************************************************************************
* Copyright (c) 2019 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************
*/
package org.eclipse.openk.gridfailureinformation.service;
import lombok.extern.log4j.Log4j2;
import org.eclipse.openk.gridfailureinformation.bpmn.base.ProcessException;
import org.eclipse.openk.gridfailureinformation.bpmn.impl.GfiGrid;
import org.eclipse.openk.gridfailureinformation.bpmn.impl.GfiProcessState;
import org.eclipse.openk.gridfailureinformation.bpmn.impl.GfiProcessSubject;
import org.eclipse.openk.gridfailureinformation.bpmn.impl.tasks.ProcessHelper;
import org.eclipse.openk.gridfailureinformation.constants.Constants;
import org.eclipse.openk.gridfailureinformation.enums.OperationType;
import org.eclipse.openk.gridfailureinformation.exceptions.BadRequestException;
import org.eclipse.openk.gridfailureinformation.exceptions.InternalServerErrorException;
import org.eclipse.openk.gridfailureinformation.exceptions.NotFoundException;
import org.eclipse.openk.gridfailureinformation.exceptions.OperationDeniedException;
import org.eclipse.openk.gridfailureinformation.mapper.FailureInformationMapper;
import org.eclipse.openk.gridfailureinformation.mapper.FailureInformationPublicationChannelMapper;
import org.eclipse.openk.gridfailureinformation.mapper.tools.AddressSplitterMerger;
import org.eclipse.openk.gridfailureinformation.model.HtblFailureInformation;
import org.eclipse.openk.gridfailureinformation.model.RefBranch;
import org.eclipse.openk.gridfailureinformation.model.RefExpectedReason;
import org.eclipse.openk.gridfailureinformation.model.RefStatus;
import org.eclipse.openk.gridfailureinformation.model.TblAddress;
import org.eclipse.openk.gridfailureinformation.model.TblFailureInformation;
import org.eclipse.openk.gridfailureinformation.model.TblFailureInformationPublicationChannel;
import org.eclipse.openk.gridfailureinformation.model.TblFailureInformationReminderMailSent;
import org.eclipse.openk.gridfailureinformation.model.TblFailureInformationStation;
import org.eclipse.openk.gridfailureinformation.model.TblStation;
import org.eclipse.openk.gridfailureinformation.repository.AddressRepository;
import org.eclipse.openk.gridfailureinformation.repository.BranchRepository;
import org.eclipse.openk.gridfailureinformation.repository.DistributionGroupRepository;
import org.eclipse.openk.gridfailureinformation.repository.ExpectedReasonRepository;
import org.eclipse.openk.gridfailureinformation.repository.FailureClassificationRepository;
import org.eclipse.openk.gridfailureinformation.repository.FailureInformationDistributionGroupRepository;
import org.eclipse.openk.gridfailureinformation.repository.FailureInformationPublicationChannelRepository;
import org.eclipse.openk.gridfailureinformation.repository.FailureInformationReminderMailSentRepository;
import org.eclipse.openk.gridfailureinformation.repository.FailureInformationRepository;
import org.eclipse.openk.gridfailureinformation.repository.FailureInformationStationRepository;
import org.eclipse.openk.gridfailureinformation.repository.HistFailureInformationRepository;
import org.eclipse.openk.gridfailureinformation.repository.RadiusRepository;
import org.eclipse.openk.gridfailureinformation.repository.StationRepository;
import org.eclipse.openk.gridfailureinformation.repository.StatusRepository;
import org.eclipse.openk.gridfailureinformation.util.ExternalStatusCalculator;
import org.eclipse.openk.gridfailureinformation.util.GrahamScan;
import org.eclipse.openk.gridfailureinformation.viewmodel.FailureInformationDto;
import org.eclipse.openk.gridfailureinformation.viewmodel.FailureInformationLastModDto;
import org.eclipse.openk.gridfailureinformation.viewmodel.FailureInformationPublicationChannelDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.awt.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import static org.eclipse.openk.gridfailureinformation.constants.Constants.FREETEXT_ADDRESS_TYPE;
@Log4j2
@Service
public class FailureInformationService {
@Value("${spring.settings.daysInPastToShowClosedInfos}")
private int daysInPastToShowClosedInfos;
@Autowired
private FailureInformationRepository failureInformationRepository;
@Autowired
private HistFailureInformationRepository histFailureInformationRepository;
@Autowired
private FailureInformationMapper failureInformationMapper;
@Autowired
private FailureInformationPublicationChannelMapper failureInformationPublicationChannelMapper;
@Autowired
private BranchRepository branchRepository;
@Autowired
private FailureClassificationRepository failureClassificationRepository;
@Autowired
private RadiusRepository radiusRepository;
@Autowired
private ExpectedReasonRepository expectedReasonRepository;
@Autowired
private StatusRepository statusRepository;
@Autowired
private StationRepository stationRepository;
@Autowired
private AddressRepository addressRepository;
@Autowired
private DistributionGroupRepository distributionGroupRepository;
@Autowired
private FailureInformationDistributionGroupRepository failureInformationDistributionGroupRepository;
@Autowired
private FailureInformationPublicationChannelRepository failureInformationPublicationChannelRepository;
@Autowired
private FailureInformationStationRepository failureInformationStationRepository;
@Autowired
FailureInformationReminderMailSentRepository failureInformationReminderMailSentRepository;
@Autowired
HistFailureInformationStationService histFailureInformationStationService;
@Autowired
private GfiGrid grid;
@Autowired
private ProcessHelper processHelper;
public FailureInformationDto findFailureInformation( UUID uuid ) {
TblFailureInformation existingTblFailureInfo = failureInformationRepository.findByUuid( uuid )
.orElseThrow(NotFoundException::new);
return enrichFailureInfo(failureInformationMapper.toFailureInformationDto(existingTblFailureInfo));
}
public Page<FailureInformationDto> findFailureInformations(Pageable pageable) {
Page<FailureInformationDto> retPage = findFailureInformationsForDisplay(pageable)
.map(failureInformationMapper::toFailureInformationDto);
retPage.getContent().forEach(this::enrichFailureInfo);
return retPage;
}
public Page<TblFailureInformation> findFailureInformationsForDisplay(Pageable pageable) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime ldt = LocalDateTime.of(now.getYear(), now.getMonth(), now.getDayOfMonth(), 0, 0, 0);
ldt = ldt.minusDays(daysInPastToShowClosedInfos);
Date nowMinusFourWeeks = Date.from(ldt.atZone(ZoneId.of("UTC")).toInstant());
return failureInformationRepository.findByTblFailureInformationForDisplay(
GfiProcessState.COMPLETED.getStatusValue(),
GfiProcessState.CANCELED.getStatusValue(),
nowMinusFourWeeks, pageable);
}
public List<FailureInformationDto> findFailureInformationsByCondensedUuid(UUID uuid) {
List<FailureInformationDto> listFailureInformationDtos = new LinkedList<>();
List<TblFailureInformation> listFailureInformations = failureInformationRepository.findByFailureInformationCondensedUuid(uuid);
for(TblFailureInformation tblInfo: listFailureInformations){
FailureInformationDto infoDto = failureInformationMapper.toFailureInformationDto(tblInfo);
enrichFailureInfo(infoDto);
listFailureInformationDtos.add(infoDto);
}
return listFailureInformationDtos;
}
public FailureInformationDto findByObjectReferenceExternalSystem( String extRef ) {
Optional<TblFailureInformation> tblFailureInformation
= failureInformationRepository.findByObjectReferenceExternalSystem( extRef );
if( tblFailureInformation.isPresent() ) {
return failureInformationMapper.toFailureInformationDto(tblFailureInformation.get());
}
else {
return null;
}
}
@Transactional
public FailureInformationDto insertFailureInfo(FailureInformationDto failureInfoDto, GfiProcessState initialState) {
failureInfoDto.setUuid(null); // force null here
return storeFailureInfo(failureInfoDto, initialState);
}
@Transactional
public FailureInformationDto updateFailureInfo(FailureInformationDto failureInfoDto) {
return processGrid(failureInfoDto, null);
}
@Transactional
public FailureInformationDto updateAndPublish( FailureInformationDto failureInformationDto) {
if( getRefStatus(failureInformationDto).getId() != GfiProcessState.QUALIFIED.getStatusValue()) {
throw new BadRequestException("Publishing is only possible with state 'qualified'");
}
TblFailureInformation tblFailureInfo = failureInformationRepository.findByUuid(failureInformationDto.getUuid()).orElseThrow(()-> new NotFoundException(""));
List<TblFailureInformationPublicationChannel> channelList = failureInformationPublicationChannelRepository.findByTblFailureInformation(tblFailureInfo);
if( channelList.isEmpty()) {
throw new BadRequestException("Publishing is only possible with at least one selected channel");
}
return processGrid(failureInformationDto, GfiProcessState.CHECKED_FOR_PUBLISH_);
}
public FailureInformationDto storeFailureInfo(FailureInformationDto dto, GfiProcessState initialState) {
TblFailureInformation tblFailureInformationToSave = failureInformationMapper.toTblFailureInformation(dto);
if(dto.getUuid() == null ) {
tblFailureInformationToSave.setUuid(UUID.randomUUID());
tblFailureInformationToSave.setVersionNumber(1L);
setFromGridFailureInformationDto(tblFailureInformationToSave, dto);
RefStatus refStatus = statusRepository.findById(initialState.getStatusValue())
.orElseThrow(() -> new NotFoundException("ref.status.not.found"));
tblFailureInformationToSave.setRefStatusIntern(refStatus);
tblFailureInformationToSave.setCondensedCount(0);
tblFailureInformationToSave.setCondensed(false);
} else {
TblFailureInformation tblFailureInformation = failureInformationRepository.findByUuid(dto.getUuid())
.orElseThrow(() -> new NotFoundException(Constants.FAILURE_INFO_UUID_NOT_EXISTING));
tblFailureInformationToSave = failureInformationMapper.toTblFailureInformation(dto);
tblFailureInformationToSave.setId(tblFailureInformation.getId());
setFromGridFailureInformationDto(tblFailureInformationToSave, dto);
setVersionNumber(tblFailureInformationToSave);
}
TblFailureInformation tblFailureInformationSaved = failureInformationRepository.save(tblFailureInformationToSave);
FailureInformationDto failureInformationDto = failureInformationMapper.toFailureInformationDto(tblFailureInformationSaved);
storeStations(tblFailureInformationSaved, dto.getStationIds());
FailureInformationDto enrichedFailureInformationDto = enrichFailureInfo(failureInformationDto);
// insert stations in history table
histFailureInformationStationService.insertHistFailureInfoStationsForGfi(tblFailureInformationSaved);
return enrichedFailureInformationDto;
}
private void storeStations( TblFailureInformation tblToStore, List<UUID> stationIds ) {
List<TblStation> stationList = resolveStationIds(stationIds);
Set<TblStation> stationSet = new HashSet<>(stationList);
if(stationList.size() > stationSet.size()){
throw new OperationDeniedException(OperationType.INSERT, "double.assignment.of.stations");
}
List<TblFailureInformationStation> tblFailureStations
= failureInformationStationRepository.findByFkTblFailureInformation(tblToStore.getId());
failureInformationStationRepository.deleteAll(tblFailureStations);
stationList.forEach(x-> {
TblFailureInformationStation newRecord = new TblFailureInformationStation();
newRecord.setStationStationId(x.getStationId());
newRecord.setFkTblFailureInformation(tblToStore.getId());
failureInformationStationRepository.save(newRecord);
});
}
private FailureInformationDto processGrid(FailureInformationDto failureInfoDto, GfiProcessState forcedState) {
GfiProcessSubject subject = GfiProcessSubject.of(failureInfoDto, processHelper );
if( forcedState != null ) {
subject.setStateInDb(forcedState); // use forced state
}
else {
// use state from db
RefStatus refStatus = getRefStatus(failureInfoDto);
subject.setStateInDb(GfiProcessState.fromValue(refStatus.getId()));
}
try {
grid.recover( subject ).start(subject::getStateInDb);
} catch (ProcessException e) {
log.error( e.getMessage() + " -> \r\n" + e.getStackTrace());
throw new InternalServerErrorException(e.getMessage());
}
return subject.getFailureInformationDto();
}
@Transactional
public RefStatus getRefStatus(FailureInformationDto failureInfoDto) {
FailureInformationDto failureInfoDtoDB = findFailureInformation(failureInfoDto.getUuid());
return statusRepository.findByUuid(failureInfoDtoDB.getStatusInternId())
.orElseThrow( () -> new InternalServerErrorException("status.not.found.or.null"));
}
private void setFromGridFailureInformationDto( TblFailureInformation destTblFailureInformation, FailureInformationDto sourceDto ) {
resolveBranch(destTblFailureInformation, sourceDto);
resolveFailureClassification(destTblFailureInformation, sourceDto);
resolveStatii(destTblFailureInformation, sourceDto);
resolveRadius(destTblFailureInformation, sourceDto);
resolveExpectedReason(destTblFailureInformation, sourceDto);
resolveCondensed(destTblFailureInformation, sourceDto);
destTblFailureInformation.setStations(resolveStationIds(sourceDto.getStationIds()));
}
private List<TblStation> resolveStationIds(List<UUID> stationUuids) {
if( stationUuids != null ) {
List<TblStation> stationList = new ArrayList<>();
for (UUID stationUuid: stationUuids) {
stationList.add(stationRepository.findByUuid(stationUuid).orElseThrow(() -> new NotFoundException("station.uuid.not.existing")));
}
return stationList;
}
return new LinkedList<>();
}
private void resolveCondensed(TblFailureInformation destTblFailureInformation, FailureInformationDto sourceDto) {
if( sourceDto.getFailureInformationCondensedId() != null ) {
destTblFailureInformation.setTblFailureInformationCondensed( failureInformationRepository
.findByUuid(sourceDto.getFailureInformationCondensedId())
.orElseThrow(() -> new NotFoundException(Constants.FAILURE_INFO_UUID_NOT_EXISTING)));
}
else {
destTblFailureInformation.setTblFailureInformationCondensed(null);
}
}
private void resolveExpectedReason(TblFailureInformation destTblFailureInformation, FailureInformationDto sourceDto) {
if( sourceDto.getExpectedReasonId() != null ) {
destTblFailureInformation.setRefExpectedReason( expectedReasonRepository
.findByUuid(sourceDto.getExpectedReasonId())
.orElseThrow(() -> new NotFoundException("expected.reason.uuid.not.existing")));
}
else {
destTblFailureInformation.setRefExpectedReason(null);
}
}
private void resolveRadius(TblFailureInformation destTblFailureInformation, FailureInformationDto sourceDto) {
if( sourceDto.getRadiusId() != null ) {
destTblFailureInformation.setRefRadius( radiusRepository
.findByUuid(sourceDto.getRadiusId())
.orElseThrow(() -> new NotFoundException("radius.uuid.not.existing")));
}
else {
destTblFailureInformation.setRefRadius(null);
}
}
private void resolveStatii(TblFailureInformation destTblFailureInformation, FailureInformationDto sourceDto) {
if( sourceDto.getStatusInternId() != null ) {
destTblFailureInformation.setRefStatusIntern( statusRepository
.findByUuid(sourceDto.getStatusInternId())
.orElseThrow(() -> new NotFoundException("status.uuid.not.existing")));
}
else {
destTblFailureInformation.setRefStatusIntern(null);
}
}
private void resolveFailureClassification(TblFailureInformation destTblFailureInformation, FailureInformationDto sourceDto) {
if( sourceDto.getFailureClassificationId() != null ) {
destTblFailureInformation.setRefFailureClassification( failureClassificationRepository
.findByUuid(sourceDto.getFailureClassificationId())
.orElseThrow(() -> new NotFoundException("failure.classification.uuid.not.existing")));
}
else {
destTblFailureInformation.setRefFailureClassification(null);
}
}
private void resolveBranch(TblFailureInformation destTblFailureInformation, FailureInformationDto sourceDto) {
if( sourceDto.getBranchId() != null ) {
destTblFailureInformation.setRefBranch( branchRepository
.findByUuid(sourceDto.getBranchId())
.orElseThrow(() -> new NotFoundException("branch.uuid.not.existing")));
}
else {
destTblFailureInformation.setRefBranch(null);
}
}
private void setVersionNumber(TblFailureInformation tblFailureInformation){
List<HtblFailureInformation> hfailureList = histFailureInformationRepository.findByUuid(tblFailureInformation.getUuid());
Long lastVersion = hfailureList.stream().map(HtblFailureInformation::getVersionNumber).max(Comparator.naturalOrder()).orElse(0L) ;
tblFailureInformation.setVersionNumber(lastVersion+1);
}
public FailureInformationDto enrichFailureInfo(FailureInformationDto failureInformationDto) {
// wenn Mittelspannung dann füge Adress-Polygonpunkte für Kartenanzeige hinzu
if(failureInformationDto.getVoltageLevel() != null && failureInformationDto.getVoltageLevel().equals("MS")) {
addPolygonAddressPoints(failureInformationDto);
}
ExternalStatusCalculator.addExternalStatus( statusRepository, failureInformationDto);
enrichStations(failureInformationDto);
return failureInformationDto;
}
@Transactional
public FailureInformationDto updateSubordinatedFailureInfos(UUID condensedUuid, List<UUID> subordinatedUuidList){
return condenseFailureInfos(subordinatedUuidList, Optional.of(condensedUuid));
}
private void storeSubordinated(TblFailureInformation child, TblFailureInformation parent) {
child.setCondensed(false);
child.setTblFailureInformationCondensed(parent);
setVersionNumber(child);
failureInformationRepository.save(child);
}
protected boolean containsAlienSubordinatedFailureInfos(Optional<UUID> condensedUuid, List<UUID> subordinatedUuidList){
List<TblFailureInformation> futureSubordinateFailureInfoList = failureInformationRepository
.findByUuidIn(subordinatedUuidList);
List<TblFailureInformation> filteredList = futureSubordinateFailureInfoList.stream()
.filter(x -> x.getTblFailureInformationCondensed() != null)
.collect(Collectors.toList());
if( condensedUuid.isPresent()) {
filteredList = filteredList.stream()
.filter(x -> !x.getTblFailureInformationCondensed().getUuid().equals( condensedUuid.get()) )
.collect(Collectors.toList());
}
return !filteredList.isEmpty();
}
private void enrichStations( FailureInformationDto dto) {
List<UUID> stationList = failureInformationStationRepository.findUuidByFkTblFailureInformation(dto.getUuid());
dto.setStationIds(stationList);
}
@Transactional
public FailureInformationDto condenseFailureInfos(List<UUID> listUuids, Optional<UUID> condensedUuid){
// pruefen, ob in der uebergebenen Liste unterzuordnender FailureInfos Teile einer anderen Verdichtung sind
if (containsAlienSubordinatedFailureInfos(condensedUuid, listUuids)) {
throw new BadRequestException("failure.info.already.subordinated");
}
if(listUuids.isEmpty()){
throw new BadRequestException("empty.array.for.subordinated.failure.infos");
}
List<TblFailureInformation> listNewSubordinatedFailureInfos= failureInformationRepository.findByUuidIn(listUuids);
List<TblFailureInformation> oldListOfSubordinatedFailureInfos = (condensedUuid.isPresent() ?
failureInformationRepository.findByFailureInformationCondensedUuid(condensedUuid.get()) : new ArrayList<>());
if(!checkSameBranch(listNewSubordinatedFailureInfos)) {
throw new OperationDeniedException(OperationType.CONDENSE, "failure.infos.have.different.branches");
}
TblFailureInformation condensedFailureInformation = getOrCreateCondensedFailureInfo(condensedUuid);
condensedFailureInformation.setRefBranch(listNewSubordinatedFailureInfos.get(0).getRefBranch());
setCondensedFieldsFromMany(condensedFailureInformation, listNewSubordinatedFailureInfos);
condensedFailureInformation.setCondensed(true);
condensedFailureInformation.setCondensedCount(listNewSubordinatedFailureInfos.size());
TblFailureInformation condensedFailureInformationSaved = failureInformationRepository.save(condensedFailureInformation);
storeCondensedStations(listNewSubordinatedFailureInfos, condensedFailureInformationSaved);
//kennzeichne die neu hingefügt FailureInfos und speichere
listNewSubordinatedFailureInfos.stream()
.filter( x -> listUuids.contains(x.getUuid()))
.forEach( x -> storeSubordinated(x, condensedFailureInformationSaved));
// die alten nicht mehr zugeordneten FailureInfos freigeben
oldListOfSubordinatedFailureInfos.stream()
.filter( x -> !listUuids.contains(x.getUuid()))
.forEach( x -> storeSubordinated(x, null));
return enrichFailureInfo( failureInformationMapper.toFailureInformationDto(condensedFailureInformationSaved));
}
private void setCondensedFieldsFromMany(TblFailureInformation condensedFailureInformation, List<TblFailureInformation> listSubordinatedFailureInfos) {
setVoltageLevel(listSubordinatedFailureInfos, condensedFailureInformation);
setEarliestStartdate(listSubordinatedFailureInfos, condensedFailureInformation);
setLatestEnddate(listSubordinatedFailureInfos, condensedFailureInformation);
setExpectedReason(listSubordinatedFailureInfos, condensedFailureInformation);
setAddress(listSubordinatedFailureInfos, condensedFailureInformation);
setRadius(listSubordinatedFailureInfos, condensedFailureInformation);
RefStatus refStatusNew = statusRepository
.findById(GfiProcessState.NEW.getStatusValue())
.orElseThrow(() -> new NotFoundException("status.not.existing"));
condensedFailureInformation.setRefStatusIntern(refStatusNew);
}
private TblFailureInformation getOrCreateCondensedFailureInfo(Optional<UUID> condensedUuid) {
TblFailureInformation condensedFailureInformation;
if(condensedUuid.isPresent()){
// update einer bestehenden Verdichtung
condensedFailureInformation = failureInformationRepository
.findByUuid(condensedUuid.get())
.orElseThrow(() -> new NotFoundException(Constants.FAILURE_INFO_UUID_NOT_EXISTING));
this.setVersionNumber(condensedFailureInformation);
}
else {
// neue Verdichtung
condensedFailureInformation = new TblFailureInformation();
condensedFailureInformation.setUuid(UUID.randomUUID());
condensedFailureInformation.setVersionNumber(1L);
}
return condensedFailureInformation;
}
private void storeCondensedStations(List<TblFailureInformation> listFailureInfos, TblFailureInformation condensedFailureInformation) {
// get unique set of station (strings) from all subordinated failureinfos
Set<String> stationsSuperSet = new HashSet<>();
listFailureInfos.forEach( x ->
stationsSuperSet.addAll(
failureInformationStationRepository.findByFkTblFailureInformation(x.getId())
.stream()
.map( TblFailureInformationStation::getStationStationId )
.collect(Collectors.toList())
)
);
final List<TblFailureInformationStation> byFkTblFailureInformation = failureInformationStationRepository.findByFkTblFailureInformation(condensedFailureInformation.getId());
Set<String> stationsOfOldExistingCondensedFi =
byFkTblFailureInformation.stream()
.map( TblFailureInformationStation::getStationStationId )
.collect(Collectors.toSet());
// store the set for the newly created failure info
stationsSuperSet
.stream()
.filter( x -> !stationsOfOldExistingCondensedFi.contains(x))
.forEach( x -> {
TblFailureInformationStation fis = new TblFailureInformationStation();
fis.setFkTblFailureInformation(condensedFailureInformation.getId());
fis.setStationStationId(x);
failureInformationStationRepository.save(fis);
});
// remove obsolete stations
byFkTblFailureInformation.stream()
.filter( x -> !stationsSuperSet.contains(x.getStationStationId()))
.forEach( x -> failureInformationStationRepository.delete(x));
}
private void setRadius(List<TblFailureInformation> listFailureInfos, TblFailureInformation condensedFailureInformation){
condensedFailureInformation.setRefRadius(
listFailureInfos.stream()
.filter(fi -> fi.getRefRadius() != null)
.map(TblFailureInformation::getRefRadius)
.max( (x,y) -> Long.compare(x.getRadius(), y.getRadius()))
.orElse( null ));
}
private void setAddress(List<TblFailureInformation> listFailureInfos, TblFailureInformation condensedFailureInformation){
Optional<TblFailureInformation> firstCompleteFailureInformation = listFailureInfos
.stream()
.filter(f -> (f.getPostcode() != null && f.getStreet() != null && f.getHousenumber() != null) || (f.getAddressType() != null && f.getAddressType().equals(FREETEXT_ADDRESS_TYPE)))
.findFirst();
if (!firstCompleteFailureInformation.isPresent()) {
setCondensedFailureInformationAddress(condensedFailureInformation, null);
} else {
String address = concatAddress(firstCompleteFailureInformation.get());
List<TblFailureInformation> filteredList = listFailureInfos
.stream()
.filter(f -> (f.getPostcode() != null && f.getStreet() != null && f.getHousenumber() != null) || (f.getAddressType() != null && f.getAddressType().equals(FREETEXT_ADDRESS_TYPE)))
.filter(f -> concatAddress(f).equals(address))
.collect(Collectors.toList());
if (listFailureInfos.size() == filteredList.size()) {
setCondensedFailureInformationAddress(condensedFailureInformation, firstCompleteFailureInformation.get());
}
else{
setCondensedFailureInformationAddress(condensedFailureInformation, null);
}
}
}
private void setCondensedFailureInformationAddress(TblFailureInformation condensedFailureInformation, TblFailureInformation failureInformation) {
condensedFailureInformation.setPostcode(failureInformation != null ? failureInformation.getPostcode() : null);
condensedFailureInformation.setStreet(failureInformation != null ? failureInformation.getStreet() : null);
condensedFailureInformation.setHousenumber(failureInformation != null ? failureInformation.getHousenumber() : null);
condensedFailureInformation.setCity(failureInformation != null ? failureInformation.getCity() : null);
condensedFailureInformation.setDistrict(failureInformation != null ? failureInformation.getDistrict() : null);
condensedFailureInformation.setLongitude(failureInformation != null ? failureInformation.getLongitude() : null);
condensedFailureInformation.setLatitude(failureInformation != null ? failureInformation.getLatitude() : null);
condensedFailureInformation.setAddressType(failureInformation != null ? failureInformation.getAddressType() : null);
}
private String concatAddress(TblFailureInformation failureInformation) {
if (failureInformation == null) return null;
return failureInformation.getPostcode() + failureInformation.getStreet() + failureInformation.getHousenumber();
}
private void setExpectedReason(List<TblFailureInformation> listFailureInfos, TblFailureInformation condensedFailureInformation){
RefExpectedReason firstExpReason = listFailureInfos.get(0).getRefExpectedReason();
UUID firstExpectedReason = firstExpReason != null ? firstExpReason.getUuid() : null;
List<TblFailureInformation> filteredList = listFailureInfos
.stream()
.filter(f-> f.getRefExpectedReason() != null && f.getRefExpectedReason().getUuid()!=null)
.filter(f -> f.getRefExpectedReason().getUuid().equals(firstExpectedReason))
.collect(Collectors.toList());
if (listFailureInfos.size() == filteredList.size()) {
condensedFailureInformation.setRefExpectedReason(listFailureInfos.get(0).getRefExpectedReason());
}
else{
condensedFailureInformation.setRefExpectedReason(null);
}
}
private void setLatestEnddate(List<TblFailureInformation> listFailureInfos, TblFailureInformation condensedFailureInformation){
Date latest = listFailureInfos
.stream()
.filter(f -> f.getFailureEndPlanned() != null)
.map(TblFailureInformation::getFailureEndPlanned).max(Comparator.naturalOrder())
.orElse(null);
condensedFailureInformation.setFailureEndPlanned(latest);
}
private void setEarliestStartdate(List<TblFailureInformation> listFailureInfos, TblFailureInformation condensedFailureInfo){
Date earliest = listFailureInfos
.stream()
.filter(f -> f.getFailureBegin() != null)
.map(TblFailureInformation::getFailureBegin).min(Comparator.naturalOrder())
.orElse(null);
condensedFailureInfo.setFailureBegin(earliest);
}
private boolean checkSameBranch(List<TblFailureInformation> listFailureInfos){
RefBranch firstBranch = listFailureInfos.get(0).getRefBranch();
List<TblFailureInformation> filteredList = listFailureInfos.stream().filter(f -> f.getRefBranch().equals(firstBranch)).collect(Collectors.toList());
return listFailureInfos.size() == filteredList.size();
}
private void setVoltageLevel(List<TblFailureInformation> listFailureInfos, TblFailureInformation condensedFailureInfo){
String firstVoltageLevel = listFailureInfos.get(0).getVoltageLevel();
List<TblFailureInformation> filteredList = listFailureInfos
.stream()
.filter(f -> f.getVoltageLevel()!= null)
.filter(f -> f.getVoltageLevel().equals(firstVoltageLevel))
.collect(Collectors.toList());
if (listFailureInfos.size() == filteredList.size()) {
condensedFailureInfo.setVoltageLevel(firstVoltageLevel);
}
else{
condensedFailureInfo.setVoltageLevel(null);
}
}
private void addPolygonAddressPoints(FailureInformationDto failureInformationDto){
// Stationen ermitteln
List<UUID> stationUuids =
failureInformationStationRepository.findUuidByFkTblFailureInformation(failureInformationDto.getUuid());
if(stationUuids.isEmpty()) {
log.debug("No station ids found for failureInfo: " + failureInformationDto.getUuid().toString());
return;
}
List<ArrayList<BigDecimal>> addressPolygonPoints = getPolygonCoordinatesForStationUuids(stationUuids);
if(!addressPolygonPoints.isEmpty()) {
failureInformationDto.setAddressPolygonPoints(addressPolygonPoints);
}
}
public List<ArrayList<BigDecimal>> getPolygonCoordinatesForStationUuids (List<UUID> stationUuids) {
List<TblAddress> allAdresses = new ArrayList<>();
List<ArrayList<BigDecimal>> addressPolygonPoints = new LinkedList<>();
// Holen der Adressen, die fuer die Stoerungsinformation relevant sind
for (UUID stationUuid : stationUuids) {
TblStation tblStation = stationRepository
.findByUuid(stationUuid)
.orElse(null);
if (tblStation == null) {
log.warn("station " + stationUuid.toString() + "not found ");
} else {
List<TblAddress> addressListForStation = addressRepository.findByStationId(tblStation.getStationId());
if (addressListForStation.isEmpty()) {
log.debug("Station " + stationUuid.toString() + "has no addresses.");
} else {
allAdresses.addAll(addressListForStation);
}
}
}
List<Point> addressPoints = new LinkedList<>();
// Hinzufügen der gefundenen Adressen zur Liste der Adresspunkte
// (Multiplikation mit 1000000 notwendig zur Erlangung von ganzzahligen Werten für die Übergabe an GrahamScan)
allAdresses
.forEach(x -> addressPoints.add
(new Point((x.getLatitude().setScale(6, RoundingMode.FLOOR).movePointRight(6)).intValue(),
(x.getLongitude().setScale(6, RoundingMode.FLOOR).movePointRight(6)).intValue())));
if (addressPoints.isEmpty()) {
log.debug("No addresses for the given stations available");
return addressPolygonPoints;
}
// GrahamScan über die Adresspunkte zum Erhalt der äußeren Punkte, die ein Polygon bilden
List<Point> polygonPoints = GrahamScan.getConvexHull(addressPoints);
// Verpacken der Polygonpunkte in eine Liste von Arrays (longitude/latitude) die ins DTO der Störungsmeldung geschrieben wird
// (Division durch 1000000 notwendig zur Wiedererlangung der ursprünglichen Werte)
for (Point point : polygonPoints) {
ArrayList<BigDecimal> twoValues = new ArrayList<>();
twoValues.add(BigDecimal.valueOf(point.getX()).movePointLeft(6));
twoValues.add(BigDecimal.valueOf(point.getY()).movePointLeft(6));
addressPolygonPoints.add(twoValues);
}
return addressPolygonPoints;
}
public FailureInformationPublicationChannelDto insertPublicationChannelForFailureInfo(UUID failureInfoUuid, String publicationChannel){
TblFailureInformation existingTblFailureInformation = failureInformationRepository
.findByUuid(failureInfoUuid)
.orElseThrow(() -> new NotFoundException(Constants.FAILURE_INFO_UUID_NOT_EXISTING));
//check if channel is already existing
if(failureInformationPublicationChannelRepository.countByTblFailureInformationAndPublicationChannel(existingTblFailureInformation, publicationChannel)>0){
throw new BadRequestException("channel.already.existing");
}
//create new channel
TblFailureInformationPublicationChannel tfiPublicationChannelToSave = new TblFailureInformationPublicationChannel();
tfiPublicationChannelToSave.setTblFailureInformation(existingTblFailureInformation);
tfiPublicationChannelToSave.setPublicationChannel(publicationChannel);
tfiPublicationChannelToSave.setPublished(false);
TblFailureInformationPublicationChannel savedTfiPublicationChannel = failureInformationPublicationChannelRepository.save(tfiPublicationChannelToSave);
return failureInformationPublicationChannelMapper.toFailureInformationPublicationChannelDto(savedTfiPublicationChannel);
}
public void deletePublicationChannelForFailureInfo(UUID failureInfoUuid, String publicationChannel){
TblFailureInformation existingTblFailureInformation = failureInformationRepository
.findByUuid(failureInfoUuid)
.orElseThrow(() -> new NotFoundException(Constants.FAILURE_INFO_UUID_NOT_EXISTING));
TblFailureInformationPublicationChannel existingTblFailureInformationPublicationChannel = failureInformationPublicationChannelRepository
.findByTblFailureInformationAndPublicationChannel(existingTblFailureInformation, publicationChannel)
.orElseThrow(() -> new NotFoundException("channel.not.existing"));
failureInformationPublicationChannelRepository.delete(existingTblFailureInformationPublicationChannel);
}
public List<FailureInformationPublicationChannelDto> getPublicationChannelsForFailureInfo(UUID failureInfoUuid){
TblFailureInformation existingTblFailureInformation = failureInformationRepository
.findByUuid(failureInfoUuid)
.orElseThrow(() -> new NotFoundException(Constants.FAILURE_INFO_UUID_NOT_EXISTING));
List<TblFailureInformationPublicationChannel> publicationChannels = failureInformationPublicationChannelRepository
.findByTblFailureInformation(existingTblFailureInformation);
return publicationChannels
.stream()
.map(x -> failureInformationPublicationChannelMapper.toFailureInformationPublicationChannelDto(x))
.collect(Collectors.toList());
}
@Transactional
public void deleteFailureInfo(UUID failureInfoUuid){
TblFailureInformation existingTblFailureInformation = failureInformationRepository
.findByUuid(failureInfoUuid)
.orElseThrow(() -> new NotFoundException("failure.info.uuid.not.existing"));
if(isStatusNewPlannedCreated(existingTblFailureInformation)){
failureInformationPublicationChannelRepository.findByTblFailureInformation(existingTblFailureInformation)
.forEach(failureInformationPublicationChannelRepository::delete);
Optional<TblFailureInformationReminderMailSent> reminder = failureInformationReminderMailSentRepository.findByTblFailureInformation(existingTblFailureInformation);
if(reminder.isPresent()) {
failureInformationReminderMailSentRepository.deleteByTblFailureInformation(existingTblFailureInformation);
}
failureInformationStationRepository.findByFkTblFailureInformation(existingTblFailureInformation.getId())
.forEach(failureInformationStationRepository::delete);
failureInformationDistributionGroupRepository.findByFkTblFailureInformation(existingTblFailureInformation.getId())
.forEach(failureInformationDistributionGroupRepository::delete);
failureInformationRepository.findByFailureInformationCondensedUuid(existingTblFailureInformation.getUuid())
.forEach( this::undoCondensedOnParentDelete );
failureInformationRepository.delete(existingTblFailureInformation);
}
else{
throw new BadRequestException("delete.not.allowed");
}
}
public FailureInformationLastModDto getFailureInformationLastModTimeStamp() {
FailureInformationLastModDto lastModDto = new FailureInformationLastModDto();
List<TblFailureInformation> visibleList = findFailureInformationsForDisplay(Pageable.unpaged()).toList();
// get the newest Elem out of the list of visible elements
TblFailureInformation newestElem = visibleList.stream().max( (x,y) -> x.getModDate().compareTo(y.getModDate()))
.orElseThrow( () -> new NotFoundException("no.failures.available"));
lastModDto.setLastModification(newestElem.getModDate());
lastModDto.setUuid(newestElem.getUuid());
return lastModDto;
}
private void undoCondensedOnParentDelete(TblFailureInformation x) {
x.setTblFailureInformationCondensed(null);
setVersionNumber(x);
failureInformationRepository.save(x);
}
private boolean isStatusNewPlannedCreated(TblFailureInformation tblFailureInformation){
RefStatus refStatus = tblFailureInformation.getRefStatusIntern();
return (refStatus.getStatus().equals("neu") || refStatus.getStatus().equals("geplant") || refStatus.getStatus().equals("angelegt"));
}
}