Administration pages for unit types for materials. Listing, creation, edition and remove of unit types.

This commit is contained in:
Javier Moran Rua 2010-04-04 03:04:15 +02:00
parent c6b490df65
commit a798653c57
10 changed files with 689 additions and 5 deletions

View file

@ -28,6 +28,7 @@ import org.navalplanner.business.materials.entities.UnitType;
/**
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
* @author Javier Moran Rua <jmoran@igalia.com>
*/
public interface IUnitTypeDAO extends IIntegrationEntityDAO<UnitType> {
@ -39,4 +40,9 @@ public interface IUnitTypeDAO extends IIntegrationEntityDAO<UnitType> {
throws InstanceNotFoundException;
boolean existsUnitTypeByNameInAnotherTransaction(String measure);
UnitType findByNameCaseInsensitive(String measure)
throws InstanceNotFoundException;
boolean isUnitTypeUsedInAnyMaterial(UnitType unitType);
}

View file

@ -23,9 +23,12 @@ package org.navalplanner.business.materials.daos;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;
import org.navalplanner.business.common.daos.IntegrationEntityDAO;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.materials.entities.Material;
import org.navalplanner.business.materials.entities.UnitType;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
@ -36,6 +39,7 @@ import org.springframework.transaction.annotation.Transactional;
/**
* DAO for {@link UnitType}
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
* @author Javier Moran Rua <jmoran@igaia.com>
*/
@Repository
@Scope(BeanDefinition.SCOPE_SINGLETON)
@ -70,18 +74,41 @@ public class UnitTypeDAO extends IntegrationEntityDAO<UnitType> implements
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public UnitType findUniqueByNameInAnotherTransaction(String measure)
throws InstanceNotFoundException {
return findByName(measure);
return findByNameCaseInsensitive(measure);
}
@Override
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public boolean existsUnitTypeByNameInAnotherTransaction(String measure) {
try {
findByName(measure);
findByNameCaseInsensitive(measure);
} catch (InstanceNotFoundException e) {
return false;
}
return true;
}
@Override
@Transactional(readOnly=true)
public UnitType findByNameCaseInsensitive(String measure)
throws InstanceNotFoundException {
Criteria c = getSession().createCriteria(UnitType.class);
c.add(Restrictions.ilike("measure", measure, MatchMode.EXACT));
UnitType result = (UnitType) c.uniqueResult();
if (result == null) {
throw new InstanceNotFoundException(measure,
getEntityClass().getName());
}
return result;
}
@Override
@Transactional(readOnly=true)
public boolean isUnitTypeUsedInAnyMaterial(UnitType unitType) {
Criteria c = getSession().createCriteria(Material.class);
return !c.add(Restrictions.eq("unitType", unitType)).list().isEmpty();
}
}

View file

