ItEr50S13AdaptacionServiciosRESTItEr49S18 : Creation and Adapting of CostCategoryServiceRest to GenericServiceRest.

Important : it should be to add the column code to the table costcategory and the table hourcost.
This commit is contained in:
Susana Montes Pedreira 2010-03-11 13:13:07 +01:00 committed by Javier Moran Rua
parent 9f10cfc47f
commit 59b6776b8c
20 changed files with 993 additions and 17 deletions

View file

@ -24,6 +24,7 @@ import org.navalplanner.business.advance.daos.IAdvanceTypeDAO;
import org.navalplanner.business.calendars.daos.IBaseCalendarDAO;
import org.navalplanner.business.common.daos.IConfigurationDAO;
import org.navalplanner.business.costcategories.daos.ICostCategoryDAO;
import org.navalplanner.business.costcategories.daos.IHourCostDAO;
import org.navalplanner.business.costcategories.daos.IResourcesCostCategoryAssignmentDAO;
import org.navalplanner.business.costcategories.daos.ITypeOfWorkHoursDAO;
import org.navalplanner.business.externalcompanies.daos.IExternalCompanyDAO;
@ -149,6 +150,9 @@ public class Registry {
@Autowired
private IOrderElementTemplateDAO orderElementTemplateDAO;
@Autowired
private IHourCostDAO hourCostDAO;
private Registry() {
}
@ -265,4 +269,8 @@ public class Registry {
public static IOrderElementTemplateDAO getOrderElementTemplateDAO() {
return getInstance().orderElementTemplateDAO;
}
public static IHourCostDAO getHourCostDAO() {
return getInstance().hourCostDAO;
}
}

View file

@ -27,7 +27,7 @@ import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import org.joda.time.LocalDate;
import org.navalplanner.business.common.daos.GenericDAOHibernate;
import org.navalplanner.business.common.daos.IntegrationEntityDAO;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.costcategories.entities.CostCategory;
import org.navalplanner.business.costcategories.entities.HourCost;
@ -44,7 +44,7 @@ import org.springframework.transaction.annotation.Transactional;
*/
@Repository
@Scope(BeanDefinition.SCOPE_SINGLETON)
public class CostCategoryDAO extends GenericDAOHibernate<CostCategory, Long>
public class CostCategoryDAO extends IntegrationEntityDAO<CostCategory>
implements ICostCategoryDAO {
@Override
@ -73,6 +73,27 @@ public class CostCategoryDAO extends GenericDAOHibernate<CostCategory, Long>
}
}
@Override
public CostCategory findUniqueByCode(String code)
throws InstanceNotFoundException {
if (code == null) {
throw new InstanceNotFoundException(code, CostCategory.class
.getName());
}
Criteria c = getSession().createCriteria(CostCategory.class).add(
Restrictions.eq("code", code).ignoreCase());
CostCategory costCategory = (CostCategory) c.uniqueResult();
if (costCategory == null) {
throw new InstanceNotFoundException(code, CostCategory.class
.getName());
} else {
return costCategory;
}
}
@Transactional(readOnly = true)
public static BigDecimal getPriceByResourceDateAndHourType(
Resource resource,

View file

@ -20,7 +20,7 @@
package org.navalplanner.business.costcategories.daos;
import org.navalplanner.business.common.daos.GenericDAOHibernate;
import org.navalplanner.business.common.daos.IntegrationEntityDAO;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.costcategories.entities.HourCost;
import org.springframework.beans.factory.config.BeanDefinition;
@ -32,7 +32,7 @@ import org.springframework.stereotype.Repository;
*/
@Repository
@Scope(BeanDefinition.SCOPE_SINGLETON)
public class HourCostDAO extends GenericDAOHibernate<HourCost, Long> implements
public class HourCostDAO extends IntegrationEntityDAO<HourCost> implements
IHourCostDAO {
@Override

View file

@ -22,7 +22,7 @@ package org.navalplanner.business.costcategories.daos;
import java.util.List;
import org.navalplanner.business.common.daos.IGenericDAO;
import org.navalplanner.business.common.daos.IIntegrationEntityDAO;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.costcategories.entities.CostCategory;
@ -30,10 +30,11 @@ import org.navalplanner.business.costcategories.entities.CostCategory;
* @author Jacobo Aragunde Perez <jaragunde@igalia.com>
* @author Fernando Bellas Permuy <fbellas@udc.es>
*/
public interface ICostCategoryDAO extends IGenericDAO<CostCategory, Long> {
public interface ICostCategoryDAO extends IIntegrationEntityDAO<CostCategory> {
List<CostCategory> findActive();
CostCategory findUniqueByName(String name) throws InstanceNotFoundException;
CostCategory findUniqueByCode(String code) throws InstanceNotFoundException;
}

View file

@ -20,15 +20,14 @@
package org.navalplanner.business.costcategories.daos;
import org.navalplanner.business.common.daos.IGenericDAO;
import org.navalplanner.business.common.daos.IIntegrationEntityDAO;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.costcategories.entities.HourCost;
/**
* @author Jacobo Aragunde Perez <jaragunde@igalia.com>
*/
public interface IHourCostDAO extends IGenericDAO<HourCost, Long> {
public interface IHourCostDAO extends IIntegrationEntityDAO<HourCost> {
@Override
public void remove(Long id) throws InstanceNotFoundException;
}

View file

@ -25,16 +25,20 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.hibernate.validator.AssertFalse;
import org.hibernate.validator.NotEmpty;
import org.hibernate.validator.Valid;
import org.joda.time.LocalDate;
import org.navalplanner.business.common.BaseEntity;
import org.navalplanner.business.common.IntegrationEntity;
import org.navalplanner.business.common.Registry;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.costcategories.daos.ICostCategoryDAO;
/**
* @author Jacobo Aragunde Perez <jaragunde@igalia.com>
*/
public class CostCategory extends BaseEntity {
public class CostCategory extends IntegrationEntity {
@NotEmpty
private String name;
@ -48,6 +52,26 @@ public class CostCategory extends BaseEntity {
}
public static CostCategory createUnvalidated(String code, String name,
Boolean enabled) {
CostCategory costCategory = create(new CostCategory(), code);
costCategory.name = name;
if (enabled != null) {
costCategory.enabled = enabled;
}
return costCategory;
}
public void updateUnvalidated(String name, Boolean enabled) {
if (!StringUtils.isBlank(name)) {
this.name = name;
}
if (enabled != null) {
this.enabled = enabled;
}
}
public static CostCategory create() {
return (CostCategory) create(new CostCategory());
}
@ -118,6 +142,22 @@ public class CostCategory extends BaseEntity {
return !overlap;
}
public HourCost getHourCostByCode(String code)
throws InstanceNotFoundException {
if (StringUtils.isBlank(code)) {
throw new InstanceNotFoundException(code, HourCost.class.getName());
}
for (HourCost c : this.hourCosts) {
if (c.getCode().equalsIgnoreCase(StringUtils.trim(code))) {
return c;
}
}
throw new InstanceNotFoundException(code, HourCost.class.getName());
}
@AssertFalse(message="Two hour costs with the same type overlap in time")
public boolean checkHourCostsOverlap() {
List<HourCost> listHourCosts = new ArrayList<HourCost>();
@ -157,4 +197,10 @@ public class CostCategory extends BaseEntity {
}
return false;
}
@Override
protected ICostCategoryDAO getIntegrationEntityDAO() {
return Registry.getCostCategoryDAO();
}
}

View file

@ -25,25 +25,23 @@ import java.math.BigDecimal;
import org.hibernate.validator.AssertTrue;
import org.hibernate.validator.NotNull;
import org.joda.time.LocalDate;
import org.navalplanner.business.common.BaseEntity;
import org.navalplanner.business.common.IntegrationEntity;
import org.navalplanner.business.common.Registry;
import org.navalplanner.business.costcategories.daos.IHourCostDAO;
/**
* @author Jacobo Aragunde Perez <jaragunde@igalia.com>
*/
public class HourCost extends BaseEntity {
public class HourCost extends IntegrationEntity {
@NotNull
private BigDecimal priceCost;
@NotNull
private LocalDate initDate;
private LocalDate endDate;
@NotNull
private TypeOfWorkHours type;
@NotNull
private CostCategory category;
// Default constructor, needed by Hibernate
@ -51,6 +49,27 @@ public class HourCost extends BaseEntity {
}
public static HourCost createUnvalidated(String code, BigDecimal priceCost,
LocalDate initDate) {
HourCost hourCost = create(new HourCost(), code);
if (priceCost != null) {
hourCost.setPriceCost(priceCost);
}
if (initDate != null) {
hourCost.setInitDate(initDate);
}
return hourCost;
}
public void updateUnvalidated(BigDecimal priceCost, LocalDate initDate) {
if (priceCost != null) {
this.priceCost = priceCost;
}
if (initDate != null) {
this.initDate = initDate;
}
}
public static HourCost create(BigDecimal priceCost, LocalDate initDate) {
return (HourCost) create(new HourCost(priceCost, initDate));
}
@ -64,6 +83,7 @@ public class HourCost extends BaseEntity {
this.initDate = initDate;
}
@NotNull(message = "price cost not specified")
public BigDecimal getPriceCost() {
return priceCost;
}
@ -72,6 +92,7 @@ public class HourCost extends BaseEntity {
this.priceCost = priceCost;
}
@NotNull(message = "init date not specified")
public LocalDate getInitDate() {
return initDate;
}
@ -88,6 +109,7 @@ public class HourCost extends BaseEntity {
this.endDate = endDate;
}
@NotNull(message = "type of work hours not specified")
public TypeOfWorkHours getType() {
return type;
}
@ -96,6 +118,7 @@ public class HourCost extends BaseEntity {
this.type = type;
}
@NotNull(message = "cost category not specified")
public CostCategory getCategory() {
return category;
}
@ -124,4 +147,9 @@ public class HourCost extends BaseEntity {
}
return (endDate.isAfter(initDate) || initDate.equals(endDate));
}
@Override
protected IHourCostDAO getIntegrationEntityDAO() {
return Registry.getHourCostDAO();
}
}

View file

@ -11,6 +11,7 @@
</id>
<version name="version" access="property" type="long" />
<property name="code" access="property" not-null="true" unique="true"/>
<property name="name" unique="true"/>
<property name="enabled"/>
@ -30,6 +31,7 @@
</id>
<version name="version" access="property" type="long" />
<property name="code" access="property" not-null="true" unique="true"/>
<property name="priceCost"/>
<property name="initDate" type="org.joda.time.contrib.hibernate.PersistentLocalDate"/>

View file

@ -0,0 +1,60 @@
package org.navalplanner.ws.costcategories.api;
import java.util.HashSet;
import java.util.Set;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import org.navalplanner.business.costcategories.entities.CostCategory;
import org.navalplanner.ws.common.api.IntegrationEntityDTO;
/**
* DTO for {@link CostCategory} entity.
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
public class CostCategoryDTO extends IntegrationEntityDTO {
public final static String ENTITY_TYPE = "cost-category";
@XmlAttribute
public String name;
@XmlAttribute
public Boolean enabled;
@XmlElementWrapper(name = "hour-cost-list")
@XmlElement(name = "hour-cost")
public Set<HourCostDTO> hourCostDTOs = new HashSet<HourCostDTO>();
public CostCategoryDTO() {
}
public CostCategoryDTO(String code, String name, Boolean enabled,
Set<HourCostDTO> hourCostDTOs) {
super(code);
this.name = name;
this.enabled = enabled;
this.hourCostDTOs = hourCostDTOs;
}
/**
* This constructor automatically generates a unique code. It is intended to
* facilitate the implementation of test cases that add new instances (such
* instances will have a unique code).
*/
public CostCategoryDTO(String name, Boolean enabled,
Set<HourCostDTO> hourCostDTOs) {
this(generateCode(), name, enabled, hourCostDTOs);
}
@Override
public String getEntityType() {
return ENTITY_TYPE;
}
}

View file

@ -0,0 +1,46 @@
/*
* This file is part of NavalPlan
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.ws.costcategories.api;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* DTO for a list of <code>CostCategory</code> entities.
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
@XmlRootElement(name = "cost-category-list")
public class CostCategoryListDTO {
@XmlElement(name = "cost-category")
public List<CostCategoryDTO> costCategories = new ArrayList<CostCategoryDTO>();
public CostCategoryListDTO() {
}
public CostCategoryListDTO(List<CostCategoryDTO> costCategories) {
this.costCategories = costCategories;
}
}

View file

@ -0,0 +1,61 @@
package org.navalplanner.ws.costcategories.api;
import java.math.BigDecimal;
import java.util.Date;
import javax.xml.bind.annotation.XmlAttribute;
import org.navalplanner.business.costcategories.entities.HourCost;
import org.navalplanner.ws.common.api.IntegrationEntityDTO;
/**
* DTO for {@link HourCost} entity.
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
public class HourCostDTO extends IntegrationEntityDTO {
public final static String ENTITY_TYPE = "hour-cost";
@XmlAttribute
public BigDecimal priceCost;
@XmlAttribute
public Date initDate;
@XmlAttribute
public Date endDate;
@XmlAttribute(name = "work-hours-type")
public String type;
public HourCostDTO() {
}
public HourCostDTO(String code, BigDecimal priceCost, Date initDate,
Date endDate, String type) {
super(code);
this.initDate = initDate;
this.endDate = endDate;
this.priceCost = priceCost;
this.type = type;
}
/**
* This constructor automatically generates a unique code. It is intended to
* facilitate the implementation of test cases that add new instances (such
* instances will have a unique code).
*/
public HourCostDTO(BigDecimal priceCost, Date initDate, Date endDate,
String type) {
this(generateCode(), priceCost, initDate, endDate, type);
}
@Override
public String getEntityType() {
return ENTITY_TYPE;
}
}

View file

@ -0,0 +1,35 @@
/*
* This file is part of NavalPlan
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.ws.costcategories.api;
import org.navalplanner.ws.common.api.InstanceConstraintViolationsListDTO;
/**
* Service for managing cost categories.
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
public interface ICostCategoryService {
InstanceConstraintViolationsListDTO addCostCategories(
CostCategoryListDTO costCategoryListDTO);
public CostCategoryListDTO getCostCotegories();
}

View file

@ -0,0 +1,27 @@
/*
* This file is part of NavalPlan
*
* 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 <http://www.gnu.org/licenses/>.
*/
/**
* Specification of namespace for REST-based services.
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
@javax.xml.bind.annotation.XmlSchema(elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED, namespace = WSCommonGlobalNames.REST_NAMESPACE)
package org.navalplanner.ws.costcategories.api;
import org.navalplanner.ws.common.api.WSCommonGlobalNames;

View file

@ -0,0 +1,194 @@
/*
* This file is part of NavalPlan
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.ws.costcategories.impl;
import static org.navalplanner.web.I18nHelper._;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.navalplanner.business.common.Registry;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.common.exceptions.ValidationException;
import org.navalplanner.business.costcategories.entities.CostCategory;
import org.navalplanner.business.costcategories.entities.HourCost;
import org.navalplanner.business.costcategories.entities.TypeOfWorkHours;
import org.navalplanner.ws.costcategories.api.CostCategoryDTO;
import org.navalplanner.ws.costcategories.api.HourCostDTO;
/**
* Converter from/to cost-category-related entities to/from DTOs.
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
public class CostCategoryConverter {
private CostCategoryConverter() {
}
public final static CostCategoryDTO toDTO(CostCategory costCategory) {
Set<HourCostDTO> hourCostDTOs = new HashSet<HourCostDTO>();
for (HourCost h : costCategory.getHourCosts()) {
hourCostDTOs.add(toDTO(h));
}
if (hourCostDTOs.isEmpty()) {
hourCostDTOs = null;
}
return new CostCategoryDTO(costCategory.getCode(), costCategory
.getName(), costCategory.getEnabled(), hourCostDTOs);
}
public final static HourCostDTO toDTO(HourCost hourCost) {
Date initDate = null;
if (hourCost.getInitDate() != null) {
initDate = hourCost.getInitDate().toDateTimeAtCurrentTime()
.toDate();
}
Date endDate = null;
if (hourCost.getEndDate() != null) {
endDate = hourCost.getEndDate().toDateTimeAtCurrentTime().toDate();
}
String type = null;
if (hourCost.getType() != null) {
type = hourCost.getType().getCode();
}
return new HourCostDTO(hourCost.getCode(), hourCost.getPriceCost(),
initDate, endDate, type);
}
public final static CostCategory toEntity(CostCategoryDTO costCategoryDTO) {
CostCategory costCategory = CostCategory.createUnvalidated(StringUtils
.trim(costCategoryDTO.code), StringUtils
.trim(costCategoryDTO.name), costCategoryDTO.enabled);
for (HourCostDTO hourCostDTO : costCategoryDTO.hourCostDTOs) {
HourCost hourCost = toEntity(hourCostDTO);
hourCost.setCategory(costCategory);
costCategory.addHourCost(hourCost);
}
return costCategory;
}
private static HourCost toEntity(HourCostDTO hourCostDTO)
throws ValidationException {
// Mandatory properties
LocalDate initDate = null;
if(hourCostDTO.initDate != null){
initDate = LocalDate.fromDateFields(hourCostDTO.initDate);
}
//Create new hour cost
HourCost hourCost = HourCost.createUnvalidated(hourCostDTO.code, hourCostDTO.priceCost, initDate);
// optional properties
if (hourCostDTO.endDate != null) {
hourCost.setEndDate(LocalDate.fromDateFields(hourCostDTO.endDate));
}
if (hourCostDTO.type != null) {
try {
TypeOfWorkHours typeOfWorkHours = Registry
.getTypeOfWorkHoursDAO().findUniqueByCode(
hourCostDTO.type);
hourCost.setType(typeOfWorkHours);
} catch (InstanceNotFoundException e) {
throw new ValidationException(
_("There is no type of work hours with this code"));
}
}
return hourCost;
}
public final static void updateCostCategory(CostCategory costCategory,
CostCategoryDTO costCategoryDTO) throws ValidationException {
/*
* 1: Update the existing work report line or add newwork report line.
*/
for (HourCostDTO hourCostDTO : costCategoryDTO.hourCostDTOs) {
/* Step 1.1: requires each hour cost DTO to have a code. */
if (StringUtils.isBlank(hourCostDTO.code)) {
throw new ValidationException(_("missing code in a hour cost"));
}
try {
HourCost hourCost = costCategory
.getHourCostByCode(hourCostDTO.code);
updateHourCost(hourCost, hourCostDTO);
} catch (InstanceNotFoundException e) {
HourCost hourCost = toEntity(hourCostDTO);
hourCost.setCategory(costCategory);
costCategory.addHourCost(hourCost);
}
}
/* 2: Update cost category basic properties. */
costCategory.updateUnvalidated(StringUtils.trim(costCategoryDTO.name),
costCategoryDTO.enabled);
}
public final static void updateHourCost(HourCost hourCost,
HourCostDTO hourCostDTO) throws ValidationException {
// Mandatory properties
LocalDate initDate = null;
if (hourCostDTO.initDate != null) {
initDate = LocalDate.fromDateFields(hourCostDTO.initDate);
}
// Create new hour cost
hourCost.updateUnvalidated(hourCostDTO.priceCost, initDate);
// optional properties
if (hourCostDTO.endDate != null) {
hourCost.setEndDate(LocalDate.fromDateFields(hourCostDTO.endDate));
}
if (hourCostDTO.type != null) {
try {
TypeOfWorkHours typeOfWorkHours = Registry
.getTypeOfWorkHoursDAO().findUniqueByCode(
hourCostDTO.type);
hourCost.setType(typeOfWorkHours);
} catch (InstanceNotFoundException e) {
throw new ValidationException(
_("There is no type of work hours with this code"));
}
}
}
}

View file

@ -0,0 +1,96 @@
/*
* This file is part of NavalPlan
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.ws.costcategories.impl;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.navalplanner.business.common.daos.IIntegrationEntityDAO;
import org.navalplanner.business.common.exceptions.ValidationException;
import org.navalplanner.business.costcategories.daos.ICostCategoryDAO;
import org.navalplanner.business.costcategories.entities.CostCategory;
import org.navalplanner.ws.common.api.InstanceConstraintViolationsListDTO;
import org.navalplanner.ws.common.impl.GenericRESTService;
import org.navalplanner.ws.costcategories.api.CostCategoryDTO;
import org.navalplanner.ws.costcategories.api.CostCategoryListDTO;
import org.navalplanner.ws.costcategories.api.ICostCategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* REST-based implementation of <code>ICostCategoryService</code>.
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
@Path("/costcategories/")
@Produces("application/xml")
@Service("costCategoryServiceREST")
public class CostCategoryServiceREST extends
GenericRESTService<CostCategory, CostCategoryDTO> implements
ICostCategoryService {
@Autowired
private ICostCategoryDAO costCategoryDAO;
@Override
@GET
@Transactional(readOnly = true)
public CostCategoryListDTO getCostCotegories() {
return new CostCategoryListDTO(findAll());
}
@Override
@POST
@Consumes("application/xml")
public InstanceConstraintViolationsListDTO addCostCategories(
CostCategoryListDTO costCategoryListDTO) {
return save(costCategoryListDTO.costCategories);
}
@Override
protected CostCategory toEntity(CostCategoryDTO entityDTO) {
return CostCategoryConverter.toEntity(entityDTO);
}
@Override
protected CostCategoryDTO toDTO(CostCategory entity) {
return CostCategoryConverter.toDTO(entity);
}
@Override
protected IIntegrationEntityDAO<CostCategory> getIntegrationEntityDAO() {
return costCategoryDAO;
}
@Override
protected void updateEntity(CostCategory entity, CostCategoryDTO entityDTO)
throws ValidationException {
CostCategoryConverter.updateCostCategory(entity, entityDTO);
}
}

View file

@ -65,6 +65,7 @@
<ref bean="resourceHoursServiceREST"/>
<ref bean="workReportServiceREST"/>
<ref bean="labelServiceREST"/>
<ref bean="costCategoryServiceREST"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="runtimeExceptionMapper" />

View file

@ -0,0 +1,272 @@
/*
* This file is part of NavalPlan
*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.navalplanner.web.test.ws.costcategories;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.navalplanner.business.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_FILE;
import static org.navalplanner.web.WebappGlobalNames.WEBAPP_SPRING_CONFIG_FILE;
import static org.navalplanner.web.test.WebappGlobalNames.WEBAPP_SPRING_CONFIG_TEST_FILE;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.hibernate.SessionFactory;
import org.joda.time.LocalDate;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.costcategories.daos.ICostCategoryDAO;
import org.navalplanner.business.costcategories.daos.IHourCostDAO;
import org.navalplanner.business.costcategories.daos.ITypeOfWorkHoursDAO;
import org.navalplanner.business.costcategories.entities.CostCategory;
import org.navalplanner.business.costcategories.entities.HourCost;
import org.navalplanner.business.costcategories.entities.TypeOfWorkHours;
import org.navalplanner.ws.common.api.InstanceConstraintViolationsDTO;
import org.navalplanner.ws.costcategories.api.CostCategoryDTO;
import org.navalplanner.ws.costcategories.api.CostCategoryListDTO;
import org.navalplanner.ws.costcategories.api.HourCostDTO;
import org.navalplanner.ws.costcategories.api.ICostCategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
/**
* Tests for <code>ICostCategoryService</code>.
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { BUSINESS_SPRING_CONFIG_FILE,
WEBAPP_SPRING_CONFIG_FILE, WEBAPP_SPRING_CONFIG_TEST_FILE })
@Transactional
public class CostCategoryServiceTest {
@Autowired
private ICostCategoryService costCategoryService;
@Autowired
private ICostCategoryDAO costCategoryDAO;
@Autowired
private IHourCostDAO hourCostDAO;
@Autowired
private ITypeOfWorkHoursDAO typeOfWorkHoursDAO;
@Autowired
private SessionFactory sessionFactory;
private final String typeOfWorkHoursCodeA = "code-A";
private final String typeOfWorkHoursCodeB = "code-B";
@Test
@Rollback(false)
public void createAPairTypeOfWorkHours() {
givenTypeOfWorkHours(typeOfWorkHoursCodeA);
givenTypeOfWorkHours(typeOfWorkHoursCodeB);
}
private void givenTypeOfWorkHours(String code) {
TypeOfWorkHours typeOfWorkHours = TypeOfWorkHours.create();
typeOfWorkHours.setCode(code);
typeOfWorkHours.setName("name" + UUID.randomUUID());
typeOfWorkHoursDAO.save(typeOfWorkHours);
typeOfWorkHoursDAO.flush();
sessionFactory.getCurrentSession().evict(typeOfWorkHours);
typeOfWorkHours.dontPoseAsTransientObjectAnymore();
}
@Test
public void testAddAndGetCostCategories() {
/* Build cost category (5 constraint violations). */
// Missing cost category name and enabled.
CostCategoryDTO cc1 = new CostCategoryDTO(null, true,
new HashSet<HourCostDTO>());
// Valid cost category DTO without hour cost
CostCategoryDTO cc2 = new CostCategoryDTO("cc2",
true, new HashSet<HourCostDTO>());
// Valid cost category DTO with a hour cost
Set<HourCostDTO> cc3_HourCostDTOs = new HashSet<HourCostDTO>();
HourCostDTO cc3_1_HourCostDTO = new HourCostDTO(new BigDecimal(3),
new Date(), new Date(), typeOfWorkHoursCodeA);
cc3_HourCostDTOs.add(cc3_1_HourCostDTO);
CostCategoryDTO cc3 = new CostCategoryDTO("cc3", true, cc3_HourCostDTOs);
// Valid cost category DTO with a invalid hour cost
// missing pricecost, initDate and type
Set<HourCostDTO> cc4_HourCostDTOs = new HashSet<HourCostDTO>();
HourCostDTO cc4_1_HourCostDTO = new HourCostDTO(null, null, null, null);
cc4_HourCostDTOs.add(cc4_1_HourCostDTO);
CostCategoryDTO cc4 = new CostCategoryDTO("cc4", true, cc4_HourCostDTOs);
/* Criterion type list. */
CostCategoryListDTO costCategoryListDTO = createCostCategoryListDTO(
cc1, cc2, cc3, cc4);
List<InstanceConstraintViolationsDTO> instanceConstraintViolationsList = costCategoryService
.addCostCategories(costCategoryListDTO).instanceConstraintViolationsList;
assertTrue(instanceConstraintViolationsList.toString(),
instanceConstraintViolationsList.size() == 2);
assertTrue(instanceConstraintViolationsList.get(0).constraintViolations
.toString(),
instanceConstraintViolationsList.get(0).constraintViolations
.size() == 1); // cc1 constraint violations.
assertTrue(instanceConstraintViolationsList.get(1).constraintViolations
.toString(),
instanceConstraintViolationsList.get(1).constraintViolations
.size() == 3); // cc1 constraint violations.
/* Test. */
assertFalse(costCategoryDAO.existsByCode(cc1.code));
assertTrue(costCategoryDAO.existsByCode(cc2.code));
assertTrue(costCategoryDAO.existsByCode(cc3.code));
assertFalse(costCategoryDAO.existsByCode(cc4.code));
try {
CostCategory costCategory = costCategoryDAO.findByCode(cc3.code);
assertTrue(costCategory.getHourCosts().size() == 1);
} catch (InstanceNotFoundException e) {
assertTrue(false);
}
}
@Test
public void testUpdateCostCategory() throws InstanceNotFoundException {
//First one it creates Valid cost category DTO with a hour cost
final String costCategoryCode = "code-CC";
final String hourCostCode = "code-HC";
Set<HourCostDTO> cc1_HourCostDTOs = new HashSet<HourCostDTO>();
HourCostDTO cc1_1_HourCostDTO = new HourCostDTO(hourCostCode,new BigDecimal(3),
new Date(), new Date(), typeOfWorkHoursCodeA);
cc1_HourCostDTOs.add(cc1_1_HourCostDTO);
CostCategoryDTO cc1 = new CostCategoryDTO(costCategoryCode,"newCC1", true, cc1_HourCostDTOs);
/* Criterion type list. */
CostCategoryListDTO costCategoryListDTO = createCostCategoryListDTO(cc1);
List<InstanceConstraintViolationsDTO> instanceConstraintViolationsList = costCategoryService
.addCostCategories(costCategoryListDTO).instanceConstraintViolationsList;
costCategoryDAO.flush();
hourCostDAO.flush();
/* Test. */
assertTrue(instanceConstraintViolationsList.toString(),
instanceConstraintViolationsList.size() == 0);
assertTrue(costCategoryDAO.existsByCode(cc1.code));
CostCategory costCategory = null;
try {
costCategory = costCategoryDAO.findByCode(cc1.code);
assertTrue(costCategory.getHourCosts().size() == 1);
} catch (InstanceNotFoundException e) {
assertTrue(false);
}
costCategoryDAO.flush();
sessionFactory.getCurrentSession().evict(costCategory);
costCategory.dontPoseAsTransientObjectAnymore();
// Update the previous cost category
Set<HourCostDTO> cc2_HourCostDTOs = new HashSet<HourCostDTO>();
HourCostDTO cc2_1_HourCostDTO = new HourCostDTO(hourCostCode,
new BigDecimal(100), getNextMonthDate(), getNextMonthDate(),
typeOfWorkHoursCodeB);
cc2_HourCostDTOs.add(cc2_1_HourCostDTO);
CostCategoryDTO cc2 = new CostCategoryDTO(costCategoryCode,"updateCC1", false, cc2_HourCostDTOs);
/* Criterion type list. */
costCategoryListDTO = createCostCategoryListDTO(cc2);
instanceConstraintViolationsList = costCategoryService
.addCostCategories(costCategoryListDTO).instanceConstraintViolationsList;
/* Test. */
// the end date cannot be before the initDate
assertTrue(instanceConstraintViolationsList.toString(),
instanceConstraintViolationsList.size() == 0);
assertTrue(costCategoryDAO.existsByCode(cc1.code));
assertTrue(hourCostDAO.existsByCode(cc1_1_HourCostDTO.code));
// Check if the changes was updated
try {
costCategory = costCategoryDAO
.findByCode(costCategoryCode);
assertTrue(costCategory.getHourCosts().size() == 1);
assertTrue(costCategory.getName().equalsIgnoreCase("updateCC1"));
assertFalse(costCategory.getEnabled());
HourCost hourCost = hourCostDAO.findByCode(cc1_1_HourCostDTO.code);
LocalDate nextMonthDate = LocalDate
.fromDateFields(getNextMonthDate());
assertTrue(hourCost.getInitDate().compareTo(nextMonthDate) == 0);
assertFalse(hourCost.getEndDate() == null);
assertTrue(hourCost.getPriceCost().compareTo(new BigDecimal(100)) == 0);
assertTrue(hourCost.getType().getCode().equalsIgnoreCase(
typeOfWorkHoursCodeB));
} catch (InstanceNotFoundException e) {
assertTrue(false);
}
}
private Date getNextMonthDate() {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.add(calendar.MONTH, 1);
int date = calendar.get(Calendar.DAY_OF_MONTH);
int month = calendar.get(calendar.MONTH);
int year = calendar.get(Calendar.YEAR);
calendar.set(year, month, date);
return calendar.getTime();
}
private CostCategoryListDTO createCostCategoryListDTO(
CostCategoryDTO... costCategories) {
List<CostCategoryDTO> costCategoryList = new ArrayList<CostCategoryDTO>();
for (CostCategoryDTO c : costCategories) {
costCategoryList.add(c);
}
return new CostCategoryListDTO(costCategoryList);
}
}

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<cost-category-list xmlns="http://rest.ws.navalplanner.org">
<cost-category enabled="true" name="Categoria A"
code="18d6ef79-5b45-4928-bfd5-ec80a374699c">
<hour-cost-list>
<hour-cost work-hours-type="code-N"
endDate="2010-04-27T12:26:47.010+01:00"
initDate="2010-03-17T12:26:47.010+01:00" priceCost="5.00"
code="31001efc-64f2-45be-acb0-045b1d9562ee" />
<hour-cost work-hours-type="code-E"
endDate="2010-04-27T12:26:47.010+01:00"
initDate="2010-03-11T12:26:47.014+01:00" priceCost="8.00"
code="fa840393-2718-4cbd-ba8e-c7f6503a7e9b" />
</hour-cost-list>
</cost-category>
<cost-category enabled="true" name="Categoria B"
code="b1029095-6ec4-484b-a620-5f0562cef800">
<hour-cost-list>
<hour-cost work-hours-type="code-P"
endDate="2010-05-27T12:26:47.010+01:00"
initDate="2010-05-17T12:26:47.010+01:00" priceCost="6.50"
code="72974982374kjfkjsdjsjdfsjls" />
</hour-cost-list>
</cost-category>
</cost-category-list>

