diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/FunctionalityExposedForExtensions.java b/ganttzk/src/main/java/org/zkoss/ganttz/FunctionalityExposedForExtensions.java index 9649c7fc6..8d3f23753 100644 --- a/ganttzk/src/main/java/org/zkoss/ganttz/FunctionalityExposedForExtensions.java +++ b/ganttzk/src/main/java/org/zkoss/ganttz/FunctionalityExposedForExtensions.java @@ -306,6 +306,7 @@ public class FunctionalityExposedForExtensions implements IContext { diagramGraph.remove(task); task.removed(); planner.removeTask(task); + adapter.doRemovalOf(mapper.findAssociatedDomainObject(task)); mapper.remove(domainObject); return position; } diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/adapters/AutoAdapter.java b/ganttzk/src/main/java/org/zkoss/ganttz/adapters/AutoAdapter.java index f944250e5..b4343f6c5 100644 --- a/ganttzk/src/main/java/org/zkoss/ganttz/adapters/AutoAdapter.java +++ b/ganttzk/src/main/java/org/zkoss/ganttz/adapters/AutoAdapter.java @@ -67,4 +67,9 @@ public class AutoAdapter implements //do nothing } + @Override + public void doRemovalOf(ITaskFundamentalProperties object) { + // do nothing + } + } diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/adapters/IAdapterToTaskFundamentalProperties.java b/ganttzk/src/main/java/org/zkoss/ganttz/adapters/IAdapterToTaskFundamentalProperties.java index 23d257def..5823f3c92 100644 --- a/ganttzk/src/main/java/org/zkoss/ganttz/adapters/IAdapterToTaskFundamentalProperties.java +++ b/ganttzk/src/main/java/org/zkoss/ganttz/adapters/IAdapterToTaskFundamentalProperties.java @@ -37,6 +37,8 @@ public interface IAdapterToTaskFundamentalProperties { public List> getIncomingDependencies(T object); + public void doRemovalOf(T object); + public boolean canAddDependency(DomainDependency dependency); public void addDependency(DomainDependency dependency); diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/common/daos/GenericDAOHibernate.java b/navalplanner-business/src/main/java/org/navalplanner/business/common/daos/GenericDAOHibernate.java index bba34374d..d6ad74521 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/common/daos/GenericDAOHibernate.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/common/daos/GenericDAOHibernate.java @@ -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 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; } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/HoursCostCalculator.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/HoursCostCalculator.java index 0fdd459f9..b5c597ba0 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/HoursCostCalculator.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/HoursCostCalculator.java @@ -135,7 +135,6 @@ public class HoursCostCalculator implements ICostCalculator { } SortedMap result = new TreeMap(); - List workReportLines = workReportLineDAO .findByOrderElementAndChildren(task.getOrderElement()); diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/TaskGroup.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/TaskGroup.java index 23e7b5c82..58b1f07a9 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/TaskGroup.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/TaskGroup.java @@ -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 diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/workreports/daos/WorkReportLineDAO.java b/navalplanner-business/src/main/java/org/navalplanner/business/workreports/daos/WorkReportLineDAO.java index f16371a37..d1c28707d 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/workreports/daos/WorkReportLineDAO.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/workreports/daos/WorkReportLineDAO.java @@ -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 @Override public List findByOrderElementAndChildren( OrderElement orderElement) { + if (orderElement.isNewObject()) { + return new ArrayList(); + } return findByOrderElementAndChildren(orderElement, false); } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/IOrderModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/IOrderModel.java index 2324b5741..c91e7b6b9 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/IOrderModel.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/IOrderModel.java @@ -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}
@@ -81,15 +83,15 @@ public interface IOrderModel extends IIntegrationEntityModel { List 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 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); diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderCRUDController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderCRUDController.java index ad1db0cf3..0a38cb965 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderCRUDController.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderCRUDController.java @@ -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() { diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderModel.java index 5698c4bd0..81ff1d806 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderModel.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/orders/OrderModel.java @@ -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}.
@@ -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 derivedScenarios = new ArrayList(); - - 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() { - @Override - public Void execute() { - saveOnTransaction(newOrderVersionNeeded); - return null; - } - }); - dontPoseAsTransientObjectAnymore(order); - } - } + this.planningState.getSaveCommand().save(new IBeforeSaveActions() { - private void dontPoseAsTransientObjectAnymore(Collection 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 getAllMeasurements( - Collection assignments) { - List result = new ArrayList(); - 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 synchronizationsNeeded = orderElement - .calculateSynchronizationsNeeded(); - for (TaskSourceSynchronization each : synchronizationsNeeded) { - each.apply(persistence); - } - } - - private void deleteOrderElementWithoutParent() throws ValidationException { - List 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 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 orderElements = new ArrayList(); - 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 getChildren() { Set children = new HashSet(); - 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(); } } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/TaskElementAdapter.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/TaskElementAdapter.java index e1f9cce60..6f57dccac 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/TaskElementAdapter.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/TaskElementAdapter.java @@ -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); + } + } + } } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/milestone/AddMilestoneCommand.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/milestone/AddMilestoneCommand.java index ecb93b54e..c805f7b3a 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/milestone/AddMilestoneCommand.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/milestone/AddMilestoneCommand.java @@ -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 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 diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/milestone/IAddMilestoneCommand.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/milestone/IAddMilestoneCommand.java index 41e5a0940..0b1fb536a 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/milestone/IAddMilestoneCommand.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/milestone/IAddMilestoneCommand.java @@ -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 { - public void setState(PlanningState planningState); } \ No newline at end of file diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/ISaveCommand.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/ISaveCommand.java index 0b34a8c0f..766969146 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/ISaveCommand.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/ISaveCommand.java @@ -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 { 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; } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java index 4c1f34628..e2c4a925d 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java @@ -973,7 +973,6 @@ public class OrderPlanningModel implements IOrderPlanningModel { } private IAddMilestoneCommand buildMilestoneCommand() { - addMilestoneCommand.setState(planningState); return addMilestoneCommand; } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/PlanningStateCreator.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/PlanningStateCreator.java index be863669f..3f2137475 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/PlanningStateCreator.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/PlanningStateCreator.java @@ -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 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 initial) { - for (TaskElement each : initial) { - forceLoadOfDataAssociatedTo(each); - if (each instanceof TaskGroup) { - findChildrenWithQueryToAvoidProxies((TaskGroup) each); - List 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 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 dependenciesWithThisOrigin) { + for (Dependency each : dependenciesWithThisOrigin) { + each.getOrigin().getName(); + each.getDestination().getName(); + } } private void forceLoadOfWorkingHours(List initial) { @@ -547,14 +565,10 @@ public class PlanningStateCreator { private ArrayList initial; - private Set toSave; - private Set toRemove = new HashSet(); private Set resources = new HashSet(); - 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(); - this.toSave = new HashSet(); } else { this.initial = new ArrayList( rootTask.getChildren()); - this.toSave = rootTask == null ? new HashSet() - : new HashSet(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 getTasksToSave() { - return Collections.unmodifiableCollection(toSave); - } - public List getInitial() { return new ArrayList(initial); } public List getAllTasks() { List result = new ArrayList(); - 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 derivedScenarios = scenarioDAO - .getDerivedScenarios(getCurrentScenario()); - for (Scenario scenario : derivedScenarios) { - scenario.addOrder(order, order.getCurrentOrderVersion()); - } - } - - private void deleteOrderElementWithoutParent() - throws ValidationException { - List 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 getResourcesRelatedWithAllocations() { diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/SaveCommandBuilder.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/SaveCommandBuilder.java index e08d194a1..b69e14bf6 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/SaveCommandBuilder.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/SaveCommandBuilder.java @@ -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 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 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() { @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 derivedScenarios = scenarioDAO + .getDerivedScenarios(state.getCurrentScenario()); + for (Scenario scenario : derivedScenarios) { + scenario.addOrder(order, order.getCurrentOrderVersion()); + } + } + + private void deleteOrderElementWithoutParent(Order order) + throws ValidationException { + List 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) { diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/tabs/MultipleTabsPlannerController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/tabs/MultipleTabsPlannerController.java index 738cf05bf..8b2eaeec4 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/tabs/MultipleTabsPlannerController.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/tabs/MultipleTabsPlannerController.java @@ -412,7 +412,7 @@ public class MultipleTabsPlannerController implements Composer, } public void goToCreateForm() { - orderCRUDController.prepareForCreate(); + orderCRUDController.prepareForCreate(tabsSwitcher.getDesktop()); orderCRUDController.getCreationPopup().showWindow(orderCRUDController, this); diff --git a/navalplanner-webapp/src/test/java/org/navalplanner/web/orders/OrderModelTest.java b/navalplanner-webapp/src/test/java/org/navalplanner/web/orders/OrderModelTest.java index 30f92e709..0664e2875 100644 --- a/navalplanner-webapp/src/test/java/org/navalplanner/web/orders/OrderModelTest.java +++ b/navalplanner-webapp/src/test/java/org/navalplanner/web/orders/OrderModelTest.java @@ -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}.
@@ -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() { + + @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() { @Override public Void execute() { - orderModel.prepareForCreate(); + orderModel.prepareForCreate(mockDesktop()); return null; } }); @@ -249,7 +269,7 @@ public class OrderModelTest { List 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() { - @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() { @@ -376,13 +391,8 @@ public class OrderModelTest { @Test @NotTransactional public void testAddingOrderElement() { - final Order order = adHocTransaction - .runOnReadOnlyTransaction(new IOnTransaction() { - @Override - public Order execute() { - return createValidOrder(); - } - }); + final Order order = createValidOrder(); + orderModel.setPlanningState(createPlanningStateFor(order)); OrderLineGroup container = adHocTransaction .runOnTransaction(new IOnTransaction() { @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() { @@ -432,13 +441,8 @@ public class OrderModelTest { @NotTransactional public void testManyToManyHoursGroupCriterionMapping() { givenCriterion(); - final Order order = adHocTransaction - .runOnReadOnlyTransaction(new IOnTransaction() { - @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() { @@ -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(); + } + }