Merge pull request #141 from lmann99/master

Possible fixes for lazy initialization errors, email notifications, and other minor issues
This commit is contained in:
Jeroen Baten 2018-06-04 13:41:47 +02:00 committed by GitHub
commit d49cee584d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
75 changed files with 1395 additions and 318 deletions

View file

@ -8,22 +8,22 @@ Purpose
This report allows to extract a list of the tasks and time devoted to them by workers in a period of time. There are several filters which allow users to adjust the query to get just the wanted information and avoiding extra data.
Input paratemers and filters
Input parameters and filters
============================
* **Dates**.
* *Type*: Optional.
* *Two date fields*:
* *Start Date.* This is the minimum date of the work reports which are wanted. Work reports with an earlier date than the *start date* are ignored. If this parameter is not filled, there is not inferior filtering date.
* *End Date.* This is the maximum date of the work reports which will be included in the results. Work reports with a later date than the *end date* will be skipped. If this parameter is not filled, there is not upper limit of the work reports filtered.
* *Start Date.* This is the minimum date of the work reports which are wanted. Work reports with an earlier date than the *start date* are ignored. If this parameter is not filled, there is no filtering of work reports by *start date*.
* *End Date.* This is the maximum date of the work reports which will be included in the results. Work reports with a later date than the *end date* will be ignored. If this parameter is not filled, there is no filtering of work reports by *end date*.
* **Filter by workers**
* *Type*: Optional.
* *How it works*: You can select one worker to restrict the work reports to the time tracking of that particular worker. If you leave it empty, the work reports are retrieved independently of the worker.
* *How it works*: You can select one or several workers to restrict the work reports to the time tracking of that particular worker. You can add a worker to be used as a filter by searching them in the selector and by pressing the *Add* button. If you leave it empty, the work reports are retrieved independently of the worker.
* **Filter by labels**
* *Type:* Optional.
* *How it works*: You can add one or several labels by searching them in the selector and by pressing the *Add* button to be used as filter. They are used to select the tasks that will be included in the results to compute the hours devoted in them.
* *How it works*: You can add one or several labels to be used as filter by searching them in the selector and by pressing the *Add* button. They are used to select the tasks that will be included in the results to compute the hours devoted in them. This filter can be applied to timesheets, tasks, both, or any.
* **Filter by criteria**
* *Type:* Optional.
@ -39,7 +39,7 @@ In the heading of the report is informed about the filters that were configured
Foot page
---------
The date in which the repot was got is showed.
The date on which the report was run is listed.
Body
----

View file

@ -30,6 +30,8 @@ The progress is represented with two bars:
* *Expected progress*. It is the progress the project should have at the
moment according to the planning created.
To view each bar's actual measured valued hover the mouse cursor over the bar.
The project global progress is estimated in several different ways as there
is not a unique right method to do it:
@ -79,7 +81,6 @@ There are several *Earned Value Management* cost indicators calculated:
* = 100 is also good, means the cost is right on plan.
* < 100 is bad, means that the cost of completing the work is higher than
planned.
* **ETC (Estimate To Complete)**. It is the time that is pending to devote
to the project to finish it.
* **BAC (Budget At Completion)**. It is the total amount of work allocated

View file

@ -0,0 +1,24 @@
Pipeline planning dashboard
###############################
.. contents::
The pipeline planning dashboard is a *LibrePlan* perspective which lists the names of all company projects in a table.
This 'pipeline' table has nine columns each corresponding to a project status:
* PRE-SALES
* OFFERED
* OUTSOURCED
* ACCEPTED
* STARTED
* ON HOLD
* FINISHED
* CANCELLED
* ARCHIVED
Projects are listed by name in each column based on their current status.
A project's start date, end date, and current progress can be viewed in a 'tool tip' popup by hovering the mouse pointer
over a project's name.
Projects with an *ARCHIVED* status can be hidden by unchecking the 'Show archived column data' checkbox.

View file

@ -0,0 +1,19 @@
Dashboards
##########
.. _informes:
.. contents::
"LibrePlan" has dashboard views for projects that provide an overview of the current state of projects.
The two dashboard views are:
.. raw:: html
<ul>
<li>
<a href="17-1-project-dashboard.html">Individual project dashboard</a>
</li><li>
<a href="17-2-pipeline-dashboard.html">All projects pipeline dashboard</a>
</ul>

View file

@ -25,7 +25,8 @@
14-custos Xavier Castaño (xcastanho@igalia.com)
15-informes Xavier Castaño (xcastanho@igalia.com)
16-ldap-authentication Ignacio Diaz Teijido (ignacio.diaz@cafedered.com), Javier Moran Rua (jmoran@igalia.com)
17-project-dashboard Javier Moran Rua (jmoran@igalia.com)
17-dashboards Javier Moran Rua (jmoran@igalia.com)
18-connectors Miciele Ghiorghis (m.ghiorghis@antoniusziekenhuis.nl)
19-scheduler Miciele Ghiorghis (m.ghiorghis@antoniusziekenhuis.nl)
20-acerca-de Xavier Castaño (xcastanho@igalia.com)
21-communications Xavier Castaño (xcastanho@igalia.com)

View file

