diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/Order.java b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/Order.java index 2998d27bb..abe18a911 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/Order.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/Order.java @@ -29,6 +29,7 @@ import java.util.Set; import org.hibernate.validator.AssertTrue; import org.hibernate.validator.NotNull; import org.navalplanner.business.calendars.entities.BaseCalendar; +import org.navalplanner.business.common.entities.OrderSequence; import org.navalplanner.business.externalcompanies.entities.ExternalCompany; import org.navalplanner.business.planner.entities.DayAssignment; import org.navalplanner.business.planner.entities.Task; @@ -325,4 +326,37 @@ public class Order extends OrderLineGroup { return OrderTemplate.create(this); } + public void generateOrderElementCodes(int numberOfDigits) { + for (OrderElement orderElement : this.getAllOrderElements()) { + if ((orderElement.getCode() == null) + || (orderElement.getCode().isEmpty()) + || (!orderElement.getCode().startsWith(this.getCode()))) { + this.incrementLastOrderElementSequenceCode(); + String orderElementCode = OrderSequence.formatValue( + numberOfDigits, this.getLastOrderElementSequenceCode()); + orderElement.setCode(this.getCode() + + OrderSequence.CODE_SEPARATOR + orderElementCode); + } + + if (orderElement instanceof OrderLine) { + for (HoursGroup hoursGroup : orderElement.getHoursGroups()) { + if ((hoursGroup.getCode() == null) + || (hoursGroup.getCode().isEmpty()) + || (!hoursGroup.getCode().startsWith( + orderElement.getCode()))) { + ((OrderLine) orderElement) + .incrementLastHoursGroupSequenceCode(); + String hoursGroupCode = OrderSequence.formatValue( + numberOfDigits, ((OrderLine) orderElement) + .getLastHoursGroupSequenceCode()); + hoursGroup + .setCode(orderElement.getCode() + + OrderSequence.CODE_SEPARATOR + + hoursGroupCode); + } + } + } + } + } + } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/OrderElement.java b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/OrderElement.java index 4d936e2c1..6dbd1dac0 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/OrderElement.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/OrderElement.java @@ -941,4 +941,13 @@ public abstract class OrderElement extends BaseEntity implements return externalCode; } + public void moveCodeToExternalCode() { + setExternalCode(getCode()); + setCode(null); + + for (OrderElement child : getChildren()) { + child.moveCodeToExternalCode(); + } + } + } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderModel.java index f554f241a..c4998a222 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderModel.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderModel.java @@ -53,7 +53,6 @@ import org.navalplanner.business.orders.daos.IOrderElementDAO; import org.navalplanner.business.orders.entities.HoursGroup; import org.navalplanner.business.orders.entities.Order; import org.navalplanner.business.orders.entities.OrderElement; -import org.navalplanner.business.orders.entities.OrderLine; import org.navalplanner.business.orders.entities.OrderLineGroup; import org.navalplanner.business.orders.entities.TaskSource; import org.navalplanner.business.orders.entities.TaskSource.TaskSourceSynchronization; @@ -378,37 +377,7 @@ public class OrderModel implements IOrderModel { OrderSequence orderSequence = orderSequenceDAO.getActiveOrderSequence(); int numberOfDigits = orderSequence.getNumberOfDigits(); - for (OrderElement orderElement : order.getAllOrderElements()) { - if ((orderElement.getCode() == null) - || (orderElement.getCode().isEmpty()) - || (!orderElement.getCode().startsWith(order.getCode()))) { - order.incrementLastOrderElementSequenceCode(); - String orderElementCode = OrderSequence - .formatValue(numberOfDigits, order - .getLastOrderElementSequenceCode()); - orderElement.setCode(order.getCode() - + OrderSequence.CODE_SEPARATOR + orderElementCode); - } - - if (orderElement instanceof OrderLine) { - for (HoursGroup hoursGroup : orderElement.getHoursGroups()) { - if ((hoursGroup.getCode() == null) - || (hoursGroup.getCode().isEmpty()) - || (!hoursGroup.getCode().startsWith( - orderElement.getCode()))) { - ((OrderLine) orderElement) - .incrementLastHoursGroupSequenceCode(); - String hoursGroupCode = OrderSequence.formatValue( - numberOfDigits, ((OrderLine) orderElement) - .getLastHoursGroupSequenceCode()); - hoursGroup - .setCode(orderElement.getCode() - + OrderSequence.CODE_SEPARATOR - + hoursGroupCode); - } - } - } - } + order.generateOrderElementCodes(numberOfDigits); } private void reattachCurrentTaskSources() { diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/impl/OrderElementConverter.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/impl/OrderElementConverter.java index 90f05461c..065ca0120 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/impl/OrderElementConverter.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/common/impl/OrderElementConverter.java @@ -324,14 +324,18 @@ public final class OrderElementConverter { OrderElement orderElement; if (orderElementDTO instanceof OrderLineDTO) { - orderElement = OrderLine.create(); + if ((configuration.isHoursGroups()) + && (!((OrderLineDTO) orderElementDTO).hoursGroups.isEmpty())) { + orderElement = OrderLine.create(); - if (configuration.isHoursGroups()) { for (HoursGroupDTO hoursGroupDTO : ((OrderLineDTO) orderElementDTO).hoursGroups) { HoursGroup hoursGroup = toEntity(hoursGroupDTO, configuration); ((OrderLine) orderElement).addHoursGroup(hoursGroup); } + } else { + orderElement = OrderLine + .createOrderLineWithUnfixedPercentage(0); } } else { // orderElementDTO instanceof OrderLineGroupDTO List children = new ArrayList(); diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/orders/impl/OrderElementServiceREST.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/orders/impl/OrderElementServiceREST.java index 9ef8f4da6..83fc53ffb 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/ws/orders/impl/OrderElementServiceREST.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/orders/impl/OrderElementServiceREST.java @@ -87,8 +87,7 @@ public class OrderElementServiceREST implements IOrderElementService { OrderElement orderElement = OrderElementConverter.toEntity( orderDTO, ConfigurationOrderElementConverter .all()); - // FIXME change all() for noAdvanceMeasurements() when - // subcontractors service exists + orderElement.validate(); orderElementDAO.save(orderElement); } catch (ValidationException e) { @@ -125,8 +124,6 @@ public class OrderElementServiceREST implements IOrderElementService { try { OrderElementConverter.update((Order) orderElement, orderDTO, ConfigurationOrderElementConverter.all()); - // FIXME change all() for noAdvanceMeasurements() when - // subcontractors service exists orderElement.validate(); orderElementDAO.save(orderElement); } catch (ValidationException e) { diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/subcontract/api/ISubcontractService.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/subcontract/api/ISubcontractService.java new file mode 100644 index 000000000..7f974d59b --- /dev/null +++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/subcontract/api/ISubcontractService.java @@ -0,0 +1,36 @@ +/* + * This file is part of ###PROJECT_NAME### + * + * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e + * Desenvolvemento Tecnolóxico de Galicia + * + * 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 . + */ + +package org.navalplanner.ws.subcontract.api; + +import org.navalplanner.ws.common.api.InstanceConstraintViolationsListDTO; + + +/** + * Service for managing subcontracting process. + * + * @author Manuel Rego Casasnovas + */ +public interface ISubcontractService { + + InstanceConstraintViolationsListDTO subcontract( + SubcontractedTaskDataDTO subcontractedTaskDataDTO); + +} \ No newline at end of file diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/subcontract/api/SubcontractedTaskDataDTO.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/subcontract/api/SubcontractedTaskDataDTO.java new file mode 100644 index 000000000..983bd5b04 --- /dev/null +++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/subcontract/api/SubcontractedTaskDataDTO.java @@ -0,0 +1,75 @@ +/* + * This file is part of ###PROJECT_NAME### + * + * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e + * Desenvolvemento Tecnolóxico de Galicia + * + * 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 . + */ + +package org.navalplanner.ws.subcontract.api; + +import java.math.BigDecimal; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElements; +import javax.xml.bind.annotation.XmlRootElement; + +import org.navalplanner.business.planner.entities.SubcontractedTaskData; +import org.navalplanner.ws.common.api.OrderDTO; +import org.navalplanner.ws.common.api.OrderElementDTO; +import org.navalplanner.ws.common.api.OrderLineDTO; +import org.navalplanner.ws.common.api.OrderLineGroupDTO; + +/** + * DTO for {@link SubcontractedTaskData} entity. + * + * @author Manuel Rego Casasnovas + */ +@XmlRootElement(name = "subcontracted-task-data") +public class SubcontractedTaskDataDTO { + + @XmlAttribute(name = "external-company-nif") + public String externalCompanyNif; + + @XmlAttribute(name = "work-description") + public String workDescription; + + @XmlAttribute(name = "subcontracted-price") + public BigDecimal subcontractPrice; + + @XmlAttribute(name = "subcontracted-code") + public String subcontractedCode; + + @XmlElements( { + @XmlElement(name = "order-line", type = OrderLineDTO.class), + @XmlElement(name = "order-line-group", type = OrderLineGroupDTO.class), + @XmlElement(name = "order", type = OrderDTO.class) }) + public OrderElementDTO orderElementDTO; + + public SubcontractedTaskDataDTO() { + } + + public SubcontractedTaskDataDTO(String externalCompanyNif, + String workDescription, BigDecimal subcontractPrice, + String subcontractedCode, OrderElementDTO orderElementDTO) { + this.externalCompanyNif = externalCompanyNif; + this.workDescription = workDescription; + this.subcontractPrice = subcontractPrice; + this.subcontractedCode = subcontractedCode; + this.orderElementDTO = orderElementDTO; + } + +} diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/subcontract/api/package-info.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/subcontract/api/package-info.java new file mode 100644 index 000000000..e32bfe9a4 --- /dev/null +++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/subcontract/api/package-info.java @@ -0,0 +1,29 @@ +/* + * This file is part of ###PROJECT_NAME### + * + * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e + * Desenvolvemento Tecnolóxico de Galicia + * + * 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 . + */ + +/** + * Specification of namespace for REST-based services. + * + * @author Manuel Rego Casasnovas + */ +@javax.xml.bind.annotation.XmlSchema(elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED, namespace = WSCommonGlobalNames.REST_NAMESPACE) +package org.navalplanner.ws.subcontract.api; + +import org.navalplanner.ws.common.api.WSCommonGlobalNames; diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/ws/subcontract/impl/SubcontractServiceREST.java b/navalplanner-webapp/src/main/java/org/navalplanner/ws/subcontract/impl/SubcontractServiceREST.java new file mode 100644 index 000000000..c74f1b173 --- /dev/null +++ b/navalplanner-webapp/src/main/java/org/navalplanner/ws/subcontract/impl/SubcontractServiceREST.java @@ -0,0 +1,187 @@ +/* + * This file is part of ###PROJECT_NAME### + * + * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e + * Desenvolvemento Tecnolóxico de Galicia + * + * 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 . + */ + +package org.navalplanner.ws.subcontract.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; + +import org.apache.commons.lang.StringUtils; +import org.navalplanner.business.calendars.entities.BaseCalendar; +import org.navalplanner.business.common.daos.IConfigurationDAO; +import org.navalplanner.business.common.daos.IOrderSequenceDAO; +import org.navalplanner.business.common.entities.OrderSequence; +import org.navalplanner.business.common.exceptions.InstanceNotFoundException; +import org.navalplanner.business.common.exceptions.ValidationException; +import org.navalplanner.business.externalcompanies.daos.IExternalCompanyDAO; +import org.navalplanner.business.externalcompanies.entities.ExternalCompany; +import org.navalplanner.business.orders.daos.IOrderElementDAO; +import org.navalplanner.business.orders.entities.Order; +import org.navalplanner.business.orders.entities.OrderElement; +import org.navalplanner.ws.common.api.InstanceConstraintViolationsDTO; +import org.navalplanner.ws.common.api.InstanceConstraintViolationsListDTO; +import org.navalplanner.ws.common.api.OrderElementDTO; +import org.navalplanner.ws.common.impl.ConfigurationOrderElementConverter; +import org.navalplanner.ws.common.impl.ConstraintViolationConverter; +import org.navalplanner.ws.common.impl.OrderElementConverter; +import org.navalplanner.ws.common.impl.Util; +import org.navalplanner.ws.subcontract.api.ISubcontractService; +import org.navalplanner.ws.subcontract.api.SubcontractedTaskDataDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * REST-based implementation of {@link ISubcontractService} + * + * @author Manuel Rego Casasnovas + */ +@Path("/subcontract/") +@Produces("application/xml") +@Service("subcontractServiceREST") +public class SubcontractServiceREST implements ISubcontractService { + + @Autowired + private IOrderElementDAO orderElementDAO; + + @Autowired + private IConfigurationDAO configurationDAO; + + @Autowired + private IExternalCompanyDAO externalCompanyDAO; + + @Autowired + private IOrderSequenceDAO orderSequenceDAO; + + @Override + @POST + @Consumes("application/xml") + @Transactional + public InstanceConstraintViolationsListDTO subcontract( + SubcontractedTaskDataDTO subcontractedTaskDataDTO) { + + List instanceConstraintViolationsList = new ArrayList(); + + InstanceConstraintViolationsDTO instanceConstraintViolationsDTO = null; + + if (StringUtils.isEmpty(subcontractedTaskDataDTO.externalCompanyNif)) { + return getErrorMessage(subcontractedTaskDataDTO.subcontractedCode, + "external company nif not specified"); + } + + ExternalCompany externalCompany; + try { + externalCompany = externalCompanyDAO + .findUniqueByNif(subcontractedTaskDataDTO.externalCompanyNif); + } catch (InstanceNotFoundException e1) { + return getErrorMessage(subcontractedTaskDataDTO.externalCompanyNif, + "external company not found"); + } + + if (!externalCompany.isClient()) { + return getErrorMessage(subcontractedTaskDataDTO.externalCompanyNif, + "external company is not registered as client"); + } + + OrderElementDTO orderElementDTO = subcontractedTaskDataDTO.orderElementDTO; + if (orderElementDTO == null) { + return getErrorMessage(subcontractedTaskDataDTO.subcontractedCode, + "order element not specified"); + } + + try { + OrderElement orderElement = OrderElementConverter.toEntity( + orderElementDTO, ConfigurationOrderElementConverter + .noAdvanceMeasurements()); + + if (!(orderElement instanceof Order)) { + orderElement = wrapInOrder(orderElement); + } + + orderElement.moveCodeToExternalCode(); + String code = orderSequenceDAO.getNextOrderCode(); + if (code == null) { + return getErrorMessage( + subcontractedTaskDataDTO.orderElementDTO.code, + "unable to generate the code for the new order, please try again later"); + } + + orderElement.setCode(code); + generateCodes((Order) orderElement); + + orderElement.validate(); + orderElementDAO.save(orderElement); + } catch (ValidationException e) { + instanceConstraintViolationsDTO = ConstraintViolationConverter + .toDTO(Util.generateInstanceId(1, orderElementDTO.code), e + .getInvalidValues()); + } + + if (instanceConstraintViolationsDTO != null) { + instanceConstraintViolationsList + .add(instanceConstraintViolationsDTO); + } + + return new InstanceConstraintViolationsListDTO( + instanceConstraintViolationsList); + } + + private void generateCodes(Order order) { + OrderSequence orderSequence = orderSequenceDAO.getActiveOrderSequence(); + int numberOfDigits = orderSequence.getNumberOfDigits(); + + order.generateOrderElementCodes(numberOfDigits); + } + + private Order wrapInOrder(OrderElement orderElement) { + if (orderElement instanceof Order) { + return (Order) orderElement; + } + + Order order = Order.create(); + order.add(orderElement); + + order.setName("Order from client"); + order.setInitDate(new Date()); + order.setCalendar(getDefaultCalendar()); + + return order; + } + + private BaseCalendar getDefaultCalendar() { + return configurationDAO.getConfiguration().getDefaultCalendar(); + } + + private InstanceConstraintViolationsListDTO getErrorMessage(String code, + String message) { + // FIXME review errors returned + return new InstanceConstraintViolationsListDTO(Arrays + .asList(InstanceConstraintViolationsDTO.create(Util + .generateInstanceId(1, code), message))); + } + +} \ No newline at end of file diff --git a/navalplanner-webapp/src/main/resources/navalplanner-webapp-spring-config.xml b/navalplanner-webapp/src/main/resources/navalplanner-webapp-spring-config.xml index fd3b1675e..0e34b5459 100644 --- a/navalplanner-webapp/src/main/resources/navalplanner-webapp-spring-config.xml +++ b/navalplanner-webapp/src/main/resources/navalplanner-webapp-spring-config.xml @@ -50,6 +50,7 @@ +