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:
parent
ca86c14065
commit
6af12a9eba
20 changed files with 686 additions and 159 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -48,4 +48,10 @@ public interface CriterionService {
|
|||
|
||||
Criterion load(Criterion criterion);
|
||||
|
||||
interface OnTransaction<T> {
|
||||
public T execute();
|
||||
}
|
||||
|
||||
<T> T onTransaction(OnTransaction<T> onTransaction);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,4 +192,9 @@ public class CriterionServiceImpl implements CriterionService {
|
|||
}
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public <T> T onTransaction(OnTransaction<T> onTransaction) {
|
||||
return onTransaction.execute();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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=">>"></button>
|
||||
<button id="assignButton" label="<<"></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>
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue