/* * This file is part of LibrePlan * * Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e * Desenvolvemento Tecnolóxico de Galicia * Copyright (C) 2010-2011 Igalia, S.L. * * Copyright (C) 2011 WirelessGalicia, S.L. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.libreplan.ws.subcontract.impl; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Set; import java.util.Collections; import javax.ws.rs.Consumes; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import org.apache.commons.lang3.StringUtils; import org.libreplan.business.advance.bootstrap.PredefinedAdvancedTypes; import org.libreplan.business.advance.entities.AdvanceAssignment; import org.libreplan.business.advance.entities.AdvanceMeasurement; import org.libreplan.business.advance.entities.DirectAdvanceAssignment; import org.libreplan.business.advance.exceptions.DuplicateAdvanceAssignmentForOrderElementException; import org.libreplan.business.advance.exceptions.DuplicateValueTrueReportGlobalAdvanceException; import org.libreplan.business.common.exceptions.InstanceNotFoundException; import org.libreplan.business.common.exceptions.ValidationException; import org.libreplan.business.externalcompanies.daos.IExternalCompanyDAO; import org.libreplan.business.externalcompanies.entities.CommunicationType; import org.libreplan.business.externalcompanies.entities.EndDateCommunication; import org.libreplan.business.externalcompanies.entities.ExternalCompany; import org.libreplan.business.orders.daos.IOrderDAO; import org.libreplan.business.orders.daos.IOrderElementDAO; import org.libreplan.business.orders.entities.Order; import org.libreplan.business.orders.entities.OrderElement; import org.libreplan.business.planner.daos.ISubcontractedTaskDataDAO; import org.libreplan.business.planner.daos.ISubcontractorCommunicationDAO; import org.libreplan.business.planner.entities.SubcontractedTaskData; import org.libreplan.business.planner.entities.SubcontractorCommunication; import org.libreplan.business.planner.entities.SubcontractorCommunicationValue; import org.libreplan.business.planner.entities.Task; import org.libreplan.business.scenarios.bootstrap.PredefinedScenarios; import org.libreplan.business.scenarios.entities.OrderVersion; import org.libreplan.business.scenarios.entities.Scenario; import org.libreplan.ws.common.api.AdvanceMeasurementDTO; import org.libreplan.ws.common.api.InstanceConstraintViolationsDTO; import org.libreplan.ws.common.api.InstanceConstraintViolationsListDTO; import org.libreplan.ws.common.impl.ConstraintViolationConverter; import org.libreplan.ws.common.impl.DateConverter; import org.libreplan.ws.common.impl.OrderElementConverter; import org.libreplan.ws.common.impl.Util; import org.libreplan.ws.subcontract.api.EndDateCommunicationToCustomerDTO; import org.libreplan.ws.subcontract.api.IReportAdvancesService; import org.libreplan.ws.subcontract.api.OrderElementWithAdvanceMeasurementsOrEndDateDTO; import org.libreplan.ws.subcontract.api.OrderElementWithAdvanceMeasurementsOrEndDateListDTO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * REST-based implementation of {@link IReportAdvancesService}. * * @author Manuel Rego Casasnovas <mrego@igalia.com> * @author Susana Montes Pedreira <smontes@wirelessgalicia.com> */ @Path("/subcontracting/reportadvances/") @Produces("application/xml") @Service("reportAdvancesServiceREST") public class ReportAdvancesServiceREST implements IReportAdvancesService { @Autowired private IOrderElementDAO orderElementDAO; @Autowired private ISubcontractedTaskDataDAO subcontractedTaskDataDAO; @Autowired private ISubcontractorCommunicationDAO subcontractorCommunicationDAO; @Autowired private IOrderDAO orderDAO; @Autowired private IExternalCompanyDAO externalCompanyDAO; private InstanceConstraintViolationsListDTO getErrorMessage(String code, String message) { // FIXME review errors returned // TODO resolve deprecated method return new InstanceConstraintViolationsListDTO(Collections.singletonList( InstanceConstraintViolationsDTO.create(Util.generateInstanceId(1, code), message))); } @Override @POST @Consumes("application/xml") @Transactional public InstanceConstraintViolationsListDTO updateAdvancesOrEndDate( OrderElementWithAdvanceMeasurementsOrEndDateListDTO orderElementWithAdvanceMeasurementsListDTO) { List<InstanceConstraintViolationsDTO> instanceConstraintViolationsList = new ArrayList<>(); InstanceConstraintViolationsDTO instanceConstraintViolationsDTO = null; if ( StringUtils.isEmpty(orderElementWithAdvanceMeasurementsListDTO.externalCompanyNif) ) { return getErrorMessage("", "external company ID not specified"); } ExternalCompany externalCompany; try { externalCompany = externalCompanyDAO.findUniqueByNif(orderElementWithAdvanceMeasurementsListDTO.externalCompanyNif); } catch (InstanceNotFoundException e1) { return getErrorMessage( orderElementWithAdvanceMeasurementsListDTO.externalCompanyNif, "external company not found"); } if ( !externalCompany.isSubcontractor() ) { return getErrorMessage( orderElementWithAdvanceMeasurementsListDTO.externalCompanyNif, "external company is not registered as subcontractor"); } List<OrderElementWithAdvanceMeasurementsOrEndDateDTO> orderElements = orderElementWithAdvanceMeasurementsListDTO.orderElements; for (OrderElementWithAdvanceMeasurementsOrEndDateDTO current : orderElements) { try { OrderElement orderElement = orderElementDAO.findUniqueByCode(current.code); Scenario scenarioMaster = PredefinedScenarios.MASTER.getScenario(); Order order = orderDAO.loadOrderAvoidingProxyFor(orderElement); OrderVersion orderVersion = order.getScenarios().get(scenarioMaster); if ( current.advanceMeasurements != null && !current.advanceMeasurements.isEmpty() ) { updateAdvances(orderVersion, orderElement, current); } if ( current.endDateCommunicationToCustomerDTO != null ) { updateEndDate(orderVersion, orderElement, current); } } catch (ValidationException e) { /* TODO resolve deprecated */ instanceConstraintViolationsDTO = ConstraintViolationConverter .toDTO(Util.generateInstanceId(1, current.code), e.getInvalidValues()); } catch (InstanceNotFoundException e) { return getErrorMessage(current.code, "instance not found"); } } if ( instanceConstraintViolationsDTO != null ) { instanceConstraintViolationsList.add(instanceConstraintViolationsDTO); } return new InstanceConstraintViolationsListDTO(instanceConstraintViolationsList); } @Transactional public InstanceConstraintViolationsListDTO updateAdvances( OrderVersion orderVersion, OrderElement orderElement, OrderElementWithAdvanceMeasurementsOrEndDateDTO orderElementWithAdvanceMeasurementsOrEndDateDTO) { DirectAdvanceAssignment advanceAssignmentSubcontractor = orderElement.getDirectAdvanceAssignmentSubcontractor(); if ( advanceAssignmentSubcontractor == null ) { DirectAdvanceAssignment reportGlobal = orderElement.getReportGlobalAdvanceAssignment(); advanceAssignmentSubcontractor = DirectAdvanceAssignment.create(reportGlobal == null, new BigDecimal(100)); advanceAssignmentSubcontractor.setAdvanceType(PredefinedAdvancedTypes.SUBCONTRACTOR.getType()); advanceAssignmentSubcontractor.setOrderElement(orderElement); try { orderElement.addAdvanceAssignment(advanceAssignmentSubcontractor); } catch (DuplicateValueTrueReportGlobalAdvanceException e) { // This shouldn't happen, because new advance is only marked as report global // if there is not other advance as report global throw new RuntimeException(e); } catch (DuplicateAdvanceAssignmentForOrderElementException e) { return getErrorMessage( orderElementWithAdvanceMeasurementsOrEndDateDTO.code, "someone in the same branch has the same advance type"); } } for (AdvanceMeasurementDTO current : orderElementWithAdvanceMeasurementsOrEndDateDTO.advanceMeasurements) { AdvanceMeasurement advanceMeasurement = advanceAssignmentSubcontractor .getAdvanceMeasurementAtExactDate(DateConverter.toLocalDate(current.date)); if ( advanceMeasurement == null ) { advanceAssignmentSubcontractor.addAdvanceMeasurements(OrderElementConverter.toEntity(current)); } else { advanceMeasurement.setValue(current.value); } } // Set the advance assignment subcontractor like spread AdvanceAssignment spreadAdvance = orderElement.getReportGlobalAdvanceAssignment(); if ( spreadAdvance != null && !spreadAdvance.equals(advanceAssignmentSubcontractor) ) { spreadAdvance.setReportGlobalAdvance(false); advanceAssignmentSubcontractor.setReportGlobalAdvance(true); } // Update the advance percentage in its related task updateAdvancePercentage(orderVersion, orderElement); orderElement.validate(); orderElementDAO.save(orderElement); /* * If the order element is subcontracted * then create the subcontracted communication for the subcontracted task data * to which the order element belongs. */ try { createSubcontractorCommunicationWithNewProgress( orderElement, orderElementWithAdvanceMeasurementsOrEndDateDTO.advanceMeasurements); } catch (InstanceNotFoundException e) { return getErrorMessage(orderElementWithAdvanceMeasurementsOrEndDateDTO.code, "instance not found"); } return null; } public void createSubcontractorCommunicationWithNewProgress( OrderElement orderElement, Set<AdvanceMeasurementDTO> advanceMeasurementDTOs) throws InstanceNotFoundException { boolean condition = orderElement != null && orderElement.getTaskSource() != null && orderElement.getTaskSource().getTask().isSubcontracted(); if ( condition ) { Task task = (Task) orderElement.getTaskSource().getTask(); SubcontractedTaskData subcontractedTaskData = task.getSubcontractedTaskData(); if ( subcontractedTaskData != null ) { SubcontractorCommunication subcontractorCommunication = SubcontractorCommunication.create( subcontractedTaskData, CommunicationType.PROGRESS_UPDATE, new Date(), false); for (AdvanceMeasurementDTO advanceMeasurementDTO : advanceMeasurementDTOs) { // Add subcontractorCommunicationValue addSubcontractorCommunicationValue(advanceMeasurementDTO, subcontractorCommunication); } subcontractorCommunicationDAO.save(subcontractorCommunication); } } } @Transactional public InstanceConstraintViolationsListDTO updateEndDate( OrderVersion orderVersion, OrderElement orderElement, OrderElementWithAdvanceMeasurementsOrEndDateDTO orderElementWithAdvanceMeasurementsOrEndDateDTO) { try { orderElement.useSchedulingDataFor(orderVersion); boolean condition = orderElement != null && orderElement.getTaskSource() != null && orderElement.getTaskSource().getTask().isSubcontracted(); if ( condition ) { Task task = (Task) orderElement.getTaskSource().getTask(); SubcontractedTaskData subcontractedTaskData = task.getSubcontractedTaskData(); EndDateCommunicationToCustomerDTO endDateDTO = orderElementWithAdvanceMeasurementsOrEndDateDTO.endDateCommunicationToCustomerDTO; Date endDate = DateConverter.toDate(endDateDTO.endDate); Date communicationDate = DateConverter.toDate(endDateDTO.communicationDate); subcontractedTaskData.getEndDatesCommunicatedFromSubcontractor().add( EndDateCommunication.create(new Date(), endDate, communicationDate)); subcontractedTaskDataDAO.save(subcontractedTaskData); createSubcontractorCommunicationWithNewEndDate(subcontractedTaskData, endDateDTO); } } catch (InstanceNotFoundException e) { return getErrorMessage(orderElementWithAdvanceMeasurementsOrEndDateDTO.code, "instance not found"); } return null; } public void createSubcontractorCommunicationWithNewEndDate( SubcontractedTaskData subcontractedTaskData, EndDateCommunicationToCustomerDTO endDateDTO) throws InstanceNotFoundException { if ( subcontractedTaskData != null ) { SubcontractorCommunication subcontractorCommunication = SubcontractorCommunication.create( subcontractedTaskData, CommunicationType.END_DATE_UPDATE, new Date(), false); Date dateValue = DateConverter.toDate(endDateDTO.endDate); SubcontractorCommunicationValue value = SubcontractorCommunicationValue.create(dateValue, null); subcontractorCommunication.getSubcontractorCommunicationValues().add(value); subcontractorCommunicationDAO.save(subcontractorCommunication); } } private void addSubcontractorCommunicationValue( AdvanceMeasurementDTO advanceMeasurementDTO, SubcontractorCommunication subcontractorCommunication) { Date dateValue = DateConverter.toDate(advanceMeasurementDTO.date); SubcontractorCommunicationValue value = SubcontractorCommunicationValue.create(dateValue, advanceMeasurementDTO.value); subcontractorCommunication.getSubcontractorCommunicationValues().add(value); } private void updateAdvancePercentage(OrderVersion orderVersion, OrderElement orderElement) { orderElement.useSchedulingDataFor(orderVersion); OrderElement parent = orderElement.getParent(); while (parent != null) { parent.useSchedulingDataFor(orderVersion); parent = parent.getParent(); } orderElement.updateAdvancePercentageTaskElement(); } }