/*
* 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.expensesheet;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.apache.commons.lang.Validate;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Hibernate;
import org.joda.time.LocalDate;
import org.libreplan.business.common.IntegrationEntity;
import org.libreplan.business.common.daos.IConfigurationDAO;
import org.libreplan.business.common.entities.EntityNameEnum;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.expensesheet.daos.IExpenseSheetDAO;
import org.libreplan.business.expensesheet.entities.ExpenseSheet;
import org.libreplan.business.expensesheet.entities.ExpenseSheetLine;
import org.libreplan.business.expensesheet.entities.ExpenseSheetLineComparator;
import org.libreplan.business.orders.daos.IOrderDAO;
import org.libreplan.business.orders.daos.ISumExpensesDAO;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.orders.entities.OrderLineGroup;
import org.libreplan.business.resources.entities.Resource;
import org.libreplan.business.users.entities.User;
import org.libreplan.web.UserUtil;
import org.libreplan.web.common.IntegrationEntityModel;
import org.libreplan.web.common.concurrentdetection.OnConcurrentModification;
import org.libreplan.web.resources.worker.WorkerModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* Model for UI operations related to {@link ExpenseSheet}.
*
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
@Service
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
@OnConcurrentModification(goToPage = "/expensesheet/expenseSheet.zul")
public class ExpenseSheetModel extends IntegrationEntityModel implements IExpenseSheetModel {
private static final org.apache.commons.logging.Log LOG = LogFactory.getLog(WorkerModel.class);
@Autowired
private IOrderDAO orderDAO;
@Autowired
private IExpenseSheetDAO expenseSheetDAO;
@Autowired
private IConfigurationDAO configurationDAO;
@Autowired
private ISumExpensesDAO sumExpensesDAO;
private ExpenseSheet expenseSheet;
private ExpenseSheetLine newExpenseSheetLine;
private List<Order> activeOrders = new ArrayList<Order>();
private List<OrderElement> allActiveOrdersChildren = new ArrayList<OrderElement>();
private Order selectedProject;
private Set<ExpenseSheetLine> deletedExpenseSheetLinesSet = new HashSet<ExpenseSheetLine>();
private Resource resource;
public void setExpenseSheet(ExpenseSheet expenseSheet) {
this.expenseSheet = expenseSheet;
}
@Override
public ExpenseSheet getExpenseSheet() {
return expenseSheet;
}
@Override
@Transactional
public void confirmSave() {
sumExpensesDAO
.updateRelatedSumExpensesWithDeletedExpenseSheetLineSet(deletedExpenseSheetLinesSet);
sumExpensesDAO.updateRelatedSumExpensesWithExpenseSheetLineSet(getExpenseSheet()
.getExpenseSheetLines());
updateCalculatedFields(getExpenseSheet());
expenseSheetDAO.save(getExpenseSheet());
dontPoseAsTransientAndChildrenObjects(getExpenseSheet());
}
private void dontPoseAsTransientAndChildrenObjects(ExpenseSheet expenseSheet) {
expenseSheet.dontPoseAsTransientObjectAnymore();
for (ExpenseSheetLine expenseSheetLine : expenseSheet.getExpenseSheetLines()) {
expenseSheetLine.dontPoseAsTransientObjectAnymore();
}
}
@Override
@Transactional
public void generateExpenseSheetLineCodesIfIsNecessary() {
if (expenseSheet.isCodeAutogenerated()) {
generateExpenseSheetLineCodes();
}
}
private void generateExpenseSheetLineCodes() {
expenseSheet.generateExpenseSheetLineCodes(getNumberOfDigitsCode());
}
private void updateCalculatedFields(ExpenseSheet expenseSheet) {
expenseSheet.updateCalculatedProperties();
}
@Override
public void prepareToList() {
this.expenseSheet = null;
}
@Override
@Transactional(readOnly = true)
public void initCreate(boolean personal) {
this.setSelectedProject(null);
createNewExpenseSheetLine();
this.expenseSheet = ExpenseSheet.create();
this.expenseSheet.setCodeAutogenerated(configurationDAO.getConfiguration()
.getGenerateCodeForExpenseSheets());
if (!this.expenseSheet.isCodeAutogenerated()) {
this.expenseSheet.setCode("");
} else {
setDefaultCode();
}
deletedExpenseSheetLinesSet = new HashSet<ExpenseSheetLine>();
expenseSheet.setPersonal(personal);
resource = initResource();
}
private Resource initResource() {
if (expenseSheet.isNotPersonal()) {
return null;
}
SortedSet<ExpenseSheetLine> expenseSheetLines = expenseSheet
.getExpenseSheetLines();
if (!expenseSheetLines.isEmpty()) {
return expenseSheetLines.iterator().next().getResource();
}
User user = UserUtil.getUserFromSession();
if (user.isBound()) {
return user.getWorker();
}
return null;
}
@Override
@Transactional(readOnly = true)
public void prepareToEdit(ExpenseSheet expenseSheet) {
this.setSelectedProject(null);
createNewExpenseSheetLine();
Validate.notNull(expenseSheet);
this.expenseSheet = getFromDB(expenseSheet);
initOldCodes();
deletedExpenseSheetLinesSet = new HashSet<ExpenseSheetLine>();
resource = initResource();
}
@Transactional(readOnly = true)
private ExpenseSheet getFromDB(ExpenseSheet expenseSheet) {
expenseSheetDAO.reattach(expenseSheet);
forceLoadExpenseSheetData(expenseSheet);
return expenseSheet;
}
private void forceLoadExpenseSheetData(ExpenseSheet expenseSheet) {
expenseSheet.getTotal();
for (ExpenseSheetLine line : expenseSheet.getExpenseSheetLines()) {
forceLoadExpenseSheetLineData(line);
}
}
private void forceLoadExpenseSheetLineData(ExpenseSheetLine line) {
line.getCode();
if (line.getResource() != null) {
line.getResource().getName();
}
initalizeOrderElement(line.getOrderElement());
}
private void initalizeOrderElement(OrderElement orderElement) {
Hibernate.initialize(orderElement);
initalizeOrder(orderElement);
}
private void initalizeOrder(OrderElement orderElement) {
OrderLineGroup parent = orderElement.getParent();
while (parent != null) {
Hibernate.initialize(parent);
parent = parent.getParent();
}
}
private void createNewExpenseSheetLine() {
this.newExpenseSheetLine = ExpenseSheetLine.create(new BigDecimal(0), "", new LocalDate(),
null);
}
@Override
@Transactional(readOnly = true)
public List<ExpenseSheet> getExpenseSheets() {
if (expenseSheetDAO != null) {
List<ExpenseSheet> result = expenseSheetDAO.list(ExpenseSheet.class);
return result;
}
return new ArrayList<ExpenseSheet>();
}
@Override
@Transactional
public void removeExpenseSheet(ExpenseSheet expenseSheet)
throws InstanceNotFoundException {
Validate.notNull(expenseSheet);
expenseSheet = getFromDB(expenseSheet);
sumExpensesDAO
.updateRelatedSumExpensesWithDeletedExpenseSheetLineSet(expenseSheet
.getExpenseSheetLines());
expenseSheetDAO.remove(expenseSheet.getId());
}
@Override
public SortedSet<ExpenseSheetLine> getExpenseSheetLines() {
if (getExpenseSheet() != null) {
return getExpenseSheet().getExpenseSheetLines();
}
return new TreeSet<ExpenseSheetLine>(new ExpenseSheetLineComparator());
}
@Override
public void removeExpenseSheetLine(ExpenseSheetLine expenseSheetLine) {
if (getExpenseSheet() != null) {
deletedExpenseSheetLinesSet.add(expenseSheetLine);
getExpenseSheet().remove(expenseSheetLine);
expenseSheetLine.setExpenseSheet(null);
}
}
@Override
public void addExpenseSheetLine() {
if (expenseSheet != null) {
ExpenseSheetLine line = this.getNewExpenseSheetLine();
line.setExpenseSheet(expenseSheet);
if (expenseSheet.isPersonal()) {
line.setResource(resource);
}
expenseSheet.add(line);
}
this.createNewExpenseSheetLine();
}
@Override
public ExpenseSheetLine getNewExpenseSheetLine() {
return newExpenseSheetLine;
}
@Override
public EntityNameEnum getEntityName() {
return EntityNameEnum.EXPENSE_SHEET;
}
@Override
public Set<IntegrationEntity> getChildren() {
return (Set<IntegrationEntity>) (getExpenseSheet() != null ? getExpenseSheet()
.getExpenseSheetLines() : new HashSet<IntegrationEntity>());
}
@Override
public IntegrationEntity getCurrentEntity() {
return this.expenseSheet;
}
@Override
@Transactional(readOnly = true)
public List<Order> getOrders() {
activeOrders = new ArrayList<Order>();
if (orderDAO != null) {
this.activeOrders = orderDAO.getActiveOrders();
loadOrdersData();
}
return activeOrders;
}
private void loadOrdersData() {
allActiveOrdersChildren = new ArrayList<OrderElement>();
for (Order order : activeOrders) {
allActiveOrdersChildren.addAll(order.getAllChildren());
order.getAllChildren().size();
}
}
public List<OrderElement> getTasks() {
if (this.selectedProject == null) {
return allActiveOrdersChildren;
}
return selectedProject.getAllChildren();
}
@Override
public void setSelectedProject(Order selectedProject) {
this.selectedProject = selectedProject;
}
@Override
public Order getSelectedProject() {
return selectedProject;
}
@Override
public Resource getResource() {
return resource;
}
public void keepSortedExpenseSheetLines(ExpenseSheetLine expenseSheetLine,
LocalDate newDate) {
if (getExpenseSheet() != null) {
this.expenseSheet.keepSortedExpenseSheetLines(expenseSheetLine,
newDate);
}
}
@Override
@Transactional(readOnly = true)
public boolean isPersonalAndBelognsToCurrentUser(ExpenseSheet expenseSheet) {
if (!expenseSheet.isPersonal()) {
return false;
}
SortedSet<ExpenseSheetLine> expenseSheetLines = getFromDB(expenseSheet)
.getExpenseSheetLines();
Resource resource = expenseSheetLines.iterator().next().getResource();
User user = UserUtil.getUserFromSession();
return user.getWorker().getId().equals(resource.getId());
}
}