@ -32,16 +32,26 @@ import org.navalplanner.business.materials.daos.IUnitTypeDAO;
* UnitType entity
*
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*
* @author Javier Moran Rua <jmoran@ialia.com>
*/
public class UnitType extends IntegrationEntity{
public static UnitType create(String code, String measure) {
return (UnitType) create(new UnitType(measure), code);
UnitType unitType = new UnitType(measure);
unitType.setNewObject(true);
return (UnitType) create(unitType, code);
}
public static UnitType create(String measure) {
return (UnitType) create(new UnitType(measure));
UnitType unitType = new UnitType(measure);
unitType.setNewObject(true);
return (UnitType) create(unitType);
}
public static UnitType create() {
UnitType unitType = new UnitType();
unitType.setNewObject(true);
return create(unitType);
}
public void updateUnvalidated(String measure) {

View file

@ -222,6 +222,7 @@ public class CustomMenuController extends Div implements IMenuItemsRegister {
subItem(_("Calendars"),"/calendars/calendars.zul", "03-calendarios.html"),
subItem(_("Label types"), "/labels/labelTypes.zul","10-etiquetas.html"),
subItem(_("Materials"), "/materials/materials.zul", "11-materiales.html#administraci-n-de-materiais"),
subItem(_("Unit types"), "/materials/unitTypes.zul", "11-materiales.html#administraci-n-de-materiais"),
subItem(_("Manage cost categories"),"/costcategories/costCategory.zul","14-custos.html#categor-as-de-custo"),
subItem(_("Manage types of work hours"),"/costcategories/typeOfWorkHours.zul","14-custos.html#administraci-n-de-horas-traballadas"),
subItem(_("Configuration"), "/common/configuration.zul","03-calendarios.html#calendario-por-defecto"),

View file

@ -0,0 +1,111 @@
package org.navalplanner.web.materials;
import java.util.List;
import org.navalplanner.business.common.exceptions.ValidationException;
import org.navalplanner.business.materials.entities.UnitType;
/**
* Interface for the model which lets the client of this model
* list the unit types, create new unit types, edit existing unit types
* and remove unity types
*
* <strong>Conversation state:</strong> A unit type being edited or created.
*
* <strong>Not conversational methods:</strong>
* <ul>
* <li>getUnitTypes</li>
* <li>existsAnotherUnitTypeWithName</li>
* <li>existsAnotherUnitTypeWithCode</li>
* <li>isUnitTypeUsedInAnyMaterial</li>
* <li>isUnitTypeUsedInAnyMaterial</li>
* <li>remove</li>
* </ul>
*
* <strong>Conversational methods:</strong>
* <ul>
* <li>initCreate</li>
* <li>initEdit</li>
* <li>getCurrentUnitType</li>
* <li>confirmSave</li>
* </ul>
*
* @author Javier Moran Rua <jmoran@igalia.com>
*/
public interface IUnitTypeModel {
// Non conversational methods
/**
* Query the database to get all the unit types in the database
*/
List<UnitType> getUnitTypes();
/**
* This method check if there is another UnitType in the database
* different from the one in the state of the model which had the same
* measure name as the parameter.
*
* @param name the measure name to be checked as unique in the unit types
* @return the boolean with the result
*/
boolean existsAnotherUnitTypeWithName(String name);
/**
* This method check if there is another UnitType in the database
* different from the one in the state of the model which had teh same
* code as the parameter
*
* @param code the code to be checked as unique
* @return the boolean showing the result
*/
boolean existsAnotherUnitTypeWithCode(String code);
/**
* This method finds out if the unit type passed as parameter is
* used to measure any material
*
* @param unitType the unitType to check
* @return the boolean with the result
*/
boolean isUnitTypeUsedInAnyMaterial(UnitType unitType);
/**
* This method removes the unit type passed as parameter from the
* database
*
* @param unitType the unitType which is wanted to be deleted
*/
void remove(UnitType unitType);
//Conversational methods
/**
* First method of the conversational state. Prepares the state with the
* unit type to edit
*/
void initEdit(UnitType unitType);
/**
* First method of the conversational state. Creates an empty unit type
* to be saved
*/
void initCreate();
/**
* Get the current unit type which is in the state of the
*
* @return
*/
UnitType getCurrentUnitType();
/**
* Last method of the conversation. It ends with the saving of the unit
* type in the state to the database
*
* @throws ValidationException
*/
void confirmSave() throws ValidationException;
}

View file

@ -0,0 +1,249 @@
package org.navalplanner.web.materials;
import static org.navalplanner.web.I18nHelper._;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.LogFactory;
import org.navalplanner.business.common.exceptions.ValidationException;
import org.navalplanner.business.materials.entities.UnitType;
import org.navalplanner.web.common.IMessagesForUser;
import org.navalplanner.web.common.Level;
import org.navalplanner.web.common.MessagesForUser;
import org.navalplanner.web.common.OnlyOneVisible;
import org.navalplanner.web.common.Util;
import org.zkoss.util.logging.Log;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.WrongValueException;
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.Constraint;
import org.zkoss.zul.Hbox;
import org.zkoss.zul.Label;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Row;
import org.zkoss.zul.RowRenderer;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.impl.InputElement;
/**
*
* Controller for the listing and editing unit types
*
* @author Javier Moran Rua <jmoran@igalia.com>
*/
public class UnitTypeController extends GenericForwardComposer {
private static final org.apache.commons.logging.Log LOG = LogFactory
.getLog(UnitTypeController.class);
private Component messagesContainer;
private IMessagesForUser messagesForUser;
private OnlyOneVisible visibility;
private Component listWindow;
private Component editWindow;
private IUnitTypeModel unitTypeModel;
@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
messagesForUser = new MessagesForUser(messagesContainer);
comp.setVariable("controller", this, true);
getVisibility().showOnly(listWindow);
}
private OnlyOneVisible getVisibility() {
if (visibility == null) {
visibility = new OnlyOneVisible(listWindow,editWindow);
}
return visibility;
}
public List<UnitType> getUnitTypes() {
return unitTypeModel.getUnitTypes();
}
public RowRenderer getUnitTypeRenderer() {
return new RowRenderer() {
@Override
public void render(Row row, Object data) throws Exception {
UnitType unitType = (UnitType) data;
appendUnitTypeName(row, unitType);
appendOperations(row, unitType);
}
private void appendUnitTypeName(Row row, UnitType unitType) {
row.appendChild(new Label(unitType.getMeasure()));
}
private void appendOperations(Row row, final UnitType unitType) {
Hbox hbox = new Hbox();
hbox.appendChild(Util.createEditButton(new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
goToEditFormInEditionMode(unitType);
}
}));
hbox.appendChild(Util.createRemoveButton(new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
confirmRemove(unitType);
}
}));
row.appendChild(hbox);
}
};
}
private void confirmRemove(UnitType unitType) {
try {
int status = Messagebox.show(_("Confirm deleting {0}. Are you sure?", unitType.getMeasure()),
"Delete", Messagebox.OK | Messagebox.CANCEL, Messagebox.QUESTION);
if (Messagebox.OK == status) {
removeUnitType(unitType);
}
} catch (InterruptedException e) {
LOG.error("Error showing confirming message box",e);
throw new RuntimeException();
}
}
private void removeUnitType(UnitType unitType) {
if (unitTypeModel.isUnitTypeUsedInAnyMaterial(unitType)) {
messagesForUser.showMessage(Level.ERROR, _("Unit {0} cannot be " +
" removed because it is used in materials",
unitType.getMeasure()));
} else {
unitTypeModel.remove(unitType);
Util.reloadBindings(listWindow);
messagesForUser.showMessage(Level.INFO, _("Deleted unit type {0}",
unitType.getMeasure()));
}
}
public void goToEditFormInCreationMode() {
unitTypeModel.initCreate();
getVisibility().showOnly(editWindow);
Util.reloadBindings(editWindow);
}
private void goToEditFormInEditionMode(UnitType unitType) {
unitTypeModel.initEdit(unitType);
getVisibility().showOnly(editWindow);
Util.reloadBindings(editWindow);
}
public UnitType getUnitType() {
return unitTypeModel.getCurrentUnitType();
}
public Constraint uniqueMeasureName() {
return new Constraint() {
@Override
public void validate(Component comp, Object value)
throws WrongValueException {
String strValue = (String) value;
if (StringUtils.isBlank(strValue)) {
throw new WrongValueException(comp,
_("Unit type name cannot be empty")
);
}
if (unitTypeModel.existsAnotherUnitTypeWithName(strValue)) {
throw new WrongValueException(comp,
_("The meausure name is not valid. There is " +
"another unit type with the same " +
"measure name"));
}
}
};
}
public Constraint uniqueCode() {
return new Constraint() {
@Override
public void validate(Component comp, Object value)
throws WrongValueException {
String strValue = (String) value;
if (StringUtils.isBlank(strValue)) {
throw new WrongValueException(comp,
_("Unit type code cannot be empty"));
}
if (unitTypeModel.existsAnotherUnitTypeWithCode(strValue)) {
throw new WrongValueException(comp,
_("The code is not valid. There is another " +
"unit type with the same code"));
}
}
};
}
public void saveAndExit() {
if (save()) {
goToList();
}
}
public void saveAndContinue() {
if (save()) {
goToEditFormInEditionMode(getUnitType());
}
}
public void cancel() {
goToList();
}
private boolean save() {
try {
validateAll();
unitTypeModel.confirmSave();
messagesForUser.showMessage(Level.INFO, _("Unit type saved"));
return true;
} catch (ValidationException e) {
messagesForUser.showInvalidValues(e);
return false;
}
}
private void validateAll() {
Textbox codeTextBox = (Textbox) editWindow.
getFellowIfAny("codeTextBox");
validate((InputElement) codeTextBox,codeTextBox.getValue());
Textbox measureTextBox = (Textbox) editWindow.
getFellowIfAny("measureTextBox");
validate((InputElement) measureTextBox,measureTextBox.getValue());
}
/**
* Validates {@link Textbox} checking {@link Constraint}
* @param comp
*/
private void validate(InputElement comp, Object value) {
if (comp != null && comp.getConstraint() != null) {
final Constraint constraint = comp.getConstraint();
constraint.validate(comp, value);
}
}
private void goToList() {
Util.reloadBindings(listWindow);
getVisibility().showOnly(listWindow);
}
}

