Calculate first/last timesheets dates when saving/editing/deleting a timesheet

In order to do that, a set of order elements affected by the lines
added/edit/removed in a timesheet is calculated before saving the timesheet.
Afterwards the first/last dates are recalculated for all the order elements in
the set.

FEA: ItEr77S12AdaptPlanningAccordingTimesheets
This commit is contained in:
Manuel Rego Casasnovas 2012-10-30 11:56:14 +01:00
parent 460896ee8b
commit 4adc1ec71f
6 changed files with 181 additions and 13 deletions

View file

@ -74,4 +74,26 @@ public interface ISumChargedEffortDAO extends
*/
void recalculateSumChargedEfforts(Long orderId);
/**
* Returns a {@link Set} of {@link OrderElement OrderElements} affected by
* any change taking into account the lines in the report and the ones to be
* removed.
*
* Usually you call this method to get the set before saving the work
* report. After saving the work report you call
* {@link ISumChargedEffortDAO#recalculateTimesheetDates(Set)} with the
* result of this method.
*
* You can pass <code>null</code> as param if you only have one of the sets.
*/
Set<OrderElement> getOrderElementsToRecalculateTimsheetDates(
Set<WorkReportLine> workReportLines,
Set<WorkReportLine> deletedWorkReportLinesSet);
/**
* Recalulates the first and last timesheets dates for each
* {@link OrderElement} in the {@link Set}.
*/
void recalculateTimesheetDates(Set<OrderElement> orderElements);
}

View file

@ -70,6 +70,9 @@ public class SumChargedEffortDAO extends
@Autowired
private IOrderDAO orderDAO;
@Autowired
private IOrderElementDAO orderElementDAO;
private Map<OrderElement, SumChargedEffort> mapSumChargedEfforts;
@Override
@ -118,6 +121,7 @@ public class SumChargedEffortDAO extends
forceLoadParents(parent);
}
}
});
previousEffort = previous.getFirst();
@ -252,7 +256,7 @@ public class SumChargedEffortDAO extends
resetMapSumChargedEfforts();
resetSumChargedEffort(order);
calculateDirectChargedEffort(order);
calculateFirstAndLastTimesheetDates(order);
calculateTimesheetDates(order);
} catch (InstanceNotFoundException e) {
throw new RuntimeException(e);
}
@ -280,7 +284,7 @@ public class SumChargedEffortDAO extends
addDirectChargedEffort(orderElement, effort);
}
private Pair<Date, Date> calculateFirstAndLastTimesheetDates(
private Pair<Date, Date> calculateTimesheetDates(
OrderElement orderElement) {
Pair<Date, Date> minMax = workReportLineDAO
.findMinAndMaxDatesByOrderElement(orderElement);
@ -292,18 +296,21 @@ public class SumChargedEffortDAO extends
addIfNotNull(maxDates, minMax.getSecond());
for (OrderElement child : orderElement.getChildren()) {
Pair<Date, Date> minMaxChild = calculateFirstAndLastTimesheetDates(child);
Pair<Date, Date> minMaxChild = calculateTimesheetDates(child);
addIfNotNull(minDates, minMaxChild.getFirst());
addIfNotNull(maxDates, minMaxChild.getSecond());
}
SumChargedEffort sumChargedEffort = getByOrderElement(orderElement);
sumChargedEffort.setTimesheetDates(minMax.getFirst(),
minMax.getSecond());
return Pair.create(
Pair<Date, Date> result = Pair.create(
minDates.isEmpty() ? null : Collections.min(minDates),
maxDates.isEmpty() ? null : Collections.max(maxDates));
SumChargedEffort sumChargedEffort = getByOrderElement(orderElement);
sumChargedEffort.setTimesheetDates(result.getFirst(),
result.getSecond());
save(sumChargedEffort);
return result;
}
private void addIfNotNull(Collection<Date> list, Date date) {
@ -312,4 +319,101 @@ public class SumChargedEffortDAO extends
}
}
@Override
@Transactional(readOnly = true)
public Set<OrderElement> getOrderElementsToRecalculateTimsheetDates(
Set<WorkReportLine> workReportLines,
Set<WorkReportLine> deletedWorkReportLines) {
Set<OrderElement> orderElements = new HashSet<OrderElement>();
if (workReportLines != null) {
for (final WorkReportLine workReportLine : workReportLines) {
if (!workReportLine.isNewObject()) {
OrderElement previousOrderElement = transactionService
.runOnAnotherTransaction(new IOnTransaction<OrderElement>() {
@Override
public OrderElement execute() {
try {
WorkReportLine line = workReportLineDAO
.find(workReportLine.getId());
return line.getOrderElement();
} catch (InstanceNotFoundException e) {
throw new RuntimeException(e);
}
}
});
orderElements.add(previousOrderElement);
}
orderElements.add(workReportLine.getOrderElement());
}
}
if (deletedWorkReportLines != null) {
for (WorkReportLine workReportLine : deletedWorkReportLines) {
if (workReportLine.isNewObject()) {
// If the line hasn't been saved, we don't take it into
// account
continue;
}
// Refresh data from database, because of changes not saved are
// not
// useful for the following operations
sessionFactory.getCurrentSession().refresh(workReportLine);
orderElements.add(workReportLine.getOrderElement());
}
}
return orderElements;
}
@Override
@Transactional
public void recalculateTimesheetDates(Set<OrderElement> orderElements) {
try {
for (OrderElement orderElement : orderElements) {
saveTimesheetDatesRecursively(orderElementDAO.find(orderElement
.getId()));
}
} catch (InstanceNotFoundException e) {
throw new RuntimeException(e);
}
}
private void saveTimesheetDatesRecursively(OrderElement orderElement) {
if (orderElement != null) {
saveTimesheetDates(orderElement);
saveTimesheetDatesRecursively(orderElement.getParent());
}
}
private void saveTimesheetDates(OrderElement orderElement) {
Pair<Date, Date> minMax = workReportLineDAO
.findMinAndMaxDatesByOrderElement(orderElement);
Set<Date> minDates = new HashSet<Date>();
Set<Date> maxDates = new HashSet<Date>();
addIfNotNull(minDates, minMax.getFirst());
addIfNotNull(maxDates, minMax.getSecond());
for (OrderElement child : orderElement.getChildren()) {
SumChargedEffort childSumChargedEffort = getByOrderElement(child);
addIfNotNull(minDates,
childSumChargedEffort.getFirstTimesheetDate());
addIfNotNull(maxDates, childSumChargedEffort.getLastTimesheetDate());
}
Pair<Date, Date> result = Pair.create(minDates.isEmpty() ? null
: Collections.min(minDates), maxDates.isEmpty() ? null
: Collections.max(maxDates));
SumChargedEffort sumChargedEffort = getByOrderElement(orderElement);
sumChargedEffort.setTimesheetDates(result.getFirst(),
result.getSecond());
save(sumChargedEffort);
}
}

