Merge branch 'master' into expenses-tracking
This commit is contained in:
commit
00378d039a
119 changed files with 6691 additions and 1321 deletions
|
|
@ -23,7 +23,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
*/
|
||||
public class Emitter<T> {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2010-2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.externalcompanies.daos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.Criteria;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
import org.libreplan.business.common.daos.GenericDAOHibernate;
|
||||
import org.libreplan.business.externalcompanies.entities.CustomerCommunication;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* Hibernate DAO for {@link CustomerCommunication}
|
||||
*
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
@Repository
|
||||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
public class CustomerCommunicationDAO extends GenericDAOHibernate<CustomerCommunication, Long>
|
||||
implements ICustomerCommunicationDAO {
|
||||
|
||||
@Override
|
||||
public List<CustomerCommunication> getAll(){
|
||||
return list(CustomerCommunication.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CustomerCommunication> getAllNotReviewed(){
|
||||
Criteria c = getSession().createCriteria(CustomerCommunication.class);
|
||||
c.add(Restrictions.eq("reviewed", false));
|
||||
return c.list();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.externalcompanies.daos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.libreplan.business.common.daos.IGenericDAO;
|
||||
import org.libreplan.business.externalcompanies.entities.CustomerCommunication;
|
||||
|
||||
|
||||
/**
|
||||
* Interface of the DAO for {@link CustomerCommunication}
|
||||
*
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
public interface ICustomerCommunicationDAO extends IGenericDAO<CustomerCommunication, Long> {
|
||||
|
||||
List<CustomerCommunication> getAll();
|
||||
|
||||
List<CustomerCommunication> getAllNotReviewed();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.externalcompanies.entities;
|
||||
|
||||
import static org.libreplan.business.i18n.I18nHelper._;
|
||||
|
||||
/**
|
||||
* Enum for specified the type of {@link CustomerCommunication}
|
||||
*
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
public enum CommunicationType {
|
||||
|
||||
NEW_PROJECT(_("New project")), PROGRESS_UPDATE(_("Progress Update")), UPDATE_DELIVERING_DATE(
|
||||
_("Update Delivering Date")), END_DATE_UPDATE(_("End date update"));
|
||||
|
||||
private String description;
|
||||
|
||||
private CommunicationType(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public static CommunicationType getDefault() {
|
||||
return NEW_PROJECT;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.externalcompanies.entities;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.hibernate.validator.NotEmpty;
|
||||
import org.hibernate.validator.NotNull;
|
||||
import org.libreplan.business.common.BaseEntity;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
|
||||
/**
|
||||
* Entity CustomerCommunication
|
||||
*
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
public class CustomerCommunication extends BaseEntity {
|
||||
|
||||
private Date deadline;
|
||||
|
||||
private CommunicationType communicationType;
|
||||
|
||||
private Date communicationDate;
|
||||
|
||||
private Boolean reviewed = false;
|
||||
|
||||
private Order order;
|
||||
|
||||
protected CustomerCommunication() {
|
||||
this.setCommunicationDate(new Date());
|
||||
}
|
||||
|
||||
private CustomerCommunication(Date deadline) {
|
||||
this.setDeadline(deadline);
|
||||
this.setCommunicationDate(new Date());
|
||||
}
|
||||
|
||||
public static CustomerCommunication create() {
|
||||
return create(new CustomerCommunication());
|
||||
}
|
||||
|
||||
public static CustomerCommunication createToday(Date deadline) {
|
||||
return create(new CustomerCommunication(deadline));
|
||||
}
|
||||
|
||||
public static CustomerCommunication createTodayNewProject(Date deadline) {
|
||||
return create(new CustomerCommunication(deadline, new Date(),
|
||||
CommunicationType.NEW_PROJECT));
|
||||
}
|
||||
|
||||
protected CustomerCommunication(Date deadline, Date communicationDate,
|
||||
CommunicationType communicationType) {
|
||||
this.setDeadline(deadline);
|
||||
this.setCommunicationDate(communicationDate);
|
||||
this.setCommunicationType(communicationType);
|
||||
}
|
||||
|
||||
protected CustomerCommunication(Date deadline, Date communicationDate,
|
||||
CommunicationType type, Order order) {
|
||||
this.setDeadline(deadline);
|
||||
this.setCommunicationDate(communicationDate);
|
||||
this.setCommunicationType(type);
|
||||
this.setOrder(order);
|
||||
}
|
||||
|
||||
public static CustomerCommunication create(Date deadline,
|
||||
Date communicationDate, CommunicationType communicationType) {
|
||||
return (CustomerCommunication) create(new CustomerCommunication(
|
||||
deadline, communicationDate, communicationType));
|
||||
}
|
||||
|
||||
public static CustomerCommunication create(Date deadline,
|
||||
Date communicationDate, CommunicationType type,
|
||||
Order order) {
|
||||
return (CustomerCommunication) create(new CustomerCommunication(
|
||||
deadline, communicationDate, type, order));
|
||||
}
|
||||
|
||||
public void setDeadline(Date deadline) {
|
||||
this.deadline = deadline;
|
||||
}
|
||||
|
||||
public Date getDeadline() {
|
||||
return deadline;
|
||||
}
|
||||
|
||||
public void setCommunicationType(CommunicationType type) {
|
||||
this.communicationType = type;
|
||||
}
|
||||
|
||||
public CommunicationType getCommunicationType() {
|
||||
return this.communicationType;
|
||||
}
|
||||
|
||||
public void setCommunicationDate(Date communicationDate) {
|
||||
this.communicationDate = communicationDate;
|
||||
}
|
||||
|
||||
public Date getCommunicationDate() {
|
||||
return communicationDate;
|
||||
}
|
||||
|
||||
public void setReviewed(Boolean reviewed) {
|
||||
this.reviewed = reviewed;
|
||||
}
|
||||
|
||||
public Boolean getReviewed() {
|
||||
return reviewed;
|
||||
}
|
||||
|
||||
public void setOrder(Order order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@NotNull(message = "order not specified")
|
||||
public Order getOrder() {
|
||||
return order;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.externalcompanies.entities;
|
||||
|
||||
import java.util.Date;
|
||||
import org.hibernate.validator.NotEmpty;
|
||||
import org.hibernate.validator.NotNull;
|
||||
import org.libreplan.business.common.BaseEntity;
|
||||
|
||||
/**
|
||||
* Entity DeadlineCommunication
|
||||
*
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
public class DeadlineCommunication extends BaseEntity implements DeliverDate{
|
||||
|
||||
private Date saveDate;
|
||||
|
||||
private Date deliverDate;
|
||||
|
||||
protected DeadlineCommunication(){
|
||||
|
||||
}
|
||||
|
||||
private DeadlineCommunication(Date saveDate, Date deliverDate){
|
||||
this.setSaveDate(saveDate);
|
||||
this.setDeliverDate(deliverDate);
|
||||
}
|
||||
|
||||
public static DeadlineCommunication create(Date saveDate, Date deliverDate){
|
||||
return create(new DeadlineCommunication(saveDate, deliverDate));
|
||||
}
|
||||
|
||||
public static DeadlineCommunication create() {
|
||||
return create(new DeadlineCommunication());
|
||||
}
|
||||
|
||||
public void setSaveDate(Date saveDate) {
|
||||
this.saveDate = saveDate;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Date getSaveDate() {
|
||||
return saveDate;
|
||||
}
|
||||
|
||||
public void setDeliverDate(Date deliverDate) {
|
||||
this.deliverDate = deliverDate;
|
||||
}
|
||||
|
||||
public Date getDeliverDate() {
|
||||
return deliverDate;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.libreplan.business.externalcompanies.entities;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.libreplan.business.planner.entities.SubcontractorCommunication;
|
||||
|
||||
/**
|
||||
* Interface for {@link SubcontractorDeliverDate} and {@link DeadlineCommunication}
|
||||
*
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
public interface DeliverDate {
|
||||
public Date getSaveDate();
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.externalcompanies.entities;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.libreplan.business.externalcompanies.entities.DeadlineCommunication;
|
||||
|
||||
/**
|
||||
* Comparator to {@link DeliverDate} interface
|
||||
*
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
|
||||
public class DeliverDateComparator implements Comparator<DeliverDate> {
|
||||
|
||||
public DeliverDateComparator(){
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(DeliverDate arg0, DeliverDate arg1) {
|
||||
if (arg0.getSaveDate() == arg1.getSaveDate()) {
|
||||
return 0;
|
||||
}
|
||||
if (arg0.getSaveDate() == null) {
|
||||
return -1;
|
||||
}
|
||||
if (arg1.getSaveDate() == null) {
|
||||
return 1;
|
||||
}
|
||||
return arg1.getSaveDate().compareTo(arg0.getSaveDate());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2012 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.externalcompanies.entities;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.libreplan.business.common.BaseEntity;
|
||||
|
||||
/**
|
||||
* Entity EndDateCommunication
|
||||
*
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
|
||||
public class EndDateCommunication extends BaseEntity {
|
||||
|
||||
private Date saveDate;
|
||||
|
||||
private Date endDate;
|
||||
|
||||
private Date communicationDate;
|
||||
|
||||
protected EndDateCommunication() {
|
||||
this.setSaveDate(new Date());
|
||||
}
|
||||
|
||||
protected EndDateCommunication(Date endDate) {
|
||||
this.setEndDate(endDate);
|
||||
this.setSaveDate(new Date());
|
||||
}
|
||||
|
||||
protected EndDateCommunication(Date saveDate, Date endDate,
|
||||
Date communicationDate) {
|
||||
this.setSaveDate(saveDate);
|
||||
this.setEndDate(endDate);
|
||||
this.setCommunicationDate(communicationDate);
|
||||
}
|
||||
|
||||
public static EndDateCommunication create() {
|
||||
return create(new EndDateCommunication());
|
||||
}
|
||||
|
||||
public static EndDateCommunication create(Date endDate) {
|
||||
return create(new EndDateCommunication(endDate));
|
||||
}
|
||||
|
||||
public static EndDateCommunication create(Date saveDate, Date endDate,
|
||||
Date communicationDate) {
|
||||
return create(new EndDateCommunication(saveDate, endDate, communicationDate));
|
||||
}
|
||||
|
||||
public void setSaveDate(Date saveDate) {
|
||||
this.saveDate = saveDate;
|
||||
}
|
||||
|
||||
public Date getSaveDate() {
|
||||
return saveDate;
|
||||
}
|
||||
|
||||
public void setEndDate(Date endDate) {
|
||||
this.endDate = endDate;
|
||||
}
|
||||
|
||||
public Date getEndDate() {
|
||||
return endDate;
|
||||
}
|
||||
|
||||
public void setCommunicationDate(Date communicationDate) {
|
||||
this.communicationDate = communicationDate;
|
||||
}
|
||||
|
||||
public Date getCommunicationDate() {
|
||||
return communicationDate;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2012 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.externalcompanies.entities;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
|
||||
public class EndDateCommunicationComparator implements
|
||||
Comparator<EndDateCommunication> {
|
||||
|
||||
public EndDateCommunicationComparator() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(EndDateCommunication arg0, EndDateCommunication arg1) {
|
||||
if (arg0.getSaveDate() == arg1.getSaveDate()) {
|
||||
return 0;
|
||||
}
|
||||
if (arg0.getSaveDate() == null) {
|
||||
return -1;
|
||||
}
|
||||
if (arg1.getSaveDate() == null) {
|
||||
return 1;
|
||||
}
|
||||
return arg1.getSaveDate().compareTo(arg0.getSaveDate());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -128,4 +128,6 @@ public interface IOrderElementDAO extends IIntegrationEntityDAO<OrderElement> {
|
|||
|
||||
boolean hasImputedExpenseSheet(Long id) throws InstanceNotFoundException;
|
||||
|
||||
OrderElement findByExternalCode(String code) throws InstanceNotFoundException;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -281,6 +281,29 @@ public class OrderElementDAO extends IntegrationEntityDAO<OrderElement>
|
|||
return c.list();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public OrderElement findByExternalCode(String code) throws InstanceNotFoundException {
|
||||
|
||||
if (StringUtils.isBlank(code)) {
|
||||
throw new InstanceNotFoundException(null, getEntityClass()
|
||||
.getName());
|
||||
}
|
||||
|
||||
Criteria c = getSession().createCriteria(OrderElement.class);
|
||||
c.add(Restrictions.eq("externalCode", code.trim()).ignoreCase());
|
||||
OrderElement entity = (OrderElement) c.uniqueResult();
|
||||
|
||||
if (entity == null) {
|
||||
throw new InstanceNotFoundException(code, getEntityClass()
|
||||
.getName());
|
||||
} else {
|
||||
return entity;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods to calculate estatistics with the estimated hours and worked
|
||||
* hours of a set of order elements.
|
||||
|
|
|
|||
|
|
@ -24,16 +24,20 @@ package org.libreplan.business.orders.entities;
|
|||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.hibernate.validator.AssertTrue;
|
||||
import org.hibernate.validator.NotNull;
|
||||
import org.hibernate.validator.Valid;
|
||||
import org.libreplan.business.advance.bootstrap.PredefinedAdvancedTypes;
|
||||
import org.libreplan.business.advance.entities.AdvanceType;
|
||||
import org.libreplan.business.advance.entities.DirectAdvanceAssignment;
|
||||
|
|
@ -41,6 +45,11 @@ import org.libreplan.business.calendars.entities.BaseCalendar;
|
|||
import org.libreplan.business.common.Registry;
|
||||
import org.libreplan.business.common.entities.EntitySequence;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.externalcompanies.entities.CustomerCommunication;
|
||||
import org.libreplan.business.externalcompanies.entities.DeadlineCommunication;
|
||||
import org.libreplan.business.externalcompanies.entities.DeliverDateComparator;
|
||||
import org.libreplan.business.externalcompanies.entities.EndDateCommunication;
|
||||
import org.libreplan.business.externalcompanies.entities.EndDateCommunicationComparator;
|
||||
import org.libreplan.business.externalcompanies.entities.ExternalCompany;
|
||||
import org.libreplan.business.orders.daos.IOrderDAO;
|
||||
import org.libreplan.business.planner.entities.DayAssignment;
|
||||
|
|
@ -109,6 +118,16 @@ public class Order extends OrderLineGroup implements Comparable {
|
|||
|
||||
private CurrentVersionInfo currentVersionInfo;
|
||||
|
||||
private Set<CustomerCommunication> customerCommunications = new HashSet<CustomerCommunication>();
|
||||
|
||||
@Valid
|
||||
private SortedSet<DeadlineCommunication> deliveringDates = new TreeSet<DeadlineCommunication>(
|
||||
new DeliverDateComparator());
|
||||
|
||||
@Valid
|
||||
private SortedSet<EndDateCommunication> endDateCommunicationToCustomer = new TreeSet<EndDateCommunication>(
|
||||
new EndDateCommunicationComparator());
|
||||
|
||||
public enum SchedulingMode {
|
||||
FORWARD, BACKWARDS;
|
||||
}
|
||||
|
|
@ -578,6 +597,63 @@ public class Order extends OrderLineGroup implements Comparable {
|
|||
return this.getName().compareToIgnoreCase(((Order) o).getName());
|
||||
}
|
||||
|
||||
public void setCustomerCommunications(Set<CustomerCommunication> customerCommunications) {
|
||||
this.customerCommunications = customerCommunications;
|
||||
}
|
||||
|
||||
public Set<CustomerCommunication> getCustomerCommunications() {
|
||||
return customerCommunications;
|
||||
}
|
||||
|
||||
public void setDeliveringDates(SortedSet<DeadlineCommunication> deliveringDates) {
|
||||
this.deliveringDates = deliveringDates;
|
||||
}
|
||||
|
||||
public SortedSet<DeadlineCommunication> getDeliveringDates() {
|
||||
return deliveringDates;
|
||||
}
|
||||
|
||||
public void setEndDateCommunicationToCustomer(
|
||||
SortedSet<EndDateCommunication> endDateCommunicationToCustomer) {
|
||||
this.endDateCommunicationToCustomer.clear();
|
||||
this.endDateCommunicationToCustomer.addAll(endDateCommunicationToCustomer);
|
||||
}
|
||||
|
||||
public SortedSet<EndDateCommunication> getEndDateCommunicationToCustomer() {
|
||||
return Collections.unmodifiableSortedSet(this.endDateCommunicationToCustomer);
|
||||
}
|
||||
|
||||
|
||||
public void updateFirstAskedEndDate(Date communicationDate) {
|
||||
if (this.endDateCommunicationToCustomer != null && !this.endDateCommunicationToCustomer.isEmpty()) {
|
||||
this.endDateCommunicationToCustomer.first().setCommunicationDate(communicationDate);
|
||||
}
|
||||
}
|
||||
|
||||
public Date getLastAskedEndDate() {
|
||||
if (this.endDateCommunicationToCustomer != null
|
||||
&& !this.endDateCommunicationToCustomer.isEmpty()) {
|
||||
return this.endDateCommunicationToCustomer.first().getEndDate();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public EndDateCommunication getLastEndDateCommunicationToCustomer() {
|
||||
if (this.endDateCommunicationToCustomer != null
|
||||
&& !this.endDateCommunicationToCustomer.isEmpty()) {
|
||||
return this.endDateCommunicationToCustomer.first();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void removeAskedEndDate(EndDateCommunication endDate) {
|
||||
this.endDateCommunicationToCustomer.remove(endDate);
|
||||
}
|
||||
|
||||
public void addAskedEndDate(EndDateCommunication endDate) {
|
||||
this.endDateCommunicationToCustomer.add(endDate);
|
||||
}
|
||||
|
||||
public void markAsNeededToRecalculateSumChargedEfforts() {
|
||||
neededToRecalculateSumChargedEfforts = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -299,6 +299,16 @@ public abstract class OrderElement extends IntegrationEntity implements
|
|||
//we have to remove the TaskSource which contains a TaskGroup instead of TaskElement
|
||||
removeTaskSource(result);
|
||||
}
|
||||
if(currentTaskSourceIsNotTheSame()) {
|
||||
//this element was unscheduled and then scheduled again. Its TaskSource has
|
||||
//been recreated but we have to remove the old one.
|
||||
if(!getParent().currentTaskSourceIsNotTheSame()) {
|
||||
//we only remove the TaskSource if the parent is not in the same situation.
|
||||
//In case the parent is in the same situation, it will remove the related
|
||||
//TaskSources in children tasks.
|
||||
removeTaskSource(result);
|
||||
}
|
||||
}
|
||||
result
|
||||
.addAll(synchronizationForSchedulingPoint(schedulingDataForVersion));
|
||||
} else if (isSuperElementPartialOrCompletelyScheduled()) {
|
||||
|
|
@ -306,6 +316,15 @@ public abstract class OrderElement extends IntegrationEntity implements
|
|||
if (wasASchedulingPoint()) {
|
||||
result.add(taskSourceRemoval());
|
||||
}
|
||||
if(currentTaskSourceIsNotTheSame()) {
|
||||
//all the children of this element were unscheduled and then scheduled again,
|
||||
//its TaskSource has been recreated but we have to remove the old one.
|
||||
if(getParent() == null || !getParent().currentTaskSourceIsNotTheSame()) {
|
||||
//if it's a container node inside another container we could have the
|
||||
//same problem than in the case of leaf tasks.
|
||||
result.add(taskSourceRemoval());
|
||||
}
|
||||
}
|
||||
result
|
||||
.add(synchronizationForSuperelement(schedulingDataForVersion));
|
||||
} else if (schedulingState.isNoScheduled()) {
|
||||
|
|
@ -333,6 +352,10 @@ public abstract class OrderElement extends IntegrationEntity implements
|
|||
.getSchedulingStateType();
|
||||
}
|
||||
|
||||
protected boolean currentTaskSourceIsNotTheSame() {
|
||||
return getOnDBTaskSource() != getTaskSource();
|
||||
}
|
||||
|
||||
private List<TaskSourceSynchronization> childrenSynchronizations() {
|
||||
List<TaskSourceSynchronization> childrenOfGroup = new ArrayList<TaskSourceSynchronization>();
|
||||
for (OrderElement orderElement : getSomewhatScheduledOrderElements()) {
|
||||
|
|
@ -742,7 +765,7 @@ public abstract class OrderElement extends IntegrationEntity implements
|
|||
* @param newAdvanceAssignment
|
||||
* @throws DuplicateAdvanceAssignmentForOrderElementException
|
||||
*/
|
||||
private void checkAncestorsNoOtherAssignmentWithSameAdvanceType(
|
||||
public void checkAncestorsNoOtherAssignmentWithSameAdvanceType(
|
||||
OrderElement orderElement,
|
||||
DirectAdvanceAssignment newAdvanceAssignment)
|
||||
throws DuplicateAdvanceAssignmentForOrderElementException {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
* Desenvolvemento Tecnolóxico de Galicia
|
||||
* Copyright (C) 2010-2011 Igalia, S.L.
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
|
|
@ -24,6 +26,8 @@ package org.libreplan.business.planner.daos;
|
|||
import java.util.List;
|
||||
|
||||
import org.libreplan.business.common.daos.IGenericDAO;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.orders.entities.OrderElement;
|
||||
import org.libreplan.business.planner.entities.SubcontractedTaskData;
|
||||
|
||||
/**
|
||||
|
|
@ -42,4 +46,6 @@ public interface ISubcontractedTaskDataDAO extends
|
|||
|
||||
List<SubcontractedTaskData> getAllForMasterScenario();
|
||||
|
||||
SubcontractedTaskData getSubcontratedTaskDataByOrderElement(
|
||||
OrderElement orderElement) throws InstanceNotFoundException;
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.planner.daos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.libreplan.business.common.daos.IGenericDAO;
|
||||
import org.libreplan.business.planner.entities.SubcontractorCommunication;
|
||||
|
||||
public interface ISubcontractorCommunicationDAO extends IGenericDAO<SubcontractorCommunication, Long> {
|
||||
|
||||
List<SubcontractorCommunication> getAll();
|
||||
|
||||
List<SubcontractorCommunication> getAllNotReviewed();
|
||||
}
|
||||
|
|
@ -5,6 +5,8 @@
|
|||
* Desenvolvemento Tecnolóxico de Galicia
|
||||
* Copyright (C) 2010-2011 Igalia, S.L.
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
|
|
@ -24,10 +26,13 @@ package org.libreplan.business.planner.daos;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.Criteria;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
import org.libreplan.business.common.daos.GenericDAOHibernate;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderElement;
|
||||
import org.libreplan.business.orders.entities.TaskSource;
|
||||
import org.libreplan.business.planner.entities.SubcontractedTaskData;
|
||||
import org.libreplan.business.planner.entities.Task;
|
||||
import org.libreplan.business.planner.entities.TaskElement;
|
||||
|
|
@ -99,4 +104,18 @@ public class SubcontractedTaskDataDAO extends
|
|||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public SubcontractedTaskData getSubcontratedTaskDataByOrderElement(
|
||||
OrderElement orderElement) throws InstanceNotFoundException {
|
||||
Criteria c = getSession().createCriteria(TaskElement.class)
|
||||
.createCriteria("taskSource","ts")
|
||||
.createCriteria("schedulingData","data")
|
||||
.add(Restrictions.eq("data.orderElement",orderElement));
|
||||
|
||||
TaskElement taskElement = (TaskElement) c.uniqueResult();
|
||||
return (taskElement != null && taskElement.isSubcontracted()) ? ((Task) taskElement)
|
||||
.getSubcontractedTaskData() : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.planner.daos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.Criteria;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
import org.libreplan.business.common.daos.GenericDAOHibernate;
|
||||
import org.libreplan.business.planner.entities.SubcontractorCommunication;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* DAO for {@link SubcontractorCommunication}
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
|
||||
@Repository
|
||||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
public class SubcontractorCommunicationDAO extends GenericDAOHibernate<SubcontractorCommunication, Long>
|
||||
implements ISubcontractorCommunicationDAO {
|
||||
|
||||
@Override
|
||||
public List<SubcontractorCommunication> getAll() {
|
||||
return list(SubcontractorCommunication.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SubcontractorCommunication> getAllNotReviewed(){
|
||||
Criteria c = getSession().createCriteria(SubcontractorCommunication.class);
|
||||
c.add(Restrictions.eq("reviewed", false));
|
||||
return c.list();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2012 Igalia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.planner.entities;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.libreplan.business.calendars.entities.AvailabilityTimeLine;
|
||||
import org.libreplan.business.calendars.entities.AvailabilityTimeLine.Interval;
|
||||
import org.libreplan.business.hibernate.notification.PredefinedDatabaseSnapshots;
|
||||
import org.libreplan.business.workreports.entities.WorkReportLine;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Diego Pino García <dpino@igalia.com>
|
||||
*/
|
||||
@Component
|
||||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
public class CompanyEarnedValueCalculator extends EarnedValueCalculator implements ICompanyEarnedValueCalculator {
|
||||
|
||||
@Autowired
|
||||
private PredefinedDatabaseSnapshots databaseSnapshots;
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public SortedMap<LocalDate, BigDecimal> calculateBudgetedCostWorkScheduled(AvailabilityTimeLine.Interval interval) {
|
||||
Map<TaskElement, SortedMap<LocalDate, BigDecimal>> estimatedCostPerTask = databaseSnapshots
|
||||
.snapshotEstimatedCostPerTask();
|
||||
Collection<TaskElement> list = filterTasksByDate(
|
||||
estimatedCostPerTask.keySet(), interval);
|
||||
SortedMap<LocalDate, BigDecimal> estimatedCost = new TreeMap<LocalDate, BigDecimal>();
|
||||
|
||||
for (TaskElement each : list) {
|
||||
addCost(estimatedCost, estimatedCostPerTask.get(each));
|
||||
}
|
||||
return accumulateResult(estimatedCost);
|
||||
}
|
||||
|
||||
private List<TaskElement> filterTasksByDate(
|
||||
Collection<TaskElement> tasks,
|
||||
AvailabilityTimeLine.Interval interval) {
|
||||
List<TaskElement> result = new ArrayList<TaskElement>();
|
||||
for(TaskElement task : tasks) {
|
||||
if (interval.includes(task.getStartAsLocalDate())
|
||||
|| interval.includes(task.getEndAsLocalDate())) {
|
||||
result.add(task);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<WorkReportLine> filterWorkReportLinesByDate(
|
||||
Collection<WorkReportLine> lines,
|
||||
AvailabilityTimeLine.Interval interval) {
|
||||
List<WorkReportLine> result = new ArrayList<WorkReportLine>();
|
||||
for(WorkReportLine line: lines) {
|
||||
if (interval.includes(line.getLocalDate())) {
|
||||
result.add(line);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void addCost(SortedMap<LocalDate, BigDecimal> currentCost,
|
||||
SortedMap<LocalDate, BigDecimal> additionalCost) {
|
||||
for (LocalDate day : additionalCost.keySet()) {
|
||||
if (!currentCost.containsKey(day)) {
|
||||
currentCost.put(day, BigDecimal.ZERO);
|
||||
}
|
||||
currentCost.put(day, currentCost.get(day).add(
|
||||
additionalCost.get(day)));
|
||||
}
|
||||
}
|
||||
|
||||
private SortedMap<LocalDate, BigDecimal> accumulateResult(
|
||||
SortedMap<LocalDate, BigDecimal> map) {
|
||||
SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
|
||||
if (map.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
BigDecimal accumulatedResult = BigDecimal.ZERO;
|
||||
for (LocalDate day : map.keySet()) {
|
||||
BigDecimal value = map.get(day);
|
||||
accumulatedResult = accumulatedResult.add(value);
|
||||
result.put(day, accumulatedResult);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<LocalDate, BigDecimal> calculateActualCostWorkPerformed(
|
||||
Interval interval) {
|
||||
SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
|
||||
Collection<WorkReportLine> workReportLines = filterWorkReportLinesByDate(
|
||||
databaseSnapshots.snapshotWorkReportLines(),
|
||||
interval);
|
||||
|
||||
if (workReportLines.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
for (WorkReportLine workReportLine : workReportLines) {
|
||||
LocalDate day = new LocalDate(workReportLine.getDate());
|
||||
BigDecimal cost = workReportLine.getEffort()
|
||||
.toHoursAsDecimalWithScale(2);
|
||||
|
||||
if (!result.containsKey(day)) {
|
||||
result.put(day, BigDecimal.ZERO);
|
||||
}
|
||||
result.put(day, result.get(day).add(cost));
|
||||
}
|
||||
return accumulateResult(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<LocalDate, BigDecimal> calculateBudgetedCostWorkPerformed(
|
||||
Interval interval) {
|
||||
Map<TaskElement, SortedMap<LocalDate, BigDecimal>> advanceCostPerTask = databaseSnapshots
|
||||
.snapshotAdvanceCostPerTask();
|
||||
Collection<TaskElement> tasks = filterTasksByDate(
|
||||
advanceCostPerTask.keySet(), interval);
|
||||
|
||||
SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
|
||||
for (TaskElement each : tasks) {
|
||||
addCost(result, advanceCostPerTask.get(each));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2012 Igalia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.planner.entities;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
* @author Diego Pino García <dpino@igalia.com>
|
||||
*
|
||||
* Calculates generic 'Earned Value' indicators (those calculated out of
|
||||
* BCWP, ACWP and BCWS
|
||||
*/
|
||||
@Component
|
||||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
public class EarnedValueCalculator implements IEarnedValueCalculator {
|
||||
|
||||
@Override
|
||||
public SortedMap<LocalDate, BigDecimal> calculateCostVariance(
|
||||
SortedMap<LocalDate, BigDecimal> bcwp,
|
||||
SortedMap<LocalDate, BigDecimal> acwp) {
|
||||
return substract(bcwp, acwp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<LocalDate, BigDecimal> calculateScheduleVariance(
|
||||
SortedMap<LocalDate, BigDecimal> bcwp,
|
||||
SortedMap<LocalDate, BigDecimal> bcws) {
|
||||
return substract(bcwp, bcws);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<LocalDate, BigDecimal> calculateBudgetAtCompletion(
|
||||
SortedMap<LocalDate, BigDecimal> bcws) {
|
||||
SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
|
||||
BigDecimal value = Collections.max(bcws.values());
|
||||
for (LocalDate day : bcws.keySet()) {
|
||||
result.put(day, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<LocalDate, BigDecimal> calculateEstimateAtCompletion(
|
||||
SortedMap<LocalDate, BigDecimal> acwp,
|
||||
SortedMap<LocalDate, BigDecimal> bcwp,
|
||||
SortedMap<LocalDate, BigDecimal> bac) {
|
||||
return multiply(divide(acwp, bcwp,
|
||||
BigDecimal.ZERO), bac);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<LocalDate, BigDecimal> calculateVarianceAtCompletion(
|
||||
SortedMap<LocalDate, BigDecimal> bac,
|
||||
SortedMap<LocalDate, BigDecimal> eac) {
|
||||
return substract(bac, eac);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<LocalDate, BigDecimal> calculateEstimatedToComplete(
|
||||
SortedMap<LocalDate, BigDecimal> eac,
|
||||
SortedMap<LocalDate, BigDecimal> acwp) {
|
||||
return substract(eac, acwp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<LocalDate, BigDecimal> calculateCostPerformanceIndex(
|
||||
SortedMap<LocalDate, BigDecimal> bcwp,
|
||||
SortedMap<LocalDate, BigDecimal> acwp) {
|
||||
return divide(bcwp, acwp, BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<LocalDate, BigDecimal> calculateSchedulePerformanceIndex(
|
||||
SortedMap<LocalDate, BigDecimal> bcwp,
|
||||
SortedMap<LocalDate, BigDecimal> bcws) {
|
||||
return divide(bcwp, bcws, BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
private SortedMap<LocalDate, BigDecimal> substract(
|
||||
SortedMap<LocalDate, BigDecimal> minuend,
|
||||
SortedMap<LocalDate, BigDecimal> subtrahend) {
|
||||
final SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
|
||||
forValuesAtSameKey(minuend, subtrahend, substractionOperation(result));
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
public static <K, V> void forValuesAtSameKey(Map<K, V> a, Map<K, V> b,
|
||||
IOperation<K, V> onSameKey) {
|
||||
for (Entry<K, V> each : a.entrySet()) {
|
||||
V aValue = each.getValue();
|
||||
V bValue = b.get(each.getKey());
|
||||
onSameKey.operate(each.getKey(), aValue, bValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static IOperation<LocalDate, BigDecimal> substractionOperation(
|
||||
final SortedMap<LocalDate, BigDecimal> result) {
|
||||
return notNullOperands(new IOperation<LocalDate, BigDecimal>() {
|
||||
|
||||
@Override
|
||||
public void operate(LocalDate key, BigDecimal minuedValue,
|
||||
BigDecimal subtrahendValue) {
|
||||
result.put(key, minuedValue.subtract(subtrahendValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undefinedFor(LocalDate key) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static <K, V> IOperation<K, V> notNullOperands(
|
||||
final IOperation<K, V> operation) {
|
||||
return new PreconditionChecker<K, V>(operation) {
|
||||
@Override
|
||||
protected boolean isOperationDefinedFor(K key, V a, V b) {
|
||||
return a != null && b != null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public interface IOperation<K, V> {
|
||||
|
||||
public void operate(K key, V a, V b);
|
||||
|
||||
public void undefinedFor(K key);
|
||||
}
|
||||
|
||||
protected static abstract class PreconditionChecker<K, V> implements
|
||||
IOperation<K, V> {
|
||||
|
||||
private final IOperation<K, V> decorated;
|
||||
|
||||
protected PreconditionChecker(IOperation<K, V> decorated) {
|
||||
this.decorated = decorated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void operate(K key, V a, V b) {
|
||||
if (isOperationDefinedFor(key, a, b)) {
|
||||
decorated.operate(key, a, b);
|
||||
} else {
|
||||
decorated.undefinedFor(key);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract boolean isOperationDefinedFor(K key, V a, V b);
|
||||
|
||||
@Override
|
||||
public void undefinedFor(K key) {
|
||||
decorated.undefinedFor(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static SortedMap<LocalDate, BigDecimal> multiply(
|
||||
Map<LocalDate, BigDecimal> firstFactor,
|
||||
Map<LocalDate, BigDecimal> secondFactor) {
|
||||
final SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
|
||||
forValuesAtSameKey(firstFactor, secondFactor,
|
||||
multiplicationOperation(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IOperation<LocalDate, BigDecimal> multiplicationOperation(
|
||||
final SortedMap<LocalDate, BigDecimal> result) {
|
||||
return notNullOperands(new IOperation<LocalDate, BigDecimal>() {
|
||||
|
||||
@Override
|
||||
public void operate(LocalDate key, BigDecimal a,
|
||||
BigDecimal b) {
|
||||
result.put(key, a.multiply(b));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undefinedFor(LocalDate key) {
|
||||
result.put(key, BigDecimal.ZERO);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static SortedMap<LocalDate, BigDecimal> divide(
|
||||
Map<LocalDate, BigDecimal> dividend,
|
||||
Map<LocalDate, BigDecimal> divisor,
|
||||
final BigDecimal defaultIfNotComputable) {
|
||||
final TreeMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
|
||||
forValuesAtSameKey(dividend, divisor,
|
||||
divisionOperation(result, defaultIfNotComputable));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IOperation<LocalDate, BigDecimal> divisionOperation(
|
||||
final TreeMap<LocalDate, BigDecimal> result,
|
||||
final BigDecimal defaultIfNotComputable) {
|
||||
return notNullOperands(secondOperandNotZero(new IOperation<LocalDate, BigDecimal>() {
|
||||
|
||||
@Override
|
||||
public void operate(LocalDate key, BigDecimal dividendValue,
|
||||
BigDecimal divisorValue) {
|
||||
result.put(key,
|
||||
dividendValue.divide(divisorValue, RoundingMode.DOWN));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undefinedFor(LocalDate key) {
|
||||
result.put(key, defaultIfNotComputable);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public static <K> IOperation<K, BigDecimal> secondOperandNotZero(
|
||||
final IOperation<K, BigDecimal> operation) {
|
||||
return new PreconditionChecker<K, BigDecimal>(operation) {
|
||||
@Override
|
||||
protected boolean isOperationDefinedFor(K key, BigDecimal a,
|
||||
BigDecimal b) {
|
||||
return b.signum() != 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2012 Igalia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.planner.entities;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.SortedMap;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.libreplan.business.calendars.entities.AvailabilityTimeLine;
|
||||
|
||||
/**
|
||||
* @author Diego Pino García <dpino@igalia.com>
|
||||
*
|
||||
* Utility class for calculating all 'Earned Value' indicators
|
||||
*/
|
||||
public interface ICompanyEarnedValueCalculator extends IEarnedValueCalculator {
|
||||
|
||||
SortedMap<LocalDate, BigDecimal> calculateBudgetedCostWorkScheduled(
|
||||
AvailabilityTimeLine.Interval interval);
|
||||
|
||||
SortedMap<LocalDate, BigDecimal> calculateActualCostWorkPerformed(
|
||||
AvailabilityTimeLine.Interval interval);
|
||||
|
||||
SortedMap<LocalDate, BigDecimal> calculateBudgetedCostWorkPerformed(
|
||||
AvailabilityTimeLine.Interval interval);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2012 Igalia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.planner.entities;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.SortedMap;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
/**
|
||||
* @author Diego Pino García <dpino@igalia.com>
|
||||
*
|
||||
* Utility class for calculating all 'Earned Value' indicators
|
||||
*/
|
||||
public interface IEarnedValueCalculator {
|
||||
|
||||
// CV = BCWP - ACWP
|
||||
SortedMap<LocalDate, BigDecimal> calculateCostVariance(
|
||||
SortedMap<LocalDate, BigDecimal> bcwp,
|
||||
SortedMap<LocalDate, BigDecimal> acwp);
|
||||
|
||||
// SV = BCWP - BCWS
|
||||
SortedMap<LocalDate, BigDecimal> calculateScheduleVariance(
|
||||
SortedMap<LocalDate, BigDecimal> bcwp,
|
||||
SortedMap<LocalDate, BigDecimal> bcws);
|
||||
|
||||
// BAC = max (BCWS)
|
||||
SortedMap<LocalDate, BigDecimal> calculateBudgetAtCompletion(
|
||||
SortedMap<LocalDate, BigDecimal> bcws);
|
||||
|
||||
// EAC = (ACWP/BCWP) * BAC
|
||||
SortedMap<LocalDate, BigDecimal> calculateEstimateAtCompletion(
|
||||
SortedMap<LocalDate, BigDecimal> acwp,
|
||||
SortedMap<LocalDate, BigDecimal> bcwp,
|
||||
SortedMap<LocalDate, BigDecimal> bac);
|
||||
|
||||
// VAC = BAC - EAC
|
||||
SortedMap<LocalDate, BigDecimal> calculateVarianceAtCompletion(
|
||||
SortedMap<LocalDate, BigDecimal> bac,
|
||||
SortedMap<LocalDate, BigDecimal> eac);
|
||||
|
||||
// ETC = EAC - ACWP
|
||||
SortedMap<LocalDate, BigDecimal> calculateEstimatedToComplete(
|
||||
SortedMap<LocalDate, BigDecimal> eac,
|
||||
SortedMap<LocalDate, BigDecimal> acwp);
|
||||
|
||||
// SPI = BCWP / BCWS
|
||||
SortedMap<LocalDate, BigDecimal> calculateSchedulePerformanceIndex(
|
||||
SortedMap<LocalDate, BigDecimal> bcwp,
|
||||
SortedMap<LocalDate, BigDecimal> bcws);
|
||||
|
||||
// CPI = BCWP / ACWP
|
||||
SortedMap<LocalDate, BigDecimal> calculateCostPerformanceIndex(
|
||||
SortedMap<LocalDate, BigDecimal> bcwp,
|
||||
SortedMap<LocalDate, BigDecimal> acwp);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2012 Igalia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.planner.entities;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.SortedMap;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
|
||||
/**
|
||||
* @author Diego Pino García <dpino@igalia.com>
|
||||
*
|
||||
* Utility class for calculating all 'Earned Value' indicators
|
||||
*/
|
||||
public interface IOrderEarnedValueCalculator extends IEarnedValueCalculator {
|
||||
|
||||
// ACWP (Actual Cost Work Performed)
|
||||
SortedMap<LocalDate, BigDecimal> calculateActualCostWorkPerformed(
|
||||
Order order);
|
||||
|
||||
// BCWP (Budgeted Cost Work Performed)
|
||||
SortedMap<LocalDate, BigDecimal> calculateBudgetedCostWorkPerformed(
|
||||
Order order);
|
||||
|
||||
// BCWS (Budgeted Cost Work Scheduled)
|
||||
SortedMap<LocalDate, BigDecimal> calculateBudgetedCostWorkScheduled(Order order);
|
||||
|
||||
// ACWP at date
|
||||
BigDecimal getActualCostWorkPerformedAt(Order order, LocalDate date);
|
||||
|
||||
// BAC (Budget at Completion)
|
||||
BigDecimal getBudgetAtCompletion(Order order);
|
||||
|
||||
// BCWP at date
|
||||
BigDecimal getBudgetedCostWorkPerformedAt(Order order, LocalDate date);
|
||||
|
||||
// CPI (Cost Performance Index)
|
||||
BigDecimal getCostPerformanceIndex(BigDecimal budgetedCost,
|
||||
BigDecimal actualCost);
|
||||
|
||||
// CV (Cost Variance)
|
||||
BigDecimal getCostVariance(BigDecimal budgetedCost, BigDecimal actualCost);
|
||||
|
||||
// EAC (Estimate At Completion)
|
||||
BigDecimal getEstimateAtCompletion(BigDecimal budgetAtCompletion,
|
||||
BigDecimal costPerformanceIndex);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2012 Igalia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.planner.entities;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Diego Pino García <dpino@igalia.com>
|
||||
*/
|
||||
@Component
|
||||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
public class OrderEarnedValueCalculator extends EarnedValueCalculator implements IOrderEarnedValueCalculator {
|
||||
|
||||
@Autowired
|
||||
private ICostCalculator hoursCostCalculator;
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
@Override
|
||||
public BigDecimal getActualCostWorkPerformedAt(Order order, LocalDate date) {
|
||||
SortedMap<LocalDate, BigDecimal> actualCost = calculateActualCostWorkPerformed(order);
|
||||
BigDecimal result = actualCost.get(date);
|
||||
return (result != null) ? result : BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
@Override
|
||||
public SortedMap<LocalDate, BigDecimal> calculateActualCostWorkPerformed(
|
||||
Order order) {
|
||||
SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
|
||||
for (TaskElement taskElement : getAllTaskElements(order)) {
|
||||
if (taskElement instanceof Task) {
|
||||
addCost(result, getWorkReportCost((Task) taskElement));
|
||||
}
|
||||
}
|
||||
return accumulateResult(result);
|
||||
}
|
||||
|
||||
private SortedMap<LocalDate, BigDecimal> accumulateResult(
|
||||
SortedMap<LocalDate, BigDecimal> map) {
|
||||
SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
|
||||
if (map.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
BigDecimal accumulatedResult = BigDecimal.ZERO;
|
||||
for (LocalDate day : map.keySet()) {
|
||||
BigDecimal value = map.get(day);
|
||||
accumulatedResult = accumulatedResult.add(value);
|
||||
result.put(day, accumulatedResult);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void addCost(SortedMap<LocalDate, BigDecimal> currentCost,
|
||||
SortedMap<LocalDate, BigDecimal> additionalCost) {
|
||||
for (LocalDate day : additionalCost.keySet()) {
|
||||
if (!currentCost.containsKey(day)) {
|
||||
currentCost.put(day, BigDecimal.ZERO);
|
||||
}
|
||||
currentCost.put(day,
|
||||
currentCost.get(day).add(additionalCost.get(day)));
|
||||
}
|
||||
}
|
||||
|
||||
private List<TaskElement> getAllTaskElements(Order order) {
|
||||
List<TaskElement> result = order.getAllChildrenAssociatedTaskElements();
|
||||
result.add(order.getAssociatedTaskElement());
|
||||
return result;
|
||||
}
|
||||
|
||||
private SortedMap<LocalDate, BigDecimal> getWorkReportCost(Task taskElement) {
|
||||
return hoursCostCalculator.getWorkReportCost(taskElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public BigDecimal getBudgetAtCompletion(Order order) {
|
||||
SortedMap<LocalDate, BigDecimal> budgedtedCost = calculateBudgetedCostWorkScheduled(order);
|
||||
LocalDate lastKey = budgedtedCost.lastKey();
|
||||
return (lastKey) != null ? budgedtedCost.get(lastKey) : BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public SortedMap<LocalDate, BigDecimal> calculateBudgetedCostWorkScheduled(
|
||||
Order order) {
|
||||
SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
|
||||
for (TaskElement taskElement : getAllTaskElements(order)) {
|
||||
if (taskElement instanceof Task) {
|
||||
addCost(result, getEstimatedCost((Task) taskElement));
|
||||
}
|
||||
}
|
||||
return accumulateResult(result);
|
||||
}
|
||||
|
||||
private SortedMap<LocalDate, BigDecimal> getEstimatedCost(Task task) {
|
||||
return hoursCostCalculator.getEstimatedCost(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public BigDecimal getBudgetedCostWorkPerformedAt(Order order, LocalDate date) {
|
||||
SortedMap<LocalDate, BigDecimal> budgetedCost = calculateBudgetedCostWorkPerformed(order);
|
||||
BigDecimal result = budgetedCost.get(date);
|
||||
return (result != null) ? result : BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public SortedMap<LocalDate, BigDecimal> calculateBudgetedCostWorkPerformed(
|
||||
Order order) {
|
||||
SortedMap<LocalDate, BigDecimal> estimatedCost = new TreeMap<LocalDate, BigDecimal>();
|
||||
for (TaskElement taskElement : getAllTaskElements(order)) {
|
||||
if (taskElement instanceof Task) {
|
||||
addCost(estimatedCost, getAdvanceCost((Task) taskElement));
|
||||
}
|
||||
}
|
||||
return accumulateResult(estimatedCost);
|
||||
}
|
||||
|
||||
private SortedMap<LocalDate, BigDecimal> getAdvanceCost(Task task) {
|
||||
return hoursCostCalculator.getAdvanceCost(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getCostPerformanceIndex(BigDecimal budgetedCost,
|
||||
BigDecimal actualCost) {
|
||||
if (BigDecimal.ZERO.compareTo(actualCost) == 0) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return asPercentage(budgetedCost.divide(actualCost));
|
||||
}
|
||||
|
||||
private BigDecimal asPercentage(BigDecimal value) {
|
||||
return value.multiply(BigDecimal.valueOf(100)).setScale(2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getCostVariance(BigDecimal budgetedCost,
|
||||
BigDecimal actualCost) {
|
||||
return budgetedCost.subtract(actualCost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getEstimateAtCompletion(BigDecimal budgetAtCompletion,
|
||||
BigDecimal costPerformanceIndex) {
|
||||
if (BigDecimal.ZERO.compareTo(costPerformanceIndex) == 0) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return asPercentage(budgetAtCompletion.divide(costPerformanceIndex));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -29,7 +29,9 @@ import static org.libreplan.business.i18n.I18nHelper._;
|
|||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
*/
|
||||
public enum SubcontractState {
|
||||
PENDING(_("Pending"), true), FAILED_SENT(_("Failed sent"), true), SUCCESS_SENT(
|
||||
PENDING_INITIAL_SEND(_("Pending initial send"), true), PENDING_UPDATE_DELIVERING_DATE(
|
||||
_("Pending update delivering date"), true), FAILED_SENT(
|
||||
_("Failed sent"), true), FAILED_UPDATE(_("Failed update"), true), SUCCESS_SENT(
|
||||
_("Success sent"), false);
|
||||
|
||||
private String name;
|
||||
|
|
|
|||
|
|
@ -22,11 +22,19 @@
|
|||
package org.libreplan.business.planner.entities;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.hibernate.validator.AssertTrue;
|
||||
import org.hibernate.validator.NotNull;
|
||||
import org.libreplan.business.common.BaseEntity;
|
||||
import org.libreplan.business.externalcompanies.entities.DeliverDateComparator;
|
||||
import org.libreplan.business.externalcompanies.entities.EndDateCommunication;
|
||||
import org.libreplan.business.externalcompanies.entities.EndDateCommunicationComparator;
|
||||
import org.libreplan.business.externalcompanies.entities.ExternalCompany;
|
||||
import org.libreplan.business.util.deepcopy.OnCopy;
|
||||
import org.libreplan.business.util.deepcopy.Strategy;
|
||||
|
|
@ -62,7 +70,10 @@ public class SubcontractedTaskData extends BaseEntity {
|
|||
result.labelsExported = subcontractedTaskData.labelsExported;
|
||||
result.materialAssignmentsExported = subcontractedTaskData.materialAssignmentsExported;
|
||||
result.hoursGroupsExported = subcontractedTaskData.hoursGroupsExported;
|
||||
|
||||
result.setState(subcontractedTaskData.getState());
|
||||
result.setRequiredDeliveringDates(subcontractedTaskData.getRequiredDeliveringDates());
|
||||
result.setEndDatesCommunicatedFromSubcontractor(subcontractedTaskData
|
||||
.getEndDatesCommunicatedFromSubcontractor());
|
||||
return create(result);
|
||||
}
|
||||
|
||||
|
|
@ -86,7 +97,15 @@ public class SubcontractedTaskData extends BaseEntity {
|
|||
private Boolean materialAssignmentsExported;
|
||||
private Boolean hoursGroupsExported;
|
||||
|
||||
private SubcontractState state = SubcontractState.PENDING;
|
||||
private SubcontractState state = SubcontractState.PENDING_INITIAL_SEND;
|
||||
|
||||
private final SortedSet<SubcontractorDeliverDate> requiredDeliveringDates = new TreeSet<SubcontractorDeliverDate>(
|
||||
new DeliverDateComparator());
|
||||
|
||||
private Set<SubcontractorCommunication> subcontractorCommunications = new HashSet<SubcontractorCommunication>();
|
||||
|
||||
private SortedSet<EndDateCommunication> endDatesCommunicatedFromSubcontractor = new TreeSet<EndDateCommunication>(
|
||||
new EndDateCommunicationComparator());
|
||||
|
||||
/**
|
||||
* Constructor for hibernate. Do not use!
|
||||
|
|
@ -219,6 +238,10 @@ public class SubcontractedTaskData extends BaseEntity {
|
|||
this.labelsExported = subcontratedTask.labelsExported;
|
||||
this.materialAssignmentsExported = subcontratedTask.materialAssignmentsExported;
|
||||
this.hoursGroupsExported = subcontratedTask.hoursGroupsExported;
|
||||
this.state = subcontratedTask.getState();
|
||||
this.setRequiredDeliveringDates(subcontratedTask.getRequiredDeliveringDates());
|
||||
this.setEndDatesCommunicatedFromSubcontractor(subcontratedTask
|
||||
.getEndDatesCommunicatedFromSubcontractor());
|
||||
}
|
||||
|
||||
@AssertTrue(message = "external company should be subcontractor")
|
||||
|
|
@ -248,4 +271,54 @@ public class SubcontractedTaskData extends BaseEntity {
|
|||
&& externalCompany.getInteractsWithApplications();
|
||||
}
|
||||
|
||||
}
|
||||
public void setRequiredDeliveringDates(
|
||||
SortedSet<SubcontractorDeliverDate> requiredDeliveringDates) {
|
||||
this.requiredDeliveringDates.clear();
|
||||
this.requiredDeliveringDates.addAll(requiredDeliveringDates);
|
||||
}
|
||||
|
||||
public SortedSet<SubcontractorDeliverDate> getRequiredDeliveringDates() {
|
||||
return Collections.unmodifiableSortedSet(this.requiredDeliveringDates);
|
||||
}
|
||||
|
||||
public void addRequiredDeliveringDates(
|
||||
SubcontractorDeliverDate subDeliverDate) {
|
||||
this.requiredDeliveringDates.add(subDeliverDate);
|
||||
}
|
||||
|
||||
public void removeRequiredDeliveringDates(
|
||||
SubcontractorDeliverDate subcontractorDeliverDate) {
|
||||
this.requiredDeliveringDates.remove(subcontractorDeliverDate);
|
||||
}
|
||||
|
||||
public void updateFirstRequiredDeliverDate(Date subcontractCommunicationDate){
|
||||
if(this.requiredDeliveringDates != null && !this.requiredDeliveringDates.isEmpty()){
|
||||
this.requiredDeliveringDates.first().setCommunicationDate(subcontractCommunicationDate);
|
||||
}
|
||||
}
|
||||
|
||||
public Date getLastRequiredDeliverDate() {
|
||||
if (this.requiredDeliveringDates != null
|
||||
&& !this.requiredDeliveringDates.isEmpty()) {
|
||||
return this.requiredDeliveringDates.first()
|
||||
.getSubcontractorDeliverDate();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setEndDatesCommunicatedFromSubcontractor(
|
||||
SortedSet<EndDateCommunication> endDatesCommunicatedFromSubcontractor) {
|
||||
this.endDatesCommunicatedFromSubcontractor = endDatesCommunicatedFromSubcontractor;
|
||||
}
|
||||
|
||||
public SortedSet<EndDateCommunication> getEndDatesCommunicatedFromSubcontractor() {
|
||||
return endDatesCommunicatedFromSubcontractor;
|
||||
}
|
||||
|
||||
public EndDateCommunication getLastEndDatesCommunicatedFromSubcontractor() {
|
||||
if (getEndDatesCommunicatedFromSubcontractor() != null) {
|
||||
return getEndDatesCommunicatedFromSubcontractor().first();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.planner.entities;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.validator.NotNull;
|
||||
import org.libreplan.business.common.BaseEntity;
|
||||
import org.libreplan.business.externalcompanies.entities.CommunicationType;
|
||||
import org.libreplan.business.qualityforms.entities.QualityFormItem;
|
||||
|
||||
/**
|
||||
* Entity {@link SubcontractorCommunication}.
|
||||
*
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia>
|
||||
*/
|
||||
public class SubcontractorCommunication extends BaseEntity {
|
||||
|
||||
private SubcontractedTaskData subcontractedTaskData;
|
||||
|
||||
private CommunicationType communicationType;
|
||||
|
||||
private Date communicationDate;
|
||||
|
||||
private Boolean reviewed = false;
|
||||
|
||||
private List<SubcontractorCommunicationValue> subcontractorCommunicationValues = new ArrayList<SubcontractorCommunicationValue>();
|
||||
|
||||
// Default constructor, needed by Hibernate
|
||||
protected SubcontractorCommunication() {
|
||||
|
||||
}
|
||||
|
||||
private SubcontractorCommunication ( SubcontractedTaskData subcontractedTaskData, CommunicationType communicationType, Date communicationDate, Boolean reviewed){
|
||||
this.setSubcontractedTaskData(subcontractedTaskData);
|
||||
this.setCommunicationType(communicationType);
|
||||
this.setCommunicationDate(communicationDate);
|
||||
this.setReviewed(reviewed);
|
||||
}
|
||||
|
||||
public static SubcontractorCommunication create(
|
||||
SubcontractedTaskData subcontractedTaskData,
|
||||
CommunicationType communicationType, Date communicationDate,
|
||||
Boolean reviewed) {
|
||||
return create(new SubcontractorCommunication(subcontractedTaskData,
|
||||
communicationType, communicationDate, reviewed));
|
||||
}
|
||||
|
||||
public static SubcontractorCommunication create() {
|
||||
return create(new SubcontractorCommunication());
|
||||
}
|
||||
|
||||
public void setSubcontractedTaskData(SubcontractedTaskData subcontractedTaskData) {
|
||||
this.subcontractedTaskData = subcontractedTaskData;
|
||||
}
|
||||
|
||||
@NotNull(message="subcontrated task data not specified")
|
||||
public SubcontractedTaskData getSubcontractedTaskData() {
|
||||
return subcontractedTaskData;
|
||||
}
|
||||
|
||||
public void setCommunicationType(CommunicationType communicationType) {
|
||||
this.communicationType = communicationType;
|
||||
}
|
||||
|
||||
public CommunicationType getCommunicationType() {
|
||||
return communicationType;
|
||||
}
|
||||
|
||||
public void setCommunicationDate(Date communicationDate) {
|
||||
this.communicationDate = communicationDate;
|
||||
}
|
||||
|
||||
public Date getCommunicationDate() {
|
||||
return communicationDate;
|
||||
}
|
||||
|
||||
public void setReviewed(Boolean reviewed) {
|
||||
this.reviewed = reviewed;
|
||||
}
|
||||
|
||||
public Boolean getReviewed() {
|
||||
return reviewed;
|
||||
}
|
||||
|
||||
public void setSubcontractorCommunicationValues(
|
||||
List<SubcontractorCommunicationValue> subcontractorCommunicationValues) {
|
||||
this.subcontractorCommunicationValues = subcontractorCommunicationValues;
|
||||
}
|
||||
|
||||
public List<SubcontractorCommunicationValue> getSubcontractorCommunicationValues() {
|
||||
return subcontractorCommunicationValues;
|
||||
}
|
||||
|
||||
public SubcontractorCommunicationValue getLastSubcontractorCommunicationValues(){
|
||||
if (subcontractorCommunicationValues.isEmpty()){
|
||||
return null;
|
||||
}
|
||||
return subcontractorCommunicationValues.get(subcontractorCommunicationValues.size()-1);
|
||||
}
|
||||
|
||||
public Date getLastSubcontractorCommunicationValueDate(){
|
||||
SubcontractorCommunicationValue value = getLastSubcontractorCommunicationValues();
|
||||
return (value == null) ? null : value.getDate();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.planner.entities;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import org.hibernate.validator.AssertTrue;
|
||||
import org.libreplan.business.INewObject;
|
||||
|
||||
/**
|
||||
* Entity to represent each {@SubcontractorCommunicationValue}.
|
||||
*
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia>
|
||||
*/
|
||||
public class SubcontractorCommunicationValue implements INewObject {
|
||||
|
||||
public static SubcontractorCommunicationValue create() {
|
||||
SubcontractorCommunicationValue subcontractorCommunicationValue = new SubcontractorCommunicationValue();
|
||||
subcontractorCommunicationValue.setNewObject(true);
|
||||
return subcontractorCommunicationValue;
|
||||
}
|
||||
|
||||
public static SubcontractorCommunicationValue create(Date date,
|
||||
BigDecimal progress) {
|
||||
SubcontractorCommunicationValue subcontractorCommunicationValue = new SubcontractorCommunicationValue(
|
||||
date, progress);
|
||||
subcontractorCommunicationValue.setNewObject(true);
|
||||
return subcontractorCommunicationValue;
|
||||
}
|
||||
|
||||
protected SubcontractorCommunicationValue() {
|
||||
|
||||
}
|
||||
|
||||
private SubcontractorCommunicationValue(Date date, BigDecimal progress) {
|
||||
this.setDate(date);
|
||||
this.setProgress(progress);
|
||||
}
|
||||
|
||||
private boolean newObject = false;
|
||||
|
||||
private Date date;
|
||||
|
||||
private BigDecimal progress;
|
||||
|
||||
public boolean isNewObject() {
|
||||
return newObject;
|
||||
}
|
||||
|
||||
private void setNewObject(boolean newObject) {
|
||||
this.newObject = newObject;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@AssertTrue(message = "progress should be greater than 0% and less than 100%")
|
||||
public boolean checkConstraintQualityFormItemPercentage() {
|
||||
if (getProgress() == null) {
|
||||
return true;
|
||||
}
|
||||
return ((getProgress().compareTo(new BigDecimal(100).setScale(2)) <= 0) && (getProgress()
|
||||
.compareTo(new BigDecimal(0).setScale(2)) > 0));
|
||||
}
|
||||
|
||||
public void setDate(Date date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setProgress(BigDecimal progress) {
|
||||
this.progress = progress;
|
||||
}
|
||||
|
||||
public BigDecimal getProgress() {
|
||||
return progress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String datetime = (date == null) ? "" : new SimpleDateFormat(
|
||||
"dd/MM/yyyy").format(date);
|
||||
String progress_reported = progress != null ? progress.toString() + "% - " : "";
|
||||
return progress_reported + datetime;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.planner.entities;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.libreplan.business.common.BaseEntity;
|
||||
import org.libreplan.business.externalcompanies.entities.DeliverDate;
|
||||
|
||||
/**
|
||||
* Entity {@link SubcontractorDeliverDate}.
|
||||
*
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia>
|
||||
*/
|
||||
public class SubcontractorDeliverDate extends BaseEntity implements DeliverDate{
|
||||
|
||||
private Date saveDate;
|
||||
|
||||
private Date subcontractorDeliverDate;
|
||||
|
||||
private Date communicationDate;
|
||||
|
||||
protected SubcontractorDeliverDate(){
|
||||
|
||||
}
|
||||
|
||||
private SubcontractorDeliverDate(Date saveDate, Date subcontractorDeliverDate, Date communicationDate){
|
||||
this.setSaveDate(saveDate);
|
||||
this.setSubcontractorDeliverDate(subcontractorDeliverDate);
|
||||
this.setCommunicationDate(communicationDate);
|
||||
}
|
||||
|
||||
public static SubcontractorDeliverDate create(){
|
||||
return create(new SubcontractorDeliverDate());
|
||||
}
|
||||
|
||||
public static SubcontractorDeliverDate create(Date saveDate, Date subcontractorDeliverDate, Date communicationDate){
|
||||
return create(new SubcontractorDeliverDate(saveDate, subcontractorDeliverDate, communicationDate));
|
||||
}
|
||||
|
||||
public void setSaveDate(Date saveDate) {
|
||||
this.saveDate = saveDate;
|
||||
}
|
||||
|
||||
public Date getSaveDate() {
|
||||
return saveDate;
|
||||
}
|
||||
|
||||
public void setSubcontractorDeliverDate(Date subcontractorDeliverDate) {
|
||||
this.subcontractorDeliverDate = subcontractorDeliverDate;
|
||||
}
|
||||
|
||||
public Date getSubcontractorDeliverDate() {
|
||||
return subcontractorDeliverDate;
|
||||
}
|
||||
|
||||
public void setCommunicationDate(Date communicationDate) {
|
||||
this.communicationDate = communicationDate;
|
||||
}
|
||||
|
||||
public Date getCommunicationDate() {
|
||||
return communicationDate;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -887,7 +887,7 @@ public class Task extends TaskElement implements ITaskPositionConstrained {
|
|||
public boolean isSubcontractedAndWasAlreadySent() {
|
||||
return (subcontractedTaskData != null)
|
||||
&& (!subcontractedTaskData.getState()
|
||||
.equals(SubcontractState.PENDING));
|
||||
.equals(SubcontractState.PENDING_INITIAL_SEND));
|
||||
}
|
||||
|
||||
public boolean hasSomeSatisfiedAllocation() {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
|
||||
* Desenvolvemento Tecnolóxico de Galicia
|
||||
* Copyright (C) 2010-2011 Igalia, S.L.
|
||||
* Copyright (C) 2010-2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
|
|
|
|||
|
|
@ -4,6 +4,134 @@
|
|||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
|
||||
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd">
|
||||
|
||||
<changeSet author="smontes" id="initial-database-creation-customer-comunication">
|
||||
<createTable tableName="customer_comunication">
|
||||
<column name="id" type="BIGINT">
|
||||
<constraints nullable="false" primaryKey="true" primaryKeyName="customer_comunication_pkey"/>
|
||||
</column>
|
||||
<column name="version" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="deadline" type="DATETIME"/>
|
||||
<column name="comunication_type" type="INTEGER"/>
|
||||
<column name="comunication_date" type="DATETIME"/>
|
||||
<column name="reviewed" type="BOOLEAN"/>
|
||||
<column name="order_id" type="BIGINT"/>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
<changeSet author="smontes" id="initial-database-creation-subcontractor-comunication">
|
||||
<createTable tableName="subcontractor_comunication">
|
||||
<column name="id" type="BIGINT">
|
||||
<constraints nullable="false" primaryKey="true" primaryKeyName="subcontractor_comunication_pkey"/>
|
||||
</column>
|
||||
<column name="version" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="comunication_type" type="INTEGER"/>
|
||||
<column name="comunication_date" type="DATETIME"/>
|
||||
<column name="reviewed" type="BOOLEAN"/>
|
||||
<column name="subcontracted_task_data" type="BIGINT"/>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
<changeSet author="smontes" id="initial-database-creation-subcontractor-comunication-value">
|
||||
<createTable tableName="subcontrator_comunication_values">
|
||||
<column name="subcontractor_comunication_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="date" type="DATETIME"/>
|
||||
<column name="progress" type="DECIMAL(19,2)"/>
|
||||
<column name="idx" type="INTEGER">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
|
||||
</changeSet>
|
||||
<changeSet id="rename-table-customer_comunication-to-customer_communication" author="smontes">
|
||||
<comment>Rename table customer_comunication to customer_communication</comment>
|
||||
<renameTable oldTableName="customer_comunication" newTableName="customer_communication" />
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="rename-column-comunication_type-to-communication_type" author="smontes">
|
||||
<comment>Rename column comunication_type to communication_type</comment>
|
||||
<renameColumn tableName="customer_communication" oldColumnName="comunication_type"
|
||||
newColumnName="communication_type"/>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="rename-column-comunication_date-to-communication_date" author="smontes">
|
||||
<comment>Rename column comunication_date to communication_date</comment>
|
||||
<renameColumn tableName="customer_communication" oldColumnName="comunication_date"
|
||||
newColumnName="communication_date"/>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="rename-table-subcontractor_comunication" author="smontes">
|
||||
<comment>Rename table subcontractor_comunication to subcontractor_communication</comment>
|
||||
<renameTable oldTableName="subcontractor_comunication" newTableName="subcontractor_communication" />
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="rename-column-comunication_type-on-subcontractor-communication" author="smontes">
|
||||
<comment>Rename column comunication_type to communication_type</comment>
|
||||
<renameColumn tableName="subcontractor_communication" oldColumnName="comunication_type"
|
||||
newColumnName="communication_type"/>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="rename-column-comunication_date-on-subcontractor-communication" author="smontes">
|
||||
<comment>Rename column comunication_date to communication_date</comment>
|
||||
<renameColumn tableName="subcontractor_communication" oldColumnName="comunication_date"
|
||||
newColumnName="communication_date"/>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="rename-table-subcontractor_comunication_values" author="smontes">
|
||||
<comment>Rename table subcontractor_comunication_values to subcontractor_communication_values</comment>
|
||||
<renameTable oldTableName="subcontrator_comunication_values" newTableName="subcontractor_communication_values" />
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="rename-column-subcontractor_comunication_id" author="smontes">
|
||||
<comment>Rename column subcontractor_comunication_id</comment>
|
||||
<renameColumn tableName="subcontractor_communication_values" oldColumnName="subcontractor_comunication_id"
|
||||
newColumnName="subcontractor_communication_id"/>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="smontes" id="creation-deadline-communication">
|
||||
<createTable tableName="deadline_communication">
|
||||
<column name="id" type="BIGINT">
|
||||
<constraints nullable="false" primaryKey="true" primaryKeyName="deadline_comunication_pkey"/>
|
||||
</column>
|
||||
<column name="version" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="save_date" type="DATETIME"/>
|
||||
<column name="deliver_date" type="DATETIME"/>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="add-delivering-date-column-to-order-entity" author="smontes">
|
||||
<comment>Add new delivering date column to order</comment>
|
||||
<addColumn tableName="deadline_communication">
|
||||
<column name="order_id" type="BIGINT"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="smontes" id="creation-subcontractor-deliver-date">
|
||||
<createTable tableName="subcontractor_deliver_date">
|
||||
<column name="id" type="BIGINT">
|
||||
<constraints nullable="false" primaryKey="true" primaryKeyName="subcontrator_deliver_date_pkey"/>
|
||||
</column>
|
||||
<column name="version" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="save_date" type="DATETIME"/>
|
||||
<column name="subcontractor_deliver_date" type="DATETIME"/>
|
||||
<column name="communication_date" type="DATETIME" />
|
||||
</createTable>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="smontes" id="add-subcontracted-task-data">
|
||||
<comment>Add the column subcontracted_task_id to maintain the relation</comment>
|
||||
<addColumn tableName="subcontractor_deliver_date">
|
||||
<column name="subcontracted_task_data_id" type="BIGINT"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="add-task_end_date_effort_duration-to-consolidated_value" author="mrego">
|
||||
<comment>
|
||||
taskEndDate attribute in class ConsolidatedValue has been changed to IntraDayDate.
|
||||
|
|
@ -70,6 +198,33 @@
|
|||
<modifyDataType tableName="order_element_template" columnName="description" newDataType="TEXT" />
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="smontes" id="database-creation-table-end-date-communication-to-customer">
|
||||
<createTable tableName="end_date_communication_to_customer">
|
||||
<column name="id" type="BIGINT">
|
||||
<constraints nullable="false" primaryKey="true" primaryKeyName="end_date_communication_to_customer_pkey"/>
|
||||
</column>
|
||||
<column name="version" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="save_date" type="DATETIME"/>
|
||||
<column name="end_date" type="DATETIME"/>
|
||||
<column name="communication_date" type="DATETIME"/>
|
||||
<column name="order_id" type="BIGINT"/>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="subcontracted-date-id-column-to-end-date-communication" author="smontes">
|
||||
<comment>Add subcontracted date id column to end date communication to customer</comment>
|
||||
<addColumn tableName="end_date_communication_to_customer">
|
||||
<column name="subcontracted_task_data_id" type="BIGINT"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="rename-table-end_date_comunication-to-customer" author="smontes">
|
||||
<comment>Rename table to end_date_communication</comment>
|
||||
<renameTable oldTableName="end_date_communication_to_customer" newTableName="end_date_communication" />
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="change-column-description-in-to-text-in-mysql"
|
||||
author="mrego" dbms="mysql">
|
||||
<comment>
|
||||
|
|
|
|||
|
|
@ -10,5 +10,4 @@
|
|||
<include file="src/main/resources/db.changelog-1.0.xml"/>
|
||||
<include file="src/main/resources/db.changelog-1.1.xml"/>
|
||||
<include file="src/main/resources/db.changelog-1.2.xml"/>
|
||||
|
||||
</databaseChangeLog>
|
||||
|
|
|
|||
|
|
@ -81,6 +81,9 @@
|
|||
<value>
|
||||
org/libreplan/business/planner/entities/AdvanceConsolidations.hbm.xml
|
||||
</value>
|
||||
<value>
|
||||
org/libreplan/business/planner/entities/SubcontractorCommunication.hbm.xml
|
||||
</value>
|
||||
<value>
|
||||
org/libreplan/business/scenarios/entities/Scenarios.hbm.xml
|
||||
</value>
|
||||
|
|
|
|||
|
|
@ -33,4 +33,51 @@
|
|||
column="company_user" />
|
||||
</class>
|
||||
|
||||
<!-- CustomerCommunication -->
|
||||
<class name="CustomerCommunication" table="customer_communication">
|
||||
<id name="id" type="long" access="property">
|
||||
<generator class="hilo">
|
||||
<param name="max_lo">100</param>
|
||||
</generator>
|
||||
</id>
|
||||
<version name="version" access="property" type="long" />
|
||||
|
||||
<property name="deadline" access="field"/>
|
||||
<property name="communicationType" access="field" column="communication_type">
|
||||
<type name="org.hibernate.type.EnumType">
|
||||
<param name="enumClass">
|
||||
org.libreplan.business.externalcompanies.entities.CommunicationType
|
||||
</param>
|
||||
</type>
|
||||
</property>
|
||||
<property name="communicationDate" access="field" column="communication_date" />
|
||||
<property name="reviewed" access="field" column="reviewed" />
|
||||
<many-to-one name="order" class="org.libreplan.business.orders.entities.Order" column="order_id" />
|
||||
</class>
|
||||
|
||||
<!-- DeadlineCommunication -->
|
||||
<class name="DeadlineCommunication" table="deadline_communication">
|
||||
<id name="id" type="long" access="property">
|
||||
<generator class="hilo">
|
||||
<param name="max_lo">100</param>
|
||||
</generator>
|
||||
</id>
|
||||
<version name="version" access="property" type="long" />
|
||||
|
||||
<property name="saveDate" access="field" column="save_date"/>
|
||||
<property name="deliverDate" access="field" column="deliver_date" />
|
||||
</class>
|
||||
|
||||
<!-- EndDateCommunication -->
|
||||
<class name="EndDateCommunication" table="end_date_communication">
|
||||
<id name="id" type="long" access="property">
|
||||
<generator class="hilo">
|
||||
<param name="max_lo">100</param>
|
||||
</generator>
|
||||
</id>
|
||||
<version name="version" access="property" type="long" />
|
||||
<property name="endDate" access="field" column="end_date"/>
|
||||
<property name="saveDate" access="field" column="save_date"/>
|
||||
<property name="communicationDate" access="field" column="communication_date" />
|
||||
</class>
|
||||
</hibernate-mapping>
|
||||
|
|
|
|||
|
|
@ -144,6 +144,23 @@
|
|||
<many-to-many column="order_version_id"
|
||||
class="org.libreplan.business.scenarios.entities.OrderVersion"/>
|
||||
</map>
|
||||
|
||||
<set name="customerCommunications" cascade="delete-orphan" inverse="true" >
|
||||
<key column="order_id" />
|
||||
<one-to-many class="org.libreplan.business.externalcompanies.entities.CustomerCommunication" />
|
||||
</set>
|
||||
|
||||
<set name="deliveringDates" inverse="false" cascade="all,delete-orphan" access="field"
|
||||
sort="org.libreplan.business.externalcompanies.entities.DeliverDateComparator">
|
||||
<key column="order_id" />
|
||||
<one-to-many class="org.libreplan.business.externalcompanies.entities.DeadlineCommunication" />
|
||||
</set>
|
||||
|
||||
<set name="endDateCommunicationToCustomer" inverse="false" cascade="all,delete-orphan" access="field"
|
||||
sort="org.libreplan.business.externalcompanies.entities.EndDateCommunicationComparator">
|
||||
<key column="order_id" />
|
||||
<one-to-many class="org.libreplan.business.externalcompanies.entities.EndDateCommunication" />
|
||||
</set>
|
||||
</joined-subclass>
|
||||
|
||||
</joined-subclass>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
|
||||
<hibernate-mapping package="org.libreplan.business.planner.entities"
|
||||
default-access="field">
|
||||
|
||||
<!-- SubcontractorCommunication -->
|
||||
<class name="SubcontractorCommunication" table="subcontractor_communication">
|
||||
<id name="id" type="long" access="property">
|
||||
<generator class="hilo">
|
||||
<param name="max_lo">100</param>
|
||||
</generator>
|
||||
</id>
|
||||
<version name="version" access="property" type="long" />
|
||||
<property name="communicationType" access="field"
|
||||
column="communication_type">
|
||||
<type name="org.hibernate.type.EnumType">
|
||||
<param name="enumClass">
|
||||
org.libreplan.business.externalcompanies.entities.CommunicationType
|
||||
</param>
|
||||
</type>
|
||||
</property>
|
||||
<property name="communicationDate" access="field"
|
||||
column="communication_date" />
|
||||
<property name="reviewed" access="field" column="reviewed" />
|
||||
<many-to-one name="subcontractedTaskData"
|
||||
class="org.libreplan.business.planner.entities.SubcontractedTaskData"
|
||||
column="subcontracted_task_data" />
|
||||
|
||||
<list name="subcontractorCommunicationValues" table="subcontractor_communication_values">
|
||||
<key column="subcontractor_communication_id" />
|
||||
<index column="idx" />
|
||||
<composite-element
|
||||
class="org.libreplan.business.planner.entities.SubcontractorCommunicationValue">
|
||||
<property name="date" access="field" />
|
||||
<property name="progress" access="field" />
|
||||
</composite-element>
|
||||
</list>
|
||||
</class>
|
||||
|
||||
<class name="SubcontractorDeliverDate" table="subcontractor_deliver_date">
|
||||
<id name="id" type="long" access="property">
|
||||
<generator class="hilo">
|
||||
<param name="max_lo">100</param>
|
||||
</generator>
|
||||
</id>
|
||||
<version name="version" access="property" type="long" />
|
||||
<property name="saveDate" access="field" column="save_date" />
|
||||
<property name="subcontractorDeliverDate" access="field" column="subcontractor_deliver_date" />
|
||||
<property name="communicationDate" access="field" column="communication_date" />
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
||||
|
|
@ -213,6 +213,22 @@
|
|||
</type>
|
||||
</property>
|
||||
|
||||
<set name="requiredDeliveringDates" inverse="false" cascade="all-delete-orphan" access="field"
|
||||
sort="org.libreplan.business.externalcompanies.entities.DeliverDateComparator">
|
||||
<key column="subcontracted_task_data_id" />
|
||||
<one-to-many class="org.libreplan.business.planner.entities.SubcontractorDeliverDate" />
|
||||
</set>
|
||||
|
||||
<set name="subcontractorCommunications" inverse="true" cascade="delete" access="field">
|
||||
<key column="subcontracted_task_data" />
|
||||
<one-to-many class="org.libreplan.business.planner.entities.SubcontractorCommunication" />
|
||||
</set>
|
||||
|
||||
<set name="endDatesCommunicatedFromSubcontractor" inverse="false" cascade="all-delete-orphan" access="field"
|
||||
sort="org.libreplan.business.externalcompanies.entities.EndDateCommunicationComparator">
|
||||
<key column="subcontracted_task_data_id" />
|
||||
<one-to-many class="org.libreplan.business.externalcompanies.entities.EndDateCommunication" />
|
||||
</set>
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.test.externalcompanies.daos;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.libreplan.business.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_FILE;
|
||||
import static org.libreplan.business.test.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_TEST_FILE;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.libreplan.business.calendars.daos.IBaseCalendarDAO;
|
||||
import org.libreplan.business.calendars.entities.BaseCalendar;
|
||||
import org.libreplan.business.common.IAdHocTransactionService;
|
||||
import org.libreplan.business.common.IOnTransaction;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.business.externalcompanies.daos.ICustomerCommunicationDAO;
|
||||
import org.libreplan.business.externalcompanies.entities.CustomerCommunication;
|
||||
import org.libreplan.business.externalcompanies.entities.ExternalCompany;
|
||||
import org.libreplan.business.orders.daos.IOrderDAO;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.scenarios.IScenarioManager;
|
||||
import org.libreplan.business.test.calendars.entities.BaseCalendarTest;
|
||||
import org.libreplan.business.workreports.entities.WorkReportLine;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for {@link CustomerCommunication}
|
||||
*
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = { BUSINESS_SPRING_CONFIG_FILE,
|
||||
BUSINESS_SPRING_CONFIG_TEST_FILE })
|
||||
@Transactional
|
||||
public class CustomerCommunicationDAOTest {
|
||||
|
||||
@Autowired
|
||||
ICustomerCommunicationDAO customerCommunicationDAO;
|
||||
|
||||
@Autowired
|
||||
IOrderDAO orderDAO;
|
||||
|
||||
@Autowired
|
||||
private IBaseCalendarDAO calendarDAO;
|
||||
|
||||
public Order createValidOrder(String name) {
|
||||
Order order = Order.create();
|
||||
order.setName(name);
|
||||
order.setCode(UUID.randomUUID().toString());
|
||||
order.setInitDate(new Date());
|
||||
BaseCalendar basicCalendar = BaseCalendarTest.createBasicCalendar();
|
||||
calendarDAO.save(basicCalendar);
|
||||
order.setCalendar(basicCalendar);
|
||||
orderDAO.save(order);
|
||||
return order;
|
||||
}
|
||||
|
||||
private Date givenDeadLine(int months) {
|
||||
LocalDate date = new LocalDate();
|
||||
date.plusMonths(months);
|
||||
return date.toDateTimeAtStartOfDay().toDate();
|
||||
}
|
||||
|
||||
public CustomerCommunication createValidCustomerCommunication() {
|
||||
Order order = createValidOrder("Order A");
|
||||
CustomerCommunication customerCommunication = CustomerCommunication
|
||||
.createTodayNewProject(givenDeadLine(2));
|
||||
customerCommunication.setOrder(order);
|
||||
return customerCommunication;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderDAOInSpringContainer() {
|
||||
assertNotNull(orderDAO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomerCommunicationDAOInSpringContainer() {
|
||||
assertNotNull(customerCommunicationDAO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveCustomerCommunication() {
|
||||
CustomerCommunication customerCommunication = createValidCustomerCommunication();
|
||||
customerCommunicationDAO.save(customerCommunication);
|
||||
assertTrue(customerCommunication.getId() != null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveCustomerCommunication()
|
||||
throws InstanceNotFoundException {
|
||||
CustomerCommunication customerCommunication = createValidCustomerCommunication();
|
||||
customerCommunicationDAO.save(customerCommunication);
|
||||
assertTrue(customerCommunication.getId() != null);
|
||||
customerCommunicationDAO.remove(customerCommunication.getId());
|
||||
assertFalse(customerCommunicationDAO
|
||||
.exists(customerCommunication.getId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveCustomerCommunicationWithoutOrder()
|
||||
throws InstanceNotFoundException {
|
||||
CustomerCommunication customerCommunication = createValidCustomerCommunication();
|
||||
customerCommunication.setOrder(null);
|
||||
try {
|
||||
customerCommunicationDAO.save(customerCommunication);
|
||||
fail("It should throw an exception");
|
||||
} catch (ValidationException e) {
|
||||
// Ok
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -20,12 +20,17 @@
|
|||
package org.libreplan.business.test.orders.daos;
|
||||
|
||||
import static junit.framework.Assert.assertNotNull;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.libreplan.business.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_FILE;
|
||||
import static org.libreplan.business.test.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_TEST_FILE;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
|
@ -34,6 +39,7 @@ import org.libreplan.business.calendars.entities.BaseCalendar;
|
|||
import org.libreplan.business.common.IAdHocTransactionService;
|
||||
import org.libreplan.business.common.IOnTransaction;
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.business.externalcompanies.entities.DeadlineCommunication;
|
||||
import org.libreplan.business.orders.daos.IOrderDAO;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.scenarios.IScenarioManager;
|
||||
|
|
@ -102,6 +108,56 @@ public class OrderDAOTest {
|
|||
return order;
|
||||
}
|
||||
|
||||
private Order createValidOrderWithDeadlineCommunications(String name) {
|
||||
Order order = createValidOrder(name);
|
||||
|
||||
//create two deadline communications
|
||||
Date date1 = (new Date());
|
||||
Date date2 = (new LocalDate(date1).plusDays(3)).toDateTimeAtStartOfDay().toDate();
|
||||
|
||||
DeadlineCommunication deadlineCommunication1 = DeadlineCommunication.create(date1, null);
|
||||
DeadlineCommunication deadlineCommunication2 = DeadlineCommunication.create(date2, null);
|
||||
|
||||
order.getDeliveringDates().add(deadlineCommunication1);
|
||||
order.getDeliveringDates().add(deadlineCommunication2);
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveOrdersWithDeliveringDates() {
|
||||
Order order = createValidOrderWithDeadlineCommunications("test");
|
||||
orderDAO.save(order);
|
||||
orderDAO.flush();
|
||||
|
||||
assertThat(order.getDeliveringDates().size(), equalTo(2));
|
||||
|
||||
DeadlineCommunication dcFirst = order.getDeliveringDates().first();
|
||||
DeadlineCommunication dcLast = order.getDeliveringDates().last();
|
||||
|
||||
assertTrue(dcFirst.getSaveDate().after(dcLast.getSaveDate()));
|
||||
|
||||
|
||||
//A new DeadlineCommunication is placed between the existing communications.
|
||||
Date date = (new LocalDate(dcLast.getSaveDate()).plusDays(2)).toDateTimeAtStartOfDay().toDate();
|
||||
DeadlineCommunication deadlineCommunication = DeadlineCommunication.create(date, null);
|
||||
order.getDeliveringDates().add(deadlineCommunication);
|
||||
|
||||
orderDAO.save(order);
|
||||
orderDAO.flush();
|
||||
|
||||
assertThat(order.getDeliveringDates().size(), equalTo(3));
|
||||
|
||||
dcFirst = order.getDeliveringDates().first();
|
||||
dcLast = order.getDeliveringDates().last();
|
||||
DeadlineCommunication new_dc = (DeadlineCommunication) order.getDeliveringDates().toArray()[1];
|
||||
|
||||
assertTrue(dcFirst.getSaveDate().after(dcLast.getSaveDate()));
|
||||
assertTrue(dcFirst.getSaveDate().after(new_dc.getSaveDate()));
|
||||
assertFalse(dcLast.equals(new_dc));
|
||||
assertTrue(dcLast.getSaveDate().before(new_dc.getSaveDate()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveTwoOrdersWithDifferentNames() {
|
||||
transactionService.runOnAnotherTransaction(new IOnTransaction<Void>() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,258 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.test.planner.daos;
|
||||
|
||||
import static junit.framework.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.libreplan.business.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_FILE;
|
||||
import static org.libreplan.business.test.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_TEST_FILE;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.libreplan.business.calendars.daos.IBaseCalendarDAO;
|
||||
import org.libreplan.business.calendars.entities.BaseCalendar;
|
||||
import org.libreplan.business.common.daos.IConfigurationDAO;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.business.externalcompanies.daos.IExternalCompanyDAO;
|
||||
import org.libreplan.business.externalcompanies.entities.CommunicationType;
|
||||
import org.libreplan.business.externalcompanies.entities.ExternalCompany;
|
||||
import org.libreplan.business.orders.daos.IOrderDAO;
|
||||
import org.libreplan.business.orders.entities.HoursGroup;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderLine;
|
||||
import org.libreplan.business.orders.entities.SchedulingDataForVersion;
|
||||
import org.libreplan.business.orders.entities.TaskSource;
|
||||
import org.libreplan.business.orders.entities.TaskSource.TaskSourceSynchronization;
|
||||
import org.libreplan.business.planner.daos.ISubcontractedTaskDataDAO;
|
||||
import org.libreplan.business.planner.daos.ISubcontractorCommunicationDAO;
|
||||
import org.libreplan.business.planner.daos.ITaskElementDAO;
|
||||
import org.libreplan.business.planner.daos.ITaskSourceDAO;
|
||||
import org.libreplan.business.planner.entities.SubcontractedTaskData;
|
||||
import org.libreplan.business.planner.entities.SubcontractorCommunication;
|
||||
import org.libreplan.business.planner.entities.Task;
|
||||
import org.libreplan.business.scenarios.IScenarioManager;
|
||||
import org.libreplan.business.scenarios.bootstrap.IScenariosBootstrap;
|
||||
import org.libreplan.business.scenarios.entities.OrderVersion;
|
||||
import org.libreplan.business.test.calendars.entities.BaseCalendarTest;
|
||||
import org.libreplan.business.test.externalcompanies.daos.ExternalCompanyDAOTest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Tests for {@link SubcontractorCommunication}
|
||||
*
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = { BUSINESS_SPRING_CONFIG_FILE,
|
||||
BUSINESS_SPRING_CONFIG_TEST_FILE })
|
||||
@Transactional
|
||||
public class SubcontractorCommunicationDAOTest {
|
||||
|
||||
@Autowired
|
||||
ISubcontractorCommunicationDAO subcontractorCommunicationDAO;
|
||||
|
||||
@Autowired
|
||||
ISubcontractedTaskDataDAO subcontractedTaskDataDAO;
|
||||
|
||||
@Autowired
|
||||
IExternalCompanyDAO externalCompanyDAO;
|
||||
|
||||
@Autowired
|
||||
private ITaskElementDAO taskElementDAO;
|
||||
|
||||
@Autowired
|
||||
private IOrderDAO orderDAO;
|
||||
|
||||
@Autowired
|
||||
private ITaskSourceDAO taskSourceDAO;
|
||||
|
||||
@Autowired
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
@Autowired
|
||||
private IConfigurationDAO configurationDAO;
|
||||
|
||||
@Autowired
|
||||
private IScenarioManager scenarioManager;
|
||||
|
||||
@Autowired
|
||||
private IBaseCalendarDAO calendarDAO;
|
||||
|
||||
@Autowired
|
||||
private IScenariosBootstrap scenariosBootstrap;
|
||||
|
||||
@Before
|
||||
public void loadRequiredData() {
|
||||
scenariosBootstrap.loadRequiredData();
|
||||
}
|
||||
|
||||
private HoursGroup associatedHoursGroup;
|
||||
|
||||
private ExternalCompany getSubcontractorExternalCompanySaved() {
|
||||
ExternalCompany externalCompany = ExternalCompanyDAOTest
|
||||
.createValidExternalCompany();
|
||||
externalCompany.setSubcontractor(true);
|
||||
|
||||
externalCompanyDAO.save(externalCompany);
|
||||
externalCompanyDAO.flush();
|
||||
sessionFactory.getCurrentSession().evict(externalCompany);
|
||||
|
||||
externalCompany.dontPoseAsTransientObjectAnymore();
|
||||
|
||||
return externalCompany;
|
||||
}
|
||||
|
||||
private OrderLine createOrderLine() {
|
||||
OrderLine orderLine = OrderLine.create();
|
||||
orderLine.setName("bla");
|
||||
orderLine.setCode("code-" + UUID.randomUUID());
|
||||
HoursGroup hoursGroup = new HoursGroup();
|
||||
hoursGroup.setCode("hours-group-code-" + UUID.randomUUID());
|
||||
orderLine.addHoursGroup(hoursGroup);
|
||||
Order order = Order.create();
|
||||
OrderVersion orderVersion = ResourceAllocationDAOTest
|
||||
.setupVersionUsing(scenarioManager, order);
|
||||
order.setName("bla-" + UUID.randomUUID());
|
||||
order.setInitDate(new Date());
|
||||
order.setCode("code-" + UUID.randomUUID());
|
||||
order.useSchedulingDataFor(orderVersion);
|
||||
order.add(orderLine);
|
||||
|
||||
//add a basic calendar
|
||||
BaseCalendar basicCalendar = BaseCalendarTest.createBasicCalendar();
|
||||
calendarDAO.save(basicCalendar);
|
||||
order.setCalendar(basicCalendar);
|
||||
|
||||
try {
|
||||
orderDAO.save(order);
|
||||
sessionFactory.getCurrentSession().flush();
|
||||
} catch (ValidationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return orderLine;
|
||||
}
|
||||
|
||||
private Task createValidTask() {
|
||||
associatedHoursGroup = new HoursGroup();
|
||||
associatedHoursGroup.setCode("hours-group-code-" + UUID.randomUUID());
|
||||
OrderLine orderLine = createOrderLine();
|
||||
orderLine.addHoursGroup(associatedHoursGroup);
|
||||
OrderVersion orderVersion = ResourceAllocationDAOTest
|
||||
.setupVersionUsing(scenarioManager,
|
||||
orderLine.getOrder());
|
||||
orderLine.useSchedulingDataFor(orderVersion);
|
||||
SchedulingDataForVersion schedulingDataForVersion = orderLine
|
||||
.getCurrentSchedulingDataForVersion();
|
||||
TaskSource taskSource = TaskSource.create(schedulingDataForVersion,
|
||||
Arrays.asList(associatedHoursGroup));
|
||||
TaskSourceSynchronization mustAdd = TaskSource.mustAdd(taskSource);
|
||||
mustAdd.apply(TaskSource.persistTaskSources(taskSourceDAO));
|
||||
Task task = (Task) taskSource.getTask();
|
||||
return task;
|
||||
}
|
||||
|
||||
public SubcontractedTaskData createValidSubcontractedTaskData(String name) {
|
||||
Task task = createValidTask();
|
||||
SubcontractedTaskData subcontractedTaskData = SubcontractedTaskData
|
||||
.create(task);
|
||||
subcontractedTaskData.setExternalCompany(getSubcontractorExternalCompanySaved());
|
||||
|
||||
task.setSubcontractedTaskData(subcontractedTaskData);
|
||||
taskElementDAO.save(task);
|
||||
taskElementDAO.flush();
|
||||
sessionFactory.getCurrentSession().evict(task);
|
||||
sessionFactory.getCurrentSession().evict(subcontractedTaskData);
|
||||
|
||||
subcontractedTaskDataDAO.save(subcontractedTaskData);
|
||||
return subcontractedTaskData;
|
||||
}
|
||||
|
||||
public SubcontractorCommunication createValidSubcontractorCommunication(){
|
||||
SubcontractedTaskData subcontractedTaskData = createValidSubcontractedTaskData("Task A");
|
||||
Date communicationDate = new Date();
|
||||
SubcontractorCommunication subcontractorCommunication = SubcontractorCommunication
|
||||
.create(subcontractedTaskData, CommunicationType.NEW_PROJECT,
|
||||
communicationDate, false);
|
||||
return subcontractorCommunication;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubcontractorCommunicationDAOInSpringContainer() {
|
||||
assertNotNull(subcontractorCommunicationDAO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveSubcontractorCommunication() {
|
||||
SubcontractorCommunication subcontractorCommunication = createValidSubcontractorCommunication();
|
||||
subcontractorCommunicationDAO.save(subcontractorCommunication);
|
||||
assertTrue(subcontractorCommunication.getId() != null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveSubcontractorCommunication()
|
||||
throws InstanceNotFoundException {
|
||||
SubcontractorCommunication subcontractorCommunication = createValidSubcontractorCommunication();
|
||||
subcontractorCommunicationDAO.save(subcontractorCommunication);
|
||||
|
||||
assertTrue(subcontractorCommunication.getId() != null);
|
||||
Long idSubcontratecTaskData = subcontractorCommunication
|
||||
.getSubcontractedTaskData().getId();
|
||||
Long idCommunication = subcontractorCommunication.getId();
|
||||
|
||||
subcontractorCommunicationDAO
|
||||
.remove(subcontractorCommunication.getId());
|
||||
try{
|
||||
subcontractorCommunicationDAO.findExistingEntity(idCommunication);
|
||||
fail("error");
|
||||
}catch(RuntimeException e){
|
||||
//ok
|
||||
}
|
||||
try{
|
||||
subcontractedTaskDataDAO.findExistingEntity(idSubcontratecTaskData);
|
||||
}catch(RuntimeException e){
|
||||
fail("error");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveSubcontractorCommunicationWithoutSubcontratedTaskData()
|
||||
throws InstanceNotFoundException {
|
||||
SubcontractorCommunication subcontractorCommunication = createValidSubcontractorCommunication();
|
||||
subcontractorCommunication.setSubcontractedTaskData(null);
|
||||
try {
|
||||
subcontractorCommunicationDAO.save(subcontractorCommunication);
|
||||
fail("It should throw an exception");
|
||||
} catch (ValidationException e) {
|
||||
// Ok
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -87,6 +87,9 @@
|
|||
<value>
|
||||
org/libreplan/business/planner/entities/AdvanceConsolidations.hbm.xml
|
||||
</value>
|
||||
<value>
|
||||
org/libreplan/business/planner/entities/SubcontractorCommunication.hbm.xml
|
||||
</value>
|
||||
<value>
|
||||
org/libreplan/business/scenarios/entities/Scenarios.hbm.xml
|
||||
</value>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
* Desenvolvemento Tecnolóxico de Galicia
|
||||
* Copyright (C) 2010-2011 Igalia, S.L.
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
|
|
@ -307,9 +309,11 @@ public class CustomMenuController extends Div implements IMenuItemsRegister {
|
|||
if (SecurityUtils.isUserInRole(UserRole.ROLE_ADMINISTRATION)) {
|
||||
resourcesItems.add(subItem(_("Companies"), "/externalcompanies/externalcompanies.zul",""));
|
||||
}
|
||||
resourcesItems.add(subItem(_("Subcontracting"), "/subcontract/subcontractedTasks.zul", "",
|
||||
subItem(_("Subcontracted Tasks"), "/subcontract/subcontractedTasks.zul", ""),
|
||||
subItem(_("Report Progress"), "/subcontract/reportAdvances.zul", "")));
|
||||
resourcesItems.add(subItem(_("Communications"), "/subcontract/subcontractedTasks.zul", "",
|
||||
subItem(_("Send to subcontractors"), "/subcontract/subcontractedTasks.zul", ""),
|
||||
subItem(_("Received from subcontractors"), "/subcontract/subcontractorCommunications.zul",""),
|
||||
subItem(_("Send to customers"), "/subcontract/reportAdvances.zul", ""),
|
||||
subItem(_("Received from customers"), "/subcontract/customerCommunications.zul","")));
|
||||
topItem(_("Resources"), "/resources/worker/worker.zul", "", resourcesItems);
|
||||
|
||||
if (isScenariosVisible()) {
|
||||
|
|
|
|||
|
|
@ -482,7 +482,11 @@ public class TemplateModel implements ITemplateModel {
|
|||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public boolean isUserAdmin() {
|
||||
return UserUtil.getUserFromSession().isAdministrator();
|
||||
User user = UserUtil.getUserFromSession();
|
||||
if(user == null) {
|
||||
return false;
|
||||
}
|
||||
return user.isAdministrator();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -661,6 +661,7 @@ public class Util {
|
|||
* {@link Configuration} object.
|
||||
*/
|
||||
public static String addCurrencySymbol(BigDecimal value) {
|
||||
value = (value == null ? BigDecimal.ZERO : value);
|
||||
DecimalFormat decimalFormat = (DecimalFormat) DecimalFormat
|
||||
.getInstance();
|
||||
decimalFormat.applyPattern(getMoneyFormat());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.web.common.converters;
|
||||
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.planner.daos.ITaskElementDAO;
|
||||
import org.libreplan.business.planner.entities.Task;
|
||||
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;
|
||||
|
||||
/**
|
||||
* A {@link IConverter} for {@link Task} <br />
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
@Component
|
||||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
public class TaskConverter implements IConverter<Task> {
|
||||
|
||||
@Autowired
|
||||
private ITaskElementDAO taskDAO;
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Task asObject(String stringRepresentation) {
|
||||
try {
|
||||
return (Task) taskDAO.find(Long.parseLong(stringRepresentation));
|
||||
} catch (InstanceNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asString(Task entity) {
|
||||
return entity.getId() + "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asStringUngeneric(Object entity) {
|
||||
return asString((Task) entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Task> getType() {
|
||||
return Task.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 Wireless Galicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.web.common.converters;
|
||||
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.planner.daos.ITaskElementDAO;
|
||||
import org.libreplan.business.planner.entities.TaskElement;
|
||||
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;
|
||||
|
||||
/**
|
||||
* A {@link IConverter} for {@link TaskElement} <br />
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
|
||||
@Component
|
||||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
public class TaskElementConverter implements IConverter<TaskElement> {
|
||||
|
||||
@Autowired
|
||||
private ITaskElementDAO taskElementDAO;
|
||||
|
||||
@Override
|
||||
public String asString(TaskElement entity) {
|
||||
return entity.getId() + "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<TaskElement> getType() {
|
||||
return TaskElement.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asStringUngeneric(Object entity) {
|
||||
return asString((TaskElement) entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public TaskElement asObject(String stringRepresentation) {
|
||||
long id = Long.parseLong(stringRepresentation);
|
||||
try {
|
||||
return taskElementDAO.find(id);
|
||||
} catch (InstanceNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2012 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.web.common.typeconverters;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zkplus.databind.TypeConverter;
|
||||
|
||||
/**
|
||||
* Converter for the type java.util.Date with an hour minute precision
|
||||
*
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*
|
||||
*/
|
||||
public class DateTimeConverter implements TypeConverter {
|
||||
|
||||
@Override
|
||||
public Object coerceToBean(Object arg0, Component arg1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object coerceToUi(Object object, Component component) {
|
||||
return object != null ? (new SimpleDateFormat("dd/MM/yyyy HH:mm"))
|
||||
.format((Date) object) : new String("");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -20,15 +20,10 @@
|
|||
package org.libreplan.web.dashboard;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.planner.entities.ICostCalculator;
|
||||
import org.libreplan.business.planner.entities.Task;
|
||||
import org.libreplan.business.planner.entities.TaskElement;
|
||||
import org.libreplan.business.planner.entities.IOrderEarnedValueCalculator;
|
||||
import org.libreplan.web.planner.order.OrderPlanningModel;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
|
|
@ -53,7 +48,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
public class CostStatusModel implements ICostStatusModel {
|
||||
|
||||
@Autowired
|
||||
private ICostCalculator hoursCostCalculator;
|
||||
private IOrderEarnedValueCalculator earnedValueCalculator;
|
||||
|
||||
private Order order;
|
||||
|
||||
|
|
@ -64,128 +59,27 @@ public class CostStatusModel implements ICostStatusModel {
|
|||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public BigDecimal getActualCostWorkPerformedAt(LocalDate date) {
|
||||
SortedMap<LocalDate, BigDecimal> actualCost = calculateActualCostWorkPerformed();
|
||||
BigDecimal result = actualCost.get(date);
|
||||
return (result != null) ? result : BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
private SortedMap<LocalDate, BigDecimal> calculateActualCostWorkPerformed() {
|
||||
SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
|
||||
for (TaskElement taskElement : getAllTaskElements(order)) {
|
||||
if (taskElement instanceof Task) {
|
||||
addCost(result, getWorkReportCost((Task) taskElement));
|
||||
}
|
||||
}
|
||||
return accumulateResult(result);
|
||||
}
|
||||
|
||||
private SortedMap<LocalDate, BigDecimal> accumulateResult(
|
||||
SortedMap<LocalDate, BigDecimal> map) {
|
||||
SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
|
||||
if (map.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
BigDecimal accumulatedResult = BigDecimal.ZERO;
|
||||
for (LocalDate day : map.keySet()) {
|
||||
BigDecimal value = map.get(day);
|
||||
accumulatedResult = accumulatedResult.add(value);
|
||||
result.put(day, accumulatedResult);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void addCost(SortedMap<LocalDate, BigDecimal> currentCost,
|
||||
SortedMap<LocalDate, BigDecimal> additionalCost) {
|
||||
for (LocalDate day : additionalCost.keySet()) {
|
||||
if (!currentCost.containsKey(day)) {
|
||||
currentCost.put(day, BigDecimal.ZERO);
|
||||
}
|
||||
currentCost.put(day,
|
||||
currentCost.get(day).add(additionalCost.get(day)));
|
||||
}
|
||||
}
|
||||
|
||||
private List<TaskElement> getAllTaskElements(Order order) {
|
||||
List<TaskElement> result = order.getAllChildrenAssociatedTaskElements();
|
||||
result.add(order.getAssociatedTaskElement());
|
||||
return result;
|
||||
}
|
||||
|
||||
private SortedMap<LocalDate, BigDecimal> getWorkReportCost(Task taskElement) {
|
||||
return hoursCostCalculator.getWorkReportCost(taskElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public BigDecimal getBudgetAtCompletion() {
|
||||
SortedMap<LocalDate, BigDecimal> budgedtedCost = calculateBudgetedCostWorkScheduled();
|
||||
LocalDate lastKey = budgedtedCost.lastKey();
|
||||
return (lastKey) != null ? budgedtedCost.get(lastKey) : BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
private SortedMap<LocalDate, BigDecimal> calculateBudgetedCostWorkScheduled() {
|
||||
SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
|
||||
for (TaskElement taskElement : getAllTaskElements(order)) {
|
||||
if (taskElement instanceof Task) {
|
||||
addCost(result, getEstimatedCost((Task) taskElement));
|
||||
}
|
||||
}
|
||||
return accumulateResult(result);
|
||||
}
|
||||
|
||||
private SortedMap<LocalDate, BigDecimal> getEstimatedCost(Task task) {
|
||||
return hoursCostCalculator.getEstimatedCost(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public BigDecimal getBudgetedCostWorkPerformedAt(LocalDate date) {
|
||||
SortedMap<LocalDate, BigDecimal> budgetedCost = calculateBudgetedCostWorkPerformed();
|
||||
BigDecimal result = budgetedCost.get(date);
|
||||
return (result != null) ? result : BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
private SortedMap<LocalDate, BigDecimal> calculateBudgetedCostWorkPerformed() {
|
||||
SortedMap<LocalDate, BigDecimal> estimatedCost = new TreeMap<LocalDate, BigDecimal>();
|
||||
for (TaskElement taskElement : getAllTaskElements(order)) {
|
||||
if (taskElement instanceof Task) {
|
||||
addCost(estimatedCost, getAdvanceCost((Task) taskElement));
|
||||
}
|
||||
}
|
||||
return accumulateResult(estimatedCost);
|
||||
}
|
||||
|
||||
private SortedMap<LocalDate, BigDecimal> getAdvanceCost(Task task) {
|
||||
return hoursCostCalculator.getAdvanceCost(task);
|
||||
return earnedValueCalculator.getActualCostWorkPerformedAt(order, date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getCostPerformanceIndex(BigDecimal budgetedCost,
|
||||
BigDecimal actualCost) {
|
||||
if (BigDecimal.ZERO.compareTo(actualCost) == 0) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return asPercentage(budgetedCost.divide(actualCost));
|
||||
}
|
||||
|
||||
private BigDecimal asPercentage(BigDecimal value) {
|
||||
return value.multiply(BigDecimal.valueOf(100)).setScale(2);
|
||||
return earnedValueCalculator.getCostPerformanceIndex(budgetedCost,
|
||||
actualCost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getCostVariance(BigDecimal budgetedCost,
|
||||
BigDecimal actualCost) {
|
||||
return budgetedCost.subtract(actualCost);
|
||||
return earnedValueCalculator.getCostVariance(budgetedCost, actualCost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getEstimateAtCompletion(BigDecimal budgetAtCompletion,
|
||||
BigDecimal costPerformanceIndex) {
|
||||
if (BigDecimal.ZERO.compareTo(costPerformanceIndex) == 0) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return asPercentage(budgetAtCompletion.divide(costPerformanceIndex));
|
||||
return earnedValueCalculator.getEstimateAtCompletion(
|
||||
budgetAtCompletion, costPerformanceIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -199,4 +93,15 @@ public class CostStatusModel implements ICostStatusModel {
|
|||
this.order = order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getBudgetAtCompletion() {
|
||||
return earnedValueCalculator.getBudgetAtCompletion(order);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getBudgetedCostWorkPerformedAt(LocalDate date) {
|
||||
return earnedValueCalculator
|
||||
.getBudgetedCostWorkPerformedAt(order, date);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -32,7 +32,6 @@ import java.util.Set;
|
|||
import org.apache.commons.lang.StringUtils;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.planner.entities.TaskStatusEnum;
|
||||
import org.libreplan.web.common.Util;
|
||||
import org.libreplan.web.dashboard.DashboardModel.Interval;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
|
@ -42,7 +41,6 @@ import org.zkoss.zk.ui.util.GenericForwardComposer;
|
|||
import org.zkoss.zul.Div;
|
||||
import org.zkoss.zul.Grid;
|
||||
import org.zkoss.zul.Label;
|
||||
import org.zkoss.zul.Window;
|
||||
|
||||
import br.com.digilabs.jqplot.Chart;
|
||||
import br.com.digilabs.jqplot.JqPlotUtils;
|
||||
|
|
@ -62,8 +60,6 @@ public class DashboardController extends GenericForwardComposer {
|
|||
|
||||
private IDashboardModel dashboardModel;
|
||||
|
||||
private Window dashboardWindow;
|
||||
|
||||
private Grid gridTasksSummary;
|
||||
private Grid gridMarginWithDeadline;
|
||||
|
||||
|
|
@ -78,28 +74,25 @@ public class DashboardController extends GenericForwardComposer {
|
|||
@Override
|
||||
public void doAfterCompose(org.zkoss.zk.ui.Component comp) throws Exception {
|
||||
super.doAfterCompose(comp);
|
||||
this.dashboardWindow = (Window) comp;
|
||||
self.setAttribute("controller", this);
|
||||
Util.createBindingsFor(this.dashboardWindow);
|
||||
}
|
||||
|
||||
public void setCurrentOrder(Order order) {
|
||||
dashboardModel.setCurrentOrder(order);
|
||||
if (dashboardModel.tasksAvailable()) {
|
||||
if (self != null) {
|
||||
renderGlobalProgress();
|
||||
renderTaskStatus();
|
||||
renderTaskCompletationLag();
|
||||
renderTasksSummary();
|
||||
renderDeadlineViolation();
|
||||
renderMarginWithDeadline();
|
||||
renderEstimationAccuracy();
|
||||
renderCostStatus(order);
|
||||
}
|
||||
showCharts();
|
||||
} else {
|
||||
hideCharts();
|
||||
}
|
||||
if (this.dashboardWindow != null) {
|
||||
renderGlobalProgress();
|
||||
renderTaskStatus();
|
||||
renderTaskCompletationLag();
|
||||
renderTasksSummary();
|
||||
renderDeadlineViolation();
|
||||
renderMarginWithDeadline();
|
||||
renderEstimationAccuracy();
|
||||
renderCostStatus(order);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderCostStatus(Order order) {
|
||||
|
|
@ -423,7 +416,7 @@ public class DashboardController extends GenericForwardComposer {
|
|||
private Map<Interval, Integer> getData() {
|
||||
if (taskCompletationData == null) {
|
||||
taskCompletationData = dashboardModel
|
||||
.calculateTaskCompletation();
|
||||
.calculateTaskCompletion();
|
||||
}
|
||||
return taskCompletationData;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,65 +141,64 @@ public class DashboardModel implements IDashboardModel {
|
|||
/* Progress KPI: "Global Progress of the Project" */
|
||||
@Override
|
||||
public BigDecimal getAdvancePercentageByHours() {
|
||||
TaskGroup rootAsTaskGroup = (TaskGroup) getRootTask();
|
||||
if (this.getRootTask() == null) {
|
||||
TaskGroup rootTask = (TaskGroup) getRootTask();
|
||||
if (rootTask == null) {
|
||||
throw new RuntimeException("Root task is null");
|
||||
}
|
||||
BigDecimal ratio = rootAsTaskGroup.getProgressAllByNumHours();
|
||||
return ratio.multiply(BigDecimal.TEN).multiply(BigDecimal.TEN);
|
||||
return asPercentage(rootTask.getProgressAllByNumHours());
|
||||
}
|
||||
|
||||
private BigDecimal asPercentage(BigDecimal value) {
|
||||
return value != null ? value.multiply(BigDecimal.valueOf(100))
|
||||
: BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getExpectedAdvancePercentageByHours() {
|
||||
TaskGroup rootAsTaskGroup = (TaskGroup) getRootTask();
|
||||
if (this.getRootTask() == null) {
|
||||
TaskGroup rootTask = (TaskGroup) getRootTask();
|
||||
if (rootTask == null) {
|
||||
throw new RuntimeException("Root task is null");
|
||||
}
|
||||
BigDecimal ratio = rootAsTaskGroup
|
||||
.getTheoreticalProgressByNumHoursForAllTasksUntilNow();
|
||||
return ratio.multiply(BigDecimal.TEN).multiply(BigDecimal.TEN);
|
||||
return asPercentage(rootTask
|
||||
.getTheoreticalProgressByNumHoursForAllTasksUntilNow());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getCriticalPathProgressByNumHours() {
|
||||
TaskGroup rootAsTaskGroup = (TaskGroup) getRootTask();
|
||||
if (this.getRootTask() == null) {
|
||||
TaskGroup rootTask = (TaskGroup) getRootTask();
|
||||
if (rootTask == null) {
|
||||
throw new RuntimeException("Root task is null");
|
||||
}
|
||||
BigDecimal ratio = rootAsTaskGroup.getCriticalPathProgressByNumHours();
|
||||
return ratio.multiply(BigDecimal.TEN).multiply(BigDecimal.TEN);
|
||||
return asPercentage(rootTask.getCriticalPathProgressByNumHours());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getExpectedCriticalPathProgressByNumHours() {
|
||||
TaskGroup rootAsTaskGroup = (TaskGroup) getRootTask();
|
||||
if (this.getRootTask() == null) {
|
||||
TaskGroup rootTask = (TaskGroup) getRootTask();
|
||||
if (rootTask == null) {
|
||||
throw new RuntimeException("Root task is null");
|
||||
}
|
||||
BigDecimal ratio = rootAsTaskGroup
|
||||
.getTheoreticalProgressByNumHoursForCriticalPathUntilNow();
|
||||
return ratio.multiply(BigDecimal.TEN).multiply(BigDecimal.TEN);
|
||||
return asPercentage(rootTask
|
||||
.getTheoreticalProgressByNumHoursForCriticalPathUntilNow());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getCriticalPathProgressByDuration() {
|
||||
TaskGroup rootAsTaskGroup = (TaskGroup) getRootTask();
|
||||
if (this.getRootTask() == null) {
|
||||
TaskGroup rootTask = (TaskGroup) getRootTask();
|
||||
if (rootTask == null) {
|
||||
throw new RuntimeException("Root task is null");
|
||||
}
|
||||
BigDecimal ratio = rootAsTaskGroup.getCriticalPathProgressByDuration();
|
||||
return ratio.multiply(BigDecimal.TEN).multiply(BigDecimal.TEN);
|
||||
return asPercentage(rootTask.getCriticalPathProgressByDuration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getExpectedCriticalPathProgressByDuration() {
|
||||
TaskGroup rootAsTaskGroup = (TaskGroup) getRootTask();
|
||||
if (this.getRootTask() == null) {
|
||||
TaskGroup rootTask = (TaskGroup) getRootTask();
|
||||
if (rootTask == null) {
|
||||
throw new RuntimeException("Root task is null");
|
||||
}
|
||||
BigDecimal ratio = rootAsTaskGroup
|
||||
.getTheoreticalProgressByDurationForCriticalPathUntilNow();
|
||||
return ratio.multiply(BigDecimal.TEN).multiply(BigDecimal.TEN);
|
||||
return asPercentage(rootTask
|
||||
.getTheoreticalProgressByDurationForCriticalPathUntilNow());
|
||||
}
|
||||
|
||||
/* Time KPI: Margin with deadline */
|
||||
|
|
@ -353,16 +352,16 @@ public class DashboardModel implements IDashboardModel {
|
|||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Map<Interval, Integer> calculateTaskCompletation() {
|
||||
public Map<Interval, Integer> calculateTaskCompletion() {
|
||||
Map<Interval, Integer> result = new LinkedHashMap<Interval, Integer>();
|
||||
Double max, min;
|
||||
|
||||
// Get deviations of finished tasks, calculate max, min and delta
|
||||
List<Double> deviations = getTaskLagDeviations();
|
||||
if (deviations.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
if (deviations.size() == 1) {
|
||||
max = Double.valueOf(3);
|
||||
min = Double.valueOf(-2);
|
||||
} else if (deviations.size() == 1) {
|
||||
max = deviations.get(0).doubleValue() + 3;
|
||||
min = deviations.get(0).doubleValue() - 2;
|
||||
} else {
|
||||
|
|
@ -421,9 +420,9 @@ public class DashboardModel implements IDashboardModel {
|
|||
// Get deviations of finished tasks, calculate max, min and delta
|
||||
List<Double> deviations = getEstimationAccuracyDeviations();
|
||||
if (deviations.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
if (deviations.size() == 1) {
|
||||
max = Double.valueOf(30);
|
||||
min = Double.valueOf(-20);
|
||||
} else if (deviations.size() == 1) {
|
||||
max = deviations.get(0).doubleValue() + 30;
|
||||
min = deviations.get(0).doubleValue() - 20;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -31,12 +31,14 @@ import org.libreplan.business.orders.entities.Order;
|
|||
*/
|
||||
interface ICostStatusModel {
|
||||
|
||||
BigDecimal getActualCostWorkPerformedAt(LocalDate day);
|
||||
// Actual Cost Work Performed (ACWP)
|
||||
BigDecimal getActualCostWorkPerformedAt(LocalDate date);
|
||||
|
||||
// Budget at Completion (BAC)
|
||||
// Budget At Completion (BAC)
|
||||
BigDecimal getBudgetAtCompletion();
|
||||
|
||||
BigDecimal getBudgetedCostWorkPerformedAt(LocalDate day);
|
||||
// Budgeted Cost Work Performed (BCWP)
|
||||
BigDecimal getBudgetedCostWorkPerformedAt(LocalDate date);
|
||||
|
||||
// Cost Performance Index (CPI)
|
||||
BigDecimal getCostPerformanceIndex(BigDecimal budgetedCost,
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ interface IDashboardModel {
|
|||
|
||||
Map<TaskStatusEnum, Integer> calculateTaskStatus();
|
||||
|
||||
Map<Interval, Integer> calculateTaskCompletation();
|
||||
Map<Interval, Integer> calculateTaskCompletion();
|
||||
|
||||
Map<Interval, Integer> calculateEstimationAccuracy();
|
||||
|
||||
|
|
|
|||
|
|
@ -121,4 +121,17 @@ public interface IManageOrderElementAdvancesModel {
|
|||
|
||||
boolean hasAnyConsolidatedAdvanceCurrentOrderElement();
|
||||
|
||||
boolean hasAnySubcontratedTaskOnChildren();
|
||||
|
||||
boolean isSubcontratedAdvanceType(AdvanceAssignment advance);
|
||||
|
||||
boolean isSubcontratedAdvanceTypeAndSubcontratedTask(
|
||||
AdvanceAssignment advance);
|
||||
|
||||
Boolean isAlreadyReportedProgress(AdvanceMeasurement measure);
|
||||
|
||||
boolean hasReportedProgress(AdvanceAssignment advance);
|
||||
|
||||
Boolean isAlreadyReportedProgressWith(LocalDate date);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,10 +21,13 @@
|
|||
|
||||
package org.libreplan.web.orders;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import org.libreplan.business.calendars.entities.BaseCalendar;
|
||||
import org.libreplan.business.externalcompanies.entities.EndDateCommunication;
|
||||
import org.libreplan.business.externalcompanies.entities.ExternalCompany;
|
||||
import org.libreplan.business.labels.entities.Label;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
|
|
@ -132,6 +135,14 @@ public interface IOrderModel extends IIntegrationEntityModel {
|
|||
|
||||
boolean hasImputedExpenseSheets(OrderElement order);
|
||||
|
||||
void removeAskedEndDate(EndDateCommunication endDate);
|
||||
|
||||
SortedSet<EndDateCommunication> getEndDates();
|
||||
|
||||
void addAskedEndDate(Date value);
|
||||
|
||||
boolean alreadyExistsRepeatedEndDate(Date value);
|
||||
|
||||
boolean isAnyTaskWithConstraint(PositionConstraintType type);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -224,6 +224,7 @@ public class ManageOrderElementAdvancesController extends
|
|||
AdvanceAssignment advance = (AdvanceAssignment) selectedItem
|
||||
.getValue();
|
||||
indexSelectedItem = editAdvances.getIndexOfItem(selectedItem);
|
||||
showInfoAbout(advance);
|
||||
prepareEditAdvanceMeasurements(advance);
|
||||
reloadAdvances();
|
||||
}
|
||||
|
|
@ -244,6 +245,7 @@ public class ManageOrderElementAdvancesController extends
|
|||
.getSpreadAdvance();
|
||||
if (advance != null) {
|
||||
indexSelectedItem = getAdvanceAssignments().indexOf(advance);
|
||||
showInfoAbout(advance);
|
||||
prepareEditAdvanceMeasurements(advance);
|
||||
} else {
|
||||
selectAdvanceLine(getAdvanceAssignments().size() - 1);
|
||||
|
|
@ -251,6 +253,13 @@ public class ManageOrderElementAdvancesController extends
|
|||
reloadAdvances();
|
||||
}
|
||||
|
||||
private void showInfoAbout(AdvanceAssignment advance) {
|
||||
if (manageOrderElementAdvancesModel
|
||||
.isSubcontratedAdvanceTypeAndSubcontratedTask(advance)) {
|
||||
showErrorMessage(_("Subcontractor values are read only because they were reported by the subcontractor company."));
|
||||
}
|
||||
}
|
||||
|
||||
public void prepareEditAdvanceMeasurements(AdvanceAssignment advance) {
|
||||
if (advance != null && advance.getAdvanceType() != null) {
|
||||
manageOrderElementAdvancesModel
|
||||
|
|
@ -351,10 +360,16 @@ public class ManageOrderElementAdvancesController extends
|
|||
final AdvanceAssignment advance = (AdvanceAssignment) data;
|
||||
listItem.setValue(advance);
|
||||
|
||||
Boolean readOnlyAdvance = false;
|
||||
boolean isQualityForm = false;
|
||||
|
||||
if (advance.getAdvanceType() != null) {
|
||||
isQualityForm = manageOrderElementAdvancesModel
|
||||
.isQualityForm(advance);
|
||||
if (manageOrderElementAdvancesModel
|
||||
.isSubcontratedAdvanceTypeAndSubcontratedTask(advance)) {
|
||||
readOnlyAdvance = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((advance instanceof DirectAdvanceAssignment)
|
||||
|
|
@ -372,7 +387,7 @@ public class ManageOrderElementAdvancesController extends
|
|||
appendRadioSpread(listItem);
|
||||
appendCalculatedCheckbox(listItem);
|
||||
appendChartCheckbox(listItem);
|
||||
appendOperations(listItem);
|
||||
appendOperations(listItem, readOnlyAdvance);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -661,17 +676,18 @@ public class ManageOrderElementAdvancesController extends
|
|||
listItem.appendChild(listCell);
|
||||
}
|
||||
|
||||
private void appendOperations(final Listitem listItem) {
|
||||
private void appendOperations(final Listitem listItem, Boolean readOnly) {
|
||||
Hbox hbox = new Hbox();
|
||||
appendAddMeasurement(hbox, listItem);
|
||||
appendRemoveButton(hbox, listItem);
|
||||
appendAddMeasurement(hbox, listItem, readOnly);
|
||||
appendRemoveButton(hbox, listItem, readOnly);
|
||||
|
||||
Listcell listCell = new Listcell();
|
||||
listCell.appendChild(hbox);
|
||||
listItem.appendChild(listCell);
|
||||
}
|
||||
|
||||
private void appendAddMeasurement(final Hbox hbox, final Listitem listItem) {
|
||||
private void appendAddMeasurement(final Hbox hbox, final Listitem listItem,
|
||||
Boolean readOnly) {
|
||||
final AdvanceAssignment advance = (AdvanceAssignment) listItem
|
||||
.getValue();
|
||||
final Button addMeasurementButton = createAddMeasurementButton();
|
||||
|
|
@ -696,13 +712,17 @@ public class ManageOrderElementAdvancesController extends
|
|||
addMeasurementButton.setDisabled(true);
|
||||
addMeasurementButton
|
||||
.setTooltiptext(_("Calculated progress can not be modified"));
|
||||
} else if (readOnly) {
|
||||
addMeasurementButton.setDisabled(true);
|
||||
addMeasurementButton
|
||||
.setTooltiptext(_("Subcontractor values are read only because they were reported by the subcontractor company."));
|
||||
}
|
||||
|
||||
hbox.appendChild(addMeasurementButton);
|
||||
|
||||
}
|
||||
|
||||
private void appendRemoveButton(final Hbox hbox, final Listitem listItem) {
|
||||
private void appendRemoveButton(final Hbox hbox, final Listitem listItem,
|
||||
Boolean readOnly) {
|
||||
final AdvanceAssignment advance = (AdvanceAssignment) listItem
|
||||
.getValue();
|
||||
final Button removeButton = createRemoveButton();
|
||||
|
|
@ -728,6 +748,14 @@ public class ManageOrderElementAdvancesController extends
|
|||
removeButton.setDisabled(true);
|
||||
removeButton
|
||||
.setTooltiptext(_("Consolidated progress can not be removed"));
|
||||
} else if (readOnly) {
|
||||
removeButton.setDisabled(true);
|
||||
removeButton
|
||||
.setTooltiptext(_("Subcontractor values are read only because they were reported by the subcontractor company."));
|
||||
} else if (manageOrderElementAdvancesModel.hasReportedProgress(advance)) {
|
||||
removeButton.setDisabled(true);
|
||||
removeButton
|
||||
.setTooltiptext(_("Advance assignment can not be removed because, it has advance measures that have already been reported to customer."));
|
||||
}
|
||||
|
||||
hbox.appendChild(removeButton);
|
||||
|
|
@ -1033,7 +1061,6 @@ public class ManageOrderElementAdvancesController extends
|
|||
@Override
|
||||
public void render(Listitem item, Object data) {
|
||||
AdvanceMeasurement advanceMeasurement = (AdvanceMeasurement) data;
|
||||
|
||||
item.setValue(advanceMeasurement);
|
||||
|
||||
appendDecimalBoxValue(item);
|
||||
|
|
@ -1053,7 +1080,9 @@ public class ManageOrderElementAdvancesController extends
|
|||
value.setScale(calculateScale(advanceMeasurement));
|
||||
value.setDisabled(isReadOnlyAdvanceMeasurements()
|
||||
|| manageOrderElementAdvancesModel
|
||||
.hasConsolidatedAdvances(advanceMeasurement));
|
||||
.hasConsolidatedAdvances(advanceMeasurement)
|
||||
|| manageOrderElementAdvancesModel.isAlreadyReportedProgress(advanceMeasurement));
|
||||
|
||||
value.addEventListener(Events.ON_CHANGE, new EventListener() {
|
||||
|
||||
@Override
|
||||
|
|
@ -1114,7 +1143,9 @@ public class ManageOrderElementAdvancesController extends
|
|||
|
||||
date.setDisabled(isReadOnlyAdvanceMeasurements()
|
||||
|| manageOrderElementAdvancesModel
|
||||
.hasConsolidatedAdvances(advanceMeasurement));
|
||||
.hasConsolidatedAdvances(advanceMeasurement)
|
||||
|| manageOrderElementAdvancesModel.isAlreadyReportedProgress(advanceMeasurement));
|
||||
|
||||
date.addEventListener(Events.ON_CHANGE, new EventListener() {
|
||||
|
||||
@Override
|
||||
|
|
@ -1197,6 +1228,14 @@ public class ManageOrderElementAdvancesController extends
|
|||
removeButton.setDisabled(true);
|
||||
removeButton
|
||||
.setTooltiptext(_("Consolidated progress measurement can not be removed"));
|
||||
} else if (manageOrderElementAdvancesModel.isAlreadyReportedProgress(measure)) {
|
||||
removeButton.setDisabled(true);
|
||||
removeButton
|
||||
.setTooltiptext(_("Values are read only because they have already been sent to the customer company."));
|
||||
} else if (isReadOnlyAdvanceMeasurements()) {
|
||||
removeButton.setDisabled(isReadOnlyAdvanceMeasurements());
|
||||
removeButton
|
||||
.setTooltiptext(_("Subcontractor values are read only because they were reported by the subcontractor company."));
|
||||
}
|
||||
|
||||
removeButton.addEventListener(Events.ON_CLICK, new EventListener() {
|
||||
|
|
@ -1321,6 +1360,9 @@ public class ManageOrderElementAdvancesController extends
|
|||
return _("Date is not valid, it must be greater than the last progress consolidation");
|
||||
}
|
||||
}
|
||||
if (manageOrderElementAdvancesModel.isAlreadyReportedProgressWith(value)) {
|
||||
return _("Date is not valid, it must be greater than the last progress reported to the customer");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
* Desenvolvemento Tecnolóxico de Galicia
|
||||
* Copyright (C) 2010-2011 Igalia, S.L.
|
||||
*
|
||||
* Copyright (C) 2011-2012 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
|
|
@ -54,7 +56,9 @@ import org.libreplan.business.advance.exceptions.DuplicateAdvanceAssignmentForOr
|
|||
import org.libreplan.business.advance.exceptions.DuplicateValueTrueReportGlobalAdvanceException;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.orders.daos.IOrderElementDAO;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderElement;
|
||||
import org.libreplan.business.planner.entities.TaskElement;
|
||||
import org.libreplan.business.planner.entities.consolidations.CalculatedConsolidatedValue;
|
||||
import org.libreplan.business.planner.entities.consolidations.CalculatedConsolidation;
|
||||
import org.libreplan.business.planner.entities.consolidations.Consolidation;
|
||||
|
|
@ -344,6 +348,14 @@ public class ManageOrderElementAdvancesModel implements
|
|||
continue;
|
||||
}
|
||||
}
|
||||
// if the associated task of the order elemement or of some its
|
||||
// children is subcontrated the advance type subcontractor is not
|
||||
// permitted
|
||||
if (advanceType.getUnitName().equals(
|
||||
PredefinedAdvancedTypes.SUBCONTRACTOR.getTypeName())
|
||||
&& hasAnySubcontratedTaskOnChildren()) {
|
||||
continue;
|
||||
}
|
||||
advanceTypes.add(advanceType);
|
||||
}
|
||||
return getSpecificOrder(advanceTypes);
|
||||
|
|
@ -402,7 +414,30 @@ public class ManageOrderElementAdvancesModel implements
|
|||
}
|
||||
}
|
||||
|
||||
return this.isIndirectAdvanceAssignment;
|
||||
if(isIndirectAdvanceAssignment){
|
||||
return true;
|
||||
}
|
||||
|
||||
return isSubcontratedAdvanceTypeAndSubcontratedTask(advanceAssignment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSubcontratedAdvanceTypeAndSubcontratedTask(
|
||||
AdvanceAssignment advance) {
|
||||
return (isSubcontratedAdvanceType(advance) && hasSubcontractedAssociatedTask(advance
|
||||
.getOrderElement()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSubcontratedAdvanceType(AdvanceAssignment advance) {
|
||||
AdvanceType advanceType = advance.getAdvanceType();
|
||||
if (advanceType != null) {
|
||||
if (advanceType.getUnitName().equals(
|
||||
PredefinedAdvancedTypes.SUBCONTRACTOR.getTypeName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -697,7 +732,7 @@ public class ManageOrderElementAdvancesModel implements
|
|||
|
||||
@Transactional(readOnly = true)
|
||||
public boolean canRemoveOrChange(AdvanceMeasurement advanceMeasurement) {
|
||||
return (!hasConsolidatedAdvances(advanceMeasurement));
|
||||
return (!hasConsolidatedAdvances(advanceMeasurement) && !isAlreadyReportedProgress(advanceMeasurement));
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
|
|
@ -838,4 +873,88 @@ public class ManageOrderElementAdvancesModel implements
|
|||
return orderElement.hasAnyConsolidatedAdvance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnySubcontratedTaskOnChildren() {
|
||||
List<OrderElement> list = new ArrayList<OrderElement>();
|
||||
list.add(orderElement);
|
||||
list.addAll(orderElement.getAllChildren());
|
||||
for (OrderElement child : list) {
|
||||
if (hasSubcontractedAssociatedTask(child)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasSubcontractedAssociatedTask(OrderElement orderElement) {
|
||||
for (TaskElement task : orderElement.getTaskElements()) {
|
||||
if (task.isSubcontracted()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isAlreadyReportedProgress(AdvanceMeasurement measure) {
|
||||
if (measure != null && !measure.isNewObject()) {
|
||||
return isAlreadyReportedProgressWith(measure.getDate());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isAlreadyReportedProgressWith(LocalDate date) {
|
||||
if (isSubcontractedByCustomer() && isSubcontratedAdvanceType(advanceAssignment)) {
|
||||
LocalDate lastReported = getLastReportedProgressToCustomer();
|
||||
return (date != null && lastReported != null && date.compareTo(lastReported) <= 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private LocalDate getLastReportedProgressToCustomer() {
|
||||
return getLastReportedProgressToCustomerOf(advanceAssignment);
|
||||
}
|
||||
|
||||
private LocalDate getLastReportedProgressToCustomerOf(DirectAdvanceAssignment advanceAssignment) {
|
||||
if (advanceAssignment != null && isSubcontractedByCustomer()) {
|
||||
AdvanceMeasurement lastAdvanceMeasurementReported = null;
|
||||
for (AdvanceMeasurement advanceMeasurement : advanceAssignment.getAdvanceMeasurements()) {
|
||||
if (advanceMeasurement.getCommunicationDate() != null) {
|
||||
if (lastAdvanceMeasurementReported == null) {
|
||||
lastAdvanceMeasurementReported = advanceMeasurement;
|
||||
} else {
|
||||
if (advanceMeasurement.getCommunicationDate().compareTo(
|
||||
lastAdvanceMeasurementReported.getCommunicationDate()) > 0) {
|
||||
lastAdvanceMeasurementReported = advanceMeasurement;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (lastAdvanceMeasurementReported != null) ? lastAdvanceMeasurementReported
|
||||
.getDate() : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Boolean isSubcontractedByCustomer() {
|
||||
if (orderElement != null) {
|
||||
Order order = orderElement.getOrder();
|
||||
if (order != null && order.getExternalCode() != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasReportedProgress(AdvanceAssignment advance) {
|
||||
if (advance instanceof DirectAdvanceAssignment) {
|
||||
return isSubcontractedByCustomer()
|
||||
&& isSubcontratedAdvanceType(advance)
|
||||
&& (getLastReportedProgressToCustomerOf((DirectAdvanceAssignment) advance) != null);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,11 @@ import java.text.SimpleDateFormat;
|
|||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
|
|
@ -38,6 +41,9 @@ import org.hibernate.validator.InvalidValue;
|
|||
import org.libreplan.business.calendars.entities.BaseCalendar;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.business.externalcompanies.entities.DeadlineCommunication;
|
||||
import org.libreplan.business.externalcompanies.entities.DeliverDateComparator;
|
||||
import org.libreplan.business.externalcompanies.entities.EndDateCommunication;
|
||||
import org.libreplan.business.externalcompanies.entities.ExternalCompany;
|
||||
import org.libreplan.business.orders.daos.IOrderDAO;
|
||||
import org.libreplan.business.orders.entities.HoursGroup;
|
||||
|
|
@ -70,6 +76,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.zkoss.ganttz.util.LongOperationFeedback;
|
||||
import org.zkoss.util.Locales;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zk.ui.Desktop;
|
||||
import org.zkoss.zk.ui.Executions;
|
||||
|
|
@ -87,13 +94,13 @@ import org.zkoss.zul.Comboitem;
|
|||
import org.zkoss.zul.ComboitemRenderer;
|
||||
import org.zkoss.zul.Constraint;
|
||||
import org.zkoss.zul.Datebox;
|
||||
import org.zkoss.zul.Decimalbox;
|
||||
import org.zkoss.zul.Grid;
|
||||
import org.zkoss.zul.Hbox;
|
||||
import org.zkoss.zul.Label;
|
||||
import org.zkoss.zul.Messagebox;
|
||||
import org.zkoss.zul.Row;
|
||||
import org.zkoss.zul.RowRenderer;
|
||||
import org.zkoss.zul.Rows;
|
||||
import org.zkoss.zul.SimpleListModel;
|
||||
import org.zkoss.zul.Tab;
|
||||
import org.zkoss.zul.Tabbox;
|
||||
|
|
@ -225,6 +232,10 @@ public class OrderCRUDController extends GenericForwardComposer {
|
|||
@Autowired
|
||||
private IOrderDAO orderDAO;
|
||||
|
||||
private Grid gridAskedEndDates;
|
||||
|
||||
private EndDatesRenderer endDatesRenderer = new EndDatesRenderer();
|
||||
|
||||
@Override
|
||||
public void doAfterCompose(Component comp) throws Exception {
|
||||
super.doAfterCompose(comp);
|
||||
|
|
@ -247,7 +258,6 @@ public class OrderCRUDController extends GenericForwardComposer {
|
|||
|
||||
checkCreationPermissions();
|
||||
setupGlobalButtons();
|
||||
|
||||
}
|
||||
|
||||
private void setupGlobalButtons() {
|
||||
|
|
@ -1049,6 +1059,8 @@ public class OrderCRUDController extends GenericForwardComposer {
|
|||
}
|
||||
});
|
||||
|
||||
gridAskedEndDates = (Grid) editWindow.getFellow("gridAskedEndDates");
|
||||
|
||||
}
|
||||
|
||||
public void setupOrderDetails() {
|
||||
|
|
@ -1340,8 +1352,8 @@ public class OrderCRUDController extends GenericForwardComposer {
|
|||
return orderModel.gettooltipText(order);
|
||||
}
|
||||
|
||||
public void reloadTotalBudget(Decimalbox decimalboxTotalBudget) {
|
||||
Util.reloadBindings(decimalboxTotalBudget);
|
||||
public void reloadTotalBudget(Label labelTotalBudget) {
|
||||
Util.reloadBindings(labelTotalBudget);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1528,6 +1540,13 @@ public class OrderCRUDController extends GenericForwardComposer {
|
|||
}
|
||||
}
|
||||
|
||||
public SortedSet<DeadlineCommunication> getDeliverDates() {
|
||||
if(getOrder() != null){
|
||||
return getOrder().getDeliveringDates();
|
||||
}
|
||||
return new TreeSet<DeadlineCommunication>(new DeliverDateComparator());
|
||||
}
|
||||
|
||||
public Constraint chekValidProjectName() {
|
||||
return new Constraint() {
|
||||
@Override
|
||||
|
|
@ -1576,8 +1595,147 @@ public class OrderCRUDController extends GenericForwardComposer {
|
|||
};
|
||||
}
|
||||
|
||||
public boolean isSubcontractedProject() {
|
||||
return (getOrder() != null) ? (getOrder().getExternalCode() != null)
|
||||
: false;
|
||||
}
|
||||
|
||||
public String getProjectType() {
|
||||
return (isSubcontractedProject()) ? "Subcontracted by client"
|
||||
: "Regular project";
|
||||
}
|
||||
|
||||
public void setCurrentDeliveryDate(Grid listDeliveryDates) {
|
||||
if (getOrder() != null && getOrder().getDeliveringDates() != null
|
||||
&& !getOrder().getDeliveringDates().isEmpty()) {
|
||||
DeadlineCommunication lastDeliveryDate = getOrder()
|
||||
.getDeliveringDates().first();
|
||||
if (listDeliveryDates != null) {
|
||||
listDeliveryDates.renderAll();
|
||||
final Rows rows = listDeliveryDates.getRows();
|
||||
for (Iterator i = rows.getChildren().iterator(); i.hasNext();) {
|
||||
final Row row = (Row) i.next();
|
||||
final DeadlineCommunication deliveryDate = (DeadlineCommunication) row
|
||||
.getValue();
|
||||
if (deliveryDate.equals(lastDeliveryDate)) {
|
||||
row.setSclass("current-delivery-date");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SortedSet<EndDateCommunication> getEndDates() {
|
||||
return orderModel.getEndDates();
|
||||
}
|
||||
|
||||
public void addAskedEndDate(Datebox newEndDate) {
|
||||
if (newEndDate == null || newEndDate.getValue() == null) {
|
||||
messagesForUser.showMessage(Level.ERROR, _("You must select a valid date. "));
|
||||
return;
|
||||
}
|
||||
if (thereIsSomeCommunicationDateEmpty()) {
|
||||
messagesForUser
|
||||
.showMessage(
|
||||
Level.ERROR,
|
||||
_("It will only be possible to add a end date if all the exiting ones in the table have already been sent to customer.."));
|
||||
return;
|
||||
}
|
||||
if (orderModel.alreadyExistsRepeatedEndDate(newEndDate.getValue())) {
|
||||
messagesForUser.showMessage(Level.ERROR,
|
||||
_("It already exists a end date with the same date. "));
|
||||
return;
|
||||
}
|
||||
orderModel.addAskedEndDate(newEndDate.getValue());
|
||||
reloadGridAskedEndDates();
|
||||
}
|
||||
|
||||
private void reloadGridAskedEndDates() {
|
||||
Util.reloadBindings(gridAskedEndDates);
|
||||
}
|
||||
|
||||
private boolean thereIsSomeCommunicationDateEmpty() {
|
||||
for (EndDateCommunication endDate : orderModel.getEndDates()) {
|
||||
if (endDate.getCommunicationDate() == null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public EndDatesRenderer getEndDatesRenderer() {
|
||||
return this.endDatesRenderer;
|
||||
}
|
||||
|
||||
private class EndDatesRenderer implements RowRenderer {
|
||||
|
||||
@Override
|
||||
public void render(Row row, Object data) throws Exception {
|
||||
EndDateCommunication endDate = (EndDateCommunication) data;
|
||||
row.setValue(endDate);
|
||||
|
||||
appendLabel(row, toString(endDate.getSaveDate(), "dd/MM/yyyy HH:mm"));
|
||||
appendLabel(row, toString(endDate.getEndDate(), "dd/MM/yyyy"));
|
||||
appendLabel(row, toString(endDate.getCommunicationDate(), "dd/MM/yyyy HH:mm"));
|
||||
appendOperations(row, endDate);
|
||||
}
|
||||
|
||||
private String toString(Date date, String precision) {
|
||||
if (date == null) {
|
||||
return "";
|
||||
}
|
||||
return new SimpleDateFormat(precision, Locales.getCurrent()).format(date);
|
||||
}
|
||||
|
||||
private void appendLabel(Row row, String label) {
|
||||
row.appendChild(new Label(label));
|
||||
}
|
||||
|
||||
private void appendOperations(Row row, EndDateCommunication endDate) {
|
||||
Hbox hbox = new Hbox();
|
||||
hbox.appendChild(getDeleteButton(endDate));
|
||||
row.appendChild(hbox);
|
||||
}
|
||||
|
||||
private Button getDeleteButton(final EndDateCommunication endDate) {
|
||||
|
||||
Button deleteButton = new Button();
|
||||
deleteButton.setDisabled(isNotUpdate(endDate));
|
||||
deleteButton.setSclass("icono");
|
||||
deleteButton.setImage("/common/img/ico_borrar1.png");
|
||||
deleteButton.setHoverImage("/common/img/ico_borrar.png");
|
||||
deleteButton.setTooltiptext(_("Delete"));
|
||||
deleteButton.addEventListener(Events.ON_CLICK, new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
removeAskedEndDate(endDate);
|
||||
}
|
||||
});
|
||||
|
||||
return deleteButton;
|
||||
}
|
||||
|
||||
private boolean isNotUpdate(final EndDateCommunication endDate) {
|
||||
EndDateCommunication lastAskedEndDate = getOrder()
|
||||
.getEndDateCommunicationToCustomer().first();
|
||||
if ((lastAskedEndDate != null) && (lastAskedEndDate.equals(endDate))) {
|
||||
return (lastAskedEndDate.getCommunicationDate() != null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAskedEndDate(EndDateCommunication endDate) {
|
||||
orderModel.removeAskedEndDate(endDate);
|
||||
reloadGridAskedEndDates();
|
||||
}
|
||||
|
||||
public String getMoneyFormat() {
|
||||
return Util.getMoneyFormat();
|
||||
}
|
||||
|
||||
public String getCurrencySymbol() {
|
||||
return Util.getCurrencySymbol();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.libreplan.business.advance.entities.AdvanceMeasurement;
|
||||
|
|
@ -46,6 +48,7 @@ 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.externalcompanies.daos.IExternalCompanyDAO;
|
||||
import org.libreplan.business.externalcompanies.entities.EndDateCommunication;
|
||||
import org.libreplan.business.externalcompanies.entities.ExternalCompany;
|
||||
import org.libreplan.business.labels.daos.ILabelDAO;
|
||||
import org.libreplan.business.labels.entities.Label;
|
||||
|
|
@ -282,12 +285,24 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
|
|||
forceLoadCriterionRequirements(order);
|
||||
forceLoadCalendar(this.getCalendar());
|
||||
forceLoadCustomer(order.getCustomer());
|
||||
forceLoadDeliveringDates(order);
|
||||
forceLoadLabels(order);
|
||||
forceLoadMaterialAssignments(order);
|
||||
forceLoadTaskQualityForms(order);
|
||||
forceLoadEndDateCommunicationToCustomer(order);
|
||||
initOldCodes();
|
||||
}
|
||||
|
||||
private void forceLoadEndDateCommunicationToCustomer(Order order) {
|
||||
if (order != null) {
|
||||
order.getEndDateCommunicationToCustomer().size();
|
||||
}
|
||||
}
|
||||
|
||||
private void forceLoadDeliveringDates(Order order){
|
||||
order.getDeliveringDates().size();
|
||||
}
|
||||
|
||||
private void forceLoadLabels(OrderElement orderElement) {
|
||||
orderElement.getLabels().size();
|
||||
for (OrderElement each : orderElement.getChildren()) {
|
||||
|
|
@ -864,6 +879,49 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
|
|||
}
|
||||
}
|
||||
|
||||
public void removeAskedEndDate(EndDateCommunication endDate) {
|
||||
Order order = (Order) getOrder();
|
||||
if (getOrder() != null && endDate != null) {
|
||||
order.removeAskedEndDate(endDate);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<EndDateCommunication> getEndDates() {
|
||||
Order order = (Order) getOrder();
|
||||
if (getOrder() != null) {
|
||||
return order.getEndDateCommunicationToCustomer();
|
||||
}
|
||||
return new TreeSet<EndDateCommunication>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAskedEndDate(Date value) {
|
||||
if (getOrder() != null) {
|
||||
Order order = (Order) getOrder();
|
||||
|
||||
EndDateCommunication askedEndDate = EndDateCommunication.create(
|
||||
new Date(), value, null);
|
||||
order.addAskedEndDate(askedEndDate);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alreadyExistsRepeatedEndDate(Date value) {
|
||||
if(getOrder() != null){
|
||||
Order order = (Order) getOrder();
|
||||
if (order.getEndDateCommunicationToCustomer().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EndDateCommunication endDateCommunicationToCustomer = order
|
||||
.getEndDateCommunicationToCustomer().first();
|
||||
Date currentEndDate = endDateCommunicationToCustomer.getEndDate();
|
||||
return (currentEndDate.compareTo(value) == 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isAnyTaskWithConstraint(PositionConstraintType type) {
|
||||
if ((planningState == null) || (planningState.getRootTask() == null)) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
|
||||
* Desenvolvemento Tecnolóxico de Galicia
|
||||
*
|
||||
* Copyright (C) 2011 Igalia S.L
|
||||
* Copyright (C) 2011-2012 Igalia S.L
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
|
|
@ -92,7 +92,11 @@ public abstract class TreeElementOperationsController<T> {
|
|||
|
||||
public void indentSelectedElement() {
|
||||
if (tree.getSelectedCount() == 1) {
|
||||
int page = tree.getActivePage();
|
||||
indent(getSelectedElement());
|
||||
if (tree.getPageCount() > page) {
|
||||
tree.setActivePage(page);
|
||||
}
|
||||
} else {
|
||||
showSelectAnElementError();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
* Desenvolvemento Tecnolóxico de Galicia
|
||||
* Copyright (C) 2010-2011 Igalia, S.L.
|
||||
*
|
||||
* Copyright (C) 2010-2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
|
|
@ -77,7 +79,6 @@ public class AdvanceAssignmentPlanningController extends GenericForwardComposer
|
|||
public void showWindow(IContextWithPlannerTask<TaskElement> context,
|
||||
TaskElement task,
|
||||
PlanningState planningState) {
|
||||
|
||||
this.context = context;
|
||||
advanceAssignmentPlanningModel.initAdvancesFor(task, context,
|
||||
planningState);
|
||||
|
|
@ -86,7 +87,7 @@ public class AdvanceAssignmentPlanningController extends GenericForwardComposer
|
|||
try {
|
||||
window.setTitle(getTitle());
|
||||
Util.reloadBindings(window);
|
||||
this.window.doModal();
|
||||
this.window.setMode("modal");
|
||||
} catch (SuspendNotAllowedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InterruptedException e) {
|
||||
|
|
|
|||
|
|
@ -508,6 +508,12 @@ public abstract class ChartFiller implements IChartFiller {
|
|||
return result;
|
||||
}
|
||||
|
||||
protected SortedMap<LocalDate, BigDecimal> calculatedValueForEveryDay(
|
||||
SortedMap<LocalDate, BigDecimal> values, Interval interval) {
|
||||
return calculatedValueForEveryDay(values, interval.getStart(),
|
||||
interval.getFinish());
|
||||
}
|
||||
|
||||
protected SortedMap<LocalDate, BigDecimal> calculatedValueForEveryDay(
|
||||
SortedMap<LocalDate, BigDecimal> map, Date start, Date finish) {
|
||||
return calculatedValueForEveryDay(map, new LocalDate(start),
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
|
||||
* Desenvolvemento Tecnolóxico de Galicia
|
||||
* Copyright (C) 2010-2011 Igalia, S.L.
|
||||
* Copyright (C) 2010-2012 Igalia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
|
|
@ -22,18 +22,13 @@
|
|||
package org.libreplan.web.planner.chart;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.libreplan.web.I18nHelper;
|
||||
import org.zkforge.timeplot.Plotinfo;
|
||||
|
|
@ -44,130 +39,24 @@ import org.zkoss.ganttz.util.Interval;
|
|||
|
||||
|
||||
/**
|
||||
* Abstract class with the common functionality for the earned value chart.
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
* @author Diego Pino García <dpino@igalia.com>
|
||||
*
|
||||
* Abstract class with the common functionality for the earned value
|
||||
* chart.
|
||||
*/
|
||||
public abstract class EarnedValueChartFiller extends ChartFiller {
|
||||
|
||||
public static <K, V> void forValuesAtSameKey(Map<K, V> a, Map<K, V> b,
|
||||
IOperation<K, V> onSameKey) {
|
||||
for (Entry<K, V> each : a.entrySet()) {
|
||||
V aValue = each.getValue();
|
||||
V bValue = b.get(each.getKey());
|
||||
onSameKey.operate(each.getKey(), aValue, bValue);
|
||||
}
|
||||
}
|
||||
public interface IOperation<K, V> {
|
||||
|
||||
public void operate(K key, V a, V b);
|
||||
|
||||
public void undefinedFor(K key);
|
||||
}
|
||||
|
||||
protected static abstract class PreconditionChecker<K, V> implements
|
||||
IOperation<K, V> {
|
||||
|
||||
private final IOperation<K, V> decorated;
|
||||
|
||||
protected PreconditionChecker(IOperation<K, V> decorated) {
|
||||
this.decorated = decorated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void operate(K key, V a, V b) {
|
||||
if (isOperationDefinedFor(key, a, b)) {
|
||||
decorated.operate(key, a, b);
|
||||
} else {
|
||||
decorated.undefinedFor(key);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract boolean isOperationDefinedFor(K key, V a, V b);
|
||||
|
||||
@Override
|
||||
public void undefinedFor(K key) {
|
||||
decorated.undefinedFor(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static <K, V> IOperation<K, V> notNullOperands(
|
||||
final IOperation<K, V> operation) {
|
||||
return new PreconditionChecker<K, V>(operation) {
|
||||
@Override
|
||||
protected boolean isOperationDefinedFor(K key, V a, V b) {
|
||||
return a != null && b != null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static <K> IOperation<K, BigDecimal> secondOperandNotZero(
|
||||
final IOperation<K, BigDecimal> operation) {
|
||||
return new PreconditionChecker<K, BigDecimal>(operation) {
|
||||
@Override
|
||||
protected boolean isOperationDefinedFor(K key, BigDecimal a, BigDecimal b) {
|
||||
return b.signum() != 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static boolean includes(Interval interval, LocalDate date) {
|
||||
LocalDate start = interval.getStart();
|
||||
LocalDate end = interval.getFinish();
|
||||
return start.compareTo(date) <= 0 && date.compareTo(end) < 0;
|
||||
}
|
||||
public enum EarnedValueType {
|
||||
|
||||
BCWS(_("BCWS"), _("Budgeted Cost Work Scheduled"), "#0000FF"), ACWP(
|
||||
_("ACWP"), _("Actual Cost Work Performed"), "#FF0000"), BCWP(
|
||||
_("BCWP"), _("Budgeted Cost Work Performed"), "#00FF00"), CV(
|
||||
_("CV"), _("Cost Variance"), "#FF8800"), SV(_("SV"),
|
||||
_("Schedule Variance"), "#00FFFF"), BAC(_("BAC"),
|
||||
_("Budget At Completion"), "#FF00FF"), EAC(_("EAC"),
|
||||
_("Estimate At Completion"), "#880000"), VAC(_("VAC"),
|
||||
_("Variance At Completion"), "#000088"), ETC(_("ETC"),
|
||||
_("Estimate To Complete"), "#008800"), CPI(_("CPI"),
|
||||
_("Cost Performance Index"), "#888800"), SPI(_("SPI"),
|
||||
_("Schedule Performance Index"), "#008888")
|
||||
;
|
||||
|
||||
/**
|
||||
* Forces to mark the string as needing translation
|
||||
*/
|
||||
private static String _(String string) {
|
||||
return string;
|
||||
}
|
||||
|
||||
private String acronym;
|
||||
private String name;
|
||||
private String color;
|
||||
|
||||
private EarnedValueType(String acronym, String name, String color) {
|
||||
this.acronym = acronym;
|
||||
this.name = name;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public String getAcronym() {
|
||||
return I18nHelper._(acronym);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return I18nHelper._(name);
|
||||
}
|
||||
|
||||
public String getColor() {
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
||||
protected Map<EarnedValueType, SortedMap<LocalDate, BigDecimal>> indicators = new HashMap<EarnedValueType, SortedMap<LocalDate, BigDecimal>>();
|
||||
private Interval indicatorsInterval;
|
||||
|
||||
protected abstract void calculateBudgetedCostWorkScheduled(Interval interval);
|
||||
protected abstract void calculateActualCostWorkPerformed(Interval interval);
|
||||
protected abstract void calculateBudgetedCostWorkPerformed(Interval interval);
|
||||
private Interval indicatorsInterval;
|
||||
|
||||
protected Plotinfo createPlotInfo(SortedMap<LocalDate, BigDecimal> map,
|
||||
Interval interval, String lineColor) {
|
||||
|
|
@ -203,167 +92,55 @@ public abstract class EarnedValueChartFiller extends ChartFiller {
|
|||
calculateSchedulePerformanceIndex();
|
||||
}
|
||||
|
||||
protected abstract void calculateBudgetedCostWorkScheduled(Interval interval);
|
||||
|
||||
protected abstract void calculateActualCostWorkPerformed(Interval interval);
|
||||
|
||||
protected abstract void calculateBudgetedCostWorkPerformed(Interval interval);
|
||||
|
||||
protected abstract void calculateCostVariance();
|
||||
|
||||
protected abstract void calculateScheduleVariance();
|
||||
|
||||
protected abstract void calculateBudgetAtCompletion();
|
||||
|
||||
protected abstract void calculateEstimateAtCompletion();
|
||||
|
||||
protected abstract void calculateVarianceAtCompletion();
|
||||
|
||||
protected abstract void calculateEstimatedToComplete();
|
||||
|
||||
protected abstract void calculateSchedulePerformanceIndex();
|
||||
|
||||
protected abstract void calculateCostPerformanceIndex();
|
||||
|
||||
protected abstract Set<EarnedValueType> getSelectedIndicators();
|
||||
|
||||
public SortedMap<LocalDate, BigDecimal> getIndicator(EarnedValueType indicator) {
|
||||
return indicators.get(indicator);
|
||||
}
|
||||
|
||||
public BigDecimal getIndicator(EarnedValueType indicator, LocalDate date) {
|
||||
return indicators.get(indicator).get(date);
|
||||
}
|
||||
|
||||
private void calculateCostVariance() {
|
||||
// CV = BCWP - ACWP
|
||||
indicators.put(EarnedValueType.CV,
|
||||
substract(EarnedValueType.BCWP, EarnedValueType.ACWP));
|
||||
public void setIndicator(EarnedValueType type, SortedMap<LocalDate, BigDecimal> values) {
|
||||
indicators.put(type, values);
|
||||
}
|
||||
|
||||
private void calculateScheduleVariance() {
|
||||
// SV = BCWP - BCWS
|
||||
|
||||
indicators.put(EarnedValueType.SV,
|
||||
substract(EarnedValueType.BCWP, EarnedValueType.BCWS));
|
||||
public void setIndicatorInInterval(EarnedValueType type,
|
||||
Interval interval, SortedMap<LocalDate, BigDecimal> values) {
|
||||
addZeroBeforeTheFirstValue(values);
|
||||
indicators.put(type, calculatedValueForEveryDay(values, interval));
|
||||
}
|
||||
|
||||
private void calculateBudgetAtCompletion() {
|
||||
// BAC = max (BCWS)
|
||||
SortedMap<LocalDate, BigDecimal> bac = new TreeMap<LocalDate, BigDecimal>();
|
||||
SortedMap<LocalDate, BigDecimal> bcws = indicators
|
||||
.get(EarnedValueType.BCWS);
|
||||
|
||||
BigDecimal value = Collections.max(bcws.values());
|
||||
for (LocalDate day : bcws.keySet()) {
|
||||
bac.put(day, value);
|
||||
protected void addZeroBeforeTheFirstValue(
|
||||
SortedMap<LocalDate, BigDecimal> map) {
|
||||
if (!map.isEmpty()) {
|
||||
map.put(map.firstKey().minusDays(1), BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
indicators.put(EarnedValueType.BAC, bac);
|
||||
}
|
||||
|
||||
private void calculateEstimateAtCompletion() {
|
||||
// EAC = (ACWP/BCWP) * BAC
|
||||
SortedMap<LocalDate, BigDecimal> dividend = divide(
|
||||
EarnedValueType.ACWP, EarnedValueType.BCWP,
|
||||
BigDecimal.ZERO);
|
||||
SortedMap<LocalDate, BigDecimal> bac = indicators
|
||||
.get(EarnedValueType.BAC);
|
||||
indicators.put(EarnedValueType.EAC, multiply(dividend, bac));
|
||||
}
|
||||
|
||||
private static SortedMap<LocalDate, BigDecimal> multiply(
|
||||
Map<LocalDate, BigDecimal> firstFactor,
|
||||
Map<LocalDate, BigDecimal> secondFactor) {
|
||||
final SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
|
||||
forValuesAtSameKey(firstFactor, secondFactor,
|
||||
multiplicationOperation(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IOperation<LocalDate, BigDecimal> multiplicationOperation(
|
||||
final SortedMap<LocalDate, BigDecimal> result) {
|
||||
return notNullOperands(new IOperation<LocalDate, BigDecimal>() {
|
||||
|
||||
@Override
|
||||
public void operate(LocalDate key, BigDecimal a,
|
||||
BigDecimal b) {
|
||||
result.put(key, a.multiply(b));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undefinedFor(LocalDate key) {
|
||||
result.put(key, BigDecimal.ZERO);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void calculateVarianceAtCompletion() {
|
||||
indicators.put(EarnedValueType.VAC,
|
||||
substract(EarnedValueType.BAC, EarnedValueType.EAC));
|
||||
}
|
||||
|
||||
private void calculateEstimatedToComplete() {
|
||||
// ETC = EAC - ACWP
|
||||
indicators.put(EarnedValueType.ETC,
|
||||
substract(EarnedValueType.EAC, EarnedValueType.ACWP));
|
||||
}
|
||||
|
||||
private SortedMap<LocalDate, BigDecimal> substract(EarnedValueType minuend,
|
||||
EarnedValueType subtrahend) {
|
||||
return substract(indicators.get(minuend), indicators.get(subtrahend));
|
||||
}
|
||||
|
||||
private static SortedMap<LocalDate, BigDecimal> substract(
|
||||
Map<LocalDate, BigDecimal> minuend,
|
||||
Map<LocalDate, BigDecimal> subtrahend) {
|
||||
final SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
|
||||
forValuesAtSameKey(minuend, subtrahend, substractionOperation(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IOperation<LocalDate, BigDecimal> substractionOperation(
|
||||
final SortedMap<LocalDate, BigDecimal> result) {
|
||||
return notNullOperands(new IOperation<LocalDate, BigDecimal>() {
|
||||
|
||||
@Override
|
||||
public void operate(LocalDate key, BigDecimal minuedValue,
|
||||
BigDecimal subtrahendValue) {
|
||||
result.put(key,
|
||||
minuedValue.subtract(subtrahendValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undefinedFor(LocalDate key) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void calculateCostPerformanceIndex() {
|
||||
// CPI = BCWP / ACWP
|
||||
indicators.put(EarnedValueType.CPI,
|
||||
divide(EarnedValueType.BCWP, EarnedValueType.ACWP,
|
||||
BigDecimal.ZERO));
|
||||
}
|
||||
|
||||
private void calculateSchedulePerformanceIndex() {
|
||||
// SPI = BCWP / BCWS
|
||||
indicators.put(EarnedValueType.SPI,
|
||||
divide(EarnedValueType.BCWP, EarnedValueType.BCWS,
|
||||
BigDecimal.ZERO));
|
||||
}
|
||||
|
||||
private SortedMap<LocalDate, BigDecimal> divide(EarnedValueType dividend,
|
||||
EarnedValueType divisor, BigDecimal defaultIfNotComputable) {
|
||||
Validate.notNull(indicators.get(dividend));
|
||||
Validate.notNull(indicators.get(divisor));
|
||||
return divide(indicators.get(dividend), indicators.get(divisor),
|
||||
defaultIfNotComputable);
|
||||
}
|
||||
|
||||
private static SortedMap<LocalDate, BigDecimal> divide(
|
||||
Map<LocalDate, BigDecimal> dividend,
|
||||
Map<LocalDate, BigDecimal> divisor,
|
||||
final BigDecimal defaultIfNotComputable) {
|
||||
final TreeMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
|
||||
forValuesAtSameKey(dividend, divisor,
|
||||
divisionOperation(result, defaultIfNotComputable));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IOperation<LocalDate, BigDecimal> divisionOperation(
|
||||
final TreeMap<LocalDate, BigDecimal> result,
|
||||
final BigDecimal defaultIfNotComputable) {
|
||||
return notNullOperands(secondOperandNotZero(new IOperation<LocalDate, BigDecimal>() {
|
||||
|
||||
@Override
|
||||
public void operate(LocalDate key, BigDecimal dividendValue,
|
||||
BigDecimal divisorValue) {
|
||||
result.put(key, dividendValue.divide(divisorValue,
|
||||
RoundingMode.DOWN));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undefinedFor(LocalDate key) {
|
||||
result.put(key, defaultIfNotComputable);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
protected abstract Set<EarnedValueType> getSelectedIndicators();
|
||||
|
||||
@Override
|
||||
public void fillChart(Timeplot chart, Interval interval, Integer size) {
|
||||
chart.getChildren().clear();
|
||||
|
|
@ -411,11 +188,55 @@ public abstract class EarnedValueChartFiller extends ChartFiller {
|
|||
return includes(chartInterval, today) ? today : chartInterval
|
||||
.getFinish().minusDays(1);
|
||||
}
|
||||
protected void addZeroBeforeTheFirstValue(
|
||||
SortedMap<LocalDate, BigDecimal> map) {
|
||||
if (!map.isEmpty()) {
|
||||
map.put(map.firstKey().minusDays(1), BigDecimal.ZERO);
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
*
|
||||
*/
|
||||
public enum EarnedValueType {
|
||||
|
||||
BCWS(_("BCWS"), _("Budgeted Cost Work Scheduled"), "#0000FF"), ACWP(
|
||||
_("ACWP"), _("Actual Cost Work Performed"), "#FF0000"), BCWP(
|
||||
_("BCWP"), _("Budgeted Cost Work Performed"), "#00FF00"), CV(
|
||||
_("CV"), _("Cost Variance"), "#FF8800"), SV(_("SV"),
|
||||
_("Schedule Variance"), "#00FFFF"), BAC(_("BAC"),
|
||||
_("Budget At Completion"), "#FF00FF"), EAC(_("EAC"),
|
||||
_("Estimate At Completion"), "#880000"), VAC(_("VAC"),
|
||||
_("Variance At Completion"), "#000088"), ETC(_("ETC"),
|
||||
_("Estimate To Complete"), "#008800"), CPI(_("CPI"),
|
||||
_("Cost Performance Index"), "#888800"), SPI(_("SPI"),
|
||||
_("Schedule Performance Index"), "#008888")
|
||||
;
|
||||
|
||||
/**
|
||||
* Forces to mark the string as needing translation
|
||||
*/
|
||||
private static String _(String string) {
|
||||
return string;
|
||||
}
|
||||
|
||||
private String acronym;
|
||||
private String name;
|
||||
private String color;
|
||||
|
||||
private EarnedValueType(String acronym, String name, String color) {
|
||||
this.acronym = acronym;
|
||||
this.name = name;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public String getAcronym() {
|
||||
return I18nHelper._(acronym);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return I18nHelper._(name);
|
||||
}
|
||||
|
||||
public String getColor() {
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -38,8 +38,6 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.libreplan.business.calendars.entities.AvailabilityTimeLine;
|
||||
|
|
@ -55,6 +53,7 @@ import org.libreplan.business.orders.entities.Order;
|
|||
import org.libreplan.business.orders.entities.OrderStatusEnum;
|
||||
import org.libreplan.business.planner.chart.ILoadChartData;
|
||||
import org.libreplan.business.planner.chart.ResourceLoadChartData;
|
||||
import org.libreplan.business.planner.entities.ICompanyEarnedValueCalculator;
|
||||
import org.libreplan.business.planner.entities.TaskElement;
|
||||
import org.libreplan.business.planner.entities.TaskGroup;
|
||||
import org.libreplan.business.planner.entities.TaskMilestone;
|
||||
|
|
@ -62,7 +61,6 @@ import org.libreplan.business.scenarios.IScenarioManager;
|
|||
import org.libreplan.business.scenarios.entities.Scenario;
|
||||
import org.libreplan.business.users.daos.IUserDAO;
|
||||
import org.libreplan.business.users.entities.User;
|
||||
import org.libreplan.business.workreports.entities.WorkReportLine;
|
||||
import org.libreplan.web.planner.TaskElementAdapter;
|
||||
import org.libreplan.web.planner.TaskGroupPredicate;
|
||||
import org.libreplan.web.planner.chart.Chart;
|
||||
|
|
@ -132,6 +130,9 @@ public class CompanyPlanningModel implements ICompanyPlanningModel {
|
|||
@Autowired
|
||||
private IAdHocTransactionService transactionService;
|
||||
|
||||
@Autowired
|
||||
private ICompanyEarnedValueCalculator earnedValueCalculator;
|
||||
|
||||
private List<IZoomLevelChangedListener> keepAliveZoomListeners = new ArrayList<IZoomLevelChangedListener>();
|
||||
|
||||
private List<Checkbox> earnedValueChartConfigurationCheckboxes = new ArrayList<Checkbox>();
|
||||
|
|
@ -275,6 +276,7 @@ public class CompanyPlanningModel implements ICompanyPlanningModel {
|
|||
setupChart(chartLoadTimeplot, new CompanyLoadChartFiller(), planner);
|
||||
|
||||
chartComponent.getTabs().getLastChild().addEventListener(Events.ON_SELECT, new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) throws Exception {
|
||||
createOnDemandEarnedValueTimePlot(chartComponent, planner);
|
||||
event.getTarget().removeEventListener(Events.ON_SELECT, this);
|
||||
|
|
@ -783,75 +785,101 @@ public class CompanyPlanningModel implements ICompanyPlanningModel {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
* @author Diego Pino García <dpino@igalia.com>
|
||||
*
|
||||
* Calculates 'Earned Value' indicators and set them in the Company
|
||||
* 'Earned Valued' chart
|
||||
*
|
||||
*/
|
||||
private class CompanyEarnedValueChartFiller extends EarnedValueChartFiller {
|
||||
|
||||
@Override
|
||||
protected void calculateBudgetedCostWorkScheduled(Interval interval) {
|
||||
Map<TaskElement, SortedMap<LocalDate, BigDecimal>> estimatedCostPerTask =
|
||||
databaseSnapshots.snapshotEstimatedCostPerTask();
|
||||
Collection<TaskElement> list = filterTasksByDate(
|
||||
estimatedCostPerTask.keySet(), getFilterInterval());
|
||||
|
||||
SortedMap<LocalDate, BigDecimal> estimatedCost = new TreeMap<LocalDate, BigDecimal>();
|
||||
|
||||
for (TaskElement taskElement : list) {
|
||||
addCost(estimatedCost, estimatedCostPerTask.get(taskElement));
|
||||
}
|
||||
|
||||
estimatedCost = accumulateResult(estimatedCost);
|
||||
addZeroBeforeTheFirstValue(estimatedCost);
|
||||
indicators.put(EarnedValueType.BCWS, calculatedValueForEveryDay(
|
||||
estimatedCost, interval.getStart(), interval.getFinish()));
|
||||
setIndicatorInInterval(EarnedValueType.BCWS, interval,
|
||||
earnedValueCalculator
|
||||
.calculateBudgetedCostWorkScheduled(getFilterInterval()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateActualCostWorkPerformed(Interval interval) {
|
||||
SortedMap<LocalDate, BigDecimal> workReportCost = getWorkReportCost();
|
||||
|
||||
workReportCost = accumulateResult(workReportCost);
|
||||
addZeroBeforeTheFirstValue(workReportCost);
|
||||
indicators.put(EarnedValueType.ACWP, calculatedValueForEveryDay(
|
||||
workReportCost, interval.getStart(), interval.getFinish()));
|
||||
}
|
||||
|
||||
private SortedMap<LocalDate, BigDecimal> getWorkReportCost() {
|
||||
SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
|
||||
|
||||
Collection<WorkReportLine> workReportLines = filterWorkReportLinesByDate(
|
||||
databaseSnapshots.snapshotWorkReportLines(),
|
||||
getFilterInterval());
|
||||
|
||||
if (workReportLines.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
for (WorkReportLine workReportLine : workReportLines) {
|
||||
LocalDate day = new LocalDate(workReportLine.getDate());
|
||||
BigDecimal cost = workReportLine.getEffort()
|
||||
.toHoursAsDecimalWithScale(2);
|
||||
|
||||
if (!result.containsKey(day)) {
|
||||
result.put(day, BigDecimal.ZERO);
|
||||
}
|
||||
result.put(day, result.get(day).add(cost));
|
||||
}
|
||||
|
||||
return result;
|
||||
setIndicatorInInterval(EarnedValueType.ACWP, interval,
|
||||
earnedValueCalculator
|
||||
.calculateActualCostWorkPerformed(getFilterInterval()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateBudgetedCostWorkPerformed(Interval interval) {
|
||||
Map<TaskElement, SortedMap<LocalDate, BigDecimal>> advanceCostPerTask =
|
||||
databaseSnapshots.snapshotAdvanceCostPerTask();
|
||||
Collection<TaskElement> list = filterTasksByDate(
|
||||
advanceCostPerTask.keySet(), getFilterInterval());
|
||||
setIndicatorInInterval(EarnedValueType.BCWP, interval,
|
||||
earnedValueCalculator
|
||||
.calculateBudgetedCostWorkPerformed(getFilterInterval()));
|
||||
}
|
||||
|
||||
SortedMap<LocalDate, BigDecimal> advanceCost = new TreeMap<LocalDate, BigDecimal>();
|
||||
@Override
|
||||
protected void calculateCostVariance() {
|
||||
setIndicator(EarnedValueType.CV,
|
||||
earnedValueCalculator.calculateCostVariance(
|
||||
getIndicator(EarnedValueType.BCWP),
|
||||
getIndicator(EarnedValueType.ACWP)));
|
||||
}
|
||||
|
||||
for (TaskElement taskElement : list) {
|
||||
addCost(advanceCost, advanceCostPerTask.get(taskElement));
|
||||
}
|
||||
@Override
|
||||
protected void calculateScheduleVariance() {
|
||||
setIndicator(EarnedValueType.SV,
|
||||
earnedValueCalculator.calculateScheduleVariance(
|
||||
getIndicator(EarnedValueType.BCWP),
|
||||
getIndicator(EarnedValueType.BCWS)));
|
||||
}
|
||||
|
||||
addZeroBeforeTheFirstValue(advanceCost);
|
||||
indicators.put(EarnedValueType.BCWP, calculatedValueForEveryDay(
|
||||
advanceCost, interval.getStart(), interval.getFinish()));
|
||||
@Override
|
||||
protected void calculateSchedulePerformanceIndex() {
|
||||
setIndicator(EarnedValueType.SPI,
|
||||
earnedValueCalculator.calculateSchedulePerformanceIndex(
|
||||
getIndicator(EarnedValueType.BCWP),
|
||||
getIndicator(EarnedValueType.BCWS)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateBudgetAtCompletion() {
|
||||
setIndicator(
|
||||
EarnedValueType.BAC,
|
||||
earnedValueCalculator
|
||||
.calculateBudgetAtCompletion(getIndicator(EarnedValueType.BCWS)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateEstimateAtCompletion() {
|
||||
setIndicator(EarnedValueType.EAC,
|
||||
earnedValueCalculator.calculateEstimateAtCompletion(
|
||||
getIndicator(EarnedValueType.ACWP),
|
||||
getIndicator(EarnedValueType.BCWP),
|
||||
getIndicator(EarnedValueType.BAC)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateVarianceAtCompletion() {
|
||||
setIndicator(EarnedValueType.VAC,
|
||||
earnedValueCalculator.calculateVarianceAtCompletion(
|
||||
getIndicator(EarnedValueType.BAC),
|
||||
getIndicator(EarnedValueType.EAC)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateEstimatedToComplete() {
|
||||
setIndicator(EarnedValueType.ETC,
|
||||
earnedValueCalculator.calculateEstimatedToComplete(
|
||||
getIndicator(EarnedValueType.EAC),
|
||||
getIndicator(EarnedValueType.ACWP)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateCostPerformanceIndex() {
|
||||
setIndicator(EarnedValueType.CPI,
|
||||
earnedValueCalculator.calculateCostPerformanceIndex(
|
||||
getIndicator(EarnedValueType.BCWP),
|
||||
getIndicator(EarnedValueType.ACWP)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -859,33 +887,9 @@ public class CompanyPlanningModel implements ICompanyPlanningModel {
|
|||
return getEarnedValueSelectedIndicators();
|
||||
}
|
||||
|
||||
private List<TaskElement> filterTasksByDate(
|
||||
Collection<TaskElement> tasks,
|
||||
AvailabilityTimeLine.Interval interval) {
|
||||
List<TaskElement> result = new ArrayList<TaskElement>();
|
||||
for(TaskElement task : tasks) {
|
||||
if (interval.includes(task.getStartAsLocalDate())
|
||||
|| interval.includes(task.getEndAsLocalDate())) {
|
||||
result.add(task);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private List<WorkReportLine> filterWorkReportLinesByDate(
|
||||
Collection<WorkReportLine> lines,
|
||||
AvailabilityTimeLine.Interval interval) {
|
||||
List<WorkReportLine> result = new ArrayList<WorkReportLine>();
|
||||
for(WorkReportLine line: lines) {
|
||||
if (interval.includes(line.getLocalDate())) {
|
||||
result.add(line);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly=true)
|
||||
public ProgressType getProgressTypeFromConfiguration() {
|
||||
return configurationDAO.getConfiguration().getProgressType();
|
||||
|
|
|
|||
|
|
@ -23,10 +23,13 @@ package org.libreplan.web.planner.order;
|
|||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.business.externalcompanies.entities.EndDateCommunication;
|
||||
import org.libreplan.business.externalcompanies.entities.ExternalCompany;
|
||||
import org.libreplan.business.planner.entities.SubcontractedTaskData;
|
||||
import org.libreplan.business.planner.entities.SubcontractorDeliverDate;
|
||||
import org.libreplan.business.planner.entities.Task;
|
||||
|
||||
/**
|
||||
|
|
@ -65,4 +68,15 @@ public interface ISubcontractModel {
|
|||
void confirm() throws ValidationException;
|
||||
void cancel();
|
||||
|
||||
SortedSet<SubcontractorDeliverDate> getDeliverDates();
|
||||
|
||||
void addDeliverDate(Date subDeliverDate);
|
||||
|
||||
void removeRequiredDeliverDate(
|
||||
SubcontractorDeliverDate subcontractorDeliverDate);
|
||||
|
||||
boolean alreadyExistsRepeatedDeliverDate(Date newDeliverDate);
|
||||
|
||||
SortedSet<EndDateCommunication> getAskedEndDates();
|
||||
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
|
||||
* Desenvolvemento Tecnolóxico de Galicia
|
||||
* Copyright (C) 2010-2011 Igalia, S.L.
|
||||
* Copyright (C) 2010-2011 WirelessGalicia S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
|
|
@ -63,6 +64,7 @@ import org.zkoss.ganttz.util.ProfilingLogFactory;
|
|||
import org.zkoss.zk.ui.Executions;
|
||||
import org.zkoss.zk.ui.WrongValueException;
|
||||
import org.zkoss.zk.ui.util.Composer;
|
||||
import org.zkoss.zk.ui.util.GenericForwardComposer;
|
||||
import org.zkoss.zul.Checkbox;
|
||||
import org.zkoss.zul.Constraint;
|
||||
import org.zkoss.zul.Datebox;
|
||||
|
|
@ -72,6 +74,7 @@ import org.zkoss.zul.Vbox;
|
|||
|
||||
/**
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
@Component
|
||||
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
||||
|
|
@ -108,6 +111,8 @@ public class OrderPlanningController implements Composer {
|
|||
@Autowired
|
||||
private OrderCRUDController orderCRUDController;
|
||||
|
||||
private GenericForwardComposer currentControllerToShow;
|
||||
|
||||
private Order order;
|
||||
|
||||
private TaskElement task;
|
||||
|
|
@ -216,6 +221,7 @@ public class OrderPlanningController implements Composer {
|
|||
+ (System.currentTimeMillis() - time) + " ms");
|
||||
planner.updateSelectedZoomLevel();
|
||||
showResorceAllocationIfIsNeeded();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -363,9 +369,17 @@ public class OrderPlanningController implements Composer {
|
|||
if ((foundTask != null) && (foundTaskElement != null)) {
|
||||
IContextWithPlannerTask<TaskElement> contextTask = ContextWithPlannerTask
|
||||
.create(context, foundTask);
|
||||
this.editTaskController
|
||||
.showEditFormResourceAllocation(contextTask,
|
||||
foundTaskElement, model.getPlanningState());
|
||||
if (this.getCurrentControllerToShow().equals(
|
||||
getEditTaskController())) {
|
||||
this.editTaskController.showEditFormResourceAllocation(
|
||||
contextTask, foundTaskElement,
|
||||
model.getPlanningState());
|
||||
} else if (this.getCurrentControllerToShow().equals(
|
||||
this.getAdvanceAssignmentPlanningController())) {
|
||||
getAdvanceAssignmentPlanningController().showWindow(
|
||||
contextTask, foundTaskElement,
|
||||
model.getPlanningState());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -378,4 +392,12 @@ public class OrderPlanningController implements Composer {
|
|||
return advanceAssignmentPlanningController;
|
||||
}
|
||||
|
||||
public void setCurrentControllerToShow(GenericForwardComposer currentControllerToShow) {
|
||||
this.currentControllerToShow = currentControllerToShow;
|
||||
}
|
||||
|
||||
public GenericForwardComposer getCurrentControllerToShow() {
|
||||
return currentControllerToShow;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,8 +38,6 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.apache.commons.logging.Log;
|
||||
|
|
@ -51,7 +49,6 @@ import org.libreplan.business.common.AdHocTransactionService;
|
|||
import org.libreplan.business.common.IAdHocTransactionService;
|
||||
import org.libreplan.business.common.IOnTransaction;
|
||||
import org.libreplan.business.common.Registry;
|
||||
import org.libreplan.business.common.entities.ProgressType;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.orders.daos.IOrderDAO;
|
||||
import org.libreplan.business.orders.entities.HoursGroup;
|
||||
|
|
@ -64,7 +61,7 @@ import org.libreplan.business.planner.chart.ResourceLoadChartData;
|
|||
import org.libreplan.business.planner.entities.DayAssignment;
|
||||
import org.libreplan.business.planner.entities.DayAssignment.FilterType;
|
||||
import org.libreplan.business.planner.entities.ICostCalculator;
|
||||
import org.libreplan.business.planner.entities.Task;
|
||||
import org.libreplan.business.planner.entities.IOrderEarnedValueCalculator;
|
||||
import org.libreplan.business.planner.entities.TaskElement;
|
||||
import org.libreplan.business.planner.entities.TaskGroup;
|
||||
import org.libreplan.business.resources.entities.CriterionSatisfaction;
|
||||
|
|
@ -140,7 +137,6 @@ import org.zkoss.zul.Div;
|
|||
import org.zkoss.zul.Hbox;
|
||||
import org.zkoss.zul.Label;
|
||||
import org.zkoss.zul.Messagebox;
|
||||
import org.zkoss.zul.Progressmeter;
|
||||
import org.zkoss.zul.Tab;
|
||||
import org.zkoss.zul.Tabbox;
|
||||
import org.zkoss.zul.Tabpanel;
|
||||
|
|
@ -152,6 +148,7 @@ import org.zkoss.zul.Vbox;
|
|||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||
* @author Diego Pino García <dpino@igalia.com>
|
||||
*/
|
||||
@Component
|
||||
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
||||
|
|
@ -262,14 +259,15 @@ public class OrderPlanningModel implements IOrderPlanningModel {
|
|||
@Autowired
|
||||
private ICostCalculator hoursCostCalculator;
|
||||
|
||||
@Autowired
|
||||
private IOrderEarnedValueCalculator earnedValueCalculator;
|
||||
|
||||
private List<Checkbox> earnedValueChartConfigurationCheckboxes = new ArrayList<Checkbox>();
|
||||
|
||||
private List<IChartVisibilityChangedListener> keepAliveChartVisibilityListeners = new ArrayList<IChartVisibilityChangedListener>();
|
||||
|
||||
private Planner planner;
|
||||
|
||||
private OverAllProgressContent overallProgressContent;
|
||||
|
||||
private String tabSelected = "load_tab";
|
||||
|
||||
private static class NullSeparatorCommandOnTask<T> implements
|
||||
|
|
@ -387,11 +385,6 @@ public class OrderPlanningModel implements IOrderPlanningModel {
|
|||
this.earnedValueChartFiller = createOrderEarnedValueChartFiller(planner.getTimeTracker());
|
||||
chartTabpanels.appendChild(createEarnedValueTab(chartEarnedValueTimeplot, earnedValueChartFiller));
|
||||
|
||||
// Create 'Overall progress' tab
|
||||
Hbox chartOverallProgressTimeplot = new Hbox();
|
||||
Tabpanel overallProgressTab = createOverallProgressTab(chartOverallProgressTimeplot);
|
||||
chartTabpanels.appendChild(overallProgressTab);
|
||||
|
||||
// Append tab panels
|
||||
chartComponent.appendChild(chartTabpanels);
|
||||
ChangeHooker changeHooker = new ChangeHooker(configuration, saveCommand);
|
||||
|
|
@ -399,45 +392,38 @@ public class OrderPlanningModel implements IOrderPlanningModel {
|
|||
setupLoadChart(chartLoadTimeplot, planner, changeHooker);
|
||||
setupEarnedValueChart(chartEarnedValueTimeplot, earnedValueChartFiller,
|
||||
planner, changeHooker);
|
||||
setupOverallProgress(planner, changeHooker);
|
||||
setupAdvanceAssignmentPlanningController(planner, advanceAssignmentPlanningController);
|
||||
PROFILING_LOG
|
||||
.info("preparing charts and miscellaneous took: "
|
||||
+ (System.currentTimeMillis() - preparingChartsAndMisc)
|
||||
+ " ms");
|
||||
|
||||
// Calculate critical path progress, needed for 'Project global progress' chart in Dashboard view
|
||||
planner.addGraphChangeListenersFromConfiguration(configuration);
|
||||
updateCriticalPathProgress();
|
||||
long overalProgressContentTime = System.currentTimeMillis();
|
||||
overallProgressContent = new OverAllProgressContent(overallProgressTab);
|
||||
overallProgressContent.updateAndRefresh();
|
||||
PROFILING_LOG.info("overalProgressContent took: "
|
||||
+ (System.currentTimeMillis() - overalProgressContentTime));
|
||||
}
|
||||
|
||||
/**
|
||||
* First time a project is loaded, it's needed to calculate the theoretical
|
||||
* critical path progress and real critical path progress. These values are
|
||||
* later updated whenever the project is saved
|
||||
*/
|
||||
private void updateCriticalPathProgress() {
|
||||
if (planningState.isEmpty() || planner == null) {
|
||||
return;
|
||||
}
|
||||
TaskGroup rootTask = planningState.getRootTask();
|
||||
rootTask.updateCriticalPathProgress(planner.getCriticalPath());
|
||||
}
|
||||
|
||||
private OrderEarnedValueChartFiller earnedValueChartFiller;
|
||||
|
||||
private void setupAdvanceAssignmentPlanningController(final Planner planner,
|
||||
AdvanceAssignmentPlanningController advanceAssignmentPlanningController) {
|
||||
|
||||
advanceAssignmentPlanningController.reloadOverallProgressListener(new IReloadChartListener() {
|
||||
|
||||
@Override
|
||||
public void reloadChart() {
|
||||
Registry.getTransactionService().runOnReadOnlyTransaction(new IOnTransaction<Void>() {
|
||||
|
||||
@Override
|
||||
public Void execute() {
|
||||
if (isExecutingOutsideZKExecution()) {
|
||||
return null;
|
||||
}
|
||||
if (planner.isVisibleChart()) {
|
||||
overallProgressContent.updateAndRefresh();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
advanceAssignmentPlanningController.setReloadEarnedValueListener(new IReloadChartListener() {
|
||||
|
||||
@Override
|
||||
|
|
@ -462,15 +448,6 @@ public class OrderPlanningModel implements IOrderPlanningModel {
|
|||
});
|
||||
}
|
||||
|
||||
private Tabpanel createOverallProgressTab(
|
||||
Hbox chartOverallProgressTimeplot) {
|
||||
Tabpanel result = new Tabpanel();
|
||||
org.zkoss.zk.ui.Component component = Executions.createComponents(
|
||||
"/planner/_tabPanelOverallProgress.zul", result, null);
|
||||
component.setParent(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private Timeplot createEmptyTimeplot() {
|
||||
Timeplot timeplot = new Timeplot();
|
||||
timeplot.appendChild(new Plotinfo());
|
||||
|
|
@ -576,24 +553,6 @@ public class OrderPlanningModel implements IOrderPlanningModel {
|
|||
setEventListenerConfigurationCheckboxes(earnedValueChart);
|
||||
}
|
||||
|
||||
private void setupOverallProgress(final Planner planner,
|
||||
ChangeHooker changeHooker) {
|
||||
|
||||
changeHooker.withReadOnlyTransactionWraping().hookInto(
|
||||
EnumSet.allOf(ChangeTypes.class), new IReloadChartListener() {
|
||||
|
||||
@Override
|
||||
public void reloadChart() {
|
||||
if (isExecutingOutsideZKExecution()) {
|
||||
return;
|
||||
}
|
||||
if (planner.isVisibleChart()) {
|
||||
overallProgressContent.updateAndRefresh();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
enum ChangeTypes {
|
||||
ON_SAVE, ON_RELOAD_CHART_REQUESTED, ON_GRAPH_CHANGED;
|
||||
}
|
||||
|
|
@ -763,8 +722,6 @@ public class OrderPlanningModel implements IOrderPlanningModel {
|
|||
Tabs chartTabs = new Tabs();
|
||||
chartTabs.appendChild(createTab(_("Load"), "load_tab"));
|
||||
chartTabs.appendChild(createTab(_("Earned value"), "earned_value_tab"));
|
||||
chartTabs.appendChild(createTab(_("Overall progress"),
|
||||
"overall_progress_tab"));
|
||||
|
||||
chartComponent.appendChild(chartTabs);
|
||||
chartTabs.setSclass("charts-tabbox");
|
||||
|
|
@ -1130,6 +1087,7 @@ public class OrderPlanningModel implements IOrderPlanningModel {
|
|||
| Messagebox.CANCEL,
|
||||
Messagebox.QUESTION,
|
||||
new org.zkoss.zk.ui.event.EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event evt)
|
||||
throws InterruptedException {
|
||||
if (evt.getName().equals("onOK")) {
|
||||
|
|
@ -1386,6 +1344,15 @@ public class OrderPlanningModel implements IOrderPlanningModel {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
* @author Diego Pino García <dpino@igalia.com>
|
||||
*
|
||||
* Calculates 'Earned Value' indicators and set them in the Order
|
||||
* 'Earned Valued' chart
|
||||
*
|
||||
*/
|
||||
class OrderEarnedValueChartFiller extends EarnedValueChartFiller {
|
||||
|
||||
private Order order;
|
||||
|
|
@ -1394,63 +1361,90 @@ public class OrderPlanningModel implements IOrderPlanningModel {
|
|||
this.order = orderReloaded;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateBudgetedCostWorkScheduled(Interval interval) {
|
||||
List<TaskElement> list = order
|
||||
.getAllChildrenAssociatedTaskElements();
|
||||
list.add(order.getAssociatedTaskElement());
|
||||
|
||||
SortedMap<LocalDate, BigDecimal> estimatedCost = new TreeMap<LocalDate, BigDecimal>();
|
||||
|
||||
for (TaskElement taskElement : list) {
|
||||
if (taskElement instanceof Task) {
|
||||
addCost(estimatedCost, hoursCostCalculator
|
||||
.getEstimatedCost((Task) taskElement));
|
||||
}
|
||||
}
|
||||
|
||||
estimatedCost = accumulateResult(estimatedCost);
|
||||
addZeroBeforeTheFirstValue(estimatedCost);
|
||||
indicators.put(EarnedValueType.BCWS, calculatedValueForEveryDay(
|
||||
estimatedCost, interval.getStart(), interval.getFinish()));
|
||||
setIndicatorInInterval(EarnedValueType.BCWS, interval,
|
||||
earnedValueCalculator
|
||||
.calculateBudgetedCostWorkScheduled(order));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateActualCostWorkPerformed(Interval interval) {
|
||||
List<TaskElement> list = order
|
||||
.getAllChildrenAssociatedTaskElements();
|
||||
list.add(order.getAssociatedTaskElement());
|
||||
|
||||
SortedMap<LocalDate, BigDecimal> workReportCost = new TreeMap<LocalDate, BigDecimal>();
|
||||
|
||||
for (TaskElement taskElement : list) {
|
||||
if (taskElement instanceof Task) {
|
||||
addCost(workReportCost, hoursCostCalculator
|
||||
.getWorkReportCost((Task) taskElement));
|
||||
}
|
||||
}
|
||||
|
||||
workReportCost = accumulateResult(workReportCost);
|
||||
addZeroBeforeTheFirstValue(workReportCost);
|
||||
indicators.put(EarnedValueType.ACWP, calculatedValueForEveryDay(
|
||||
workReportCost, interval.getStart(), interval.getFinish()));
|
||||
setIndicatorInInterval(EarnedValueType.ACWP, interval,
|
||||
earnedValueCalculator
|
||||
.calculateActualCostWorkPerformed(order));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateBudgetedCostWorkPerformed(Interval interval) {
|
||||
List<TaskElement> list = order
|
||||
.getAllChildrenAssociatedTaskElements();
|
||||
list.add(order.getAssociatedTaskElement());
|
||||
setIndicatorInInterval(EarnedValueType.BCWP, interval,
|
||||
earnedValueCalculator
|
||||
.calculateBudgetedCostWorkPerformed(order));
|
||||
}
|
||||
|
||||
SortedMap<LocalDate, BigDecimal> advanceCost = new TreeMap<LocalDate, BigDecimal>();
|
||||
@Override
|
||||
protected void calculateCostVariance() {
|
||||
setIndicator(EarnedValueType.CV,
|
||||
earnedValueCalculator.calculateCostVariance(
|
||||
getIndicator(EarnedValueType.BCWP),
|
||||
getIndicator(EarnedValueType.ACWP)));
|
||||
}
|
||||
|
||||
for (TaskElement taskElement : list) {
|
||||
if (taskElement instanceof Task) {
|
||||
addCost(advanceCost, hoursCostCalculator
|
||||
.getAdvanceCost((Task) taskElement));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void calculateScheduleVariance() {
|
||||
setIndicator(EarnedValueType.SV,
|
||||
earnedValueCalculator.calculateScheduleVariance(
|
||||
getIndicator(EarnedValueType.BCWP),
|
||||
getIndicator(EarnedValueType.BCWS)));
|
||||
}
|
||||
|
||||
addZeroBeforeTheFirstValue(advanceCost);
|
||||
indicators.put(EarnedValueType.BCWP, calculatedValueForEveryDay(
|
||||
advanceCost, interval.getStart(), interval.getFinish()));
|
||||
@Override
|
||||
protected void calculateBudgetAtCompletion() {
|
||||
setIndicator(
|
||||
EarnedValueType.BAC,
|
||||
earnedValueCalculator
|
||||
.calculateBudgetAtCompletion(getIndicator(EarnedValueType.BCWS)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateEstimateAtCompletion() {
|
||||
setIndicator(EarnedValueType.EAC,
|
||||
earnedValueCalculator.calculateEstimateAtCompletion(
|
||||
getIndicator(EarnedValueType.ACWP),
|
||||
getIndicator(EarnedValueType.BCWP),
|
||||
getIndicator(EarnedValueType.BAC)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateVarianceAtCompletion() {
|
||||
setIndicator(EarnedValueType.VAC,
|
||||
earnedValueCalculator.calculateVarianceAtCompletion(
|
||||
getIndicator(EarnedValueType.BAC),
|
||||
getIndicator(EarnedValueType.EAC)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateEstimatedToComplete() {
|
||||
setIndicator(EarnedValueType.ETC,
|
||||
earnedValueCalculator.calculateEstimatedToComplete(
|
||||
getIndicator(EarnedValueType.EAC),
|
||||
getIndicator(EarnedValueType.ACWP)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateCostPerformanceIndex() {
|
||||
setIndicator(EarnedValueType.CPI,
|
||||
earnedValueCalculator.calculateCostPerformanceIndex(
|
||||
getIndicator(EarnedValueType.BCWP),
|
||||
getIndicator(EarnedValueType.ACWP)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateSchedulePerformanceIndex() {
|
||||
setIndicator(EarnedValueType.SPI,
|
||||
earnedValueCalculator.calculateSchedulePerformanceIndex(
|
||||
getIndicator(EarnedValueType.BCWP),
|
||||
getIndicator(EarnedValueType.BCWS)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -1466,6 +1460,7 @@ public class OrderPlanningModel implements IOrderPlanningModel {
|
|||
return subcontractCommand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Order getOrder() {
|
||||
return planningState.getOrder();
|
||||
}
|
||||
|
|
@ -1505,149 +1500,4 @@ public class OrderPlanningModel implements IOrderPlanningModel {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Diego Pino García<dpino@igalia.com>
|
||||
*
|
||||
* Helper class to show the content of a OverallProgress panel
|
||||
*
|
||||
*/
|
||||
private class OverAllProgressContent {
|
||||
|
||||
private Progressmeter progressCriticalPathByDuration;
|
||||
|
||||
private Label lbCriticalPathByDuration;
|
||||
|
||||
private Progressmeter progressCriticalPathByNumHours;
|
||||
|
||||
private Label lbCriticalPathByNumHours;
|
||||
|
||||
private Progressmeter progressSpread;
|
||||
|
||||
private Label lbProgressSpread;
|
||||
|
||||
private Progressmeter progressAllByNumHours;
|
||||
|
||||
private Label lbProgressAllByNumHours;
|
||||
|
||||
public OverAllProgressContent(Tabpanel tabpanel) {
|
||||
initializeProgressCriticalPathByDuration(tabpanel);
|
||||
initializeProgressCriticalPathByNumHours(tabpanel);
|
||||
initializeProgressSpread(tabpanel);
|
||||
initializeProgressAllByNumHours(tabpanel);
|
||||
|
||||
tabpanel.setVariable("overall_progress_content", this, true);
|
||||
}
|
||||
|
||||
private void initializeProgressCriticalPathByNumHours(Tabpanel tabpanel) {
|
||||
progressCriticalPathByNumHours = (Progressmeter) tabpanel
|
||||
.getFellow("progressCriticalPathByNumHours");
|
||||
lbCriticalPathByNumHours = (Label) tabpanel
|
||||
.getFellow("lbCriticalPathByNumHours");
|
||||
((Label) tabpanel.getFellow("textCriticalPathByNumHours"))
|
||||
.setValue(_(ProgressType.CRITICAL_PATH_NUMHOURS.toString()));
|
||||
}
|
||||
|
||||
private void initializeProgressCriticalPathByDuration(Tabpanel tabpanel) {
|
||||
progressCriticalPathByDuration = (Progressmeter) tabpanel
|
||||
.getFellow("progressCriticalPathByDuration");
|
||||
lbCriticalPathByDuration = (Label) tabpanel
|
||||
.getFellow("lbCriticalPathByDuration");
|
||||
((Label) tabpanel.getFellow("textCriticalPathByDuration"))
|
||||
.setValue(_(ProgressType.CRITICAL_PATH_DURATION.toString()));
|
||||
}
|
||||
|
||||
public void initializeProgressSpread(Tabpanel tabpanel) {
|
||||
progressSpread = (Progressmeter) tabpanel
|
||||
.getFellow("progressSpread");
|
||||
lbProgressSpread = (Label) tabpanel.getFellow("lbProgressSpread");
|
||||
((Label) tabpanel.getFellow("textProgressSpread"))
|
||||
.setValue(_(ProgressType.SPREAD_PROGRESS.toString()));
|
||||
}
|
||||
|
||||
public void initializeProgressAllByNumHours(Tabpanel tabpanel) {
|
||||
progressAllByNumHours = (Progressmeter) tabpanel
|
||||
.getFellow("progressAllByNumHours");
|
||||
lbProgressAllByNumHours = (Label) tabpanel
|
||||
.getFellow("lbProgressAllByNumHours");
|
||||
((Label) tabpanel.getFellow("textProgressAllByNumHours"))
|
||||
.setValue(_(ProgressType.ALL_NUMHOURS.toString()));
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
if (planningState.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
TaskGroup rootTask = planningState.getRootTask();
|
||||
|
||||
setProgressSpread(rootTask.getAdvancePercentage());
|
||||
setProgressAllByNumHours(rootTask.getProgressAllByNumHours());
|
||||
setCriticalPathByDuration(rootTask
|
||||
.getCriticalPathProgressByDuration());
|
||||
setCriticalPathByNumHours(rootTask
|
||||
.getCriticalPathProgressByNumHours());
|
||||
}
|
||||
|
||||
private void updateAndRefresh() {
|
||||
if (planningState.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
update();
|
||||
refresh();
|
||||
}
|
||||
|
||||
private void update() {
|
||||
TaskGroup rootTask = planningState.getRootTask();
|
||||
updateCriticalPathProgress(rootTask);
|
||||
}
|
||||
|
||||
private void updateCriticalPathProgress(TaskGroup rootTask) {
|
||||
if (planner != null) {
|
||||
rootTask.updateCriticalPathProgress((List<TaskElement>) planner
|
||||
.getCriticalPath());
|
||||
}
|
||||
}
|
||||
|
||||
private void setProgressSpread(BigDecimal value) {
|
||||
if (value == null) {
|
||||
value = BigDecimal.ZERO;
|
||||
}
|
||||
value = value.multiply(BigDecimal.valueOf(100));
|
||||
value = value.setScale(2, BigDecimal.ROUND_HALF_EVEN);
|
||||
lbProgressSpread.setValue(value.toString() + " %");
|
||||
progressSpread.setValue(value.intValue());
|
||||
}
|
||||
|
||||
private void setProgressAllByNumHours(BigDecimal value) {
|
||||
if (value == null) {
|
||||
value = BigDecimal.ZERO;
|
||||
}
|
||||
value = value.multiply(BigDecimal.valueOf(100));
|
||||
value = value.setScale(2, BigDecimal.ROUND_HALF_EVEN);
|
||||
lbProgressAllByNumHours.setValue(value.toString() + " %");
|
||||
progressAllByNumHours.setValue(value.intValue());
|
||||
}
|
||||
|
||||
public void setCriticalPathByDuration(BigDecimal value) {
|
||||
if (value == null) {
|
||||
value = BigDecimal.ZERO;
|
||||
}
|
||||
value = value.multiply(BigDecimal.valueOf(100));
|
||||
value = value.setScale(2, BigDecimal.ROUND_HALF_EVEN);
|
||||
lbCriticalPathByDuration.setValue(value.toString() + " %");
|
||||
progressCriticalPathByDuration.setValue(value.intValue());
|
||||
}
|
||||
|
||||
public void setCriticalPathByNumHours(BigDecimal value) {
|
||||
if (value == null) {
|
||||
value = BigDecimal.ZERO;
|
||||
}
|
||||
value = value.multiply(BigDecimal.valueOf(100));
|
||||
value = value.setScale(2, BigDecimal.ROUND_HALF_EVEN);
|
||||
lbCriticalPathByNumHours.setValue(value.toString() + " %");
|
||||
progressCriticalPathByNumHours.setValue(value.intValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ import org.libreplan.business.planner.entities.ResourceAllocation;
|
|||
import org.libreplan.business.planner.entities.ResourceAllocation.IVisitor;
|
||||
import org.libreplan.business.planner.entities.SpecificResourceAllocation;
|
||||
import org.libreplan.business.planner.entities.StretchesFunction;
|
||||
import org.libreplan.business.planner.entities.SubcontractorDeliverDate;
|
||||
import org.libreplan.business.planner.entities.Task;
|
||||
import org.libreplan.business.planner.entities.TaskElement;
|
||||
import org.libreplan.business.planner.entities.TaskGroup;
|
||||
|
|
@ -333,6 +334,7 @@ public class PlanningStateCreator {
|
|||
private void forceLoadOfDataAssociatedTo(TaskElement each) {
|
||||
forceLoadOfResourceAllocationsResourcesAndAssignmentFunction(each);
|
||||
forceLoadOfCriterions(each);
|
||||
forceLoadOfSubcontractedTaskData(each);
|
||||
|
||||
BaseCalendar calendar = each.getOwnCalendar();
|
||||
if (calendar == null) {
|
||||
|
|
@ -392,6 +394,18 @@ public class PlanningStateCreator {
|
|||
}
|
||||
}
|
||||
|
||||
private static void forceLoadOfSubcontractedTaskData(TaskElement taskElement){
|
||||
if(taskElement.isLeaf()){
|
||||
if(((Task)taskElement).getSubcontractedTaskData() != null){
|
||||
for (SubcontractorDeliverDate subDeliverDate : ((Task) taskElement)
|
||||
.getSubcontractedTaskData()
|
||||
.getRequiredDeliveringDates()) {
|
||||
subDeliverDate.getSaveDate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void findChildrenWithQueryToAvoidProxies(TaskGroup group) {
|
||||
for (TaskElement eachTask : taskDAO.findChildrenOf(group)) {
|
||||
Hibernate.initialize(eachTask);
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@ import org.libreplan.business.planner.entities.DerivedAllocation;
|
|||
import org.libreplan.business.planner.entities.DerivedDayAssignment;
|
||||
import org.libreplan.business.planner.entities.DerivedDayAssignmentsContainer;
|
||||
import org.libreplan.business.planner.entities.ResourceAllocation;
|
||||
import org.libreplan.business.planner.entities.SubcontractedTaskData;
|
||||
import org.libreplan.business.planner.entities.SubcontractorDeliverDate;
|
||||
import org.libreplan.business.planner.entities.Task;
|
||||
import org.libreplan.business.planner.entities.TaskElement;
|
||||
import org.libreplan.business.planner.entities.TaskGroup;
|
||||
|
|
@ -120,6 +122,7 @@ import org.zkoss.zul.Messagebox;
|
|||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
public class SaveCommandBuilder {
|
||||
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(SaveCommandBuilder.class);
|
||||
|
||||
public ISaveCommand build(PlanningState planningState,
|
||||
|
|
@ -291,6 +294,8 @@ public class SaveCommandBuilder {
|
|||
}
|
||||
});
|
||||
dontPoseAsTransientObjectAnymore(state.getOrder());
|
||||
dontPoseAsTransientObjectAnymore(state.getOrder()
|
||||
.getEndDateCommunicationToCustomer());
|
||||
state.getScenarioInfo().afterCommit();
|
||||
|
||||
if (state.getOrder()
|
||||
|
|
@ -359,6 +364,7 @@ public class SaveCommandBuilder {
|
|||
state.synchronizeTrees();
|
||||
|
||||
TaskGroup rootTask = state.getRootTask();
|
||||
|
||||
if (rootTask != null) {
|
||||
// This reattachment is needed to ensure that the root task in
|
||||
// the state is the one associated to the transaction's session.
|
||||
|
|
@ -375,6 +381,7 @@ public class SaveCommandBuilder {
|
|||
|
||||
updateTasksRelatedData();
|
||||
removeTasksToRemove();
|
||||
loadDataAccessedWithNotPosedAsTransientInOrder(state.getOrder());
|
||||
loadDataAccessedWithNotPosedAsTransient(state.getOrder());
|
||||
if (state.getRootTask() != null) {
|
||||
loadDependenciesCollectionsForTaskRoot(state.getRootTask());
|
||||
|
|
@ -812,6 +819,10 @@ public class SaveCommandBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
private void loadDataAccessedWithNotPosedAsTransientInOrder(Order order) {
|
||||
order.getEndDateCommunicationToCustomer().size();
|
||||
}
|
||||
|
||||
private void loadDataAccessedWithNotPosedAsTransient(
|
||||
OrderElement orderElement) {
|
||||
orderElement.getDirectAdvanceAssignments().size();
|
||||
|
|
@ -986,6 +997,7 @@ public class SaveCommandBuilder {
|
|||
}
|
||||
if (taskElement instanceof Task) {
|
||||
dontPoseAsTransient(((Task) taskElement).getConsolidation());
|
||||
dontPoseAsTransient(((Task) taskElement).getSubcontractedTaskData());
|
||||
}
|
||||
if (taskElement instanceof TaskGroup) {
|
||||
((TaskGroup) taskElement).dontPoseAsTransientPlanningData();
|
||||
|
|
@ -1005,6 +1017,19 @@ public class SaveCommandBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
private void dontPoseAsTransient(SubcontractedTaskData subcontractedTaskData) {
|
||||
if (subcontractedTaskData != null) {
|
||||
//dontPoseAsTransient - subcontratedTaskData
|
||||
subcontractedTaskData.dontPoseAsTransientObjectAnymore();
|
||||
|
||||
for (SubcontractorDeliverDate subDeliverDate : subcontractedTaskData
|
||||
.getRequiredDeliveringDates()) {
|
||||
//dontPoseAsTransient - DeliverDate
|
||||
subDeliverDate.dontPoseAsTransientObjectAnymore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void dontPoseAsTransient(
|
||||
SortedSet<? extends ConsolidatedValue> values) {
|
||||
for (ConsolidatedValue value : values) {
|
||||
|
|
|
|||
|
|
@ -21,21 +21,42 @@
|
|||
|
||||
package org.libreplan.web.planner.order;
|
||||
|
||||
import static org.libreplan.web.I18nHelper._;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.business.externalcompanies.entities.EndDateCommunication;
|
||||
import org.libreplan.business.externalcompanies.entities.ExternalCompany;
|
||||
import org.libreplan.business.planner.entities.SubcontractState;
|
||||
import org.libreplan.business.planner.entities.SubcontractedTaskData;
|
||||
import org.libreplan.business.planner.entities.SubcontractorDeliverDate;
|
||||
import org.libreplan.business.planner.entities.Task;
|
||||
import org.libreplan.business.planner.entities.TaskElement;
|
||||
import org.libreplan.web.common.IMessagesForUser;
|
||||
import org.libreplan.web.common.Level;
|
||||
import org.libreplan.web.common.MessagesForUser;
|
||||
import org.libreplan.web.common.Util;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.zkoss.ganttz.TaskEditFormComposer;
|
||||
import org.zkoss.ganttz.extensions.IContextWithPlannerTask;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zk.ui.event.Event;
|
||||
import org.zkoss.zk.ui.event.EventListener;
|
||||
import org.zkoss.zk.ui.event.Events;
|
||||
import org.zkoss.zk.ui.util.GenericForwardComposer;
|
||||
import org.zkoss.zul.Button;
|
||||
import org.zkoss.zul.Comboitem;
|
||||
import org.zkoss.zul.Grid;
|
||||
import org.zkoss.zul.Hbox;
|
||||
import org.zkoss.zul.Label;
|
||||
import org.zkoss.zul.Row;
|
||||
import org.zkoss.zul.RowRenderer;
|
||||
import org.zkoss.zul.api.Datebox;
|
||||
import org.zkoss.zul.api.Tabpanel;
|
||||
|
||||
/**
|
||||
|
|
@ -51,15 +72,32 @@ public class SubcontractController extends GenericForwardComposer {
|
|||
|
||||
private ISubcontractModel subcontractModel;
|
||||
|
||||
private Grid gridDeliverDate;
|
||||
|
||||
private DeliverDatesRenderer deliverDatesRenderer = new DeliverDatesRenderer();
|
||||
|
||||
protected IMessagesForUser messagesForUser;
|
||||
|
||||
private Component messagesContainer;
|
||||
|
||||
private IContextWithPlannerTask<TaskElement> currentContext;
|
||||
|
||||
private Grid gridEndDates;
|
||||
|
||||
private TaskEditFormComposer taskEditFormComposer = new TaskEditFormComposer();
|
||||
|
||||
@Override
|
||||
public void doAfterCompose(Component comp) throws Exception {
|
||||
super.doAfterCompose(comp);
|
||||
tabpanel = (Tabpanel) comp;
|
||||
messagesForUser = new MessagesForUser(messagesContainer);
|
||||
}
|
||||
|
||||
public void init(Task task,
|
||||
IContextWithPlannerTask<TaskElement> context) {
|
||||
public void init(Task task, IContextWithPlannerTask<TaskElement> context,
|
||||
TaskEditFormComposer taskEditFormComposer) {
|
||||
this.currentContext = context;
|
||||
subcontractModel.init(task, context.getTask());
|
||||
this.taskEditFormComposer = taskEditFormComposer;
|
||||
Util.reloadBindings(tabpanel);
|
||||
}
|
||||
|
||||
|
|
@ -101,8 +139,216 @@ public class SubcontractController extends GenericForwardComposer {
|
|||
subcontractModel.removeSubcontractedTaskData();
|
||||
}
|
||||
|
||||
public SortedSet<SubcontractorDeliverDate> getDeliverDates() {
|
||||
return subcontractModel.getDeliverDates();
|
||||
}
|
||||
|
||||
public void addDeliverDate(Datebox newDeliverDate){
|
||||
if (newDeliverDate == null || newDeliverDate.getValue() == null) {
|
||||
messagesForUser.showMessage(Level.ERROR,
|
||||
_("You must select a valid date. "));
|
||||
return;
|
||||
}
|
||||
if (thereIsSomeCommunicationDateEmpty()) {
|
||||
messagesForUser
|
||||
.showMessage(
|
||||
Level.ERROR,
|
||||
_("It will only be possible to add a Deliver Date if all the deliver date exiting in the table have a CommunicationDate not empty. "));
|
||||
return;
|
||||
}
|
||||
if(subcontractModel.alreadyExistsRepeatedDeliverDate(newDeliverDate.getValue())){
|
||||
messagesForUser
|
||||
.showMessage(
|
||||
Level.ERROR,
|
||||
_("It already exists a deliver date with the same date. "));
|
||||
return;
|
||||
}
|
||||
subcontractModel.addDeliverDate(newDeliverDate.getValue());
|
||||
Util.reloadBindings(gridDeliverDate);
|
||||
gridDeliverDate.invalidate();
|
||||
}
|
||||
|
||||
private boolean thereIsSomeCommunicationDateEmpty(){
|
||||
for(SubcontractorDeliverDate subDeliverDate : subcontractModel.getDeliverDates()){
|
||||
if(subDeliverDate.getCommunicationDate() == null){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public DeliverDatesRenderer getDeliverDatesRenderer(){
|
||||
return new DeliverDatesRenderer();
|
||||
}
|
||||
|
||||
private class DeliverDatesRenderer implements RowRenderer{
|
||||
|
||||
@Override
|
||||
public void render(Row row, Object data) throws Exception {
|
||||
SubcontractorDeliverDate subcontractorDeliverDate = (SubcontractorDeliverDate) data;
|
||||
row.setValue(subcontractorDeliverDate);
|
||||
|
||||
appendLabel(row, SubcontractController.this.toString(
|
||||
subcontractorDeliverDate.getSaveDate(), "dd/MM/yyyy HH:mm"));
|
||||
appendLabel(
|
||||
row,
|
||||
SubcontractController.this.toString(
|
||||
subcontractorDeliverDate.getSubcontractorDeliverDate(), "dd/MM/yyyy"));
|
||||
appendLabel(
|
||||
row,
|
||||
SubcontractController.this.toString(
|
||||
subcontractorDeliverDate.getCommunicationDate(), "dd/MM/yyyy HH:mm"));
|
||||
appendOperations(row, subcontractorDeliverDate);
|
||||
}
|
||||
|
||||
private void appendLabel(Row row, String label) {
|
||||
row.appendChild(new Label(label));
|
||||
}
|
||||
|
||||
private void appendOperations(Row row,
|
||||
SubcontractorDeliverDate subcontractorDeliverDate) {
|
||||
Hbox hbox = new Hbox();
|
||||
hbox.appendChild(getDeleteButton(subcontractorDeliverDate));
|
||||
row.appendChild(hbox);
|
||||
}
|
||||
|
||||
private Button getDeleteButton(
|
||||
final SubcontractorDeliverDate subcontractorDeliverDate) {
|
||||
|
||||
Button deleteButton = new Button();
|
||||
deleteButton.setDisabled(isNotUpdate(subcontractorDeliverDate));
|
||||
deleteButton.setSclass("icono");
|
||||
deleteButton.setImage("/common/img/ico_borrar1.png");
|
||||
deleteButton.setHoverImage("/common/img/ico_borrar.png");
|
||||
deleteButton.setTooltiptext(_("Delete"));
|
||||
deleteButton.addEventListener(Events.ON_CLICK, new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
removeRequiredDeliverDate(subcontractorDeliverDate);
|
||||
}
|
||||
});
|
||||
|
||||
return deleteButton;
|
||||
}
|
||||
|
||||
private boolean isNotUpdate(final SubcontractorDeliverDate subDeliverDate){
|
||||
SubcontractorDeliverDate lastDeliverDate = getSubcontractedTaskData()
|
||||
.getRequiredDeliveringDates().first();
|
||||
if ((lastDeliverDate != null) && (lastDeliverDate.equals(subDeliverDate))) {
|
||||
return (lastDeliverDate.getCommunicationDate() != null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeRequiredDeliverDate(SubcontractorDeliverDate subcontractorDeliverDate){
|
||||
subcontractModel.removeRequiredDeliverDate(subcontractorDeliverDate);
|
||||
Util.reloadBindings(gridDeliverDate);
|
||||
}
|
||||
|
||||
public boolean isSent(){
|
||||
return !isNotSent();
|
||||
}
|
||||
|
||||
public boolean isNotSent() {
|
||||
if (this.getSubcontractedTaskData() != null && this.getSubcontractedTaskData().getState() != null) {
|
||||
return ((this.getSubcontractedTaskData().getState()
|
||||
.equals(SubcontractState.PENDING_INITIAL_SEND)) || (this
|
||||
.getSubcontractedTaskData().getState()
|
||||
.equals(SubcontractState.FAILED_SENT)));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String toString(Date date, String precision) {
|
||||
if (date == null) {
|
||||
return "";
|
||||
}
|
||||
return new SimpleDateFormat(precision).format(date);
|
||||
}
|
||||
|
||||
public SortedSet<EndDateCommunication> getAskedEndDates() {
|
||||
return subcontractModel.getAskedEndDates();
|
||||
}
|
||||
|
||||
public EndDatesRenderer getEndDatesRenderer() {
|
||||
return new EndDatesRenderer();
|
||||
}
|
||||
|
||||
private class EndDatesRenderer implements RowRenderer {
|
||||
|
||||
@Override
|
||||
public void render(Row row, Object data) throws Exception {
|
||||
EndDateCommunication endDateFromSubcontractor = (EndDateCommunication) data;
|
||||
row.setValue(endDateFromSubcontractor);
|
||||
|
||||
appendLabel(row, SubcontractController.this.toString(
|
||||
endDateFromSubcontractor.getEndDate(), "dd/MM/yyyy"));
|
||||
appendLabel(row,
|
||||
SubcontractController.this.toString(
|
||||
endDateFromSubcontractor.getCommunicationDate(), "dd/MM/yyyy HH:mm"));
|
||||
appendOperations(row, endDateFromSubcontractor);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void appendLabel(Row row, String label) {
|
||||
row.appendChild(new Label(label));
|
||||
}
|
||||
|
||||
private void appendOperations(Row row,
|
||||
EndDateCommunication endDateFromSubcontractor) {
|
||||
Hbox hbox = new Hbox();
|
||||
hbox.appendChild(getUpdateButton(endDateFromSubcontractor));
|
||||
row.appendChild(hbox);
|
||||
}
|
||||
|
||||
private Button getUpdateButton(final EndDateCommunication endDateFromSubcontractor) {
|
||||
|
||||
Button updateButton = new Button(_("Update task end"));
|
||||
updateButton.setDisabled(!isUpgradeable(endDateFromSubcontractor));
|
||||
|
||||
updateButton.setTooltiptext(_("Update task end"));
|
||||
updateButton.addEventListener(Events.ON_CLICK, new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
updateTaskEnd(endDateFromSubcontractor.getEndDate());
|
||||
}
|
||||
});
|
||||
|
||||
return updateButton;
|
||||
}
|
||||
|
||||
private boolean isUpgradeable(EndDateCommunication endDateFromSubcontractor) {
|
||||
EndDateCommunication lastEndDateReported = getSubcontractedTaskData()
|
||||
.getLastEndDatesCommunicatedFromSubcontractor();
|
||||
if (lastEndDateReported != null) {
|
||||
if (lastEndDateReported.equals(endDateFromSubcontractor)) {
|
||||
Date newEndDate = lastEndDateReported.getEndDate();
|
||||
Date endDateTask = taskEditFormComposer.getTaskDTO().deadlineDate;
|
||||
if (endDateTask != null) {
|
||||
return (newEndDate.compareTo(endDateTask) != 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void updateTaskEnd(Date date) {
|
||||
if (taskEditFormComposer != null) {
|
||||
taskEditFormComposer.getTaskDTO().deadlineDate = date;
|
||||
}
|
||||
refressGridEndDates();
|
||||
}
|
||||
|
||||
public void refressGridEndDates() {
|
||||
Util.reloadBindings(gridEndDates);
|
||||
}
|
||||
|
||||
public String getMoneyFormat() {
|
||||
return Util.getMoneyFormat();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -23,25 +23,31 @@ package org.libreplan.web.planner.order;
|
|||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.business.externalcompanies.daos.IExternalCompanyDAO;
|
||||
import org.libreplan.business.externalcompanies.entities.EndDateCommunication;
|
||||
import org.libreplan.business.externalcompanies.entities.ExternalCompany;
|
||||
import org.libreplan.business.planner.daos.ISubcontractedTaskDataDAO;
|
||||
import org.libreplan.business.planner.entities.SubcontractState;
|
||||
import org.libreplan.business.planner.entities.SubcontractedTaskData;
|
||||
import org.libreplan.business.planner.entities.SubcontractorDeliverDate;
|
||||
import org.libreplan.business.planner.entities.Task;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.zkoss.ganttz.data.GanttDate;
|
||||
|
||||
/**
|
||||
* Model for UI operations related with subcontract process and
|
||||
* {@link SubcontractedTaskData} entity.
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
@Service
|
||||
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
||||
|
|
@ -75,16 +81,39 @@ public class SubcontractModel implements ISubcontractModel {
|
|||
|
||||
SubcontractedTaskData subcontractedTaskData = task
|
||||
.getSubcontractedTaskData();
|
||||
|
||||
this.currentSubcontractedTaskData = subcontractedTaskData;
|
||||
|
||||
if (subcontractedTaskData == null) {
|
||||
this.subcontractedTaskData = SubcontractedTaskData.create(task);
|
||||
this.addDeliverDate(getEndDate());
|
||||
} else {
|
||||
subcontractedTaskDataDAO.reattach(subcontractedTaskData);
|
||||
loadRequiredDeliveringDates(subcontractedTaskData);
|
||||
loadAskedEndDatesFromSubcontractor(subcontractedTaskData);
|
||||
this.subcontractedTaskData = SubcontractedTaskData
|
||||
.createFrom(subcontractedTaskData);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadAskedEndDatesFromSubcontractor(SubcontractedTaskData subcontractedTaskData) {
|
||||
if (subcontractedTaskData != null) {
|
||||
for (EndDateCommunication askedEndDate : subcontractedTaskData
|
||||
.getEndDatesCommunicatedFromSubcontractor()) {
|
||||
askedEndDate.getEndDate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadRequiredDeliveringDates(SubcontractedTaskData subcontractedTaskData){
|
||||
if(subcontractedTaskData != null){
|
||||
for (SubcontractorDeliverDate subDeliverDate : subcontractedTaskData
|
||||
.getRequiredDeliveringDates()) {
|
||||
subDeliverDate.getSaveDate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubcontractedTaskData getSubcontractedTaskData() {
|
||||
return subcontractedTaskData;
|
||||
|
|
@ -166,4 +195,92 @@ public class SubcontractModel implements ISubcontractModel {
|
|||
subcontractedTaskData = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<SubcontractorDeliverDate> getDeliverDates(){
|
||||
if(subcontractedTaskData != null){
|
||||
return subcontractedTaskData.getRequiredDeliveringDates();
|
||||
}
|
||||
return new TreeSet<SubcontractorDeliverDate>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDeliverDate(Date subDeliverDate){
|
||||
if(subcontractedTaskData != null){
|
||||
SubcontractorDeliverDate subcontractorDeliverDate = SubcontractorDeliverDate
|
||||
.create(new Date(), subDeliverDate, null);
|
||||
subcontractedTaskData
|
||||
.addRequiredDeliveringDates(subcontractorDeliverDate);
|
||||
|
||||
//update the end date of the task
|
||||
updateEndDateWithDeliverDate();
|
||||
|
||||
//update the state of the subcontracted task data
|
||||
updateStateToPendingUpdateDeliveringDate();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateEndDateWithDeliverDate(){
|
||||
SubcontractorDeliverDate lastDeliverDate = this
|
||||
.getSubcontractedTaskData().getRequiredDeliveringDates().last();
|
||||
task.setEndDate(lastDeliverDate.getSubcontractorDeliverDate());
|
||||
}
|
||||
|
||||
private void updateStateToPendingUpdateDeliveringDate(){
|
||||
if ((subcontractedTaskData.getState() != null)
|
||||
&& (subcontractedTaskData.getState()
|
||||
.equals(SubcontractState.SUCCESS_SENT))) {
|
||||
subcontractedTaskData
|
||||
.setState(SubcontractState.PENDING_UPDATE_DELIVERING_DATE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alreadyExistsRepeatedDeliverDate(Date newDeliverDate) {
|
||||
if (this.getSubcontractedTaskData().getRequiredDeliveringDates()
|
||||
.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SubcontractorDeliverDate currentSubDeliverDate = this
|
||||
.getSubcontractedTaskData().getRequiredDeliveringDates()
|
||||
.first();
|
||||
|
||||
Date deliverDate = new LocalDate(newDeliverDate)
|
||||
.toDateTimeAtStartOfDay().toDate();
|
||||
Date currentDeliverDate = new LocalDate(
|
||||
currentSubDeliverDate.getSubcontractorDeliverDate())
|
||||
.toDateTimeAtStartOfDay().toDate();
|
||||
|
||||
return (currentDeliverDate.compareTo(deliverDate) == 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRequiredDeliverDate(
|
||||
SubcontractorDeliverDate subcontractorDeliverDate) {
|
||||
if(subcontractedTaskData != null){
|
||||
subcontractedTaskData.removeRequiredDeliveringDates(subcontractorDeliverDate);
|
||||
updateStateFromPendingDeliveringDateToSuccessSent();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateStateFromPendingDeliveringDateToSuccessSent(){
|
||||
if (subcontractedTaskData.getState() != null) {
|
||||
switch (subcontractedTaskData.getState()) {
|
||||
case PENDING_UPDATE_DELIVERING_DATE:
|
||||
case FAILED_UPDATE:
|
||||
subcontractedTaskData
|
||||
.setState(SubcontractState.SUCCESS_SENT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<EndDateCommunication> getAskedEndDates() {
|
||||
if (subcontractedTaskData != null) {
|
||||
return subcontractedTaskData.getEndDatesCommunicatedFromSubcontractor();
|
||||
}
|
||||
return new TreeSet<EndDateCommunication>();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
|
||||
* Desenvolvemento Tecnolóxico de Galicia
|
||||
* Copyright (C) 2010-2011 Igalia, S.L.
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
|
|
@ -22,6 +23,7 @@ package org.libreplan.web.planner.tabs;
|
|||
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderElement;
|
||||
import org.libreplan.business.planner.entities.TaskElement;
|
||||
import org.libreplan.business.templates.entities.OrderTemplate;
|
||||
import org.libreplan.web.common.entrypoints.EntryPoint;
|
||||
import org.libreplan.web.common.entrypoints.EntryPoints;
|
||||
|
|
@ -30,6 +32,7 @@ import org.libreplan.web.common.entrypoints.EntryPoints;
|
|||
* Entry points for {@link MultipleTabsPlannerController} <br />
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
|
||||
*/
|
||||
@EntryPoints(page = "/planner/index.zul", registerAs = "globalView")
|
||||
|
|
@ -65,4 +68,10 @@ public interface IGlobalViewEntryPoints {
|
|||
@EntryPoint("order_advanced_allocation")
|
||||
void goToAdvancedAllocation(Order order);
|
||||
|
||||
@EntryPoint("create_order_from_template")
|
||||
void goToCreateotherOrderFromTemplate(OrderTemplate template);
|
||||
|
||||
@EntryPoint({"order","task"})
|
||||
void goToAdvanceTask(Order order,TaskElement task);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
* Desenvolvemento Tecnolóxico de Galicia
|
||||
* Copyright (C) 2010-2011 Igalia, S.L.
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
|
|
@ -40,8 +42,6 @@ import org.libreplan.web.dashboard.DashboardController;
|
|||
import org.libreplan.web.limitingresources.LimitingResourcesController;
|
||||
import org.libreplan.web.montecarlo.MonteCarloController;
|
||||
import org.libreplan.web.orders.OrderCRUDController;
|
||||
import org.libreplan.web.orders.assigntemplates.TemplateFinderPopup;
|
||||
import org.libreplan.web.orders.assigntemplates.TemplateFinderPopup.IOnResult;
|
||||
import org.libreplan.web.planner.allocation.AdvancedAllocationController.IBack;
|
||||
import org.libreplan.web.planner.company.CompanyPlanningController;
|
||||
import org.libreplan.web.planner.order.IOrderPlanningGate;
|
||||
|
|
@ -63,7 +63,6 @@ import org.zkoss.ganttz.adapters.TabsConfiguration;
|
|||
import org.zkoss.ganttz.adapters.TabsConfiguration.ChangeableTab;
|
||||
import org.zkoss.ganttz.extensions.ITab;
|
||||
import org.zkoss.ganttz.extensions.TabProxy;
|
||||
import org.zkoss.ganttz.resourceload.ResourcesLoadPanel.IToolbarCommand;
|
||||
import org.zkoss.ganttz.util.LongOperationFeedback;
|
||||
import org.zkoss.ganttz.util.LongOperationFeedback.ILongOperation;
|
||||
import org.zkoss.zk.ui.Executions;
|
||||
|
|
@ -71,7 +70,6 @@ import org.zkoss.zk.ui.event.Event;
|
|||
import org.zkoss.zk.ui.event.EventListener;
|
||||
import org.zkoss.zk.ui.event.Events;
|
||||
import org.zkoss.zk.ui.util.Composer;
|
||||
import org.zkoss.zul.Button;
|
||||
|
||||
/**
|
||||
* Creates and handles several tabs
|
||||
|
|
@ -229,6 +227,7 @@ public class MultipleTabsPlannerController implements Composer,
|
|||
public void goToTaskResourceAllocation(Order order,
|
||||
TaskElement task) {
|
||||
orderPlanningController.setShowedTask(task);
|
||||
orderPlanningController.setCurrentControllerToShow(orderPlanningController.getEditTaskController());
|
||||
getTabsRegistry()
|
||||
.show(planningTab, changeModeTo(order));
|
||||
}
|
||||
|
|
@ -475,6 +474,21 @@ public class MultipleTabsPlannerController implements Composer,
|
|||
getTabsRegistry().show(advancedAllocationTab, changeModeTo(order));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void goToCreateotherOrderFromTemplate(OrderTemplate template) {
|
||||
getTabsRegistry().show(ordersTab);
|
||||
orderCRUDController.showCreateFormFromTemplate(template);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void goToAdvanceTask(Order order,TaskElement task) {
|
||||
orderPlanningController.setShowedTask(task);
|
||||
orderPlanningController
|
||||
.setCurrentControllerToShow(orderPlanningController
|
||||
.getAdvanceAssignmentPlanningController());
|
||||
getTabsRegistry().show(planningTab, changeModeTo(order));
|
||||
}
|
||||
|
||||
private IBeforeShowAction changeModeTo(final Order order) {
|
||||
return new IBeforeShowAction() {
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -174,7 +174,9 @@ public class EditTaskController extends GenericForwardComposer {
|
|||
|
||||
if (ResourceAllocationTypeEnum.SUBCONTRACT
|
||||
.equals(resourceAllocationType)) {
|
||||
subcontractController.init(asTask(taskElement), context);
|
||||
|
||||
subcontractController.init(asTask(taskElement), context,
|
||||
taskPropertiesController.getTaskEditFormComposer());
|
||||
showSubcontractTab();
|
||||
} else if (ResourceAllocationTypeEnum.NON_LIMITING_RESOURCES
|
||||
.equals(resourceAllocationType)) {
|
||||
|
|
@ -186,7 +188,6 @@ public class EditTaskController extends GenericForwardComposer {
|
|||
planningState, messagesForUser);
|
||||
showLimitingResourcesTab();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void showSubcontractTab() {
|
||||
|
|
@ -382,5 +383,4 @@ public class EditTaskController extends GenericForwardComposer {
|
|||
public Integer getStatus() {
|
||||
return (Integer) self.getVariable("status", true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,12 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.libreplan.business.advance.bootstrap.PredefinedAdvancedTypes;
|
||||
import org.libreplan.business.advance.entities.AdvanceType;
|
||||
import org.libreplan.business.advance.entities.DirectAdvanceAssignment;
|
||||
import org.libreplan.business.advance.exceptions.DuplicateAdvanceAssignmentForOrderElementException;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderElement;
|
||||
import org.libreplan.business.planner.entities.ITaskPositionConstrained;
|
||||
import org.libreplan.business.planner.entities.PositionConstraintType;
|
||||
import org.libreplan.business.planner.entities.Task;
|
||||
|
|
@ -94,6 +99,8 @@ public class TaskPropertiesController extends GenericForwardComposer {
|
|||
|
||||
private Datebox endDateBox;
|
||||
|
||||
private Datebox deadLineDateBox;
|
||||
|
||||
private Combobox startConstraintTypes;
|
||||
|
||||
private Datebox startConstraintDate;
|
||||
|
|
@ -165,6 +172,12 @@ public class TaskPropertiesController extends GenericForwardComposer {
|
|||
return topTask.getParent().getOrderElement().getOrder();
|
||||
}
|
||||
|
||||
private OrderElement findOrderElementIn(IContextWithPlannerTask<TaskElement> context) {
|
||||
TaskElement topTask = context.getMapper().findAssociatedDomainObject(
|
||||
findTopMostTask(context));
|
||||
return topTask.getOrderElement();
|
||||
}
|
||||
|
||||
private org.zkoss.ganttz.data.Task findTopMostTask(
|
||||
IContextWithPlannerTask<TaskElement> context) {
|
||||
List<? extends TaskContainer> parents = context.getMapper().getParents(
|
||||
|
|
@ -325,9 +338,20 @@ public class TaskPropertiesController extends GenericForwardComposer {
|
|||
restoreOldState();
|
||||
editTaskController.showNonPermitChangeResourceAllocationType();
|
||||
} else {
|
||||
changeResourceAllocationType(oldState, newState);
|
||||
editTaskController.selectAssignmentTab(lbResourceAllocationType
|
||||
if(newState.equals(ResourceAllocationTypeEnum.SUBCONTRACT) && checkCompatibleAllocation()){
|
||||
changeResourceAllocationType(oldState, newState);
|
||||
editTaskController.selectAssignmentTab(lbResourceAllocationType
|
||||
.getSelectedIndex() + 1);
|
||||
}else{
|
||||
try {
|
||||
restoreOldState();
|
||||
Messagebox.show(_("This resource allocation type is incompatible. The task has an associated order element which has a progress that is of type subcontractor. "),
|
||||
_("Error"), Messagebox.OK , Messagebox.ERROR);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oldState == null) {
|
||||
|
|
@ -349,6 +373,30 @@ public class TaskPropertiesController extends GenericForwardComposer {
|
|||
|
||||
}
|
||||
|
||||
private boolean checkCompatibleAllocation(){
|
||||
OrderElement orderElement = null;
|
||||
AdvanceType advanceType = PredefinedAdvancedTypes.SUBCONTRACTOR.getType();
|
||||
|
||||
if (this.currentContext != null) {
|
||||
orderElement = findOrderElementIn(this.currentContext );
|
||||
} else {
|
||||
orderElement = this.currentTaskElement.getOrderElement();
|
||||
}
|
||||
if(orderElement.getAdvanceAssignmentByType(advanceType) != null){
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
DirectAdvanceAssignment newAdvanceAssignment = DirectAdvanceAssignment
|
||||
.create();
|
||||
newAdvanceAssignment.setAdvanceType(advanceType);
|
||||
orderElement.checkAncestorsNoOtherAssignmentWithSameAdvanceType(
|
||||
orderElement.getParent(), newAdvanceAssignment);
|
||||
} catch (DuplicateAdvanceAssignmentForOrderElementException e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean thereIsTransition(ResourceAllocationTypeEnum newState) {
|
||||
return getOldState() != null && !getOldState().equals(newState);
|
||||
}
|
||||
|
|
@ -640,6 +688,14 @@ public class TaskPropertiesController extends GenericForwardComposer {
|
|||
Util.reloadBindings(startDateBox);
|
||||
}
|
||||
|
||||
public TaskEditFormComposer getTaskEditFormComposer() {
|
||||
return taskEditFormComposer;
|
||||
}
|
||||
|
||||
public void refreshTaskDeadline() {
|
||||
Util.reloadBindings(deadLineDateBox);
|
||||
}
|
||||
|
||||
public String getMoneyFormat() {
|
||||
return Util.getMoneyFormat();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ public class ResourceLoadModel implements IResourceLoadModel {
|
|||
allocationsFinder.lazilyGetResourcesIncluded(),
|
||||
allocationsFinder.lazilyGetAssignmentsShown());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
|
|
@ -642,7 +642,7 @@ public class ResourceLoadModel implements IResourceLoadModel {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private LoadTimeLine buildTimeLine(Collection<Criterion> criterions,
|
||||
Task task, Resource resource, String type,
|
||||
List<GenericResourceAllocation> allocationsSortedByStartDate,
|
||||
|
|
@ -1043,7 +1043,7 @@ class PeriodBuilderFactory {
|
|||
this.initDateFilter = initDateFilter;
|
||||
this.endDateFilter = endDateFilter;
|
||||
}
|
||||
|
||||
|
||||
public List<LoadPeriod> build(LoadPeriodGeneratorFactory factory, List<? extends ResourceAllocation<?>> sortedByStartDate){
|
||||
if (initDateFilter == null && endDateFilter == null) {
|
||||
return PeriodsBuilder.build(factory, sortedByStartDate);
|
||||
|
|
@ -1055,7 +1055,7 @@ class PeriodBuilderFactory {
|
|||
private Date asDate(LocalDate date) {
|
||||
return ResourceLoadModel.asDate(date);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class PeriodsBuilder {
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ public class ResourceLoadParameters {
|
|||
criteriaToShowList.clear();
|
||||
criteriaToShowList.addAll(criteriaList);
|
||||
}
|
||||
|
||||
|
||||
public <T> Paginator<T> getEntities(Class<T> type,
|
||||
Callable<List<T>> allEntities, IReattacher<T> reattacher) {
|
||||
Validate.isTrue(
|
||||
|
|
@ -119,7 +119,7 @@ public class ResourceLoadParameters {
|
|||
allEntities, reattacher);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private <T> List<T> listOfType(Class<T> klass, Collection<?> objects) {
|
||||
List<T> result = new ArrayList<T>();
|
||||
for (Object each : objects) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.web.subcontract;
|
||||
|
||||
import static org.libreplan.web.I18nHelper._;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.business.externalcompanies.entities.CommunicationType;
|
||||
import org.libreplan.business.externalcompanies.entities.CustomerCommunication;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.web.common.IMessagesForUser;
|
||||
import org.libreplan.web.common.MessagesForUser;
|
||||
import org.libreplan.web.planner.tabs.IGlobalViewEntryPoints;
|
||||
import org.zkoss.util.Locales;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zk.ui.event.Event;
|
||||
import org.zkoss.zk.ui.event.EventListener;
|
||||
import org.zkoss.zk.ui.event.Events;
|
||||
import org.zkoss.zk.ui.util.GenericForwardComposer;
|
||||
import org.zkoss.zul.Button;
|
||||
import org.zkoss.zul.Checkbox;
|
||||
import org.zkoss.zul.Grid;
|
||||
import org.zkoss.zul.Label;
|
||||
import org.zkoss.zul.Row;
|
||||
import org.zkoss.zul.RowRenderer;
|
||||
import org.zkoss.zul.SimpleListModel;
|
||||
|
||||
/**
|
||||
* Controller for CRUD actions over a {@link CustomerCommunication}
|
||||
*
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CustomerCommunicationCRUDController extends GenericForwardComposer {
|
||||
|
||||
private static final org.apache.commons.logging.Log LOG = LogFactory
|
||||
.getLog(CustomerCommunicationCRUDController.class);
|
||||
|
||||
private ICustomerCommunicationModel customerCommunicationModel;
|
||||
|
||||
private CustomerCommunicationRenderer customerCommunicationRenderer = new CustomerCommunicationRenderer();;
|
||||
|
||||
protected IMessagesForUser messagesForUser;
|
||||
|
||||
private Component messagesContainer;
|
||||
|
||||
private Grid listing;
|
||||
|
||||
@Resource
|
||||
private IGlobalViewEntryPoints globalView;
|
||||
|
||||
@Override
|
||||
public void doAfterCompose(Component comp) throws Exception {
|
||||
super.doAfterCompose(comp);
|
||||
comp.setAttribute("controller", this);
|
||||
messagesForUser = new MessagesForUser(messagesContainer);
|
||||
}
|
||||
|
||||
public void goToEdit(CustomerCommunication customerCommunication) {
|
||||
if(customerCommunication != null && customerCommunication.getOrder() != null){
|
||||
Order order = customerCommunication.getOrder();
|
||||
globalView.goToOrderDetails(order);
|
||||
}
|
||||
}
|
||||
|
||||
public FilterCommunicationEnum[] getFilterItems(){
|
||||
return FilterCommunicationEnum.values();
|
||||
}
|
||||
|
||||
public FilterCommunicationEnum getCurrentFilterItem() {
|
||||
return customerCommunicationModel.getCurrentFilter();
|
||||
}
|
||||
|
||||
public void setCurrentFilterItem(FilterCommunicationEnum selected) {
|
||||
customerCommunicationModel.setCurrentFilter(selected);
|
||||
refreshCustomerCommunicationsList();
|
||||
}
|
||||
|
||||
private void refreshCustomerCommunicationsList(){
|
||||
// update the customer communication list
|
||||
listing.setModel(new SimpleListModel(getCustomerCommunications()));
|
||||
listing.invalidate();
|
||||
}
|
||||
|
||||
protected void save(CustomerCommunication customerCommunication)
|
||||
throws ValidationException {
|
||||
customerCommunicationModel.confirmSave(customerCommunication);
|
||||
}
|
||||
|
||||
public List<CustomerCommunication> getCustomerCommunications() {
|
||||
FilterCommunicationEnum currentFilter = customerCommunicationModel.getCurrentFilter();
|
||||
switch(currentFilter){
|
||||
case ALL: return customerCommunicationModel.getCustomerAllCommunications();
|
||||
case NOT_REVIEWED: return customerCommunicationModel.getCustomerCommunicationWithoutReviewed();
|
||||
default: return customerCommunicationModel.getCustomerAllCommunications();
|
||||
}
|
||||
}
|
||||
|
||||
public CustomerCommunicationRenderer getCustomerCommunicationRenderer() {
|
||||
return customerCommunicationRenderer;
|
||||
}
|
||||
|
||||
private class CustomerCommunicationRenderer implements
|
||||
RowRenderer {
|
||||
|
||||
@Override
|
||||
public void render(Row row, Object data) {
|
||||
CustomerCommunication customerCommunication = (CustomerCommunication) data;
|
||||
row.setValue(customerCommunication);
|
||||
|
||||
final CommunicationType type = customerCommunication.getCommunicationType();
|
||||
final boolean reviewed = customerCommunication.getReviewed();
|
||||
if(!customerCommunication.getReviewed()){
|
||||
row.setSclass("communication-not-reviewed");
|
||||
}
|
||||
|
||||
appendLabel(row, toString(type));
|
||||
appendLabel(row, customerCommunication.getOrder().getName());
|
||||
appendLabel(row,
|
||||
toString(customerCommunication.getDeadline(), "dd/MM/yyyy"));
|
||||
appendLabel(row, customerCommunication.getOrder().getCode());
|
||||
appendLabel(row, customerCommunication.getOrder()
|
||||
.getCustomerReference());
|
||||
appendLabel(row,
|
||||
toString(customerCommunication.getCommunicationDate(),
|
||||
"dd/MM/yyyy HH:mm"));
|
||||
appendCheckbox(row, customerCommunication);
|
||||
appendOperations(row, customerCommunication);
|
||||
}
|
||||
|
||||
private String toString(Date date, String precision) {
|
||||
if (date == null) {
|
||||
return "";
|
||||
}
|
||||
return new SimpleDateFormat(precision, Locales.getCurrent())
|
||||
.format(date);
|
||||
}
|
||||
|
||||
private String toString(Object object) {
|
||||
if (object == null) {
|
||||
return "";
|
||||
}
|
||||
return object.toString();
|
||||
}
|
||||
|
||||
private void appendLabel(Row row, String label) {
|
||||
row.appendChild(new Label(label));
|
||||
}
|
||||
|
||||
private void appendCheckbox(final Row row,
|
||||
final CustomerCommunication customerCommunication) {
|
||||
final Checkbox checkBoxReviewed = new Checkbox();
|
||||
checkBoxReviewed.setChecked(customerCommunication.getReviewed());
|
||||
|
||||
checkBoxReviewed.addEventListener(Events.ON_CHECK,
|
||||
new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event arg0) throws Exception {
|
||||
customerCommunication.setReviewed(checkBoxReviewed.isChecked());
|
||||
save(customerCommunication);
|
||||
updateRowClass(row,checkBoxReviewed.isChecked());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
row.appendChild(checkBoxReviewed);
|
||||
}
|
||||
|
||||
private void updateRowClass(final Row row, Boolean reviewed){
|
||||
row.setSclass("");
|
||||
if(!reviewed){
|
||||
row.setSclass("communication-not-reviewed");
|
||||
}
|
||||
}
|
||||
|
||||
private void appendOperations(Row row,
|
||||
final CustomerCommunication customerCommunication) {
|
||||
Button buttonEdit = new Button();
|
||||
buttonEdit.setSclass("icono");
|
||||
buttonEdit.setImage("/common/img/ico_editar1.png");
|
||||
buttonEdit.setHoverImage("/common/img/ico_editar.png");
|
||||
buttonEdit.setTooltiptext(_("Edit"));
|
||||
buttonEdit.addEventListener(Events.ON_CLICK, new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event arg0) throws Exception {
|
||||
goToEdit(customerCommunication);
|
||||
}
|
||||
});
|
||||
row.appendChild(buttonEdit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply filter to customers communications
|
||||
* @param event
|
||||
*/
|
||||
public void onApplyFilter(Event event) {
|
||||
refreshCustomerCommunicationsList();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.web.subcontract;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.libreplan.business.externalcompanies.daos.ICustomerCommunicationDAO;
|
||||
import org.libreplan.business.externalcompanies.entities.CustomerCommunication;
|
||||
import org.libreplan.web.common.concurrentdetection.OnConcurrentModification;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
||||
@OnConcurrentModification(goToPage = "/subcontract/customerCommunication.zul")
|
||||
public class CustomerCommunicationModel implements ICustomerCommunicationModel{
|
||||
|
||||
@Autowired
|
||||
private ICustomerCommunicationDAO customerCommunicationDAO;
|
||||
|
||||
private FilterCommunicationEnum currentFilter = FilterCommunicationEnum.NOT_REVIEWED;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void confirmSave(CustomerCommunication customerCommunication){
|
||||
customerCommunicationDAO.save(customerCommunication);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public List<CustomerCommunication> getCustomerAllCommunications(){
|
||||
List<CustomerCommunication> list = customerCommunicationDAO.getAll();
|
||||
forceLoadAssociatedData(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public List<CustomerCommunication> getCustomerCommunicationWithoutReviewed(){
|
||||
List<CustomerCommunication> list = customerCommunicationDAO.getAllNotReviewed();
|
||||
forceLoadAssociatedData(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
private void forceLoadAssociatedData(List<CustomerCommunication> customerCommunicationList){
|
||||
if (customerCommunicationList != null) {
|
||||
for (CustomerCommunication customerCommunication : customerCommunicationList) {
|
||||
customerCommunication.getOrder().getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentFilter(FilterCommunicationEnum currentFilter) {
|
||||
this.currentFilter = currentFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterCommunicationEnum getCurrentFilter() {
|
||||
return currentFilter;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.web.subcontract;
|
||||
|
||||
/**
|
||||
* Enum to filter the {@link CustomerCommunication} list.
|
||||
*
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
public enum FilterCommunicationEnum {
|
||||
ALL(_("All")), NOT_REVIEWED(_("Not Reviewed"));
|
||||
|
||||
/**
|
||||
* Forces to mark the string as needing translation
|
||||
*/
|
||||
private static String _(String string) {
|
||||
return string;
|
||||
}
|
||||
|
||||
private String displayName;
|
||||
|
||||
private FilterCommunicationEnum(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public static FilterCommunicationEnum getDefault() {
|
||||
return ALL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return displayName;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.web.subcontract;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.libreplan.business.externalcompanies.entities.CustomerCommunication;
|
||||
|
||||
public interface ICustomerCommunicationModel {
|
||||
|
||||
void confirmSave(CustomerCommunication customerCommunication);
|
||||
|
||||
List<CustomerCommunication> getCustomerCommunicationWithoutReviewed();
|
||||
|
||||
List<CustomerCommunication> getCustomerAllCommunications();
|
||||
|
||||
void setCurrentFilter(FilterCommunicationEnum currentFilter);
|
||||
|
||||
FilterCommunicationEnum getCurrentFilter();
|
||||
|
||||
}
|
||||
|
|
@ -53,4 +53,6 @@ public interface IReportAdvancesModel {
|
|||
boolean isAnyAdvanceMeasurementNotReported(
|
||||
DirectAdvanceAssignment directAdvanceAssignment);
|
||||
|
||||
String getStatus(Order order);
|
||||
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ package org.libreplan.web.subcontract;
|
|||
import java.util.List;
|
||||
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.planner.entities.SubcontractedTaskData;
|
||||
import org.libreplan.web.subcontract.exceptions.ConnectionProblemsException;
|
||||
import org.libreplan.web.subcontract.exceptions.UnrecoverableErrorServiceException;
|
||||
|
|
@ -36,12 +37,11 @@ public interface ISubcontractedTasksModel {
|
|||
|
||||
List<SubcontractedTaskData> getSubcontractedTasks();
|
||||
|
||||
String getOrderCode(SubcontractedTaskData subcontractedTaskData);
|
||||
|
||||
void sendToSubcontractor(SubcontractedTaskData subcontractedTaskData)
|
||||
throws ValidationException, ConnectionProblemsException,
|
||||
UnrecoverableErrorServiceException;
|
||||
|
||||
String exportXML(SubcontractedTaskData subcontractedTaskData);
|
||||
|
||||
Order getOrder(SubcontractedTaskData subcontractedTaskData);
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.web.subcontract;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderElement;
|
||||
import org.libreplan.business.planner.entities.SubcontractedTaskData;
|
||||
import org.libreplan.business.planner.entities.SubcontractorCommunication;
|
||||
|
||||
public interface ISubcontractorCommunicationModel {
|
||||
|
||||
void confirmSave(SubcontractorCommunication customerCommunication);
|
||||
|
||||
List<SubcontractorCommunication> getSubcontractorCommunicationWithoutReviewed();
|
||||
|
||||
List<SubcontractorCommunication> getSubcontractorAllCommunications();
|
||||
|
||||
void setCurrentFilter(FilterCommunicationEnum currentFilter);
|
||||
|
||||
FilterCommunicationEnum getCurrentFilter();
|
||||
|
||||
String getOrderCode(SubcontractedTaskData subcontractedTaskData);
|
||||
|
||||
String getOrderName(SubcontractedTaskData subcontractedTaskData);
|
||||
|
||||
Order getOrder(OrderElement orderElement);
|
||||
|
||||
}
|
||||
|
|
@ -107,9 +107,9 @@ public class ReportAdvancesController extends GenericForwardComposer {
|
|||
DirectAdvanceAssignment directAdvanceAssignment = order
|
||||
.getDirectAdvanceAssignmentOfTypeSubcontractor();
|
||||
|
||||
// append the last advance measurement reported
|
||||
AdvanceMeasurement lastAdvanceMeasurementReported = reportAdvancesModel
|
||||
.getLastAdvanceMeasurementReported(directAdvanceAssignment);
|
||||
|
||||
if (lastAdvanceMeasurementReported != null) {
|
||||
appendLabel(row, toString(lastAdvanceMeasurementReported.getDate()));
|
||||
appendLabel(row, toString(lastAdvanceMeasurementReported.getValue()));
|
||||
|
|
@ -118,9 +118,9 @@ public class ReportAdvancesController extends GenericForwardComposer {
|
|||
appendLabel(row, "");
|
||||
}
|
||||
|
||||
// append the last advance measurement not reported
|
||||
AdvanceMeasurement lastAdvanceMeasurement = reportAdvancesModel
|
||||
.getLastAdvanceMeasurement(directAdvanceAssignment);
|
||||
|
||||
if (lastAdvanceMeasurement != null) {
|
||||
appendLabel(row, toString(lastAdvanceMeasurement.getDate()));
|
||||
appendLabel(row, toString(lastAdvanceMeasurement.getValue()));
|
||||
|
|
@ -129,15 +129,16 @@ public class ReportAdvancesController extends GenericForwardComposer {
|
|||
appendLabel(row, "");
|
||||
}
|
||||
|
||||
if (reportAdvancesModel
|
||||
.isAnyAdvanceMeasurementNotReported(directAdvanceAssignment)) {
|
||||
appendLabel(row, _("Pending update"));
|
||||
appendOperations(row, order, false);
|
||||
} else {
|
||||
appendLabel(row, _("Updated"));
|
||||
appendOperations(row, order, true);
|
||||
}
|
||||
// append the status
|
||||
String status = reportAdvancesModel.getStatus(order);
|
||||
appendLabel(row, _(status));
|
||||
|
||||
// append the operations
|
||||
if (status.equals("Updated")) {
|
||||
appendOperations(row, order, true);
|
||||
} else {
|
||||
appendOperations(row, order, false);
|
||||
}
|
||||
}
|
||||
|
||||
private String toString(Object object) {
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import org.apache.cxf.jaxrs.client.WebClient;
|
|||
import org.libreplan.business.advance.entities.AdvanceMeasurement;
|
||||
import org.libreplan.business.advance.entities.DirectAdvanceAssignment;
|
||||
import org.libreplan.business.common.daos.IConfigurationDAO;
|
||||
import org.libreplan.business.externalcompanies.entities.EndDateCommunication;
|
||||
import org.libreplan.business.externalcompanies.entities.ExternalCompany;
|
||||
import org.libreplan.business.orders.daos.IOrderDAO;
|
||||
import org.libreplan.business.orders.daos.IOrderElementDAO;
|
||||
|
|
@ -55,8 +56,9 @@ import org.libreplan.ws.common.api.InstanceConstraintViolationsDTO;
|
|||
import org.libreplan.ws.common.api.InstanceConstraintViolationsListDTO;
|
||||
import org.libreplan.ws.common.impl.OrderElementConverter;
|
||||
import org.libreplan.ws.common.impl.Util;
|
||||
import org.libreplan.ws.subcontract.api.OrderElementWithAdvanceMeasurementsDTO;
|
||||
import org.libreplan.ws.subcontract.api.OrderElementWithAdvanceMeasurementsListDTO;
|
||||
import org.libreplan.ws.subcontract.api.EndDateCommunicationToCustomerDTO;
|
||||
import org.libreplan.ws.subcontract.api.OrderElementWithAdvanceMeasurementsOrEndDateDTO;
|
||||
import org.libreplan.ws.subcontract.api.OrderElementWithAdvanceMeasurementsOrEndDateListDTO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
|
@ -83,7 +85,6 @@ public class ReportAdvancesModel implements IReportAdvancesModel {
|
|||
@Autowired
|
||||
private IConfigurationDAO configurationDAO;
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<Order> getOrdersWithExternalCodeInAnyOrderElement() {
|
||||
|
|
@ -97,12 +98,17 @@ public class ReportAdvancesModel implements IReportAdvancesModel {
|
|||
ordersMap.put(order.getId(), order);
|
||||
forceLoadHoursGroups(order);
|
||||
forceLoadAdvanceAssignments(order);
|
||||
forceLoadAskedEndDate(order);
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayList<Order>(ordersMap.values());
|
||||
}
|
||||
|
||||
private void forceLoadAskedEndDate(Order order) {
|
||||
order.getEndDateCommunicationToCustomer().size();
|
||||
}
|
||||
|
||||
private void forceLoadHoursGroups(OrderElement orderElement) {
|
||||
orderElement.getHoursGroups().size();
|
||||
for (OrderElement child : orderElement.getChildren()) {
|
||||
|
|
@ -182,7 +188,7 @@ public class ReportAdvancesModel implements IReportAdvancesModel {
|
|||
ConnectionProblemsException {
|
||||
orderDAO.save(order);
|
||||
|
||||
OrderElementWithAdvanceMeasurementsListDTO orderElementWithAdvanceMeasurementsListDTO = getOrderElementWithAdvanceMeasurementsListDTO(order);
|
||||
OrderElementWithAdvanceMeasurementsOrEndDateListDTO orderElementWithAdvanceMeasurementsListDTO = getOrderElementWithAdvanceMeasurementsListDTO(order);
|
||||
ExternalCompany externalCompany = order.getCustomer();
|
||||
|
||||
NaiveTrustProvider.setAlwaysTrust(true);
|
||||
|
|
@ -211,6 +217,7 @@ public class ReportAdvancesModel implements IReportAdvancesModel {
|
|||
|
||||
throw new UnrecoverableErrorServiceException(message);
|
||||
}
|
||||
|
||||
} catch (WebApplicationException e) {
|
||||
LOG.error("Problems connecting with client web service", e);
|
||||
|
||||
|
|
@ -223,33 +230,45 @@ public class ReportAdvancesModel implements IReportAdvancesModel {
|
|||
}
|
||||
}
|
||||
|
||||
private OrderElementWithAdvanceMeasurementsListDTO getOrderElementWithAdvanceMeasurementsListDTO(
|
||||
private OrderElementWithAdvanceMeasurementsOrEndDateListDTO getOrderElementWithAdvanceMeasurementsListDTO(
|
||||
Order order) {
|
||||
List<OrderElementWithAdvanceMeasurementsDTO> orderElementWithAdvanceMeasurementsDTOs = new ArrayList<OrderElementWithAdvanceMeasurementsDTO>();
|
||||
List<OrderElementWithAdvanceMeasurementsOrEndDateDTO> orderElementWithAdvanceMeasurementsDTOs = new ArrayList<OrderElementWithAdvanceMeasurementsOrEndDateDTO>();
|
||||
// create the asked end dates
|
||||
EndDateCommunicationToCustomerDTO endDateCommunicationToCustomerDTO = null;
|
||||
if (isAnyEndDateNotReported(order)) {
|
||||
EndDateCommunication lastEndDateCommunicationToCustomerReported = order
|
||||
.getLastEndDateCommunicationToCustomer();
|
||||
lastEndDateCommunicationToCustomerReported.setCommunicationDate(new Date());
|
||||
endDateCommunicationToCustomerDTO = OrderElementConverter.toDTO(lastEndDateCommunicationToCustomerReported);
|
||||
}
|
||||
|
||||
// create the progress
|
||||
DirectAdvanceAssignment directAdvanceAssignment = order
|
||||
.getDirectAdvanceAssignmentOfTypeSubcontractor();
|
||||
Set<AdvanceMeasurementDTO> advanceMeasurementDTOs = new HashSet<AdvanceMeasurementDTO>();
|
||||
|
||||
for (AdvanceMeasurement advanceMeasurement : directAdvanceAssignment
|
||||
.getAdvanceMeasurements()) {
|
||||
if (advanceMeasurement.getCommunicationDate() == null) {
|
||||
AdvanceMeasurementDTO advanceMeasurementDTO = OrderElementConverter
|
||||
.toDTO(advanceMeasurement);
|
||||
advanceMeasurement.updateCommunicationDate(new Date());
|
||||
advanceMeasurementDTOs.add(advanceMeasurementDTO);
|
||||
if (directAdvanceAssignment != null) {
|
||||
for (AdvanceMeasurement advanceMeasurement : directAdvanceAssignment
|
||||
.getAdvanceMeasurements()) {
|
||||
if (advanceMeasurement.getCommunicationDate() == null) {
|
||||
AdvanceMeasurementDTO advanceMeasurementDTO = OrderElementConverter
|
||||
.toDTO(advanceMeasurement);
|
||||
advanceMeasurement.updateCommunicationDate(new Date());
|
||||
advanceMeasurementDTOs.add(advanceMeasurementDTO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!advanceMeasurementDTOs.isEmpty()) {
|
||||
OrderElementWithAdvanceMeasurementsDTO orderElementWithAdvanceMeasurementsDTO = new OrderElementWithAdvanceMeasurementsDTO(
|
||||
directAdvanceAssignment.getOrderElement().getExternalCode(),
|
||||
advanceMeasurementDTOs);
|
||||
// add the updates
|
||||
if (endDateCommunicationToCustomerDTO != null || !advanceMeasurementDTOs.isEmpty()) {
|
||||
OrderElementWithAdvanceMeasurementsOrEndDateDTO orderElementWithAdvanceMeasurementsOrEndDateDTO = new OrderElementWithAdvanceMeasurementsOrEndDateDTO(
|
||||
order.getExternalCode(),
|
||||
advanceMeasurementDTOs, endDateCommunicationToCustomerDTO);
|
||||
orderElementWithAdvanceMeasurementsDTOs
|
||||
.add(orderElementWithAdvanceMeasurementsDTO);
|
||||
.add(orderElementWithAdvanceMeasurementsOrEndDateDTO);
|
||||
}
|
||||
|
||||
return new OrderElementWithAdvanceMeasurementsListDTO(getCompanyCode(),
|
||||
return new OrderElementWithAdvanceMeasurementsOrEndDateListDTO(getCompanyCode(),
|
||||
orderElementWithAdvanceMeasurementsDTOs);
|
||||
}
|
||||
|
||||
|
|
@ -260,12 +279,12 @@ public class ReportAdvancesModel implements IReportAdvancesModel {
|
|||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public String exportXML(Order order) {
|
||||
OrderElementWithAdvanceMeasurementsListDTO orderElementWithAdvanceMeasurementsListDTO = getOrderElementWithAdvanceMeasurementsListDTO(order);
|
||||
OrderElementWithAdvanceMeasurementsOrEndDateListDTO orderElementWithAdvanceMeasurementsListDTO = getOrderElementWithAdvanceMeasurementsListDTO(order);
|
||||
|
||||
StringWriter xml = new StringWriter();
|
||||
try {
|
||||
JAXBContext jaxbContext = JAXBContext
|
||||
.newInstance(OrderElementWithAdvanceMeasurementsListDTO.class);
|
||||
.newInstance(OrderElementWithAdvanceMeasurementsOrEndDateListDTO.class);
|
||||
Marshaller marshaller = jaxbContext.createMarshaller();
|
||||
marshaller.marshal(orderElementWithAdvanceMeasurementsListDTO, xml);
|
||||
} catch (Exception e) {
|
||||
|
|
@ -275,4 +294,31 @@ public class ReportAdvancesModel implements IReportAdvancesModel {
|
|||
return xml.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatus(Order order) {
|
||||
DirectAdvanceAssignment directAdvanceAssignment = order
|
||||
.getDirectAdvanceAssignmentOfTypeSubcontractor();
|
||||
|
||||
boolean advancesNotReported = isAnyAdvanceMeasurementNotReported(directAdvanceAssignment);
|
||||
boolean endDateNotReported = isAnyEndDateNotReported(order);
|
||||
if (advancesNotReported && endDateNotReported) {
|
||||
return "Pending update of progress and communication date";
|
||||
} else if (endDateNotReported) {
|
||||
return "Pending update for communication date";
|
||||
} else if (advancesNotReported) {
|
||||
return "Pending update of progress";
|
||||
}
|
||||
return "Updated";
|
||||
}
|
||||
|
||||
private boolean isAnyEndDateNotReported(Order order) {
|
||||
if (order != null && order.getEndDateCommunicationToCustomer() != null) {
|
||||
EndDateCommunication lastAskedEndDate = order
|
||||
.getLastEndDateCommunicationToCustomer();
|
||||
return lastAskedEndDate != null ? (lastAskedEndDate.getCommunicationDate() == null)
|
||||
: false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
* Desenvolvemento Tecnolóxico de Galicia
|
||||
* Copyright (C) 2010-2011 Igalia, S.L.
|
||||
*
|
||||
* Copyright (C) 2011-2012 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
|
|
@ -32,6 +34,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.planner.entities.SubcontractedTaskData;
|
||||
import org.libreplan.web.common.IMessagesForUser;
|
||||
import org.libreplan.web.common.Level;
|
||||
|
|
@ -52,16 +55,19 @@ import org.zkoss.zk.ui.event.EventListener;
|
|||
import org.zkoss.zk.ui.event.Events;
|
||||
import org.zkoss.zk.ui.util.GenericForwardComposer;
|
||||
import org.zkoss.zul.Button;
|
||||
import org.zkoss.zul.Column;
|
||||
import org.zkoss.zul.Grid;
|
||||
import org.zkoss.zul.Hbox;
|
||||
import org.zkoss.zul.Label;
|
||||
import org.zkoss.zul.ListModelExt;
|
||||
import org.zkoss.zul.Row;
|
||||
import org.zkoss.zul.RowRenderer;
|
||||
import org.zkoss.zul.api.Window;
|
||||
|
||||
/**
|
||||
* Controller for operations related with subcontracted tasks.
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
@org.springframework.stereotype.Component
|
||||
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
||||
|
|
@ -69,6 +75,10 @@ public class SubcontractedTasksController extends GenericForwardComposer {
|
|||
|
||||
private Window window;
|
||||
|
||||
private Column columnBySort;
|
||||
|
||||
private Grid listing;
|
||||
|
||||
private Component messagesContainer;
|
||||
private IMessagesForUser messagesForUser;
|
||||
|
||||
|
|
@ -100,21 +110,39 @@ public class SubcontractedTasksController extends GenericForwardComposer {
|
|||
SubcontractedTaskData subcontractedTaskData = (SubcontractedTaskData) data;
|
||||
row.setValue(subcontractedTaskData);
|
||||
|
||||
appendLabel(row, toString(subcontractedTaskData
|
||||
.getSubcontratationDate()));
|
||||
appendLabel(row, toString(subcontractedTaskData
|
||||
.getSubcontractCommunicationDate()));
|
||||
Order order = getOrder(subcontractedTaskData);
|
||||
|
||||
appendLabel(row,
|
||||
toString(subcontractedTaskData.getSubcontratationDate(), "dd/MM/yyyy HH:mm"));
|
||||
appendLabel(
|
||||
row,
|
||||
toString(subcontractedTaskData.getSubcontractCommunicationDate(),
|
||||
"dd/MM/yyyy HH:mm"));
|
||||
appendLabel(row, getExternalCompany(subcontractedTaskData));
|
||||
appendLabel(row, getOrderCode(subcontractedTaskData));
|
||||
appendLabel(row, getOrderCode(order));
|
||||
appendLabel(row, getOrderName(order));
|
||||
appendLabel(row, subcontractedTaskData.getSubcontractedCode());
|
||||
appendLabel(row, getTaskName(subcontractedTaskData));
|
||||
appendLabel(row, subcontractedTaskData.getWorkDescription());
|
||||
appendLabel(row, Util.addCurrencySymbol(subcontractedTaskData
|
||||
.getSubcontractPrice()));
|
||||
appendLabel(row, Util.addCurrencySymbol(subcontractedTaskData.getSubcontractPrice()));
|
||||
appendLabel(row,
|
||||
toString(subcontractedTaskData.getLastRequiredDeliverDate(), "dd/MM/yyyy"));
|
||||
appendLabel(row, _(toString(subcontractedTaskData.getState())));
|
||||
appendOperations(row, subcontractedTaskData);
|
||||
}
|
||||
|
||||
private String getOrderCode(Order order) {
|
||||
return (order != null) ? order.getCode() : "";
|
||||
}
|
||||
|
||||
private String getOrderName(Order order) {
|
||||
return (order != null) ? order.getName() : "";
|
||||
}
|
||||
|
||||
private Order getOrder(SubcontractedTaskData subcontractedTaskData) {
|
||||
return subcontractedTasksModel.getOrder(subcontractedTaskData);
|
||||
}
|
||||
|
||||
private String toString(Object object) {
|
||||
if (object == null) {
|
||||
return "";
|
||||
|
|
@ -123,22 +151,17 @@ public class SubcontractedTasksController extends GenericForwardComposer {
|
|||
return object.toString();
|
||||
}
|
||||
|
||||
private String toString(Date date) {
|
||||
private String toString(Date date, String precision) {
|
||||
if (date == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return new SimpleDateFormat("dd/MM/yyyy HH:mm").format(date);
|
||||
return new SimpleDateFormat(precision).format(date);
|
||||
}
|
||||
|
||||
private void appendLabel(Row row, String label) {
|
||||
row.appendChild(new Label(label));
|
||||
}
|
||||
|
||||
private String getOrderCode(SubcontractedTaskData subcontractedTaskData) {
|
||||
return subcontractedTasksModel.getOrderCode(subcontractedTaskData);
|
||||
}
|
||||
|
||||
private String getTaskName(SubcontractedTaskData subcontractedTaskData) {
|
||||
return subcontractedTaskData.getTask().getName();
|
||||
}
|
||||
|
|
@ -211,7 +234,7 @@ public class SubcontractedTasksController extends GenericForwardComposer {
|
|||
} catch (ValidationException e) {
|
||||
messagesForUser.showInvalidValues(e);
|
||||
}
|
||||
Util.reloadBindings(window);
|
||||
reload();
|
||||
}
|
||||
|
||||
});
|
||||
|
|
@ -223,4 +246,23 @@ public class SubcontractedTasksController extends GenericForwardComposer {
|
|||
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
Util.reloadBindings(window);
|
||||
forceSortGridSatisfaction();
|
||||
}
|
||||
|
||||
public void forceSortGridSatisfaction() {
|
||||
Column column = (Column) columnBySort;
|
||||
ListModelExt model = (ListModelExt) listing.getModel();
|
||||
if ("ascending".equals(column.getSortDirection())) {
|
||||
model.sort(column.getSortAscending(), true);
|
||||
}
|
||||
if ("descending".equals(column.getSortDirection())) {
|
||||
model.sort(column.getSortDescending(), false);
|
||||
}
|
||||
}
|
||||
|
||||
public void initRender() {
|
||||
forceSortGridSatisfaction();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ package org.libreplan.web.subcontract;
|
|||
import static org.libreplan.web.I18nHelper._;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -39,11 +41,13 @@ import org.libreplan.business.common.exceptions.ValidationException;
|
|||
import org.libreplan.business.externalcompanies.entities.ExternalCompany;
|
||||
import org.libreplan.business.orders.daos.IOrderDAO;
|
||||
import org.libreplan.business.orders.daos.IOrderElementDAO;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderElement;
|
||||
import org.libreplan.business.planner.daos.ISubcontractedTaskDataDAO;
|
||||
import org.libreplan.business.planner.entities.SubcontractState;
|
||||
import org.libreplan.business.planner.entities.SubcontractedTaskData;
|
||||
import org.libreplan.business.planner.entities.Task;
|
||||
import org.libreplan.web.common.concurrentdetection.OnConcurrentModification;
|
||||
import org.libreplan.web.subcontract.exceptions.ConnectionProblemsException;
|
||||
import org.libreplan.web.subcontract.exceptions.UnrecoverableErrorServiceException;
|
||||
import org.libreplan.ws.cert.NaiveTrustProvider;
|
||||
|
|
@ -71,6 +75,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
*/
|
||||
@Component
|
||||
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
||||
@OnConcurrentModification(goToPage = "/subcontract/subcontractedTasks.zul")
|
||||
public class SubcontractedTasksModel implements ISubcontractedTasksModel {
|
||||
|
||||
private static Log LOG = LogFactory.getLog(SubcontractedTasksModel.class);
|
||||
|
|
@ -94,8 +99,13 @@ public class SubcontractedTasksModel implements ISubcontractedTasksModel {
|
|||
.getAllForMasterScenario();
|
||||
for (SubcontractedTaskData subcontractedTaskData : result) {
|
||||
forceLoadExternalCompany(subcontractedTaskData);
|
||||
forceLastDeliveryDate(subcontractedTaskData);
|
||||
}
|
||||
return result;
|
||||
return sortByState(result);
|
||||
}
|
||||
|
||||
private void forceLastDeliveryDate(SubcontractedTaskData subcontractedTaskData) {
|
||||
subcontractedTaskData.getLastRequiredDeliverDate();
|
||||
}
|
||||
|
||||
private void forceLoadExternalCompany(
|
||||
|
|
@ -103,13 +113,44 @@ public class SubcontractedTasksModel implements ISubcontractedTasksModel {
|
|||
subcontractedTaskData.getExternalCompany().getName();
|
||||
}
|
||||
|
||||
private List<SubcontractedTaskData> sortByState(List<SubcontractedTaskData> tasks){
|
||||
Collections.sort(tasks, new Comparator<SubcontractedTaskData>(){
|
||||
|
||||
@Override
|
||||
public int compare(SubcontractedTaskData arg0, SubcontractedTaskData arg1) {
|
||||
if((arg0 == null) || (arg0.getState() == null)){
|
||||
return -1;
|
||||
}
|
||||
if((arg1 == null) || (arg1.getState() == null)){
|
||||
return 1;
|
||||
}
|
||||
if(arg0.getState().equals(arg1.getState())){
|
||||
return 0;
|
||||
}
|
||||
if (arg0.getState().equals(
|
||||
SubcontractState.PENDING_INITIAL_SEND)) {
|
||||
return 1;
|
||||
}
|
||||
if (arg1.getState().equals(
|
||||
SubcontractState.PENDING_INITIAL_SEND)) {
|
||||
return -1;
|
||||
}
|
||||
if( arg0.getState().equals(SubcontractState.PENDING_UPDATE_DELIVERING_DATE)) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
});
|
||||
return tasks;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public String getOrderCode(SubcontractedTaskData subcontractedTaskData) {
|
||||
public Order getOrder(SubcontractedTaskData subcontractedTaskData) {
|
||||
Task task = subcontractedTaskData.getTask();
|
||||
OrderElement orderElement = orderDAO.loadOrderAvoidingProxyFor(task
|
||||
.getOrderElement());
|
||||
return orderElement.getOrder().getCode();
|
||||
return orderElement.getOrder();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -119,7 +160,14 @@ public class SubcontractedTasksModel implements ISubcontractedTasksModel {
|
|||
UnrecoverableErrorServiceException {
|
||||
subcontractedTaskDataDAO.save(subcontractedTaskData);
|
||||
|
||||
subcontractedTaskData.setState(SubcontractState.FAILED_SENT);
|
||||
SubcontractState currentState = subcontractedTaskData.getState();
|
||||
|
||||
if (currentState.equals(SubcontractState.PENDING_INITIAL_SEND)) {
|
||||
subcontractedTaskData.setState(SubcontractState.FAILED_SENT);
|
||||
} else if (currentState
|
||||
.equals(SubcontractState.PENDING_UPDATE_DELIVERING_DATE)) {
|
||||
subcontractedTaskData.setState(SubcontractState.FAILED_UPDATE);
|
||||
}
|
||||
|
||||
if (!subcontractedTaskData.isSendable()) {
|
||||
throw new RuntimeException("Subcontracted task already sent");
|
||||
|
|
@ -131,13 +179,82 @@ public class SubcontractedTasksModel implements ISubcontractedTasksModel {
|
|||
"External company has not interaction fields filled");
|
||||
}
|
||||
|
||||
makeSubcontractRequestRequest(subcontractedTaskData);
|
||||
makeSubcontractRequestRequest(subcontractedTaskData,currentState);
|
||||
|
||||
subcontractedTaskData.setSubcontractCommunicationDate(new Date());
|
||||
Date today = new Date();
|
||||
if ((currentState.equals(SubcontractState.PENDING_INITIAL_SEND))
|
||||
|| (currentState.equals(SubcontractState.FAILED_SENT))) {
|
||||
subcontractedTaskData.setSubcontractCommunicationDate(today);
|
||||
}
|
||||
|
||||
//update the first required deliver date
|
||||
subcontractedTaskData.updateFirstRequiredDeliverDate(today);
|
||||
subcontractedTaskData.setSubcontractCommunicationDate(today);
|
||||
subcontractedTaskData.setState(SubcontractState.SUCCESS_SENT);
|
||||
}
|
||||
|
||||
private void makeSubcontractRequestRequest(
|
||||
SubcontractedTaskData subcontractedTaskData,
|
||||
SubcontractState currentState) throws ConnectionProblemsException,
|
||||
UnrecoverableErrorServiceException {
|
||||
if (subcontractedTaskData.getState() != null) {
|
||||
if ((currentState.equals(SubcontractState.PENDING_INITIAL_SEND) || (currentState
|
||||
.equals(SubcontractState.FAILED_SENT)))) {
|
||||
makeSubcontractRequestRequest_InitialSent(subcontractedTaskData);
|
||||
} else if ((currentState
|
||||
.equals(SubcontractState.PENDING_UPDATE_DELIVERING_DATE) || currentState
|
||||
.equals(SubcontractState.FAILED_UPDATE))) {
|
||||
makeSubcontractRequestRequest_UpdateDeliverDate(subcontractedTaskData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void makeSubcontractRequestRequest_UpdateDeliverDate(SubcontractedTaskData subcontractedTaskData)
|
||||
throws ConnectionProblemsException, UnrecoverableErrorServiceException {
|
||||
UpdateDeliveringDateDTO updateDeliveringDateDTO = SubcontractedTaskDataConverter
|
||||
.toUpdateDeliveringDateDTO(subcontractedTaskData);
|
||||
ExternalCompany externalCompany = subcontractedTaskData
|
||||
.getExternalCompany();
|
||||
|
||||
NaiveTrustProvider.setAlwaysTrust(true);
|
||||
|
||||
try {
|
||||
WebClient client = WebClient.create(externalCompany.getAppURI());
|
||||
client.path("ws/rest/subcontract/update");
|
||||
|
||||
Util.addAuthorizationHeader(client,
|
||||
externalCompany.getOurCompanyLogin(),
|
||||
externalCompany.getOurCompanyPassword());
|
||||
|
||||
InstanceConstraintViolationsListDTO instanceConstraintViolationsListDTO = client
|
||||
.post(updateDeliveringDateDTO,
|
||||
InstanceConstraintViolationsListDTO.class);
|
||||
|
||||
List<InstanceConstraintViolationsDTO> instanceConstraintViolationsList = instanceConstraintViolationsListDTO.instanceConstraintViolationsList;
|
||||
if ((instanceConstraintViolationsList != null)
|
||||
&& (!instanceConstraintViolationsList.isEmpty())) {
|
||||
String message = "";
|
||||
|
||||
for (ConstraintViolationDTO constraintViolationDTO : instanceConstraintViolationsList
|
||||
.get(0).constraintViolations) {
|
||||
message += constraintViolationDTO.toString() + "\n";
|
||||
}
|
||||
|
||||
throw new UnrecoverableErrorServiceException(message);
|
||||
}
|
||||
} catch (WebApplicationException e) {
|
||||
LOG.error("Problems connecting with subcontractor web service", e);
|
||||
|
||||
String message = _("Problems connecting with subcontractor web service");
|
||||
if (e.getMessage() != null) {
|
||||
message += ". " + _("Error: {0}", e.getMessage());
|
||||
}
|
||||
|
||||
throw new ConnectionProblemsException(message, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void makeSubcontractRequestRequest_InitialSent(
|
||||
SubcontractedTaskData subcontractedTaskData)
|
||||
throws ConnectionProblemsException, UnrecoverableErrorServiceException {
|
||||
SubcontractedTaskDataDTO subcontractedTaskDataDTO = getSubcontractedTaskData(subcontractedTaskData);
|
||||
|
|
@ -150,7 +267,7 @@ public class SubcontractedTasksModel implements ISubcontractedTasksModel {
|
|||
try {
|
||||
WebClient client = WebClient.create(externalCompany.getAppURI());
|
||||
|
||||
client.path("ws/rest/subcontract");
|
||||
client.path("ws/rest/subcontract/create");
|
||||
|
||||
Util.addAuthorizationHeader(client, externalCompany
|
||||
.getOurCompanyLogin(), externalCompany
|
||||
|
|
@ -239,6 +356,16 @@ public class SubcontractedTasksModel implements ISubcontractedTasksModel {
|
|||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public String exportXML(SubcontractedTaskData subcontractedTaskData) {
|
||||
SubcontractState currentState = subcontractedTaskData.getState();
|
||||
if ((currentState.equals(SubcontractState.PENDING_INITIAL_SEND) || (currentState
|
||||
.equals(SubcontractState.FAILED_SENT)))) {
|
||||
return exportXML_CreateSubcontractor(subcontractedTaskData);
|
||||
} else {
|
||||
return exportXML_UpdateSubcontractor(subcontractedTaskData);
|
||||
}
|
||||
}
|
||||
|
||||
public String exportXML_CreateSubcontractor(SubcontractedTaskData subcontractedTaskData){
|
||||
SubcontractedTaskDataDTO subcontractedTaskDataDTO = getSubcontractedTaskData(subcontractedTaskData);
|
||||
|
||||
StringWriter xml = new StringWriter();
|
||||
|
|
@ -254,4 +381,21 @@ public class SubcontractedTasksModel implements ISubcontractedTasksModel {
|
|||
return xml.toString();
|
||||
}
|
||||
|
||||
public String exportXML_UpdateSubcontractor(SubcontractedTaskData subcontractedTaskData){
|
||||
subcontractedTaskDataDAO.reattachUnmodifiedEntity(subcontractedTaskData);
|
||||
UpdateDeliveringDateDTO updateDeliveringDateDTO = SubcontractedTaskDataConverter
|
||||
.toUpdateDeliveringDateDTO(subcontractedTaskData);
|
||||
|
||||
StringWriter xml = new StringWriter();
|
||||
try {
|
||||
JAXBContext jaxbContext = JAXBContext
|
||||
.newInstance(UpdateDeliveringDateDTO.class);
|
||||
Marshaller marshaller = jaxbContext.createMarshaller();
|
||||
marshaller.marshal(updateDeliveringDateDTO, xml);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return xml.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.web.subcontract;
|
||||
|
||||
import static org.libreplan.web.I18nHelper._;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.business.externalcompanies.entities.CommunicationType;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderElement;
|
||||
import org.libreplan.business.planner.entities.SubcontractedTaskData;
|
||||
import org.libreplan.business.planner.entities.SubcontractorCommunication;
|
||||
import org.libreplan.business.planner.entities.SubcontractorCommunicationValue;
|
||||
import org.libreplan.business.planner.entities.TaskElement;
|
||||
import org.libreplan.web.common.IMessagesForUser;
|
||||
import org.libreplan.web.common.MessagesForUser;
|
||||
import org.libreplan.web.planner.tabs.IGlobalViewEntryPoints;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zk.ui.event.Event;
|
||||
import org.zkoss.zk.ui.event.EventListener;
|
||||
import org.zkoss.zk.ui.event.Events;
|
||||
import org.zkoss.zk.ui.util.GenericForwardComposer;
|
||||
import org.zkoss.zul.Button;
|
||||
import org.zkoss.zul.Checkbox;
|
||||
import org.zkoss.zul.Grid;
|
||||
import org.zkoss.zul.Label;
|
||||
import org.zkoss.zul.Popup;
|
||||
import org.zkoss.zul.Row;
|
||||
import org.zkoss.zul.RowRenderer;
|
||||
import org.zkoss.zul.SimpleListModel;
|
||||
|
||||
/**
|
||||
* Controller for CRUD actions over a {@link SubcontractorCommunication}
|
||||
*
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class SubcontractorCommunicationCRUDController extends GenericForwardComposer {
|
||||
|
||||
private static final org.apache.commons.logging.Log LOG = LogFactory
|
||||
.getLog(SubcontractorCommunicationCRUDController.class);
|
||||
|
||||
private ISubcontractorCommunicationModel subcontractorCommunicationModel;
|
||||
|
||||
private SubcontractorCommunicationRenderer subcontractorCommunicationRenderer = new SubcontractorCommunicationRenderer();
|
||||
|
||||
protected IMessagesForUser messagesForUser;
|
||||
|
||||
private Component messagesContainer;
|
||||
|
||||
private Grid listing;
|
||||
|
||||
private Grid listingValues;
|
||||
|
||||
private Label labelValue;
|
||||
|
||||
private Popup pp;
|
||||
|
||||
@Resource
|
||||
private IGlobalViewEntryPoints globalView;
|
||||
|
||||
@Override
|
||||
public void doAfterCompose(Component comp) throws Exception {
|
||||
super.doAfterCompose(comp);
|
||||
comp.setAttribute("controller", this);
|
||||
messagesForUser = new MessagesForUser(messagesContainer);
|
||||
}
|
||||
|
||||
public void goToEdit(SubcontractorCommunication subcontractorCommunication) {
|
||||
if(subcontractorCommunication != null){
|
||||
TaskElement task = subcontractorCommunication.getSubcontractedTaskData().getTask();
|
||||
OrderElement orderElement = task.getOrderElement();
|
||||
Order order = subcontractorCommunicationModel.getOrder(orderElement);
|
||||
|
||||
if(subcontractorCommunication.getCommunicationType().equals(CommunicationType.PROGRESS_UPDATE)){
|
||||
globalView.goToAdvanceTask(order,task);
|
||||
}else{
|
||||
globalView.goToOrderDetails(order);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public FilterCommunicationEnum[] getFilterItems(){
|
||||
return FilterCommunicationEnum.values();
|
||||
}
|
||||
|
||||
public FilterCommunicationEnum getCurrentFilterItem() {
|
||||
return subcontractorCommunicationModel.getCurrentFilter();
|
||||
}
|
||||
|
||||
public void setCurrentFilterItem(FilterCommunicationEnum selected) {
|
||||
subcontractorCommunicationModel.setCurrentFilter(selected);
|
||||
refreshSubcontractorCommunicationsList();
|
||||
}
|
||||
|
||||
private void refreshSubcontractorCommunicationsList() {
|
||||
// update the subcontractor communication list
|
||||
listing.setModel(new SimpleListModel(getSubcontractorCommunications()));
|
||||
listing.invalidate();
|
||||
}
|
||||
|
||||
protected void save(SubcontractorCommunication subcontractorCommunication)
|
||||
throws ValidationException {
|
||||
subcontractorCommunicationModel.confirmSave(subcontractorCommunication);
|
||||
}
|
||||
|
||||
public List<SubcontractorCommunication> getSubcontractorCommunications() {
|
||||
FilterCommunicationEnum currentFilter = subcontractorCommunicationModel.getCurrentFilter();
|
||||
switch(currentFilter){
|
||||
case ALL: return subcontractorCommunicationModel.getSubcontractorAllCommunications();
|
||||
case NOT_REVIEWED: return subcontractorCommunicationModel.getSubcontractorCommunicationWithoutReviewed();
|
||||
default: return subcontractorCommunicationModel.getSubcontractorAllCommunications();
|
||||
}
|
||||
}
|
||||
|
||||
public SubcontractorCommunicationRenderer getSubcontractorCommunicationRenderer() {
|
||||
return subcontractorCommunicationRenderer;
|
||||
}
|
||||
|
||||
private class SubcontractorCommunicationRenderer implements
|
||||
RowRenderer {
|
||||
|
||||
@Override
|
||||
public void render(Row row, Object data) {
|
||||
SubcontractorCommunication subcontractorCommunication = (SubcontractorCommunication) data;
|
||||
row.setValue(subcontractorCommunication);
|
||||
|
||||
final boolean reviewed = subcontractorCommunication.getReviewed();
|
||||
if(!reviewed){
|
||||
row.setSclass("communication-not-reviewed");
|
||||
}
|
||||
appendLabel(row, subcontractorCommunication.getCommunicationType().toString());
|
||||
appendLabel(row, subcontractorCommunication.getSubcontractedTaskData().getTask().getName());
|
||||
appendLabel(row, getOrderName(subcontractorCommunication.getSubcontractedTaskData()));
|
||||
appendLabel(row, getOrderCode(subcontractorCommunication.getSubcontractedTaskData()));
|
||||
appendLabel(row, subcontractorCommunication.getSubcontractedTaskData().getExternalCompany().getName());
|
||||
appendLabel(row, toString(subcontractorCommunication.getCommunicationDate()));
|
||||
appendLabelWithTooltip(row, subcontractorCommunication);
|
||||
appendCheckbox(row, subcontractorCommunication);
|
||||
appendOperations(row, subcontractorCommunication);
|
||||
}
|
||||
|
||||
private String toString(Date date) {
|
||||
if (date == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return new SimpleDateFormat("dd/MM/yyyy HH:mm").format(date);
|
||||
}
|
||||
|
||||
private String getOrderCode(SubcontractedTaskData subcontractedTaskData) {
|
||||
return subcontractorCommunicationModel.getOrderCode(subcontractedTaskData);
|
||||
}
|
||||
|
||||
private String getOrderName(SubcontractedTaskData subcontractedTaskData) {
|
||||
return subcontractorCommunicationModel.getOrderName(subcontractedTaskData);
|
||||
}
|
||||
|
||||
private String getLastValue(
|
||||
SubcontractorCommunication subcontractorCommunication) {
|
||||
SubcontractorCommunicationValue value = subcontractorCommunication
|
||||
.getLastSubcontractorCommunicationValues();
|
||||
return (value != null) ? value.toString() : "";
|
||||
}
|
||||
|
||||
private void appendLabel(Row row, String label) {
|
||||
row.appendChild(new Label(label));
|
||||
}
|
||||
|
||||
private void appendLabelWithTooltip(final Row row,
|
||||
final SubcontractorCommunication subcontractorCommunication) {
|
||||
String lastValue = getLastValue(subcontractorCommunication);
|
||||
final Label compLabel = new Label(lastValue);
|
||||
|
||||
if (subcontractorCommunication.getCommunicationType().equals(
|
||||
CommunicationType.PROGRESS_UPDATE)) {
|
||||
compLabel.setTooltip(pp);
|
||||
compLabel.addEventListener(Events.ON_MOUSE_OVER,
|
||||
new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event arg0) throws Exception {
|
||||
List<SubcontractorCommunicationValue> model = subcontractorCommunication
|
||||
.getSubcontractorCommunicationValues();
|
||||
listingValues.setModel(new SimpleListModel(model));
|
||||
listingValues.invalidate();
|
||||
}
|
||||
});
|
||||
}
|
||||
row.appendChild(compLabel);
|
||||
}
|
||||
|
||||
private void appendCheckbox(final Row row,
|
||||
final SubcontractorCommunication subcontractorCommunication) {
|
||||
final Checkbox checkBoxReviewed = new Checkbox();
|
||||
checkBoxReviewed.setChecked(subcontractorCommunication.getReviewed());
|
||||
|
||||
checkBoxReviewed.addEventListener(Events.ON_CHECK,
|
||||
new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event arg0) throws Exception {
|
||||
subcontractorCommunication.setReviewed(checkBoxReviewed.isChecked());
|
||||
save(subcontractorCommunication);
|
||||
updateRowClass(row, checkBoxReviewed.isChecked());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
row.appendChild(checkBoxReviewed);
|
||||
}
|
||||
|
||||
private void updateRowClass(final Row row, Boolean reviewed){
|
||||
row.setSclass("");
|
||||
if(!reviewed){
|
||||
row.setSclass("communication-not-reviewed");
|
||||
}
|
||||
}
|
||||
|
||||
private void appendOperations(Row row,
|
||||
final SubcontractorCommunication subcontractorCommunication) {
|
||||
Button buttonEdit = new Button();
|
||||
buttonEdit.setSclass("icono");
|
||||
buttonEdit.setImage("/common/img/ico_editar1.png");
|
||||
buttonEdit.setHoverImage("/common/img/ico_editar.png");
|
||||
buttonEdit.setTooltiptext(_("Edit"));
|
||||
buttonEdit.addEventListener(Events.ON_CLICK, new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event arg0) throws Exception {
|
||||
goToEdit(subcontractorCommunication);
|
||||
}
|
||||
});
|
||||
row.appendChild(buttonEdit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply filter to subcontractors communications
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
public void onApplyFilter(Event event) {
|
||||
refreshSubcontractorCommunicationsList();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.web.subcontract;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.libreplan.business.orders.daos.IOrderDAO;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderElement;
|
||||
import org.libreplan.business.planner.daos.ISubcontractorCommunicationDAO;
|
||||
import org.libreplan.business.planner.entities.SubcontractedTaskData;
|
||||
import org.libreplan.business.planner.entities.SubcontractorCommunication;
|
||||
import org.libreplan.business.planner.entities.SubcontractorCommunicationValue;
|
||||
import org.libreplan.business.planner.entities.Task;
|
||||
import org.libreplan.web.common.concurrentdetection.OnConcurrentModification;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
||||
@OnConcurrentModification(goToPage = "/subcontract/subcontractorCommunication.zul")
|
||||
public class SubcontractorCommunicationModel implements ISubcontractorCommunicationModel{
|
||||
|
||||
@Autowired
|
||||
private ISubcontractorCommunicationDAO subcontractorCommunicationDAO;
|
||||
|
||||
@Autowired
|
||||
IOrderDAO orderDAO;
|
||||
|
||||
private FilterCommunicationEnum currentFilter = FilterCommunicationEnum.NOT_REVIEWED;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void confirmSave(SubcontractorCommunication subcontractorCommunication){
|
||||
subcontractorCommunicationDAO.save(subcontractorCommunication);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public List<SubcontractorCommunication> getSubcontractorAllCommunications(){
|
||||
List<SubcontractorCommunication> list = subcontractorCommunicationDAO.getAll();
|
||||
forceLoadAssociatedData(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public List<SubcontractorCommunication> getSubcontractorCommunicationWithoutReviewed(){
|
||||
List<SubcontractorCommunication> list = subcontractorCommunicationDAO.getAllNotReviewed();
|
||||
forceLoadAssociatedData(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
private void forceLoadAssociatedData(List<SubcontractorCommunication> subcontractorCommunicationList){
|
||||
if (subcontractorCommunicationList != null) {
|
||||
for (SubcontractorCommunication subcontractorCommunication : subcontractorCommunicationList) {
|
||||
subcontractorCommunication.getSubcontractedTaskData().getExternalCompany().getName();
|
||||
subcontractorCommunication.getSubcontractedTaskData().getTask().getName();
|
||||
subcontractorCommunication.getSubcontractedTaskData().getTask().getOrderElement().getName();
|
||||
subcontractorCommunication.getLastSubcontractorCommunicationValues().getDate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void forceLoadAssociatedDataValue(List<SubcontractorCommunicationValue> subcontractorCommunicationValueList){
|
||||
if (subcontractorCommunicationValueList != null) {
|
||||
for (SubcontractorCommunicationValue value : subcontractorCommunicationValueList) {
|
||||
value.getDate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public String getOrderCode(SubcontractedTaskData subcontractedTaskData) {
|
||||
Task task = subcontractedTaskData.getTask();
|
||||
OrderElement orderElement = orderDAO.loadOrderAvoidingProxyFor(task
|
||||
.getOrderElement());
|
||||
return orderElement.getOrder().getCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public String getOrderName(SubcontractedTaskData subcontractedTaskData) {
|
||||
Task task = subcontractedTaskData.getTask();
|
||||
OrderElement orderElement = orderDAO.loadOrderAvoidingProxyFor(task
|
||||
.getOrderElement());
|
||||
return orderElement.getOrder().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentFilter(FilterCommunicationEnum currentFilter) {
|
||||
this.currentFilter = currentFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterCommunicationEnum getCurrentFilter() {
|
||||
return currentFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Order getOrder(OrderElement orderElement) {
|
||||
return (orderDAO.loadOrderAvoidingProxyFor(orderElement)).getOrder();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.web.subcontract;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.datatype.XMLGregorianCalendar;
|
||||
|
||||
import org.libreplan.business.planner.entities.SubcontractedTaskData;
|
||||
import org.libreplan.ws.common.impl.DateConverter;
|
||||
|
||||
/**
|
||||
* DTO UpdateDeliveringDate
|
||||
*
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
@XmlRootElement(name = "update-delivering-date")
|
||||
public class UpdateDeliveringDateDTO {
|
||||
|
||||
@XmlAttribute(name = "customer-reference")
|
||||
public String customerReference;
|
||||
|
||||
@XmlAttribute(name = "external-code")
|
||||
public String externalCode;
|
||||
|
||||
@XmlAttribute(name = "external-company-nif")
|
||||
public String companyNif;
|
||||
|
||||
@XmlAttribute(name = "deliver-date")
|
||||
public XMLGregorianCalendar deliverDate;
|
||||
|
||||
public UpdateDeliveringDateDTO(){
|
||||
}
|
||||
|
||||
public UpdateDeliveringDateDTO(String customerReference,
|
||||
String externalCode, String companyNif, XMLGregorianCalendar deliverDate) {
|
||||
this.customerReference = customerReference;
|
||||
this.deliverDate = deliverDate;
|
||||
this.companyNif = companyNif;
|
||||
this.externalCode = externalCode;
|
||||
}
|
||||
}
|
||||
|
|
@ -43,6 +43,7 @@ import org.libreplan.business.calendars.entities.BaseCalendar;
|
|||
import org.libreplan.business.common.Registry;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.business.externalcompanies.entities.EndDateCommunication;
|
||||
import org.libreplan.business.labels.entities.Label;
|
||||
import org.libreplan.business.materials.bootstrap.PredefinedMaterialCategories;
|
||||
import org.libreplan.business.materials.entities.Material;
|
||||
|
|
@ -74,6 +75,7 @@ import org.libreplan.ws.common.api.OrderElementDTO;
|
|||
import org.libreplan.ws.common.api.OrderLineDTO;
|
||||
import org.libreplan.ws.common.api.OrderLineGroupDTO;
|
||||
import org.libreplan.ws.common.api.ResourceEnumDTO;
|
||||
import org.libreplan.ws.subcontract.api.EndDateCommunicationToCustomerDTO;
|
||||
|
||||
/**
|
||||
* Converter from/to {@link OrderElement} entities to/from DTOs.
|
||||
|
|
@ -846,4 +848,26 @@ public final class OrderElementConverter {
|
|||
.getValue());
|
||||
}
|
||||
|
||||
public static EndDateCommunication toEntity(
|
||||
EndDateCommunicationToCustomerDTO endDateCommunicationToCustomerDTO) {
|
||||
Date endDate = DateConverter.toDate(endDateCommunicationToCustomerDTO.endDate);
|
||||
Date communicationDate = DateConverter
|
||||
.toDate(endDateCommunicationToCustomerDTO.communicationDate);
|
||||
Date saveDate = DateConverter.toDate(endDateCommunicationToCustomerDTO.saveDate);
|
||||
EndDateCommunication endDateCommunicationToCustomer = EndDateCommunication
|
||||
.create(saveDate, endDate, communicationDate);
|
||||
return endDateCommunicationToCustomer;
|
||||
}
|
||||
|
||||
public static EndDateCommunicationToCustomerDTO toDTO(
|
||||
EndDateCommunication endDateCommunicationToCustomer) {
|
||||
XMLGregorianCalendar endDate = DateConverter
|
||||
.toXMLGregorianCalendar(endDateCommunicationToCustomer.getEndDate());
|
||||
XMLGregorianCalendar saveDate = DateConverter
|
||||
.toXMLGregorianCalendar(endDateCommunicationToCustomer.getSaveDate());
|
||||
XMLGregorianCalendar communicationDate = DateConverter
|
||||
.toXMLGregorianCalendar(endDateCommunicationToCustomer.getCommunicationDate());
|
||||
return new EndDateCommunicationToCustomerDTO(saveDate, endDate, communicationDate);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2012 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.ws.subcontract.api;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.datatype.XMLGregorianCalendar;
|
||||
|
||||
import org.libreplan.business.externalcompanies.entities.EndDateCommunication;
|
||||
|
||||
/**
|
||||
* DTO for {@link EndDateCommunication} just with information about end date asked by subcontractors
|
||||
*
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
|
||||
public class EndDateCommunicationToCustomerDTO {
|
||||
|
||||
@XmlAttribute
|
||||
public XMLGregorianCalendar communicationDate;
|
||||
|
||||
@XmlAttribute
|
||||
public XMLGregorianCalendar endDate;
|
||||
|
||||
@XmlAttribute
|
||||
public XMLGregorianCalendar saveDate;
|
||||
|
||||
public EndDateCommunicationToCustomerDTO() {
|
||||
|
||||
}
|
||||
|
||||
public EndDateCommunicationToCustomerDTO(XMLGregorianCalendar saveDate,
|
||||
XMLGregorianCalendar endDate,
|
||||
XMLGregorianCalendar communicationDate) {
|
||||
this.saveDate = saveDate;
|
||||
this.communicationDate = communicationDate;
|
||||
this.endDate = endDate;
|
||||
}
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ import org.libreplan.ws.common.api.InstanceConstraintViolationsListDTO;
|
|||
*/
|
||||
public interface IReportAdvancesService {
|
||||
|
||||
InstanceConstraintViolationsListDTO updateAdvances(
|
||||
OrderElementWithAdvanceMeasurementsListDTO orderElementWithAdvanceMeasurementsListDTO);
|
||||
InstanceConstraintViolationsListDTO updateAdvancesOrEndDate(
|
||||
OrderElementWithAdvanceMeasurementsOrEndDateListDTO orderElementWithAdvanceMeasurementsListDTO);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
package org.libreplan.ws.subcontract.api;
|
||||
|
||||
import org.libreplan.web.subcontract.UpdateDeliveringDateDTO;
|
||||
import org.libreplan.ws.common.api.InstanceConstraintViolationsListDTO;
|
||||
|
||||
|
||||
|
|
@ -34,4 +35,8 @@ public interface ISubcontractService {
|
|||
InstanceConstraintViolationsListDTO subcontract(
|
||||
SubcontractedTaskDataDTO subcontractedTaskDataDTO);
|
||||
|
||||
|
||||
InstanceConstraintViolationsListDTO updateDeliveringDates(
|
||||
UpdateDeliveringDateDTO updateDeliveringDateDTO);
|
||||
|
||||
}
|
||||
|
|
@ -38,7 +38,7 @@ import org.libreplan.ws.common.api.AdvanceMeasurementDTO;
|
|||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
*/
|
||||
@XmlRootElement(name = "order-element")
|
||||
public class OrderElementWithAdvanceMeasurementsDTO {
|
||||
public class OrderElementWithAdvanceMeasurementsOrEndDateDTO {
|
||||
|
||||
@XmlAttribute
|
||||
public String code;
|
||||
|
|
@ -47,13 +47,18 @@ public class OrderElementWithAdvanceMeasurementsDTO {
|
|||
@XmlElement(name = "advance-measurement")
|
||||
public Set<AdvanceMeasurementDTO> advanceMeasurements = new HashSet<AdvanceMeasurementDTO>();
|
||||
|
||||
public OrderElementWithAdvanceMeasurementsDTO() {
|
||||
@XmlElement(name = "end-date-communication-to-customer")
|
||||
public EndDateCommunicationToCustomerDTO endDateCommunicationToCustomerDTO;
|
||||
|
||||
public OrderElementWithAdvanceMeasurementsOrEndDateDTO() {
|
||||
}
|
||||
|
||||
public OrderElementWithAdvanceMeasurementsDTO(String code,
|
||||
Set<AdvanceMeasurementDTO> advanceMeasurements) {
|
||||
public OrderElementWithAdvanceMeasurementsOrEndDateDTO(String code,
|
||||
Set<AdvanceMeasurementDTO> advanceMeasurements,
|
||||
EndDateCommunicationToCustomerDTO endDateCommunicationToCustomerDTO) {
|
||||
this.code = code;
|
||||
this.advanceMeasurements = advanceMeasurements;
|
||||
this.endDateCommunicationToCustomerDTO = endDateCommunicationToCustomerDTO;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -36,19 +36,19 @@ import org.libreplan.business.orders.entities.OrderElement;
|
|||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
*/
|
||||
@XmlRootElement(name = "order-element-list")
|
||||
public class OrderElementWithAdvanceMeasurementsListDTO {
|
||||
public class OrderElementWithAdvanceMeasurementsOrEndDateListDTO {
|
||||
|
||||
@XmlAttribute(name = "external-company-nif")
|
||||
public String externalCompanyNif;
|
||||
|
||||
@XmlElement(name = "order-element")
|
||||
public List<OrderElementWithAdvanceMeasurementsDTO> orderElements = new ArrayList<OrderElementWithAdvanceMeasurementsDTO>();
|
||||
public List<OrderElementWithAdvanceMeasurementsOrEndDateDTO> orderElements = new ArrayList<OrderElementWithAdvanceMeasurementsOrEndDateDTO>();
|
||||
|
||||
public OrderElementWithAdvanceMeasurementsListDTO() {
|
||||
public OrderElementWithAdvanceMeasurementsOrEndDateListDTO() {
|
||||
}
|
||||
|
||||
public OrderElementWithAdvanceMeasurementsListDTO(String externalCompanyNif,
|
||||
List<OrderElementWithAdvanceMeasurementsDTO> orderElements) {
|
||||
public OrderElementWithAdvanceMeasurementsOrEndDateListDTO(String externalCompanyNif,
|
||||
List<OrderElementWithAdvanceMeasurementsOrEndDateDTO> orderElements) {
|
||||
this.externalCompanyNif = externalCompanyNif;
|
||||
this.orderElements = orderElements;
|
||||
}
|
||||
|
|
@ -27,6 +27,7 @@ import javax.xml.bind.annotation.XmlAttribute;
|
|||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlElements;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.datatype.XMLGregorianCalendar;
|
||||
|
||||
import org.libreplan.business.planner.entities.SubcontractedTaskData;
|
||||
import org.libreplan.ws.common.api.OrderDTO;
|
||||
|
|
@ -54,6 +55,9 @@ public class SubcontractedTaskDataDTO {
|
|||
@XmlAttribute(name = "subcontracted-code")
|
||||
public String subcontractedCode;
|
||||
|
||||
@XmlAttribute(name = "deliver-date")
|
||||
public XMLGregorianCalendar deliverDate;
|
||||
|
||||
@XmlElements( {
|
||||
@XmlElement(name = "order-line", type = OrderLineDTO.class),
|
||||
@XmlElement(name = "order-line-group", type = OrderLineGroupDTO.class),
|
||||
|
|
@ -65,12 +69,14 @@ public class SubcontractedTaskDataDTO {
|
|||
|
||||
public SubcontractedTaskDataDTO(String externalCompanyNif,
|
||||
String workDescription, BigDecimal subcontractPrice,
|
||||
String subcontractedCode, OrderElementDTO orderElementDTO) {
|
||||
String subcontractedCode, OrderElementDTO orderElementDTO,
|
||||
XMLGregorianCalendar deliverDate) {
|
||||
this.externalCompanyNif = externalCompanyNif;
|
||||
this.workDescription = workDescription;
|
||||
this.subcontractPrice = subcontractPrice;
|
||||
this.subcontractedCode = subcontractedCode;
|
||||
this.orderElementDTO = orderElementDTO;
|
||||
this.deliverDate = deliverDate;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
* Desenvolvemento Tecnolóxico de Galicia
|
||||
* Copyright (C) 2010-2011 Igalia, S.L.
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
|
|
@ -24,7 +26,9 @@ package org.libreplan.ws.subcontract.impl;
|
|||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.POST;
|
||||
|
|
@ -41,11 +45,19 @@ import org.libreplan.business.advance.exceptions.DuplicateValueTrueReportGlobalA
|
|||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.business.externalcompanies.daos.IExternalCompanyDAO;
|
||||
import org.libreplan.business.externalcompanies.entities.CommunicationType;
|
||||
import org.libreplan.business.externalcompanies.entities.EndDateCommunication;
|
||||
import org.libreplan.business.externalcompanies.entities.ExternalCompany;
|
||||
import org.libreplan.business.orders.daos.IOrderDAO;
|
||||
import org.libreplan.business.orders.daos.IOrderElementDAO;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderElement;
|
||||
import org.libreplan.business.planner.daos.ISubcontractedTaskDataDAO;
|
||||
import org.libreplan.business.planner.daos.ISubcontractorCommunicationDAO;
|
||||
import org.libreplan.business.planner.entities.SubcontractedTaskData;
|
||||
import org.libreplan.business.planner.entities.SubcontractorCommunication;
|
||||
import org.libreplan.business.planner.entities.SubcontractorCommunicationValue;
|
||||
import org.libreplan.business.planner.entities.Task;
|
||||
import org.libreplan.business.scenarios.bootstrap.PredefinedScenarios;
|
||||
import org.libreplan.business.scenarios.entities.OrderVersion;
|
||||
import org.libreplan.business.scenarios.entities.Scenario;
|
||||
|
|
@ -56,9 +68,10 @@ import org.libreplan.ws.common.impl.ConstraintViolationConverter;
|
|||
import org.libreplan.ws.common.impl.DateConverter;
|
||||
import org.libreplan.ws.common.impl.OrderElementConverter;
|
||||
import org.libreplan.ws.common.impl.Util;
|
||||
import org.libreplan.ws.subcontract.api.EndDateCommunicationToCustomerDTO;
|
||||
import org.libreplan.ws.subcontract.api.IReportAdvancesService;
|
||||
import org.libreplan.ws.subcontract.api.OrderElementWithAdvanceMeasurementsDTO;
|
||||
import org.libreplan.ws.subcontract.api.OrderElementWithAdvanceMeasurementsListDTO;
|
||||
import org.libreplan.ws.subcontract.api.OrderElementWithAdvanceMeasurementsOrEndDateDTO;
|
||||
import org.libreplan.ws.subcontract.api.OrderElementWithAdvanceMeasurementsOrEndDateListDTO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
|
@ -67,6 +80,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
* REST-based implementation of {@link IReportAdvancesService}.
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
@Path("/reportadvances/")
|
||||
@Produces("application/xml")
|
||||
|
|
@ -76,32 +90,37 @@ public class ReportAdvancesServiceREST implements IReportAdvancesService {
|
|||
@Autowired
|
||||
private IOrderElementDAO orderElementDAO;
|
||||
|
||||
@Autowired
|
||||
private ISubcontractedTaskDataDAO subcontractedTaskDataDAO;
|
||||
|
||||
@Autowired
|
||||
private ISubcontractorCommunicationDAO subcontractorCommunicationDAO;
|
||||
|
||||
@Autowired
|
||||
private IOrderDAO orderDAO;
|
||||
|
||||
@Autowired
|
||||
private IExternalCompanyDAO externalCompanyDAO;
|
||||
|
||||
private InstanceConstraintViolationsListDTO getErrorMessage(String code,
|
||||
String message) {
|
||||
private InstanceConstraintViolationsListDTO getErrorMessage(String code, String message) {
|
||||
// FIXME review errors returned
|
||||
return new InstanceConstraintViolationsListDTO(Arrays
|
||||
.asList(InstanceConstraintViolationsDTO.create(Util
|
||||
.generateInstanceId(1, code), message)));
|
||||
return new InstanceConstraintViolationsListDTO(
|
||||
Arrays.asList(InstanceConstraintViolationsDTO.create(
|
||||
Util.generateInstanceId(1, code), message)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@POST
|
||||
@Consumes("application/xml")
|
||||
@Transactional
|
||||
public InstanceConstraintViolationsListDTO updateAdvances(OrderElementWithAdvanceMeasurementsListDTO orderElementWithAdvanceMeasurementsListDTO) {
|
||||
public InstanceConstraintViolationsListDTO updateAdvancesOrEndDate(
|
||||
OrderElementWithAdvanceMeasurementsOrEndDateListDTO orderElementWithAdvanceMeasurementsListDTO) {
|
||||
|
||||
List<InstanceConstraintViolationsDTO> instanceConstraintViolationsList = new ArrayList<InstanceConstraintViolationsDTO>();
|
||||
|
||||
InstanceConstraintViolationsDTO instanceConstraintViolationsDTO = null;
|
||||
|
||||
if (StringUtils
|
||||
.isEmpty(orderElementWithAdvanceMeasurementsListDTO.externalCompanyNif)) {
|
||||
if (StringUtils.isEmpty(orderElementWithAdvanceMeasurementsListDTO.externalCompanyNif)) {
|
||||
return getErrorMessage("", "external company ID not specified");
|
||||
}
|
||||
|
||||
|
|
@ -110,109 +129,203 @@ public class ReportAdvancesServiceREST implements IReportAdvancesService {
|
|||
externalCompany = externalCompanyDAO
|
||||
.findUniqueByNif(orderElementWithAdvanceMeasurementsListDTO.externalCompanyNif);
|
||||
} catch (InstanceNotFoundException e1) {
|
||||
return getErrorMessage(
|
||||
orderElementWithAdvanceMeasurementsListDTO.externalCompanyNif,
|
||||
return getErrorMessage(orderElementWithAdvanceMeasurementsListDTO.externalCompanyNif,
|
||||
"external company not found");
|
||||
}
|
||||
|
||||
if (!externalCompany.isSubcontractor()) {
|
||||
return getErrorMessage(
|
||||
orderElementWithAdvanceMeasurementsListDTO.externalCompanyNif,
|
||||
return getErrorMessage(orderElementWithAdvanceMeasurementsListDTO.externalCompanyNif,
|
||||
"external company is not registered as subcontractor");
|
||||
}
|
||||
|
||||
List<OrderElementWithAdvanceMeasurementsDTO> orderElements = orderElementWithAdvanceMeasurementsListDTO.orderElements;
|
||||
for (OrderElementWithAdvanceMeasurementsDTO orderElementWithAdvanceMeasurementsDTO : orderElements) {
|
||||
List<OrderElementWithAdvanceMeasurementsOrEndDateDTO> orderElements = orderElementWithAdvanceMeasurementsListDTO.orderElements;
|
||||
for (OrderElementWithAdvanceMeasurementsOrEndDateDTO orderElementWithAdvanceMeasurementsOrEndDateDTO : orderElements) {
|
||||
try {
|
||||
OrderElement orderElement = orderElementDAO
|
||||
.findUniqueByCode(orderElementWithAdvanceMeasurementsDTO.code);
|
||||
.findUniqueByCode(orderElementWithAdvanceMeasurementsOrEndDateDTO.code);
|
||||
|
||||
DirectAdvanceAssignment advanceAssignmentSubcontractor = orderElement
|
||||
.getDirectAdvanceAssignmentSubcontractor();
|
||||
|
||||
if (advanceAssignmentSubcontractor == null) {
|
||||
DirectAdvanceAssignment reportGlobal = orderElement
|
||||
.getReportGlobalAdvanceAssignment();
|
||||
|
||||
advanceAssignmentSubcontractor = DirectAdvanceAssignment
|
||||
.create((reportGlobal == null), new BigDecimal(100));
|
||||
advanceAssignmentSubcontractor
|
||||
.setAdvanceType(PredefinedAdvancedTypes.SUBCONTRACTOR
|
||||
.getType());
|
||||
advanceAssignmentSubcontractor
|
||||
.setOrderElement(orderElement);
|
||||
|
||||
try {
|
||||
orderElement
|
||||
.addAdvanceAssignment(advanceAssignmentSubcontractor);
|
||||
} catch (DuplicateValueTrueReportGlobalAdvanceException e) {
|
||||
// This shouldn't happen, because new advance is only
|
||||
// marked as report global if there is not other advance
|
||||
// as report global
|
||||
throw new RuntimeException(e);
|
||||
} catch (DuplicateAdvanceAssignmentForOrderElementException e) {
|
||||
return getErrorMessage(
|
||||
orderElementWithAdvanceMeasurementsDTO.code,
|
||||
"someone in the same branch has the same advance type");
|
||||
}
|
||||
}
|
||||
|
||||
for (AdvanceMeasurementDTO advanceMeasurementDTO : orderElementWithAdvanceMeasurementsDTO.advanceMeasurements) {
|
||||
AdvanceMeasurement advanceMeasurement = advanceAssignmentSubcontractor
|
||||
.getAdvanceMeasurementAtExactDate(DateConverter
|
||||
.toLocalDate(advanceMeasurementDTO.date));
|
||||
if (advanceMeasurement == null) {
|
||||
advanceAssignmentSubcontractor
|
||||
.addAdvanceMeasurements(OrderElementConverter
|
||||
.toEntity(advanceMeasurementDTO));
|
||||
} else {
|
||||
advanceMeasurement
|
||||
.setValue(advanceMeasurementDTO.value);
|
||||
}
|
||||
}
|
||||
|
||||
// set the advance assingment subcontractor like spread
|
||||
AdvanceAssignment spreadAdvance = orderElement
|
||||
.getReportGlobalAdvanceAssignment();
|
||||
if (spreadAdvance != null
|
||||
&& !spreadAdvance
|
||||
.equals(advanceAssignmentSubcontractor)) {
|
||||
spreadAdvance.setReportGlobalAdvance(false);
|
||||
advanceAssignmentSubcontractor.setReportGlobalAdvance(true);
|
||||
}
|
||||
// update the advance percentage in its related task
|
||||
Scenario scenarioMaster = PredefinedScenarios.MASTER
|
||||
.getScenario();
|
||||
Scenario scenarioMaster = PredefinedScenarios.MASTER.getScenario();
|
||||
Order order = orderDAO.loadOrderAvoidingProxyFor(orderElement);
|
||||
OrderVersion orderVersion = order.getScenarios().get(
|
||||
scenarioMaster);
|
||||
updateAdvancePercentage(orderVersion, orderElement);
|
||||
OrderVersion orderVersion = order.getScenarios().get(scenarioMaster);
|
||||
|
||||
if (orderElementWithAdvanceMeasurementsOrEndDateDTO.advanceMeasurements != null
|
||||
&& !orderElementWithAdvanceMeasurementsOrEndDateDTO.advanceMeasurements
|
||||
.isEmpty()) {
|
||||
updateAdvances(orderVersion, orderElement,
|
||||
orderElementWithAdvanceMeasurementsOrEndDateDTO);
|
||||
}
|
||||
|
||||
if (orderElementWithAdvanceMeasurementsOrEndDateDTO.endDateCommunicationToCustomerDTO != null) {
|
||||
updateEndDate(orderVersion, orderElement,
|
||||
orderElementWithAdvanceMeasurementsOrEndDateDTO);
|
||||
}
|
||||
|
||||
orderElement.validate();
|
||||
orderElementDAO.save(orderElement);
|
||||
} catch (ValidationException e) {
|
||||
instanceConstraintViolationsDTO = ConstraintViolationConverter
|
||||
.toDTO(Util.generateInstanceId(1,
|
||||
orderElementWithAdvanceMeasurementsDTO.code), e
|
||||
instanceConstraintViolationsDTO = ConstraintViolationConverter.toDTO(
|
||||
Util.generateInstanceId(1,
|
||||
orderElementWithAdvanceMeasurementsOrEndDateDTO.code), e
|
||||
.getInvalidValues());
|
||||
} catch (InstanceNotFoundException e) {
|
||||
return getErrorMessage(
|
||||
orderElementWithAdvanceMeasurementsDTO.code,
|
||||
return getErrorMessage(orderElementWithAdvanceMeasurementsOrEndDateDTO.code,
|
||||
"instance not found");
|
||||
}
|
||||
}
|
||||
|
||||
if (instanceConstraintViolationsDTO != null) {
|
||||
instanceConstraintViolationsList
|
||||
.add(instanceConstraintViolationsDTO);
|
||||
instanceConstraintViolationsList.add(instanceConstraintViolationsDTO);
|
||||
}
|
||||
|
||||
return new InstanceConstraintViolationsListDTO(
|
||||
instanceConstraintViolationsList);
|
||||
return new InstanceConstraintViolationsListDTO(instanceConstraintViolationsList);
|
||||
}
|
||||
|
||||
private void updateAdvancePercentage(OrderVersion orderVersion,
|
||||
OrderElement orderElement) {
|
||||
@Transactional
|
||||
public InstanceConstraintViolationsListDTO updateAdvances(
|
||||
OrderVersion orderVersion,
|
||||
OrderElement orderElement,
|
||||
OrderElementWithAdvanceMeasurementsOrEndDateDTO orderElementWithAdvanceMeasurementsOrEndDateDTO) {
|
||||
DirectAdvanceAssignment advanceAssignmentSubcontractor = orderElement
|
||||
.getDirectAdvanceAssignmentSubcontractor();
|
||||
|
||||
if (advanceAssignmentSubcontractor == null) {
|
||||
DirectAdvanceAssignment reportGlobal = orderElement.getReportGlobalAdvanceAssignment();
|
||||
|
||||
advanceAssignmentSubcontractor = DirectAdvanceAssignment.create((reportGlobal == null),
|
||||
new BigDecimal(100));
|
||||
advanceAssignmentSubcontractor.setAdvanceType(PredefinedAdvancedTypes.SUBCONTRACTOR
|
||||
.getType());
|
||||
advanceAssignmentSubcontractor.setOrderElement(orderElement);
|
||||
|
||||
try {
|
||||
orderElement.addAdvanceAssignment(advanceAssignmentSubcontractor);
|
||||
} catch (DuplicateValueTrueReportGlobalAdvanceException e) {
|
||||
// This shouldn't happen, because new advance is only
|
||||
// marked as report global if there is not other advance
|
||||
// as report global
|
||||
throw new RuntimeException(e);
|
||||
} catch (DuplicateAdvanceAssignmentForOrderElementException e) {
|
||||
return getErrorMessage(orderElementWithAdvanceMeasurementsOrEndDateDTO.code,
|
||||
"someone in the same branch has the same advance type");
|
||||
}
|
||||
}
|
||||
|
||||
for (AdvanceMeasurementDTO advanceMeasurementDTO : orderElementWithAdvanceMeasurementsOrEndDateDTO.advanceMeasurements) {
|
||||
AdvanceMeasurement advanceMeasurement = advanceAssignmentSubcontractor
|
||||
.getAdvanceMeasurementAtExactDate(DateConverter
|
||||
.toLocalDate(advanceMeasurementDTO.date));
|
||||
if (advanceMeasurement == null) {
|
||||
advanceAssignmentSubcontractor.addAdvanceMeasurements(OrderElementConverter
|
||||
.toEntity(advanceMeasurementDTO));
|
||||
} else {
|
||||
advanceMeasurement.setValue(advanceMeasurementDTO.value);
|
||||
}
|
||||
}
|
||||
|
||||
// set the advance assingment subcontractor like spread
|
||||
AdvanceAssignment spreadAdvance = orderElement.getReportGlobalAdvanceAssignment();
|
||||
if (spreadAdvance != null && !spreadAdvance.equals(advanceAssignmentSubcontractor)) {
|
||||
spreadAdvance.setReportGlobalAdvance(false);
|
||||
advanceAssignmentSubcontractor.setReportGlobalAdvance(true);
|
||||
}
|
||||
// update the advance percentage in its related task
|
||||
updateAdvancePercentage(orderVersion, orderElement);
|
||||
|
||||
orderElement.validate();
|
||||
orderElementDAO.save(orderElement);
|
||||
|
||||
/*
|
||||
* If the order element is subcontrated then create the subcontrated
|
||||
* communication for the subcontrated task data to which the order
|
||||
* element belongs.
|
||||
*/
|
||||
try {
|
||||
createSubcontractorCommunicationWithNewProgress(orderElement,
|
||||
orderElementWithAdvanceMeasurementsOrEndDateDTO.advanceMeasurements);
|
||||
} catch (InstanceNotFoundException e) {
|
||||
return getErrorMessage(orderElementWithAdvanceMeasurementsOrEndDateDTO.code,
|
||||
"instance not found");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void createSubcontractorCommunicationWithNewProgress(OrderElement orderElement,
|
||||
Set<AdvanceMeasurementDTO> advanceMeasurementDTOs) throws InstanceNotFoundException {
|
||||
if (orderElement != null && orderElement.getTaskSource() != null
|
||||
&& orderElement.getTaskSource().getTask().isSubcontracted()) {
|
||||
Task task = (Task) orderElement.getTaskSource().getTask();
|
||||
SubcontractedTaskData subcontractedTaskData = task.getSubcontractedTaskData();
|
||||
if (subcontractedTaskData != null) {
|
||||
SubcontractorCommunication subcontractorCommunication = SubcontractorCommunication
|
||||
.create(subcontractedTaskData, CommunicationType.PROGRESS_UPDATE,
|
||||
new Date(), false);
|
||||
|
||||
for (AdvanceMeasurementDTO advanceMeasurementDTO : advanceMeasurementDTOs) {
|
||||
// add subcontractorCommunicationValue
|
||||
addSubcontractorCommunicationValue(advanceMeasurementDTO,
|
||||
subcontractorCommunication);
|
||||
}
|
||||
subcontractorCommunicationDAO.save(subcontractorCommunication);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public InstanceConstraintViolationsListDTO updateEndDate(
|
||||
OrderVersion orderVersion,
|
||||
OrderElement orderElement,
|
||||
OrderElementWithAdvanceMeasurementsOrEndDateDTO orderElementWithAdvanceMeasurementsOrEndDateDTO) {
|
||||
try {
|
||||
orderElement.useSchedulingDataFor(orderVersion);
|
||||
|
||||
if (orderElement != null && orderElement.getTaskSource() != null
|
||||
&& orderElement.getTaskSource().getTask().isSubcontracted()) {
|
||||
|
||||
Task task = (Task) orderElement.getTaskSource().getTask();
|
||||
SubcontractedTaskData subcontractedTaskData = task.getSubcontractedTaskData();
|
||||
EndDateCommunicationToCustomerDTO endDateDTO = orderElementWithAdvanceMeasurementsOrEndDateDTO.endDateCommunicationToCustomerDTO;
|
||||
|
||||
Date endDate = DateConverter.toDate(endDateDTO.endDate);
|
||||
Date communicationDate = DateConverter.toDate(endDateDTO.communicationDate);
|
||||
|
||||
subcontractedTaskData.getEndDatesCommunicatedFromSubcontractor().add(
|
||||
EndDateCommunication.create(new Date(), endDate,
|
||||
communicationDate));
|
||||
subcontractedTaskDataDAO.save(subcontractedTaskData);
|
||||
|
||||
createSubcontractorCommunicationWithNewEndDate(subcontractedTaskData, endDateDTO);
|
||||
}
|
||||
} catch (InstanceNotFoundException e) {
|
||||
return getErrorMessage(orderElementWithAdvanceMeasurementsOrEndDateDTO.code,
|
||||
"instance not found");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void createSubcontractorCommunicationWithNewEndDate(
|
||||
SubcontractedTaskData subcontractedTaskData,
|
||||
EndDateCommunicationToCustomerDTO endDateDTO) throws InstanceNotFoundException {
|
||||
|
||||
if (subcontractedTaskData != null) {
|
||||
SubcontractorCommunication subcontractorCommunication = SubcontractorCommunication
|
||||
.create(subcontractedTaskData, CommunicationType.END_DATE_UPDATE,
|
||||
new Date(), false);
|
||||
Date dateValue = DateConverter.toDate(endDateDTO.endDate);
|
||||
SubcontractorCommunicationValue value = SubcontractorCommunicationValue.create(
|
||||
dateValue, null);
|
||||
subcontractorCommunication.getSubcontractorCommunicationValues().add(value);
|
||||
subcontractorCommunicationDAO.save(subcontractorCommunication);
|
||||
}
|
||||
}
|
||||
|
||||
private void addSubcontractorCommunicationValue(AdvanceMeasurementDTO advanceMeasurementDTO,
|
||||
SubcontractorCommunication subcontractorCommunication) {
|
||||
Date dateValue = DateConverter.toDate(advanceMeasurementDTO.date);
|
||||
SubcontractorCommunicationValue value = SubcontractorCommunicationValue.create(dateValue,
|
||||
advanceMeasurementDTO.value);
|
||||
subcontractorCommunication.getSubcontractorCommunicationValues().add(value);
|
||||
}
|
||||
|
||||
private void updateAdvancePercentage(OrderVersion orderVersion, OrderElement orderElement) {
|
||||
orderElement.useSchedulingDataFor(orderVersion);
|
||||
OrderElement parent = orderElement.getParent();
|
||||
while (parent != null) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
* Desenvolvemento Tecnolóxico de Galicia
|
||||
* Copyright (C) 2010-2011 Igalia, S.L.
|
||||
*
|
||||
* Copyright (C) 2011 WirelessGalicia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
|
|
@ -22,6 +24,7 @@
|
|||
package org.libreplan.ws.subcontract.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
|
|
@ -32,6 +35,7 @@ import javax.ws.rs.Produces;
|
|||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.hibernate.NonUniqueResultException;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.libreplan.business.calendars.entities.BaseCalendar;
|
||||
import org.libreplan.business.common.IAdHocTransactionService;
|
||||
import org.libreplan.business.common.IOnTransaction;
|
||||
|
|
@ -42,7 +46,11 @@ import org.libreplan.business.common.entities.EntityNameEnum;
|
|||
import org.libreplan.business.common.entities.EntitySequence;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.business.externalcompanies.daos.ICustomerCommunicationDAO;
|
||||
import org.libreplan.business.externalcompanies.daos.IExternalCompanyDAO;
|
||||
import org.libreplan.business.externalcompanies.entities.CommunicationType;
|
||||
import org.libreplan.business.externalcompanies.entities.CustomerCommunication;
|
||||
import org.libreplan.business.externalcompanies.entities.DeadlineCommunication;
|
||||
import org.libreplan.business.externalcompanies.entities.ExternalCompany;
|
||||
import org.libreplan.business.orders.daos.IOrderElementDAO;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
|
|
@ -55,6 +63,7 @@ import org.libreplan.business.planner.daos.ITaskSourceDAO;
|
|||
import org.libreplan.business.scenarios.daos.IScenarioDAO;
|
||||
import org.libreplan.business.scenarios.entities.OrderVersion;
|
||||
import org.libreplan.business.scenarios.entities.Scenario;
|
||||
import org.libreplan.web.subcontract.UpdateDeliveringDateDTO;
|
||||
import org.libreplan.ws.common.api.InstanceConstraintViolationsDTO;
|
||||
import org.libreplan.ws.common.api.InstanceConstraintViolationsDTOId;
|
||||
import org.libreplan.ws.common.api.InstanceConstraintViolationsListDTO;
|
||||
|
|
@ -62,6 +71,7 @@ import org.libreplan.ws.common.api.OrderDTO;
|
|||
import org.libreplan.ws.common.api.OrderElementDTO;
|
||||
import org.libreplan.ws.common.impl.ConfigurationOrderElementConverter;
|
||||
import org.libreplan.ws.common.impl.ConstraintViolationConverter;
|
||||
import org.libreplan.ws.common.impl.DateConverter;
|
||||
import org.libreplan.ws.common.impl.OrderElementConverter;
|
||||
import org.libreplan.ws.common.impl.Util;
|
||||
import org.libreplan.ws.subcontract.api.ISubcontractService;
|
||||
|
|
@ -73,6 +83,7 @@ import org.springframework.stereotype.Service;
|
|||
* REST-based implementation of {@link ISubcontractService}
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
*/
|
||||
@Path("/subcontract/")
|
||||
@Produces("application/xml")
|
||||
|
|
@ -94,6 +105,9 @@ public class SubcontractServiceREST implements ISubcontractService {
|
|||
@Autowired
|
||||
private IScenarioDAO scenarioDAO;
|
||||
|
||||
@Autowired
|
||||
private ICustomerCommunicationDAO customerCommunicationDAO;
|
||||
|
||||
@Autowired
|
||||
private ITaskSourceDAO taskSourceDAO;
|
||||
|
||||
|
|
@ -123,6 +137,104 @@ public class SubcontractServiceREST implements ISubcontractService {
|
|||
|
||||
@Override
|
||||
@POST
|
||||
@Path("update/")
|
||||
@Consumes("application/xml")
|
||||
public InstanceConstraintViolationsListDTO updateDeliveringDates(
|
||||
final UpdateDeliveringDateDTO updateDeliveringDateDTO) {
|
||||
try {
|
||||
updateSubcontract(updateDeliveringDateDTO);
|
||||
} catch (ViolationError e) {
|
||||
return e.toViolationList();
|
||||
}
|
||||
return new InstanceConstraintViolationsListDTO();
|
||||
}
|
||||
|
||||
|
||||
private void updateSubcontract(
|
||||
final UpdateDeliveringDateDTO updateDeliveringDateDTO) {
|
||||
|
||||
if (StringUtils.isEmpty(updateDeliveringDateDTO.companyNif)) {
|
||||
throw new ViolationError(updateDeliveringDateDTO.companyNif,
|
||||
"external company Nif not specified");
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(updateDeliveringDateDTO.externalCode)) {
|
||||
throw new ViolationError(updateDeliveringDateDTO.externalCode,
|
||||
"external order code not specified");
|
||||
}
|
||||
|
||||
if ((updateDeliveringDateDTO.deliverDate) == null) {
|
||||
throw new ViolationError(updateDeliveringDateDTO.deliverDate.toString(),
|
||||
"deliver date not specified");
|
||||
}
|
||||
|
||||
final ExternalCompany externalCompany = adHocTransactionService
|
||||
.runOnTransaction(new IOnTransaction<ExternalCompany>() {
|
||||
@Override
|
||||
public ExternalCompany execute() {
|
||||
return findExternalCompanyFor(updateDeliveringDateDTO.companyNif);
|
||||
}
|
||||
});
|
||||
if (!externalCompany.isClient()) {
|
||||
throw new ViolationError(updateDeliveringDateDTO.companyNif,
|
||||
"external company is not registered as client");
|
||||
}
|
||||
try {
|
||||
adHocTransactionService
|
||||
.runOnTransaction(new IOnTransaction<Void>() {
|
||||
|
||||
@Override
|
||||
public Void execute() {
|
||||
updateDeliveringDateInOrder(updateDeliveringDateDTO);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
} catch (ValidationException e) {
|
||||
InstanceConstraintViolationsDTO violation = ConstraintViolationConverter
|
||||
.toDTO(new InstanceConstraintViolationsDTOId(Long.valueOf(1),
|
||||
updateDeliveringDateDTO.companyNif, OrderDTO.ENTITY_TYPE), e);
|
||||
throw new ViolationError(violation);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDeliveringDateInOrder(UpdateDeliveringDateDTO updateDeliveringDateDTO){
|
||||
try {
|
||||
OrderElement orderElement = orderElementDAO
|
||||
.findByExternalCode(updateDeliveringDateDTO.externalCode);
|
||||
|
||||
if((orderElement != null) && (orderElement instanceof Order)) {
|
||||
Order order = (Order)orderElement;
|
||||
|
||||
Date newDeliverDate = DateConverter.toDate(updateDeliveringDateDTO.deliverDate);
|
||||
DeadlineCommunication deadlineCommunication = DeadlineCommunication
|
||||
.create(new Date(), newDeliverDate);
|
||||
order.getDeliveringDates().add(deadlineCommunication);
|
||||
|
||||
LocalDate newLocalDeliverDate = new LocalDate(newDeliverDate);
|
||||
OrderVersion orderVersion = order.getOrderVersionFor(Registry
|
||||
.getScenarioManager().getCurrent());
|
||||
order.useSchedulingDataFor(orderVersion);
|
||||
if (order.getAssociatedTaskElement() != null) {
|
||||
order.getAssociatedTaskElement().setDeadline(
|
||||
newLocalDeliverDate);
|
||||
}
|
||||
createCustomerCommunication(order, CommunicationType.UPDATE_DELIVERING_DATE);
|
||||
orderElementDAO.save(order);
|
||||
|
||||
} else {
|
||||
throw new ViolationError(
|
||||
updateDeliveringDateDTO.customerReference,
|
||||
"It do not exist any order with this reference");
|
||||
}
|
||||
} catch (InstanceNotFoundException e) {
|
||||
throw new ViolationError(updateDeliveringDateDTO.customerReference,
|
||||
"It do not exist any order with this reference");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@POST
|
||||
@Path("create/")
|
||||
@Consumes("application/xml")
|
||||
public InstanceConstraintViolationsListDTO subcontract(
|
||||
final SubcontractedTaskDataDTO subcontractedTaskDataDTO) {
|
||||
|
|
@ -193,6 +305,7 @@ public class SubcontractServiceREST implements ISubcontractService {
|
|||
order = (Order) orderElement;
|
||||
order.setVersionForScenario(current, version);
|
||||
order.useSchedulingDataFor(version);
|
||||
order.setExternalCode(order.getCode());
|
||||
} else {
|
||||
order = wrapInOrder(current, version,
|
||||
orderElement);
|
||||
|
|
@ -223,8 +336,22 @@ public class SubcontractServiceREST implements ISubcontractService {
|
|||
TaskSource.persistTaskSources(taskSourceDAO));
|
||||
order.writeSchedulingDataChanges();
|
||||
|
||||
if (subcontractedTaskDataDTO.deliverDate != null) {
|
||||
DeadlineCommunication deadlineCommunication = DeadlineCommunication
|
||||
.create(new Date(), DateConverter
|
||||
.toDate(subcontractedTaskDataDTO.deliverDate));
|
||||
order.getDeliveringDates().add(deadlineCommunication);
|
||||
}
|
||||
|
||||
order.validate();
|
||||
orderElementDAO.save(order);
|
||||
|
||||
/*
|
||||
* create the customer communication to a new subcontrating project.
|
||||
*/
|
||||
if(!StringUtils.isBlank(order.getExternalCode())){
|
||||
createCustomerCommunication(order, CommunicationType.NEW_PROJECT);
|
||||
}
|
||||
}
|
||||
|
||||
private void synchronizeWithSchedule(OrderElement orderElement,
|
||||
|
|
@ -286,13 +413,18 @@ public class SubcontractServiceREST implements ISubcontractService {
|
|||
}
|
||||
|
||||
private ExternalCompany findExternalCompanyFor(
|
||||
final SubcontractedTaskDataDTO subcontractedTask)
|
||||
final SubcontractedTaskDataDTO subcontractedTask){
|
||||
return findExternalCompanyFor(subcontractedTask.externalCompanyNif);
|
||||
}
|
||||
|
||||
private ExternalCompany findExternalCompanyFor(
|
||||
final String externalCompanyNif)
|
||||
throws ViolationError {
|
||||
try {
|
||||
return externalCompanyDAO
|
||||
.findUniqueByNif(subcontractedTask.externalCompanyNif);
|
||||
.findUniqueByNif(externalCompanyNif);
|
||||
} catch (InstanceNotFoundException e) {
|
||||
throw new ViolationError(subcontractedTask.externalCompanyNif,
|
||||
throw new ViolationError(externalCompanyNif,
|
||||
"external company not found");
|
||||
}
|
||||
}
|
||||
|
|
@ -303,4 +435,17 @@ public class SubcontractServiceREST implements ISubcontractService {
|
|||
Util.generateInstanceId(1, code), message);
|
||||
}
|
||||
|
||||
private void createCustomerCommunication(Order order, CommunicationType type){
|
||||
Date communicationDate = new Date();
|
||||
Date deadline = null;
|
||||
if(type.equals(CommunicationType.NEW_PROJECT)){
|
||||
deadline = order.getDeadline();
|
||||
}else{
|
||||
deadline = order.getDeliveringDates().first().getDeliverDate();
|
||||
}
|
||||
CustomerCommunication customerCommunication = CustomerCommunication
|
||||
.create(deadline, communicationDate,
|
||||
type, order);
|
||||
customerCommunicationDAO.save(customerCommunication);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue