Now project's details view shares the state with gantt and resource load

OrderModel references and uses the PlanningState. The changes in the
WBS are seen in the gantt view even if the WBS is not saved.

FEA: ItEr75S11PreventLooseChanges
This commit is contained in:
Óscar González Fernández 2011-09-25 13:35:23 +02:00
parent 4720094b96
commit 1be5121b12
20 changed files with 430 additions and 533 deletions

View file

@ -306,6 +306,7 @@ public class FunctionalityExposedForExtensions<T> implements IContext<T> {
diagramGraph.remove(task);
task.removed();
planner.removeTask(task);
adapter.doRemovalOf(mapper.findAssociatedDomainObject(task));
mapper.remove(domainObject);
return position;
}

View file

@ -67,4 +67,9 @@ public class AutoAdapter implements
//do nothing
}
@Override
public void doRemovalOf(ITaskFundamentalProperties object) {
// do nothing
}
}

View file

@ -37,6 +37,8 @@ public interface IAdapterToTaskFundamentalProperties<T> {
public List<DomainDependency<T>> getIncomingDependencies(T object);
public void doRemovalOf(T object);
public boolean canAddDependency(DomainDependency<T> dependency);
public void addDependency(DomainDependency<T> dependency);

View file

@ -27,6 +27,7 @@ import java.lang.reflect.ParameterizedType;
import java.util.List;
import org.apache.commons.lang.Validate;
import org.hibernate.Hibernate;
import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
@ -107,7 +108,9 @@ public class GenericDAOHibernate<E extends BaseEntity,
}
public void reattachUnmodifiedEntity(E entity) {
if (Hibernate.isInitialized(entity) && entity.isNewObject()) {
return;
}
getSession().lock(entity, LockMode.NONE);
}

View file