View file

@ -0,0 +1,21 @@
#!/bin/sh
. ./rest-common-env.sh
printf "Login name: "
read loginName
printf "Password: "
read password
if [ "$1" = "--prod" ]; then
baseServiceURL=$PRODUCTION_BASE_SERVICE_URL
certificate=$PRODUCTION_CERTIFICATE
else
baseServiceURL=$DEVELOPMENT_BASE_SERVICE_URL
certificate=$DEVELOPMENT_CERTIFICATE
fi
authorization=`./base64.sh $loginName:$password`
curl -sv -X GET $certificate --header "Authorization: Basic $authorization" \
$baseServiceURL/costcategories | tidy -xml -i -q -utf8

View file

@ -0,0 +1,33 @@
#!/bin/sh
. ./rest-common-env.sh
printf "Login name: "
read loginName
printf "Password: "
read password
baseServiceURL=$DEVELOPMENT_BASE_SERVICE_URL
certificate=$DEVELOPMENT_CERTIFICATE
for i in "$@"
do
if [ "$i" = "--prod" ]; then
baseServiceURL=$PRODUCTION_BASE_SERVICE_URL
certificate=$PRODUCTION_CERTIFICATE
else
file=$i
fi
done
if [ "$file" = "" ]; then
printf "Missing file\n" 1>&2
exit 1
fi
authorization=`./base64.sh $loginName:$password`
curl -sv -X POST $certificate -d @$file \
--header "Content-type: application/xml" \
--header "Authorization: Basic $authorization" \
$baseServiceURL/costcategories | tidy -xml -i -q -utf8