View file

@ -431,12 +431,16 @@ public class PersonalTimesheetModel implements IPersonalTimesheetModel {
// saved as it will not be possible to find it later with
// WorkReportDAO.getPersonalTimesheetWorkReport() method.
} else {
Set<OrderElement> orderElements = sumChargedEffortDAO
.getOrderElementsToRecalculateTimsheetDates(
workReport.getWorkReportLines(), null);
sumChargedEffortDAO
.updateRelatedSumChargedEffortWithWorkReportLineSet(workReport
.getWorkReportLines());
workReport.generateWorkReportLineCodes(entitySequenceDAO
.getNumberOfDigitsCode(EntityNameEnum.WORK_REPORT));
workReportDAO.save(workReport);
sumChargedEffortDAO.recalculateTimesheetDates(orderElements);
}
resetModifiedFields();

View file

@ -274,12 +274,17 @@ public class WorkReportModel extends IntegrationEntityModel implements
@Override
@Transactional
public void confirmSave() throws ValidationException {
Set<OrderElement> orderElements = sumChargedEffortDAO
.getOrderElementsToRecalculateTimsheetDates(
workReport.getWorkReportLines(),
deletedWorkReportLinesSet);
sumChargedEffortDAO.updateRelatedSumChargedEffortWithDeletedWorkReportLineSet(deletedWorkReportLinesSet);
sumChargedEffortDAO
.updateRelatedSumChargedEffortWithWorkReportLineSet(workReport
.getWorkReportLines());
workReportDAO.save(workReport);
sumChargedEffortDAO.recalculateTimesheetDates(orderElements);
}
@Override
@ -412,10 +417,14 @@ public class WorkReportModel extends IntegrationEntityModel implements
//before deleting the report, update OrderElement.SumChargedHours
try {
workReportDAO.reattach(workReport);
Set<OrderElement> orderElements = sumChargedEffortDAO
.getOrderElementsToRecalculateTimsheetDates(null,
workReport.getWorkReportLines());
sumChargedEffortDAO
.updateRelatedSumChargedEffortWithDeletedWorkReportLineSet(workReport
.getWorkReportLines());
workReportDAO.remove(workReport.getId());
sumChargedEffortDAO.recalculateTimesheetDates(orderElements);
} catch (InstanceNotFoundException e) {
throw new RuntimeException(e);
}