@ -393,15 +393,23 @@ public abstract class OrderElement extends IntegrationEntity implements
private void removeTaskSource(List<TaskSourceSynchronization> result) {
removeChildrenTaskSource(result);
if (getTaskSource() != null) {
if (getOnDBTaskSource() != null) {
result.add(taskSourceRemoval());
}
}
private TaskSource getOnDBTaskSource() {
OrderVersion version = getCurrentSchedulingData()
.getOriginOrderVersion();
SchedulingDataForVersion schedulingDataForVersion = schedulingDatasForVersion
.get(version);
return schedulingDataForVersion.getTaskSource();
}
private TaskSourceSynchronization taskSourceRemoval() {
Validate.notNull(getTaskSource());
Validate.notNull(getOnDBTaskSource());
TaskSourceSynchronization result = TaskSource
.mustRemove(getTaskSource());
.mustRemove(getOnDBTaskSource());
getCurrentSchedulingData().taskSourceRemovalRequested();
return result;
}

View file

@ -135,7 +135,6 @@ public class HoursCostCalculator implements ICostCalculator {
}
SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
List<WorkReportLine> workReportLines = workReportLineDAO
.findByOrderElementAndChildren(task.getOrderElement());

View file

@ -270,6 +270,12 @@ public class TaskGroup extends TaskElement {
planningData.update(criticalPathJustTasks);
}
public void dontPoseAsTransientPlanningData() {
if (planningData != null) {
planningData.dontPoseAsTransientObjectAnymore();
}
}
/**
* For a root task, retrieves the progress selected by the progressType
* If there's not progressType, return taskElement.advancePercentage

View file

@ -21,6 +21,7 @@
package org.navalplanner.business.workreports.daos;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
@ -80,6 +81,9 @@ public class WorkReportLineDAO extends IntegrationEntityDAO<WorkReportLine>
@Override
public List<WorkReportLine> findByOrderElementAndChildren(
OrderElement orderElement) {
if (orderElement.isNewObject()) {
return new ArrayList<WorkReportLine>();
}
return findByOrderElementAndChildren(orderElement, false);
}

View file

@ -37,7 +37,9 @@ import org.navalplanner.business.resources.entities.CriterionType;
import org.navalplanner.business.templates.entities.OrderElementTemplate;
import org.navalplanner.business.templates.entities.OrderTemplate;
import org.navalplanner.web.common.IIntegrationEntityModel;
import org.navalplanner.web.planner.order.PlanningStateCreator.PlanningState;
import org.zkoss.ganttz.IPredicate;
import org.zkoss.zk.ui.Desktop;
/**
* Contract for {@link OrderModel}<br />
@ -81,15 +83,15 @@ public interface IOrderModel extends IIntegrationEntityModel {
List<Order> getOrders();
void initEdit(Order order);
void initEdit(Order order, Desktop desktop);
void prepareForCreate();
void prepareForCreate(Desktop desktop);
void remove(Order order);
void save() throws ValidationException;
void setOrder(Order order);
void setPlanningState(PlanningState planningState);
List<BaseCalendar> getBaseCalendars();
@ -101,7 +103,7 @@ public interface IOrderModel extends IIntegrationEntityModel {
boolean isCodeAutogenerated();
void prepareCreationFrom(OrderTemplate template);
void prepareCreationFrom(OrderTemplate template, Desktop desktop);
OrderElement createFrom(OrderLineGroup parent, OrderElementTemplate template);

View file

@ -72,6 +72,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.zkoss.ganttz.util.LongOperationFeedback;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Desktop;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.WrongValueException;
import org.zkoss.zk.ui.event.Event;
@ -181,7 +182,7 @@ public class OrderCRUDController extends GenericForwardComposer {
public void showCreateFormFromTemplate(OrderTemplate template) {
showOrderElementFilter();
showCreateButtons(false);
orderModel.prepareCreationFrom(template);
orderModel.prepareCreationFrom(template, getDesktop());
prepareEditWindow();
showEditWindow(_("Create project from Template"));
}
@ -948,7 +949,7 @@ public class OrderCRUDController extends GenericForwardComposer {
}
}
orderModel.initEdit(order);
orderModel.initEdit(order, getDesktop());
if (editWindow != null) {
resetTabControllers();
setupOrderElementTreeController();
@ -960,6 +961,10 @@ public class OrderCRUDController extends GenericForwardComposer {
showEditWindow(_("Edit project"));
}
private Desktop getDesktop() {
return listWindow.getDesktop();
}
private void resetTabControllers() {
orderElementTreeController = null;
assignedHoursController = null;
@ -1062,12 +1067,12 @@ public class OrderCRUDController extends GenericForwardComposer {
}
public void goToCreateForm() {
prepareForCreate();
prepareForCreate(getDesktop());
getCreationPopup().showWindow(this, null);
}
public void prepareForCreate() {
orderModel.prepareForCreate();
public void prepareForCreate(Desktop desktop) {
orderModel.prepareForCreate(desktop);
}
private void editNewCreatedOrder() {

View file

@ -38,11 +38,7 @@ import org.navalplanner.business.advance.entities.DirectAdvanceAssignment;
import org.navalplanner.business.advance.entities.IndirectAdvanceAssignment;
import org.navalplanner.business.calendars.daos.IBaseCalendarDAO;
import org.navalplanner.business.calendars.entities.BaseCalendar;
import org.navalplanner.business.common.BaseEntity;
import org.navalplanner.business.common.IAdHocTransactionService;
import org.navalplanner.business.common.IOnTransaction;
import org.navalplanner.business.common.IntegrationEntity;
import org.navalplanner.business.common.Registry;
import org.navalplanner.business.common.daos.IConfigurationDAO;
import org.navalplanner.business.common.entities.Configuration;
import org.navalplanner.business.common.entities.EntityNameEnum;
@ -58,12 +54,6 @@ 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.OrderLineGroup;
import org.navalplanner.business.orders.entities.TaskSource;
import org.navalplanner.business.orders.entities.TaskSource.IOptionalPersistence;
import org.navalplanner.business.orders.entities.TaskSource.TaskSourceSynchronization;
import org.navalplanner.business.planner.daos.ITaskElementDAO;
import org.navalplanner.business.planner.daos.ITaskSourceDAO;
import org.navalplanner.business.planner.entities.TaskElement;
import org.navalplanner.business.qualityforms.daos.IQualityFormDAO;
import org.navalplanner.business.qualityforms.entities.QualityForm;
import org.navalplanner.business.requirements.entities.DirectCriterionRequirement;
@ -88,7 +78,10 @@ import org.navalplanner.business.users.entities.UserRole;
import org.navalplanner.web.common.IntegrationEntityModel;
import org.navalplanner.web.common.concurrentdetection.OnConcurrentModification;
import org.navalplanner.web.orders.labels.LabelsOnConversation;
import org.navalplanner.web.planner.order.ISaveCommand.IBeforeSaveActions;
import org.navalplanner.web.planner.order.PlanningStateCreator;
import org.navalplanner.web.planner.order.PlanningStateCreator.IActionsOnRetrieval;
import org.navalplanner.web.planner.order.PlanningStateCreator.PlanningState;
import org.navalplanner.web.security.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
@ -96,7 +89,7 @@ import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.zkoss.ganttz.IPredicate;
import org.zkoss.zul.Messagebox;
import org.zkoss.zk.ui.Desktop;
/**
* Model for UI operations related to {@link Order}. <br />
@ -109,9 +102,6 @@ import org.zkoss.zul.Messagebox;
@OnConcurrentModification(goToPage = "/planner/index.zul;orders_list")
public class OrderModel extends IntegrationEntityModel implements IOrderModel {
@Autowired
private PlanningStateCreator planningStateCreator;
@Autowired
private ICriterionTypeDAO criterionTypeDAO;
@ -125,7 +115,10 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
@Autowired
private IOrderDAO orderDAO;
private Order order;
@Autowired
private PlanningStateCreator planningStateCreator;
private PlanningState planningState;
private OrderElementTreeModel orderElementTreeModel;
@ -147,12 +140,6 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
@Autowired
private IOrderElementTemplateDAO templateDAO;
@Autowired
private ITaskSourceDAO taskSourceDAO;
@Autowired
private ITaskElementDAO taskElementDAO;
@Autowired
private IBaseCalendarDAO baseCalendarDAO;
@ -173,9 +160,6 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
@Autowired
private IScenarioManager scenarioManager;
@Autowired
private IAdHocTransactionService transactionService;
@Autowired
private IOrderVersionDAO orderVersionDAO;
@ -196,12 +180,6 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
private QualityFormsOnConversation qualityFormsOnConversation;
private Scenario currentScenario;
private List<Scenario> derivedScenarios = new ArrayList<Scenario>();
private boolean isEditing = false;
private QualityFormsOnConversation getQualityFormsOnConversation() {
if (qualityFormsOnConversation == null) {
qualityFormsOnConversation = new QualityFormsOnConversation(
@ -278,43 +256,29 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
@Override
@Transactional(readOnly = true)
public void initEdit(Order order) {
Validate.notNull(order);
isEditing = true;
public void initEdit(Order orderToEdit, Desktop desktop) {
Validate.notNull(orderToEdit);
loadNeededDataForConversation();
this.order = getFromDB(order);
this.orderElementTreeModel = new OrderElementTreeModel(this.order);
forceLoadAdvanceAssignmentsAndMeasurements(this.order);
forceLoadCriterionRequirements(this.order);
this.planningState = planningStateCreator.retrieveOrCreate(desktop,
orderToEdit, new IActionsOnRetrieval() {
@Override
public void onRetrieval(PlanningState planningState) {
planningState.reattach();
}
});
Order order = this.planningState.getOrder();
this.orderElementTreeModel = new OrderElementTreeModel(order);
forceLoadAdvanceAssignmentsAndMeasurements(order);
forceLoadCriterionRequirements(order);
forceLoadCalendar(this.getCalendar());
forceLoadCustomer(this.order.getCustomer());
forceLoadLabels(this.order);
forceLoadMaterialAssignments(this.order);
forceLoadTaskQualityForms(this.order);
currentScenario = scenarioManager.getCurrent();
this.order.useSchedulingDataFor(currentScenario);
loadTasks(this.order);
forceLoadCustomer(order.getCustomer());
forceLoadLabels(order);
forceLoadMaterialAssignments(order);
forceLoadTaskQualityForms(order);
initOldCodes();
}
private void loadTasks(Order order) {
TaskSource taskSource = order.getTaskSource();
if (taskSource == null) {
return;
}
loadTask(taskSource.getTask());
}
private void loadTask(TaskElement task) {
task.getDependenciesWithThisDestination().size();
task.getDependenciesWithThisOrigin().size();
if (!task.isLeaf()) {
for (TaskElement each : task.getChildren()) {
loadTask(each);
}
}
}
private void forceLoadLabels(OrderElement orderElement) {
orderElement.getLabels().size();
for (OrderElement each : orderElement.getChildren()) {
@ -405,54 +369,37 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
}
}
private Order getFromDB(Order order) {
try {
return orderDAO.find(order.getId());
} catch (InstanceNotFoundException e) {
throw new RuntimeException(e);
}
}
@Override
@Transactional(readOnly = true)
public void prepareForCreate() {
public void prepareForCreate(Desktop desktop) {
loadNeededDataForConversation();
this.order = Order.create();
this.planningState = planningStateCreator.createOn(desktop,
Order.create());
initializeOrder();
initializeCalendar();
currentScenario = scenarioManager.getCurrent();
addOrderToCurrentScenario(this.order);
this.order.useSchedulingDataFor(currentScenario);
}
private OrderVersion addOrderToCurrentScenario(Order order) {
OrderVersion orderVersion = currentScenario.addOrder(order);
order.setVersionForScenario(currentScenario, orderVersion);
derivedScenarios = scenarioDAO.getDerivedScenarios(currentScenario);
for (Scenario scenario : derivedScenarios) {
scenario.addOrder(order, orderVersion);
}
return orderVersion;
}
private void initializeOrder() {
this.orderElementTreeModel = new OrderElementTreeModel(this.order);
this.order.setInitDate(new Date());
Order order = planningState.getOrder();
this.orderElementTreeModel = new OrderElementTreeModel(
order);
order.setInitDate(new Date());
setDefaultCode();
this.order.setCodeAutogenerated(true);
order.setCodeAutogenerated(true);
}
private void initializeCalendar() {
this.order.setCalendar(getDefaultCalendar());
this.planningState.getOrder().setCalendar(getDefaultCalendar());
}
@Override
@Transactional(readOnly = true)
public void prepareCreationFrom(OrderTemplate template) {
public void prepareCreationFrom(OrderTemplate template, Desktop desktop) {
loadNeededDataForConversation();
this.order = createOrderFrom((OrderTemplate) templateDAO
Order order = createOrderFrom((OrderTemplate) templateDAO
.findExistingEntity(template.getId()));
forceLoadAdvanceAssignmentsAndMeasurements(this.order);
planningStateCreator.createOn(desktop, order);
forceLoadAdvanceAssignmentsAndMeasurements(planningState.getOrder());
initializeOrder();
}
@ -489,251 +436,24 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
@Override
public void save() throws ValidationException {
final boolean newOrderVersionNeeded = isEditing
&& order.hasSchedulingDataBeingModified()
&& !order.isUsingTheOwnerScenario();
if (!newOrderVersionNeeded || userAcceptsCreateANewOrderVersion()) {
transactionService.runOnTransaction(new IOnTransaction<Void>() {
@Override
public Void execute() {
saveOnTransaction(newOrderVersionNeeded);
return null;
}
});
dontPoseAsTransientObjectAnymore(order);
}
}
this.planningState.getSaveCommand().save(new IBeforeSaveActions() {
private void dontPoseAsTransientObjectAnymore(Collection<? extends BaseEntity> collection) {
for(BaseEntity entity : collection) {
entity.dontPoseAsTransientObjectAnymore();
}
}
private void dontPoseAsTransientObjectAnymore(OrderElement orderElement) {
orderElement.dontPoseAsTransientObjectAnymore();
dontPoseAsTransientObjectAnymore(orderElement.getTaskSourcesFromBottomToTop());
dontPoseAsTransientObjectAnymore(orderElement.getSchedulingDatasForVersionFromBottomToTop());
dontPoseAsTransientObjectAnymore(orderElement.getDirectAdvanceAssignments());
dontPoseAsTransientObjectAnymore(getAllMeasurements(orderElement.getDirectAdvanceAssignments()));
dontPoseAsTransientObjectAnymore(orderElement
.getIndirectAdvanceAssignments());
dontPoseAsTransientObjectAnymore(orderElement
.getCriterionRequirements());
dontPoseAsTransientObjectAnymore(orderElement.getLabels());
dontPoseAsTransientObjectAnymore(orderElement.getTaskElements());
dontPoseAsTransientObjectAnymore(orderElement.getHoursGroups());
dontPoseAsTransientObjectAnymore(orderElement.getTaskQualityForms());
dontPoseAsTransientObjectAnymore(orderElement
.getAllMaterialAssignments());
for (HoursGroup hoursGroup : orderElement.getHoursGroups()) {
dontPoseAsTransientObjectAnymore(hoursGroup
.getCriterionRequirements());
}
for(OrderElement child : orderElement.getAllChildren()) {
child.dontPoseAsTransientObjectAnymore();
dontPoseAsTransientObjectAnymore(child);
}
}
private List<AdvanceMeasurement> getAllMeasurements(
Collection<? extends DirectAdvanceAssignment> assignments) {
List<AdvanceMeasurement> result = new ArrayList<AdvanceMeasurement>();
for (DirectAdvanceAssignment each : assignments) {
result.addAll(each.getAdvanceMeasurements());
}
return result;
}
private void saveOnTransaction(boolean newOrderVersionNeeded) {
checkConstraintOrderUniqueCode(order);
checkConstraintHoursGroupUniqueCode(order);
reattachCalendar();
reattachCriterions();
reattachTasksForTasksSources();
if (order.isCodeAutogenerated()) {
generateOrderElementCodes();
}
calculateAndSetTotalHours();
orderDAO.save(order);
reattachCurrentTaskSources();
if (newOrderVersionNeeded) {
OrderVersion newVersion = OrderVersion
.createInitialVersion(currentScenario);
reattachAllTaskSources();
order.writeSchedulingDataChangesTo(currentScenario, newVersion);
createAndSaveNewOrderVersion(scenarioManager.getCurrent(),
newVersion);
synchronizeWithSchedule(order,
TaskSource.persistButDontRemoveTaskSources(taskSourceDAO));
order.writeSchedulingDataChanges();
} else {
OrderVersion orderVersion = order.getCurrentVersionInfo()
.getOrderVersion();
orderVersion.savingThroughOwner();
synchronizeWithSchedule(order,
TaskSource.persistTaskSources(taskSourceDAO));
order.writeSchedulingDataChanges();
}
saveDerivedScenarios();
deleteOrderElementWithoutParent();
}
private static void checkConstraintOrderUniqueCode(OrderElement order) {
OrderElement repeatedOrder;
// Check no code is repeated in this order
if (order instanceof OrderLineGroup) {
repeatedOrder = ((OrderLineGroup) order).findRepeatedOrderCode();
if (repeatedOrder != null) {
throw new ValidationException(_(
"Repeated Project code {0} in Project {1}",
repeatedOrder.getCode(), repeatedOrder.getName()));
@Override
public void doActions() {
reattachCalendar();
reattachCriterions();
}
}
// Check no code is repeated within the DB
repeatedOrder = Registry.getOrderElementDAO()
.findRepeatedOrderCodeInDB(order);
if (repeatedOrder != null) {
throw new ValidationException(_(
"Repeated Project code {0} in Project {1}",
repeatedOrder.getCode(), repeatedOrder.getName()));
}
});
}
private static void checkConstraintHoursGroupUniqueCode(Order order) {
HoursGroup repeatedHoursGroup;
if (order instanceof OrderLineGroup) {
repeatedHoursGroup = ((OrderLineGroup) order)
.findRepeatedHoursGroupCode();
if (repeatedHoursGroup != null) {
throw new ValidationException(_(
"Repeated Hours Group code {0} in Project {1}",
repeatedHoursGroup.getCode(), repeatedHoursGroup
.getParentOrderLine().getName()));
}
}
repeatedHoursGroup = Registry.getHoursGroupDAO()
.findRepeatedHoursGroupCodeInDB(order.getHoursGroups());
if (repeatedHoursGroup != null) {
throw new ValidationException(_(
"Repeated Hours Group code {0} in Project {1}",
repeatedHoursGroup.getCode(), repeatedHoursGroup
.getParentOrderLine().getName()));
}
}
private void createAndSaveNewOrderVersion(Scenario currentScenario,
OrderVersion newOrderVersion) {
OrderVersion previousOrderVersion = currentScenario
.getOrderVersion(order);
currentScenario.setOrderVersion(order, newOrderVersion);
scenarioDAO.updateDerivedScenariosWithNewVersion(previousOrderVersion,
order, currentScenario, newOrderVersion);
}
private boolean userAcceptsCreateANewOrderVersion() {
try {
int status = Messagebox
.show(
_("Confirm creating a new project version for this scenario and derived. Are you sure?"),
_("New project version"), Messagebox.OK
| Messagebox.CANCEL, Messagebox.QUESTION);
return (Messagebox.OK == status);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private void saveDerivedScenarios() {
if (derivedScenarios != null) {
for (Scenario scenario : derivedScenarios) {
scenarioDAO.save(scenario);
}
}
}
private void calculateAndSetTotalHours() {
Integer result = 0;
for (OrderElement orderElement : order.getChildren()) {
result = result + orderElement.getWorkHours();
}
order.setTotalHours(result);
}
private void generateOrderElementCodes() {
order.generateOrderElementCodes(getNumberOfDigitsCode());
}
private void reattachCurrentTaskSources() {
for (TaskSource each : order.getTaskSourcesFromBottomToTop()) {
taskSourceDAO.reattach(each);
}
}
private void reattachCalendar() {
if (order.getCalendar() == null) {
if (planningState.getOrder().getCalendar() == null) {
return;
}
BaseCalendar calendar = order.getCalendar();
BaseCalendar calendar = planningState.getOrder().getCalendar();
baseCalendarDAO.reattachUnmodifiedEntity(calendar);
}
private void reattachAllTaskSources() {
// avoid LazyInitializationException for when doing
// removePredecessorsDayAssignmentsFor
for (TaskSource each : order
.getAllScenariosTaskSourcesFromBottomToTop()) {
taskSourceDAO.reattach(each);
}
}
private void reattachTasksForTasksSources() {
for (TaskSource each : order.getTaskSourcesFromBottomToTop()) {
each.reattachTask(taskElementDAO);
}
}
private void synchronizeWithSchedule(OrderElement orderElement,
IOptionalPersistence persistence) {
List<TaskSourceSynchronization> synchronizationsNeeded = orderElement
.calculateSynchronizationsNeeded();
for (TaskSourceSynchronization each : synchronizationsNeeded) {
each.apply(persistence);
}
}
private void deleteOrderElementWithoutParent() throws ValidationException {
List<OrderElement> listToBeRemoved = orderElementDAO
.findWithoutParent();
for (OrderElement orderElement : listToBeRemoved) {
if (!(orderElement instanceof Order)) {
try {
// checking no work reports for that orderElement
if (!orderElementDAO
.isAlreadyInUseThisOrAnyOfItsChildren(orderElement)) {
orderElementDAO.remove(orderElement.getId());
}
} catch (InstanceNotFoundException e) {
throw new ValidationException(_(""
+ "It not could remove the task "
+ orderElement.getName()));
}
}
}
}
private void reattachCriterions() {
for (List<Criterion> list : mapCriterions.values()) {
for (Criterion criterion : list) {
@ -744,7 +464,7 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
@Override
public OrderLineGroup getOrder() {
return order;
return planningState.getOrder();
}
@Override
@ -817,7 +537,8 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
IPredicate predicate) {
// Iterate through orderElements from order
List<OrderElement> orderElements = new ArrayList<OrderElement>();
for (OrderElement orderElement : order.getAllOrderElements()) {
for (OrderElement orderElement : planningState.getOrder()
.getAllOrderElements()) {
if (!orderElement.isNewObject()) {
reattachOrderElement(orderElement);
}
@ -828,7 +549,8 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
}
}
// Return list of filtered elements
return new OrderElementTreeModel(order, orderElements);
return new OrderElementTreeModel(planningState.getOrder(),
orderElements);
}
private void reattachLabels() {
@ -853,8 +575,8 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
}
@Override
public void setOrder(Order order) {
this.order = order;
public void setPlanningState(PlanningState planningState) {
this.planningState = planningState;
}
@Override
@ -882,25 +604,25 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
@Override
public BaseCalendar getCalendar() {
if (order == null) {
if (planningState == null) {
return null;
}
return order.getCalendar();
return planningState.getOrder().getCalendar();
}
@Override
public void setCalendar(BaseCalendar calendar) {
if (order != null) {
order.setCalendar(calendar);
if (planningState != null) {
planningState.getOrder().setCalendar(calendar);
}
}
@Override
public boolean isCodeAutogenerated() {
if (order == null) {
if (planningState == null) {
return false;
}
return order.isCodeAutogenerated();
return planningState.getOrder().isCodeAutogenerated();
}
@Override
@ -1079,15 +801,15 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
@Override
public Set<IntegrationEntity> getChildren() {
Set<IntegrationEntity> children = new HashSet<IntegrationEntity>();
if (order != null) {
children.addAll(order.getOrderElements());
if (planningState != null) {
children.addAll(planningState.getOrder().getOrderElements());
}
return children;
}
@Override
public IntegrationEntity getCurrentEntity() {
return this.order;
return this.planningState.getOrder();
}
}

View file

@ -1133,5 +1133,14 @@ public class TaskElementAdapter {
type);
}
@Override
public void doRemovalOf(TaskElement taskElement) {
taskElement.detach();
TaskGroup parent = taskElement.getParent();
if (parent != null) {
parent.remove(taskElement);
}
}
}
}

View file

@ -27,7 +27,6 @@ import org.navalplanner.business.planner.daos.ITaskElementDAO;
import org.navalplanner.business.planner.entities.TaskElement;
import org.navalplanner.business.planner.entities.TaskGroup;
import org.navalplanner.business.planner.entities.TaskMilestone;
import org.navalplanner.web.planner.order.PlanningStateCreator.PlanningState;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
@ -44,16 +43,9 @@ import org.zkoss.ganttz.extensions.IContextWithPlannerTask;
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class AddMilestoneCommand implements IAddMilestoneCommand {
private PlanningState planningState;
@Autowired
private ITaskElementDAO taskElementDAO;
@Override
public void setState(PlanningState planningState) {
this.planningState = planningState;
}
@Override
@Transactional(readOnly = true)
public void doAction(IContextWithPlannerTask<TaskElement> context,
@ -68,8 +60,6 @@ public class AddMilestoneCommand implements IAddMilestoneCommand {
TaskGroup parent = task.getParent();
parent.addTaskElement(insertAt, milestone);
context.add(taskPosition.sameLevelAt(insertAt), milestone);
planningState.added(milestone.getParent());
}
@Override

View file

@ -22,7 +22,6 @@
package org.navalplanner.web.planner.milestone;
import org.navalplanner.business.planner.entities.TaskElement;
import org.navalplanner.web.planner.order.PlanningStateCreator.PlanningState;
import org.zkoss.ganttz.extensions.ICommandOnTask;
/**
@ -31,5 +30,4 @@ import org.zkoss.ganttz.extensions.ICommandOnTask;
*/
public interface IAddMilestoneCommand extends ICommandOnTask<TaskElement> {
public void setState(PlanningState planningState);
}

View file

@ -21,6 +21,7 @@
package org.navalplanner.web.planner.order;
import org.navalplanner.business.common.exceptions.ValidationException;
import org.navalplanner.business.planner.entities.TaskElement;
import org.zkoss.ganttz.extensions.ICommand;
@ -40,5 +41,17 @@ public interface ISaveCommand extends ICommand<TaskElement> {
public String getImage();
public interface IBeforeSaveActions {
public void doActions();
}
public interface IAfterSaveActions {
public void doActions();
}
void save(IBeforeSaveActions beforeSaveActions);
void save(IBeforeSaveActions beforeSaveActions,
IAfterSaveActions afterSaveActions) throws ValidationException;
}

View file

@ -973,7 +973,6 @@ public class OrderPlanningModel implements IOrderPlanningModel {
}
private IAddMilestoneCommand buildMilestoneCommand() {
addMilestoneCommand.setState(planningState);
return addMilestoneCommand;
}

View file

@ -21,21 +21,20 @@ package org.navalplanner.web.planner.order;
import static org.navalplanner.business.planner.entities.TaskElement.justTasks;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.Validate;
import org.hibernate.Hibernate;
import org.joda.time.LocalDate;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.common.exceptions.ValidationException;
import org.navalplanner.business.common.daos.IEntitySequenceDAO;
import org.navalplanner.business.common.entities.EntityNameEnum;
import org.navalplanner.business.labels.entities.Label;
import org.navalplanner.business.orders.daos.IOrderDAO;
import org.navalplanner.business.orders.daos.IOrderElementDAO;
import org.navalplanner.business.orders.entities.Order;
import org.navalplanner.business.orders.entities.OrderElement;
import org.navalplanner.business.orders.entities.TaskSource;
@ -45,6 +44,7 @@ import org.navalplanner.business.planner.daos.ITaskElementDAO;
import org.navalplanner.business.planner.daos.ITaskSourceDAO;
import org.navalplanner.business.planner.entities.AssignmentFunction;
import org.navalplanner.business.planner.entities.DayAssignment;
import org.navalplanner.business.planner.entities.Dependency;
import org.navalplanner.business.planner.entities.DerivedAllocation;
import org.navalplanner.business.planner.entities.GenericResourceAllocation;
import org.navalplanner.business.planner.entities.ResourceAllocation;
@ -131,15 +131,15 @@ public class PlanningStateCreator {
@Autowired
private IOrderDAO orderDAO;
@Autowired
private IOrderElementDAO orderElementDAO;
@Autowired
private IScenarioDAO scenarioDAO;
@Autowired
private ITaskSourceDAO taskSourceDAO;
@Autowired
private IEntitySequenceDAO entitySequenceDAO;
@Autowired
private TaskElementAdapter taskElementAdapterCreator;
@ -159,6 +159,22 @@ public class PlanningStateCreator {
public void onRetrieval(PlanningState planningState);
}
public PlanningState createOn(Desktop desktop, Order order) {
Validate.notNull(desktop);
Validate.notNull(order);
setupScenario(order);
PlanningState result = createPlanning(order);
desktop.setAttribute(ATTRIBUTE_NAME, result);
return result;
}
void setupScenario(Order order) {
Scenario currentScenario = scenarioManager.getCurrent();
OrderVersion orderVersion = currentScenario.addOrder(order);
order.setVersionForScenario(currentScenario, orderVersion);
order.useSchedulingDataFor(currentScenario);
}
public PlanningState retrieveOrCreate(Desktop desktop, Order order) {
return retrieveOrCreate(desktop, order, null);
}
@ -168,13 +184,15 @@ public class PlanningStateCreator {
Object existent = desktop.getAttribute(ATTRIBUTE_NAME);
if (existent instanceof PlanningState) {
PlanningState result = (PlanningState) existent;
result.onRetrieval();
if (onRetrieval != null) {
onRetrieval.onRetrieval(result);
if (ObjectUtils.equals(order.getId(), result.getOrder().getId())) {
result.onRetrieval();
if (onRetrieval != null) {
onRetrieval.onRetrieval(result);
}
return result;
}
return result;
}
PlanningState result = createInitialPlanning(reload(order));
PlanningState result = createPlanning(reload(order));
desktop.setAttribute(ATTRIBUTE_NAME, result);
return result;
}
@ -185,20 +203,20 @@ public class PlanningStateCreator {
return result;
}
private PlanningState createInitialPlanning(Order orderReloaded) {
private PlanningState createPlanning(Order orderReloaded) {
Scenario currentScenario = scenarioManager.getCurrent();
final List<Resource> allResources = resourceDAO.list(Resource.class);
criterionDAO.list(Criterion.class);
TaskGroup rootTask = orderReloaded.getAssociatedTaskElement();
if (rootTask != null) {
forceLoadOfChildren(Arrays.asList(rootTask));
forceLoadOf(rootTask);
forceLoadDayAssignments(orderReloaded.getResources());
forceLoadOfDepedenciesCollections(rootTask);
}
PlanningState result = new PlanningState(orderReloaded, allResources,
currentScenario);
forceLoadOfDependenciesCollections(result.getInitial());
forceLoadOfWorkingHours(result.getInitial());
forceLoadOfLabels(result.getInitial());
return result;
@ -210,18 +228,17 @@ public class PlanningStateCreator {
}
}
private void forceLoadOfChildren(Collection<? extends TaskElement> initial) {
for (TaskElement each : initial) {
forceLoadOfDataAssociatedTo(each);
if (each instanceof TaskGroup) {
findChildrenWithQueryToAvoidProxies((TaskGroup) each);
List<TaskElement> children = each.getChildren();
forceLoadOfChildren(children);
private void forceLoadOf(TaskElement taskElement) {
forceLoadOfDataAssociatedTo(taskElement);
if (taskElement instanceof TaskGroup) {
findChildrenWithQueryToAvoidProxies((TaskGroup) taskElement);
for (TaskElement each : taskElement.getChildren()) {
forceLoadOf(each);
}
}
}
private static void forceLoadOfDataAssociatedTo(TaskElement each) {
private void forceLoadOfDataAssociatedTo(TaskElement each) {
forceLoadOfResourceAllocationsResourcesAndAssignmentFunction(each);
forceLoadOfCriterions(each);
if (each.getCalendar() != null) {
@ -272,6 +289,7 @@ public class PlanningStateCreator {
private void findChildrenWithQueryToAvoidProxies(TaskGroup group) {
for (TaskElement eachTask : taskDAO.findChildrenOf(group)) {
Hibernate.initialize(eachTask);
eachTask.getParent().getName();
}
}
@ -302,19 +320,19 @@ public class PlanningStateCreator {
}
}
private void forceLoadOfDependenciesCollections(
Collection<? extends TaskElement> elements) {
for (TaskElement task : elements) {
forceLoadOfDepedenciesCollections(task);
if (!task.isLeaf()) {
forceLoadOfDependenciesCollections(task.getChildren());
}
private void forceLoadOfDepedenciesCollections(TaskElement task) {
loadDependencies(task.getDependenciesWithThisOrigin());
loadDependencies(task.getDependenciesWithThisDestination());
for (TaskElement each : task.getChildren()) {
forceLoadOfDepedenciesCollections(each);
}
}
private void forceLoadOfDepedenciesCollections(TaskElement task) {
task.getDependenciesWithThisOrigin().size();
task.getDependenciesWithThisDestination().size();
private void loadDependencies(Set<Dependency> dependenciesWithThisOrigin) {
for (Dependency each : dependenciesWithThisOrigin) {
each.getOrigin().getName();
each.getDestination().getName();
}
}
private void forceLoadOfWorkingHours(List<TaskElement> initial) {
@ -547,14 +565,10 @@ public class PlanningStateCreator {
private ArrayList<TaskElement> initial;
private Set<TaskElement> toSave;
private Set<TaskElement> toRemove = new HashSet<TaskElement>();
private Set<Resource> resources = new HashSet<Resource>();
private TaskGroup rootTask;
private final IScenarioInfo scenarioInfo;
public PlanningState(Order order,
@ -562,7 +576,7 @@ public class PlanningStateCreator {
Scenario currentScenario) {
Validate.notNull(order);
this.order = order;
rebuildTasksState(order);
rebuildTasksState();
this.scenarioInfo = new ChangeScenarioInfoOnSave(
buildScenarioInfo(order), order);
this.resources = OrderPlanningModel
@ -574,24 +588,26 @@ public class PlanningStateCreator {
cachedConfiguration = null;
cachedCommand = null;
synchronizeScheduling();
rebuildTasksState(order);
generateOrderElementCodes();
rebuildTasksState();
}
void synchronizeScheduling() {
synchronizeWithSchedule(order, TaskSource.dontPersist());
}
private void rebuildTasksState(Order order) {
this.rootTask = order.getAssociatedTaskElement();
if (this.rootTask == null) {
private void generateOrderElementCodes() {
order.generateOrderElementCodes(entitySequenceDAO
.getNumberOfDigitsCode(EntityNameEnum.ORDER));
}
private void rebuildTasksState() {
TaskGroup rootTask = getRootTask();
if (rootTask == null) {
this.initial = new ArrayList<TaskElement>();
this.toSave = new HashSet<TaskElement>();
} else {
this.initial = new ArrayList<TaskElement>(
rootTask.getChildren());
this.toSave = rootTask == null ? new HashSet<TaskElement>()
: new HashSet<TaskElement>(rootTask.getChildren());
this.toSave.removeAll(this.toRemove);
}
}
@ -600,7 +616,6 @@ public class PlanningStateCreator {
Scenario currentScenario = getCurrentScenario();
for (Resource each : resources) {
each.useScenario(currentScenario);
}
}
@ -609,7 +624,7 @@ public class PlanningStateCreator {
}
public boolean isEmpty() {
return rootTask == null;
return getRootTask() == null;
}
/**
@ -663,18 +678,14 @@ public class PlanningStateCreator {
getConfiguration());
}
public Collection<? extends TaskElement> getTasksToSave() {
return Collections.unmodifiableCollection(toSave);
}
public List<TaskElement> getInitial() {
return new ArrayList<TaskElement>(initial);
}
public List<Task> getAllTasks() {
List<Task> result = new ArrayList<Task>();
if (rootTask != null) {
findTasks(rootTask, result);
if (getRootTask() != null) {
findTasks(getRootTask(), result);
}
return result;
}
@ -750,7 +761,6 @@ public class PlanningStateCreator {
if (!isTopLevel(taskElement)) {
return;
}
toSave.remove(taskElement);
toRemove.add(taskElement);
}
@ -758,19 +768,11 @@ public class PlanningStateCreator {
if (taskElement instanceof TaskMilestone) {
return true;
}
return taskElement.getParent() == rootTask;
}
public void added(TaskElement taskElement) {
if (!isTopLevel(taskElement)) {
return;
}
toRemove.remove(taskElement);
toSave.add(taskElement);
return taskElement.getParent() == getRootTask();
}
public TaskGroup getRootTask() {
return rootTask;
return order.getAssociatedTaskElement();
}
public IScenarioInfo getScenarioInfo() {
@ -789,49 +791,7 @@ public class PlanningStateCreator {
}
public void synchronizeTrees() {
orderDAO.save(order);
scenarioInfo.saveVersioningInfo();
reattachCurrentTaskSources();
saveDerivedScenarios();
deleteOrderElementWithoutParent();
}
private void reattachCurrentTaskSources() {
for (TaskSource each : order.getTaskSourcesFromBottomToTop()) {
taskSourceDAO.reattach(each);
}
}
private void saveDerivedScenarios() {
List<Scenario> derivedScenarios = scenarioDAO
.getDerivedScenarios(getCurrentScenario());
for (Scenario scenario : derivedScenarios) {
scenario.addOrder(order, order.getCurrentOrderVersion());
}
}
private void deleteOrderElementWithoutParent()
throws ValidationException {
List<OrderElement> listToBeRemoved = orderElementDAO
.findWithoutParent();
for (OrderElement orderElement : listToBeRemoved) {
if (!(orderElement instanceof Order)) {
tryToRemove(orderElement);
}
}
}
private void tryToRemove(OrderElement orderElement) {
// checking no work reports for that orderElement
if (orderElementDAO
.isAlreadyInUseThisOrAnyOfItsChildren(orderElement)) {
return;
}
try {
orderElementDAO.remove(orderElement.getId());
} catch (InstanceNotFoundException e) {
throw new RuntimeException(e);
}
}
public List<Resource> getResourcesRelatedWithAllocations() {

View file

@ -40,10 +40,17 @@ import org.navalplanner.business.advance.entities.DirectAdvanceAssignment;
import org.navalplanner.business.common.BaseEntity;
import org.navalplanner.business.common.IAdHocTransactionService;
import org.navalplanner.business.common.IOnTransaction;
import org.navalplanner.business.common.Registry;
import org.navalplanner.business.common.daos.IEntitySequenceDAO;
import org.navalplanner.business.common.entities.EntityNameEnum;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.common.exceptions.ValidationException;
import org.navalplanner.business.orders.daos.IOrderDAO;
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.OrderLineGroup;
import org.navalplanner.business.planner.daos.IConsolidationDAO;
import org.navalplanner.business.planner.daos.ISubcontractedTaskDataDAO;
import org.navalplanner.business.planner.daos.ITaskElementDAO;
@ -66,6 +73,8 @@ import org.navalplanner.business.planner.entities.consolidations.NonCalculatedCo
import org.navalplanner.business.planner.limiting.daos.ILimitingResourceQueueDependencyDAO;
import org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueDependency;
import org.navalplanner.business.planner.limiting.entities.LimitingResourceQueueElement;
import org.navalplanner.business.scenarios.daos.IScenarioDAO;
import org.navalplanner.business.scenarios.entities.Scenario;
import org.navalplanner.web.common.concurrentdetection.ConcurrentModificationHandling;
import org.navalplanner.web.planner.TaskElementAdapter;
import org.navalplanner.web.planner.order.PlanningStateCreator.PlanningState;
@ -81,6 +90,7 @@ import org.zkoss.ganttz.data.DependencyType.Point;
import org.zkoss.ganttz.data.GanttDate;
import org.zkoss.ganttz.data.constraint.Constraint;
import org.zkoss.ganttz.extensions.IContext;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zul.Messagebox;
/**
@ -104,10 +114,9 @@ public class SaveCommandBuilder {
PlannerConfiguration<TaskElement> plannerConfiguration) {
SaveCommand result = new SaveCommand(planningState,
plannerConfiguration);
return ConcurrentModificationHandling.addHandling(
"/planner/index.zul;company_scheduling",
ISaveCommand.class, result);
"/planner/index.zul;company_scheduling", ISaveCommand.class,
result);
}
public static void dontPoseAsTransientAndChildrenObjects(
@ -153,9 +162,21 @@ public class SaveCommandBuilder {
@Autowired
private IConsolidationDAO consolidationDAO;
@Autowired
private IEntitySequenceDAO entitySequenceDAO;
@Autowired
private ITaskElementDAO taskElementDAO;
@Autowired
private IOrderDAO orderDAO;
@Autowired
private IOrderElementDAO orderElementDAO;
@Autowired
private IScenarioDAO scenarioDAO;
@Autowired
private ITaskSourceDAO taskSourceDAO;
@ -204,11 +225,32 @@ public class SaveCommandBuilder {
@Override
public void doAction(IContext<TaskElement> context) {
save(null, new IAfterSaveActions() {
@Override
public void doActions() {
notifyUserThatSavingIsDone();
}
});
}
@Override
public void save(IBeforeSaveActions beforeSaveActions) {
save(beforeSaveActions, null);
}
@Override
public void save(final IBeforeSaveActions beforeSaveActions,
IAfterSaveActions afterSaveActions)
throws ValidationException {
if (state.getScenarioInfo().isUsingTheOwnerScenario()
|| userAcceptsCreateANewOrderVersion()) {
transactionService.runOnTransaction(new IOnTransaction<Void>() {
@Override
public Void execute() {
if (beforeSaveActions != null) {
beforeSaveActions.doActions();
}
doTheSaving();
return null;
}
@ -216,7 +258,9 @@ public class SaveCommandBuilder {
dontPoseAsTransientObjectAnymore(state.getOrder());
state.getScenarioInfo().afterCommit();
fireAfterSave();
notifyUserThatSavingIsDone();
if (afterSaveActions != null) {
afterSaveActions.doActions();
}
}
}
@ -227,6 +271,10 @@ public class SaveCommandBuilder {
}
private void notifyUserThatSavingIsDone() {
if (Executions.getCurrent() == null) {
// test environment
return;
}
try {
Messagebox.show(_("Scheduling saved"), _("Information"),
Messagebox.OK, Messagebox.INFORMATION);
@ -236,8 +284,28 @@ public class SaveCommandBuilder {
}
private void doTheSaving() {
Order order = state.getOrder();
if (order.isCodeAutogenerated()) {
generateOrderElementCodes(order);
}
calculateAndSetTotalHours(order);
checkConstraintOrderUniqueCode(order);
checkConstraintHoursGroupUniqueCode(order);
state.synchronizeTrees();
saveTasksToSave();
TaskGroup rootTask = state.getRootTask();
if (rootTask != null) {
// This reattachment is needed to ensure that the root task in
// the state is the one associated to the transaction's session.
// Otherwise if some order element has been removed, when doing
// the deletes on cascade a new root task is fetched causing a
// NonUniqueObjectException later
taskElementDAO.reattach(rootTask);
}
orderDAO.save(order);
saveDerivedScenarios(order);
deleteOrderElementWithoutParent(order);
updateTasksRelatedData();
removeTasksToRemove();
loadDataAccessedWithNotPosedAsTransient(state.getOrder());
if (state.getRootTask() != null) {
@ -246,6 +314,99 @@ public class SaveCommandBuilder {
subcontractedTaskDataDAO.removeOrphanedSubcontractedTaskData();
}
private void generateOrderElementCodes(Order order) {
order.generateOrderElementCodes(entitySequenceDAO
.getNumberOfDigitsCode(EntityNameEnum.ORDER));
}
private void calculateAndSetTotalHours(Order order) {
int result = 0;
for (OrderElement orderElement : order.getChildren()) {
result = result + orderElement.getWorkHours();
}
order.setTotalHours(result);
}
private void checkConstraintOrderUniqueCode(OrderElement order) {
OrderElement repeatedOrder;
// Check no code is repeated in this order
if (order instanceof OrderLineGroup) {
repeatedOrder = ((OrderLineGroup) order)
.findRepeatedOrderCode();
if (repeatedOrder != null) {
throw new ValidationException(_(
"Repeated Project code {0} in Project {1}",
repeatedOrder.getCode(), repeatedOrder.getName()));
}
}
// Check no code is repeated within the DB
repeatedOrder = Registry.getOrderElementDAO()
.findRepeatedOrderCodeInDB(order);
if (repeatedOrder != null) {
throw new ValidationException(_(
"Repeated Project code {0} in Project {1}",
repeatedOrder.getCode(), repeatedOrder.getName()));
}
}
private void checkConstraintHoursGroupUniqueCode(Order order) {
HoursGroup repeatedHoursGroup;
if (order instanceof OrderLineGroup) {
repeatedHoursGroup = ((OrderLineGroup) order)
.findRepeatedHoursGroupCode();
if (repeatedHoursGroup != null) {
throw new ValidationException(_(
"Repeated Hours Group code {0} in Project {1}",
repeatedHoursGroup.getCode(), repeatedHoursGroup
.getParentOrderLine().getName()));
}
}
repeatedHoursGroup = Registry.getHoursGroupDAO()
.findRepeatedHoursGroupCodeInDB(order.getHoursGroups());
if (repeatedHoursGroup != null) {
throw new ValidationException(_(
"Repeated Hours Group code {0} in Project {1}",
repeatedHoursGroup.getCode(), repeatedHoursGroup
.getParentOrderLine().getName()));
}
}
private void saveDerivedScenarios(Order order) {
List<Scenario> derivedScenarios = scenarioDAO
.getDerivedScenarios(state.getCurrentScenario());
for (Scenario scenario : derivedScenarios) {
scenario.addOrder(order, order.getCurrentOrderVersion());
}
}
private void deleteOrderElementWithoutParent(Order order)
throws ValidationException {
List<OrderElement> listToBeRemoved = orderElementDAO
.findWithoutParent();
for (OrderElement orderElement : listToBeRemoved) {
if (!(orderElement instanceof Order)) {
tryToRemove(orderElement);
}
}
}
private void tryToRemove(OrderElement orderElement) {
// checking no work reports for that orderElement
if (orderElementDAO
.isAlreadyInUseThisOrAnyOfItsChildren(orderElement)) {
return;
}
try {
orderElementDAO.remove(orderElement.getId());
} catch (InstanceNotFoundException e) {
throw new RuntimeException(e);
}
}
private void removeTasksToRemove() {
for (TaskElement taskElement : state.getToRemove()) {
if (taskElementDAO.exists(taskElement.getId())) {
@ -260,35 +421,35 @@ public class SaveCommandBuilder {
}
}
private void saveTasksToSave() {
for (TaskElement taskElement : state.getTasksToSave()) {
private void updateTasksRelatedData() {
TaskGroup rootTask = state.getRootTask();
if (rootTask == null) {
return;
}
for (TaskElement taskElement : rootTask.getChildren()) {
removeEmptyConsolidation(taskElement);
updateLimitingResourceQueueElementDates(taskElement);
taskElementDAO.save(taskElement);
if (taskElement.getTaskSource() != null
&& taskElement.getTaskSource().isNewObject()) {
saveTaskSources(taskElement);
}
updateLimitingQueueDependencies(taskElement);
}
saveRootTaskIfNecessary();
saveRootTask();
}
private void saveRootTaskIfNecessary() {
if (!state.getTasksToSave().isEmpty()) {
TaskGroup rootTask = state.getRootTask();
updateRootTaskPosition(rootTask);
taskElementDAO.save(rootTask);
}
private void saveRootTask() {
TaskGroup rootTask = state.getRootTask();
updateRootTaskPosition(rootTask);
taskElementDAO.save(rootTask);
}
private void updateRootTaskPosition(TaskGroup rootTask) {
final Date min = minDate(state.getTasksToSave());
final Date min = minDate(rootTask.getChildren());
if (min != null) {
rootTask.setStartDate(min);
}
final Date max = maxDate(state.getTasksToSave());
final Date max = maxDate(rootTask.getChildren());
if (max != null) {
rootTask.setEndDate(max);
}
@ -661,6 +822,9 @@ public class SaveCommandBuilder {
if (taskElement instanceof Task) {
dontPoseAsTransient(((Task) taskElement).getConsolidation());
}
if (taskElement instanceof TaskGroup) {
((TaskGroup) taskElement).dontPoseAsTransientPlanningData();
}
}
private void dontPoseAsTransient(Consolidation consolidation) {

View file

@ -412,7 +412,7 @@ public class MultipleTabsPlannerController implements Composer,
}
public void goToCreateForm() {
orderCRUDController.prepareForCreate();
orderCRUDController.prepareForCreate(tabsSwitcher.getDesktop());
orderCRUDController.getCreationPopup().showWindow(orderCRUDController,
this);

View file

@ -35,11 +35,13 @@ import static org.navalplanner.web.test.WebappGlobalNames.WEBAPP_SPRING_SECURITY
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import javax.annotation.Resource;
import org.easymock.EasyMock;
import org.hibernate.SessionFactory;
import org.junit.Before;
import org.junit.Ignore;
@ -71,12 +73,15 @@ import org.navalplanner.business.resources.entities.ResourceEnum;
import org.navalplanner.business.scenarios.IScenarioManager;
import org.navalplanner.business.scenarios.entities.OrderVersion;
import org.navalplanner.business.scenarios.entities.Scenario;
import org.navalplanner.web.planner.order.PlanningStateCreator;
import org.navalplanner.web.planner.order.PlanningStateCreator.PlanningState;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.NotTransactional;
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;
import org.zkoss.zk.ui.Desktop;
/**
* Tests for {@link OrderModel}. <br />
@ -108,9 +113,6 @@ public class OrderModelTest {
@Resource
private IDataBootstrap scenariosBootstrap;
@Autowired
private IScenarioManager scenarioManager;
@Before
public void loadRequiredaData() {
defaultAdvanceTypesBootstrapListener.loadRequiredData();
@ -152,8 +154,27 @@ public class OrderModelTest {
@Autowired
private IExternalCompanyDAO externalCompanyDAO;
@Autowired
private PlanningStateCreator planningStateCreator;
private Criterion criterion;
private Desktop mockDesktop() {
return EasyMock.createNiceMock(Desktop.class);
}
private PlanningState createPlanningStateFor(final Order newOrder) {
return adHocTransaction
.runOnAnotherReadOnlyTransaction(new IOnTransaction<PlanningState>() {
@Override
public PlanningState execute() {
return planningStateCreator.createOn(mockDesktop(),
newOrder);
}
});
}
private Order createValidOrder() {
Order order = Order.create();
order.setDescription("description");
@ -161,10 +182,9 @@ public class OrderModelTest {
order.setName("name");
order.setResponsible("responsible");
order.setCode("code-" + UUID.randomUUID());
order.setCalendar(configurationDAO.getConfiguration()
order.setCalendar(configurationDAO
.getConfigurationWithReadOnlyTransaction()
.getDefaultCalendar());
setupVersionUsing(scenarioManager, order);
order.useSchedulingDataFor(scenarioManager.getCurrent());
return order;
}
@ -187,7 +207,7 @@ public class OrderModelTest {
public void testCreation() throws ValidationException {
Order order = createValidOrder();
order.setCustomer(createValidExternalCompany());
orderModel.setOrder(order);
orderModel.setPlanningState(createPlanningStateFor(order));
orderModel.save();
assertTrue(orderDAO.exists(order.getId()));
}
@ -197,7 +217,7 @@ public class OrderModelTest {
.runOnAnotherReadOnlyTransaction(new IOnTransaction<Void>() {
@Override
public Void execute() {
orderModel.prepareForCreate();
orderModel.prepareForCreate(mockDesktop());
return null;
}
});
@ -249,7 +269,7 @@ public class OrderModelTest {
List<Order> list = orderModel.getOrders();
Order order = createValidOrder();
order.setCustomer(createValidExternalCompany());
orderModel.setOrder(order);
orderModel.setPlanningState(createPlanningStateFor(order));
orderModel.save();
assertThat(orderModel.getOrders().size(), equalTo(list.size() + 1));
}
@ -257,7 +277,7 @@ public class OrderModelTest {
@Test
public void testRemove() {
Order order = createValidOrder();
orderModel.setOrder(order);
orderModel.setPlanningState(createPlanningStateFor(order));
orderModel.save();
assertTrue(orderDAO.exists(order.getId()));
orderModel.remove(order);
@ -269,14 +289,14 @@ public class OrderModelTest {
throws ValidationException {
Order order = createValidOrder();
order.setDeadline(year(0));
orderModel.setOrder(order);
orderModel.setPlanningState(createPlanningStateFor(order));
orderModel.save();
}
@Test
public void testFind() throws InstanceNotFoundException {
Order order = createValidOrder();
orderModel.setOrder(order);
orderModel.setPlanningState(createPlanningStateFor(order));
orderModel.save();
assertThat(orderDAO.find(order.getId()), notNullValue());
}
@ -285,12 +305,8 @@ public class OrderModelTest {
@NotTransactional
public void testOrderPreserved() throws ValidationException,
InstanceNotFoundException {
final Order order = adHocTransaction.runOnReadOnlyTransaction(new IOnTransaction<Order>() {
@Override
public Order execute() {
return createValidOrder();
}
});
final Order order = createValidOrder();
orderModel.setPlanningState(createPlanningStateFor(order));
final OrderElement[] containers = new OrderLineGroup[10];
for (int i = 0; i < containers.length; i++) {
containers[i] = adHocTransaction
@ -319,7 +335,6 @@ public class OrderModelTest {
orderLineGroup.add(leaf);
}
orderModel.setOrder(order);
orderModel.save();
adHocTransaction.runOnTransaction(new IOnTransaction<Void>() {
@ -376,13 +391,8 @@ public class OrderModelTest {
@Test
@NotTransactional
public void testAddingOrderElement() {
final Order order = adHocTransaction
.runOnReadOnlyTransaction(new IOnTransaction<Order>() {
@Override
public Order execute() {
return createValidOrder();
}
});
final Order order = createValidOrder();
orderModel.setPlanningState(createPlanningStateFor(order));
OrderLineGroup container = adHocTransaction
.runOnTransaction(new IOnTransaction<OrderLineGroup>() {
@Override
@ -401,7 +411,6 @@ public class OrderModelTest {
hoursGroup.setCode("hoursGroupName");
hoursGroup.setWorkingHours(3);
leaf.addHoursGroup(hoursGroup);
orderModel.setOrder(order);
orderModel.save();
adHocTransaction.runOnTransaction(new IOnTransaction<Void>() {
@ -432,13 +441,8 @@ public class OrderModelTest {
@NotTransactional
public void testManyToManyHoursGroupCriterionMapping() {
givenCriterion();
final Order order = adHocTransaction
.runOnReadOnlyTransaction(new IOnTransaction<Order>() {
@Override
public Order execute() {
return createValidOrder();
}
});
final Order order = createValidOrder();
orderModel.setPlanningState(createPlanningStateFor(order));
OrderLine orderLine = OrderLine.create();
orderLine.setName("Order element");
@ -461,7 +465,6 @@ public class OrderModelTest {
hoursGroup.addCriterionRequirement(criterionRequirement);
//hoursGroup2.addCriterionRequirement(criterionRequirement);
orderModel.setOrder(order);
orderModel.save();
adHocTransaction.runOnTransaction(new IOnTransaction<Void>() {
@ -523,14 +526,18 @@ public class OrderModelTest {
@Test(expected = ValidationException.class)
public void testAtLeastOneHoursGroup() {
Order order = createValidOrder();
orderModel.setPlanningState(createPlanningStateFor(order));
OrderLine orderLine = OrderLine.create();
orderLine.setName("foo");
orderLine.setCode("000000000");
orderLine.setName(randomize("foo" + new Random().nextInt()));
orderLine.setCode(randomize("000000000"));
order.add(orderLine);
orderModel.setOrder(order);
orderModel.save();
}
private static String randomize(String original) {
return original + new Random().nextInt();
}
}