Create basic UI to bound a user to a worker

FEA: ItEr76S27ResourceBinding
This commit is contained in:
Manuel Rego Casasnovas 2012-05-07 16:35:11 +02:00
parent 24bb2f50e2
commit 9a011d35e9
7 changed files with 242 additions and 83 deletions

View file

@ -3,7 +3,7 @@
*
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
* Copyright (C) 2010-2011 Igalia, S.L.
* Copyright (C) 2010-2012 Igalia, S.L.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -25,6 +25,7 @@ import java.util.List;
import org.libreplan.business.common.daos.IGenericDAO;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.resources.entities.Worker;
import org.libreplan.business.scenarios.entities.Scenario;
import org.libreplan.business.users.entities.OrderAuthorization;
import org.libreplan.business.users.entities.User;
@ -33,6 +34,7 @@ import org.libreplan.business.users.entities.User;
* DAO interface for the <code>User</code> entity.
*
* @author Fernando Bellas Permuy <fbellas@udc.es>
* @author Manuel Rego Casasnovas <rego@igalia.com>
*/
public interface IUserDAO extends IGenericDAO<User, Long>{
@ -82,4 +84,12 @@ public interface IUserDAO extends IGenericDAO<User, Long>{
public List<User> findByLastConnectedScenario(Scenario scenario);
List<OrderAuthorization> getOrderAuthorizationsByUser(User user);
/**
* Returns the list of {@link User}s not bound to any {@link Worker} yet,
* plus the {@link User} bound to the {@link Worker} specified as parameter
* if any.
*/
List<User> getUnboundUsers(Worker worker);
}

View file

@ -3,7 +3,7 @@
*
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
* Copyright (C) 2010-2011 Igalia, S.L.
* Copyright (C) 2010-2012 Igalia, S.L.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -21,12 +21,14 @@
package org.libreplan.business.users.daos;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import org.libreplan.business.common.daos.GenericDAOHibernate;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.resources.entities.Worker;
import org.libreplan.business.scenarios.entities.Scenario;
import org.libreplan.business.users.entities.OrderAuthorization;
import org.libreplan.business.users.entities.User;
@ -40,6 +42,7 @@ import org.springframework.transaction.annotation.Transactional;
*
* @author Fernando Bellas Permuy <fbellas@udc.es>
* @author Jacobo Aragunde Perez <jaragunde@igalia.com>
* @author Manuel Rego Casasnovas <rego@igalia.com>
*/
@Repository
public class UserDAO extends GenericDAOHibernate<User, Long>
@ -127,4 +130,23 @@ public class UserDAO extends GenericDAOHibernate<User, Long>
.add(Restrictions.eq("user", user)).list();
return orderAuthorizations;
}
@Override
public List<User> getUnboundUsers(Worker worker) {
List<User> result = new ArrayList<User>();
for (User user : getUsersOrderByLoginame()) {
if ((user.getWorker() == null)
|| (worker != null && !worker.isNewObject() && worker
.getId().equals(user.getWorker().getId()))) {
result.add(user);
}
}
return result;
}
private List<User> getUsersOrderByLoginame() {
return getSession().createCriteria(User.class).addOrder(
org.hibernate.criterion.Order.asc("loginName")).list();
}
}

View file

