/* * 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.lang3.Validate; 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.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 { @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<>(); private List<OrderElement> allActiveOrdersChildren = new ArrayList<>(); private Order selectedProject; private Set<ExpenseSheetLine> deletedExpenseSheetLinesSet = new HashSet<>(); 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<>(); 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(); return user.isBound() ? user.getWorker() : 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<>(); 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(); initializeOrderElement(line.getOrderElement()); } private void initializeOrderElement(OrderElement orderElement) { Hibernate.initialize(orderElement); initializeOrder(orderElement); } private void initializeOrder(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() { return expenseSheetDAO != null ? expenseSheetDAO.list(ExpenseSheet.class) : new ArrayList<>(); } @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() { return getExpenseSheet() != null ? getExpenseSheet().getExpenseSheetLines() : new TreeSet<>(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<>(); if (orderDAO != null) { this.activeOrders = orderDAO.getActiveOrders(); loadOrdersData(); } return activeOrders; } private void loadOrdersData() { allActiveOrdersChildren = new ArrayList<>(); for (Order order : activeOrders) { allActiveOrdersChildren.addAll(order.getAllChildren()); order.getAllChildren().size(); } } public List<OrderElement> getTasks() { return this.selectedProject == null ? allActiveOrdersChildren : 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 isPersonalAndBelongsToCurrentUser(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()); } }