View file

@ -143,6 +143,7 @@ public abstract class GenericRESTService<E extends IntegrationEntity,
entity.validate();
beforeSaving(entity);
entityDAO.saveWithoutValidating(entity);
afterSaving(entity);
return null;
@ -155,12 +156,23 @@ public abstract class GenericRESTService<E extends IntegrationEntity,
}
/**
* it adds operations that must be done before saving.
* It allows to add operations that must be done before saving.
*
* Default implementation is empty.
*/
protected void beforeSaving(E entity) {
}
/**
* It allows to add operations that must be done after saving.
*
* Default implementation is empty.
*/
protected void afterSaving(E entity) {
}
/**
* It creates an entity from a DTO.
*

View file

@ -22,7 +22,9 @@
package org.libreplan.ws.workreports.impl;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
@ -37,8 +39,8 @@ import javax.ws.rs.core.Response.Status;
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.orders.daos.IOrderElementDAO;
import org.libreplan.business.orders.daos.ISumChargedEffortDAO;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.workreports.daos.IWorkReportDAO;
import org.libreplan.business.workreports.daos.IWorkReportLineDAO;
import org.libreplan.business.workreports.entities.WorkReport;
@ -64,15 +66,14 @@ public class WorkReportServiceREST extends
GenericRESTService<WorkReport, WorkReportDTO> implements
IWorkReportService {
private Set<OrderElement> orderElements;
@Autowired
private IWorkReportDAO workReportDAO;
@Autowired
private IWorkReportLineDAO workReportLineDAO;
@Autowired
private IOrderElementDAO orderElementDAO;
@Autowired
private ISumChargedEffortDAO sumChargedEffortDAO;
@ -120,11 +121,19 @@ public class WorkReportServiceREST extends
@Override
protected void beforeSaving(WorkReport entity) {
orderElements = sumChargedEffortDAO
.getOrderElementsToRecalculateTimsheetDates(
entity.getWorkReportLines(), null);
sumChargedEffortDAO
.updateRelatedSumChargedEffortWithWorkReportLineSet(entity
.getWorkReportLines());
}
@Override
protected void afterSaving(WorkReport entity) {
sumChargedEffortDAO.recalculateTimesheetDates(orderElements);
}
@Override
@GET
@Path("/{code}/")
@ -140,10 +149,14 @@ public class WorkReportServiceREST extends
public Response removeWorkReport(@PathParam("code") String code) {
try {
WorkReport workReport = workReportDAO.findByCode(code);
Set<OrderElement> orderElements = sumChargedEffortDAO
.getOrderElementsToRecalculateTimsheetDates(null,
workReport.getWorkReportLines());
sumChargedEffortDAO
.updateRelatedSumChargedEffortWithDeletedWorkReportLineSet(workReport
.getWorkReportLines());
workReportDAO.remove(workReport.getId());
sumChargedEffortDAO.recalculateTimesheetDates(orderElements);
return Response.ok().build();
} catch (InstanceNotFoundException e) {
return Response.status(Status.NOT_FOUND).build();
@ -157,10 +170,14 @@ public class WorkReportServiceREST extends
public Response removeWorkReportLine(@PathParam("code") String code) {
try {
WorkReportLine workReportLine = workReportLineDAO.findByCode(code);
Set<OrderElement> orderElements = sumChargedEffortDAO
.getOrderElementsToRecalculateTimsheetDates(null,
Collections.singleton(workReportLine));
sumChargedEffortDAO
.updateRelatedSumChargedEffortWithDeletedWorkReportLineSet(new HashSet<WorkReportLine>(
Arrays.asList(workReportLine)));
workReportLineDAO.remove(workReportLine.getId());
sumChargedEffortDAO.recalculateTimesheetDates(orderElements);
return Response.ok().build();
} catch (InstanceNotFoundException e) {
return Response.status(Status.NOT_FOUND).build();