@ -3,7 +3,7 @@
*
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
* Copyright (C) 2010-2011 Igalia, S.L.
* Copyright (C) 2010-2012 Igalia, S.L.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -39,6 +39,8 @@ import org.libreplan.business.common.IAdHocTransactionService;
import org.libreplan.business.common.IOnTransaction;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.resources.daos.IWorkerDAO;
import org.libreplan.business.resources.entities.Worker;
import org.libreplan.business.users.daos.IProfileDAO;
import org.libreplan.business.users.daos.IUserDAO;
import org.libreplan.business.users.entities.Profile;
@ -55,6 +57,7 @@ import org.springframework.transaction.annotation.Transactional;
*
* @author Fernando Bellas Permuy <fbellas@udc.es>
* @author Jacobo Aragunde Perez <jaragunde@igalia.com>
* @author Manuel Rego Casasnovas <rego@igalia.com>
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { BUSINESS_SPRING_CONFIG_FILE,
@ -71,6 +74,9 @@ public class UserDAOTest {
@Autowired
IProfileDAO profileDAO;
@Autowired
private IWorkerDAO workerDAO;
@Test
public void testBasicSave() throws InstanceNotFoundException {
@ -283,4 +289,35 @@ public class UserDAOTest {
Set<UserRole> roles = new HashSet<UserRole>();
return Profile.create(profileName, roles);
}
@Test
public void testUnoundUsers1() {
int previous = userDAO.list(User.class).size();
userDAO.save(createUser(getUniqueName()));
List<User> unboundUsers = userDAO.getUnboundUsers(null);
assertEquals(previous + 1, unboundUsers.size());
}
private Worker givenStoredWorkerRelatedTo(User user) {
Worker worker = Worker.create();
worker.setFirstName("Name " + UUID.randomUUID());
worker.setSurname("Surname " + UUID.randomUUID());
worker.setNif("ID " + UUID.randomUUID());
worker.setUser(user);
workerDAO.save(worker);
return worker;
}
@Test
public void testUnoundUsers2() {
int previous = userDAO.list(User.class).size();
User user = createUser(getUniqueName());
user.setWorker(givenStoredWorkerRelatedTo(user));
List<User> unboundUsers = userDAO.getUnboundUsers(null);
assertEquals(previous, unboundUsers.size());
}
}

View file

@ -3,7 +3,7 @@
*
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
* Copyright (C) 2010-2011 Igalia, S.L.
* Copyright (C) 2010-2012 Igalia, S.L.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -33,6 +33,7 @@ import org.libreplan.business.resources.entities.Criterion;
import org.libreplan.business.resources.entities.CriterionSatisfaction;
import org.libreplan.business.resources.entities.ICriterionType;
import org.libreplan.business.resources.entities.Worker;
import org.libreplan.business.users.entities.User;
import org.libreplan.web.common.IIntegrationEntityModel;
import org.libreplan.web.resources.search.ResourcePredicate;
@ -40,44 +41,39 @@ import org.libreplan.web.resources.search.ResourcePredicate;
* This interface contains the operations to create/edit a worker. The
* creation/edition process of a worker is conversational. <br/>
*
* <strong>Conversation state</strong>: the <code>Worker</code> instance and
* the associated <code>CriterionSatisfaction</code> instances. Some of the
* <strong>Conversation state</strong>: the <code>Worker</code> instance and the
* associated <code>CriterionSatisfaction</code> instances. Some of the
* <code>CriterionSatisfaction</code> instances represent temporal work
* relationships (e.g. paternity leave) and others represent locations. <br/>
*
* <strong>Non conversational steps</strong>: <code>getWorkers</code> (to return
* all workers) and <code>getLaboralRelatedCriterions</code></li> (to return
* all <code>Criterion</code> instances representing temporal work
* relationships). <br/>
* all workers) and <code>getLaboralRelatedCriterions</code></li> (to return all
* <code>Criterion</code> instances representing temporal work relationships). <br/>
*
* <strong>Conversation protocol:</strong>
* <ul>
* <li>
* Initial conversation step: <code>prepareForCreate</code> (to create
* a worker) or (exclusive) <code>prepareEditFor</code> (to edit an existing
* worker).
* </li>
* Initial conversation step: <code>prepareForCreate</code> (to create a worker)
* or (exclusive) <code>prepareEditFor</code> (to edit an existing worker).</li>
* <li>
* Intermediate conversation steps: <code>getWorker</code> (to return the
* worker being edited/created), <code>getLocalizationsAssigner</code> (to
* assist in the location tab), <code>isCreating</code> (to check if the worker
* is being created or edited),
* <code>getLaboralRelatedCriterionSatisfactions</code> (to return all the
* temporal work relationships), <code>addSatisfaction</code> (to add a
* temporal work relationship), <code>removeSatisfaction</code> (to remove a
* temporal work relationship) (note: to modify an existing temporal work
* Intermediate conversation steps: <code>getWorker</code> (to return the worker
* being edited/created), <code>getLocalizationsAssigner</code> (to assist in
* the location tab), <code>isCreating</code> (to check if the worker is being
* created or edited), <code>getLaboralRelatedCriterionSatisfactions</code> (to
* return all the temporal work relationships), <code>addSatisfaction</code> (to
* add a temporal work relationship), <code>removeSatisfaction</code> (to remove
* a temporal work relationship) (note: to modify an existing temporal work
* relationship, it is necessary to remove it and add a new one),
* <code>assignCriteria</code> (to add locations), and
* <code>unassignSatisfactions</code> (to remove locations).
* </li>
* <code>unassignSatisfactions</code> (to remove locations).</li>
* <li>
* Final conversational step: <code>save</code> (to save the worker being
* edited/created).
* </li>
* edited/created).</li>
* </ul>
*
* @author Óscar González Fernández <ogonzalez@igalia.com>
* @author Fernando Bellas Permuy <fbellas@udc.es>
* @author Manuel Rego Casasnovas <rego@igalia.com>
*/
public interface IWorkerModel extends IIntegrationEntityModel {
@ -142,4 +138,10 @@ public interface IWorkerModel extends IIntegrationEntityModel {
void removeCalendar();
}
List<User> getPossibleUsersToBound();
User getBoundUser();
void setBoundUser(User user);
}

View file

@ -3,7 +3,7 @@
*
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
* Copyright (C) 2010-2011 Igalia, S.L.
* Copyright (C) 2010-2012 Igalia, S.L.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -38,6 +38,7 @@ import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.resources.entities.ResourceType;
import org.libreplan.business.resources.entities.VirtualWorker;
import org.libreplan.business.resources.entities.Worker;
import org.libreplan.business.users.entities.User;
import org.libreplan.web.calendars.BaseCalendarEditionController;
import org.libreplan.web.calendars.IBaseCalendarModel;
import org.libreplan.web.common.BaseCRUDController.CRUDControllerState;
@ -71,6 +72,7 @@ import org.zkoss.zul.Label;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listcell;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.ListitemRenderer;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Row;
import org.zkoss.zul.RowRenderer;
@ -82,8 +84,10 @@ import org.zkoss.zul.api.Window;
/**
* Controller for {@link Worker} resource <br />
*
* @author Óscar González Fernández <ogonzalez@igalia.com>
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
* @author Manuel Rego Casasnovas <rego@igalia.com>
*/
public class WorkerCRUDController extends GenericForwardComposer implements
IWorkerCRUDControllerEntryPoints {
@ -896,4 +900,29 @@ public class WorkerCRUDController extends GenericForwardComposer implements
}
}
public List<User> getPossibleUsersToBound() {
return workerModel.getPossibleUsersToBound();
}
public User getBoundUser() {
return workerModel.getBoundUser();
}
public void setBoundUser(User user) {
workerModel.setBoundUser(user);
}
public ListitemRenderer getUsersRenderer() {
return new ListitemRenderer() {
@Override
public void render(Listitem item, Object data) throws Exception {
User user = (User) data;
item.setLabel(user.getLoginName());
item.setValue(user);
}
};
}
}

