Merge branch 'personal-timesheets-periodicity'

This commit is contained in:
Manuel Rego Casasnovas 2012-09-03 08:13:47 +02:00
commit be439d08d1
43 changed files with 887 additions and 373 deletions

View file

@ -109,8 +109,9 @@ public class Configuration extends BaseEntity {
private String currencyCode = "EUR";
private String currencySymbol = "";
private TypeOfWorkHours monthlyTimesheetsTypeOfWorkHours;
private TypeOfWorkHours personalTimesheetsTypeOfWorkHours;
private PersonalTimesheetsPeriodicityEnum personalTimesheetsPeriodicity = PersonalTimesheetsPeriodicityEnum.MONTHLY;
public void setDefaultCalendar(BaseCalendar defaultCalendar) {
this.defaultCalendar = defaultCalendar;
@ -451,13 +452,22 @@ public class Configuration extends BaseEntity {
this.currencySymbol = currencySymbol;
}
public TypeOfWorkHours getMonthlyTimesheetsTypeOfWorkHours() {
return monthlyTimesheetsTypeOfWorkHours;
public TypeOfWorkHours getPersonalTimesheetsTypeOfWorkHours() {
return personalTimesheetsTypeOfWorkHours;
}
public void setMonthlyTimesheetsTypeOfWorkHours(
public void setPersonalTimesheetsTypeOfWorkHours(
TypeOfWorkHours typeOfWorkHours) {
monthlyTimesheetsTypeOfWorkHours = typeOfWorkHours;
personalTimesheetsTypeOfWorkHours = typeOfWorkHours;
}
public PersonalTimesheetsPeriodicityEnum getPersonalTimesheetsPeriodicity() {
return personalTimesheetsPeriodicity;
}
public void setPersonalTimesheetsPeriodicity(
PersonalTimesheetsPeriodicityEnum personalTimesheetsPeriodicity) {
this.personalTimesheetsPeriodicity = personalTimesheetsPeriodicity;
}
}

View file

@ -22,11 +22,11 @@ package org.libreplan.business.common.entities;
import org.libreplan.business.IDataBootstrap;
/**
* Contract for {@link MonthlyTimesheetsTypeOfWorkHoursBootstrap}.
* Contract for {@link PersonalTimesheetsTypeOfWorkHoursBootstrap}.
*
* @author Manuel Rego Casasnovas <mrego@igalia.com>
*/
public interface IMonthlyTimesheetsTypeOfWorkHoursBootstrap extends
public interface IPersonalTimesheetsTypeOfWorkHoursBootstrap extends
IDataBootstrap {
void loadRequiredData();

View file

@ -0,0 +1,201 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2012 Igalia, S.L.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* 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/>.
*/
package org.libreplan.business.common.entities;
import static org.libreplan.business.i18n.I18nHelper._;
import org.joda.time.LocalDate;
import org.joda.time.Months;
import org.joda.time.Weeks;
/**
* Different values for personal timesheets periodicity.
*
* @author Manuel Rego Casasnovas <rego@igalia.com>
*/
public enum PersonalTimesheetsPeriodicityEnum {
MONTHLY(_("Monthly")) {
@Override
public LocalDate getStart(LocalDate date) {
return date.dayOfMonth().withMinimumValue();
}
@Override
public LocalDate getEnd(LocalDate date) {
return date.dayOfMonth().withMaximumValue();
}
@Override
public int getItemsBetween(LocalDate start, LocalDate end) {
return Months.monthsBetween(start, end).getMonths();
}
@Override
public LocalDate getDateForItemFromDate(int item, LocalDate fromDate) {
return fromDate.plusMonths(item);
}
@Override
public LocalDate previous(LocalDate date) {
return getStart(date).minusMonths(1);
}
@Override
public LocalDate next(LocalDate date) {
return getStart(date).plusMonths(1);
}
},
TWICE_MONTHLY(_("Twice-monthly")) {
@Override
public LocalDate getStart(LocalDate date) {
if (date.getDayOfMonth() <= 15) {
return date.dayOfMonth().withMinimumValue();
} else {
return date.dayOfMonth().withMinimumValue().plusDays(15);
}
}
@Override
public LocalDate getEnd(LocalDate date) {
if (date.getDayOfMonth() <= 15) {
return date.dayOfMonth().withMinimumValue().plusDays(14);
} else {
return date.dayOfMonth().withMaximumValue();
}
}
@Override
public int getItemsBetween(LocalDate start, LocalDate end) {
return Months.monthsBetween(start, end).getMonths() * 2;
}
@Override
public LocalDate getDateForItemFromDate(int item, LocalDate fromDate) {
int months = (item % 2 == 0) ? (item / 2) : ((item - 1) / 2);
LocalDate date = fromDate.plusMonths(months);
if (item % 2 != 0) {
if (date.getDayOfMonth() <= 15) {
date = date.dayOfMonth().withMinimumValue().plusDays(15);
} else {
date = date.plusMonths(1).dayOfMonth().withMinimumValue();
}
}
return date;
}
@Override
public LocalDate previous(LocalDate date) {
if (date.getDayOfMonth() <= 15) {
return date.minusMonths(1).dayOfMonth().withMinimumValue()
.plusDays(15);
} else {
return date.dayOfMonth().withMinimumValue();
}
}
@Override
public LocalDate next(LocalDate date) {
if (date.getDayOfMonth() <= 15) {
return date.dayOfMonth().withMinimumValue().plusDays(15);
} else {
return date.plusMonths(1).dayOfMonth().withMinimumValue();
}
}
},
WEEKLY(_("Weekly")) {
@Override
public LocalDate getStart(LocalDate date) {
return date.dayOfWeek().withMinimumValue();
}
@Override
public LocalDate getEnd(LocalDate date) {
return date.dayOfWeek().withMaximumValue();
}
@Override
public int getItemsBetween(LocalDate start, LocalDate end) {
return Weeks.weeksBetween(start, end).getWeeks();
}
@Override
public LocalDate getDateForItemFromDate(int item, LocalDate fromDate) {
return fromDate.plusWeeks(item);
}
@Override
public LocalDate previous(LocalDate date) {
return getStart(date).minusWeeks(1);
}
@Override
public LocalDate next(LocalDate date) {
return getStart(date).plusWeeks(1);
}
};
private String name;
private PersonalTimesheetsPeriodicityEnum(String name) {
this.name = name;
}
public String getName() {
return name;
}
/**
* Returns the start date of the personal timesheet which includes the
* specified <code>date</code>.
*/
public abstract LocalDate getStart(LocalDate date);
/**
* Returns the end date of the personal timesheet which includes the
* specified <code>date</code>.
*/
public abstract LocalDate getEnd(LocalDate date);
/**
* Returns the number of personal timesheets between the specified dates.
*/
public abstract int getItemsBetween(LocalDate start, LocalDate end);
/**
* Returns the date of the personal timesheet in the position specified by
* <code>item</code> taking into account the <code>fromDate</code>.
*/
public abstract LocalDate getDateForItemFromDate(int item,
LocalDate fromDate);
/**
* Returns the date of the previous personal timesheet to the one which
* includes the specified <code>date</code>.
*/
public abstract LocalDate previous(LocalDate date);
/**
* Returns the date of the next personal timesheet to the one which includes
* the specified <code>date</code>.
*/
public abstract LocalDate next(LocalDate date);
}

View file

@ -32,7 +32,7 @@ import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
/**
* Fills the attribute {@link Configuration#monthlyTimesheetsTypeOfWorkHours}
* Fills the attribute {@link Configuration#personalTimesheetsTypeOfWorkHours}
* with a default value.<br />
*
* If possible it uses the "Default" {@link TypeOfWorkHours}, but if it doesn't
@ -47,8 +47,8 @@ import org.springframework.transaction.annotation.Transactional;
@Component
@Scope("singleton")
@BootstrapOrder(1)
public class MonthlyTimesheetsTypeOfWorkHoursBootstrap implements
IMonthlyTimesheetsTypeOfWorkHoursBootstrap {
public class PersonalTimesheetsTypeOfWorkHoursBootstrap implements
IPersonalTimesheetsTypeOfWorkHoursBootstrap {
@Autowired
private IConfigurationDAO configurationDAO;
@ -73,7 +73,7 @@ public class MonthlyTimesheetsTypeOfWorkHoursBootstrap implements
typeOfWorkHours = typeOfWorkHoursDAO.findActive().get(0);
}
configuration.setMonthlyTimesheetsTypeOfWorkHours(typeOfWorkHours);
configuration.setPersonalTimesheetsTypeOfWorkHours(typeOfWorkHours);
configurationDAO.save(configuration);
}

View file

@ -148,7 +148,7 @@ public class TypeOfWorkHoursDAO extends IntegrationEntityDAO<TypeOfWorkHours>
public void checkIsReferencedByOtherEntities(TypeOfWorkHours type) throws ValidationException {
checkHasHourCost(type);
checkHasWorkReportLine(type);
checkIsMonthlyTimesheetsTypeOfWorkHours(type);
checkIsPersonalTimesheetsTypeOfWorkHours(type);
}
private void checkHasWorkReportLine(TypeOfWorkHours type) {
@ -174,13 +174,13 @@ public class TypeOfWorkHoursDAO extends IntegrationEntityDAO<TypeOfWorkHours>
}
}
private void checkIsMonthlyTimesheetsTypeOfWorkHours(TypeOfWorkHours type) {
private void checkIsPersonalTimesheetsTypeOfWorkHours(TypeOfWorkHours type) {
Configuration configuration = configurationDAO.getConfiguration();
if (configuration.getMonthlyTimesheetsTypeOfWorkHours().getId()
if (configuration.getPersonalTimesheetsTypeOfWorkHours().getId()
.equals(type.getId())) {
throw ValidationException
.invalidValue(
"Cannot delete the type of work hours. It is configured as type of work hours for monthly timesheets.",
"Cannot delete the type of work hours. It is configured as type of work hours for personal timesheets.",
type);
}
}

View file

@ -143,11 +143,11 @@ public class TypeOfWorkHours extends IntegrationEntity implements IHumanIdentifi
}
}
@AssertTrue(message = "type of work hours for monthly timesheets cannot be disabled")
public boolean checkMonthlyTimesheetsTypeOfWorkHoursNotDisabled() {
@AssertTrue(message = "type of work hours for personal timesheets cannot be disabled")
public boolean checkPersonalTimesheetsTypeOfWorkHoursNotDisabled() {
if (!isNewObject() && !getEnabled()) {
TypeOfWorkHours typeOfWorkHours = Registry.getConfigurationDAO()
.getConfiguration().getMonthlyTimesheetsTypeOfWorkHours();
.getConfiguration().getPersonalTimesheetsTypeOfWorkHours();
if (typeOfWorkHours.getId().equals(getId())) {
return false;
}

View file

@ -25,6 +25,7 @@ import java.util.List;
import org.joda.time.LocalDate;
import org.libreplan.business.common.daos.IIntegrationEntityDAO;
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
import org.libreplan.business.resources.entities.Resource;
import org.libreplan.business.workreports.entities.WorkReport;
import org.libreplan.business.workreports.entities.WorkReportType;
@ -47,11 +48,15 @@ public interface IWorkReportDAO extends IIntegrationEntityDAO<WorkReport> {
int getLastReportYear();
/**
* Returns the {@link WorkReport} of the predefined type monthly timesheet
* for the given <code>resource</code> in the specified <code>date</code>.<br />
* Returns the {@link WorkReport} of the predefined type personal timesheet
* for the given <code>resource</code> in the specified <code>date</code>
* depending on the configured <code>periodicity</code>.<br />
*
* If there isn't any, it returns <code>null</code>.
*/
WorkReport getMonthlyTimesheetWorkReport(Resource resource, LocalDate date);
WorkReport getPersonalTimesheetWorkReport(Resource resource, LocalDate date,
PersonalTimesheetsPeriodicityEnum periodicity);
boolean isAnyPersonalTimesheetAlreadySaved();
}

View file

@ -36,6 +36,7 @@ import org.joda.time.LocalDate;
import org.libreplan.business.common.IAdHocTransactionService;
import org.libreplan.business.common.IOnTransaction;
import org.libreplan.business.common.daos.IntegrationEntityDAO;
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.orders.daos.IOrderDAO;
import org.libreplan.business.orders.entities.OrderElement;
@ -140,12 +141,12 @@ public class WorkReportDAO extends IntegrationEntityDAO<WorkReport>
@Override
@SuppressWarnings("unchecked")
public WorkReport getMonthlyTimesheetWorkReport(Resource resource,
LocalDate date) {
public WorkReport getPersonalTimesheetWorkReport(Resource resource,
LocalDate date, PersonalTimesheetsPeriodicityEnum periodicity) {
WorkReportType workReportType;
try {
workReportType = workReportTypeDAO
.findUniqueByName(PredefinedWorkReportTypes.MONTHLY_TIMESHEETS
.findUniqueByName(PredefinedWorkReportTypes.PERSONAL_TIMESHEETS
.getName());
} catch (NonUniqueResultException e) {
throw new RuntimeException(e);
@ -155,17 +156,21 @@ public class WorkReportDAO extends IntegrationEntityDAO<WorkReport>
Criteria criteria = getSession().createCriteria(WorkReport.class);
criteria.add(Restrictions.eq("workReportType", workReportType));
List<WorkReport> monthlyTimesheets = criteria.add(
List<WorkReport> personalTimesheets = criteria.add(
Restrictions.eq("resource", resource)).list();
for (WorkReport workReport : monthlyTimesheets) {
LocalDate start = periodicity.getStart(date);
LocalDate end = periodicity.getEnd(date);
for (WorkReport workReport : personalTimesheets) {
Set<WorkReportLine> workReportLines = workReport
.getWorkReportLines();
if (workReportLines.size() > 0) {
Date workReportDate = workReportLines.iterator().next()
.getDate();
if (LocalDate.fromDateFields(workReportDate).monthOfYear()
.equals(date.monthOfYear())) {
LocalDate workReportDate = LocalDate
.fromDateFields(workReportLines.iterator().next()
.getDate());
if (workReportDate.compareTo(start) >= 0
&& workReportDate.compareTo(end) <= 0) {
return workReport;
}
}
@ -174,4 +179,22 @@ public class WorkReportDAO extends IntegrationEntityDAO<WorkReport>
return null;
}
@Override
public boolean isAnyPersonalTimesheetAlreadySaved() {
WorkReportType workReportType;
try {
workReportType = workReportTypeDAO
.findUniqueByName(PredefinedWorkReportTypes.PERSONAL_TIMESHEETS
.getName());
} catch (NonUniqueResultException e) {
throw new RuntimeException(e);
} catch (InstanceNotFoundException e) {
throw new RuntimeException(e);
}
Criteria criteria = getSession().createCriteria(WorkReport.class);
criteria.add(Restrictions.eq("workReportType", workReportType));
return criteria.list().isEmpty();
}
}

View file

@ -27,7 +27,7 @@ package org.libreplan.business.workreports.entities;
*/
public enum PredefinedWorkReportTypes {
DEFAULT("Default", false, false, false),
MONTHLY_TIMESHEETS("Monthly timesheets", false, true, false);
PERSONAL_TIMESHEETS("Personal timesheets", false, true, false);
private WorkReportType workReportType;

View file

@ -34,10 +34,10 @@ import org.hibernate.validator.AssertTrue;
import org.hibernate.validator.NotNull;
import org.hibernate.validator.Valid;
import org.joda.time.LocalDate;
import org.joda.time.LocalDate.Property;
import org.libreplan.business.common.IntegrationEntity;
import org.libreplan.business.common.Registry;
import org.libreplan.business.common.entities.EntitySequence;
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.labels.entities.Label;
import org.libreplan.business.labels.entities.LabelType;
@ -470,9 +470,9 @@ public class WorkReport extends IntegrationEntity implements
return result;
}
@AssertTrue(message = "only one timesheet line per day and task is allowed in monthly timesheets")
public boolean checkConstraintOnlyOneWorkReportLinePerDayAndOrderElementInMonthlyTimesheet() {
if (!getWorkReportType().isMonthlyTimesheetsType()) {
@AssertTrue(message = "only one timesheet line per day and task is allowed in personal timesheets")
public boolean checkConstraintOnlyOneWorkReportLinePerDayAndOrderElementInPersonalTimesheet() {
if (!getWorkReportType().isPersonalTimesheetsType()) {
return true;
}
@ -492,9 +492,9 @@ public class WorkReport extends IntegrationEntity implements
return true;
}
@AssertTrue(message = "In monthly timesheets, all timesheet lines should be in the same month")
public boolean checkConstraintAllWorkReportLinesInTheSameMonthInMonthlyTimesheet() {
if (!getWorkReportType().isMonthlyTimesheetsType()) {
@AssertTrue(message = "In personal timesheets, all timesheet lines should be in the same period")
public boolean checkConstraintAllWorkReportLinesInTheSamePeriodInPersonalTimesheet() {
if (!getWorkReportType().isPersonalTimesheetsType()) {
return true;
}
@ -502,10 +502,14 @@ public class WorkReport extends IntegrationEntity implements
return true;
}
Property dayOfMonth = LocalDate.fromDateFields(
workReportLines.iterator().next().getDate()).dayOfMonth();
LocalDate min = dayOfMonth.withMinimumValue();
LocalDate max = dayOfMonth.withMaximumValue();
LocalDate workReportDate = LocalDate.fromDateFields(workReportLines
.iterator().next().getDate());
PersonalTimesheetsPeriodicityEnum periodicity = Registry
.getConfigurationDAO()
.getConfigurationWithReadOnlyTransaction()
.getPersonalTimesheetsPeriodicity();
LocalDate min = periodicity.getStart(workReportDate);
LocalDate max = periodicity.getEnd(workReportDate);
for (WorkReportLine line : workReportLines) {
LocalDate date = LocalDate.fromDateFields(line.getDate());
@ -516,9 +520,9 @@ public class WorkReport extends IntegrationEntity implements
return true;
}
@AssertTrue(message = "resource has to be bound to a user in monthly timesheets")
public boolean checkConstraintResourceIsBoundInMonthlyTimesheet() {
if (!getWorkReportType().isMonthlyTimesheetsType()) {
@AssertTrue(message = "resource has to be bound to a user in personal timesheets")
public boolean checkConstraintResourceIsBoundInPersonalTimesheet() {
if (!getWorkReportType().isPersonalTimesheetsType()) {
return true;
}

View file

@ -524,11 +524,11 @@ public class WorkReportType extends IntegrationEntity implements IHumanIdentifia
return name;
}
public boolean isMonthlyTimesheetsType() {
public boolean isPersonalTimesheetsType() {
if (StringUtils.isBlank(name)) {
return false;
}
return name.equals(PredefinedWorkReportTypes.MONTHLY_TIMESHEETS
return name.equals(PredefinedWorkReportTypes.PERSONAL_TIMESHEETS
.getName());
}

View file

@ -35,7 +35,7 @@ import org.springframework.transaction.annotation.Transactional;
* If there is no work report types, it creates a default work report type.<br />
*
* Even if there are already some work report types defined, it creates a work
* report type for monthly timesheets if it is not present in the database yet.
* report type for personal timesheets if it is not present in the database yet.
*
* @author Ignacio Díaz Teijido <ignacio.diaz@cafedered.com>
* @author Manuel Rego Casasnovas <rego@igalia.com>
@ -59,7 +59,7 @@ public class WorkReportTypeBootstrap implements IWorkReportTypeBootstrap {
createAndSaveWorkReportType(predefinedWorkReportType);
}
} else {
createMonthlyTimesheetsWorkReportTypeIfNeeded();
createPersonalTimesheetsWorkReportTypeIfNeeded();
}
}
@ -74,15 +74,15 @@ public class WorkReportTypeBootstrap implements IWorkReportTypeBootstrap {
workReportTypeDAO.save(workReportType);
}
private void createMonthlyTimesheetsWorkReportTypeIfNeeded() {
private void createPersonalTimesheetsWorkReportTypeIfNeeded() {
try {
workReportTypeDAO
.findUniqueByName(PredefinedWorkReportTypes.MONTHLY_TIMESHEETS
.findUniqueByName(PredefinedWorkReportTypes.PERSONAL_TIMESHEETS
.getName());
} catch (NonUniqueResultException e) {
throw new RuntimeException(e);
} catch (InstanceNotFoundException e) {
createAndSaveWorkReportType(PredefinedWorkReportTypes.MONTHLY_TIMESHEETS);
createAndSaveWorkReportType(PredefinedWorkReportTypes.PERSONAL_TIMESHEETS);
}
}

View file

@ -16,4 +16,44 @@
<sql>ALTER TABLE task_element MODIFY notes TEXT</sql>
</changeSet>
</databaseChangeLog>
<changeSet id="update-work_report_type-name-to-personal-timehseets"
author="mrego">
<comment>
Update work_report_type name from "Monthly timesheets" to "Personal
timehsheets"
</comment>
<update tableName="work_report_type">
<column name="name" value="Personal timesheets"/>
<where>name='Monthly timesheets'</where>
</update>
</changeSet>
<changeSet id="add-personal_timesheets_periodicity-column-to-configuration"
author="mrego">
<comment>Add personal_timesheets_periodicity column to configuration</comment>
<addColumn tableName="configuration">
<column name="personal_timesheets_periodicity" type="INTEGER" />
</addColumn>
<update tableName="configuration">
<column name="personal_timesheets_periodicity" value="0" />
</update>
</changeSet>
<changeSet id="rename-column-from-monthly-to-personal-in-configuration"
author="mrego">
<comment>
Rename column monthly_timesheets_type_of_work_hours to
personal_timesheets_type_of_work_hours in configuration table
</comment>
<dropForeignKeyConstraint baseTableName="configuration"
constraintName="configuration_type_of_work_hours_fkey"/>
<renameColumn tableName="configuration"
oldColumnName="monthly_timesheets_type_of_work_hours"
newColumnName="personal_timesheets_type_of_work_hours"
columnDataType="BIGINT" />
<addForeignKeyConstraint constraintName="configuration_type_of_work_hours_fkey"
baseTableName="configuration" baseColumnNames="personal_timesheets_type_of_work_hours"
referencedTableName="type_of_work_hours" referencedColumnNames="id" />
</changeSet>
</databaseChangeLog>

View file

@ -79,8 +79,14 @@
<property name="currencyCode" not-null="true" column="currency_code" />
<property name="currencySymbol" not-null="true" column="currency_symbol" />
<many-to-one name="monthlyTimesheetsTypeOfWorkHours" cascade="none"
column="monthly_timesheets_type_of_work_hours" />
<many-to-one name="personalTimesheetsTypeOfWorkHours" cascade="none"
column="personal_timesheets_type_of_work_hours" />
<property name="personalTimesheetsPeriodicity" column="personal_timesheets_periodicity">
<type name="org.hibernate.type.EnumType">
<param name="enumClass">org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum</param>
</type>
</property>
<component name="ldapConfiguration" class="org.libreplan.business.common.entities.LDAPConfiguration">
<property name="ldapHost" column="ldap_host"/>

View file

@ -40,6 +40,7 @@ import org.libreplan.business.common.entities.Configuration;
import org.libreplan.business.common.entities.EntityNameEnum;
import org.libreplan.business.common.entities.EntitySequence;
import org.libreplan.business.common.entities.LDAPConfiguration;
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
import org.libreplan.business.common.entities.ProgressType;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.costcategories.entities.TypeOfWorkHours;
@ -869,13 +870,49 @@ public class ConfigurationController extends GenericForwardComposer {
configurationModel.setCurrency(currencyCode);
}
public TypeOfWorkHours getMonthlyTimesheetsTypeOfWorkHours() {
return configurationModel.getMonthlyTimesheetsTypeOfWorkHours();
public TypeOfWorkHours getPersonalTimesheetsTypeOfWorkHours() {
return configurationModel.getPersonalTimesheetsTypeOfWorkHours();
}
public void setMonthlyTimesheetsTypeOfWorkHours(
public void setPersonalTimesheetsTypeOfWorkHours(
TypeOfWorkHours typeOfWorkHours) {
configurationModel.setMonthlyTimesheetsTypeOfWorkHours(typeOfWorkHours);
configurationModel.setPersonalTimesheetsTypeOfWorkHours(typeOfWorkHours);
}
public List<PersonalTimesheetsPeriodicityEnum> getPersonalTimesheetsPeriodicities() {
return Arrays.asList(PersonalTimesheetsPeriodicityEnum.values());
}
public ListitemRenderer getPersonalTimesheetsPeriodicityRenderer() {
return new ListitemRenderer() {
@Override
public void render(Listitem item, Object data) throws Exception {
PersonalTimesheetsPeriodicityEnum periodicity = (PersonalTimesheetsPeriodicityEnum) data;
item.setLabel(_(periodicity.getName()));
item.setValue(periodicity);
}
};
}
public PersonalTimesheetsPeriodicityEnum getSelectedPersonalTimesheetsPeriodicity() {
return configurationModel.getPersonalTimesheetsPeriodicity();
}
public void setSelectedPersonalTimesheetsPeriodicity(
PersonalTimesheetsPeriodicityEnum personalTimesheetsPeriodicity) {
configurationModel
.setPersonalTimesheetsPeriodicity(personalTimesheetsPeriodicity);
}
public boolean isPersonalTimesheetsPeriodicityDisabled() {
return configurationModel.isAnyPersonalTimesheetAlreadySaved();
}
public String getPersonalTimesheetsPeriodicityTooltip() {
if (isPersonalTimesheetsPeriodicityDisabled()) {
return _("Periocity cannot be changed because there is already any personal timesheet stored");
}
return "";
}
}

View file

@ -43,10 +43,12 @@ import org.libreplan.business.common.entities.Configuration;
import org.libreplan.business.common.entities.EntityNameEnum;
import org.libreplan.business.common.entities.EntitySequence;
import org.libreplan.business.common.entities.LDAPConfiguration;
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
import org.libreplan.business.common.entities.ProgressType;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.costcategories.entities.TypeOfWorkHours;
import org.libreplan.business.workreports.daos.IWorkReportDAO;
import org.libreplan.web.common.concurrentdetection.OnConcurrentModification;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
@ -82,6 +84,9 @@ public class ConfigurationModel implements IConfigurationModel {
@Autowired
private IEntitySequenceDAO entitySequenceDAO;
@Autowired
private IWorkReportDAO workReportDAO;
@Override
@Transactional(readOnly = true)
public List<BaseCalendar> getCalendars() {
@ -132,7 +137,7 @@ public class ConfigurationModel implements IConfigurationModel {
private void forceLoad(Configuration configuration) {
forceLoad(configuration.getDefaultCalendar());
forceLoad(configuration.getMonthlyTimesheetsTypeOfWorkHours());
forceLoad(configuration.getPersonalTimesheetsTypeOfWorkHours());
}
private void forceLoad(BaseCalendar calendar) {
@ -622,16 +627,34 @@ public class ConfigurationModel implements IConfigurationModel {
}
@Override
public TypeOfWorkHours getMonthlyTimesheetsTypeOfWorkHours() {
return configuration.getMonthlyTimesheetsTypeOfWorkHours();
public TypeOfWorkHours getPersonalTimesheetsTypeOfWorkHours() {
return configuration.getPersonalTimesheetsTypeOfWorkHours();
}
@Override
public void setMonthlyTimesheetsTypeOfWorkHours(
public void setPersonalTimesheetsTypeOfWorkHours(
TypeOfWorkHours typeOfWorkHours) {
if (configuration != null) {
configuration.setMonthlyTimesheetsTypeOfWorkHours(typeOfWorkHours);
configuration.setPersonalTimesheetsTypeOfWorkHours(typeOfWorkHours);
}
}
@Override
public PersonalTimesheetsPeriodicityEnum getPersonalTimesheetsPeriodicity() {
return configuration.getPersonalTimesheetsPeriodicity();
}
@Override
public void setPersonalTimesheetsPeriodicity(
PersonalTimesheetsPeriodicityEnum personalTimesheetsPeriodicity) {
configuration
.setPersonalTimesheetsPeriodicity(personalTimesheetsPeriodicity);
}
@Override
@Transactional(readOnly = true)
public boolean isAnyPersonalTimesheetAlreadySaved() {
return !workReportDAO.isAnyPersonalTimesheetAlreadySaved();
}
}

View file

@ -28,6 +28,7 @@ import org.libreplan.business.calendars.entities.BaseCalendar;
import org.libreplan.business.common.entities.EntityNameEnum;
import org.libreplan.business.common.entities.EntitySequence;
import org.libreplan.business.common.entities.LDAPConfiguration;
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
import org.libreplan.business.common.entities.ProgressType;
import org.libreplan.business.costcategories.entities.TypeOfWorkHours;
@ -168,8 +169,15 @@ public interface IConfigurationModel {
void setCurrency(String currencyCode);
TypeOfWorkHours getMonthlyTimesheetsTypeOfWorkHours();
TypeOfWorkHours getPersonalTimesheetsTypeOfWorkHours();
void setMonthlyTimesheetsTypeOfWorkHours(TypeOfWorkHours typeOfWorkHours);
void setPersonalTimesheetsTypeOfWorkHours(TypeOfWorkHours typeOfWorkHours);
PersonalTimesheetsPeriodicityEnum getPersonalTimesheetsPeriodicity();
void setPersonalTimesheetsPeriodicity(
PersonalTimesheetsPeriodicityEnum personalTimesheetsPeriodicity);
boolean isAnyPersonalTimesheetAlreadySaved();
}

View file

@ -21,6 +21,8 @@ package org.libreplan.web.users.dashboard;
import java.util.List;
import org.libreplan.business.common.entities.Configuration;
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
import org.libreplan.business.planner.entities.SpecificResourceAllocation;
import org.libreplan.business.planner.entities.Task;
import org.libreplan.business.planner.entities.TaskElement;
@ -40,4 +42,10 @@ public interface IMyTasksAreaModel {
*/
List<Task> getTasks();
/**
* Returns the {@link PersonalTimesheetsPeriodicityEnum} from
* {@link Configuration}.
*/
PersonalTimesheetsPeriodicityEnum getPersonalTimesheetsPeriodicity();
}

View file

@ -25,12 +25,12 @@ import org.libreplan.web.common.entrypoints.EntryPoint;
import org.libreplan.web.common.entrypoints.EntryPoints;
/**
* Entry points for monthly timesheet creation/edition window
* Entry points for personal timesheet creation/edition window
*
* @author Manuel Rego Casasnovas <mrego@igalia.com>
*/
@EntryPoints(page = "/myaccount/monthlyTimesheet.zul", registerAs = "monthlyTimesheetController")
public interface IMonthlyTimesheetController {
@EntryPoints(page = "/myaccount/personalTimesheet.zul", registerAs = "personalTimesheetController")
public interface IPersonalTimesheetController {
@EntryPoint("date")
void goToCreateOrEditForm(LocalDate date);

View file

@ -22,6 +22,8 @@ package org.libreplan.web.users.dashboard;
import java.util.List;
import org.joda.time.LocalDate;
import org.libreplan.business.common.entities.Configuration;
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.resources.entities.Resource;
@ -30,40 +32,38 @@ import org.libreplan.business.workingday.EffortDuration;
import org.libreplan.business.workreports.entities.WorkReport;
/**
* Interface for creation/edition of a monthly timesheet model
* Interface for creation/edition of a personal timesheet model
*
* @author Manuel Rego Casasnovas <mrego@igalia.com>
*/
public interface IMonthlyTimesheetModel {
public interface IPersonalTimesheetModel {
/**
* Edits the monthly timesheet for the specified <code>date</code> and
* Edits the personal timesheet for the specified <code>date</code> and
* resource bound to current user or creates a new one if it doesn't exist
* yet.
*/
void initCreateOrEdit(LocalDate date);
/**
* Edits the monthly timesheet for the specified <code>date</code> and
* Edits the personal timesheet for the specified <code>date</code> and
* resource bound to the {@link Worker} specified by the
* <code>resource</code> or creates a new one if it doesn't exist yet.
*/
void initCreateOrEdit(LocalDate date, Resource resource);
/**
* Returns the date of the monthly timesheet (only year and month should
* take into account as the day is not important to define a monthly
* timesheet).
* Returns the date of the personal timesheet.
*/
LocalDate getDate();
/**
* Returns the first day of the month of the current monthly timesheet.
* Returns the first day of the current personal timesheet.
*/
LocalDate getFirstDay();
/**
* Returns the last day of the month of the current monthly timesheet.
* Returns the last day of the current personal timesheet.
*/
LocalDate getLastDate();
@ -79,45 +79,45 @@ public interface IMonthlyTimesheetModel {
List<OrderElement> getOrderElements();
/**
* Returns the {@link EffortDuration} in the current monthly timesheet for
* Returns the {@link EffortDuration} in the current personal timesheet for
* the specified <code>orderElement</code> and <code>date</code>.
*/
EffortDuration getEffortDuration(OrderElement orderElement, LocalDate date);
/**
* Sets the {@link EffortDuration} in the current monthly timesheet for the
* Sets the {@link EffortDuration} in the current personal timesheet for the
* specified <code>orderElement</code> and <code>date</code>.<br />
*
* Marks the current monthly timesheet as modified.
* Marks the current personal timesheet as modified.
*/
void setEffortDuration(OrderElement orderElement, LocalDate date,
EffortDuration effortDuration);
/**
* Save {@link WorkReport} for the monthly timesheet.
* Save {@link WorkReport} for the personal timesheet.
*/
void save();
/**
* Cancel changes in {@link WorkReport} for the monthly timesheet.
* Cancel changes in {@link WorkReport} for the personal timesheet.
*/
void cancel();
/**
* Returns the {@link EffortDuration} in the current monthly timesheet for
* Returns the {@link EffortDuration} in the current personal timesheet for
* the specified <code>orderElement</code>.
*/
EffortDuration getEffortDuration(OrderElement orderElement);
/**
* Returns the {@link EffortDuration} for all the {@link OrderElement
* OrderElements} in the current monthly timesheet in the specified
* OrderElements} in the current personal timesheet in the specified
* <code>date</code>.
*/
EffortDuration getEffortDuration(LocalDate date);
/**
* Returns the total {@link EffortDuration} for the currently monthly
* Returns the total {@link EffortDuration} for the currently personal
* timesheet.
*/
EffortDuration getTotalEffortDuration();
@ -129,7 +129,7 @@ public interface IMonthlyTimesheetModel {
EffortDuration getResourceCapacity(LocalDate date);
/**
* Adds the <code>orderElement</code> to the current monthly timehseet.
* Adds the <code>orderElement</code> to the current personal timehseet.
*/
void addOrderElement(OrderElement orderElement);
@ -140,22 +140,22 @@ public interface IMonthlyTimesheetModel {
Order getOrder(OrderElement orderElement);
/**
* Returns <code>true</code> if current monthly timesheet has been modified
* Returns <code>true</code> if current personal timesheet has been modified
* by the user.
*/
boolean isModified();
/**
* Checks if current monthly timesheet is the first month, that means the
* Checks if current personal timesheet is the first period, that means the
* first activation period of the resource.
*/
boolean isFirstMonth();
boolean isFirstPeriod();
/**
* Checks if current monthly timesheet is the last month, that means the
* Checks if current personal timesheet is the last period, that means the
* next month of current date.
*/
boolean isLastMonth();
boolean isLastPeriod();
/**
* Returns true if the value for the specified <code>orderElement</code> in
@ -165,7 +165,7 @@ public interface IMonthlyTimesheetModel {
/**
* Returns <code>true</code> or <code>false</code> depending on if it's
* editing a monthly timesheet of the current user or not.<br />
* editing a personal timesheet of the current user or not.<br />
*
* That means if you entered via:
* <ul>
@ -177,30 +177,54 @@ public interface IMonthlyTimesheetModel {
boolean isCurrentUser();
/**
* Returns <code>true</code> if the resource of the current monthly
* Returns <code>true</code> if the resource of the current personal
* timesheet has any effort reported in other {@link WorkReport WorkReports}
* in the month of the timesheet.
* in the period of the timesheet.
*/
boolean hasOtherReports();
/**
* Returns the {@link EffortDuration} of the specified
* <code>orderElement</code> from other {@link WorkReport WorkReports} for
* the current resource in the month of the timesheet.<br />
* the current resource in the period of the timesheet.<br />
*/
EffortDuration getOtherEffortDuration(OrderElement orderElement);
/**
* Returns the {@link EffortDuration} in the specified <code>date</code>
* from other {@link WorkReport WorkReports} for the current resource in the
* month of the timesheet.
* period of the timesheet.
*/
EffortDuration getOtherEffortDuration(LocalDate date);
/**
* Returns the total {@link EffortDuration} from other {@link WorkReport
* WorkReports} for the current resource in the month of the timesheet.
* WorkReports} for the current resource in the period of the timesheet.
*/
EffortDuration getTotalOtherEffortDuration();
/**
* Returns the {@link PersonalTimesheetsPeriodicityEnum} from
* {@link Configuration}.
*/
PersonalTimesheetsPeriodicityEnum getPersonalTimesheetsPeriodicity();
/**
* Returns the string that represents the personal timesheet depending on
* the configured periodicity.
*/
String getTimesheetString();
/**
* Returns the previous personal timesheet to the current one depending on
* the configured periodicity.
*/
LocalDate getPrevious();
/**
* Returns the next personal timesheet to the current one depending on the
* configured periodicity.
*/
LocalDate getNext();
}

View file

@ -22,30 +22,31 @@ package org.libreplan.web.users.dashboard;
import java.util.List;
import org.libreplan.business.calendars.entities.CalendarAvailability;
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.users.entities.User;
import org.libreplan.business.workreports.entities.WorkReport;
/**
* Interface for "Monthly timesheets" area model
* Interface for "Personal timesheets" area model
*
* @author Manuel Rego Casasnovas <mrego@igalia.com>
*/
public interface IMonthlyTimesheetsAreaModel {
public interface IPersonalTimesheetsAreaModel {
/**
* Returns the list of {@link MonthlyTimesheetDTO MonthlyTimesheets} for the
* resource bound to current {@link User}.<br />
* Returns the list of {@link PersonalTimesheetDTO PersonalTimesheetDTOs}
* for the resource bound to current {@link User}.<br />
*
* There's no need that a {@link WorkReport} is saved in order to a
* {@link MonthlyTimesheetDTO} exists for a month.<br />
* {@link PersonalTimesheetDTO} exists for a period.<br />
*
* The list of {@link MonthlyTimesheetDTO MonthlyTimesheets} will be since the
* date the resource is activated in the system (checking
* The list of {@link PersonalTimesheetDTO PersonalTimesheetDTOs} will be
* since the date the resource is activated in the system (checking
* {@link CalendarAvailability} for the resource) to next month of current
* date.
*/
List<MonthlyTimesheetDTO> getMonthlyTimesheets();
List<PersonalTimesheetDTO> getPersonalTimesheets();
/**
* Returns the number of different {@link OrderElement OrderElements} with
@ -53,4 +54,9 @@ public interface IMonthlyTimesheetsAreaModel {
*/
int getNumberOfOrderElementsWithTrackedTime(WorkReport workReport);
/**
* Returns configured periodicity for personal timesheets.
*/
PersonalTimesheetsPeriodicityEnum getPersonalTimesheetsPeriodicity();
}

View file

@ -29,6 +29,7 @@ import javax.annotation.Resource;
import org.joda.time.LocalDate;
import org.libreplan.business.advance.entities.AdvanceMeasurement;
import org.libreplan.business.advance.entities.DirectAdvanceAssignment;
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.orders.entities.SumChargedEffort;
import org.libreplan.business.planner.entities.Task;
@ -54,7 +55,7 @@ public class MyTasksAreaController extends GenericForwardComposer {
private IMyTasksAreaModel myTasksAreaModel;
@Resource
private IMonthlyTimesheetController monthlyTimesheetController;
private IPersonalTimesheetController personalTimesheetController;
private RowRenderer tasksRenderer = new RowRenderer() {
@ -112,17 +113,19 @@ public class MyTasksAreaController extends GenericForwardComposer {
EventListener trackTimeButtonListener = new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
monthlyTimesheetController
.goToCreateOrEditForm(getMonthlyTimesheetDateForTask(task));
personalTimesheetController
.goToCreateOrEditForm(getPersonalTimesheetDateForTask(task));
}
private LocalDate getMonthlyTimesheetDateForTask(Task task) {
private LocalDate getPersonalTimesheetDateForTask(Task task) {
LocalDate start = task.getStartAsLocalDate();
LocalDate end = task.getEndAsLocalDate();
LocalDate currentDate = new LocalDate();
LocalDate min = currentDate.dayOfMonth().withMinimumValue();
LocalDate max = currentDate.dayOfMonth().withMaximumValue();
PersonalTimesheetsPeriodicityEnum periodicity = myTasksAreaModel
.getPersonalTimesheetsPeriodicity();
LocalDate min = periodicity.getStart(currentDate);
LocalDate max = periodicity.getEnd(currentDate);
if (dateBetween(start, min, max)) {
return start;

View file

@ -26,6 +26,8 @@ import java.util.List;
import org.libreplan.business.advance.entities.AdvanceMeasurement;
import org.libreplan.business.advance.entities.DirectAdvanceAssignment;
import org.libreplan.business.common.daos.IConfigurationDAO;
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
import org.libreplan.business.planner.daos.IResourceAllocationDAO;
import org.libreplan.business.planner.entities.SpecificResourceAllocation;
import org.libreplan.business.planner.entities.Task;
@ -53,6 +55,9 @@ public class MyTasksAreaModel implements IMyTasksAreaModel {
@Autowired
private IScenarioManager scenarioManager;
@Autowired
private IConfigurationDAO configurationDAO;
@Override
@Transactional(readOnly = true)
public List<Task> getTasks() {
@ -103,4 +108,11 @@ public class MyTasksAreaModel implements IMyTasksAreaModel {
}
}
@Override
@Transactional(readOnly = true)
public PersonalTimesheetsPeriodicityEnum getPersonalTimesheetsPeriodicity() {
return configurationDAO.getConfiguration()
.getPersonalTimesheetsPeriodicity();
}
}

View file

@ -67,20 +67,20 @@ import org.zkoss.zul.Textbox;
import org.zkoss.zul.api.Grid;
/**
* Controller for creation/edition of a monthly timesheet
* Controller for creation/edition of a personal timesheet
*
* @author Manuel Rego Casasnovas <mrego@igalia.com>
*/
@SuppressWarnings("serial")
public class MonthlyTimesheetController extends GenericForwardComposer
implements IMonthlyTimesheetController {
public class PersonalTimesheetController extends GenericForwardComposer
implements IPersonalTimesheetController {
private final static String EFFORT_DURATION_TEXTBOX_WIDTH = "30px";
private final static String TOTAL_DURATION_TEXTBOX_WIDTH = "50px";
private final static String WORK_REPORTS_URL = "/workreports/workReport.zul";
private IMonthlyTimesheetModel monthlyTimesheetModel;
private IPersonalTimesheetModel personalTimesheetModel;
private IURLHandlerRegistry URLHandlerRegistry;
@ -90,15 +90,15 @@ public class MonthlyTimesheetController extends GenericForwardComposer
private BandboxSearch orderElementBandboxSearch;
private Button previousMonth;
private Button previousPeriod;
private Button nextMonth;
private Button nextPeriod;
private Component messagesContainer;
private IMessagesForUser messagesForUser;
private Label summaryTotalMonthlyTimesheet;
private Label summaryTotalPersonalTimesheet;
private Label summaryTotalOther;
@ -111,7 +111,7 @@ public class MonthlyTimesheetController extends GenericForwardComposer
private Label summaryTotalExtra;
@Resource
private IMonthlyTimesheetController monthlyTimesheetController;
private IPersonalTimesheetController personalTimesheetController;
private RowRenderer rowRenderer = new RowRenderer() {
@ -120,14 +120,14 @@ public class MonthlyTimesheetController extends GenericForwardComposer
@Override
public void render(Row row, Object data) throws Exception {
MonthlyTimesheetRow monthlyTimesheetRow = (MonthlyTimesheetRow) data;
PersonalTimesheetRow personalTimesheetRow = (PersonalTimesheetRow) data;
initMonthlyTimesheetDates();
initPersonalTimesheetDates();
switch (monthlyTimesheetRow.getType()) {
switch (personalTimesheetRow.getType()) {
case ORDER_ELEMENT:
renderOrderElementRow(row,
monthlyTimesheetRow.getOrderElemement());
personalTimesheetRow.getOrderElemement());
break;
case OTHER:
renderOtherRow(row);
@ -146,24 +146,24 @@ public class MonthlyTimesheetController extends GenericForwardComposer
break;
default:
throw new IllegalStateException(
"Unknown MonthlyTimesheetRow type: "
+ monthlyTimesheetRow.getType());
"Unknown PersonalTimesheetRow type: "
+ personalTimesheetRow.getType());
}
}
private void initMonthlyTimesheetDates() {
first = monthlyTimesheetModel.getFirstDay();
last = monthlyTimesheetModel.getLastDate();
private void initPersonalTimesheetDates() {
first = personalTimesheetModel.getFirstDay();
last = personalTimesheetModel.getLastDate();
}
private void renderOrderElementRow(Row row, OrderElement orderElement) {
Util.appendLabel(row, monthlyTimesheetModel.getOrder(orderElement)
Util.appendLabel(row, personalTimesheetModel.getOrder(orderElement)
.getName());
Util.appendLabel(row, orderElement.getName());
appendInputsForDays(row, orderElement);
if (monthlyTimesheetModel.hasOtherReports()) {
if (personalTimesheetModel.hasOtherReports()) {
appendOtherColumn(row, orderElement);
}
@ -182,7 +182,7 @@ public class MonthlyTimesheetController extends GenericForwardComposer
Util.bind(textbox, new Util.Getter<String>() {
@Override
public String get() {
EffortDuration effortDuration = monthlyTimesheetModel
EffortDuration effortDuration = personalTimesheetModel
.getEffortDuration(orderElement, textboxDate);
return effortDurationToString(effortDuration);
}
@ -194,7 +194,7 @@ public class MonthlyTimesheetController extends GenericForwardComposer
throw new WrongValueException(textbox,
_("Invalid Effort Duration"));
}
monthlyTimesheetModel.setEffortDuration(orderElement,
personalTimesheetModel.setEffortDuration(orderElement,
textboxDate, effortDuration);
markAsModified(textbox);
updateTotals(orderElement, textboxDate);
@ -212,13 +212,13 @@ public class MonthlyTimesheetController extends GenericForwardComposer
});
if (monthlyTimesheetModel
if (personalTimesheetModel
.wasModified(orderElement, textboxDate)) {
markAsModified(textbox);
}
Cell cell = getCenteredCell(textbox);
if (monthlyTimesheetModel.getResourceCapacity(day).isZero()) {
if (personalTimesheetModel.getResourceCapacity(day).isZero()) {
setBackgroundNonCapacityCell(cell);
}
row.appendChild(cell);
@ -232,7 +232,7 @@ public class MonthlyTimesheetController extends GenericForwardComposer
private void appendOtherColumn(Row row, final OrderElement orderElement) {
Textbox other = getDisabledTextbox(getOtherRowTextboxId(orderElement));
other.setValue(effortDurationToString(monthlyTimesheetModel.getOtherEffortDuration(orderElement)));
other.setValue(effortDurationToString(personalTimesheetModel.getOtherEffortDuration(orderElement)));
row.appendChild(getCenteredCell(other));
}
@ -242,9 +242,9 @@ public class MonthlyTimesheetController extends GenericForwardComposer
}
private void updateTotalColumn(OrderElement orderElement) {
EffortDuration effort = monthlyTimesheetModel
EffortDuration effort = personalTimesheetModel
.getEffortDuration(orderElement);
effort = effort.plus(monthlyTimesheetModel
effort = effort.plus(personalTimesheetModel
.getOtherEffortDuration(orderElement));
Textbox textbox = (Textbox) timesheet
@ -272,7 +272,7 @@ public class MonthlyTimesheetController extends GenericForwardComposer
for (LocalDate day = first; day.compareTo(last) <= 0; day = day
.plusDays(1)) {
Cell cell = getCenteredCell(getDisabledTextbox(getTotalColumnTextboxId(day)));
if (monthlyTimesheetModel.getResourceCapacity(day).isZero()) {
if (personalTimesheetModel.getResourceCapacity(day).isZero()) {
setBackgroundNonCapacityCell(cell);
}
row.appendChild(cell);
@ -282,9 +282,9 @@ public class MonthlyTimesheetController extends GenericForwardComposer
}
private void updateTotalRow(LocalDate date) {
EffortDuration effort = monthlyTimesheetModel
EffortDuration effort = personalTimesheetModel
.getEffortDuration(date);
effort = effort.plus(monthlyTimesheetModel
effort = effort.plus(personalTimesheetModel
.getOtherEffortDuration(date));
Textbox textbox = (Textbox) timesheet
@ -294,7 +294,7 @@ public class MonthlyTimesheetController extends GenericForwardComposer
private void appendTotalColumn(Row row) {
Cell totalCell = getCenteredCell(getDisabledTextbox(getTotalTextboxId()));
if (monthlyTimesheetModel.hasOtherReports()) {
if (personalTimesheetModel.hasOtherReports()) {
totalCell.setColspan(2);
}
row.appendChild(totalCell);
@ -302,9 +302,9 @@ public class MonthlyTimesheetController extends GenericForwardComposer
}
private void updateTotalColumn() {
EffortDuration effort = monthlyTimesheetModel
EffortDuration effort = personalTimesheetModel
.getTotalEffortDuration();
effort = effort.plus(monthlyTimesheetModel
effort = effort.plus(personalTimesheetModel
.getTotalOtherEffortDuration());
Textbox textbox = (Textbox) timesheet
@ -322,12 +322,12 @@ public class MonthlyTimesheetController extends GenericForwardComposer
for (LocalDate day = first; day.compareTo(last) <= 0; day = day
.plusDays(1)) {
EffortDuration other = monthlyTimesheetModel
EffortDuration other = personalTimesheetModel
.getOtherEffortDuration(day);
Cell cell = getCenteredCell(getDisabledTextbox(
getOtherColumnTextboxId(day), other));
if (monthlyTimesheetModel.getResourceCapacity(day).isZero()) {
if (personalTimesheetModel.getResourceCapacity(day).isZero()) {
setBackgroundNonCapacityCell(cell);
}
row.appendChild(cell);
@ -351,12 +351,12 @@ public class MonthlyTimesheetController extends GenericForwardComposer
for (LocalDate day = first; day.compareTo(last) <= 0; day = day
.plusDays(1)) {
EffortDuration capacity = monthlyTimesheetModel
EffortDuration capacity = personalTimesheetModel
.getResourceCapacity(day);
Cell cell = getCenteredCell(getDisabledTextbox(
getCapcityColumnTextboxId(day), capacity));
if (monthlyTimesheetModel.getResourceCapacity(day).isZero()) {
if (personalTimesheetModel.getResourceCapacity(day).isZero()) {
setBackgroundNonCapacityCell(cell);
}
row.appendChild(cell);
@ -366,7 +366,7 @@ public class MonthlyTimesheetController extends GenericForwardComposer
Cell totalCapacityCell = getCenteredCell(getDisabledTextbox(
getTotalCapacityTextboxId(), totalCapacity));
if (monthlyTimesheetModel.hasOtherReports()) {
if (personalTimesheetModel.hasOtherReports()) {
totalCapacityCell.setColspan(2);
}
row.appendChild(totalCapacityCell);
@ -382,7 +382,7 @@ public class MonthlyTimesheetController extends GenericForwardComposer
for (LocalDate day = first; day.compareTo(last) <= 0; day = day
.plusDays(1)) {
Cell cell = getCenteredCell(getDisabledTextbox(getExtraColumnTextboxId(day)));
if (monthlyTimesheetModel.getResourceCapacity(day).isZero()) {
if (personalTimesheetModel.getResourceCapacity(day).isZero()) {
setBackgroundNonCapacityCell(cell);
}
row.appendChild(cell);
@ -414,7 +414,7 @@ public class MonthlyTimesheetController extends GenericForwardComposer
private void appendTotalExtra(Row row) {
Cell totalExtraCell = getCenteredCell(getDisabledTextbox(getTotalExtraTextboxId()));
if (monthlyTimesheetModel.hasOtherReports()) {
if (personalTimesheetModel.hasOtherReports()) {
totalExtraCell.setColspan(2);
}
row.appendChild(totalExtraCell);
@ -478,7 +478,7 @@ public class MonthlyTimesheetController extends GenericForwardComposer
checkUserComesFromEntryPointsOrSendForbiddenCode();
URLHandlerRegistry.getRedirectorFor(IMonthlyTimesheetController.class)
URLHandlerRegistry.getRedirectorFor(IPersonalTimesheetController.class)
.register(this, page);
}
@ -508,7 +508,7 @@ public class MonthlyTimesheetController extends GenericForwardComposer
breadcrumbs.appendChild(new Image(BREADCRUMBS_SEPARATOR));
breadcrumbs.appendChild(new Label(_("My dashboard")));
breadcrumbs.appendChild(new Image(BREADCRUMBS_SEPARATOR));
breadcrumbs.appendChild(new Label(_("Monthly timesheet")));
breadcrumbs.appendChild(new Label(_("Personal timesheet")));
}
@Override
@ -517,7 +517,7 @@ public class MonthlyTimesheetController extends GenericForwardComposer
Util.sendForbiddenStatusCodeInHttpServletResponse();
}
monthlyTimesheetModel.initCreateOrEdit(date);
personalTimesheetModel.initCreateOrEdit(date);
initTimesheet(date);
}
@ -528,7 +528,7 @@ public class MonthlyTimesheetController extends GenericForwardComposer
Util.sendForbiddenStatusCodeInHttpServletResponse();
}
monthlyTimesheetModel.initCreateOrEdit(date, resource);
personalTimesheetModel.initCreateOrEdit(date, resource);
initTimesheet(date);
}
@ -549,7 +549,7 @@ public class MonthlyTimesheetController extends GenericForwardComposer
private void createColumns(LocalDate date) {
createProjectAndTaskColumns();
createColumnsForDays(date);
if (monthlyTimesheetModel.hasOtherReports()) {
if (personalTimesheetModel.hasOtherReports()) {
createOtherColumn();
}
createTotalColumn();
@ -568,8 +568,10 @@ public class MonthlyTimesheetController extends GenericForwardComposer
}
private void createColumnsForDays(LocalDate date) {
LocalDate start = date.dayOfMonth().withMinimumValue();
LocalDate end = date.dayOfMonth().withMaximumValue();
LocalDate start = personalTimesheetModel
.getPersonalTimesheetsPeriodicity().getStart(date);
LocalDate end = personalTimesheetModel
.getPersonalTimesheetsPeriodicity().getEnd(date);
for (LocalDate day = start; day.compareTo(end) <= 0; day = day
.plusDays(1)) {
@ -596,24 +598,24 @@ public class MonthlyTimesheetController extends GenericForwardComposer
columns.appendChild(total);
}
public String getDate() {
return monthlyTimesheetModel.getDate().toString("MMMM y");
public String getTimesheetString() {
return personalTimesheetModel.getTimesheetString();
}
public String getResource() {
return monthlyTimesheetModel.getWorker().getShortDescription();
return personalTimesheetModel.getWorker().getShortDescription();
}
public List<MonthlyTimesheetRow> getRows() {
List<MonthlyTimesheetRow> result = MonthlyTimesheetRow
.wrap(monthlyTimesheetModel
public List<PersonalTimesheetRow> getRows() {
List<PersonalTimesheetRow> result = PersonalTimesheetRow
.wrap(personalTimesheetModel
.getOrderElements());
if (monthlyTimesheetModel.hasOtherReports()) {
result.add(MonthlyTimesheetRow.createOtherRow());
if (personalTimesheetModel.hasOtherReports()) {
result.add(PersonalTimesheetRow.createOtherRow());
}
result.add(MonthlyTimesheetRow.createTotalRow());
result.add(MonthlyTimesheetRow.createCapacityRow());
result.add(MonthlyTimesheetRow.createExtraRow());
result.add(PersonalTimesheetRow.createTotalRow());
result.add(PersonalTimesheetRow.createCapacityRow());
result.add(PersonalTimesheetRow.createExtraRow());
return result;
}
@ -622,31 +624,31 @@ public class MonthlyTimesheetController extends GenericForwardComposer
}
public void save() {
monthlyTimesheetModel.save();
personalTimesheetModel.save();
String url = CustomTargetUrlResolver.USER_DASHBOARD_URL
+ "?timesheet_saved=" + monthlyTimesheetModel.getDate();
if (!monthlyTimesheetModel.isCurrentUser()) {
+ "?timesheet_saved=" + personalTimesheetModel.getDate();
if (!personalTimesheetModel.isCurrentUser()) {
url = WORK_REPORTS_URL + "?timesheet_saved=true";
}
Executions.getCurrent().sendRedirect(url);
}
public void saveAndContinue() {
monthlyTimesheetModel.save();
if (monthlyTimesheetModel.isCurrentUser()) {
goToCreateOrEditForm(monthlyTimesheetModel.getDate());
personalTimesheetModel.save();
if (personalTimesheetModel.isCurrentUser()) {
goToCreateOrEditForm(personalTimesheetModel.getDate());
} else {
goToCreateOrEditFormForResource(monthlyTimesheetModel.getDate(),
monthlyTimesheetModel.getWorker());
goToCreateOrEditFormForResource(personalTimesheetModel.getDate(),
personalTimesheetModel.getWorker());
}
messagesForUser.showMessage(Level.INFO, _("Monthly timesheet saved"));
messagesForUser.showMessage(Level.INFO, _("Personal timesheet saved"));
Util.reloadBindings(timesheet);
}
public void cancel() {
monthlyTimesheetModel.cancel();
personalTimesheetModel.cancel();
String url = CustomTargetUrlResolver.USER_DASHBOARD_URL;
if (!monthlyTimesheetModel.isCurrentUser()) {
if (!personalTimesheetModel.isCurrentUser()) {
url = WORK_REPORTS_URL;
}
Executions.getCurrent().sendRedirect(url);
@ -656,56 +658,56 @@ public class MonthlyTimesheetController extends GenericForwardComposer
OrderElement orderElement = (OrderElement) orderElementBandboxSearch
.getSelectedElement();
if (orderElement != null) {
monthlyTimesheetModel.addOrderElement(orderElement);
personalTimesheetModel.addOrderElement(orderElement);
orderElementBandboxSearch.setSelectedElement(null);
Util.reloadBindings(timesheet);
adjustFrozenWidth();
}
}
public boolean isFirstMonth() {
return monthlyTimesheetModel.isFirstMonth();
public boolean isFirstPeriod() {
return personalTimesheetModel.isFirstPeriod();
}
public boolean isLastMonth() {
return monthlyTimesheetModel.isLastMonth();
public boolean isLastPeriod() {
return personalTimesheetModel.isLastPeriod();
}
public void previousMonth() {
if (monthlyTimesheetModel.isModified()) {
public void previousPeriod() {
if (personalTimesheetModel.isModified()) {
throw new WrongValueException(
previousMonth,
_("There are unsaved changes in the current monthly timesheet, please save before moving"));
previousPeriod,
_("There are unsaved changes in the current personal timesheet, please save before moving"));
}
sendToMonthlyTimesheet(monthlyTimesheetModel.getDate().minusMonths(1));
sendToPersonalTimesheet(personalTimesheetModel.getPrevious());
}
public void nextMonth() {
if (monthlyTimesheetModel.isModified()) {
public void nextPeriod() {
if (personalTimesheetModel.isModified()) {
throw new WrongValueException(
nextMonth,
_("There are unsaved changes in the current monthly timesheet, please save before moving"));
nextPeriod,
_("There are unsaved changes in the current personal timesheet, please save before moving"));
}
sendToMonthlyTimesheet(monthlyTimesheetModel.getDate().plusMonths(1));
sendToPersonalTimesheet(personalTimesheetModel.getNext());
}
private void sendToMonthlyTimesheet(final LocalDate date) {
private void sendToPersonalTimesheet(final LocalDate date) {
String capturePath = EntryPointsHandler.capturePath(new ICapture() {
@Override
public void capture() {
monthlyTimesheetController.goToCreateOrEditForm(date);
personalTimesheetController.goToCreateOrEditForm(date);
}
});
Executions.getCurrent().sendRedirect(capturePath);
}
public boolean isCurrentUser() {
return monthlyTimesheetModel.isCurrentUser();
return personalTimesheetModel.isCurrentUser();
}
public boolean isNotCurrentUser() {
return !monthlyTimesheetModel.isCurrentUser();
return !personalTimesheetModel.isCurrentUser();
}
private static String getTotalRowTextboxId(final OrderElement orderElement) {
@ -781,7 +783,7 @@ public class MonthlyTimesheetController extends GenericForwardComposer
public void updateSummary() {
EffortDuration total = getEffortDurationFromTextbox(getTotalTextboxId());
EffortDuration other = EffortDuration.zero();
if (monthlyTimesheetModel.hasOtherReports()) {
if (personalTimesheetModel.hasOtherReports()) {
other = getEffortDurationFromTextbox(getTotalOtherTextboxId());
}
EffortDuration capacity = getEffortDurationFromTextbox(getTotalCapacityTextboxId());
@ -793,8 +795,8 @@ public class MonthlyTimesheetController extends GenericForwardComposer
extra = total.minus(capacity);
}
if (monthlyTimesheetModel.hasOtherReports()) {
summaryTotalMonthlyTimesheet
if (personalTimesheetModel.hasOtherReports()) {
summaryTotalPersonalTimesheet
.setValue(timesheet.toFormattedString());
summaryTotalOther.setValue(other.toFormattedString());
}
@ -811,64 +813,64 @@ public class MonthlyTimesheetController extends GenericForwardComposer
}
public boolean hasOtherReports() {
return monthlyTimesheetModel.hasOtherReports();
return personalTimesheetModel.hasOtherReports();
}
}
/**
* Simple class to represent the the rows in the monthly timesheet grid.<br />
* Simple class to represent the the rows in the personal timesheet grid.<br />
*
* This is used to mark the special rows like capacity and total.
*/
class MonthlyTimesheetRow {
enum MonthlyTimesheetRowType {
class PersonalTimesheetRow {
enum PersonalTimesheetRowType {
ORDER_ELEMENT, OTHER, CAPACITY, TOTAL, EXTRA
};
private MonthlyTimesheetRowType type;
private PersonalTimesheetRowType type;
private OrderElement orderElemement;
public static MonthlyTimesheetRow createOrderElementRow(
public static PersonalTimesheetRow createOrderElementRow(
OrderElement orderElemement) {
MonthlyTimesheetRow row = new MonthlyTimesheetRow(
MonthlyTimesheetRowType.ORDER_ELEMENT);
PersonalTimesheetRow row = new PersonalTimesheetRow(
PersonalTimesheetRowType.ORDER_ELEMENT);
Assert.notNull(orderElemement);
row.orderElemement = orderElemement;
return row;
}
public static MonthlyTimesheetRow createOtherRow() {
return new MonthlyTimesheetRow(MonthlyTimesheetRowType.OTHER);
public static PersonalTimesheetRow createOtherRow() {
return new PersonalTimesheetRow(PersonalTimesheetRowType.OTHER);
}
public static MonthlyTimesheetRow createCapacityRow() {
return new MonthlyTimesheetRow(MonthlyTimesheetRowType.CAPACITY);
public static PersonalTimesheetRow createCapacityRow() {
return new PersonalTimesheetRow(PersonalTimesheetRowType.CAPACITY);
}
public static MonthlyTimesheetRow createTotalRow() {
return new MonthlyTimesheetRow(MonthlyTimesheetRowType.TOTAL);
public static PersonalTimesheetRow createTotalRow() {
return new PersonalTimesheetRow(PersonalTimesheetRowType.TOTAL);
}
public static MonthlyTimesheetRow createExtraRow() {
return new MonthlyTimesheetRow(MonthlyTimesheetRowType.EXTRA);
public static PersonalTimesheetRow createExtraRow() {
return new PersonalTimesheetRow(PersonalTimesheetRowType.EXTRA);
}
public static List<MonthlyTimesheetRow> wrap(
public static List<PersonalTimesheetRow> wrap(
List<OrderElement> orderElements) {
List<MonthlyTimesheetRow> result = new ArrayList<MonthlyTimesheetRow>();
List<PersonalTimesheetRow> result = new ArrayList<PersonalTimesheetRow>();
for (OrderElement each : orderElements) {
result.add(createOrderElementRow(each));
}
return result;
}
private MonthlyTimesheetRow(MonthlyTimesheetRowType type) {
private PersonalTimesheetRow(PersonalTimesheetRowType type) {
this.type = type;
}
public MonthlyTimesheetRowType getType() {
public PersonalTimesheetRowType getType() {
return type;
}

View file

@ -19,19 +19,22 @@
package org.libreplan.web.users.dashboard;
import static org.libreplan.web.I18nHelper._;
import org.joda.time.LocalDate;
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
import org.libreplan.business.workingday.EffortDuration;
import org.libreplan.business.workreports.entities.WorkReport;
/**
* Simple class to represent the monthly timesheets to be shown in the list.<br />
* Simple class to represent the personal timesheets to be shown in the list.<br />
*
* This is only a utility class for the UI, everything will be saved using
* {@link WorkReport} class.
*
* @author Manuel Rego Casasnovas <mrego@igalia.com>
*/
public class MonthlyTimesheetDTO {
public class PersonalTimesheetDTO {
private LocalDate date;
@ -45,24 +48,23 @@ public class MonthlyTimesheetDTO {
/**
* @param date
* Only the year and month are used, the day is reseted to first
* day of the month. As there's only one timesheet per month.
* The date of the timesheet.
* @param workReport
* The work report of the monthly timesheet, it could be
* The work report of the personal timesheet, it could be
* <code>null</code> if it doesn't exist yet.
* @param resourceCapacity
* The capacity of the resource bound to current user in the
* month of this timesheet.
* period of this timesheet.
* @param totalHours
* Total hours worked by the resource bound to the current user
* in the monthly timesheet
* in the personal timesheet
* @param tasksNumber
* Number of tasks in the monthly timesheet
* Number of tasks in the personal timesheet
*/
MonthlyTimesheetDTO(LocalDate date, WorkReport workReport,
PersonalTimesheetDTO(LocalDate date, WorkReport workReport,
EffortDuration resourceCapacity, EffortDuration totalHours,
int tasksNumber) {
this.date = date.dayOfMonth().withMaximumValue();
this.date = date;
this.workReport = workReport;
this.resourceCapacity = resourceCapacity;
this.totalHours = totalHours;
@ -89,4 +91,41 @@ public class MonthlyTimesheetDTO {
return tasksNumber;
}
public String toString(PersonalTimesheetsPeriodicityEnum periodicity) {
return toString(periodicity, date);
}
/**
* Returns a string representing the personal timehseet in a given
* <code>date</code> depending on the <code>periodicity</code>.
*/
public static String toString(PersonalTimesheetsPeriodicityEnum periodicity, LocalDate date) {
switch (periodicity) {
case WEEKLY:
LocalDate start = periodicity.getStart(date);
LocalDate end = periodicity.getEnd(date);
String string = date.toString("w");
if (start.getMonthOfYear() == end.getMonthOfYear()) {
string += " (" + date.toString("MMMM y") + ")";
} else {
if (start.getYear() == end.getYear()) {
string += " (" + start.toString("MMMM") + " - "
+ end.toString("MMMM y") + ")";
} else {
string += " (" + start.toString("MMMM y") + " - "
+ end.toString("MMMM y") + ")";
}
}
return _("Week {0}", string);
case TWICE_MONTHLY:
return (date.getDayOfMonth() <= 15) ?
_("{0} 1st fortnight", date.toString("MMMM y")) :
_("{0} 2nd fortnight", date.toString("MMMM y"));
case MONTHLY:
default:
return date.toString("MMMM y");
}
}
}

View file

@ -34,6 +34,7 @@ import org.libreplan.business.calendars.entities.ResourceCalendar;
import org.libreplan.business.common.daos.IConfigurationDAO;
import org.libreplan.business.common.daos.IEntitySequenceDAO;
import org.libreplan.business.common.entities.EntityNameEnum;
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.costcategories.entities.TypeOfWorkHours;
import org.libreplan.business.orders.daos.IOrderDAO;
@ -67,14 +68,14 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* Model for creation/edition of a monthly timesheet
* Model for creation/edition of a personal timesheet
*
* @author Manuel Rego Casasnovas <mrego@igalia.com>
*/
@Service
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
@OnConcurrentModification(goToPage = "/myaccount/userDashboard.zul")
public class MonthlyTimesheetModel implements IMonthlyTimesheetModel {
public class PersonalTimesheetModel implements IPersonalTimesheetModel {
private User user;
@ -102,6 +103,8 @@ public class MonthlyTimesheetModel implements IMonthlyTimesheetModel {
private Map<LocalDate, EffortDuration> otherEffortPerDay;
private PersonalTimesheetsPeriodicityEnum periodicity;
@Autowired
private IResourceAllocationDAO resourceAllocationDAO;
@ -147,6 +150,8 @@ public class MonthlyTimesheetModel implements IMonthlyTimesheetModel {
private void initFields(LocalDate date) {
this.date = date;
periodicity = getPersonalTimesheetsPeriodicity();
initDates();
initCapacityMap();
@ -173,8 +178,8 @@ public class MonthlyTimesheetModel implements IMonthlyTimesheetModel {
}
private void initDates() {
firstDay = date.dayOfMonth().withMinimumValue();
lastDay = date.dayOfMonth().withMaximumValue();
firstDay = periodicity.getStart(date);
lastDay = periodicity.getEnd(date);
}
private void initCapacityMap() {
@ -195,13 +200,13 @@ public class MonthlyTimesheetModel implements IMonthlyTimesheetModel {
}
private void initWorkReport() {
// Get work report representing this monthly timesheet
workReport = workReportDAO.getMonthlyTimesheetWorkReport(
user.getWorker(), date);
// Get work report representing this personal timesheet
workReport = workReportDAO.getPersonalTimesheetWorkReport(
user.getWorker(), date, periodicity);
if (workReport == null) {
// If it doesn't exist yet create a new one
workReport = WorkReport
.create(getMonthlyTimesheetsWorkReportType());
.create(getPersonalTimesheetsWorkReportType());
workReport
.setCode(entitySequenceDAO
.getNextEntityCodeWithoutTransaction(EntityNameEnum.WORK_REPORT));
@ -211,10 +216,10 @@ public class MonthlyTimesheetModel implements IMonthlyTimesheetModel {
forceLoad(workReport.getWorkReportType());
}
private WorkReportType getMonthlyTimesheetsWorkReportType() {
private WorkReportType getPersonalTimesheetsWorkReportType() {
try {
WorkReportType workReportType = workReportTypeDAO
.findUniqueByName(PredefinedWorkReportTypes.MONTHLY_TIMESHEETS
.findUniqueByName(PredefinedWorkReportTypes.PERSONAL_TIMESHEETS
.getName());
return workReportType;
} catch (NonUniqueResultException e) {
@ -413,7 +418,7 @@ public class MonthlyTimesheetModel implements IMonthlyTimesheetModel {
private TypeOfWorkHours getTypeOfWorkHours() {
return configurationDAO.getConfiguration()
.getMonthlyTimesheetsTypeOfWorkHours();
.getPersonalTimesheetsTypeOfWorkHours();
}
@Override
@ -424,7 +429,7 @@ public class MonthlyTimesheetModel implements IMonthlyTimesheetModel {
// Do nothing.
// A new work report if it doesn't have work report lines is not
// saved as it will not be possible to find it later with
// WorkReportDAO.getMonthlyTimesheetWorkReport() method.
// WorkReportDAO.getPersonalTimesheetWorkReport() method.
} else {
sumChargedEffortDAO
.updateRelatedSumChargedEffortWithWorkReportLineSet(workReport
@ -502,16 +507,18 @@ public class MonthlyTimesheetModel implements IMonthlyTimesheetModel {
}
@Override
public boolean isFirstMonth() {
@Transactional(readOnly = true)
public boolean isFirstPeriod() {
LocalDate activationDate = getWorker().getCalendar()
.getFistCalendarAvailability().getStartDate();
return firstDay.equals(activationDate.dayOfMonth().withMinimumValue());
return firstDay.equals(periodicity.getStart(activationDate));
}
@Override
public boolean isLastMonth() {
return firstDay.equals(new LocalDate().plusMonths(1).dayOfMonth()
.withMinimumValue());
@Transactional(readOnly = true)
public boolean isLastPeriod() {
return firstDay.equals(periodicity.getStart(new LocalDate()
.plusMonths(1)));
}
@Override
@ -552,4 +559,26 @@ public class MonthlyTimesheetModel implements IMonthlyTimesheetModel {
return result;
}
@Override
@Transactional(readOnly = true)
public PersonalTimesheetsPeriodicityEnum getPersonalTimesheetsPeriodicity() {
return configurationDAO.getConfiguration()
.getPersonalTimesheetsPeriodicity();
}
@Override
public String getTimesheetString() {
return PersonalTimesheetDTO.toString(periodicity, date);
}
@Override
public LocalDate getPrevious() {
return periodicity.previous(date);
}
@Override
public LocalDate getNext() {
return periodicity.next(date);
}
}

View file

@ -32,37 +32,39 @@ import org.zkoss.zul.Row;
import org.zkoss.zul.RowRenderer;
/**
* Controller for "Monthly timesheets" area in the user dashboard window
* Controller for "Personal timesheets" area in the user dashboard window
*
* @author Manuel Rego Casasnovas <mrego@igalia.com>
*/
@SuppressWarnings("serial")
public class MonthlyTimesheetsAreaController extends GenericForwardComposer {
public class PersonalTimesheetsAreaController extends GenericForwardComposer {
private IMonthlyTimesheetsAreaModel monthlyTimesheetsAreaModel;
private IPersonalTimesheetsAreaModel personalTimesheetsAreaModel;
@Resource
private IMonthlyTimesheetController monthlyTimesheetController;
private IPersonalTimesheetController personalTimesheetController;
private RowRenderer monthlyTimesheetsRenderer = new RowRenderer() {
private RowRenderer personalTimesheetsRenderer = new RowRenderer() {
@Override
public void render(Row row, Object data) throws Exception {
final MonthlyTimesheetDTO monthlyTimesheet = (MonthlyTimesheetDTO) data;
row.setValue(monthlyTimesheet);
final PersonalTimesheetDTO personalTimesheet = (PersonalTimesheetDTO) data;
row.setValue(personalTimesheet);
Util.appendLabel(row, monthlyTimesheet.getDate().toString("MMMM y"));
Util.appendLabel(row, monthlyTimesheet.getResourceCapacity()
Util.appendLabel(row, personalTimesheet
.toString(personalTimesheetsAreaModel
.getPersonalTimesheetsPeriodicity()));
Util.appendLabel(row, personalTimesheet.getResourceCapacity()
.toFormattedString());
Util.appendLabel(row, monthlyTimesheet.getTotalHours()
Util.appendLabel(row, personalTimesheet.getTotalHours()
.toFormattedString());
Util.appendLabel(row, monthlyTimesheet.getTasksNumber() + "");
Util.appendLabel(row, personalTimesheet.getTasksNumber() + "");
Util.appendOperationsAndOnClickEvent(row, new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
monthlyTimesheetController.goToCreateOrEditForm(monthlyTimesheet
personalTimesheetController.goToCreateOrEditForm(personalTimesheet
.getDate());
}
}, null);
@ -76,12 +78,12 @@ public class MonthlyTimesheetsAreaController extends GenericForwardComposer {
comp.setAttribute("controller", this);
}
public List<MonthlyTimesheetDTO> getMonthlyTimesheets() {
return monthlyTimesheetsAreaModel.getMonthlyTimesheets();
public List<PersonalTimesheetDTO> getPersonalTimesheets() {
return personalTimesheetsAreaModel.getPersonalTimesheets();
}
public RowRenderer getMonthlyTimesheetsRenderer() {
return monthlyTimesheetsRenderer;
public RowRenderer getPersonalTimesheetsRenderer() {
return personalTimesheetsRenderer;
}
}
}

View file

@ -24,7 +24,8 @@ import java.util.Collections;
import java.util.List;
import org.joda.time.LocalDate;
import org.joda.time.Months;
import org.libreplan.business.common.daos.IConfigurationDAO;
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.resources.entities.Resource;
import org.libreplan.business.resources.entities.Worker;
@ -45,20 +46,23 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* Model for for "Monthly timesheets" area in the user dashboard window
* Model for for "Personal timesheets" area in the user dashboard window
*
* @author Manuel Rego Casasnovas <mrego@igalia.com>
*/
@Service
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class MonthlyTimesheetsAreaModel implements IMonthlyTimesheetsAreaModel {
public class PersonalTimesheetsAreaModel implements IPersonalTimesheetsAreaModel {
@Autowired
private IWorkReportDAO workReportDAO;
@Autowired
private IConfigurationDAO configurationDAO;
@Override
@Transactional(readOnly = true)
public List<MonthlyTimesheetDTO> getMonthlyTimesheets() {
public List<PersonalTimesheetDTO> getPersonalTimesheets() {
User user = UserUtil.getUserFromSession();
if (!user.isBound()) {
return Collections.emptyList();
@ -68,22 +72,25 @@ public class MonthlyTimesheetsAreaModel implements IMonthlyTimesheetsAreaModel {
LocalDate activationDate = getActivationDate(user.getWorker());
LocalDate currentDate = new LocalDate();
return getMonthlyTimesheets(user.getWorker(), activationDate,
currentDate.plusMonths(1));
return getPersonalTimesheets(user.getWorker(), activationDate,
currentDate.plusMonths(1), getPersonalTimesheetsPeriodicity());
}
private List<MonthlyTimesheetDTO> getMonthlyTimesheets(Resource resource,
LocalDate start, LocalDate end) {
int months = Months.monthsBetween(start, end).getMonths();
private List<PersonalTimesheetDTO> getPersonalTimesheets(Resource resource,
LocalDate start, LocalDate end,
PersonalTimesheetsPeriodicityEnum periodicity) {
start = periodicity.getStart(start);
end = periodicity.getEnd(end);
int items = periodicity.getItemsBetween(start, end);
List<MonthlyTimesheetDTO> result = new ArrayList<MonthlyTimesheetDTO>();
List<PersonalTimesheetDTO> result = new ArrayList<PersonalTimesheetDTO>();
// In decreasing order to provide a list sorted with the more recent
// monthly timesheets at the beginning
for (int i = months; i >= 0; i--) {
LocalDate date = start.plusMonths(i);
// personal timesheets at the beginning
for (int i = items; i >= 0; i--) {
LocalDate date = periodicity.getDateForItemFromDate(i, start);
WorkReport workReport = getWorkReport(resource, date);
WorkReport workReport = getWorkReport(resource, date, periodicity);
EffortDuration hours = EffortDuration.zero();
int tasksNumber = 0;
@ -92,24 +99,29 @@ public class MonthlyTimesheetsAreaModel implements IMonthlyTimesheetsAreaModel {
tasksNumber = getNumberOfOrderElementsWithTrackedTime(workReport);
}
result.add(new MonthlyTimesheetDTO(date, workReport,
getResourceCapcity(resource, date), hours, tasksNumber));
result.add(new PersonalTimesheetDTO(date, workReport,
getResourceCapcity(resource, date, periodicity), hours,
tasksNumber));
}
return result;
}
private WorkReport getWorkReport(Resource resource, LocalDate date) {
WorkReport workReport = workReportDAO.getMonthlyTimesheetWorkReport(
resource, date);
private WorkReport getWorkReport(Resource resource, LocalDate date,
PersonalTimesheetsPeriodicityEnum periodicity) {
WorkReport workReport = workReportDAO.getPersonalTimesheetWorkReport(
resource, date, periodicity);
forceLoad(workReport);
return workReport;
}
private EffortDuration getResourceCapcity(Resource resource, LocalDate date) {
private EffortDuration getResourceCapcity(Resource resource,
LocalDate date, PersonalTimesheetsPeriodicityEnum periodicity) {
LocalDate start = periodicity.getStart(date);
LocalDate end = periodicity.getEnd(date);
EffortDuration capacity = EffortDuration.zero();
for (LocalDate day = date.dayOfMonth().withMinimumValue(); day
.compareTo(date.dayOfMonth().withMaximumValue()) <= 0; day = day
for (LocalDate day = start; day.compareTo(end) <= 0; day = day
.plusDays(1)) {
capacity = capacity.plus(resource.getCalendar().getCapacityOn(
PartialDay.wholeDay(day)));
@ -149,4 +161,11 @@ public class MonthlyTimesheetsAreaModel implements IMonthlyTimesheetsAreaModel {
return orderElements.size();
}
@Override
@Transactional(readOnly = true)
public PersonalTimesheetsPeriodicityEnum getPersonalTimesheetsPeriodicity() {
return configurationDAO.getConfiguration()
.getPersonalTimesheetsPeriodicity();
}
}

View file

@ -23,6 +23,7 @@ import static org.libreplan.web.I18nHelper._;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.libreplan.business.common.Registry;
import org.libreplan.web.common.IMessagesForUser;
import org.libreplan.web.common.Level;
import org.libreplan.web.common.MessagesForUser;
@ -34,7 +35,7 @@ import org.zkoss.zk.ui.util.GenericForwardComposer;
* Controller for user dashboard window.<br />
*
* At this moment it's only used to show a message to user after saving a
* monthly timesheet.
* personal timesheet.
*
* @author Manuel Rego Casasnovas <mrego@igalia.com>
*/
@ -54,10 +55,13 @@ public class UserDashboardController extends GenericForwardComposer {
String timesheetSave = Executions.getCurrent().getParameter(
"timesheet_saved");
if (!StringUtils.isBlank(timesheetSave)) {
String monthlyTimesheet = new LocalDate(timesheetSave)
.toString("MMMM y");
String personalTimesheet = PersonalTimesheetDTO.toString(Registry
.getConfigurationDAO()
.getConfigurationWithReadOnlyTransaction()
.getPersonalTimesheetsPeriodicity(), new LocalDate(
timesheetSave));
messagesForUser.showMessage(Level.INFO,
_("Monthly timesheet \"{0}\" saved", monthlyTimesheet));
_("Personal timesheet \"{0}\" saved", personalTimesheet));
}
String expenseSheetSaved = Executions.getCurrent().getParameter(

View file

@ -239,9 +239,9 @@ public interface IWorkReportModel extends IIntegrationEntityModel {
List<Worker> getBoundWorkers();
/**
* Checks if a {@link WorkReport} is or not a monthly timesheet.
* Checks if a {@link WorkReport} is or not a personal timesheet.
*/
boolean isMonthlyTimesheet(WorkReport workReport);
boolean isPersonalTimesheet(WorkReport workReport);
WorkReportLine getFirstWorkReportLine();

View file

@ -52,11 +52,11 @@ public interface IWorkReportTypeModel extends IIntegrationEntityModel {
/**
* Gets the {@link List} of {@link WorkReportType WorkReportTypes} except
* the {@link WorkReportType} used for monthly timesheets.
* the {@link WorkReportType} used for personal timesheets.
*
* @return A {@link List} of {@link WorkReportType}
*/
List<WorkReportType> getWorkReportTypesExceptMonthlyTimeSheets();
List<WorkReportType> getWorkReportTypesExceptPersonalTimeSheets();
/**
* Stores the current {@link WorkReportType}.

View file

@ -60,7 +60,7 @@ import org.libreplan.web.common.components.NewDataSortableGrid;
import org.libreplan.web.common.components.bandboxsearch.BandboxSearch;
import org.libreplan.web.common.entrypoints.EntryPointsHandler;
import org.libreplan.web.common.entrypoints.IURLHandlerRegistry;
import org.libreplan.web.users.dashboard.IMonthlyTimesheetController;
import org.libreplan.web.users.dashboard.IPersonalTimesheetController;
import org.zkoss.ganttz.IPredicate;
import org.zkoss.ganttz.util.ComponentsFinder;
import org.zkoss.zk.ui.Component;
@ -157,13 +157,13 @@ public class WorkReportCRUDController extends GenericForwardComposer implements
private Datebox filterFinishDate;
@javax.annotation.Resource
private IMonthlyTimesheetController monthlyTimesheetController;
private IPersonalTimesheetController personalTimesheetController;
private Popup monthlyTimesheetsPopup;
private Popup personalTimesheetsPopup;
private Datebox monthlyTimesheetsDatebox;
private Datebox personalTimesheetsDatebox;
private BandboxSearch monthlyTimesheetsBandboxSearch;
private BandboxSearch personalTimesheetsBandboxSearch;
@Override
public void doAfterCompose(Component comp) throws Exception {
@ -171,7 +171,7 @@ public class WorkReportCRUDController extends GenericForwardComposer implements
listWorkReportLines = (NewDataSortableGrid) createWindow
.getFellowIfAny("listWorkReportLines");
messagesForUser = new MessagesForUser(messagesContainer);
showMessageIfMonthlyTimesheetWasSaved();
showMessageIfPersonalTimesheetWasSaved();
comp.setAttribute("controller", this);
goToList();
@ -185,12 +185,12 @@ public class WorkReportCRUDController extends GenericForwardComposer implements
handler.register(this, page);
}
private void showMessageIfMonthlyTimesheetWasSaved() {
private void showMessageIfPersonalTimesheetWasSaved() {
String timesheetSave = Executions.getCurrent().getParameter(
"timesheet_saved");
if (!StringUtils.isBlank(timesheetSave)) {
messagesForUser.showMessage(Level.INFO,
_("Monthly timesheet saved"));
_("Personal timesheet saved"));
}
}
@ -598,8 +598,8 @@ public class WorkReportCRUDController extends GenericForwardComposer implements
@Override
public void goToCreateForm(WorkReportType workReportType) {
if (workReportType.isMonthlyTimesheetsType()) {
monthlyTimesheetsPopup.open(listTypeToAssign);
if (workReportType.isPersonalTimesheetsType()) {
personalTimesheetsPopup.open(listTypeToAssign);
} else {
cameBackList = false;
workReportModel.initCreate(workReportType);
@ -617,8 +617,8 @@ public class WorkReportCRUDController extends GenericForwardComposer implements
@Override
public void goToEditForm(WorkReport workReport) {
if (workReportModel.isMonthlyTimesheet(workReport)) {
goToEditMonthlyTimeSheet(workReport);
if (workReportModel.isPersonalTimesheet(workReport)) {
goToEditPersonalTimeSheet(workReport);
} else {
workReportModel.initEdit(workReport);
createWindow.setTitle(_("Edit Timesheet"));
@ -629,11 +629,11 @@ public class WorkReportCRUDController extends GenericForwardComposer implements
}
}
private void goToEditMonthlyTimeSheet(WorkReport workReport) {
private void goToEditPersonalTimeSheet(WorkReport workReport) {
workReportModel.initEdit(workReport);
Date date = workReportModel.getFirstWorkReportLine().getDate();
Resource resource = workReport.getResource();
monthlyTimesheetController.goToCreateOrEditFormForResource(
personalTimesheetController.goToCreateOrEditFormForResource(
LocalDate.fromDateFields(date), resource);
}
@ -682,12 +682,12 @@ public class WorkReportCRUDController extends GenericForwardComposer implements
listTypeToAssign = (Listbox) window.getFellow("listTypeToAssign");
filterStartDate = (Datebox) window.getFellow("filterStartDate");
filterFinishDate = (Datebox) window.getFellow("filterFinishDate");
monthlyTimesheetsPopup = (Popup) window
.getFellow("monthlyTimesheetsPopup");
monthlyTimesheetsDatebox = (Datebox) window
.getFellow("monthlyTimesheetsDatebox");
monthlyTimesheetsBandboxSearch = (BandboxSearch) window
.getFellow("monthlyTimesheetsBandboxSearch");
personalTimesheetsPopup = (Popup) window
.getFellow("personalTimesheetsPopup");
personalTimesheetsDatebox = (Datebox) window
.getFellow("personalTimesheetsDatebox");
personalTimesheetsBandboxSearch = (BandboxSearch) window
.getFellow("personalTimesheetsBandboxSearch");
clearFilterDates();
}
@ -1616,20 +1616,20 @@ public class WorkReportCRUDController extends GenericForwardComposer implements
return workReportModel.getBoundWorkers();
}
public void createOrEditMonthlyTimesheet() {
Date date = monthlyTimesheetsDatebox.getValue();
public void createOrEditPersonalTimesheet() {
Date date = personalTimesheetsDatebox.getValue();
if (date == null) {
throw new WrongValueException(monthlyTimesheetsDatebox,
throw new WrongValueException(personalTimesheetsDatebox,
_("Please set a date"));
}
Resource resource = (Resource) monthlyTimesheetsBandboxSearch
Resource resource = (Resource) personalTimesheetsBandboxSearch
.getSelectedElement();
if (resource == null) {
throw new WrongValueException(monthlyTimesheetsBandboxSearch,
throw new WrongValueException(personalTimesheetsBandboxSearch,
_("Please select a worker"));
}
monthlyTimesheetController.goToCreateOrEditFormForResource(
personalTimesheetController.goToCreateOrEditFormForResource(
LocalDate.fromDateFields(date), resource);
}

View file

@ -42,7 +42,7 @@ public class WorkReportDTO {
WorkReportType workReportType = workReport.getWorkReportType();
this.type = workReportType.getName();
if (workReportType.isMonthlyTimesheetsType()) {
if (workReportType.isPersonalTimesheetsType()) {
this.type += " - " + workReport.getResource().getShortDescription();
}

View file

@ -629,11 +629,11 @@ public class WorkReportModel extends IntegrationEntityModel implements
@Override
@Transactional(readOnly = true)
public boolean isMonthlyTimesheet(WorkReport workReport) {
public boolean isPersonalTimesheet(WorkReport workReport) {
try {
return workReportTypeDAO.find(
workReport.getWorkReportType().getId())
.isMonthlyTimesheetsType();
.isPersonalTimesheetsType();
} catch (InstanceNotFoundException e) {
throw new RuntimeException(e);
}

View file

@ -47,7 +47,7 @@ import org.libreplan.web.common.MessagesForUser;
import org.libreplan.web.common.components.Autocomplete;
import org.libreplan.web.common.components.bandboxsearch.BandboxSearch;
import org.libreplan.web.security.SecurityUtils;
import org.libreplan.web.users.dashboard.IMonthlyTimesheetController;
import org.libreplan.web.users.dashboard.IPersonalTimesheetController;
import org.zkoss.ganttz.IPredicate;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.WrongValueException;
@ -109,7 +109,7 @@ public class WorkReportQueryController extends GenericForwardComposer {
private IWorkReportCRUDControllerEntryPoints workReportCRUD;
@javax.annotation.Resource
private IMonthlyTimesheetController monthlyTimesheetController;
private IPersonalTimesheetController personalTimesheetController;
@Override
public void doAfterCompose(Component comp) throws Exception {
@ -329,9 +329,9 @@ public class WorkReportQueryController extends GenericForwardComposer {
if (SecurityUtils.isSuperuserOrUserInRoles(UserRole.ROLE_TIMESHEETS)) {
workReportCRUD.goToEditForm(workReport);
} else if (SecurityUtils.isUserInRole(UserRole.ROLE_BOUND_USER)
&& workReportModel.isMonthlyTimesheet(workReport)
&& workReportModel.isPersonalTimesheet(workReport)
&& belongsToCurrentUser(line)) {
monthlyTimesheetController
personalTimesheetController
.goToCreateOrEditForm(line.getLocalDate());
} else {
messagesForUser.showMessage(Level.WARNING,

View file

@ -116,7 +116,7 @@ public class WorkReportTypeCRUDController extends BaseCRUDController<WorkReportT
private OrderedFieldsAndLabelsRowRenderer orderedFieldsAndLabesRowRenderer = new OrderedFieldsAndLabelsRowRenderer();
public List<WorkReportType> getWorkReportTypes() {
return workReportTypeModel.getWorkReportTypesExceptMonthlyTimeSheets();
return workReportTypeModel.getWorkReportTypesExceptPersonalTimeSheets();
}
public WorkReportType getWorkReportType() {

View file

@ -118,11 +118,11 @@ public class WorkReportTypeModel extends IntegrationEntityModel implements
@Override
@Transactional(readOnly = true)
public List<WorkReportType> getWorkReportTypesExceptMonthlyTimeSheets() {
public List<WorkReportType> getWorkReportTypesExceptPersonalTimeSheets() {
List<WorkReportType> list = workReportTypeDAO.list(WorkReportType.class);
try {
list.remove(workReportTypeDAO
.findUniqueByName(PredefinedWorkReportTypes.MONTHLY_TIMESHEETS
.findUniqueByName(PredefinedWorkReportTypes.PERSONAL_TIMESHEETS
.getName()));
} catch (NonUniqueResultException e) {
throw new RuntimeException(e);
@ -151,9 +151,9 @@ public class WorkReportTypeModel extends IntegrationEntityModel implements
@Override
@Transactional(readOnly = true)
public void initEdit(WorkReportType workReportType) {
if (workReportType.isMonthlyTimesheetsType()) {
if (workReportType.isPersonalTimesheetsType()) {
throw new IllegalArgumentException(
"Monthly timesheets timesheet template cannot be edited");
"Personal timesheets timesheet template cannot be edited");
}
setListing(false);
@ -220,9 +220,9 @@ public class WorkReportTypeModel extends IntegrationEntityModel implements
@Override
@Transactional
public void confirmRemove(WorkReportType workReportType) {
if (workReportType.isMonthlyTimesheetsType()) {
if (workReportType.isPersonalTimesheetsType()) {
throw new IllegalArgumentException(
"Monthly timesheets timesheet template cannot be removed");
"Personal timesheets timesheet template cannot be removed");
}
try {

View file

@ -69,10 +69,19 @@
selectedElement="@{configurationController.defaultCalendar}" />
</row>
<row>
<label value="${i18n:_('Hours type for monthly timesheets')}" />
<label value="${i18n:_('Hours type for personal timesheets')}" />
<bandboxSearch
finder="TypeOfWorkHoursBandboxFinder"
selectedElement="@{configurationController.monthlyTimesheetsTypeOfWorkHours, access='both'}" />
selectedElement="@{configurationController.personalTimesheetsTypeOfWorkHours, access='both'}" />
</row>
<row>
<label value="${i18n:_('Personal timesheets peridocity')}" />
<listbox model="@{configurationController.personalTimesheetsPeriodicities}"
itemRenderer="@{configurationController.personalTimesheetsPeriodicityRenderer}"
selectedItem="@{configurationController.selectedPersonalTimesheetsPeriodicity}"
disabled="@{configurationController.personalTimesheetsPeriodicityDisabled}"
tooltiptext="@{configurationController.personalTimesheetsPeriodicityTooltip}"
mold="select" />
</row>
<row>
<label

View file

@ -18,11 +18,11 @@
<http://www.gnu.org/licenses/>.
-->
<groupbox apply="org.libreplan.web.users.dashboard.MonthlyTimesheetsAreaController">
<caption label="${i18n:_('Monthly timesheets')}" />
<groupbox apply="org.libreplan.web.users.dashboard.PersonalTimesheetsAreaController">
<caption label="${i18n:_('Personal timesheets')}" />
<grid model="@{controller.monthlyTimesheets}" mold="paging"
pageSize="10" rowRenderer="@{controller.monthlyTimesheetsRenderer}"
<grid model="@{controller.personalTimesheets}" mold="paging"
pageSize="10" rowRenderer="@{controller.personalTimesheetsRenderer}"
sclass="clickable-rows">
<columns sizable="true">
<column label="${i18n:_('Date')}"

View file

@ -18,7 +18,7 @@
<http://www.gnu.org/licenses/>.
-->
<?page id="exceptionDayTypesList" title="${i18n:_('LibrePlan: Monthly timesheet')}" ?>
<?page id="exceptionDayTypesList" title="${i18n:_('LibrePlan: Personal timesheet')}" ?>
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
<?init class="org.zkoss.zk.ui.util.Composition" arg0="/common/layout/template.zul"?>
@ -28,8 +28,8 @@
<?link rel="stylesheet" type="text/css" href="/common/css/user_dashboard.css"?>
<zk>
<window apply="org.libreplan.web.users.dashboard.MonthlyTimesheetController"
self="@{define(content)}" title="${i18n:_('Monthly timesheet')}">
<window apply="org.libreplan.web.users.dashboard.PersonalTimesheetController"
self="@{define(content)}" title="${i18n:_('Personal timesheet')}">
<div id="messagesContainer" />
@ -48,22 +48,22 @@
<rows>
<row>
<label value="${i18n:_('Date')}" />
<hbox align="pack">
<div visible="@{controller.currentUser}">
<button id="previousMonth"
image="/common/img/ico_step_left.png" sclass="icono"
onClick="controller.previousMonth();"
tooltiptext="${i18n:_('Previous')}"
disabled="@{controller.firstMonth}" />
</div>
<label value="@{controller.date}" />
<div visible="@{controller.currentUser}">
<button id="nextMonth"
onClick="controller.nextMonth();" image="/common/img/ico_step_right.png"
tooltiptext="${i18n:_('Next')}" sclass="icono"
disabled="@{controller.lastMonth}" />
</div></hbox>
<hbox align="pack">
<div visible="@{controller.currentUser}">
<button id="previousPeriod"
image="/common/img/ico_step_left.png" sclass="icono"
onClick="controller.previousPeriod();"
tooltiptext="${i18n:_('Previous')}"
disabled="@{controller.firstPeriod}" />
</div>
<label value="@{controller.timesheetString}" />
<div visible="@{controller.currentUser}">
<button id="nextPeriod"
onClick="controller.nextPeriod();" image="/common/img/ico_step_right.png"
tooltiptext="${i18n:_('Next')}" sclass="icono"
disabled="@{controller.lastPeriod}" />
</div>
</hbox>
</row>
<row>
<label value="${i18n:_('Resource')}" />
@ -81,8 +81,8 @@
</columns>
<rows>
<row visible="@{controller.hasOtherReports}">
<label value="${i18n:_('Total monthly timesheet')}" />
<label id="summaryTotalMonthlyTimesheet" />
<label value="${i18n:_('Total personal timesheet')}" />
<label id="summaryTotalPersonalTimesheet" />
</row>
<row visible="@{controller.hasOtherReports}">
<label value="${i18n:_('Total other')}" />

View file

@ -27,7 +27,7 @@
<?link rel="stylesheet" type="text/css" href="/common/css/libreplan_zk.css"?>
<?component name="my-tasks-area" inline="true" macroURI="_myTasksArea.zul"?>
<?component name="monthly-timesheets-area" inline="true" macroURI="_monthlyTimesheetsArea.zul"?>
<?component name="personal-timesheets-area" inline="true" macroURI="_personalTimesheetsArea.zul"?>
<?component name="expenses-area" inline="true" macroURI="_expensesArea.zul"?>
<zk>
@ -39,7 +39,7 @@
<my-tasks-area />
<monthly-timesheets-area />
<personal-timesheets-area />
<expenses-area />

View file

@ -107,7 +107,7 @@
onClick="controller.onCreateNewWorkReport()"/>
</hbox>
</div>
<popup id="monthlyTimesheetsPopup" width="300px">
<popup id="personalTimesheetsPopup" width="300px">
<grid>
<columns>
<column width="50px"/>
@ -116,11 +116,11 @@
<rows>
<row>
<label value="${i18n:_('Date')}" />
<datebox id="monthlyTimesheetsDatebox" />
<datebox id="personalTimesheetsDatebox" />
</row>
<row>
<label value="${i18n:_('Worker')}" />
<bandboxSearch id="monthlyTimesheetsBandboxSearch"
<bandboxSearch id="personalTimesheetsBandboxSearch"
finder="ResourceBandboxFinder"
model="@{controller.boundWorkers}"
widthBandbox="200px"
@ -128,8 +128,8 @@
</row>
</rows>
</grid>
<button onClick="controller.createOrEditMonthlyTimesheet();"
label="${i18n:_('Go to monthly timesheet')}" />
<button onClick="controller.createOrEditPersonalTimesheet();"
label="${i18n:_('Go to personal timesheet')}" />
</popup>
</window>

View file

@ -40,7 +40,7 @@ import org.junit.runner.RunWith;
import org.libreplan.business.common.IAdHocTransactionService;
import org.libreplan.business.common.IOnTransaction;
import org.libreplan.business.common.entities.IConfigurationBootstrap;
import org.libreplan.business.common.entities.IMonthlyTimesheetsTypeOfWorkHoursBootstrap;
import org.libreplan.business.common.entities.IPersonalTimesheetsTypeOfWorkHoursBootstrap;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.costcategories.daos.ITypeOfWorkHoursDAO;
import org.libreplan.business.costcategories.entities.ITypeOfWorkHoursBootstrap;
@ -86,7 +86,7 @@ public class TypeOfWorkHoursServiceTest {
private ITypeOfWorkHoursBootstrap typeOfWorkHoursBootstrap;
@Autowired
private IMonthlyTimesheetsTypeOfWorkHoursBootstrap monthlyTimesheetsTypeOfWorkHoursBootstrap;
private IPersonalTimesheetsTypeOfWorkHoursBootstrap personalTimesheetsTypeOfWorkHoursBootstrap;
@Before
public void loadRequiredData() {
@ -96,7 +96,7 @@ public class TypeOfWorkHoursServiceTest {
public Void execute() {
configurationBootstrap.loadRequiredData();
typeOfWorkHoursBootstrap.loadRequiredData();
monthlyTimesheetsTypeOfWorkHoursBootstrap.loadRequiredData();
personalTimesheetsTypeOfWorkHoursBootstrap.loadRequiredData();
return null;
}
});