/* * 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. * * 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.web.subcontract; import static org.libreplan.web.I18nHelper._; import java.io.StringWriter; import java.util.Collections; import java.util.Date; import java.util.List; import javax.ws.rs.WebApplicationException; import javax.xml.bind.JAXBContext; import javax.xml.bind.Marshaller; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.cxf.jaxrs.client.WebClient; import org.libreplan.business.common.exceptions.InstanceNotFoundException; 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.entities.SubcontractState; import org.libreplan.business.planner.entities.SubcontractedTaskData; import org.libreplan.business.planner.entities.Task; import org.libreplan.web.common.concurrentdetection.OnConcurrentModification; import org.libreplan.web.subcontract.exceptions.ConnectionProblemsException; import org.libreplan.web.subcontract.exceptions.UnrecoverableErrorServiceException; import org.libreplan.ws.cert.NaiveTrustProvider; import org.libreplan.ws.common.api.ConstraintViolationDTO; import org.libreplan.ws.common.api.InstanceConstraintViolationsDTO; import org.libreplan.ws.common.api.InstanceConstraintViolationsListDTO; import org.libreplan.ws.common.api.OrderElementDTO; import org.libreplan.ws.common.impl.ConfigurationOrderElementConverter; 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.SubcontractedTaskDataDTO; import org.libreplan.ws.subcontract.impl.SubcontractedTaskDataConverter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; /** * Model for operations related with subcontracted tasks. * * @author Manuel Rego Casasnovas <mrego@igalia.com> * @author Bogdan Bodnarjuk <b.bodnarjuk@libreplan-enterprise.com> */ @Component @Scope(BeanDefinition.SCOPE_PROTOTYPE) @OnConcurrentModification(goToPage = "/subcontract/subcontractedTasks.zul") public class SubcontractedTasksModel implements ISubcontractedTasksModel { private static Log LOG = LogFactory.getLog(SubcontractedTasksModel.class); private String CONNECTION_PROBLEM = "Problems connecting with subcontractor web service"; @Autowired private ISubcontractedTaskDataDAO subcontractedTaskDataDAO; @Autowired private IOrderElementDAO orderElementDAO; @Autowired private IOrderDAO orderDAO; @Override @Transactional(readOnly = true) public List<SubcontractedTaskData> getSubcontractedTasks() { List<SubcontractedTaskData> result = subcontractedTaskDataDAO.getAllForMasterScenario(); for (SubcontractedTaskData subcontractedTaskData : result) { forceLoadExternalCompany(subcontractedTaskData); forceLastDeliveryDate(subcontractedTaskData); } return sortByState(result); } private void forceLastDeliveryDate(SubcontractedTaskData subcontractedTaskData) { subcontractedTaskData.getLastRequiredDeliverDate(); } private void forceLoadExternalCompany(SubcontractedTaskData subcontractedTaskData) { subcontractedTaskData.getExternalCompany().getName(); } private List<SubcontractedTaskData> sortByState(List<SubcontractedTaskData> tasks) { Collections.sort(tasks, (arg0, arg1) -> { if ( (arg0 == null) || (arg0.getState() == null) ) { return -1; } if ( (arg1 == null) || (arg1.getState() == null) ) { return 1; } if ( arg0.getState().equals(arg1.getState()) ) { return 0; } if ( arg0.getState().equals(SubcontractState.PENDING_INITIAL_SEND) ) { return 1; } if ( arg1.getState().equals(SubcontractState.PENDING_INITIAL_SEND) ) { return -1; } if( arg0.getState().equals(SubcontractState.PENDING_UPDATE_DELIVERING_DATE) ) { return 1; } return -1; }); return tasks; } @Override @Transactional(readOnly = true) public Order getOrder(SubcontractedTaskData subcontractedTaskData) { Task task = subcontractedTaskData.getTask(); OrderElement orderElement = orderDAO.loadOrderAvoidingProxyFor(task.getOrderElement()); return orderElement.getOrder(); } @Override @Transactional public void sendToSubcontractor(SubcontractedTaskData subcontractedTaskData) throws ConnectionProblemsException, UnrecoverableErrorServiceException { subcontractedTaskDataDAO.save(subcontractedTaskData); SubcontractState currentState = subcontractedTaskData.getState(); if ( currentState.equals(SubcontractState.PENDING_INITIAL_SEND) ) { subcontractedTaskData.setState(SubcontractState.FAILED_SENT); } else if ( currentState.equals(SubcontractState.PENDING_UPDATE_DELIVERING_DATE) ) { subcontractedTaskData.setState(SubcontractState.FAILED_UPDATE); } if ( !subcontractedTaskData.isSendable() ) { throw new RuntimeException("Subcontracted task already sent"); } if ( !subcontractedTaskData.getExternalCompany().getInteractsWithApplications() ) { throw new RuntimeException("External company has not interaction fields filled"); } makeSubcontractRequest(subcontractedTaskData,currentState); Date today = new Date(); if (currentState.equals(SubcontractState.PENDING_INITIAL_SEND) || currentState.equals(SubcontractState.FAILED_SENT)) { subcontractedTaskData.setSubcontractCommunicationDate(today); } // Update the first required deliver date subcontractedTaskData.updateFirstRequiredDeliverDate(today); subcontractedTaskData.setSubcontractCommunicationDate(today); subcontractedTaskData.setState(SubcontractState.SUCCESS_SENT); } private void makeSubcontractRequest(SubcontractedTaskData subcontractedTaskData, SubcontractState currentState) throws ConnectionProblemsException, UnrecoverableErrorServiceException { if ( subcontractedTaskData.getState() != null ) { if ( currentState.equals(SubcontractState.PENDING_INITIAL_SEND) || currentState.equals(SubcontractState.FAILED_SENT) ) { makeSubcontractRequestRequest_InitialSent(subcontractedTaskData); } else if ( currentState.equals(SubcontractState.PENDING_UPDATE_DELIVERING_DATE) || currentState.equals(SubcontractState.FAILED_UPDATE) ) { makeSubcontractRequestRequest_UpdateDeliverDate(subcontractedTaskData); } } } private void makeSubcontractRequestRequest_UpdateDeliverDate(SubcontractedTaskData subcontractedTaskData) throws ConnectionProblemsException, UnrecoverableErrorServiceException { UpdateDeliveringDateDTO updateDeliveringDateDTO = SubcontractedTaskDataConverter.toUpdateDeliveringDateDTO(subcontractedTaskData.getExternalCompany().getNif(), subcontractedTaskData); ExternalCompany externalCompany = subcontractedTaskData.getExternalCompany(); NaiveTrustProvider.setAlwaysTrust(true); try { WebClient client = WebClient.create(externalCompany.getAppURI()); client.path("ws/rest/subcontracting/subcontract/update"); Util.addAuthorizationHeader( client, externalCompany.getOurCompanyLogin(), externalCompany.getOurCompanyPassword()); InstanceConstraintViolationsListDTO instanceConstraintViolationsListDTO = client.post(updateDeliveringDateDTO, InstanceConstraintViolationsListDTO.class); List<InstanceConstraintViolationsDTO> instanceConstraintViolationsList = instanceConstraintViolationsListDTO.instanceConstraintViolationsList; checkConstraintViolations(instanceConstraintViolationsList); } catch (WebApplicationException e) { LOG.error(CONNECTION_PROBLEM, e); String message = _(CONNECTION_PROBLEM); if ( e.getMessage() != null ) { message += ". " + _("Error: {0}", e.getMessage()); } throw new ConnectionProblemsException(message, e); } } private void makeSubcontractRequestRequest_InitialSent(SubcontractedTaskData subcontractedTaskData) throws ConnectionProblemsException, UnrecoverableErrorServiceException { SubcontractedTaskDataDTO subcontractedTaskDataDTO = getSubcontractedTaskData(subcontractedTaskData); ExternalCompany externalCompany = subcontractedTaskData.getExternalCompany(); NaiveTrustProvider.setAlwaysTrust(true); try { WebClient client = WebClient.create(externalCompany.getAppURI()); client.path("ws/rest/subcontracting/subcontract/create"); Util.addAuthorizationHeader( client, externalCompany.getOurCompanyLogin(), externalCompany.getOurCompanyPassword()); InstanceConstraintViolationsListDTO instanceConstraintViolationsListDTO = client.post(subcontractedTaskDataDTO, InstanceConstraintViolationsListDTO.class); List<InstanceConstraintViolationsDTO> instanceConstraintViolationsList = instanceConstraintViolationsListDTO.instanceConstraintViolationsList; checkConstraintViolations(instanceConstraintViolationsList); } catch (WebApplicationException e) { LOG.error(CONNECTION_PROBLEM, e); String message = _(CONNECTION_PROBLEM); if ( e.getMessage() != null ) { message += ". " + _("Error: {0}", e.getMessage()); } throw new ConnectionProblemsException(message, e); } } private void checkConstraintViolations(List<InstanceConstraintViolationsDTO> instanceConstraintViolationsList) throws UnrecoverableErrorServiceException { if ( instanceConstraintViolationsList != null && !instanceConstraintViolationsList.isEmpty() ) { StringBuilder stringBuilder = new StringBuilder(); for (ConstraintViolationDTO current : instanceConstraintViolationsList.get(0).constraintViolations) { stringBuilder.append(current.toString()).append("\n"); } throw new UnrecoverableErrorServiceException(stringBuilder.toString()); } } private SubcontractedTaskDataDTO getSubcontractedTaskData(SubcontractedTaskData subcontractedTaskData) { return SubcontractedTaskDataConverter.toDTO( subcontractedTaskData.getExternalCompany().getNif(), subcontractedTaskData, getOrderElement(subcontractedTaskData)); } private OrderElementDTO getOrderElement(SubcontractedTaskData subcontractedTaskData) { OrderElement orderElement; try { orderElement = orderElementDAO.find(subcontractedTaskData.getTask().getOrderElement().getId()); } catch (InstanceNotFoundException e) { throw new RuntimeException(e); } if ( subcontractedTaskData.isNodeWithoutChildrenExported() ) { orderElement = orderElement.calculateOrderLineForSubcontract(); } OrderElementDTO orderElementDTO = OrderElementConverter.toDTO(orderElement, getConfiguration(subcontractedTaskData)); overrideDateInformationForRootNode(orderElementDTO, subcontractedTaskData.getTask()); return orderElementDTO; } private void overrideDateInformationForRootNode(OrderElementDTO orderElementDTO, Task task) { orderElementDTO.initDate = DateConverter.toXMLGregorianCalendar(task.getStartDate()); orderElementDTO.deadline = DateConverter.toXMLGregorianCalendar(task.getEndDate()); } private ConfigurationOrderElementConverter getConfiguration(SubcontractedTaskData subcontractedTaskData) { // Never export criterions and advances to subcontract return ConfigurationOrderElementConverter.create( subcontractedTaskData.isLabelsExported(), subcontractedTaskData.isMaterialAssignmentsExported(), false, subcontractedTaskData.isHoursGroupsExported(), false); } @Override @Transactional(readOnly = true) public String exportXML(SubcontractedTaskData subcontractedTaskData) { SubcontractState currentState = subcontractedTaskData.getState(); if (currentState.equals(SubcontractState.PENDING_INITIAL_SEND) || currentState.equals(SubcontractState.FAILED_SENT) ) { return exportXML_CreateSubcontractor(subcontractedTaskData); } else { return exportXML_UpdateSubcontractor(subcontractedTaskData); } } public String exportXML_CreateSubcontractor(SubcontractedTaskData subcontractedTaskData){ SubcontractedTaskDataDTO subcontractedTaskDataDTO = getSubcontractedTaskData(subcontractedTaskData); StringWriter xml = new StringWriter(); try { JAXBContext jaxbContext = JAXBContext.newInstance(SubcontractedTaskDataDTO.class); Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.marshal(subcontractedTaskDataDTO, xml); } catch (Exception e) { throw new RuntimeException(e); } return xml.toString(); } public String exportXML_UpdateSubcontractor(SubcontractedTaskData subcontractedTaskData){ subcontractedTaskDataDAO.reattachUnmodifiedEntity(subcontractedTaskData); UpdateDeliveringDateDTO updateDeliveringDateDTO = SubcontractedTaskDataConverter.toUpdateDeliveringDateDTO(subcontractedTaskData.getExternalCompany().getNif(), subcontractedTaskData); StringWriter xml = new StringWriter(); try { JAXBContext jaxbContext = JAXBContext.newInstance(UpdateDeliveringDateDTO.class); Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.marshal(updateDeliveringDateDTO, xml); } catch (Exception e) { throw new RuntimeException(e); } return xml.toString(); } }