ItEr09S09AdministracionGrupos: Assignment of worker to localization groups. It uses a subcontroller for managing localizations. Worker controller and related model classes are moved to another package.

Javier Moran Rua <jmoran@igalia.com> Deleted duplicated files.
This commit is contained in:
Óscar González Fernández 2009-05-25 18:45:58 +02:00 committed by Javier Moran Rua
parent ca86c14065
commit 6af12a9eba
20 changed files with 686 additions and 159 deletions

View file

@ -86,8 +86,8 @@ public class Criterion implements ICriterion {
public boolean isEquivalent(ICriterion criterion) {
if (criterion instanceof Criterion) {
Criterion other = (Criterion) criterion;
return new EqualsBuilder().append(name, other.name).append(type,
other.type).isEquals();
return new EqualsBuilder().append(getName(), other.getName())
.append(getType(), other.getType()).isEquals();
}
return false;
}

View file

@ -37,6 +37,13 @@ public abstract class Resource {
return id;
}
public void forceLoadSatisfactions() {
for (CriterionSatisfaction criterionSatisfaction : criterionSatisfactions) {
criterionSatisfaction.getCriterion().getName();
criterionSatisfaction.getCriterion().getType();
}
}
public abstract int getDailyCapacity();
public long getVersion() {
@ -84,6 +91,15 @@ public abstract class Resource {
return result;
}
public Set<Criterion> getActiveCriterionsFor(ICriterionType<?> type) {
Set<Criterion> result = new HashSet<Criterion>();
Collection<CriterionSatisfaction> active = getActiveSatisfactionsFor(type);
for (CriterionSatisfaction satisfaction : active) {
result.add(satisfaction.getCriterion());
}
return result;
}
public Collection<CriterionSatisfaction> getActiveSatisfactionsFor(
ICriterionType<?> criterionType) {
Collection<CriterionSatisfaction> satisfactionsFor = getSatisfactionsFor(criterionType);

View file

@ -48,4 +48,10 @@ public interface CriterionService {
Criterion load(Criterion criterion);
interface OnTransaction<T> {
public T execute();
}
<T> T onTransaction(OnTransaction<T> onTransaction);
}

View file

@ -192,4 +192,9 @@ public class CriterionServiceImpl implements CriterionService {
}
}
@Transactional(readOnly = true)
public <T> T onTransaction(OnTransaction<T> onTransaction) {
return onTransaction.execute();
}
}

View file

@ -1,12 +1,5 @@
package org.navalplanner.business.test.resources.entities;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.HashSet;
@ -22,6 +15,13 @@ import org.navalplanner.business.resources.entities.Worker;
import org.navalplanner.business.test.resources.daos.CriterionDAOTest;
import org.navalplanner.business.test.resources.daos.CriterionSatisfactionDAOTest;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Tests for {@link Resource}. <br />
* @author Óscar González Fernández <ogonzalez@igalia.com>
@ -81,6 +81,29 @@ public class ResourceTest {
assertEquals(1, worker.getActiveSatisfactionsFor(criterionType).size());
}
@Test
public void testActiveCriterions() throws Exception {
final Criterion criterion = CriterionDAOTest.createValidCriterion();
Criterion otherCriterion = CriterionDAOTest.createValidCriterion();
ICriterionType<Criterion> type = createTypeThatMatches(criterion,
otherCriterion);
CriterionWithItsType criterionWithItsType = new CriterionWithItsType(
type, criterion);
CriterionWithItsType otherCriterionWithItsType = new CriterionWithItsType(
type, otherCriterion);
Worker worker = new Worker("firstName", "surName", "2333232", 10);
assertThat(worker.getActiveCriterionsFor(type).size(), equalTo(0));
worker.activate(criterionWithItsType, CriterionSatisfactionDAOTest
.year(2000));
assertThat(worker.getActiveCriterionsFor(type).size(), equalTo(1));
worker.activate(criterionWithItsType, CriterionSatisfactionDAOTest
.year(2002));
assertThat(worker.getActiveCriterionsFor(type).size(), equalTo(1));
worker.activate(otherCriterionWithItsType, CriterionSatisfactionDAOTest
.year(2000));
assertThat(worker.getActiveCriterionsFor(type).size(), equalTo(2));
}
public static CriterionTypeBase createTypeThatMatches(
final Criterion... criterions) {
return createTypeThatMatches(true, criterions);

View file

@ -1,22 +1,16 @@
package org.navalplanner.business.test.resources.services;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
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;
import java.util.Collection;
import java.util.UUID;
import org.hibernate.SessionFactory;
import org.hibernate.validator.InvalidStateException;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.navalplanner.business.resources.daos.impl.CriterionDAO;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.CriterionSatisfaction;
import org.navalplanner.business.resources.entities.CriterionWithItsType;
import org.navalplanner.business.resources.entities.ICriterion;
import org.navalplanner.business.resources.entities.ICriterionOnData;
@ -26,6 +20,7 @@ import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.business.resources.entities.Worker;
import org.navalplanner.business.resources.services.CriterionService;
import org.navalplanner.business.resources.services.ResourceService;
import org.navalplanner.business.resources.services.CriterionService.OnTransaction;
import org.navalplanner.business.test.resources.daos.CriterionDAOTest;
import org.navalplanner.business.test.resources.daos.CriterionSatisfactionDAOTest;
import org.navalplanner.business.test.resources.entities.ResourceTest;
@ -36,6 +31,14 @@ 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.is;
import static org.junit.Assert.assertEquals;
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;
/**
* Test cases for {@link CriterionService} <br />
* @author Óscar González Fernández <ogonzalez@igalia.com>
@ -55,10 +58,6 @@ public class CriterionServiceTest {
@Autowired
private SessionFactory sessionFactory;
@Autowired
private CriterionDAO criterionDAO;
@Test(expected = InvalidStateException.class)
public void testCantSaveCriterionWithoutNameAndType() throws Exception {
Criterion criterion = Criterion.withNameAndType("valido", "valido");
@ -84,8 +83,7 @@ public class CriterionServiceTest {
int initial = criterionService.getCriterionsFor(
PredefinedCriterionTypes.WORK_RELATIONSHIP).size();
criterionService.save(criterion);
assertThat("after saving one more", criterionService
.getCriterionsFor(
assertThat("after saving one more", criterionService.getCriterionsFor(
PredefinedCriterionTypes.WORK_RELATIONSHIP).size(),
equalTo(initial + 1));
criterion.setActive(false);
@ -224,6 +222,42 @@ public class CriterionServiceTest {
CriterionSatisfactionDAOTest.year(2005)).size());
}
@Test
@NotTransactional
public void testCriterionIsEquivalentOnDetachedAndProxifiedCriterion()
throws Exception {
final Worker worker1 = new Worker("worker-1", "worker-2-surname",
"11111111A", 8);
resourceService.saveResource(worker1);
Criterion criterion = CriterionDAOTest.createValidCriterion();
criterionService.save(criterion);
ICriterionType<?> type = createTypeThatMatches(criterion);
worker1.activate(new CriterionWithItsType(type, criterion));
resourceService.saveResource(worker1);
Resource workerReloaded = criterionService
.onTransaction(new OnTransaction<Resource>() {
@Override
public Resource execute() {
try {
Resource result = resourceService
.findResource(worker1.getId());
result.forceLoadSatisfactions();
return result;
} catch (InstanceNotFoundException e) {
throw new RuntimeException(e);
}
}
});
Collection<CriterionSatisfaction> satisfactionsFor = workerReloaded
.getSatisfactionsFor(type);
Criterion reloadedCriterion = satisfactionsFor.iterator().next()
.getCriterion();
Assume.assumeTrue(!reloadedCriterion.getClass().equals(
criterion.getClass()));
assertTrue(reloadedCriterion.isEquivalent(criterion));
}
@Test
@NotTransactional
public void shouldntThrowExceptionDueToTransparentProxyGotcha() {
@ -345,7 +379,7 @@ public class CriterionServiceTest {
@Override
public boolean contains(ICriterion c) {
return criterion.equals(c);
return criterion.isEquivalent(c);
}
@Override

View file

@ -9,10 +9,12 @@ import org.zkoss.zkplus.databind.DataBinder;
*/
public class Util {
public static void reloadBindings(Component reload) {
DataBinder binder = Util.getBinder(reload);
if (binder != null) {
binder.loadComponent(reload);
public static void reloadBindings(Component... toReload) {
for (Component reload : toReload) {
DataBinder binder = Util.getBinder(reload);
if (binder != null) {
binder.loadComponent(reload);
}
}
}

View file

@ -1,78 +0,0 @@
package org.navalplanner.web.resources;
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 java.util.Set;
import org.navalplanner.business.resources.entities.CriterionSatisfaction;
import org.navalplanner.business.resources.entities.Worker;
import org.navalplanner.business.resources.services.ResourceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
/**
* Model for worker <br />
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
public class WorkerModel implements IWorkerModel {
private final ResourceService resourceService;
private Worker worker;
private ClassValidator<Worker> workerValidator;
@Autowired
public WorkerModel(ResourceService resourceService) {
if (resourceService == null)
throw new IllegalArgumentException("resourceService cannot be null");
this.resourceService = resourceService;
this.workerValidator = new ClassValidator<Worker>(Worker.class);
}
@Override
public void save() throws ValidationException {
InvalidValue[] invalidValues = workerValidator
.getInvalidValues(getWorker());
if (invalidValues.length > 0) {
throw new ValidationException(invalidValues);
}
resourceService.saveResource(worker);
}
@Override
public List<Worker> getWorkers() {
return resourceService.getWorkers();
}
@Override
public Worker getWorker() {
return worker;
}
@Override
public void prepareForCreate() {
worker = new Worker();
}
@Override
@Transactional(readOnly=true)
public void prepareEditFor(Worker worker) {
Validate.notNull(worker, "worker is not null");
try {
this.worker = (Worker) resourceService.findResource(worker.getId());
} catch (InstanceNotFoundException e) {
throw new RuntimeException(e);
}
this.worker.getAllSatisfactions();
for ( CriterionSatisfaction cs : this.worker.getAllSatisfactions() ) {}
}
public Set<CriterionSatisfaction> getCriterionSatisfactions(Worker worker) {
return worker.getAllSatisfactions();
}
}

View file

@ -0,0 +1,24 @@
package org.navalplanner.web.resources.worker;
import java.util.Collection;
import java.util.List;
import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.CriterionSatisfaction;
public interface IMultipleCriterionActiveAssigner {
public List<CriterionSatisfaction> getHistoric();
public List<CriterionSatisfaction> getActiveSatisfactions();
public List<Criterion> getCriterionsNotAssigned();
public void unassign(
Collection<? extends CriterionSatisfaction> satisfactions);
public void assign(Collection<? extends Criterion> criterions);
public void applyChanges();
}

View file

@ -1,14 +1,14 @@
package org.navalplanner.web.resources;
package org.navalplanner.web.resources.worker;
import java.util.List;
import java.util.Set;
import org.navalplanner.business.common.exceptions.ValidationException;
import org.navalplanner.business.resources.entities.CriterionSatisfaction;
import org.navalplanner.business.resources.entities.Worker;
/**
* Interface for workerModel. <br />
* Interface for {@link WorkerModel}. <br />
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
public interface IWorkerModel {
@ -23,5 +23,10 @@ public interface IWorkerModel {
void prepareEditFor(Worker worker);
IMultipleCriterionActiveAssigner getLocalizationsAssigner();
boolean isCreating();
Set<CriterionSatisfaction> getCriterionSatisfactions(Worker worker);
}
}

View file

@ -0,0 +1,94 @@
package org.navalplanner.web.resources.worker;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.Validate;
import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.CriterionSatisfaction;
import org.navalplanner.web.common.Util;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.api.Button;
import org.zkoss.zul.api.Listbox;
import org.zkoss.zul.api.Listitem;
/**
* Subcontroller for assigning localizations <br />
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
public class LocalizationsController extends GenericForwardComposer {
private IWorkerModel workerModel;
private Listbox activeSatisfactions;
private Listbox criterionsNotAssigned;
private Button unassignButton;
private Button assignButton;
LocalizationsController(IWorkerModel workerModel) {
Validate.notNull(workerModel);
this.workerModel = workerModel;
}
public List<CriterionSatisfaction> getLocalizationsHistory() {
return workerModel.getLocalizationsAssigner().getHistoric();
}
public List<CriterionSatisfaction> getActiveSatisfactions() {
return workerModel.getLocalizationsAssigner().getActiveSatisfactions();
}
public List<Criterion> getCriterionsNotAssigned() {
return workerModel.getLocalizationsAssigner()
.getCriterionsNotAssigned();
}
private void reloadLists() {
Util.reloadBindings(activeSatisfactions, criterionsNotAssigned);
}
private static <T> List<T> extractValuesOf(
Collection<? extends Listitem> items, Class<T> klass) {
ArrayList<T> result = new ArrayList<T>();
for (Listitem listitem : items) {
result.add(klass.cast(listitem.getValue()));
}
return result;
}
@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
unassignButton.addEventListener("onClick", new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
workerModel.getLocalizationsAssigner().unassign(
extractValuesOf(activeSatisfactions.getSelectedItems(),
CriterionSatisfaction.class));
reloadLists();
}
});
assignButton.addEventListener("onClick", new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
Set<Listitem> selectedItems = criterionsNotAssigned
.getSelectedItems();
workerModel.getLocalizationsAssigner().assign(
extractValuesOf(selectedItems, Criterion.class));
reloadLists();
}
});
}
}

View file

@ -1,8 +1,10 @@
package org.navalplanner.web.resources;
package org.navalplanner.web.resources.worker;
import java.util.HashSet;
import java.util.Set;
import org.navalplanner.business.resources.entities.CriterionSatisfaction;
import org.navalplanner.business.resources.entities.Worker;
import org.zkoss.zk.ui.util.GenericForwardComposer;
/**
@ -24,8 +26,9 @@ public class WorkRelationshipsController extends GenericForwardComposer {
if (this.workerCRUDController.getWorker() == null) {
return new HashSet();
} else {
return workerModel.getCriterionSatisfactions(
this.workerCRUDController.getWorker());
return workerModel
.getCriterionSatisfactions(this.workerCRUDController
.getWorker());
}
}
}

View file

@ -1,12 +1,9 @@
package org.navalplanner.web.resources;
package org.navalplanner.web.resources.worker;
import java.util.List;
import java.util.Set;
import org.hibernate.validator.InvalidValue;
import org.navalplanner.business.common.exceptions.ValidationException;
import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.CriterionSatisfaction;
import org.navalplanner.business.resources.entities.Worker;
import org.navalplanner.web.common.IMessagesForUser;
import org.navalplanner.web.common.Level;
@ -41,6 +38,10 @@ public class WorkerCRUDController extends GenericForwardComposer {
private GenericForwardComposer workRelationship;
private LocalizationsController localizationsForEditionController;
private LocalizationsController localizationsForCreationController;
public WorkerCRUDController() {
}
@ -63,6 +64,12 @@ public class WorkerCRUDController extends GenericForwardComposer {
return workerModel.getWorkers();
}
public LocalizationsController getLocalizations() {
if (workerModel.isCreating())
return localizationsForCreationController;
return localizationsForEditionController;
}
public void save() {
try {
workerModel.save();
@ -95,24 +102,39 @@ public class WorkerCRUDController extends GenericForwardComposer {
workerModel.prepareForCreate();
getVisibility().showOnly(createWindow);
Util.reloadBindings(createWindow);
this.workRelationship = new WorkRelationshipsController(
this.workerModel, this);
}
@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
localizationsForEditionController = createLocalizationsController(comp,
"editWindow");
localizationsForCreationController = createLocalizationsController(
comp, "createWindow");
comp.setVariable("controller", this, true);
getVisibility().showOnly(listWindow);
if (messagesContainer == null)
throw new RuntimeException("messagesContainer is needed");
messages = new MessagesForUser(messagesContainer);
this.workRelationship =
new WorkRelationshipsController(this.workerModel,this);
}
private LocalizationsController createLocalizationsController(
Component comp, String localizationsContainerName) throws Exception {
LocalizationsController localizationsController = new LocalizationsController(
workerModel);
localizationsController
.doAfterCompose(comp.getFellow(localizationsContainerName)
.getFellow("localizationsContainer"));
return localizationsController;
}
private OnlyOneVisible getVisibility() {
if (visibility == null) {
visibility = new OnlyOneVisible(listWindow, editWindow,
createWindow, workRelationshipsWindow );
createWindow, workRelationshipsWindow);
}
return visibility;
}

View file

@ -0,0 +1,287 @@
package org.navalplanner.web.resources.worker;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.CriterionSatisfaction;
import org.navalplanner.business.resources.entities.CriterionWithItsType;
import org.navalplanner.business.resources.entities.ICriterionType;
import org.navalplanner.business.resources.entities.PredefinedCriterionTypes;
import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.business.resources.entities.Worker;
import org.navalplanner.business.resources.services.CriterionService;
import org.navalplanner.business.resources.services.ResourceService;
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 worker <br />
* @author Óscar González Fernández <ogonzalez@igalia.com>
*/
@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class WorkerModel implements IWorkerModel {
private final ResourceService resourceService;
private Worker worker;
private ClassValidator<Worker> workerValidator;
private final CriterionService criterionService;
private IMultipleCriterionActiveAssigner localizationsAssigner;
@Autowired
public WorkerModel(ResourceService resourceService,
CriterionService criterionService) {
Validate.notNull(resourceService);
Validate.notNull(criterionService);
this.resourceService = resourceService;
this.workerValidator = new ClassValidator<Worker>(Worker.class);
this.criterionService = criterionService;
}
@Override
public void save() throws ValidationException {
InvalidValue[] invalidValues = workerValidator
.getInvalidValues(getWorker());
if (invalidValues.length > 0) {
throw new ValidationException(invalidValues);
}
getLocalizationsAssigner().applyChanges();
resourceService.saveResource(worker);
worker = null;
localizationsAssigner = null;
}
@Override
public List<Worker> getWorkers() {
return resourceService.getWorkers();
}
@Override
public Worker getWorker() {
return worker;
}
@Override
@Transactional(readOnly = true)
public void prepareForCreate() {
worker = new Worker();
localizationsAssigner = new MultipleCriterionActiveAssigner(
criterionService, worker,
PredefinedCriterionTypes.LOCATION_GROUP);
}
@Override
@Transactional(readOnly = true)
public void prepareEditFor(Worker worker) {
Validate.notNull(worker, "worker is not null");
try {
this.worker = (Worker) resourceService.findResource(worker.getId());
this.worker.forceLoadSatisfactions();
localizationsAssigner = new MultipleCriterionActiveAssigner(
criterionService, this.worker,
PredefinedCriterionTypes.LOCATION_GROUP);
} catch (InstanceNotFoundException e) {
throw new RuntimeException(e);
}
}
public Set<CriterionSatisfaction> getCriterionSatisfactions(Worker worker) {
return worker.getAllSatisfactions();
}
private static class NullAssigner implements
IMultipleCriterionActiveAssigner {
private List<CriterionSatisfaction> empty = Arrays.asList();
private List<Criterion> emptyCriterions = Arrays.asList();
@Override
public void assign(Collection<? extends Criterion> criterions) {
}
@Override
public List<CriterionSatisfaction> getActiveSatisfactions() {
return empty;
}
@Override
public List<Criterion> getCriterionsNotAssigned() {
return emptyCriterions;
}
@Override
public List<CriterionSatisfaction> getHistoric() {
return empty;
}
@Override
public void unassign(
Collection<? extends CriterionSatisfaction> satisfactions) {
}
@Override
public void applyChanges() {
}
}
private static class MultipleCriterionActiveAssigner implements
IMultipleCriterionActiveAssigner {
private final Resource resource;
private final ICriterionType<?> type;
private final CriterionService criterionService;
private List<CriterionSatisfaction> history;
private List<Criterion> initialCriterionsNotAssigned;
private Set<CriterionSatisfaction> initialActive;
private Map<Criterion, CriterionSatisfaction> unassigned = new HashMap<Criterion, CriterionSatisfaction>();
private Set<CriterionSatisfaction> added = new HashSet<CriterionSatisfaction>();
public MultipleCriterionActiveAssigner(
CriterionService criterionService, Resource resource,
ICriterionType<?> type) {
Validate
.isTrue(
type.allowMultipleActiveCriterionsPerResource(),
"must allow multiple active criterions for this type to use this assignment strategy");
this.criterionService = criterionService;
this.resource = resource;
this.type = type;
this.resource.forceLoadSatisfactions();
this.history = calculateInitialHistory();
this.initialCriterionsNotAssigned = calculateInitialCriterionsNotAssigned();
for (Criterion criterion : initialCriterionsNotAssigned) {
unassigned.put(criterion, createSatisfactionFor(criterion));
}
this.initialActive = calculateInitialActive();
}
public List<CriterionSatisfaction> getHistoric() {
return history;
}
private List<CriterionSatisfaction> calculateInitialHistory() {
Collection<CriterionSatisfaction> allSatisfactions = resource
.getSatisfactionsFor(type);
ArrayList<CriterionSatisfaction> result = new ArrayList<CriterionSatisfaction>();
for (CriterionSatisfaction criterionSatisfaction : allSatisfactions) {
if (criterionSatisfaction.isFinished()) {
result.add(criterionSatisfaction);
}
}
return result;
}
private HashSet<CriterionSatisfaction> calculateInitialActive() {
return new HashSet<CriterionSatisfaction>(resource
.getActiveSatisfactionsFor(type));
}
private List<Criterion> calculateInitialCriterionsNotAssigned() {
Map<Long, Criterion> allCriterions = byId(criterionService
.getCriterionsFor(type));
for (Long activeId : asIds(resource.getActiveCriterionsFor(type))) {
allCriterions.remove(activeId);
}
return new ArrayList<Criterion>(allCriterions.values());
}
public List<CriterionSatisfaction> getActiveSatisfactions() {
Set<CriterionSatisfaction> result = new HashSet<CriterionSatisfaction>(
added);
for (CriterionSatisfaction criterionSatisfaction : initialActive) {
if (!unassigned.containsKey(criterionSatisfaction
.getCriterion())) {
result.add(criterionSatisfaction);
}
}
return new ArrayList<CriterionSatisfaction>(result);
}
public List<Criterion> getCriterionsNotAssigned() {
return new ArrayList<Criterion>(unassigned.keySet());
}
public void unassign(
Collection<? extends CriterionSatisfaction> satisfactions) {
for (CriterionSatisfaction criterionSatisfaction : satisfactions) {
unassigned.put(criterionSatisfaction.getCriterion(),
criterionSatisfaction);
added.remove(criterionSatisfaction);
}
}
public void assign(Collection<? extends Criterion> criterions) {
for (Criterion criterion : criterions) {
CriterionSatisfaction removed = unassigned.remove(criterion);
if (!initialActive.contains(removed)) {
added.add(removed);
}
}
}
private CriterionSatisfaction createSatisfactionFor(Criterion criterion) {
return new CriterionSatisfaction(new Date(), criterion, resource);
}
@Override
public void applyChanges() {
for (CriterionSatisfaction criterionSatisfaction : added) {
resource.activate(new CriterionWithItsType(type,
criterionSatisfaction.getCriterion()),
criterionSatisfaction.getStartDate());
}
for (Criterion criterion : unassigned.keySet()) {
resource.deactivate(new CriterionWithItsType(type, criterion));
}
}
}
public IMultipleCriterionActiveAssigner getLocalizationsAssigner() {
return localizationsAssigner != null ? localizationsAssigner
: new NullAssigner();
}
private static List<Long> asIds(Collection<? extends Criterion> criterions) {
List<Long> result = new ArrayList<Long>();
for (Criterion criterion : criterions) {
result.add(criterion.getId());
}
return result;
}
private static Map<Long, Criterion> byId(
Collection<? extends Criterion> criterions) {
Map<Long, Criterion> result = new HashMap<Long, Criterion>();
for (Criterion criterion : criterions) {
result.put(criterion.getId(), criterion);
}
return result;
}
@Override
public boolean isCreating() {
return worker != null && worker.getId() == null;
}
}

View file

@ -15,7 +15,4 @@
<context:annotation-config />
<context:component-scan base-package="org.navalplanner.web"/>
<bean id="workerModel" class="org.navalplanner.web.resources.WorkerModel"
scope="prototype" />
</beans>

View file

@ -1,33 +1,50 @@
<?component name="localizations" inline="true" macroURI="_localizations.zul"?>
<window id="${arg.top_id}" title="${arg.title}">
<grid fixedLayout="false">
<columns>
<column label="Type" />
<column label="Content" />
</columns>
<rows>
<row>
<label value="first_name" />
<textbox value="@{controller.worker.firstName}" />
</row>
<row>
<label value="last_name" />
<textbox value="@{controller.worker.surname}"
/>
</row>
<row>
<label value="nif" />
<textbox value="@{controller.worker.nif}" />
</row>
<row>
<label value="daily_hours" />
<textbox value="@{controller.worker.dailyHours}"/>
</row>
</rows>
</grid>
<button onClick="controller.save();" label="${arg.save_button_label}" />
<button onClick="controller.cancel();" label="${arg.cancel_button_label}" />
<button label="Work Relationships"
<tabbox>
<tabs>
<tab label="Edición"></tab>
<tab label="Localizacións"></tab>
</tabs>
<tabpanels>
<tabpanel>
<grid fixedLayout="false">
<columns>
<column label="Type" />
<column label="Content" />
</columns>
<rows>
<row>
<label value="first_name" />
<textbox
value="@{controller.worker.firstName}" />
</row>
<row>
<label value="last_name" />
<textbox
value="@{controller.worker.surname}" />
</row>
<row>
<label value="nif" />
<textbox value="@{controller.worker.nif}" />
</row>
<row>
<label value="daily_hours" />
<textbox
value="@{controller.worker.dailyHours}" />
</row>
</rows>
</grid>
</tabpanel>
<tabpanel>
<localizations />
</tabpanel>
</tabpanels>
</tabbox>
<button onClick="controller.save();"
label="${arg.save_button_label}" />
<button onClick="controller.cancel();"
label="${arg.cancel_button_label}" />
<button label="Work Relationships"
onClick="controller.goToWorkRelationshipsForm(controller.worker)">
</button>
</window>
</window>

View file

@ -0,0 +1,46 @@
<vbox id="localizationsContainer">
<hbox>
<listbox id="activeSatisfactions" mold="paging" model="@{controller.localizations.activeSatisfactions}"
pageSize="5" multiple="true" checkmark="true">
<listhead>
<listheader label="Grupo" sort="auto(criterion.name)"></listheader>
<listheader label="Data Inicio" sort="auto(startDate)" />
</listhead>
<listitem self="@{each='satisfaction'}" value="@{satisfaction}">
<listcell label="@{satisfaction.criterion.name}"></listcell>
<listcell label="@{satisfaction.startDate}"></listcell>
</listitem>
</listbox>
<vbox>
<button id="unassignButton" label="&gt;&gt;"></button>
<button id="assignButton" label="&lt;&lt;"></button>
</vbox>
<listbox id="criterionsNotAssigned" mold="paging" model="@{controller.localizations.criterionsNotAssigned}"
pageSize="5" multiple="true" checkmark="true">
<listhead>
<listheader label="Grupo" sort="auto(name)"></listheader>
</listhead>
<listitem self="@{each='criterion'}" value="@{criterion}">
<listcell label="@{criterion.name}"></listcell>
</listitem>
</listbox>
</hbox>
<grid id="listing" model="@{controller.localizations.localizationsHistory}"
mold="paging" pageSize="5">
<columns>
<column label="Grupo" sort="auto(criterion.name)" />
<column label="Data Inicio" sort="auto(startDate)" />
<column label="Data fin" sort="auto(endDate)" />
</columns>
<rows>
<row self="@{each='satisfaction'}">
<label value="@{satisfaction.criterion.name}" />
<label value="@{satisfaction.startDate}" />
<label value="@{satisfaction.endDate}" />
</row>
</rows>
</grid>
</vbox>

View file

@ -10,7 +10,7 @@
<?component name="workRelationships" inline="true" macroURI="_workRelationships.zul"?>
<zk>
<window self="@{define(content)}"
apply="org.navalplanner.web.resources.WorkerCRUDController"
apply="org.navalplanner.web.resources.worker.WorkerCRUDController"
sclass="workerwindow">
<vbox id="messagesContainer">
</vbox>

View file

@ -17,6 +17,8 @@ import org.junit.Test;
import org.navalplanner.business.resources.entities.Worker;
import org.navalplanner.web.common.IMessagesForUser;
import org.navalplanner.web.common.Level;
import org.navalplanner.web.resources.worker.IWorkerModel;
import org.navalplanner.web.resources.worker.WorkerCRUDController;
import org.zkoss.zul.api.Window;
/**

View file

@ -4,11 +4,18 @@ import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import java.util.ArrayList;
import java.util.Collection;
import org.junit.Test;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.common.exceptions.ValidationException;
import org.navalplanner.business.resources.entities.Criterion;
import org.navalplanner.business.resources.entities.PredefinedCriterionTypes;
import org.navalplanner.business.resources.entities.Worker;
import org.navalplanner.business.resources.services.CriterionService;
import org.navalplanner.business.resources.services.ResourceService;
import org.navalplanner.web.resources.worker.WorkerModel;
/**
* Some test cases for {@link WorkerModel}. <br />
@ -20,18 +27,26 @@ public class WorkerModelTest {
public void testWorkerValid() throws ValidationException,
InstanceNotFoundException {
ResourceService resourceServiceMock = createMock(ResourceService.class);
WorkerModel workerModel = new WorkerModel(resourceServiceMock);
CriterionService criterionServiceMock = createMock(CriterionService.class);
Worker workerToReturn = new Worker();
workerToReturn.setDailyHours(2);
workerToReturn.setFirstName("firstName");
workerToReturn.setSurname("surname");
workerToReturn.setNif("232344243");
// expectations
Collection<Criterion> criterions = new ArrayList<Criterion>();
expect(
criterionServiceMock
.getCriterionsFor(PredefinedCriterionTypes.LOCATION_GROUP))
.andReturn(criterions).anyTimes();
expect(resourceServiceMock.findResource(workerToReturn.getId()))
.andReturn(workerToReturn);
resourceServiceMock.saveResource(workerToReturn);
replay(resourceServiceMock);
replay(resourceServiceMock, criterionServiceMock);
// perform actions
WorkerModel workerModel = new WorkerModel(resourceServiceMock,
criterionServiceMock);
workerModel.prepareEditFor(workerToReturn);
workerModel.save();
}
@ -40,13 +55,20 @@ public class WorkerModelTest {
public void testWorkerInvalid() throws ValidationException,
InstanceNotFoundException {
ResourceService resourceServiceMock = createMock(ResourceService.class);
WorkerModel workerModel = new WorkerModel(resourceServiceMock);
CriterionService criterionServiceMock = createMock(CriterionService.class);
Worker workerToReturn = new Worker();
// expectations
Collection<Criterion> criterions = new ArrayList<Criterion>();
expect(
criterionServiceMock
.getCriterionsFor(PredefinedCriterionTypes.LOCATION_GROUP))
.andReturn(criterions).anyTimes();
expect(resourceServiceMock.findResource(workerToReturn.getId()))
.andReturn(workerToReturn);
replay(resourceServiceMock);
replay(resourceServiceMock, criterionServiceMock);
// perform actions
WorkerModel workerModel = new WorkerModel(resourceServiceMock,
criterionServiceMock);
workerModel.prepareEditFor(workerToReturn);
workerModel.save();
}