View file

@ -0,0 +1,138 @@
package org.navalplanner.web.materials;
import static org.navalplanner.web.I18nHelper._;
import java.util.List;
import org.apache.commons.lang.Validate;
import org.apache.commons.logging.LogFactory;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.common.exceptions.ValidationException;
import org.navalplanner.business.materials.daos.IUnitTypeDAO;
import org.navalplanner.business.materials.entities.UnitType;
import org.navalplanner.web.common.concurrentdetection.OnConcurrentModification;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* Model for the listing, creation and edition of UnitTypes
*
* @author Javier Moran Rua <jmoran@igalia.com>
*
*/
@Service
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
@OnConcurrentModification(goToPage = "/materials/unitTypes.zul")
public class UnitTypeModel implements IUnitTypeModel {
private static final org.apache.commons.logging.Log LOG = LogFactory
.getLog(UnitTypeModel.class);
// This is the state of the model, just the current unitType being edited
private UnitType unitTypeState;
@Autowired
private IUnitTypeDAO unitTypeDAO;
@Override
@Transactional(readOnly=true)
public List<UnitType> getUnitTypes() {
return unitTypeDAO.getAll();
}
@Override
public void initCreate() {
this.unitTypeState = UnitType.create();
}
@Override
@Transactional(readOnly=true)
public void initEdit(UnitType unitType) {
Validate.notNull(unitType);
this.unitTypeState = getFromDB(unitType);
}
private UnitType getFromDB(UnitType unitType) {
try {
return unitTypeDAO.find(unitType.getId());
} catch (InstanceNotFoundException e) {
LOG.error(_("It was not possible load entity. Not found. Id: " +
unitType.getId()), e);
throw new RuntimeException(e);
}
}
@Override
public UnitType getCurrentUnitType() {
return this.unitTypeState;
}
@Override
@Transactional
public void confirmSave() throws ValidationException {
unitTypeDAO.save(this.unitTypeState);
}
@Override
@Transactional(readOnly=true)
public boolean existsAnotherUnitTypeWithName(String name) {
boolean result;
try {
UnitType foundUnitType =
unitTypeDAO.findByNameCaseInsensitive(name);
result = isTheSameEntityAsState(foundUnitType) ? false : true;
} catch (InstanceNotFoundException e) {
result = false;
}
return result;
}
@Override
@Transactional(readOnly=true)
public boolean existsAnotherUnitTypeWithCode(String code) {
boolean result;
try {
UnitType foundUnitType =
unitTypeDAO.findByCode(code);
result = isTheSameEntityAsState(foundUnitType) ? false : true;
} catch (InstanceNotFoundException e) {
result = false;
}
return result;
}
private boolean isTheSameEntityAsState(UnitType foundUnitType) {
if (getCurrentUnitType().isNewObject()) {
return false;
} else {
return foundUnitType.getId().equals(getCurrentUnitType().getId());
}
}
@Override
@Transactional(readOnly=true)
public boolean isUnitTypeUsedInAnyMaterial(UnitType unitType) {
return unitTypeDAO.isUnitTypeUsedInAnyMaterial(unitType);
}
@Override
@Transactional
public void remove(UnitType unitType) {
try {
unitTypeDAO.remove(unitType.getId());
} catch (InstanceNotFoundException e) {
LOG.error("Trying to remove unit type with id " + unitType.getId() +
" but it is not found in the database",e);
throw new RuntimeException();
}
}
}