@ -243,6 +243,8 @@ public class FunctionalityExposedForExtensions<T> implements IContext<T> {
result.setShowingReportedHours(planner.showReportedHoursRightNow());
result.setShowingMoneyCostBar(planner.showMoneyCostBarRightNow());
result.setShowingAdvances(planner.showAdvancesRightNow());
result.setShowingLabels(planner.showLabelsRightNow());
result.setShowingResources(planner.showResourcesRightNow());
mapper.register(position, result, data);

View file

@ -156,6 +156,10 @@ public class Planner extends HtmlMacroComponent {
private boolean shownMoneyCostBarByDefault = false;
private boolean shownLabelsByDefault = false;
private boolean shownResourcesByDefault = false;
private FilterAndParentExpandedPredicates predicate;
private boolean visibleChart;
@ -430,6 +434,27 @@ public class Planner extends HtmlMacroComponent {
showMoneyCostBarButton.setVisible(false);
}
// view buttons toggle state so set all off prior to toggling
if ( configuration.isShowResourcesOn() ) {
showAllResources();
}
if ( configuration.isShowAdvancesOn() ) {
showAdvances();
}
if ( configuration.isShowReportedHoursOn() ) {
showReportedHours();
}
if ( configuration.isShowLabelsOn() ) {
showAllLabels();
}
if ( configuration.isShowMoneyCostBarOn() ) {
showMoneyCostBar();
}
listZoomLevels.setSelectedIndex(getZoomLevel().ordinal());
this.visibleChart = configuration.isExpandPlanningViewCharts();
@ -656,7 +681,6 @@ public class Planner extends HtmlMacroComponent {
public void showReportedHours() {
Button showReportedHoursButton = (Button) getFellow("showReportedHours");
if ( disabilityConfiguration.isReportedHoursEnabled() ) {
if ( isShowingReportedHours ) {
context.hideReportedHours();
diagramGraph.removePostGraphChangeListener(showReportedHoursOnChange);
@ -694,28 +718,33 @@ public class Planner extends HtmlMacroComponent {
public void showAllLabels() {
Button showAllLabelsButton = (Button) getFellow("showAllLabels");
if ( isShowingLabels ) {
Clients.evalJavaScript("ganttz.TaskList.getInstance().hideAllTaskLabels()");
showAllLabelsButton.setSclass("planner-command show-labels");
} else {
Clients.evalJavaScript("ganttz.TaskList.getInstance().showAllTaskLabels()");
showAllLabelsButton.setSclass("planner-command show-labels clicked");
}
if ( disabilityConfiguration.isLabelsEnabled() ) {
if ( isShowingLabels ) {
Clients.evalJavaScript("ganttz.TaskList.getInstance().hideAllTaskLabels()");
showAllLabelsButton.setSclass("planner-command show-labels");
} else {
Clients.evalJavaScript("ganttz.TaskList.getInstance().showAllTaskLabels()");
showAllLabelsButton.setSclass("planner-command show-labels clicked");
}
isShowingLabels = !isShowingLabels;
isShowingLabels = !isShowingLabels;
}
}
public void showAllResources() {
Button showAllLabelsButton = (Button) getFellow("showAllResources");
if ( isShowingResources ) {
Clients.evalJavaScript("ganttz.TaskList.getInstance().hideResourceTooltips()");
showAllLabelsButton.setSclass("planner-command show-resources");
} else {
Clients.evalJavaScript("ganttz.TaskList.getInstance().showResourceTooltips()");
showAllLabelsButton.setSclass("planner-command show-resources clicked");
}
if ( disabilityConfiguration.isResourcesEnabled() ) {
if ( isShowingResources ) {
Clients.evalJavaScript("ganttz.TaskList.getInstance().hideResourceTooltips()");
showAllLabelsButton.setSclass("planner-command show-resources");
} else {
Clients.evalJavaScript("ganttz.TaskList.getInstance().showResourceTooltips()");
showAllLabelsButton.setSclass("planner-command show-resources clicked");
}
isShowingResources = !isShowingResources;
isShowingResources = !isShowingResources;
}
}
public void print() {
@ -752,7 +781,6 @@ public class Planner extends HtmlMacroComponent {
public void setAreShownAdvancesByDefault(boolean shownAdvanceByDefault) {
this.shownAdvanceByDefault = shownAdvanceByDefault;
this.isShowingAdvances = shownAdvanceByDefault;
}
public void setAreShownReportedHoursByDefault(boolean shownReportedHoursByDefault) {
@ -779,6 +807,30 @@ public class Planner extends HtmlMacroComponent {
return areShownMoneyCostBarByDefault() || isShowingMoneyCostBar;
}
public void setAreShownLabelsByDefault(boolean shownLabelsByDefault) {
this.shownLabelsByDefault = shownLabelsByDefault;
}
public boolean areShownLabelsByDefault() {
return shownLabelsByDefault;
}
public boolean showLabelsRightNow() {
return areShownLabelsByDefault() || isShowingLabels;
}
public void setAreShownResourcesByDefault(boolean shownResourcesByDefault) {
this.shownResourcesByDefault = shownResourcesByDefault;
}
public boolean areShownResourcesByDefault() {
return shownResourcesByDefault;
}
public boolean showResourcesRightNow() {
return areShownResourcesByDefault() || isShowingResources;
}
public void expandAll() {
Button expandAllButton = (Button) getFellow(EXPAND_ALL_BUTTON);
if ( disabilityConfiguration.isExpandAllEnabled() ) {

View file

@ -42,6 +42,10 @@ public interface IDisabilityConfiguration {
public boolean isMoneyCostBarEnabled();
public boolean isLabelsEnabled();
public boolean isResourcesEnabled();
public boolean isExpandAllEnabled();
public boolean isFlattenTreeEnabled();

View file

@ -157,6 +157,10 @@ public class PlannerConfiguration<T> implements IDisabilityConfiguration {
private boolean moneyCostBarEnabled = true;
private boolean labelsEnabled = true;
private boolean ResourcesEnabled = true;
private boolean expandAllEnabled = true;
private boolean flattenTreeEnabled = true;
@ -167,6 +171,18 @@ public class PlannerConfiguration<T> implements IDisabilityConfiguration {
private boolean treeEditable = true;
private boolean showResourcesOn = false;
private boolean showAdvancesOn = false;
private boolean showReportedHoursOn = false;
private boolean showLabelsOn = false;
private boolean showMoneyCostBarOn = false;
private boolean filterExcludeFinishedProject = false;
private IDetailItemModifier firstLevelModifiers = SeveralModifiers.empty();
private IDetailItemModifier secondLevelModifiers = SeveralModifiers.empty();
@ -355,6 +371,24 @@ public class PlannerConfiguration<T> implements IDisabilityConfiguration {
return moneyCostBarEnabled;
}
public void setLabelsEnabled(boolean labelsEnabled) {
this.labelsEnabled = labelsEnabled;
}
@Override
public boolean isLabelsEnabled() {
return labelsEnabled;
}
public void setResourcesEnabled(boolean ResourcesEnabled) {
this.ResourcesEnabled = ResourcesEnabled;
}
@Override
public boolean isResourcesEnabled() {
return ResourcesEnabled;
}
public void setExpandAllEnabled(boolean expandAllEnabled) {
this.expandAllEnabled = expandAllEnabled;
}
@ -495,4 +529,52 @@ public class PlannerConfiguration<T> implements IDisabilityConfiguration {
this.scheduleBackwards = scheduleBackwards;
}
public boolean isShowResourcesOn() {
return showResourcesOn;
}
public void setShowResourcesOn(boolean showResourcesOn) {
this.showResourcesOn = showResourcesOn;
}
public boolean isShowAdvancesOn() {
return showAdvancesOn;
}
public void setShowAdvancesOn(boolean showAdvancesOn) {
this.showAdvancesOn = showAdvancesOn;
}
public boolean isShowReportedHoursOn() {
return showReportedHoursOn;
}
public void setShowReportedHoursOn(boolean showReportedHoursOn) {
this.showReportedHoursOn = showReportedHoursOn;
}
public boolean isShowLabelsOn() {
return showLabelsOn;
}
public void setShowLabelsOn(boolean showLabelsOn) {
this.showLabelsOn = showLabelsOn;
}
public boolean isShowMoneyCostBarOn() {
return showMoneyCostBarOn;
}
public void setShowMoneyCostBarOn(boolean showMoneyCostBarOn) {
this.showMoneyCostBarOn = showMoneyCostBarOn;
}
public boolean isFilterExcludeFinishedProject() {
return filterExcludeFinishedProject;
}
public void setFilterExcludeFinishedProject(boolean filterExcludeFinishedProject) {
this.filterExcludeFinishedProject = filterExcludeFinishedProject;
}
}

View file

@ -73,6 +73,10 @@ public abstract class Task implements ITaskFundamentalProperties {
private PropertyChangeSupport moneyCostBarProperty = new PropertyChangeSupport(this);
private PropertyChangeSupport labelsProperty = new PropertyChangeSupport(this);
private PropertyChangeSupport resourcesProperty = new PropertyChangeSupport(this);
private final ITaskFundamentalProperties fundamentalProperties;
private boolean visible = true;
@ -85,6 +89,10 @@ public abstract class Task implements ITaskFundamentalProperties {
private boolean showingMoneyCostBar = false;
private boolean showingLabels = false;
private boolean showingResources = false;
private ConstraintViolationNotificator<GanttDate> violationNotificator = ConstraintViolationNotificator.create();
private IDependenciesEnforcerHook dependenciesEnforcerHook = GanttDiagramGraph.doNothingHook();
@ -231,6 +239,26 @@ public abstract class Task implements ITaskFundamentalProperties {
return showingMoneyCostBar;
}
public void setShowingResources(boolean showingResources) {
boolean previousValue = this.showingResources;
this.showingResources = showingResources;
resourcesProperty.firePropertyChange("showingResources", previousValue, this.showingResources);
}
public boolean isShowingResources() {
return showingResources;
}
public void setShowingLabels(boolean showingLabels) {
boolean previousValue = this.showingLabels;
this.showingLabels = showingLabels;
labelsProperty.firePropertyChange("showingLabels", previousValue, this.showingLabels);
}
public boolean isShowingLabels() {
return showingLabels;
}
public String getName() {
return fundamentalProperties.getName();
}

View file

@ -103,6 +103,7 @@ public class AdHocTransactionService implements IAdHocTransactionService {
};
}
@Override
@Transactional
public <T> T runOnTransaction(IOnTransaction<T> onTransaction) {
return onTransaction.execute();

View file

@ -23,8 +23,12 @@ import org.hibernate.criterion.Restrictions;
import org.libreplan.business.common.daos.GenericDAOHibernate;
import org.libreplan.business.email.entities.EmailNotification;
import org.libreplan.business.email.entities.EmailTemplateEnum;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.planner.entities.TaskElement;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
//import java.util.ArrayList;
import java.util.List;
/**
@ -50,6 +54,22 @@ public class EmailNotificationDAO
.list();
}
@Override
public List<EmailNotification> getAllByProject(TaskElement taskElement) {
return getSession()
.createCriteria(EmailNotification.class)
.add(Restrictions.eq("project", taskElement))
.list();
}
@Override
public List<EmailNotification> getAllByTask(TaskElement taskElement) {
return getSession()
.createCriteria(EmailNotification.class)
.add(Restrictions.eq("task", taskElement))
.list();
}
@Override
public boolean deleteAll() {
List<EmailNotification> notifications = list(EmailNotification.class);
@ -89,4 +109,26 @@ public class EmailNotificationDAO
.uniqueResult() == null;
}
@Override
public boolean deleteByProject(TaskElement taskElement) {
List<EmailNotification> notifications = getAllByProject(taskElement);
for (Object item : notifications){
getSession().delete(item);
}
return getAllByProject(taskElement).isEmpty();
}
@Override
public boolean deleteByTask(TaskElement taskElement) {
List<EmailNotification> notifications = getAllByTask(taskElement);
for (Object item : notifications){
getSession().delete(item);
}
return getAllByTask(taskElement).isEmpty();
}
}

View file

@ -22,6 +22,8 @@ package org.libreplan.business.email.daos;
import org.libreplan.business.common.daos.IGenericDAO;
import org.libreplan.business.email.entities.EmailNotification;
import org.libreplan.business.email.entities.EmailTemplateEnum;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.planner.entities.TaskElement;
import java.util.List;
@ -36,9 +38,18 @@ public interface IEmailNotificationDAO extends IGenericDAO<EmailNotification, Lo
List<EmailNotification> getAllByType(EmailTemplateEnum enumeration);
List<EmailNotification> getAllByProject(TaskElement taskElement);
List<EmailNotification> getAllByTask(TaskElement taskElement);
boolean deleteAll();
boolean deleteAllByType(EmailTemplateEnum enumeration);
boolean deleteById(EmailNotification notification);
boolean deleteByProject(TaskElement taskElement);
boolean deleteByTask(TaskElement taskElement);
}

View file

@ -86,7 +86,7 @@ public interface IOrderDAO extends IIntegrationEntityDAO<Order> {
List<Order> getOrdersByReadAuthorizationBetweenDatesByLabelsCriteriaCustomerAndState(
String username, Scenario scenario, Date startDate, Date endDate,
List<Label> labels, List<Criterion> criteria,
ExternalCompany customer, OrderStatusEnum state);
ExternalCompany customer, OrderStatusEnum state, Boolean excludeFinishedProject);
/**
* Returns the order filtered by the name.

View file

@ -231,9 +231,10 @@ public class OrderDAO extends IntegrationEntityDAO<Order> implements IOrderDAO {
List<Label> labels,
List<Criterion> criteria,
ExternalCompany customer,
OrderStatusEnum state) {
OrderStatusEnum state,
Boolean excludeFinishedProject) {
List<Long> ordersIdsFiltered = getOrdersIdsFiltered(user, labels, criteria, customer, state);
List<Long> ordersIdsFiltered = getOrdersIdsFiltered(user, labels, criteria, customer, state, excludeFinishedProject);
if (ordersIdsFiltered != null && ordersIdsFiltered.isEmpty()) {
return Collections.emptyList();
}
@ -354,7 +355,8 @@ public class OrderDAO extends IntegrationEntityDAO<Order> implements IOrderDAO {
List<Label> labels,
List<Criterion> criteria,
ExternalCompany customer,
OrderStatusEnum state) {
OrderStatusEnum state,
Boolean excludeFinishedProject) {
List<Long> ordersIdsByReadAuthorization = getOrdersIdsByReadAuthorization(user);
@ -405,6 +407,15 @@ public class OrderDAO extends IntegrationEntityDAO<Order> implements IOrderDAO {
where += "o.state = :state ";
}
if (excludeFinishedProject != null && excludeFinishedProject == true) {
if (where.isEmpty()) {
where += "WHERE ";
} else {
where += "AND ";
}
where += "o.state <> '" + OrderStatusEnum.FINISHED.getIndex() + "'";
}
// If not restrictions by labels, criteria, customer or state
if (where.isEmpty()) {
return ordersIdsByReadAuthorization;
@ -550,7 +561,8 @@ public class OrderDAO extends IntegrationEntityDAO<Order> implements IOrderDAO {
List<Label> labels,
List<Criterion> criteria,
ExternalCompany customer,
OrderStatusEnum state) {
OrderStatusEnum state,
Boolean excludeFinishedProject) {
User user;
try {
@ -559,7 +571,7 @@ public class OrderDAO extends IntegrationEntityDAO<Order> implements IOrderDAO {
throw new RuntimeException(e);
}
return existsInScenario(getOrdersByReadAuthorizationBetweenDatesByLabelsCriteriaCustomerAndState(
user, startDate, endDate, labels, criteria, customer, state), scenario);
user, startDate, endDate, labels, criteria, customer, state, excludeFinishedProject), scenario);
}
private List<Order> existsInScenario(List<Order> orders, Scenario scenario) {

View file

@ -39,6 +39,7 @@ import org.hibernate.Query;
import org.hibernate.criterion.Restrictions;
import org.libreplan.business.common.daos.IntegrationEntityDAO;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.email.daos.IEmailNotificationDAO;
import org.libreplan.business.expensesheet.daos.IExpenseSheetLineDAO;
import org.libreplan.business.labels.entities.Label;
import org.libreplan.business.orders.entities.Order;
@ -46,6 +47,7 @@ import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.orders.entities.SchedulingDataForVersion;
import org.libreplan.business.orders.entities.TaskSource;
import org.libreplan.business.planner.daos.ITaskSourceDAO;
import org.libreplan.business.planner.entities.TaskElement;
import org.libreplan.business.resources.entities.Criterion;
import org.libreplan.business.templates.entities.OrderElementTemplate;
import org.libreplan.business.workingday.EffortDuration;
@ -84,6 +86,9 @@ public class OrderElementDAO extends IntegrationEntityDAO<OrderElement> implemen
@Autowired
private ITaskSourceDAO taskSourceDAO;
@Autowired
private IEmailNotificationDAO emailNotificationDAO;
@Override
public List<OrderElement> findWithoutParent() {
return getSession()
@ -142,6 +147,9 @@ public class OrderElementDAO extends IntegrationEntityDAO<OrderElement> implemen
@Override
public void remove(Long id) throws InstanceNotFoundException {
OrderElement orderElement = find(id);
removeNotifications(orderElement);
removeTaskSourcesFor(this.taskSourceDAO, orderElement);
for (WorkReport each : getWorkReportsPointingTo(orderElement)) {
@ -151,6 +159,17 @@ public class OrderElementDAO extends IntegrationEntityDAO<OrderElement> implemen
super.remove(id);
}
public void removeNotifications(OrderElement orderElement) {
List<SchedulingDataForVersion> allVersions = orderElement.getSchedulingDataForVersionFromBottomToTop();
for (TaskSource each : taskSourcesFrom(allVersions)) {
TaskElement taskElement = each.getTask();
if ( taskElement != null) {
emailNotificationDAO.deleteByTask(taskElement);
}
}
}
public static void removeTaskSourcesFor(ITaskSourceDAO taskSourceDAO, OrderElement orderElement)
throws InstanceNotFoundException {

View file

@ -243,7 +243,8 @@ public abstract class TaskElement extends BaseEntity {
}
public String getProjectCode() {
return getOrderElement().getOrder().getCode();
//then get the top level project code
return getTopMost().getOrderElement().getOrder().getCode();
}
public void setName(String name) {

View file

@ -122,8 +122,11 @@ public interface IWorkerDAO extends IIntegrationEntityDAO<Worker> {
public List<Worker> findByFirstNameSecondNameAnotherTransaction(
String firstname, String secondname);
public Worker getCurrentWorker(Long resourceID);
/**
* Return the list of {@link Worker Workers} bound to any {@link User}.
*/
List<Worker> getBound();
}

View file

@ -198,4 +198,18 @@ public class WorkerDAO extends IntegrationEntityDAO<Worker>
criteria.add(Restrictions.isNotNull("user"));
return criteria.list();
}
}
@Override
@Transactional(readOnly = true)
public Worker getCurrentWorker(Long resourceID) {
List<Worker> workerList = getWorkers();
for (Worker worker : workerList) {
if (worker.getId().equals(resourceID)) {
return worker;
}
}
return null;
}
}

View file

@ -26,6 +26,7 @@ import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import org.libreplan.business.common.Registry;
import org.libreplan.business.common.daos.GenericDAOHibernate;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.users.entities.OrderAuthorization;
@ -68,6 +69,7 @@ public class OrderAuthorizationDAO extends GenericDAOHibernate<OrderAuthorizatio
public List<OrderAuthorization> listByUserAndItsProfiles(User user) {
List<OrderAuthorization> list = new ArrayList<OrderAuthorization>();
list.addAll(listByUser(user));
Registry.getUserDAO().reattach(user);
for(Profile profile : user.getProfiles()) {
list.addAll(listByProfile(profile));
}
@ -79,6 +81,7 @@ public class OrderAuthorizationDAO extends GenericDAOHibernate<OrderAuthorizatio
if (!listByUser(user).isEmpty()) {
return true;
}
Registry.getUserDAO().reattach(user);
for (Profile profile : user.getProfiles()) {
if (!listByProfile(profile).isEmpty()) {
return true;
@ -108,6 +111,7 @@ public class OrderAuthorizationDAO extends GenericDAOHibernate<OrderAuthorizatio
public List<OrderAuthorization> listByOrderUserAndItsProfiles(Order order, User user) {
List<OrderAuthorization> list = new ArrayList<OrderAuthorization>();
list.addAll(listByOrderAndUser(order,user));
Registry.getUserDAO().reattach(user);
for(Profile profile : user.getProfiles()) {
list.addAll(listByOrderAndProfile(order, profile));
}

View file

@ -93,12 +93,24 @@ public class User extends BaseEntity implements IHumanIdentifiable{
private Integer projectsFilterPeriodTo;
private Boolean projectsFilterFinishedOn = false;
private Criterion resourcesLoadFilterCriterion = null;
private Integer resourcesLoadFilterPeriodSince;
private Integer resourcesLoadFilterPeriodTo;
private boolean showResourcesOn = false;
private boolean showAdvancesOn = false;
private boolean showReportedHoursOn = false;
private boolean showLabelsOn = false;
private boolean showMoneyCostBarOn = false;
/**
* Necessary for Hibernate. Please, do not call it.
*/
@ -434,6 +446,14 @@ public class User extends BaseEntity implements IHumanIdentifiable{
projectsFilterPeriodTo = period;
}
public boolean isProjectsFilterFinishedOn() {
return projectsFilterFinishedOn;
}
public void setProjectsFilterFinishedOn(boolean projectsFilterFinishedOn) {
this.projectsFilterFinishedOn = projectsFilterFinishedOn;
}
public Integer getResourcesLoadFilterPeriodSince() {
return resourcesLoadFilterPeriodSince;
}
@ -450,4 +470,44 @@ public class User extends BaseEntity implements IHumanIdentifiable{
resourcesLoadFilterPeriodTo = period;
}
public boolean isShowResourcesOn() {
return showResourcesOn;
}
public void setShowResourcesOn(boolean showResourcesOn) {
this.showResourcesOn = showResourcesOn;
}
public boolean isShowAdvancesOn() {
return showAdvancesOn;
}
public void setShowAdvancesOn(boolean showAdvancesOn) {
this.showAdvancesOn = showAdvancesOn;
}
public boolean isShowReportedHoursOn() {
return showReportedHoursOn;
}
public void setShowReportedHoursOn(boolean showReportedHoursOn) {
this.showReportedHoursOn = showReportedHoursOn;
}
public boolean isShowLabelsOn() {
return showLabelsOn;
}
public void setShowLabelsOn(boolean showLabelsOn) {
this.showLabelsOn = showLabelsOn;
}
public boolean isShowMoneyCostBarOn() {
return showMoneyCostBarOn;
}
public void setShowMoneyCostBarOn(boolean showMoneyCostBarOn) {
this.showMoneyCostBarOn = showMoneyCostBarOn;
}
}

View file

@ -0,0 +1,109 @@
<?xml version="1.0" encoding="utf-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet id="add-new-column-show-reported-hours" author="lmann">
<comment>Add columns to store user default setting of show/hide reported hours button</comment>
<addColumn tableName="user_table">
<column name="show_reported_hours_on" type="BOOLEAN" />
</addColumn>
</changeSet>
<changeSet id="add-new-columns-show-resources" author="lmann">
<comment>Add columns to store user default setting of show/hide resources button</comment>
<addColumn tableName="user_table">
<column name="show_resources_on" type="BOOLEAN" />
</addColumn>
</changeSet>
<changeSet id="add-new-columns-show-advances" author="lmann">
<comment>Add columns to store user default setting of show/hide advances button</comment>
<addColumn tableName="user_table">
<column name="show_advances_on" type="BOOLEAN" />
</addColumn>
</changeSet>
<changeSet id="add-new-columns-show-labels" author="lmann">
<comment>Add columns to store user default setting of show/hide labels button</comment>
<addColumn tableName="user_table">
<column name="show_labels_on" type="BOOLEAN" />
</addColumn>
</changeSet>
<changeSet id="add-new-columns-show-moneycostbar" author="lmann">
<comment>Add columns to store user default setting of show/hide moneycostbar button</comment>
<addColumn tableName="user_table">
<column name="show_money_cost_bar_on" type="BOOLEAN" />
</addColumn>
</changeSet>
<changeSet id="add-new-columns-projects-filter-finished" author="lmann">
<comment>Add columns to store user default setting of filter finished projects in views</comment>
<addColumn tableName="user_table">
<column name="projects_filter_finished_on" type="BOOLEAN" />
</addColumn>
</changeSet>
<changeSet id="set-default-value-show-reported-hours" author="lmann">
<addDefaultValue tableName="user_table"
columnName="show_reported_hours_on"
defaultValueBoolean="FALSE" />
<addNotNullConstraint tableName="user_table"
columnName="show_reported_hours_on"
defaultNullValue="FALSE"
columnDataType="BOOLEAN" />
</changeSet>
<changeSet id="set-default-value-show-resources" author="lmann">
<addDefaultValue tableName="user_table"
columnName="show_resources_on"
defaultValueBoolean="FALSE" />
<addNotNullConstraint tableName="user_table"
columnName="show_resources_on"
defaultNullValue="FALSE"
columnDataType="BOOLEAN" />
</changeSet>
<changeSet id="set-default-value-show-advances" author="lmann">
<addDefaultValue tableName="user_table"
columnName="show_advances_on"
defaultValueBoolean="FALSE" />
<addNotNullConstraint tableName="user_table"
columnName="show_advances_on"
defaultNullValue="FALSE"
columnDataType="BOOLEAN" />
</changeSet>
<changeSet id="set-default-value-show-labels" author="lmann">
<addDefaultValue tableName="user_table"
columnName="show_labels_on"
defaultValueBoolean="FALSE" />
<addNotNullConstraint tableName="user_table"
columnName="show_labels_on"
defaultNullValue="FALSE"
columnDataType="BOOLEAN" />
</changeSet>
<changeSet id="set-default-value-show-money_cost_bar" author="lmann">
<addDefaultValue tableName="user_table"
columnName="show_money_cost_bar_on"
defaultValueBoolean="FALSE" />
<addNotNullConstraint tableName="user_table"
columnName="show_money_cost_bar_on"
defaultNullValue="FALSE"
columnDataType="BOOLEAN" />
</changeSet>
<changeSet id="set-default-value-projects-filter-finished" author="lmann">
<addDefaultValue tableName="user_table"
columnName="projects_filter_finished_on"
defaultValueBoolean="FALSE" />
<addNotNullConstraint tableName="user_table"
columnName="projects_filter_finished_on"
defaultNullValue="FALSE"
columnDataType="BOOLEAN" />
</changeSet>
</databaseChangeLog>

View file

@ -12,4 +12,5 @@
<include file="db.changelog-1.3.xml"/>
<include file="db.changelog-1.4.xml"/>
<include file="db.changelog-1.5.xml"/>
<include file="db.changelog-1.6.xml"/>
</databaseChangeLog>

View file

@ -40,7 +40,7 @@
</set>
<!-- Indexed the other side -->
<set name="criterionRequirements" access="field" cascade="all,delete-orphan" inverse="true" batch-size="10">
<set name="criterionRequirements" access="field" cascade="all,delete-orphan" inverse="true" batch-size="10" lazy="false">
<key column="order_element_id" not-null="false"/>
<one-to-many class="org.libreplan.business.requirements.entities.CriterionRequirement"/>
</set>
@ -86,7 +86,7 @@
<key column="order_element_id"/>
<!-- Indexed the other side -->
<list name="children" access="field" cascade="all">
<list name="children" access="field" cascade="all" lazy="false">
<key column="parent" not-null="false"/>
<index column="position_in_container"/>
<one-to-many class="OrderElement" />
@ -216,7 +216,7 @@
<property name="fixedPercentage" column="fixed_percentage" access="field" />
<!-- Indexed the other side -->
<set name="criterionRequirements" access="field" cascade="save-update,delete-orphan" inverse="true" batch-size="10">
<set name="criterionRequirements" access="field" cascade="save-update,delete-orphan" inverse="true" batch-size="10" lazy="false">
<key column="hours_group_id" not-null="false"/>
<one-to-many class="org.libreplan.business.requirements.entities.CriterionRequirement"/>
</set>

View file

@ -35,7 +35,7 @@
<!-- Inverse navigation from CriterionRequirement to Criterion -->
<!-- Not indexed. Other side navigation not useful -->
<many-to-one class="org.libreplan.business.resources.entities.Criterion" column="criterion_id"
name="criterion"/>
name="criterion" lazy="false"/>
<subclass discriminator-value="direct" name="DirectCriterionRequirement">
<set access="field" name="children" cascade="delete-orphan" inverse="true" batch-size="10">

View file

@ -53,7 +53,7 @@
</set>
<!-- Index created in a database-object section -->
<set name="profiles" table="user_profiles">
<set name="profiles" table="user_profiles" lazy="false">
<key column="user_id"/>
<many-to-many column="profile_id" class="org.libreplan.business.users.entities.Profile"/>
</set>
@ -66,10 +66,22 @@
<property name="projectsFilterPeriodTo" column="projects_filter_period_to"/>
<property name="projectsFilterFinishedOn" column="projects_filter_finished_on"/>
<property name="resourcesLoadFilterPeriodSince" column="resources_load_filter_period_since"/>
<property name="resourcesLoadFilterPeriodTo" column="resources_load_filter_period_to"/>
<property name="showResourcesOn" column="show_resources_on"/>
<property name="showAdvancesOn" column="show_advances_on"/>
<property name="showReportedHoursOn" column="show_reported_hours_on"/>
<property name="showLabelsOn" column="show_labels_on"/>
<property name="showMoneyCostBarOn" column="show_money_cost_bar_on"/>
<many-to-one name="projectsFilterLabel" cascade="none" lazy="false" column="projects_filter_label_id" />
<many-to-one name="resourcesLoadFilterCriterion" cascade="none" lazy="false"
@ -89,7 +101,7 @@
<property name="profileName" not-null="true" unique="true" column="profile_name" />
<!-- Index created in a database-object section -->
<set name="roles" table="profile_roles">
<set name="roles" table="profile_roles" lazy="false">
<key column="profile_id"/>
<element column="role">
<type name="org.hibernate.type.EnumType">

View file

@ -303,6 +303,42 @@ public class TaskElementDAOTest {
assertThat(child.getParent(), equalTo(reloaded));
}
@Test
@Transactional
public void theTopMostPropertyIsTheToplevelTask() {
TaskGroup taskGroup = createValidTaskGroup();
TaskElement taskElement = createValidTask();
taskGroup.addTaskElement(taskElement);
taskElementDAO.save(taskGroup);
TaskGroup taskGroup2 = createValidTaskGroup();
TaskElement taskElement2 = createValidTask();
taskGroup2.addTaskElement(taskElement2);
taskElementDAO.save(taskGroup2);
taskGroup.addTaskElement(taskGroup2);
taskElementDAO.save(taskGroup);
flushAndEvict(taskGroup);
flushAndEvict(taskGroup2);
TaskElement reloaded;
try {
reloaded = taskElementDAO.find(taskGroup.getId());
} catch (InstanceNotFoundException e) {
throw new RuntimeException(e);
}
List<TaskElement> children = reloaded.getChildren();
for (TaskElement child : children) {
if (child instanceof TaskGroup) {
TaskElement child2 = child.getChildren().get(0);
assertThat(child2.getTopMost(), equalTo(reloaded));
}
}
}
@Test
@Transactional
public void savingGroupSavesAssociatedTaskElements() {

View file

@ -150,7 +150,7 @@ public class SchedulerManager implements ISchedulerManager {
String triggerName = jobSchedulerConfiguration.getJobName() + TRIGGER_SUFFIX;
String triggerGroup = jobSchedulerConfiguration.getJobGroup() + TRIGGER_SUFFIX;
CronTriggerFactoryBean trigger = getTriggerBean(triggerName, triggerGroup);
CronTrigger trigger = getTriggerBean(triggerName, triggerGroup);
if ( trigger == null ) {
LOG.warn("Trigger not found");
@ -164,7 +164,7 @@ public class SchedulerManager implements ISchedulerManager {
}
// deleteJob doesn't work using unscheduleJob
this.scheduler.unscheduleJob(trigger.getObject().getKey());
this.scheduler.unscheduleJob(trigger.getKey());
}
/**
@ -230,7 +230,7 @@ public class SchedulerManager implements ISchedulerManager {
* create it
*/
private CronTriggerFactoryBean createCronTriggerBean(JobSchedulerConfiguration jobSchedulerConfiguration) {
CronTriggerFactoryBean cronTriggerBean = new CronTriggerFactoryBean();
final CronTriggerFactoryBean cronTriggerBean = new CronTriggerFactoryBean();
cronTriggerBean.setName(jobSchedulerConfiguration.getJobName() + TRIGGER_SUFFIX);
cronTriggerBean.setGroup(jobSchedulerConfiguration.getJobGroup() + TRIGGER_SUFFIX);
@ -238,9 +238,8 @@ public class SchedulerManager implements ISchedulerManager {
cronTriggerBean.setCronExpression(
String.valueOf(new CronExpression(jobSchedulerConfiguration.getCronExpression())));
cronTriggerBean.setName(jobSchedulerConfiguration.getJobName());
cronTriggerBean.setGroup(jobSchedulerConfiguration.getJobGroup());
cronTriggerBean.afterPropertiesSet();
return cronTriggerBean;
} catch (ParseException e) {
@ -259,7 +258,7 @@ public class SchedulerManager implements ISchedulerManager {
* @return the created <code>JobDetailFactoryBean</code> or null if unable to it
*/
private JobDetailFactoryBean createJobDetailBean(JobSchedulerConfiguration jobSchedulerConfiguration) {
JobDetailFactoryBean jobDetailBean = new JobDetailFactoryBean();
final JobDetailFactoryBean jobDetailBean = new JobDetailFactoryBean();
Class<?> jobClass = getJobClass(jobSchedulerConfiguration.getJobClassName());
if ( jobClass == null ) {
@ -274,6 +273,8 @@ public class SchedulerManager implements ISchedulerManager {
jobDataAsMap.put("applicationContext", applicationContext);
jobDetailBean.setJobDataAsMap(jobDataAsMap);
jobDetailBean.afterPropertiesSet();
return jobDetailBean;
}
@ -322,9 +323,9 @@ public class SchedulerManager implements ISchedulerManager {
* the trigger group
* @return CronTriggerFactoryBean if found, otherwise null
*/
private CronTriggerFactoryBean getTriggerBean(String triggerName, String triggerGroup) {
private CronTrigger getTriggerBean(String triggerName, String triggerGroup) {
try {
return (CronTriggerFactoryBean) this.scheduler.getTrigger(TriggerKey.triggerKey(triggerName, triggerGroup));
return (CronTrigger) this.scheduler.getTrigger(TriggerKey.triggerKey(triggerName, triggerGroup));
} catch (SchedulerException e) {
LOG.error("Unable to get job trigger", e);
}
@ -333,3 +334,4 @@ public class SchedulerManager implements ISchedulerManager {
}
}

View file

@ -19,12 +19,15 @@
package org.libreplan.importers.notifications;
//import javax.annotation.Resource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.libreplan.business.common.entities.ConnectorProperty;
import org.libreplan.business.email.entities.EmailNotification;
import org.libreplan.business.email.entities.EmailTemplate;
import org.libreplan.business.email.entities.EmailTemplateEnum;
import org.libreplan.business.resources.daos.IWorkerDAO;
import org.libreplan.business.resources.entities.Resource;
import org.libreplan.business.resources.entities.Worker;
import org.libreplan.business.settings.entities.Language;
@ -33,9 +36,20 @@ import org.libreplan.web.email.IEmailTemplateModel;
import org.libreplan.web.planner.tabs.MultipleTabsPlannerController;
import org.libreplan.web.resources.worker.IWorkerModel;
import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.beans.factory.annotation;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.core.env.AbstractEnvironment;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.servlet.ServletContext;
import org.zkoss.zul.Messagebox;
import javax.mail.Message;
@ -45,243 +59,283 @@ import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.Query;
import javax.management.ReflectionException;
import javax.naming.InitialContext;
import javax.naming.Context;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.Set;
import java.util.Iterator;
import java.util.Map;
import java.util.ArrayList;
import java.util.HashMap;
import java.lang.String;
import java.lang.management.ManagementFactory;
import java.io.File;
import java.net.InetAddress;
import java.net.URLDecoder;
import java.net.UnknownHostException;
import java.io.UnsupportedEncodingException;
import org.springframework.core.env.MapPropertySource;
import static org.libreplan.web.I18nHelper._;
/**
* Sends E-mail to users with data that storing in notification_queue table
* and that are treat to incoming {@link EmailNotification}.
* Sends E-mail to users with data that storing in notification_queue table and
* that are treat to incoming {@link EmailNotification}.
*
* @author Vova Perebykivskyi <vova@libreplan-enterprise.com>
*/
@Configuration
@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class ComposeMessage {
@Autowired
private IWorkerModel workerModel;
@Autowired
private IWorkerDAO workerDAO;
@Autowired
private IEmailTemplateModel emailTemplateModel;
@Autowired
private IEmailTemplateModel emailTemplateModel;
@Autowired
private EmailConnectionValidator emailConnectionValidator;
@Autowired
private EmailConnectionValidator emailConnectionValidator;
private String protocol;
private String protocol;
private String host;
private String host;
private String port;
private String port;
private String sender;
private String sender;
private String usrnme;
private String usrnme;
private String psswrd;
private String psswrd;
private Properties properties;
private Properties properties;
private static final Log LOG = LogFactory.getLog(ComposeMessage.class);
private static final Log LOG = LogFactory.getLog(ComposeMessage.class);
public boolean composeMessageForUser(EmailNotification notification) {
// Gather data about EmailTemplate needs to be used
Resource resource = notification.getResource();
EmailTemplateEnum type = notification.getType();
Locale locale;
Worker currentWorker = workerDAO.getCurrentWorker(resource.getId());
public boolean composeMessageForUser(EmailNotification notification) {
// Gather data about EmailTemplate needs to be used
Resource resource = notification.getResource();
EmailTemplateEnum type = notification.getType();
Locale locale;
Worker currentWorker = getCurrentWorker(resource.getId());
UserRole currentUserRole = getCurrentUserRole(notification.getType());
UserRole currentUserRole = getCurrentUserRole(notification.getType());
if (currentWorker != null && (currentWorker.getUser() != null) && currentWorker.getUser().isInRole(currentUserRole)) {
if (currentWorker.getUser().getApplicationLanguage().equals(Language.BROWSER_LANGUAGE)) {
locale = new Locale(System.getProperty("user.language"));
} else {
locale = new Locale(currentWorker.getUser().getApplicationLanguage().getLocale().getLanguage());
}
if (currentWorker != null && currentWorker.getUser().isInRole(currentUserRole)) {
if (currentWorker.getUser().getApplicationLanguage().equals(Language.BROWSER_LANGUAGE)) {
locale = new Locale(System.getProperty("user.language"));
} else {
locale = new Locale(currentWorker.getUser().getApplicationLanguage().getLocale().getLanguage());
}
EmailTemplate currentEmailTemplate = findCurrentEmailTemplate(type, locale);
EmailTemplate currentEmailTemplate = findCurrentEmailTemplate(type, locale);
if (currentEmailTemplate == null) {
LOG.error("Email template is null");
return false;
}
if (currentEmailTemplate == null) {
LOG.error("Email template is null");
return false;
}
// Modify text that will be composed
String text = currentEmailTemplate.getContent();
text = replaceKeywords(text, currentWorker, notification);
// Modify text that will be composed
String text = currentEmailTemplate.getContent();
text = replaceKeywords(text, currentWorker, notification);
String receiver = currentWorker.getUser().getEmail();
String receiver = currentWorker.getUser().getEmail();
setupConnectionProperties();
setupConnectionProperties();
final String username = usrnme;
final String password = psswrd;
final String username = usrnme;
final String password = psswrd;
// It is very important to use Session.getInstance() instead of
// Session.getDefaultInstance()
Session mailSession = Session.getInstance(properties, new javax.mail.Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
// It is very important to use Session.getInstance() instead of Session.getDefaultInstance()
Session mailSession = Session.getInstance(properties, new javax.mail.Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
// Send message
try {
MimeMessage message = new MimeMessage(mailSession);
// Send message
try {
MimeMessage message = new MimeMessage(mailSession);
message.setFrom(new InternetAddress(sender));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(receiver));
message.setFrom(new InternetAddress(sender));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(receiver));
String subject = currentEmailTemplate.getSubject();
message.setSubject(subject);
String subject = currentEmailTemplate.getSubject();
message.setSubject(subject);
message.setText(text);
message.setText(text);
Transport.send(message);
Transport.send(message);
return true;
return true;
} catch (MessagingException e) {
throw new RuntimeException(e);
} catch (NullPointerException e) {
if (receiver == null) {
Messagebox.show(_(currentWorker.getUser().getLoginName() + " - this user have not filled E-mail"),
_("Error"), Messagebox.OK, Messagebox.ERROR);
}
}
}
return false;
}
} catch (MessagingException e) {
throw new RuntimeException(e);
} catch (NullPointerException e) {
if (receiver == null) {
Messagebox.show(
_(currentWorker.getUser().getLoginName() + " - this user have not filled E-mail"),
_("Error"), Messagebox.OK, Messagebox.ERROR);
}
}
}
return false;
}
private EmailTemplate findCurrentEmailTemplate(EmailTemplateEnum templateEnum, Locale locale) {
List<EmailTemplate> emailTemplates;
emailTemplates = emailTemplateModel.getAll();
private Worker getCurrentWorker(Long resourceID){
List<Worker> workerList = workerModel.getWorkers();
for (EmailTemplate item : emailTemplates) {
if (item.getType().equals(templateEnum) && item.getLanguage().getLocale().equals(locale)) {
return item;
}
for (Worker aWorkerList : workerList) {
if (aWorkerList.getId().equals(resourceID)) {
return aWorkerList;
}
}
}
return null;
}
return null;
}
private EmailTemplate findCurrentEmailTemplate(EmailTemplateEnum templateEnum, Locale locale) {
List<EmailTemplate> emailTemplates;
emailTemplates = emailTemplateModel.getAll();
private String replaceKeywords(String text, Worker currentWorker, EmailNotification notification) {
String newText = text;
for (EmailTemplate item : emailTemplates) {
if ( item.getType().equals(templateEnum) && item.getLanguage().getLocale().equals(locale) ) {
return item;
}
// replace {url} in all messages even timesheet reminder emails
// as a link may be helpful
newText = newText.replaceAll("\\{url\\}", MultipleTabsPlannerController.WELCOME_URL);
if (notification.getType().equals(EmailTemplateEnum.TEMPLATE_ENTER_DATA_IN_TIMESHEET)) {
// It is because there is no other data for
// EmailNotification of TEMPLATE_ENTER_DATA_IN_TIMESHEET
// notification type
newText = newText.replaceAll("\\{resource\\}", notification.getResource().getName());
} else {
newText = newText.replaceAll("\\{username\\}", currentWorker.getUser().getLoginName());
newText = newText.replaceAll("\\{firstname\\}", currentWorker.getUser().getFirstName());
newText = newText.replaceAll("\\{lastname\\}", currentWorker.getUser().getLastName());
newText = newText.replaceAll("\\{project\\}", notification.getProject().getName());
newText = newText.replaceAll("\\{resource\\}", notification.getResource().getName());
newText = newText.replaceAll("\\{task\\}", notification.getTask().getName());
newText = newText.replaceAll("\\{projecturl\\}", MultipleTabsPlannerController.WELCOME_URL+ ";order=" + notification.getProject().getProjectCode());
}
return newText;
}
}
List<String> getEndPoints() throws MalformedObjectNameException, NullPointerException, UnknownHostException,
AttributeNotFoundException, InstanceNotFoundException, MBeanException, ReflectionException {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
Set<ObjectName> objs = mbs.queryNames(new ObjectName("*:type=Connector,*"),
Query.match(Query.attr("protocol"), Query.value("HTTP/1.1")));
String hostname = InetAddress.getLocalHost().getHostName();
InetAddress[] addresses = InetAddress.getAllByName(hostname);
ArrayList<String> endPoints = new ArrayList<String>();
for (Iterator<ObjectName> i = objs.iterator(); i.hasNext();) {
ObjectName obj = i.next();
String scheme = mbs.getAttribute(obj, "scheme").toString();
String port = obj.getKeyProperty("port");
for (InetAddress addr : addresses) {
String host = addr.getHostAddress();
String ep = scheme + "://" + host + ":" + port;
endPoints.add(ep);
}
}
return endPoints;
}
return null;
}
private void setupConnectionProperties() {
List<ConnectorProperty> emailConnectorProperties = emailConnectionValidator.getEmailConnectorProperties();
private String replaceKeywords(String text, Worker currentWorker, EmailNotification notification) {
String newText = text;
for (int i = 0; i < emailConnectorProperties.size(); i++) {
switch (i) {
if ( notification.getType().equals(EmailTemplateEnum.TEMPLATE_ENTER_DATA_IN_TIMESHEET) ) {
// It is because there is no other data for
// EmailNotification of TEMPLATE_ENTER_DATA_IN_TIMESHEET notification type
newText = newText.replaceAll("\\{resource\\}", notification.getResource().getName());
}
else {
newText = newText.replaceAll("\\{username\\}", currentWorker.getUser().getLoginName());
newText = newText.replaceAll("\\{firstname\\}", currentWorker.getUser().getFirstName());
newText = newText.replaceAll("\\{lastname\\}", currentWorker.getUser().getLastName());
newText = newText.replaceAll("\\{project\\}", notification.getProject().getName());
newText = newText.replaceAll("\\{resource\\}", notification.getResource().getName());
newText = newText.replaceAll("\\{task\\}", notification.getTask().getName());
newText = newText.replaceAll("\\{url\\}", MultipleTabsPlannerController.WELCOME_URL);
}
return newText;
}
case 1:
protocol = emailConnectorProperties.get(1).getValue();
break;
private void setupConnectionProperties() {
List<ConnectorProperty> emailConnectorProperties = emailConnectionValidator.getEmailConnectorProperties();
case 2:
host = emailConnectorProperties.get(2).getValue();
break;
for (int i = 0; i < emailConnectorProperties.size(); i++) {
switch (i) {
case 3:
port = emailConnectorProperties.get(3).getValue();
break;
case 1:
protocol = emailConnectorProperties.get(1).getValue();
break;
case 4:
sender = emailConnectorProperties.get(4).getValue();
break;
case 2:
host = emailConnectorProperties.get(2).getValue();
break;
case 5:
usrnme = emailConnectorProperties.get(5).getValue();
break;
case 3:
port = emailConnectorProperties.get(3).getValue();
break;
case 6:
psswrd = emailConnectorProperties.get(6).getValue();
break;
case 4:
sender = emailConnectorProperties.get(4).getValue();
break;
default:
break;
case 5:
usrnme = emailConnectorProperties.get(5).getValue();
break;
}
}
case 6:
psswrd = emailConnectorProperties.get(6).getValue();
break;
properties = new Properties();
default:
break;
if ("STARTTLS".equals(protocol)) {
properties.put("mail.smtp.starttls.enable", "true");
properties.put("mail.smtp.host", host);
properties.put("mail.smtp.socketFactory.port", port);
properties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
properties.put("mail.smtp.auth", "true");
properties.put("mail.smtp.port", port);
} else if ("SMTP".equals(protocol)) {
properties.put("mail.smtp.host", host);
properties.put("mail.smtp.port", port);
}
}
}
}
private UserRole getCurrentUserRole(EmailTemplateEnum type) {
switch (type) {
properties = new Properties();
case TEMPLATE_TASK_ASSIGNED_TO_RESOURCE:
return UserRole.ROLE_EMAIL_TASK_ASSIGNED_TO_RESOURCE;
if ( "STARTTLS".equals(protocol) ) {
properties.put("mail.smtp.starttls.enable", "true");
properties.put("mail.smtp.host", host);
properties.put("mail.smtp.socketFactory.port", port);
properties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
properties.put("mail.smtp.auth", "true");
properties.put("mail.smtp.port", port);
}
else if ( "SMTP".equals(protocol) ) {
properties.put("mail.smtp.host", host);
properties.put("mail.smtp.port", port);
}
}
case TEMPLATE_RESOURCE_REMOVED_FROM_TASK:
return UserRole.ROLE_EMAIL_RESOURCE_REMOVED_FROM_TASK;
private UserRole getCurrentUserRole(EmailTemplateEnum type) {
switch (type) {
case TEMPLATE_MILESTONE_REACHED:
return UserRole.ROLE_EMAIL_MILESTONE_REACHED;
case TEMPLATE_TASK_ASSIGNED_TO_RESOURCE:
return UserRole.ROLE_EMAIL_TASK_ASSIGNED_TO_RESOURCE;
case TEMPLATE_TODAY_TASK_SHOULD_START:
return UserRole.ROLE_EMAIL_TASK_SHOULD_START;
case TEMPLATE_RESOURCE_REMOVED_FROM_TASK:
return UserRole.ROLE_EMAIL_RESOURCE_REMOVED_FROM_TASK;
case TEMPLATE_TODAY_TASK_SHOULD_FINISH:
return UserRole.ROLE_EMAIL_TASK_SHOULD_FINISH;
case TEMPLATE_MILESTONE_REACHED:
return UserRole.ROLE_EMAIL_MILESTONE_REACHED;
case TEMPLATE_TODAY_TASK_SHOULD_START:
return UserRole.ROLE_EMAIL_TASK_SHOULD_START;
case TEMPLATE_TODAY_TASK_SHOULD_FINISH:
return UserRole.ROLE_EMAIL_TASK_SHOULD_FINISH;
case TEMPLATE_ENTER_DATA_IN_TIMESHEET:
return UserRole.ROLE_EMAIL_TIMESHEET_DATA_MISSING;
default:
/* There is no other template */
return null;
}
}
case TEMPLATE_ENTER_DATA_IN_TIMESHEET:
return UserRole.ROLE_EMAIL_TIMESHEET_DATA_MISSING;
default:
/* There is no other template */
return null;
}
}
}

View file

@ -43,7 +43,7 @@ public class SendEmailOnMilestoneReachedJob extends QuartzJobBean {
(ApplicationContext) context.getJobDetail().getJobDataMap().get("applicationContext");
IEmailNotificationJob milestoneReached =
(SendEmailOnMilestoneReached) applicationContext.getBean("SendEmailOnMilestoneReached");
(IEmailNotificationJob) applicationContext.getBean("sendEmailOnMilestoneReached");
milestoneReached.sendEmail();
}

View file

@ -42,7 +42,7 @@ public class SendEmailOnResourceRemovedFromTaskJob extends QuartzJobBean {
(ApplicationContext) context.getJobDetail().getJobDataMap().get("applicationContext");
IEmailNotificationJob resourceRemovedFromTask =
(IEmailNotificationJob) applicationContext.getBean("SendEmailOnResourceRemovedFromTask");
(IEmailNotificationJob) applicationContext.getBean("sendEmailOnResourceRemovedFromTask");
resourceRemovedFromTask.sendEmail();
}

View file

@ -43,7 +43,7 @@ public class SendEmailOnTaskAssignedToResourceJob extends QuartzJobBean {
(ApplicationContext) context.getJobDetail().getJobDataMap().get("applicationContext");
IEmailNotificationJob taskAssignedToResource =
(IEmailNotificationJob) applicationContext.getBean("SendEmailOnTaskAssignedToResource");
(IEmailNotificationJob) applicationContext.getBean("sendEmailOnTaskAssignedToResource");
taskAssignedToResource.sendEmail();
}

View file

@ -43,7 +43,7 @@ public class SendEmailOnTaskShouldFinishJob extends QuartzJobBean {
(ApplicationContext) context.getJobDetail().getJobDataMap().get("applicationContext");
IEmailNotificationJob taskShouldFinish =
(IEmailNotificationJob) applicationContext.getBean("SendEmailOnTaskShouldFinish");
(IEmailNotificationJob) applicationContext.getBean("sendEmailOnTaskShouldFinish");
taskShouldFinish.sendEmail();
}

View file

@ -43,7 +43,7 @@ public class SendEmailOnTaskShouldStartJob extends QuartzJobBean {
context.getJobDetail().getJobDataMap().get("applicationContext");
IEmailNotificationJob taskShouldStart =
(IEmailNotificationJob) applicationContext.getBean("SendEmailOnTaskShouldStart");
(IEmailNotificationJob) applicationContext.getBean("sendEmailOnTaskShouldStart");
taskShouldStart.sendEmail();
}

View file

@ -42,7 +42,7 @@ public class SendEmailOnTimesheetDataMissingJob extends QuartzJobBean {
(ApplicationContext) context.getJobDetail().getJobDataMap().get("applicationContext");
IEmailNotificationJob timesheetMissing =
(IEmailNotificationJob) applicationContext.getBean("SendEmailOnTimesheetDataMissing");
(IEmailNotificationJob) applicationContext.getBean("sendEmailOnTimesheetDataMissing");
timesheetMissing.sendEmail();
}

View file

@ -112,32 +112,30 @@ public class SendEmailOnMilestoneReached implements IEmailNotificationJob {
}
private void sendEmailNotificationToManager(TaskElement item) {
emailNotificationModel.setNewObject();
emailNotificationModel.setType(EmailTemplateEnum.TEMPLATE_MILESTONE_REACHED);
emailNotificationModel.setUpdated(new Date());
String responsible = "";
if ( item.getParent().getOrderElement().getOrder().getResponsible() != null ) {
responsible = item.getParent().getOrderElement().getOrder().getResponsible();
if ( item.getTopMost().getOrderElement().getOrder().getResponsible() != null ) {
responsible = item.getTopMost().getOrderElement().getOrder().getResponsible();
}
User user = null;
try {
// FIXME: Code below can produce NullPointerException if "Responsible" field is not set in Project Details -> General data
user = userDAO.findByLoginName(responsible);
} catch (InstanceNotFoundException e) {
e.printStackTrace();
}
boolean userHasNeededRoles =
boolean userHasNeededRoles =
user.isInRole(UserRole.ROLE_SUPERUSER) || user.isInRole(UserRole.ROLE_EMAIL_MILESTONE_REACHED);
if ( user.getWorker() != null && userHasNeededRoles ) {
emailNotificationModel.setResource(user.getWorker());
emailNotificationModel.setTask(item);
emailNotificationModel.setProject(item.getParent());
emailNotificationModel.confirmSave();
}
if ( user.getWorker() != null && userHasNeededRoles ) {
emailNotificationModel.setNewObject();
emailNotificationModel.setType(EmailTemplateEnum.TEMPLATE_MILESTONE_REACHED);
emailNotificationModel.setUpdated(new Date());
emailNotificationModel.setResource(user.getWorker());
emailNotificationModel.setTask(item);
emailNotificationModel.setProject(item.getTopMost());
emailNotificationModel.confirmSave();
}
} catch (InstanceNotFoundException e) {
// do nothing, responsible user is either blank or free text in order
}
}
public void checkMilestoneDate() {

View file

@ -28,11 +28,15 @@ import org.libreplan.business.email.entities.EmailTemplateEnum;
import org.libreplan.business.planner.daos.ITaskElementDAO;
import org.libreplan.business.planner.entities.ResourceAllocation;
import org.libreplan.business.planner.entities.TaskElement;
import org.libreplan.business.resources.daos.IWorkerDAO;
import org.libreplan.business.resources.entities.Resource;
import org.libreplan.business.resources.entities.Worker;
import org.libreplan.business.users.entities.UserRole;
import org.libreplan.importers.notifications.ComposeMessage;
import org.libreplan.importers.notifications.EmailConnectionValidator;
import org.libreplan.importers.notifications.IEmailNotificationJob;
import org.libreplan.web.email.IEmailNotificationModel;
import org.libreplan.web.resources.worker.IWorkerModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
@ -68,6 +72,9 @@ public class SendEmailOnTaskShouldFinish implements IEmailNotificationJob {
@Autowired
private EmailConnectionValidator emailConnectionValidator;
@Autowired
private IWorkerDAO workerDAO;
/**
* Transactional here is needed because without this annotation we are getting
* "LazyInitializationException: could not initialize proxy - no Session" error,
@ -115,14 +122,13 @@ public class SendEmailOnTaskShouldFinish implements IEmailNotificationJob {
for (TaskElement item : tasks) {
DateTime endDate = new DateTime(item.getEndDate());
if ( dateTimeComparator.compare(currentDate, endDate) == 0 ) {
if ( dateTimeComparator.compare(currentDate, endDate) == 0 && item.isLeaf() ) {
// Get all resources for current task and send them email notification
sendEmailNotificationAboutTaskShouldFinish(item);
}
}
}
private void sendEmailNotificationAboutTaskShouldFinish(TaskElement item){
List<ResourceAllocation<?>> resourceAllocations = new ArrayList<>(item.getAllResourceAllocations());
@ -131,13 +137,17 @@ public class SendEmailOnTaskShouldFinish implements IEmailNotificationJob {
resources.add(allocation.getAssociatedResources().get(0));
for (Resource resourceItem : resources){
emailNotificationModel.setNewObject();
emailNotificationModel.setType(EmailTemplateEnum.TEMPLATE_TODAY_TASK_SHOULD_FINISH);
emailNotificationModel.setUpdated(new Date());
emailNotificationModel.setResource(resourceItem);
emailNotificationModel.setTask(item);
emailNotificationModel.setProject(item.getParent());
emailNotificationModel.confirmSave();
Worker currentWorker = workerDAO.getCurrentWorker(resourceItem.getId());
if (currentWorker != null && (currentWorker.getUser() != null) && currentWorker.getUser().isInRole(UserRole.ROLE_EMAIL_TASK_SHOULD_FINISH)) {
emailNotificationModel.setNewObject();
emailNotificationModel.setType(EmailTemplateEnum.TEMPLATE_TODAY_TASK_SHOULD_FINISH);
emailNotificationModel.setUpdated(new Date());
emailNotificationModel.setResource(resourceItem);
emailNotificationModel.setTask(item);
emailNotificationModel.setProject(item.getTopMost());
emailNotificationModel.confirmSave();
}
}
}

View file

@ -28,16 +28,22 @@ import org.libreplan.business.email.entities.EmailTemplateEnum;
import org.libreplan.business.planner.daos.ITaskElementDAO;
import org.libreplan.business.planner.entities.ResourceAllocation;
import org.libreplan.business.planner.entities.TaskElement;
import org.libreplan.business.resources.daos.IWorkerDAO;
import org.libreplan.business.resources.entities.Resource;
import org.libreplan.business.resources.entities.Worker;
import org.libreplan.business.users.entities.User;
import org.libreplan.business.users.entities.UserRole;
import org.libreplan.importers.notifications.ComposeMessage;
import org.libreplan.importers.notifications.EmailConnectionValidator;
import org.libreplan.importers.notifications.IEmailNotificationJob;
import org.libreplan.web.email.IEmailNotificationModel;
import org.libreplan.web.resources.worker.IWorkerModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.zkoss.zkplus.spring.SpringUtil;
import java.util.ArrayList;
import java.util.Date;
@ -68,6 +74,9 @@ public class SendEmailOnTaskShouldStart implements IEmailNotificationJob {
@Autowired
private EmailConnectionValidator emailConnectionValidator;
@Autowired
private IWorkerDAO workerDAO;
/**
* Transactional here is needed because without this annotation we are getting
* "LazyInitializationException: could not initialize proxy - no Session" error,
@ -115,7 +124,7 @@ public class SendEmailOnTaskShouldStart implements IEmailNotificationJob {
for (TaskElement item : tasks) {
DateTime startDate = new DateTime(item.getStartDate());
if ( dateTimeComparator.compare(currentDate, startDate) == 0) {
if ( dateTimeComparator.compare(currentDate, startDate) == 0 && item.isLeaf() ) {
// Get all resources for current task and send them email notification
sendEmailNotificationAboutTaskShouldStart(item);
}
@ -130,13 +139,17 @@ public class SendEmailOnTaskShouldStart implements IEmailNotificationJob {
resources.add(allocation.getAssociatedResources().get(0));
for (Resource resourceItem : resources) {
emailNotificationModel.setNewObject();
emailNotificationModel.setType(EmailTemplateEnum.TEMPLATE_TODAY_TASK_SHOULD_START);
emailNotificationModel.setUpdated(new Date());
emailNotificationModel.setResource(resourceItem);
emailNotificationModel.setTask(item);
emailNotificationModel.setProject(item.getParent());
emailNotificationModel.confirmSave();
Worker currentWorker = workerDAO.getCurrentWorker(resourceItem.getId());
if (currentWorker != null && (currentWorker.getUser() != null) && currentWorker.getUser().isInRole(UserRole.ROLE_EMAIL_TASK_SHOULD_START)) {
emailNotificationModel.setNewObject();
emailNotificationModel.setType(EmailTemplateEnum.TEMPLATE_TODAY_TASK_SHOULD_START);
emailNotificationModel.setUpdated(new Date());
emailNotificationModel.setResource(resourceItem);
emailNotificationModel.setTask(item);
emailNotificationModel.setProject(item.getTopMost());
emailNotificationModel.confirmSave();
}
}
}

View file

@ -33,6 +33,7 @@ import org.libreplan.business.resources.entities.Resource;
import org.libreplan.business.resources.entities.Worker;
import org.libreplan.business.users.entities.User;
import org.libreplan.business.users.entities.UserRole;
import org.libreplan.business.workingday.EffortDuration;
import org.libreplan.business.workingday.IntraDayDate;
import org.libreplan.business.workreports.daos.IWorkReportDAO;
@ -159,11 +160,13 @@ public class SendEmailOnTimesheetDataMissing implements IEmailNotificationJob {
private void addRowsToNotificationTable(List<User> users){
for (User user : users){
emailNotificationModel.setNewObject();
emailNotificationModel.setResource(user.getWorker());
emailNotificationModel.setType(EmailTemplateEnum.TEMPLATE_ENTER_DATA_IN_TIMESHEET);
emailNotificationModel.setUpdated(new Date());
emailNotificationModel.confirmSave();
if ( user.isInRole(UserRole.ROLE_EMAIL_TIMESHEET_DATA_MISSING) ) {
emailNotificationModel.setNewObject();
emailNotificationModel.setResource(user.getWorker());
emailNotificationModel.setType(EmailTemplateEnum.TEMPLATE_ENTER_DATA_IN_TIMESHEET);
emailNotificationModel.setUpdated(new Date());
emailNotificationModel.confirmSave();
}
}
}

View file

@ -1577,7 +1577,7 @@ public class ConfigurationController extends GenericForwardComposer {
.getCurrentWebApplicationContext()
.getResource("/")
.getFile()
.getPath() + "\\" + media.getName());
.getPath() + "/" + media.getName());
OutputStream outputStream = new FileOutputStream(fileToSave);
out = new BufferedOutputStream(outputStream);
@ -1628,9 +1628,9 @@ public class ConfigurationController extends GenericForwardComposer {
if ( !"".equals(companyLogoURL.getValue()) ) {
((org.zkoss.zul.Image) configurationWindow.getFellow(LOGO_PREVIEW_COMPONENT)).setSrc("");
findAndRemoveLogoFromTarget(companyLogoURL.getValue());
Util.logo = null;
}
Util.logo = null;
companyLogoURL.setValue("");
configurationModel.setCompanyLogoURL("");
}

View file

@ -50,6 +50,11 @@ public class FilterUtils {
return (String) Sessions.getCurrent().getAttribute("companyFilterOrderName");
}
public static Boolean readExcludeFinishedProjects() {
Boolean res = (Boolean) Sessions.getCurrent().getAttribute("companyFilterFinished");
return res;
}
public static List<FilterPair> readProjectsParameters() {
return (List<FilterPair>) Sessions.getCurrent().getAttribute("companyFilterLabel");
}
@ -76,6 +81,15 @@ public class FilterUtils {
Sessions.getCurrent().setAttribute("companyFilterOrderName", name);
}
public static void writeExcludeFinishedProjects(Boolean excludeFinishedProject) {
Sessions.getCurrent().setAttribute("companyFilterFinished", excludeFinishedProject);
Sessions.getCurrent().setAttribute("companyFilterFinishedChanged", true);
}
public static boolean hasExcludeFinishedProjects() {
return Sessions.getCurrent().hasAttribute("companyFilterFinishedChanged");
}
public static void writeProjectsParameters(List<FilterPair> parameters) {
Sessions.getCurrent().setAttribute("companyFilterLabel", parameters);
}
@ -83,12 +97,14 @@ public class FilterUtils {
public static void writeProjectsFilter(Date startDate,
Date endDate,
List<FilterPair> parameters,
String projectName) {
String projectName,
Boolean excludeFinishedProject) {
writeProjectsStartDate(startDate);
writeProjectsEndDate(endDate);
writeProjectsParameters(parameters);
writeProjectsName(projectName);
writeExcludeFinishedProjects(excludeFinishedProject);
}
public static void writeProjectFilterChanged(boolean changed) {
@ -159,6 +175,10 @@ public class FilterUtils {
return (String) Sessions.getCurrent().getAttribute(order.getCode() + "-tasknameFilter");
}
public static String readOrderStatus(Order order) {
return (String) Sessions.getCurrent().getAttribute(order.getCode() + "-orderStatus");
}
public static List<FilterPair> readOrderParameters(Order order) {
return (List<FilterPair>) Sessions.getCurrent().getAttribute(order.getCode() + "-labelsandcriteriaFilter");
}

View file

@ -143,10 +143,11 @@ public class BandboxSearch extends HtmlMacroComponent {
}
public void pickElementFromList() {
final Object object = getSelectedItem().getValue();
bandbox.setValue(finder.objectToString(object));
setSelectedElement(object);
Util.getBinder(this).saveAttribute(this, SELECTED_ELEMENT_ATTRIBUTE);
final Listitem listitem = getSelectedItem();
if ( listitem != null ) {
setSelectedElement(listitem.getValue());
}
}
private void clearSelectedElement() {

View file

@ -22,6 +22,7 @@ package org.libreplan.web.email;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.email.daos.IEmailNotificationDAO;
import org.libreplan.business.email.entities.EmailTemplateEnum;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.email.entities.EmailNotification;
import org.libreplan.business.planner.entities.TaskElement;
@ -68,6 +69,17 @@ public class EmailNotificationModel implements IEmailNotificationModel {
return emailNotificationDAO.getAllByType(enumeration);
}
@Override
@Transactional
public List<EmailNotification> getAllByProject(TaskElement taskElement) {
return emailNotificationDAO.getAllByProject(taskElement);
}
@Override
@Transactional
public List<EmailNotification> getAllByTask(TaskElement taskElement) {
return emailNotificationDAO.getAllByTask(taskElement);
}
@Override
@Transactional
public boolean deleteAll() {
@ -85,6 +97,18 @@ public class EmailNotificationModel implements IEmailNotificationModel {
return emailNotificationDAO.deleteById(notification);
}
@Override
@Transactional
public boolean deleteByProject(TaskElement taskElement) {
return emailNotificationDAO.deleteByProject(taskElement);
}
@Override
@Transactional
public boolean deleteByTask(TaskElement taskElement) {
return emailNotificationDAO.deleteByTask(taskElement);
}
@Override
public void setType(EmailTemplateEnum type) {
this.emailNotification.setType(type);
@ -110,11 +134,12 @@ public class EmailNotificationModel implements IEmailNotificationModel {
this.emailNotification.setProject(project);
}
@Override
public EmailNotification getEmailNotification() {
return emailNotification;
}
@Override
public void setNewObject(){
this.emailNotification = new EmailNotification();
}

View file

@ -21,6 +21,7 @@ package org.libreplan.web.email;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.email.entities.EmailTemplateEnum;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.email.entities.EmailNotification;
import org.libreplan.business.planner.entities.TaskElement;
import org.libreplan.business.resources.entities.Resource;
@ -41,12 +42,20 @@ public interface IEmailNotificationModel {
List<EmailNotification> getAllByType(EmailTemplateEnum enumeration);
List<EmailNotification> getAllByProject(TaskElement taskElement);
List<EmailNotification> getAllByTask(TaskElement taskElement);
boolean deleteAll();
boolean deleteAllByType(EmailTemplateEnum enumeration);
boolean deleteById(EmailNotification notification);
boolean deleteByProject(TaskElement taskElement);
boolean deleteByTask(TaskElement taskElement);
void setType(EmailTemplateEnum type);
void setUpdated(Date date);
@ -60,4 +69,5 @@ public interface IEmailNotificationModel {
EmailNotification getEmailNotification();
void setNewObject();
}

View file

@ -91,7 +91,7 @@ public interface IOrderModel extends IIntegrationEntityModel {
List<Order> getOrders(Date startDate, Date endDate, List<Label> labels,
List<Criterion> criteria, ExternalCompany customer,
OrderStatusEnum state);
OrderStatusEnum state, Boolean excludeFinishedProject);
void initEdit(Order order, Desktop desktop);

View file

@ -849,7 +849,6 @@ public class ManageOrderElementAdvancesController extends GenericForwardComposer
this.manageOrderElementAdvancesModel.sortListAdvanceMeasurement();
Util.reloadBindings(editAdvancesMeasurement);
this.setCurrentDate();
this.setPercentage();
this.setCurrentValue();
Util.reloadBindings(chart);

View file

@ -78,6 +78,7 @@ import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.SelectEvent;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Button;
import org.zkoss.zul.Checkbox;
import org.zkoss.zul.Column;
import org.zkoss.zul.Combobox;
import org.zkoss.zul.Comboitem;
@ -220,6 +221,8 @@ public class OrderCRUDController extends GenericForwardComposer {
private Textbox filterProjectName;
private Checkbox filterExcludeFinishedProject;
private Runnable onUp;
private boolean readOnly = true;
@ -248,6 +251,8 @@ public class OrderCRUDController extends GenericForwardComposer {
filterProjectName = (Textbox) filterComponent.getFellow("filterProjectName");
filterExcludeFinishedProject = (Checkbox) filterComponent.getFellow("filterExcludeFinishedProject");
checkCreationPermissions();
setupGlobalButtons();
initializeFilter();
@ -291,6 +296,8 @@ public class OrderCRUDController extends GenericForwardComposer {
filterProjectName.setValue(FilterUtils.readProjectsName());
filterExcludeFinishedProject.setValue(FilterUtils.readExcludeFinishedProjects());
loadLabels();
FilterUtils.writeProjectPlanningFilterChanged(false);
@ -802,6 +809,7 @@ public class OrderCRUDController extends GenericForwardComposer {
List<Criterion> criteria = new ArrayList<>();
ExternalCompany customer = null;
OrderStatusEnum state = null;
//Boolean excludeFinishedProject = false;
for (FilterPair filterPair : (List<FilterPair>) bdFilters.getSelectedElements()) {
OrderFilterEnum type = (OrderFilterEnum) filterPair.getType();
@ -837,7 +845,7 @@ public class OrderCRUDController extends GenericForwardComposer {
}
return orderModel.getOrders(
filterStartDate.getValue(), filterFinishDate.getValue(), labels, criteria, customer, state);
filterStartDate.getValue(), filterFinishDate.getValue(), labels, criteria, customer, state, filterExcludeFinishedProject.isChecked());
}
private OnlyOneVisible getVisibility() {
@ -1286,6 +1294,7 @@ public class OrderCRUDController extends GenericForwardComposer {
appendDate(row, order.getDeadline());
appendCustomer(row, order.getCustomer());
appendObject(row, Util.addCurrencySymbol(order.getTotalManualBudget()));
appendObject(row, Util.addCurrencySymbol(order.getTotalBudget()));
appendObject(row, order.getTotalHours());
appendObject(row, _(order.getState().toString()));
appendOperations(row, order);
@ -1437,7 +1446,8 @@ public class OrderCRUDController extends GenericForwardComposer {
filterStartDate.getValue(),
filterFinishDate.getValue(),
getSelectedBandboxAsTaskGroupFilters(),
filterProjectName.getValue());
filterProjectName.getValue(),
filterExcludeFinishedProject.getValue());
}
private List<FilterPair> getSelectedBandboxAsTaskGroupFilters() {
@ -1768,6 +1778,7 @@ public class OrderCRUDController extends GenericForwardComposer {
filterStartDate.setValue(FilterUtils.readProjectsStartDate());
filterFinishDate.setValue(FilterUtils.readProjectsEndDate());
filterProjectName.setValue(FilterUtils.readProjectsName());
filterExcludeFinishedProject.setValue(FilterUtils.readExcludeFinishedProjects());
loadLabels();
}

View file

@ -47,6 +47,7 @@ import org.libreplan.business.common.daos.IConfigurationDAO;
import org.libreplan.business.common.entities.Configuration;
import org.libreplan.business.common.entities.EntityNameEnum;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.email.entities.EmailNotification;
import org.libreplan.business.externalcompanies.daos.IExternalCompanyDAO;
import org.libreplan.business.externalcompanies.entities.EndDateCommunication;
import org.libreplan.business.externalcompanies.entities.ExternalCompany;
@ -60,6 +61,7 @@ import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.orders.entities.OrderLineGroup;
import org.libreplan.business.orders.entities.OrderStatusEnum;
import org.libreplan.business.planner.entities.PositionConstraintType;
import org.libreplan.business.planner.entities.TaskElement;
import org.libreplan.business.qualityforms.daos.IQualityFormDAO;
import org.libreplan.business.qualityforms.entities.QualityForm;
import org.libreplan.business.requirements.entities.DirectCriterionRequirement;
@ -84,6 +86,7 @@ import org.libreplan.business.users.entities.UserRole;
import org.libreplan.web.calendars.BaseCalendarModel;
import org.libreplan.web.common.IntegrationEntityModel;
import org.libreplan.web.common.concurrentdetection.OnConcurrentModification;
import org.libreplan.web.email.IEmailNotificationModel;
import org.libreplan.web.logs.IIssueLogModel;
import org.libreplan.web.logs.IRiskLogModel;
import org.libreplan.web.orders.files.IOrderFileModel;
@ -181,6 +184,9 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
@Autowired
private IIssueLogModel issueLogModel;
@Autowired
private IEmailNotificationModel emailNotificationModel;
private List<Order> orderList = new ArrayList<>();
@Override
@ -235,13 +241,13 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
@Transactional(readOnly = true)
public List<Order> getOrders(Date startDate, Date endDate,
List<Label> labels, List<Criterion> criteria,
ExternalCompany customer, OrderStatusEnum state) {
ExternalCompany customer, OrderStatusEnum state, Boolean excludeFinishedProject) {
getLabelsOnConversation().reattachLabels();
List<Order> orders = orderDAO
.getOrdersByReadAuthorizationBetweenDatesByLabelsCriteriaCustomerAndState(
SecurityUtils.getSessionUserLoginName(),
scenarioManager.getCurrent(), startDate, endDate,
labels, criteria, customer, state);
labels, criteria, customer, state, excludeFinishedProject);
initializeOrders(orders);
@ -436,7 +442,8 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
newOrder.setCustomer(getOrder().getCustomer());
newOrder.setCalendar(getCalendar());
newOrder.setInitDate(getOrder().getInitDate());
newOrder.setDescription(getOrder().getDescription());
if ( getOrder().getDeadline() != null ) {
newOrder.setDeadline(getOrder().getDeadline());
}
@ -521,6 +528,8 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
public void remove(Order detachedOrder) {
Order order = orderDAO.findExistingEntity(detachedOrder.getId());
removeNotifications(order);
removeFiles(order);
removeLogs(order);
@ -541,6 +550,18 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
orderFileModel.findByParent(order).forEach(orderFile -> orderFileModel.delete(orderFile));
}
private void removeNotifications(Order order) {
for ( Scenario scenario: currentAndDerivedScenarios()) {
order.useSchedulingDataFor(scenario.getOrderVersion(order));
TaskElement taskElement = order.getTaskElement();
if ( taskElement != null) {
emailNotificationModel.deleteByProject(taskElement);
}
}
}
private void removeVersions(Order order) {
Map<Long, OrderVersion> versionsRemovedById = new HashMap<>();
List<Scenario> currentAndDerived = currentAndDerivedScenarios();

View file

@ -80,6 +80,8 @@ public class ProjectDetailsController extends GenericForwardComposer<Component>
private Textbox txtName;
private Textbox txtDescription;
private Datebox deadline;
private Checkbox generateCode;

View file

@ -56,12 +56,15 @@ public class TaskGroupPredicate implements IPredicate {
private String name;
private Boolean excludeFinishedProject;
public TaskGroupPredicate(List<FilterPair> filters, Date startDate,
Date finishDate, String name) {
Date finishDate, String name, Boolean excludeFinishedProject) {
this.filters = filters;
this.startDate = startDate;
this.finishDate = finishDate;
this.name = name;
this.excludeFinishedProject = excludeFinishedProject;
}
@Override
@ -166,6 +169,15 @@ public class TaskGroupPredicate implements IPredicate {
return false;
}
private boolean acceptFinishedProject(FilterPair filter, TaskGroup taskGroup) {
Label filterLabel = (Label) filter.getValue();
Order order = (Order) taskGroup.getOrderElement();
if (order.getState() != OrderStatusEnum.FINISHED) {
return true;
}
return false;
}
private boolean acceptExternalCompany(FilterPair filter, TaskGroup taskGroup) {
Order order = (Order) taskGroup.getOrderElement();
ExternalCompany filterCustomer = (ExternalCompany) filter.getValue();
@ -300,4 +312,8 @@ public class TaskGroupPredicate implements IPredicate {
return false;
}
}
public Boolean getExcludeFinishedProjects() {
return excludeFinishedProject;
}
}

View file

@ -38,7 +38,9 @@ public abstract class LoadChartFiller extends ChartFiller {
@Override
public void fillChart(Timeplot chart, Interval interval, Integer size) {
chart.getChildren().clear();
if (chart.getChildren() != null) {
chart.getChildren().clear();
}
chart.invalidate();
if (getOptionalJavascriptCall() != null) {

View file

@ -91,6 +91,8 @@ public class CompanyPlanningController implements Composer {
private Textbox filterProjectName;
private Checkbox filterExcludeFinishedProject;
private BandboxMultipleSearch bdFilters;
private ICommandOnTask<TaskElement> doubleClickCommand;
@ -135,6 +137,7 @@ public class CompanyPlanningController implements Composer {
filterStartDate = (Datebox) filterComponent.getFellow("filterStartDate");
filterFinishDate = (Datebox) filterComponent.getFellow("filterFinishDate");
filterProjectName = (Textbox) filterComponent.getFellow("filterProjectName");
filterExcludeFinishedProject = (Checkbox) filterComponent.getFellow("filterExcludeFinishedProject");
bdFilters = (BandboxMultipleSearch) filterComponent.getFellow("bdFilters");
bdFilters.setFinder("taskGroupsMultipleFiltersFinder");
@ -179,6 +182,8 @@ public class CompanyPlanningController implements Composer {
.toDate());
}
filterProjectName.setValue(FilterUtils.readProjectsName());
filterExcludeFinishedProject.setChecked(user.isProjectsFilterFinishedOn());
}
}
@ -311,6 +316,10 @@ public class CompanyPlanningController implements Composer {
filterStartDate.setValue(FilterUtils.readProjectsStartDate());
filterFinishDate.setValue(FilterUtils.readProjectsEndDate());
filterProjectName.setValue(FilterUtils.readProjectsName());
Boolean excludeFinishedProjects = FilterUtils.readExcludeFinishedProjects();
if ( excludeFinishedProjects != null ) {
filterExcludeFinishedProject.setChecked(excludeFinishedProjects);
}
loadPredefinedBandboxFilter();
}
@ -319,7 +328,8 @@ public class CompanyPlanningController implements Composer {
filterStartDate.getValue(),
filterFinishDate.getValue(),
bdFilters.getSelectedElements(),
filterProjectName.getValue());
filterProjectName.getValue(),
filterExcludeFinishedProject.isChecked());
FilterUtils.writeProjectPlanningFilterChanged(true);
filterByPredicate(createPredicate());
@ -333,6 +343,7 @@ public class CompanyPlanningController implements Composer {
List<FilterPair> listFilters = (List<FilterPair>) bdFilters.getSelectedElements();
Date startDate = filterStartDate.getValue();
Date finishDate = filterFinishDate.getValue();
Boolean excludeFinishedProject = filterExcludeFinishedProject.isChecked();
String name = filterProjectName.getValue();
@ -354,7 +365,7 @@ public class CompanyPlanningController implements Composer {
return predicate;
}
return new TaskGroupPredicate(listFilters, startDate, finishDate, name);
return new TaskGroupPredicate(listFilters, startDate, finishDate, name, excludeFinishedProject);
}
private void filterByPredicate(TaskGroupPredicate predicate) {

View file

@ -164,6 +164,8 @@ public class CompanyPlanningModel implements ICompanyPlanningModel {
private LocalDate filterFinishDate;
private Boolean filterExcludeFinishedProject;
private static final class TaskElementNavigator implements IStructureNavigator<TaskElement> {
@Override
@ -204,6 +206,9 @@ public class CompanyPlanningModel implements ICompanyPlanningModel {
boolean expandPlanningViewChart = user.isExpandCompanyPlanningViewCharts();
configuration.setExpandPlanningViewCharts(expandPlanningViewChart);
boolean projectsFilterFinished = user.isProjectsFilterFinishedOn();
configuration.setFilterExcludeFinishedProject(projectsFilterFinished);
final Tabbox chartComponent = new Tabbox();
chartComponent.setOrient("vertical");
chartComponent.setHeight("200px");
@ -218,6 +223,7 @@ public class CompanyPlanningModel implements ICompanyPlanningModel {
addAdditionalCommands(additional, configuration);
addPrintSupport(configuration);
disableSomeFeatures(configuration);
setDefaultButtonState(configuration,user);
planner.setInitialZoomLevel(getZoomLevel(configuration));
@ -247,6 +253,23 @@ public class CompanyPlanningModel implements ICompanyPlanningModel {
}
}
private void setDefaultButtonState(PlannerConfiguration<TaskElement> configuration, User user) {
// set initial button show mode
if ( user.isShowAdvancesOn() ) {
configuration.setShowAdvancesOn(user.isShowAdvancesOn());
}
if ( user.isShowReportedHoursOn() ) {
configuration.setShowReportedHoursOn(user.isShowReportedHoursOn());
}
if ( user.isShowLabelsOn() ) {
configuration.setShowLabelsOn(user.isShowLabelsOn());
}
}
private ZoomLevel getZoomLevel(PlannerConfiguration<TaskElement> configuration) {
ZoomLevel sessionZoom = FilterUtils.readZoomLevelCompanyView();
@ -692,6 +715,7 @@ public class CompanyPlanningModel implements ICompanyPlanningModel {
Date startDate = predicate.getStartDate();
Date endDate = predicate.getFinishDate();
Boolean excludeFinishedProject = predicate.getExcludeFinishedProjects();
List<org.libreplan.business.labels.entities.Label> labels = new ArrayList<>();
List<Criterion> criteria = new ArrayList<>();
ExternalCompany customer = null;
@ -732,7 +756,7 @@ public class CompanyPlanningModel implements ICompanyPlanningModel {
}
return orderDAO.getOrdersByReadAuthorizationBetweenDatesByLabelsCriteriaCustomerAndState(
username, currentScenario, startDate, endDate, labels, criteria, customer, state);
username, currentScenario, startDate, endDate, labels, criteria, customer, state, excludeFinishedProject);
}
@Override
@ -742,6 +766,12 @@ public class CompanyPlanningModel implements ICompanyPlanningModel {
Date startDate = FilterUtils.readProjectsStartDate();
Date endDate = FilterUtils.readProjectsEndDate();
String name = FilterUtils.readProjectsName();
Boolean projectsFinished = FilterUtils.readExcludeFinishedProjects();
if ( projectsFinished == null ) {
User user = getUser();
projectsFinished = user.isProjectsFilterFinishedOn();
}
boolean calculateStartDate = startDate == null;
boolean calculateEndDate = endDate == null;
@ -776,8 +806,9 @@ public class CompanyPlanningModel implements ICompanyPlanningModel {
}
filterStartDate = startDate != null ? LocalDate.fromDateFields(startDate) : null;
filterFinishDate = endDate != null ? LocalDate.fromDateFields(endDate) : null;
//filterExcludeFinishedProject = projectsFinished != null ? projectsFinished : false;
return new TaskGroupPredicate(null, startDate, endDate, name);
return new TaskGroupPredicate(null, startDate, endDate, name, projectsFinished);
}
private static <T> List<T> notNull(T... values) {
@ -886,4 +917,12 @@ public class CompanyPlanningModel implements ICompanyPlanningModel {
return user;
}
public Boolean getFilterExcludeFinishedProject() {
return filterExcludeFinishedProject;
}
public void setFilterExcludeFinishedProject(Boolean filterExcludeFinishedProject) {
this.filterExcludeFinishedProject = filterExcludeFinishedProject;
}
}

View file

@ -354,6 +354,8 @@ public class OrderPlanningModel implements IOrderPlanningModel {
chartComponent.setHeight("200px");
appendTabs(chartComponent);
setDefaultButtonState(configuration,user);
configuration.setChartComponent(chartComponent);
configureModifiers(planningState.getOrder(), configuration);
long setConfigurationTime = System.currentTimeMillis();
@ -395,6 +397,36 @@ public class OrderPlanningModel implements IOrderPlanningModel {
PROFILING_LOG.debug("overallProgressContent took: " + (System.currentTimeMillis() - overallProgressContentTime));
}
private void setDefaultButtonState(PlannerConfiguration<TaskElement> configuration, User user) {
// set initial button show mode
if ( !planner.areShownAdvancesByDefault() && user.isShowAdvancesOn() ) {
configuration.setShowAdvancesOn(user.isShowAdvancesOn());
planner.setAreShownAdvancesByDefault(user.isShowAdvancesOn());
}
if ( !planner.areShownReportedHoursByDefault() && user.isShowReportedHoursOn() ) {
configuration.setShowReportedHoursOn(user.isShowReportedHoursOn());
planner.setAreShownReportedHoursByDefault(user.isShowReportedHoursOn());
}
if ( !planner.areShownMoneyCostBarByDefault() && user.isShowMoneyCostBarOn() ) {
configuration.setShowMoneyCostBarOn(user.isShowMoneyCostBarOn());
planner.setAreShownMoneyCostBarByDefault(user.isShowMoneyCostBarOn());
}
if ( !planner.areShownLabelsByDefault() && user.isShowLabelsOn() ) {
configuration.setShowLabelsOn(user.isShowLabelsOn());
planner.setAreShownLabelsByDefault(user.isShowLabelsOn());
}
if ( !planner.areShownResourcesByDefault() && user.isShowResourcesOn() ) {
configuration.setShowResourcesOn(user.isShowResourcesOn());
planner.setAreShownResourcesByDefault(user.isShowResourcesOn());
}
}
private ZoomLevel getZoomLevel(PlannerConfiguration<TaskElement> configuration, Order order) {
ZoomLevel sessionZoom = FilterUtils.readZoomLevel(order);
if ( sessionZoom != null ) {

View file

@ -589,9 +589,19 @@ public class SaveCommandBuilder {
removeEmptyConsolidation(taskElement);
updateLimitingResourceQueueElementDates(taskElement);
if (taskElement.getTaskSource() != null && taskElement.getTaskSource().isNewObject())
if (taskElement.getTaskSource() != null && taskElement.getTaskSource().isNewObject()) {
saveTaskSources(taskElement);
// hack to update taskPropertiesController reference to current currentTaskElement
if (SaveCommandBuilder.taskPropertiesController != null) {
TaskElement taskControllerTaskElement = SaveCommandBuilder.taskPropertiesController.getCurrentTaskElement();
if ( taskControllerTaskElement != null && taskControllerTaskElement.getOrderElement() == taskElement.getOrderElement() &&
taskControllerTaskElement.isNewObject()) {
SaveCommandBuilder.taskPropertiesController.setCurrentTaskElement(taskElement);
}
}
}
updateLimitingQueueDependencies(taskElement);
}
saveRootTask();

View file

@ -800,7 +800,7 @@ public class TaskPropertiesController extends GenericForwardComposer<Component>
emailNotificationModel.setTask(currentTaskElement.getTaskSource().getTask());
emailNotificationModel.setProject(currentTaskElement.getParent().getTaskSource().getTask());
emailNotificationModel.setProject(currentTaskElement.getTopMost().getTaskSource().getTask());
emailNotificationModel.confirmSave();
} catch (DataIntegrityViolationException e) {
@ -826,4 +826,12 @@ public class TaskPropertiesController extends GenericForwardComposer<Component>
return this;
}
public TaskElement getCurrentTaskElement() {
return currentTaskElement;
}
public void setCurrentTaskElement(TaskElement taskElement) {
currentTaskElement = taskElement;
}
}

View file

@ -609,7 +609,7 @@ public abstract class TreeController<T extends ITreeNode<T>> extends GenericForw
int myPosition = parent.getIndex();
if (myPosition < treeItems.size() - 1) {
if ((myPosition < treeItems.size() - 1) && myPosition > 0) {
// The current node is not the last one
Treerow downTreerow = treeItems.get(myPosition + 1).getTreerow();

View file

@ -35,8 +35,14 @@ import org.libreplan.business.workreports.entities.WorkReport;
*/
public class PersonalTimesheetDTO {
private static final String d_Y_PATTERN = "d Y";
private static final String MMMM_d_PATTERN = "MMMM d";
private static final String MMMM_Y_PATTERN = "MMMM y";
private static final String MMMM_d_Y_PATTERN = "MMMM d y";
private LocalDate date;
private WorkReport workReport;
@ -108,20 +114,20 @@ public class PersonalTimesheetDTO {
String string = date.toString("w");
if (start.getMonthOfYear() == end.getMonthOfYear()) {
string += " (" + date.toString(MMMM_Y_PATTERN) + ")";
string += " (" + start.toString(MMMM_d_PATTERN) + " - " + end.toString(d_Y_PATTERN) + ")";
} else {
if (start.getYear() == end.getYear()) {
string += " (" + start.toString("MMMM") + " - " + end.toString(MMMM_Y_PATTERN) + ")";
string += " (" + start.toString(MMMM_d_PATTERN) + " - " + end.toString(MMMM_d_Y_PATTERN) + ")";
} else {
string += " (" + start.toString(MMMM_Y_PATTERN) + " - " + end.toString(MMMM_Y_PATTERN) + ")";
string += " (" + start.toString(MMMM_d_Y_PATTERN) + " - " + end.toString(MMMM_d_Y_PATTERN) + ")";
}
}
return _("Week {0}", string);
case TWICE_MONTHLY:
return (date.getDayOfMonth() <= 15)
? _("{0} 1st fortnight", date.toString(MMMM_Y_PATTERN))
: _("{0} 2nd fortnight", date.toString(MMMM_Y_PATTERN));
? _("{0} 1st fortnight", date.toString(MMMM_d_Y_PATTERN))
: _("{0} 2nd fortnight", date.toString(MMMM_d_Y_PATTERN));
case MONTHLY:
default:

View file

@ -101,4 +101,27 @@ public interface ISettingsModel {
void setResourcesLoadFilterCriterion(Criterion criterion);
boolean isShowResourcesOn();
void setShowResourcesOn(boolean showResourcesOn);
boolean isShowAdvancesOn();
void setShowAdvancesOn(boolean showAdvancesOn);
boolean isShowReportedHoursOn();
void setShowReportedHoursOn(boolean showReportedHoursOn);
boolean isShowLabelsOn();
void setShowLabelsOn(boolean showLabelsOn);
boolean isShowMoneyCostBarOn();
void setShowMoneyCostBarOn(boolean showMoneyCostBarOn);
boolean isProjectsFilterFinishedOn();
void setProjectsFilterFinishedOn(boolean projectsFilterFinishedOn);
}

View file

@ -314,4 +314,52 @@ public class SettingsController extends GenericForwardComposer {
settingsModel.setResourcesLoadFilterCriterion(criterion);
}
public boolean isShowResourcesOn() {
return settingsModel.isShowResourcesOn();
}
public void setShowResourcesOn(boolean showResourcesOn) {
settingsModel.setShowResourcesOn(showResourcesOn);
}
public boolean isShowAdvancesOn() {
return settingsModel.isShowAdvancesOn();
}
public void setShowAdvancesOn(boolean showAdvancesOn) {
settingsModel.setShowAdvancesOn(showAdvancesOn);
}
public boolean isShowReportedHoursOn() {
return settingsModel.isShowReportedHoursOn();
}
public void setShowReportedHoursOn(boolean showReportedHoursOn) {
settingsModel.setShowReportedHoursOn(showReportedHoursOn);
}
public boolean isShowLabelsOn() {
return settingsModel.isShowLabelsOn();
}
public void setShowLabelsOn(boolean showLabelsOn) {
settingsModel.setShowLabelsOn(showLabelsOn);
}
public boolean isShowMoneyCostBarOn() {
return settingsModel.isShowMoneyCostBarOn();
}
public void setShowMoneyCostBarOn(boolean showMoneyCostBarOn) {
settingsModel.setShowMoneyCostBarOn(showMoneyCostBarOn);
}
public boolean isProjectsFilterFinishedOn() {
return settingsModel.isProjectsFilterFinishedOn();
}
public void setProjectsFilterFinishedOn(boolean projectsFilterFinishedOn) {
settingsModel.setProjectsFilterFinishedOn(projectsFilterFinishedOn);
}
}

View file

@ -311,4 +311,64 @@ public class SettingsModel implements ISettingsModel {
user.setResourcesLoadFilterCriterion(criterion);
}
@Override
public boolean isShowResourcesOn() {
return user.isShowResourcesOn();
}
@Override
public void setShowResourcesOn(boolean showResourcesOn) {
user.setShowResourcesOn(showResourcesOn);
}
@Override
public boolean isShowAdvancesOn() {
return user.isShowAdvancesOn();
}
@Override
public void setShowAdvancesOn(boolean showAdvancesOn) {
user.setShowAdvancesOn(showAdvancesOn);
}
@Override
public boolean isShowReportedHoursOn() {
return user.isShowReportedHoursOn();
}
@Override
public void setShowReportedHoursOn(boolean showReportedHoursOn) {
user.setShowReportedHoursOn(showReportedHoursOn);
}
@Override
public boolean isShowLabelsOn() {
return user.isShowLabelsOn();
}
@Override
public void setShowLabelsOn(boolean showLabelsOn) {
user.setShowLabelsOn(showLabelsOn);
}
@Override
public boolean isShowMoneyCostBarOn() {
return user.isShowMoneyCostBarOn();
}
@Override
public void setShowMoneyCostBarOn(boolean showMoneyCostBarOn) {
user.setShowMoneyCostBarOn(showMoneyCostBarOn);
}
@Override
public boolean isProjectsFilterFinishedOn() {
return user.isProjectsFilterFinishedOn();
}
@Override
public void setProjectsFilterFinishedOn(boolean projectsFilterFinishedOn) {
user.setProjectsFilterFinishedOn(projectsFilterFinishedOn);
}
}

View file

@ -40,6 +40,8 @@ import org.libreplan.business.labels.entities.LabelType;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.resources.entities.Resource;
import org.libreplan.business.resources.entities.Worker;
import org.libreplan.business.users.entities.User;
import org.libreplan.business.users.entities.UserRole;
import org.libreplan.business.workingday.EffortDuration;
import org.libreplan.business.workreports.entities.HoursManagementEnum;
import org.libreplan.business.workreports.entities.WorkReport;
@ -48,6 +50,7 @@ import org.libreplan.business.workreports.entities.WorkReportLine;
import org.libreplan.business.workreports.entities.WorkReportType;
import org.libreplan.business.workreports.valueobjects.DescriptionField;
import org.libreplan.business.workreports.valueobjects.DescriptionValue;
import org.libreplan.web.UserUtil;
import org.libreplan.web.common.ConstraintChecker;
import org.libreplan.web.common.IMessagesForUser;
import org.libreplan.web.common.Level;
@ -59,6 +62,7 @@ import org.libreplan.web.common.components.NewDataSortableColumn;
import org.libreplan.web.common.components.NewDataSortableGrid;
import org.libreplan.web.common.components.bandboxsearch.BandboxSearch;
import org.libreplan.web.common.entrypoints.IURLHandlerRegistry;
import org.libreplan.web.security.SecurityUtils;
import org.libreplan.web.users.dashboard.IPersonalTimesheetController;
import org.zkoss.ganttz.IPredicate;
import org.zkoss.ganttz.util.ComponentsFinder;
@ -689,16 +693,29 @@ public class WorkReportCRUDController
@Override
public void goToEditForm(WorkReport workReport) {
if ( workReportModel.isPersonalTimesheet(workReport) ) {
goToEditPersonalTimeSheet(workReport);
} else {
if (SecurityUtils.isSuperuserOrUserInRoles(UserRole.ROLE_TIMESHEETS)) {
workReportModel.initEdit(workReport);
createWindow.setTitle(_("Edit Timesheet"));
loadComponents(createWindow);
prepareWorkReportList();
getVisibility().showOnly(createWindow);
Util.reloadBindings(createWindow);
} else if (SecurityUtils.isUserInRole(UserRole.ROLE_BOUND_USER) &&
workReportModel.isPersonalTimesheet(workReport) &&
belongsToCurrentUser(workReport)) {
goToEditPersonalTimeSheet(workReport);
} else {
messagesForUser.showMessage(Level.WARNING, _("You do not have permissions to edit this timesheet"));
}
}
private boolean belongsToCurrentUser(WorkReport workReport) {
User user = UserUtil.getUserFromSession();
assert user != null;
return workReport.getResource().getId().equals(user.getWorker().getId());
}
private void goToEditPersonalTimeSheet(WorkReport workReport) {
@ -989,7 +1006,8 @@ public class WorkReportCRUDController
NewDataSortableGrid grid = (NewDataSortableGrid) row.getParent().getParent();
NewDataSortableColumn priorityColumn = (NewDataSortableColumn) grid.getChildren().get(1).getChildren().get(2);
priorityColumn.setWidth("110px");
// DISCUSS: Are there any implications to not setting a width on this column??
//priorityColumn.setWidth("110px");
if (!getWorkReport().getWorkReportType().getHoursManagement().equals(HoursManagementEnum.NUMBER_OF_HOURS)) {
appendHoursStartAndFinish(row);

View file

@ -1674,7 +1674,7 @@ msgstr ""
#: libreplan-webapp/src/main/webapp/templates/_editTemplate.zul:90
#: libreplan-webapp/src/main/webapp/common/configuration.zul:178
#: libreplan-webapp/src/main/webapp/orders/_edition.zul:140
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:76
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:82
msgid "Calendar"
msgstr ""
@ -3532,7 +3532,7 @@ msgstr ""
#: libreplan-webapp/src/main/webapp/costcategories/_editCostCategory.zul:98
#: libreplan-webapp/src/main/webapp/profiles/_editProfile.zul:74
#: libreplan-webapp/src/main/webapp/orders/components/_listOrderElementMaterials.zul:132
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:90
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:95
#: libreplan-webapp/src/main/webapp/unittypes/unitTypes.zul:43
#: libreplan-webapp/src/main/webapp/qualityforms/_editQualityForm.zul:137
#: libreplan-webapp/src/main/webapp/limitingresources/manualAllocation.zul:135
@ -3725,7 +3725,7 @@ msgstr ""
#: libreplan-webapp/src/main/webapp/workreports/workReport.zul:43
#: libreplan-webapp/src/main/webapp/workreports/workReport.zul:65
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:42
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:48
msgid "Template"
msgstr ""
@ -4300,7 +4300,7 @@ msgstr ""
#: libreplan-webapp/src/main/java/org/libreplan/web/common/components/finders/TaskGroupFilterEnum.java:30
#: libreplan-webapp/src/main/webapp/subcontract/customerCommunications.zul:56
#: libreplan-webapp/src/main/webapp/orders/_edition.zul:227
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:69
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:75
#: libreplan-webapp/src/main/webapp/orders/_list.zul:32
msgid "Customer"
msgstr ""
@ -4447,7 +4447,7 @@ msgstr ""
#: libreplan-webapp/src/main/webapp/orders/_orderElementDetails.zul:35
#: libreplan-webapp/src/main/webapp/orders/_orderElementDetails.zul:41
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:38
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:52
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:58
msgid "cannot be empty"
msgstr ""
@ -7209,7 +7209,7 @@ msgstr ""
#: libreplan-webapp/src/main/webapp/workreports/_editWorkReportType.zul:60
#: libreplan-webapp/src/main/webapp/costcategories/_editCostCategory.zul:45
#: libreplan-webapp/src/main/webapp/orders/_edition.zul:90
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:53
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:59
#: libreplan-webapp/src/main/webapp/unittypes/_editUnitType.zul:45
msgid "Generate code"
msgstr ""
@ -7452,7 +7452,7 @@ msgstr ""
#: libreplan-webapp/src/main/webapp/planner/editTask.zul:81
#: libreplan-webapp/src/main/webapp/planner/reassign.zul:48
#: libreplan-webapp/src/main/webapp/common/layout/template.zul:102
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:88
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:94
#: libreplan-webapp/src/main/webapp/limitingresources/manualAllocation.zul:133
msgid "Accept"
msgstr ""
@ -7590,7 +7590,7 @@ msgstr ""
#: libreplan-webapp/src/main/webapp/costcategories/_editCostCategory.zul:78
#: libreplan-webapp/src/main/webapp/orders/components/_listOrderElementMaterials.zul:109
#: libreplan-webapp/src/main/webapp/orders/_edition.zul:85
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:48
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:54
#: libreplan-webapp/src/main/webapp/orders/_assignmentsBox.zul:26
#: libreplan-webapp/src/main/webapp/orders/_list.zul:29
#: libreplan-webapp/src/main/webapp/unittypes/_editUnitType.zul:37
@ -7767,6 +7767,7 @@ msgstr ""
#: libreplan-webapp/src/main/webapp/scenarios/_edition.zul:43
#: libreplan-webapp/src/main/webapp/orders/_edition.zul:100
#: libreplan-webapp/src/main/webapp/orders/_orderElementDetails.zul:59
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:44
#: libreplan-webapp/src/main/webapp/qualityforms/_listQualityForm.zul:37
#: libreplan-webapp/src/main/webapp/qualityforms/_editQualityForm.zul:49
#: libreplan-webapp/src/main/webapp/email/email_templates.zul:83
@ -7896,7 +7897,7 @@ msgstr ""
#: libreplan-webapp/src/main/webapp/reports/schedulingProgressPerOrderReport.zul:53
#: libreplan-webapp/src/main/webapp/orders/_edition.zul:129
#: libreplan-webapp/src/main/webapp/orders/_orderElementDetails.zul:45
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:58
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:64
#: libreplan-webapp/src/main/webapp/orders/_list.zul:30
msgid "Starting date"
msgstr ""
@ -8357,7 +8358,7 @@ msgstr ""
#: libreplan-webapp/src/main/webapp/subcontract/customerCommunications.zul:54
#: libreplan-webapp/src/main/webapp/orders/_edition.zul:134
#: libreplan-webapp/src/main/webapp/orders/_orderElementDetails.zul:52
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:64
#: libreplan-webapp/src/main/webapp/orders/_projectDetails.zul:70
#: libreplan-webapp/src/main/webapp/orders/_list.zul:31
msgid "Deadline"
msgstr ""
@ -9291,6 +9292,10 @@ msgstr ""
msgid "Welcome page"
msgstr ""
#: libreplan-webapp/src/main/webapp/email/email_templates.zul:124
msgid "Project details page"
msgstr ""
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderStatusEnum.java:43
msgid "ARCHIVED"
msgstr ""

View file

@ -2,6 +2,6 @@
<config-name>i18n</config-name>
<taglib>
<taglib-uri>http://org.libreplan.web/i18n</taglib-uri>
<taglib-location>libreplan-webapp/WEB-INF/tld/i18n.tld</taglib-location>
<taglib-location>/metainfo/tld/i18n.tld</taglib-location>
</taglib>
</config>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="ISO-8859-1" ?>
<taglib>
<uri>http://org.libreplan.web/i18n</uri>
<description>
</description>
<function>
<name>_</name>
<function-class>org.libreplan.web.I18nHelper</function-class>
<function-signature>
java.lang.String _(java.lang.String name)
</function-signature>
<description>
</description>
</function>
<!-- Pass one extra argument -->
<function>
<name>__</name>
<function-class>org.libreplan.web.I18nHelper</function-class>
<function-signature>
java.lang.String _(java.lang.String name, java.lang.Object arg0)
</function-signature>
<description>
</description>
</function>
</taglib>

View file

@ -1,9 +1,5 @@
<zk>
<log>
<log-base/>
</log>
<desktop-config>
<desktop-config>
<!--
Seconds it takes between requests for a desktop to be invalidated.
A timer is introduced to avoid invalidation of pages still open.

View file

@ -3,7 +3,7 @@
<checkbox id="storedColumnVisible" label="${i18n:_('Show archived column data')}"
checked="true" onCheck="dashboardControllerGlobal.showStoredColumn()"/>
<grid id="pipelineGrid" sclass="global-dashboard-grid">
<grid id="pipelineGrid" sclass="global-dashboard-grid" height="500px">
<columns>
<column label="${i18n:_('PRE-SALES')}"/>
<column label="${i18n:_('OFFERED')}"/>

View file

@ -118,6 +118,11 @@
<label value="{url}"/>
<label value="${i18n:_('Welcome page')}"/>
</row>
<row>
<label value="{projecturl}"/>
<label value="${i18n:_('Project details page')}"/>
</row>
</rows>
</grid>

View file

@ -121,6 +121,35 @@
</rows>
</grid>
</row>
<row>
<label value="${i18n:_('Planning view modes on')}" />
<grid>
<columns>
<column />
<column />
<column />
</columns>
<rows>
<row>
<checkbox id="showResourcesOn"
label="${i18n:_('Show resources')}"
checked="@{settingsController.showResourcesOn}"/>
<checkbox id="showAdvancesOn"
label="${i18n:_('Show progress')}"
checked="@{settingsController.showAdvancesOn}"/>
<checkbox id="showReportedHoursOn"
label="${i18n:_('Show reported hours')}"
checked="@{settingsController.showReportedHoursOn}"/>
<checkbox id="showLabelsOn"
label="${i18n:_('Show labels')}"
checked="@{settingsController.showLabelsOn}"/>
<checkbox id="showMoneyCostBarOn"
label="${i18n:_('Show money cost bar')}"
checked="@{settingsController.showMoneyCostBarOn}"/>
</row>
</rows>
</grid>
</row>
<row>
<label value="${i18n:_('Projects view filtering')}" />
<hbox>
@ -143,6 +172,9 @@
value="@{settingsController.projectsFilterPeriodTo}"
width="50px"
constraint="@{settingsController.checkMonthsMaxValue}"/>
<checkbox id="projectsFilterFinishedOn"
label="${i18n:_('Exclude finished projects')}"
checked="@{settingsController.projectsFilterFinishedOn}"/>
</hbox>
</row>

View file

@ -32,9 +32,10 @@
sort="auto(initDate,deadline)" sortDirection="ascending" sclass="date" hflex="min"/>
<column label="${i18n:_('Deadline')}" sort="auto(deadline,initDate)" align="center" sclass="date" hflex="min"/>
<column label="${i18n:_('Customer')}" sort="auto(customerReference)" hflex="min"/>
<column label="${i18n:_('Total Budget')}" sort="auto(totalBudget)" align="right" hflex="min"/>
<column label="${i18n:_('Total Budget')}" sort="auto(totalManualBudget)" align="right" hflex="min"/>
<column label="${i18n:_('Planned Budget')}" sort="auto(totalBudget)" align="right" hflex="min"/>
<column label="${i18n:_('Hours')}" sort="auto(totalHours)" align="right" hflex="min"/>
<column label="${i18n:_('State')}" sort="auto(totalBudget)" align="center" hflex="min"/>
<column label="${i18n:_('State')}" sort="auto(lower(state))" align="center" hflex="min"/>
<column label="${i18n:_('Operations')}" sclass="operations" width="120px"/>
</columns>
</grid>

View file

@ -24,7 +24,8 @@
tooltiptext="${i18n:_('Select required criteria set and press filter button')}"/>
<textbox id="filterProjectName" width="100px"
onChange="orderFilterController.onApplyFilter()" />
onChange="orderFilterController.onApplyFilter()"
onOK="orderFilterController.onApplyFilter()" />
<label value=" ${i18n:_('with')}" />
@ -41,6 +42,11 @@
<datebox id="filterFinishDate" constraint = "@{orderFilterController.checkConstraintFinishDate}"
onChange="orderFilterController.onApplyFilter()"/>
<label value=" ${i18n:_('Exclude finished projects')}" />
<checkbox id="filterExcludeFinishedProject"
onChange="orderFilterController.onApplyFilter()"/>
<button mold="trendy" image="/common/img/ico_filter.png" style="margin-top: -4px"
tooltiptext="${i18n:_('Apply filtering to tasks satisfying required criteria')}"
onClick="orderFilterController.onApplyFilter()"/>

View file

@ -39,6 +39,10 @@
<textbox id="txtName" value="@{projectController.order.name}" width="500px"
constraint="no empty:${i18n:_('cannot be empty')}"
onOK="projectController.accept();"/>
</row>
<row>
<label value="${i18n:_('Description')}" />
<textbox id="txtDescription" value="@{projectController.order.description}" width="500px" rows="7"/>
</row>
<row>
<label value="${i18n:_('Template')}" />

View file

@ -2,7 +2,9 @@ package org.libreplan.web.test.ws.email;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.libreplan.business.common.Registry;
@ -167,6 +169,20 @@ public class EmailTest {
assertTrue(EmailConnectionValidator.exceptionType instanceof MessagingException);
}
@Test
@Transactional
public void testDDeleteEmailNotification() {
EmailTemplate emailTemplate = createEmailTemplate();
emailTemplateDAO.save(emailTemplate);
EmailNotification emailNotification = createEmailNotification();
emailNotificationDAO.save(emailNotification);
emailTemplateDAO.delete(emailTemplate);
boolean result = emailNotificationDAO.deleteByProject(emailNotification.getProject());
assertTrue(result);
}
private EmailTemplate createEmailTemplate() {
EmailTemplate emailTemplate = new EmailTemplate();
emailTemplate.setType(EmailTemplateEnum.TEMPLATE_TODAY_TASK_SHOULD_START);

View file

@ -866,6 +866,12 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.21</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>