Merge branch 'master' into expenses-tracking

This commit is contained in:
Susana Montes Pedreira 2012-05-09 10:51:43 +01:00
commit 00378d039a
119 changed files with 6691 additions and 1321 deletions

View file

@ -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> {

View file

@ -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();
}
}

View file

@ -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();
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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();
}

View file

@ -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());
}
}

View file

@ -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;
}
}

View file

@ -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());
}
}

View file

@ -128,4 +128,6 @@ public interface IOrderElementDAO extends IIntegrationEntityDAO<OrderElement> {
boolean hasImputedExpenseSheet(Long id) throws InstanceNotFoundException;
OrderElement findByExternalCode(String code) throws InstanceNotFoundException;
}

View file

@ -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.

View file

@ -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;
}

View file

@ -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 {

View file

@ -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;
}

View file

@ -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();
}

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -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;
}
}

View file

@ -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;
}
};
}
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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));
}
}

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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() {

View file

@ -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

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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
}
}
}

View file

@ -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>() {

View file

@ -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
}
}
}

View file

@ -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>

View file

@ -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()) {

View file

@ -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

View file

@ -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());

View file

@ -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;
}
}

View file

@ -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);
}
}
}

View file

@ -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("");
}
}

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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 {

View file

@ -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,

View file

@ -75,7 +75,7 @@ interface IDashboardModel {
Map<TaskStatusEnum, Integer> calculateTaskStatus();
Map<Interval, Integer> calculateTaskCompletation();
Map<Interval, Integer> calculateTaskCompletion();
Map<Interval, Integer> calculateEstimationAccuracy();

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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");
}
}
}

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -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;

View file

@ -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();
}

View file

@ -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) {

View file

@ -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),

View file

@ -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;
}
}
}
}

View file

@ -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();

View file

@ -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();
}

View file

@ -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;
}
}

View file

@ -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());
}
}
}

View file

@ -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);

View file

@ -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) {

View file

@ -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();
}
}

View file

@ -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>();
}
}

View file

@ -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);
}

View file

@ -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

View file

@ -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);
}
}

View file

@ -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();
}

View file

@ -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 {

View file

@ -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) {

View file

@ -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();
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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();
}

View file

@ -53,4 +53,6 @@ public interface IReportAdvancesModel {
boolean isAnyAdvanceMeasurementNotReported(
DirectAdvanceAssignment directAdvanceAssignment);
String getStatus(Order order);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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) {

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -30,7 +30,7 @@ import org.libreplan.ws.common.api.InstanceConstraintViolationsListDTO;
*/
public interface IReportAdvancesService {
InstanceConstraintViolationsListDTO updateAdvances(
OrderElementWithAdvanceMeasurementsListDTO orderElementWithAdvanceMeasurementsListDTO);
InstanceConstraintViolationsListDTO updateAdvancesOrEndDate(
OrderElementWithAdvanceMeasurementsOrEndDateListDTO orderElementWithAdvanceMeasurementsListDTO);
}

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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) {

View file

@ -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