diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/common/daos/impl/GenericDaoHibernate.java b/navalplanner-business/src/main/java/org/navalplanner/business/common/daos/impl/GenericDaoHibernate.java
index 3ce190c4c..b2697b07f 100644
--- a/navalplanner-business/src/main/java/org/navalplanner/business/common/daos/impl/GenericDaoHibernate.java
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/common/daos/impl/GenericDaoHibernate.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
+import org.apache.commons.lang.Validate;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
@@ -19,19 +20,19 @@ import org.springframework.orm.hibernate3.SessionFactoryUtils;
* An implementation of IGenericDao based on Hibernate's native
* API. Concrete DAOs must extend directly from this class. This constraint is
* imposed by the constructor of this class that must infer the type of the
- * entity from the declaration of the concrete DAO.
- *
+ * entity from the declaration of the concrete DAO.
+ *
* This class autowires a SessionFactory bean and allows to
* implement DAOs with Hibernate's native API. Subclasses access Hibernate's
* Session by calling on getSession() method.
* Operations must be implemented by catching HibernateException
* and rethrowing it by using convertHibernateAccessException()
* method. See source code of this class for an example.
- *
* @author Fernando Bellas Permuy
- *
- * @param Entity class
- * @param Primary key class
+ * @param
+ * Entity class
+ * @param
+ * Primary key class
*/
public class GenericDaoHibernate implements
IGenericDao {
@@ -47,6 +48,11 @@ public class GenericDaoHibernate implements
.getGenericSuperclass()).getActualTypeArguments()[0];
}
+ public GenericDaoHibernate(Class entityClass) {
+ Validate.notNull(entityClass);
+ this.entityClass = entityClass;
+ }
+
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/common/exceptions/ValidationException.java b/navalplanner-business/src/main/java/org/navalplanner/business/common/exceptions/ValidationException.java
index 77ff08314..3ea2fa958 100644
--- a/navalplanner-business/src/main/java/org/navalplanner/business/common/exceptions/ValidationException.java
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/common/exceptions/ValidationException.java
@@ -40,4 +40,8 @@ public class ValidationException extends Exception {
this.invalidValues = invalidValues;
}
+ public ValidationException(String message) {
+ this(new InvalidValue[] {}, message);
+ }
+
}
diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/ProjectWork.java b/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/ProjectWork.java
new file mode 100644
index 000000000..c71c7d372
--- /dev/null
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/workorders/entities/ProjectWork.java
@@ -0,0 +1,97 @@
+package org.navalplanner.business.workorders.entities;
+
+import java.util.Date;
+
+import org.hibernate.validator.NotEmpty;
+import org.hibernate.validator.NotNull;
+
+/**
+ * It represents a project with its related information.
+ * @author Óscar González Fernández
+ */
+public class ProjectWork {
+
+ private static Date copy(Date date) {
+ return date != null ? new Date(date.getTime()) : date;
+ }
+
+ private Long id;
+
+ private Long version;
+
+ @NotEmpty
+ private String name;
+
+ @NotNull
+ private Date initDate;
+
+ private Date endDate;
+
+ private String description;
+
+ private String responsible;
+
+ // TODO turn into a many to one relationship when Customer entity is defined
+ private String customer;
+
+ public Long getId() {
+ return id;
+ }
+
+ public Long getVersion() {
+ return version;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Date getInitDate() {
+ return copy(initDate);
+ }
+
+ public void setInitDate(Date initDate) {
+ this.initDate = initDate;
+ }
+
+ public Date getEndDate() {
+ return copy(endDate);
+ }
+
+ public void setEndDate(Date endDate) {
+ this.endDate = endDate;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getResponsible() {
+ return responsible;
+ }
+
+ public void setResponsible(String responsible) {
+ this.responsible = responsible;
+ }
+
+ public String getCustomer() {
+ return customer;
+ }
+
+ public void setCustomer(String customer) {
+ this.customer = customer;
+ }
+
+ public boolean isEndDateBeforeStart() {
+ return endDate != null && endDate.before(initDate);
+ }
+
+}
diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/workorders/services/IProjectWorkService.java b/navalplanner-business/src/main/java/org/navalplanner/business/workorders/services/IProjectWorkService.java
new file mode 100644
index 000000000..6e7db2ba3
--- /dev/null
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/workorders/services/IProjectWorkService.java
@@ -0,0 +1,25 @@
+package org.navalplanner.business.workorders.services;
+
+import java.util.List;
+
+import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
+import org.navalplanner.business.common.exceptions.ValidationException;
+import org.navalplanner.business.workorders.entities.ProjectWork;
+
+/**
+ * Management of {@link ProjectWork}
+ * @author Óscar González Fernández
+ */
+public interface IProjectWorkService {
+
+ void save(ProjectWork projectWork) throws ValidationException;
+
+ boolean exists(ProjectWork projectWork);
+
+ List getProjectWorks();
+
+ void remove(ProjectWork projectWork) throws InstanceNotFoundException;
+
+ ProjectWork find(Long workerId) throws InstanceNotFoundException;
+
+}
diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/workorders/services/ProjectWorkService.java b/navalplanner-business/src/main/java/org/navalplanner/business/workorders/services/ProjectWorkService.java
new file mode 100644
index 000000000..650b00515
--- /dev/null
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/workorders/services/ProjectWorkService.java
@@ -0,0 +1,73 @@
+package org.navalplanner.business.workorders.services;
+
+import java.util.List;
+
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.navalplanner.business.common.daos.impl.GenericDaoHibernate;
+import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
+import org.navalplanner.business.common.exceptions.ValidationException;
+import org.navalplanner.business.workorders.entities.ProjectWork;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Default implementation of {@link IProjectWorkService}
+ * @author Óscar González Fernández
+ */
+@Component
+@Scope(BeanDefinition.SCOPE_SINGLETON)
+@Transactional
+public class ProjectWorkService implements IProjectWorkService {
+
+ @Autowired
+ private SessionFactory sessionFactory;
+
+ /*
+ * Because the dao for project work doesn't have special needs, it's not
+ * created an interface for defining its contract
+ */
+
+ private GenericDaoHibernate dao = new GenericDaoHibernate() {
+
+ @Override
+ protected Session getSession() {
+ return sessionFactory.getCurrentSession();
+ }
+ };
+
+ @Override
+ @Transactional(readOnly = true)
+ public boolean exists(ProjectWork projectWork) {
+ return dao.exists(projectWork.getId());
+ }
+
+ @Override
+ public void save(ProjectWork projectWork) throws ValidationException {
+ if (projectWork.isEndDateBeforeStart()) {
+ throw new ValidationException("endDate must be after startDate");
+ }
+ dao.save(projectWork);
+ }
+
+ @Override
+ public List getProjectWorks() {
+ return dao.list(ProjectWork.class);
+ }
+
+ @Override
+ public ProjectWork find(Long projectWorkId)
+ throws InstanceNotFoundException {
+ return dao.find(projectWorkId);
+ }
+
+ @Override
+ public void remove(ProjectWork projectWork)
+ throws InstanceNotFoundException {
+ dao.remove(projectWork.getId());
+ }
+
+}
diff --git a/navalplanner-business/src/main/resources/navalplanner-business-spring-config.xml b/navalplanner-business/src/main/resources/navalplanner-business-spring-config.xml
index 6ffb33648..760900fee 100644
--- a/navalplanner-business/src/main/resources/navalplanner-business-spring-config.xml
+++ b/navalplanner-business/src/main/resources/navalplanner-business-spring-config.xml
@@ -23,6 +23,9 @@
org/navalplanner/business/resources/entities/Resources.hbm.xml
+
+ org/navalplanner/business/resources/entities/WorkOrders.hbm.xml
+
diff --git a/navalplanner-business/src/main/resources/org/navalplanner/business/resources/entities/WorkOrders.hbm.xml b/navalplanner-business/src/main/resources/org/navalplanner/business/resources/entities/WorkOrders.hbm.xml
new file mode 100644
index 000000000..f6c5dab2b
--- /dev/null
+++ b/navalplanner-business/src/main/resources/org/navalplanner/business/resources/entities/WorkOrders.hbm.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/navalplanner-business/src/test/java/org/navalplanner/business/test/workorders/services/ProjectWorkServiceTest.java b/navalplanner-business/src/test/java/org/navalplanner/business/test/workorders/services/ProjectWorkServiceTest.java
new file mode 100644
index 000000000..27f9e7f36
--- /dev/null
+++ b/navalplanner-business/src/test/java/org/navalplanner/business/test/workorders/services/ProjectWorkServiceTest.java
@@ -0,0 +1,86 @@
+package org.navalplanner.business.test.workorders.services;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.navalplanner.business.common.exceptions.ValidationException;
+import org.navalplanner.business.test.resources.daos.CriterionSatisfactionDAOTest;
+import org.navalplanner.business.workorders.entities.ProjectWork;
+import org.navalplanner.business.workorders.services.IProjectWorkService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.transaction.annotation.Transactional;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.navalplanner.business.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_FILE;
+import static org.navalplanner.business.test.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_TEST_FILE;
+
+/**
+ * Tests for {@link ProjectWork}.
+ * @author Óscar González Fernández
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(locations = { BUSINESS_SPRING_CONFIG_FILE,
+ BUSINESS_SPRING_CONFIG_TEST_FILE })
+@Transactional
+public class ProjectWorkServiceTest {
+
+ private static ProjectWork createValidProjectWork() {
+ ProjectWork projectWork = new ProjectWork();
+ projectWork.setDescription("description");
+ projectWork.setCustomer("blabla");
+ projectWork.setInitDate(CriterionSatisfactionDAOTest.year(2000));
+ projectWork.setName("name");
+ projectWork.setResponsible("responsible");
+ return projectWork;
+ }
+
+ @Autowired
+ private IProjectWorkService projectWorkService;
+
+ @Test
+ public void testCreation() throws ValidationException {
+ ProjectWork projectWork = createValidProjectWork();
+ projectWorkService.save(projectWork);
+ assertTrue(projectWorkService.exists(projectWork));
+ }
+
+ @Test
+ public void testListing() throws Exception {
+ List list = projectWorkService.getProjectWorks();
+ projectWorkService.save(createValidProjectWork());
+ assertThat(projectWorkService.getProjectWorks().size(), equalTo(list
+ .size() + 1));
+ }
+
+ @Test
+ public void testRemove() throws Exception {
+ ProjectWork projectWork = createValidProjectWork();
+ projectWorkService.save(projectWork);
+ assertTrue(projectWorkService.exists(projectWork));
+ projectWorkService.remove(projectWork);
+ assertFalse(projectWorkService.exists(projectWork));
+ }
+
+ @Test(expected = ValidationException.class)
+ public void shouldSendValidationExceptionIfEndDateIsBeforeThanStartingDate()
+ throws ValidationException {
+ ProjectWork projectWork = createValidProjectWork();
+ projectWork.setEndDate(CriterionSatisfactionDAOTest.year(0));
+ projectWorkService.save(projectWork);
+ }
+
+ @Test
+ public void testFind() throws Exception {
+ ProjectWork projectWork = createValidProjectWork();
+ projectWorkService.save(projectWork);
+ assertThat(projectWorkService.find(projectWork.getId()), notNullValue());
+ }
+
+}
diff --git a/navalplanner-business/src/test/resources/navalplanner-business-spring-config-test.xml b/navalplanner-business/src/test/resources/navalplanner-business-spring-config-test.xml
index 982dbcde8..9e6419d39 100644
--- a/navalplanner-business/src/test/resources/navalplanner-business-spring-config-test.xml
+++ b/navalplanner-business/src/test/resources/navalplanner-business-spring-config-test.xml
@@ -29,6 +29,9 @@
org/navalplanner/business/resources/entities/Resources.hbm.xml
+
+ org/navalplanner/business/resources/entities/WorkOrders.hbm.xml
+
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/MessagesForUser.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/MessagesForUser.java
index 14233d109..e55441af8 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/MessagesForUser.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/MessagesForUser.java
@@ -5,6 +5,7 @@ import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
+import org.apache.commons.lang.StringUtils;
import org.hibernate.validator.InvalidValue;
import org.navalplanner.business.common.exceptions.ValidationException;
import org.zkoss.zk.ui.Component;
@@ -135,6 +136,9 @@ public class MessagesForUser extends GenericForwardComposer implements
for (InvalidValue invalidValue : e.getInvalidValues()) {
invalidValue(invalidValue);
}
+ if (!StringUtils.isEmpty(e.getMessage())) {
+ showMessage(Level.INFO, e.getMessage());
+ }
}
}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/IProjectWorkModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/IProjectWorkModel.java
new file mode 100644
index 000000000..4beec6d0c
--- /dev/null
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/IProjectWorkModel.java
@@ -0,0 +1,28 @@
+package org.navalplanner.web.workorders;
+
+import java.util.List;
+
+import org.navalplanner.business.common.exceptions.ValidationException;
+import org.navalplanner.business.workorders.entities.ProjectWork;
+
+/**
+ * Contract for {@link ProjectWorkModel}
+ * @author Óscar González Fernández
+ */
+public interface IProjectWorkModel {
+
+ List getProjects();
+
+ void prepareEditFor(ProjectWork project);
+
+ void prepareForCreate();
+
+ void save() throws ValidationException;
+
+ ProjectWork getProject();
+
+ void remove(ProjectWork projectWork);
+
+ void prepareForRemove(ProjectWork project);
+
+}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/ProjectWorkCRUDController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/ProjectWorkCRUDController.java
new file mode 100644
index 000000000..40119be80
--- /dev/null
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/ProjectWorkCRUDController.java
@@ -0,0 +1,133 @@
+package org.navalplanner.web.workorders;
+
+import java.util.List;
+
+import org.navalplanner.business.common.exceptions.ValidationException;
+import org.navalplanner.business.workorders.entities.ProjectWork;
+import org.navalplanner.web.common.IMessagesForUser;
+import org.navalplanner.web.common.Level;
+import org.navalplanner.web.common.MessagesForUser;
+import org.navalplanner.web.common.OnlyOneVisible;
+import org.navalplanner.web.common.Util;
+import org.zkoss.zk.ui.Component;
+import org.zkoss.zk.ui.util.GenericForwardComposer;
+import org.zkoss.zul.api.Window;
+
+/**
+ * Controller for CRUD actions
+ * @author Óscar González Fernández
+ */
+public class ProjectWorkCRUDController extends GenericForwardComposer {
+
+ private IProjectWorkModel projectWorkModel;
+
+ private IMessagesForUser messagesForUser;
+
+ private Component messagesContainer;
+
+ private Component editWindow;
+
+ private Component createWindow;
+
+ private Component listWindow;
+
+ private OnlyOneVisible cachedOnlyOneVisible;
+
+ private Window confirmRemove;
+
+ public List getProjects() {
+ return projectWorkModel.getProjects();
+ }
+
+ private OnlyOneVisible getVisibility() {
+ if (cachedOnlyOneVisible == null) {
+ cachedOnlyOneVisible = new OnlyOneVisible(listWindow, editWindow,
+ createWindow);
+ }
+ return cachedOnlyOneVisible;
+ }
+
+ public ProjectWork getProject() {
+ return projectWorkModel.getProject();
+ }
+
+ public void save() {
+ try {
+ projectWorkModel.save();
+ messagesForUser.showMessage(Level.INFO, "proxecto gardado");
+ goToList();
+ } catch (ValidationException e) {
+ messagesForUser.showInvalidValues(e);
+ }
+ }
+
+ private void goToList() {
+ Util.reloadBindings(listWindow);
+ getVisibility().showOnly(listWindow);
+ }
+
+ public void cancel() {
+ goToList();
+ }
+
+ public void confirmRemove(ProjectWork project) {
+ projectWorkModel.prepareForRemove(project);
+ showConfirmingWindow();
+ }
+
+ public void cancelRemove() {
+ confirmingRemove = false;
+ confirmRemove.setVisible(false);
+ Util.reloadBindings(confirmRemove);
+ }
+
+ private boolean confirmingRemove = false;
+
+ public boolean isConfirmingRemove() {
+ return confirmingRemove;
+ }
+
+ private void hideConfirmingWindow() {
+ confirmingRemove = false;
+ Util.reloadBindings(confirmRemove);
+ }
+
+ private void showConfirmingWindow() {
+ confirmingRemove = true;
+ try {
+ Util.reloadBindings(confirmRemove);
+ confirmRemove.doModal();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void goToEditForm(ProjectWork project) {
+ projectWorkModel.prepareEditFor(project);
+ getVisibility().showOnly(editWindow);
+ Util.reloadBindings(editWindow);
+ }
+
+ public void remove(ProjectWork projectWork) {
+ projectWorkModel.remove(projectWork);
+ hideConfirmingWindow();
+ Util.reloadBindings(listWindow);
+ messagesForUser.showMessage(Level.INFO, "removed "
+ + projectWork.getName());
+ }
+
+ public void goToCreateForm() {
+ projectWorkModel.prepareForCreate();
+ getVisibility().showOnly(createWindow);
+ Util.reloadBindings(createWindow);
+ }
+
+ @Override
+ public void doAfterCompose(Component comp) throws Exception {
+ super.doAfterCompose(comp);
+ messagesForUser = new MessagesForUser(messagesContainer);
+ comp.setVariable("controller", this, true);
+ getVisibility().showOnly(listWindow);
+ }
+
+}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/ProjectWorkModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/ProjectWorkModel.java
new file mode 100644
index 000000000..5e8b184f2
--- /dev/null
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/workorders/ProjectWorkModel.java
@@ -0,0 +1,92 @@
+package org.navalplanner.web.workorders;
+
+import java.util.Date;
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
+import org.hibernate.validator.ClassValidator;
+import org.hibernate.validator.InvalidValue;
+import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
+import org.navalplanner.business.common.exceptions.ValidationException;
+import org.navalplanner.business.workorders.entities.ProjectWork;
+import org.navalplanner.business.workorders.services.IProjectWorkService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Model for UI operations related to {@link ProjectWork}.
+ * @author Óscar González Fernández
+ */
+@Component
+@Scope(BeanDefinition.SCOPE_PROTOTYPE)
+public class ProjectWorkModel implements IProjectWorkModel {
+
+ private final IProjectWorkService projectService;
+
+ private ProjectWork project;
+
+ private ClassValidator projectValidator = new ClassValidator(
+ ProjectWork.class);
+
+ @Autowired
+ public ProjectWorkModel(IProjectWorkService projectService) {
+ Validate.notNull(projectService);
+ this.projectService = projectService;
+ }
+
+ @Override
+ @Transactional(readOnly = true)
+ public List getProjects() {
+ return projectService.getProjectWorks();
+ }
+
+ @Override
+ @Transactional(readOnly = true)
+ public void prepareEditFor(ProjectWork project) {
+ Validate.notNull(project);
+ try {
+ this.project = projectService.find(project.getId());
+ } catch (InstanceNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void prepareForCreate() {
+ this.project = new ProjectWork();
+ this.project.setInitDate(new Date());
+ }
+
+ @Override
+ @Transactional
+ public void save() throws ValidationException {
+ InvalidValue[] invalidValues = projectValidator
+ .getInvalidValues(project);
+ if (invalidValues.length > 0)
+ throw new ValidationException(invalidValues);
+ this.projectService.save(project);
+ }
+
+ @Override
+ public ProjectWork getProject() {
+ return project;
+ }
+
+ @Override
+ public void remove(ProjectWork projectWork) {
+ try {
+ this.projectService.remove(projectWork);
+ } catch (InstanceNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void prepareForRemove(ProjectWork project) {
+ this.project = project;
+ }
+
+}
diff --git a/navalplanner-webapp/src/main/webapp/WEB-INF/i3-label.properties b/navalplanner-webapp/src/main/webapp/WEB-INF/i3-label.properties
index 07080d2a3..763c2febc 100644
--- a/navalplanner-webapp/src/main/webapp/WEB-INF/i3-label.properties
+++ b/navalplanner-webapp/src/main/webapp/WEB-INF/i3-label.properties
@@ -29,3 +29,5 @@ mainmenu.help=Axuda
mainmenu.about=Acerca de
mainmenu.aclunaga=Aclunaga
mainmenu.manage_criterions=Administrar criterios
+mainmenu.workorders=Traballos
+mainmenu.list_projects=Proxectos
\ No newline at end of file
diff --git a/navalplanner-webapp/src/main/webapp/WEB-INF/i3-label_en_US.properties b/navalplanner-webapp/src/main/webapp/WEB-INF/i3-label_en_US.properties
index 182323798..9136891e7 100644
--- a/navalplanner-webapp/src/main/webapp/WEB-INF/i3-label_en_US.properties
+++ b/navalplanner-webapp/src/main/webapp/WEB-INF/i3-label_en_US.properties
@@ -29,3 +29,5 @@ mainmenu.help=Help
mainmenu.about=About
mainmenu.aclunaga=Aclunaga
mainmenu.manage_criterions=Manage criterions
+mainmenu.workorders=Work
+mainmenu.list_projects=Projects
\ No newline at end of file
diff --git a/navalplanner-webapp/src/main/webapp/common/layout/template.zul b/navalplanner-webapp/src/main/webapp/common/layout/template.zul
index da2e7497b..1cf9c1e51 100644
--- a/navalplanner-webapp/src/main/webapp/common/layout/template.zul
+++ b/navalplanner-webapp/src/main/webapp/common/layout/template.zul
@@ -36,6 +36,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/navalplanner-webapp/src/main/webapp/workorders/_list.zul b/navalplanner-webapp/src/main/webapp/workorders/_list.zul
new file mode 100644
index 000000000..c85e965b4
--- /dev/null
+++ b/navalplanner-webapp/src/main/webapp/workorders/_list.zul
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/navalplanner-webapp/src/main/webapp/workorders/projects.zul b/navalplanner-webapp/src/main/webapp/workorders/projects.zul
new file mode 100644
index 000000000..60bba2205
--- /dev/null
+++ b/navalplanner-webapp/src/main/webapp/workorders/projects.zul
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ¿Desexa borrar ?
+
+
+
+
+
+
+
+
+
+