import and export the expense sheets.

FEA: ItEr76S22ExpenseTrackingSystem
This commit is contained in:
Susana Montes Pedreira 2012-06-04 17:18:49 +01:00
parent 6bdf2fd045
commit 488977188e
8 changed files with 683 additions and 0 deletions

View file

@ -24,6 +24,7 @@ import java.util.Collections;
import java.util.SortedSet;
import java.util.TreeSet;
import org.apache.commons.lang.StringUtils;
import org.hibernate.validator.AssertTrue;
import org.hibernate.validator.Min;
import org.hibernate.validator.NotEmpty;
@ -34,6 +35,7 @@ import org.libreplan.business.common.IHumanIdentifiable;
import org.libreplan.business.common.IntegrationEntity;
import org.libreplan.business.common.Registry;
import org.libreplan.business.common.entities.EntitySequence;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.expensesheet.daos.IExpenseSheetDAO;
/**
@ -198,4 +200,22 @@ public class ExpenseSheet extends IntegrationEntity implements IHumanIdentifiabl
return getCode() + (description != null ? description : "");
}
public ExpenseSheetLine getExpenseSheetLineByCode(String code)
throws InstanceNotFoundException {
if (StringUtils.isBlank(code)) {
throw new InstanceNotFoundException(code,
ExpenseSheetLine.class.getName());
}
for (ExpenseSheetLine l : this.expenseSheetLines) {
if (l.getCode().equalsIgnoreCase(StringUtils.trim(code))) {
return l;
}
}
throw new InstanceNotFoundException(code,
ExpenseSheetLine.class.getName());
}
}

View file

@ -0,0 +1,69 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2012 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.expensesheets.api;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import org.libreplan.business.expensesheet.entities.ExpenseSheet;
import org.libreplan.ws.common.api.IntegrationEntityDTO;
/**
* DTO for {@link ExpenseSheet} entity.
*
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
@XmlRootElement(name = "expense-sheet")
public class ExpenseSheetDTO extends IntegrationEntityDTO {
public final static String ENTITY_TYPE = "expense-sheet";
@XmlAttribute
public String description;
@XmlElementWrapper(name = "expense-sheet-line-list")
@XmlElement(name = "expense-sheet-line")
public List<ExpenseSheetLineDTO> lines = new ArrayList<ExpenseSheetLineDTO>();
public ExpenseSheetDTO() {
}
public ExpenseSheetDTO(String code, String description,
List<ExpenseSheetLineDTO> lines) {
super(code);
this.description = description;
this.lines = lines;
}
public ExpenseSheetDTO(String description, List<ExpenseSheetLineDTO> lines) {
this(generateCode(), description, lines);
}
@Override
public String getEntityType() {
return ENTITY_TYPE;
}
}

View file

@ -0,0 +1,80 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2012 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.expensesheets.api;
import java.math.BigDecimal;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.datatype.XMLGregorianCalendar;
import org.libreplan.business.expensesheet.entities.ExpenseSheet;
import org.libreplan.ws.common.api.IntegrationEntityDTO;
/**
* DTO for {@link ExpenseSheet} entity.
*
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
@XmlRootElement(name = "expense-sheet-line")
public class ExpenseSheetLineDTO extends IntegrationEntityDTO {
public final static String ENTITY_TYPE = "expense-sheet-line";
@XmlAttribute
public String concept;
@XmlAttribute
public BigDecimal value;
@XmlAttribute
public String resource;
@XmlAttribute(name = "task")
public String orderElement;
@XmlAttribute
public XMLGregorianCalendar date;
public ExpenseSheetLineDTO() {
}
public ExpenseSheetLineDTO(String code, String concept, BigDecimal value, String resource,
String orderElement, XMLGregorianCalendar date) {
super(code);
this.concept = concept;
this.value = value;
this.resource = resource;
this.orderElement = orderElement;
this.date = date;
}
public ExpenseSheetLineDTO(String concept, BigDecimal value, String resource,
String orderElement,
XMLGregorianCalendar date) {
this(generateCode(), concept, value, resource, orderElement, date);
}
@Override
public String getEntityType() {
return ENTITY_TYPE;
}
}

View file

@ -0,0 +1,45 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2012, 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.expensesheets.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 {@link ExpensesSheet} entities.
*
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
@XmlRootElement(name = "expense-sheet-list")
public class ExpenseSheetListDTO {
@XmlElement(name = "expense-sheet")
public List<ExpenseSheetDTO> expenseSheets = new ArrayList<ExpenseSheetDTO>();
public ExpenseSheetListDTO() {
}
public ExpenseSheetListDTO(List<ExpenseSheetDTO> expenseSheets) {
this.expenseSheets = expenseSheets;
}
}

View file

@ -0,0 +1,41 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2012, 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.expensesheets.api;
import javax.ws.rs.core.Response;
import org.libreplan.business.expensesheet.entities.ExpenseSheet;
import org.libreplan.ws.common.api.InstanceConstraintViolationsListDTO;
/**
* Service for managing {@link ExpenseSheet} entities.
*
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
public interface IExpenseSheetService {
ExpenseSheetListDTO getExpenseSheets();
InstanceConstraintViolationsListDTO addExpenseSheets(
ExpenseSheetListDTO expenseSheetListDTO);
Response getLabel(String code);
}

View file

@ -0,0 +1,264 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2012 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.expensesheets.impl;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.xml.datatype.XMLGregorianCalendar;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.libreplan.business.common.Registry;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.expensesheet.entities.ExpenseSheet;
import org.libreplan.business.expensesheet.entities.ExpenseSheetLine;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.resources.entities.Resource;
import org.libreplan.ws.common.impl.DateConverter;
import org.libreplan.ws.expensesheets.api.ExpenseSheetDTO;
import org.libreplan.ws.expensesheets.api.ExpenseSheetLineDTO;
import org.libreplan.ws.expensesheets.api.ExpenseSheetListDTO;
/**
* Converter from/to {@link ExpenseSheet} related entities to/from DTOs.
*
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
public final class ExpenseSheetConverter {
private ExpenseSheetConverter() {
}
public final static ExpenseSheetListDTO toDTO(Collection<ExpenseSheet> expenseSheets) {
List<ExpenseSheetDTO> expenseSheetDTOs = new ArrayList<ExpenseSheetDTO>();
for (ExpenseSheet expenseSheet : expenseSheets) {
expenseSheetDTOs.add(toDTO(expenseSheet));
}
return new ExpenseSheetListDTO(expenseSheetDTOs);
}
public final static ExpenseSheetDTO toDTO(ExpenseSheet expenseSheet) {
String code = expenseSheet.getCode();
if (StringUtils.isBlank(code)) {
throw new ValidationException("missing code in the expense sheet");
}
List<ExpenseSheetLineDTO> lineDTOs = new ArrayList<ExpenseSheetLineDTO>();
if (expenseSheet.getExpenseSheetLines() == null
|| expenseSheet.getExpenseSheetLines().isEmpty()) {
throw new ValidationException(
"the expense sheet must have least a expense sheet line.");
}
for (ExpenseSheetLine line : expenseSheet.getExpenseSheetLines()) {
lineDTOs.add(toDTO(line));
}
return new ExpenseSheetDTO(code, expenseSheet.getDescription(),
lineDTOs);
}
private static ExpenseSheetLineDTO toDTO(ExpenseSheetLine line) {
if (line != null) {
String code = line.getCode();
if (StringUtils.isBlank(code)) {
throw new ValidationException(
"missing code in the expense sheet line");
}
BigDecimal value = line.getValue();
if (value != null && value.compareTo(BigDecimal.ZERO) > 0) {
}
String resourceCode = null;
if (line.getResource() != null) {
resourceCode = line.getResource().getCode();
}
String orderElementCode = null;
if (line.getOrderElement() != null) {
orderElementCode = line.getOrderElement().getCode();
} else {
throw new ValidationException(
"missing order element code in a expense sheet line");
}
XMLGregorianCalendar date = null;
if (line.getDate() != null) {
date = DateConverter.toXMLGregorianCalendar(line.getDate());
} else {
throw new ValidationException(
"missing date in a expense sheet line");
}
return new ExpenseSheetLineDTO(code, line.getConcept(), value,
resourceCode, orderElementCode, date);
} else {
throw new ValidationException(
"the expense sheet line is not initialized");
}
}
public final static ExpenseSheet toEntity(ExpenseSheetDTO expenseSheetDTO) {
ExpenseSheet expenseSheet = ExpenseSheet.create();
expenseSheet.setCode(expenseSheetDTO.code);
expenseSheet.setDescription(expenseSheetDTO.description);
for (ExpenseSheetLineDTO lineDTO : expenseSheetDTO.lines) {
expenseSheet.add(toEntity(lineDTO, expenseSheet));
}
return expenseSheet;
}
private static ExpenseSheetLine toEntity(ExpenseSheetLineDTO lineDTO, ExpenseSheet expenseSheet) {
String code = lineDTO.code;
if(StringUtils.isBlank(code)){
throw new ValidationException("missing code expense sheet line");
}
BigDecimal value = lineDTO.value;
String concept = lineDTO.concept;
LocalDate date = null;
if (lineDTO.date != null) {
date = DateConverter.toLocalDate(lineDTO.date);
}
String orderElementCode = lineDTO.orderElement;
OrderElement orderElement = null;
try{
orderElement = Registry.getOrderElementDAO().findByCode(
orderElementCode);
}catch (InstanceNotFoundException e) {
throw new ValidationException(
"There is no order element with this code");
}
ExpenseSheetLine line = ExpenseSheetLine.create(value, concept, date,
orderElement);
line.setExpenseSheet(expenseSheet);
line.setCode(code);
if(lineDTO.resource != null){
String resourceCode = lineDTO.resource;
try{
Resource resource = Registry.getResourceDAO().findByCode(resourceCode);
line.setResource(resource);
}catch (InstanceNotFoundException e) {
throw new ValidationException(
"There is no resource with this code");
}
}
return line;
}
public final static void updateExpenseSheet(ExpenseSheet expenseSheet,
ExpenseSheetDTO expenseSheetDTO) throws ValidationException {
if (StringUtils.isBlank(expenseSheetDTO.code)) {
throw new ValidationException("missing code in a expense sheet.");
}
if (!StringUtils.isBlank(expenseSheetDTO.description)) {
expenseSheet.setDescription(expenseSheetDTO.description);
}
/*
* 1: Update the existing expense sheet line or add new expense sheet
* line.
*/
for (ExpenseSheetLineDTO lineDTO : expenseSheetDTO.lines) {
/* Step 1.1: requires each expense sheet line DTO to have a code. */
if (StringUtils.isBlank(lineDTO.code)) {
throw new ValidationException(
"missing code in a expense sheet line");
}
try {
ExpenseSheetLine line = expenseSheet
.getExpenseSheetLineByCode(lineDTO.code);
updateExpenseSheetLine(line, lineDTO);
} catch (InstanceNotFoundException e) {
expenseSheet.add(toEntity(lineDTO, expenseSheet));
}
}
}
public final static void updateExpenseSheetLine(ExpenseSheetLine line,
ExpenseSheetLineDTO lineDTO) throws ValidationException {
/*
* 1: Update the concept
*/
if (lineDTO.concept != null) {
line.setConcept(lineDTO.concept);
}
/*
* 2: Update the value
*/
if (lineDTO.value != null) {
line.setValue(lineDTO.value);
}
/*
* 3: Update the order element
*/
String orderElementCode = lineDTO.orderElement;
if (!StringUtils.isBlank(orderElementCode)) {
try {
OrderElement orderElement = Registry.getOrderElementDAO()
.findUniqueByCode(orderElementCode);
line.setOrderElement(orderElement);
} catch (InstanceNotFoundException e) {
throw new ValidationException("There is no task with this code");
}
}
/* Step 3.1: Update the date. */
if (lineDTO != null) {
LocalDate date = DateConverter.toLocalDate(lineDTO.date);
line.setDate(date);
}
/* Step 3.4: Update the resource. */
if (lineDTO.resource != null) {
try {
Resource resource = Registry.getResourceDAO().findByCode(
lineDTO.resource);
line.setResource(resource);
} catch (InstanceNotFoundException e) {
throw new ValidationException(
"There is no resource with this code");
}
}
}
}