View file

@ -0,0 +1,64 @@
<!--
This file is part of NavalPlan
Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
Desenvolvemento Tecnolóxico de Galicia
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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
-->
<window id="${arg.top_id}" title="${arg.title}">
<tabbox>
<tabs>
<tab label="${i18n:_('Edit')}"></tab>
</tabs>
<tabpanels>
<tabpanel>
<grid fixedLayout="true">
<columns>
<column width="200px" />
<column />
</columns>
<rows>
<row>
<label value="${i18n:_('Code')}"/>
<textbox
id="codeTextBox"
value="@{controller.unitType.code}"
constraint="@{controller.uniqueCode}"
width="300px"/>
</row>
<row>
<label value="${i18n:_('Unit measure name')}" />
<textbox
id="measureTextBox"
value="@{controller.unitType.measure}"
constraint="@{controller.uniqueMeasureName}"
width="300px"/>
</row>
</rows>
</grid>
</tabpanel>
</tabpanels>
</tabbox>
<button onClick="controller.saveAndExit();"
label="${arg.save_button_label}"
sclass="save-button global-action"/>
<button onClick="controller.saveAndContinue();"
label="${arg.save_and_continue_button_label}"
sclass="save-button global-action"/>
<button onClick="controller.cancel();"
label="${arg.cancel_button_label}"
sclass="cancel-button global-action"/>
</window>