View file

@ -3,7 +3,7 @@
*
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
* Copyright (C) 2010-2011 Igalia, S.L.
* Copyright (C) 2010-2012 Igalia, S.L.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@ -59,6 +59,8 @@ import org.libreplan.business.resources.entities.Resource;
import org.libreplan.business.resources.entities.VirtualWorker;
import org.libreplan.business.resources.entities.Worker;
import org.libreplan.business.scenarios.IScenarioManager;
import org.libreplan.business.users.daos.IUserDAO;
import org.libreplan.business.users.entities.User;
import org.libreplan.business.workreports.daos.IWorkReportLineDAO;
import org.libreplan.web.calendars.IBaseCalendarModel;
import org.libreplan.web.common.IntegrationEntityModel;
@ -73,9 +75,11 @@ import org.springframework.transaction.annotation.Transactional;
/**
* Model for worker <br />
*
* @author Óscar González Fernández <ogonzalez@igalia.com>
* @author Fernando Bellas Permuy <fbellas@udc.es>
* @author Diego Pino García <dpino@igalia.com>
* @author Manuel Rego Casasnovas <rego@igalia.com>
*/
@Service
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
@ -127,6 +131,9 @@ public class WorkerModel extends IntegrationEntityModel implements IWorkerModel
@Autowired
private IScenarioManager scenarioManager;
@Autowired
private IUserDAO userDAO;
@Autowired
public WorkerModel(IResourceDAO resourceDAO, ICriterionDAO criterionDAO) {
Validate.notNull(resourceDAO);
@ -224,6 +231,7 @@ public class WorkerModel extends IntegrationEntityModel implements IWorkerModel
this.worker = (Worker) resourceDAO.find(worker.getId());
forceLoadSatisfactions(this.worker);
forceLoadCalendar(this.worker);
forceLoadUser(this.worker);
localizationsAssigner = new MultipleCriterionActiveAssigner(
criterionDAO, this.worker,
PredefinedCriterionTypes.LOCATION);
@ -257,6 +265,12 @@ public class WorkerModel extends IntegrationEntityModel implements IWorkerModel
baseCalendar.getExceptions().size();
}
private void forceLoadUser(Worker worker) {
if (worker.getUser() != null) {
worker.getUser().getLoginName();
}
}
@Override
@Transactional(readOnly = true)
public void assignCriteria(Collection<? extends Criterion> criteria) {
@ -614,4 +628,27 @@ public class WorkerModel extends IntegrationEntityModel implements IWorkerModel
worker.setCalendar(null);
}
@Override
@Transactional(readOnly = true)
public List<User> getPossibleUsersToBound() {
List<User> users = new ArrayList<User>();
users.addAll(userDAO.getUnboundUsers(worker));
return users;
}
@Override
public User getBoundUser() {
if (worker != null) {
return worker.getUser();
}
return null;
}
@Override
public void setBoundUser(User user) {
if (worker != null) {
worker.setUser(user);
}
}
}