View file

@ -0,0 +1,163 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2012 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.expensesheets.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.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import org.libreplan.business.common.IOnTransaction;
import org.libreplan.business.common.daos.IIntegrationEntityDAO;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.expensesheet.daos.IExpenseSheetDAO;
import org.libreplan.business.expensesheet.entities.ExpenseSheet;
import org.libreplan.business.orders.daos.ISumExpensesDAO;
import org.libreplan.ws.common.api.InstanceConstraintViolationsListDTO;
import org.libreplan.ws.common.impl.GenericRESTService;
import org.libreplan.ws.common.impl.RecoverableErrorException;
import org.libreplan.ws.expensesheets.api.ExpenseSheetDTO;
import org.libreplan.ws.expensesheets.api.ExpenseSheetListDTO;
import org.libreplan.ws.expensesheets.api.IExpenseSheetService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* REST-based implementation of {@link IExpenseSheetService}.
*
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
@Path("/expenses/")
@Produces("application/xml")
@Service("expenseSheetServiceREST")
public class ExpenseSheetServiceREST extends
GenericRESTService<ExpenseSheet, ExpenseSheetDTO> implements
IExpenseSheetService {
@Autowired
private ISumExpensesDAO sumExpensesDAO;
@Autowired
private IExpenseSheetDAO expenseSheetDAO;
/**
* It saves (inserts or updates) an entity DTO by using a new transaction.
*
* @throws ValidationException if validations are not passed
* @throws RecoverableErrorException if a recoverable error occurs
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*
*/
protected void insertOrUpdate(final ExpenseSheetDTO entityDTO)
throws ValidationException, RecoverableErrorException {
/*
* NOTE: ValidationException and RecoverableErrorException are runtime
* exceptions. In consequence, if any of them occurs, transaction is
* automatically rolled back.
*/
IOnTransaction<Void> save = new IOnTransaction<Void>() {
@Override
public Void execute() {
ExpenseSheet entity = null;
IIntegrationEntityDAO<ExpenseSheet> entityDAO = getIntegrationEntityDAO();
/* Insert or update? */
try {
entity = entityDAO.findByCode(entityDTO.code);
updateEntity(entity, entityDTO);
} catch (InstanceNotFoundException e) {
entity = toEntity(entityDTO);
}
/*
* Validate and save (insert or update) the entity.
*/
entity.validate();
sumExpensesDAO
.updateRelatedSumExpensesWithExpenseSheetLineSet(entity
.getExpenseSheetLines());
entity.updateCalculatedProperties();
entityDAO.saveWithoutValidating(entity);
return null;
}
};
transactionService.runOnAnotherTransaction(save);
}
@Override
@POST
@Consumes("application/xml")
@Transactional
public InstanceConstraintViolationsListDTO addExpenseSheets(
ExpenseSheetListDTO expenseSheetListDTO) {
return save(expenseSheetListDTO.expenseSheets);
}
@Override
protected IIntegrationEntityDAO<ExpenseSheet> getIntegrationEntityDAO() {
return expenseSheetDAO;
}
@Override
protected ExpenseSheetDTO toDTO(ExpenseSheet entity) {
return ExpenseSheetConverter.toDTO(entity);
}
@Override
protected ExpenseSheet toEntity(ExpenseSheetDTO entityDTO)
throws ValidationException, RecoverableErrorException {
return ExpenseSheetConverter.toEntity(entityDTO);
}
@Override
@GET
@Path("/{code}/")
@Transactional(readOnly = true)
public Response getLabel(@PathParam("code") String code) {
return getDTOByCode(code);
}
@Override
protected void updateEntity(ExpenseSheet entity, ExpenseSheetDTO entityDTO)
throws ValidationException, RecoverableErrorException {
ExpenseSheetConverter.updateExpenseSheet(entity, entityDTO);
}
@Override
@GET
@Transactional(readOnly = true)
public ExpenseSheetListDTO getExpenseSheets() {
return new ExpenseSheetListDTO(findAll());
}
}

View file

@ -72,6 +72,7 @@
<ref bean="calendarServiceREST"/>
<ref bean="materialServiceREST"/>
<ref bean="unitTypeServiceREST"/>
<ref bean="expenseSheetServiceREST"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="runtimeExceptionMapper" />