View file

@ -0,0 +1,34 @@
<!--
This file is part of NavalPlan
Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
Desenvolvemento Tecnolóxico de Galicia
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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<window id="${arg.top_id}" title="${i18n:_('Unit type list')}">
<newdatasortablegrid id="listing" model="@{controller.unitTypes}" mold="paging"
pageSize="10" fixedLayout="true"
rowRenderer="@{controller.unitTypeRenderer}" >
<columns>
<newdatasortablecolumn label="${i18n:_('Unit Measure')}"
sortDirection="ascending" sort="auto(measure)"/>
<newdatasortablecolumn label="${i18n:_('Operations')}"/>
</columns>
</newdatasortablegrid>
<button id="show_create_form" onClick="controller.goToEditFormInCreationMode();" label="${i18n:_('Create')}"
sclass="create-button global-action">
</button>
</window>

View file

@ -0,0 +1,44 @@
<!--
This file is part of NavalPlan
Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e
Desenvolvemento Tecnolóxico de Galicia
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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<?page title="${i18n:_('NavalPlan: Unit types')}" id="unitTypes"?>
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
<?init class="org.zkoss.zk.ui.util.Composition" arg0="/common/layout/template.zul"?>
<?link rel="stylesheet" type="text/css" href="/common/css/navalplan.css"?>
<?link rel="stylesheet" type="text/css" href="/common/css/navalplan_zk.css"?>
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<?component name="list" inline="true" macroURI="_listUnitTypes.zul"?>
<?component name="edition" inline="true" macroURI="_editUnitType.zul"?>
<zk>
<window self="@{define(content)}"
apply="org.navalplanner.web.materials.UnitTypeController">
<vbox id="messagesContainer"/>
<list top_id="listWindow"/>
<edition top_id="editWindow"
title="${i18n:_('Edit unit type data')}"
save_button_label="${i18n:_('Save')}"
save_and_continue_button_label="${i18n:_('Save &amp; Continue')}"
cancel_button_label="${i18n:_('Cancel')}"
/>
</window>
</zk>