View file

@ -3,7 +3,7 @@
Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
Desenvolvemento Tecnolóxico de Galicia
Copyright (C) 2010-2011 Igalia, S.L.
Copyright (C) 2010-2012 Igalia, S.L.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
@ -37,60 +37,82 @@
</tabs>
<tabpanels>
<tabpanel id="personalDataTabpanel">
<grid fixedLayout="true">
<columns>
<column width="200px" />
<column />
</columns>
<rows>
<row>
<label value="${i18n:_('Code')}" />
<hbox>
<textbox width="350px" value="@{controller.worker.code}"
constraint="no empty:${i18n:_('cannot be null or empty')}"
disabled="@{controller.worker.codeAutogenerated}" />
<checkbox id="generateCode" label="${i18n:_('Generate code')}"
onCheck="controller.onCheckGenerateCode(event)"
checked="@{controller.worker.codeAutogenerated}" />
</hbox>
</row>
<row visible="@{controller.isRealWorker}">
<label value="${i18n:_('First name')}" />
<textbox
value="@{controller.worker.firstName}" constraint="no empty" width="500px"
onBlur="controller.updateWindowTitle()" />
</row>
<row visible="@{controller.isVirtualWorker}">
<label value="${i18n:_('Group name')}" />
<textbox
value="@{controller.worker.firstName}" constraint="no empty" width="500px"
onBlur="controller.updateWindowTitle()" />
</row>
<row visible="@{controller.isRealWorker}">
<label value="${i18n:_('Last name')}" />
<textbox
value="@{controller.worker.surname}" constraint="no empty" width="500px"
onBlur="controller.updateWindowTitle()" />
</row>
<row visible="@{controller.isRealWorker}">
<label value="${i18n:_('ID')}" />
<textbox value="@{controller.worker.nif}" constraint="no empty"/>
</row>
<row visible="@{controller.isRealWorker}">
<hbox><label value="${i18n:_('Limiting resource')}" /><image height="15px" src="/common/img/axuda.gif" tooltip="limiting-resources-popup" />
</hbox>
<listbox mold="select" width="200px"
model="@{controller.limitingResourceOptionList}"
selectedItem="@{controller.limitingResource}"
onSelect="controller.setLimitingResource(self.selectedItem.value);"
disabled="@{controller.isEditing}" />
</row>
<row visible="@{controller.isVirtualWorker}">
<label value="${i18n:_('Observations')}" />
<textbox value="@{controller.virtualWorkerObservations}" width="500px" multiline="true" />
</row>
</rows>
</grid>
<groupbox style="margin-top: 5px" closable="false">
<caption label="${i18n:_('Basic data')}" />
<grid fixedLayout="true">
<columns>
<column width="200px" />
<column />
</columns>
<rows>
<row>
<label value="${i18n:_('Code')}" />
<hbox>
<textbox width="350px" value="@{controller.worker.code}"
constraint="no empty:${i18n:_('cannot be null or empty')}"
disabled="@{controller.worker.codeAutogenerated}" />
<checkbox id="generateCode" label="${i18n:_('Generate code')}"
onCheck="controller.onCheckGenerateCode(event)"
checked="@{controller.worker.codeAutogenerated}" />
</hbox>
</row>
<row visible="@{controller.isRealWorker}">
<label value="${i18n:_('First name')}" />
<textbox
value="@{controller.worker.firstName}" constraint="no empty" width="500px"
onBlur="controller.updateWindowTitle()" />
</row>
<row visible="@{controller.isVirtualWorker}">
<label value="${i18n:_('Group name')}" />
<textbox
value="@{controller.worker.firstName}" constraint="no empty" width="500px"
onBlur="controller.updateWindowTitle()" />
</row>
<row visible="@{controller.isRealWorker}">
<label value="${i18n:_('Last name')}" />
<textbox
value="@{controller.worker.surname}" constraint="no empty" width="500px"
onBlur="controller.updateWindowTitle()" />
</row>
<row visible="@{controller.isRealWorker}">
<label value="${i18n:_('ID')}" />
<textbox value="@{controller.worker.nif}" constraint="no empty"/>
</row>
<row visible="@{controller.isRealWorker}">
<hbox><label value="${i18n:_('Limiting resource')}" /><image height="15px" src="/common/img/axuda.gif" tooltip="limiting-resources-popup" />
</hbox>
<listbox mold="select" width="200px"
model="@{controller.limitingResourceOptionList}"
selectedItem="@{controller.limitingResource}"
onSelect="controller.setLimitingResource(self.selectedItem.value);"
disabled="@{controller.isEditing}" />
</row>
<row visible="@{controller.isVirtualWorker}">
<label value="${i18n:_('Observations')}" />
<textbox value="@{controller.virtualWorkerObservations}" width="500px" multiline="true" />
</row>
</rows>
</grid>
</groupbox>
<groupbox style="margin-top: 5px" closable="false">
<caption label="${i18n:_('Bound user')}" />
<grid fixedLayout="true">
<columns>
<column width="200px" />
<column />
</columns>
<rows>
<row>
<label value="${i18n:_('User')}" />
<listbox mold="select"
model="@{controller.possibleUsersToBound}"
selectedItem="@{controller.boundUser}"
itemRenderer="@{controller.usersRenderer}" />
</row>
</rows>
</grid>
</groupbox>
</tabpanel>
<tabpanel>
<criterions />