/** * Axelor Business Solutions * * Copyright (C) 2016 Axelor (<http://axelor.com>). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * 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 com.axelor.apps.hr.web.expense; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.joda.time.LocalDate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.axelor.apps.ReportFactory; import com.axelor.apps.account.db.Move; import com.axelor.apps.base.db.Wizard; import com.axelor.apps.base.service.administration.GeneralService; import com.axelor.apps.hr.db.Expense; import com.axelor.apps.hr.db.ExpenseLine; import com.axelor.apps.base.db.Product; import com.axelor.apps.hr.db.HRConfig; import com.axelor.apps.hr.db.KilometricAllowanceRate; import com.axelor.apps.hr.db.repo.ExpenseRepository; import com.axelor.apps.hr.db.repo.KilometricAllowanceRateRepository; import com.axelor.apps.hr.db.repo.TimesheetRepository; import com.axelor.apps.hr.exception.IExceptionMessage; import com.axelor.apps.hr.report.IReport; import com.axelor.apps.hr.service.HRMenuTagService; import com.axelor.apps.hr.service.MailManagementService; import com.axelor.apps.hr.service.config.HRConfigService; import com.axelor.apps.hr.service.expense.ExpenseService; import com.axelor.apps.message.db.Template; import com.axelor.auth.AuthUtils; import com.axelor.auth.db.User; import com.axelor.db.JPA; import com.axelor.db.Query; import com.axelor.exception.AxelorException; import com.axelor.exception.db.IException; import com.axelor.exception.service.TraceBackService; import com.axelor.i18n.I18n; import com.axelor.inject.Beans; import com.axelor.meta.schema.actions.ActionView; import com.axelor.rpc.ActionRequest; import com.axelor.rpc.ActionResponse; import com.google.common.base.Joiner; import com.google.common.collect.Lists; import com.google.inject.Inject; import com.google.inject.persist.Transactional; public class ExpenseController { private final Logger logger = LoggerFactory.getLogger(getClass()); @Inject private HRConfigService hrConfigService; @Inject private HRMenuTagService hrMenuTagService; @Inject private MailManagementService mailManagementService; @Inject private ExpenseService expenseService; @Inject private GeneralService generalService; public void createAnalyticDistributionWithTemplate(ActionRequest request, ActionResponse response) throws AxelorException{ ExpenseLine expenseLine = request.getContext().asType(ExpenseLine.class); Expense expense = expenseLine.getExpense(); if(expense == null){ expense = request.getContext().getParentContext().asType(Expense.class); expenseLine.setExpense(expense); } if(expenseLine.getAnalyticDistributionTemplate() != null){ expenseLine = expenseService.createAnalyticDistributionWithTemplate(expenseLine); response.setValue("analyticDistributionLineList", expenseLine.getAnalyticDistributionLineList()); } else{ throw new AxelorException(I18n.get("No template selected"), IException.CONFIGURATION_ERROR); } } public void computeAnalyticDistribution(ActionRequest request, ActionResponse response) throws AxelorException{ ExpenseLine expenseLine = request.getContext().asType(ExpenseLine.class); Expense expense = expenseLine.getExpense(); if(expense == null){ expense = request.getContext().getParentContext().asType(Expense.class); expenseLine.setExpense(expense); } if(Beans.get(GeneralService.class).getGeneral().getManageAnalyticAccounting()){ expenseLine = expenseService.computeAnalyticDistribution(expenseLine); response.setValue("analyticDistributionLineList", expenseLine.getAnalyticDistributionLineList()); } } public void editExpense(ActionRequest request, ActionResponse response){ List<Expense> expenseList = Beans.get(ExpenseRepository.class).all().filter("self.user = ?1 AND self.company = ?2 AND self.statusSelect = 1",AuthUtils.getUser(),AuthUtils.getUser().getActiveCompany()).fetch(); if(expenseList.isEmpty()){ response.setView(ActionView .define(I18n.get("Expense")) .model(Expense.class.getName()) .add("form", "expense-form") .map()); } else if(expenseList.size() == 1){ response.setView(ActionView .define(I18n.get("Expense")) .model(Expense.class.getName()) .add("form", "expense-form") .param("forceEdit", "true") .context("_showRecord", String.valueOf(expenseList.get(0).getId())).map()); } else{ response.setView(ActionView .define(I18n.get("Expense")) .model(Wizard.class.getName()) .add("form", "popup-expense-form") .param("forceEdit", "true") .param("popup", "true") .param("show-toolbar", "false") .param("show-confirm", "false") .param("forceEdit", "true") .param("popup-save", "false") .map()); } } public void editExpenseSelected(ActionRequest request, ActionResponse response){ Map expenseMap = (Map)request.getContext().get("expenseSelect"); Expense expense = Beans.get(ExpenseRepository.class).find(new Long((Integer)expenseMap.get("id"))); response.setView(ActionView .define(I18n.get("Expense")) .model(Expense.class.getName()) .add("form", "expense-form") .param("forceEdit", "true") .domain("self.id = "+expenseMap.get("id")) .context("_showRecord", String.valueOf(expense.getId())).map()); } public void validateExpense(ActionRequest request, ActionResponse response) throws AxelorException{ List<Expense> expenseList = Lists.newArrayList(); if(AuthUtils.getUser().getEmployee() != null && AuthUtils.getUser().getEmployee().getHrManager()){ expenseList = Query.of(Expense.class).filter("self.company = ?1 AND self.statusSelect = 2",AuthUtils.getUser().getActiveCompany()).fetch(); }else{ expenseList = Query.of(Expense.class).filter("self.user.employee.manager = ?1 AND self.company = ?2 AND self.statusSelect = 2",AuthUtils.getUser(),AuthUtils.getUser().getActiveCompany()).fetch(); } List<Long> expenseListId = new ArrayList<Long>(); for (Expense expense : expenseList) { expenseListId.add(expense.getId()); } if(AuthUtils.getUser().getEmployee() != null && AuthUtils.getUser().getEmployee().getManager() == null && !AuthUtils.getUser().getEmployee().getHrManager()){ expenseList = Query.of(Expense.class).filter("self.user = ?1 AND self.company = ?2 AND self.statusSelect = 2 ",AuthUtils.getUser(),AuthUtils.getUser().getActiveCompany()).fetch(); } for (Expense expense : expenseList) { expenseListId.add(expense.getId()); } String expenseListIdStr = "-2"; if(!expenseListId.isEmpty()){ expenseListIdStr = Joiner.on(",").join(expenseListId); } response.setView(ActionView.define(I18n.get("Expenses to Validate")) .model(Expense.class.getName()) .add("grid","expense-validate-grid") .add("form","expense-form") .domain("self.id in ("+expenseListIdStr+")") .map()); } public void historicExpense(ActionRequest request, ActionResponse response){ List<Expense> expenseList = Lists.newArrayList(); if(AuthUtils.getUser().getEmployee() != null && AuthUtils.getUser().getEmployee().getHrManager()){ expenseList = Query.of(Expense.class).filter("self.company = ?1 AND (self.statusSelect = 3 OR self.statusSelect = 4)",AuthUtils.getUser().getActiveCompany()).fetch(); }else{ expenseList = Query.of(Expense.class).filter("self.user.employee.manager = ?1 AND self.company = ?2 AND (self.statusSelect = 3 OR self.statusSelect = 4)",AuthUtils.getUser(),AuthUtils.getUser().getActiveCompany()).fetch(); } List<Long> expenseListId = new ArrayList<Long>(); for (Expense expense : expenseList) { expenseListId.add(expense.getId()); } String expenseListIdStr = "-2"; if(!expenseListId.isEmpty()){ expenseListIdStr = Joiner.on(",").join(expenseListId); } response.setView(ActionView.define(I18n.get("Historic colleague Expenses")) .model(Expense.class.getName()) .add("grid","expense-grid") .add("form","expense-form") .domain("self.id in ("+expenseListIdStr+")") .map()); } public void showSubordinateExpenses(ActionRequest request, ActionResponse response){ List<User> userList = Query.of(User.class).filter("self.employee.manager = ?1",AuthUtils.getUser()).fetch(); List<Long> expenseListId = new ArrayList<Long>(); for (User user : userList) { List<Expense> expenseList = Query.of(Expense.class).filter("self.user.employee.manager = ?1 AND self.company = ?2 AND self.statusSelect = 2",user,AuthUtils.getUser().getActiveCompany()).fetch(); for (Expense expense : expenseList) { expenseListId.add(expense.getId()); } } if(expenseListId.isEmpty()){ response.setNotify(I18n.get("No expense to be validated by your subordinates")); } else{ String expenseListIdStr = "-2"; if(!expenseListId.isEmpty()){ expenseListIdStr = Joiner.on(",").join(expenseListId); } response.setView(ActionView.define(I18n.get("Expenses to be Validated by your subordinates")) .model(Expense.class.getName()) .add("grid","expense-grid") .add("form","expense-form") .domain("self.id in ("+expenseListIdStr+")") .map()); } } public void compute(ActionRequest request, ActionResponse response){ Expense expense = request.getContext().asType(Expense.class); expense = expenseService.compute(expense); response.setValues(expense); } public void ventilate(ActionRequest request, ActionResponse response) throws AxelorException{ Expense expense = request.getContext().asType(Expense.class); expense = Beans.get(ExpenseRepository.class).find(expense.getId()); Move move = expenseService.ventilate(expense); response.setReload(true); response.setView(ActionView.define(I18n.get("Move")) .model(Move.class.getName()) .add("grid","move-grid") .add("form","move-form") .context("_showRecord", String.valueOf(move.getId())) .map()); } public void cancelExpense(ActionRequest request, ActionResponse response) throws AxelorException{ Expense expense = request.getContext().asType(Expense.class); expense = Beans.get(ExpenseRepository.class).find(expense.getId()); expenseService.cancel(expense); response.setReload(true); } public void validateDates(ActionRequest request, ActionResponse response) throws AxelorException{ Expense expense = request.getContext().asType(Expense.class); if(expense.getExpenseLineList()!= null){ List<ExpenseLine> expenseLineList = expense.getExpenseLineList(); List<Integer> expenseLineId = new ArrayList<Integer>(); int compt = 0; for (ExpenseLine expenseLine : expenseLineList) { compt++; if(expenseLine.getExpenseDate().isAfter(generalService.getTodayDate())){ expenseLineId.add(compt); } } if(!expenseLineId.isEmpty()){ String ids = Joiner.on(",").join(expenseLineId); throw new AxelorException(String.format(I18n.get("Problème de date pour la (les) ligne(s) : "+ids)), IException.CONFIGURATION_ERROR); } } } public void printExpense(ActionRequest request, ActionResponse response) throws AxelorException { Expense expense = request.getContext().asType(Expense.class); User user = AuthUtils.getUser(); String language = user != null? (user.getLanguage() == null || user.getLanguage().equals(""))? "en" : user.getLanguage() : "en"; String name = I18n.get("Expense") + " " + expense.getFullName() .replace("/", "-"); String fileLink = ReportFactory.createReport(IReport.EXPENSE, name) .addParam("ExpenseId", expense.getId()) .addParam("Locale", language) .toAttach(expense) .generate() .getFileLink(); logger.debug("Printing "+name); response.setView(ActionView .define(name) .add("html", fileLink).map()); } /* Count Tags displayed on the menu items */ public String expenseValidateTag() { Expense expense = new Expense(); return hrMenuTagService.CountRecordsTag(expense); } public String expenseVentilateTag() { Long total = JPA.all(Expense.class).filter("self.statusSelect = 3 AND self.ventilated = false").count(); return String.format("%s", total); } //sending expense and sending mail to manager public void send(ActionRequest request, ActionResponse response) throws AxelorException{ try{ Expense expense = request.getContext().asType(Expense.class); if(!hrConfigService.getHRConfig(expense.getUser().getActiveCompany()).getExpenseMailNotification()){ response.setValue("statusSelect", TimesheetRepository.STATUS_CONFIRMED); response.setValue("sentDate", generalService.getTodayDate()); response.setView(ActionView .define(I18n.get("Expense")) .model(Expense.class.getName()) .add("form", "expense-form") .map()); } else{ User manager = expense.getUser().getEmployee().getManager(); if(manager!=null){ Template template = hrConfigService.getHRConfig(expense.getUser().getActiveCompany()).getSentExpenseTemplate(); if(mailManagementService.sendEmail(template,expense.getId())){ String message = "Email sent to"; response.setFlash(I18n.get(message)+" "+manager.getFullName()); response.setValue("statusSelect", TimesheetRepository.STATUS_CONFIRMED); response.setValue("sentDate", generalService.getTodayDate()); response.setView(ActionView .define(I18n.get("Expense")) .model(Expense.class.getName()) .add("form", "expense-form") .map()); } else{ throw new AxelorException(String.format(I18n.get(IExceptionMessage.HR_CONFIG_TEMPLATES), expense.getUser().getActiveCompany().getName()), IException.CONFIGURATION_ERROR); } } } }catch(Exception e) { TraceBackService.trace(response, e); } } //validating expense and sending mail to applicant public void valid(ActionRequest request, ActionResponse response) throws AxelorException{ try{ Expense expense = request.getContext().asType(Expense.class); if(!hrConfigService.getHRConfig(expense.getUser().getActiveCompany()).getExpenseMailNotification()){ response.setValue("statusSelect", TimesheetRepository.STATUS_VALIDATED); response.setValue("validatedBy", AuthUtils.getUser()); response.setValue("validationDate", generalService.getTodayDate()); } else{ User manager = expense.getUser().getEmployee().getManager(); if(manager!=null){ Template template = hrConfigService.getHRConfig(expense.getUser().getActiveCompany()).getValidatedExpenseTemplate(); if(mailManagementService.sendEmail(template,expense.getId())){ String message = "Email sent to"; response.setFlash(I18n.get(message)+" "+expense.getUser().getFullName()); response.setValue("statusSelect", TimesheetRepository.STATUS_VALIDATED); response.setValue("validatedBy", AuthUtils.getUser()); response.setValue("validationDate", generalService.getTodayDate()); } else{ throw new AxelorException(String.format(I18n.get(IExceptionMessage.HR_CONFIG_TEMPLATES), expense.getUser().getActiveCompany().getName()), IException.CONFIGURATION_ERROR); } } } }catch(Exception e) { TraceBackService.trace(response, e); } } //refusing expense and sending mail to applicant public void refuse(ActionRequest request, ActionResponse response) throws AxelorException{ try{ Expense expense = request.getContext().asType(Expense.class); if(!hrConfigService.getHRConfig(expense.getUser().getActiveCompany()).getExpenseMailNotification()){ response.setValue("statusSelect", TimesheetRepository.STATUS_REFUSED); response.setValue("refusedBy", AuthUtils.getUser()); response.setValue("refusalDate", generalService.getTodayDate()); } else{ User manager = expense.getUser().getEmployee().getManager(); if(manager!=null){ Template template = hrConfigService.getHRConfig(expense.getUser().getActiveCompany()).getRefusedExpenseTemplate(); if(mailManagementService.sendEmail(template,expense.getId())){ String message = "Email sent to"; response.setFlash(I18n.get(message)+" "+expense.getUser().getFullName()); response.setValue("statusSelect", TimesheetRepository.STATUS_REFUSED); response.setValue("refusedBy", AuthUtils.getUser()); response.setValue("refusalDate", generalService.getTodayDate()); } else{ throw new AxelorException(String.format(I18n.get(IExceptionMessage.HR_CONFIG_TEMPLATES), expense.getUser().getActiveCompany().getName()), IException.CONFIGURATION_ERROR); } } } }catch(Exception e) { TraceBackService.trace(response, e); } } public void fillKilometricExpenseProduct(ActionRequest request, ActionResponse response) throws AxelorException{ try { Expense expense = request.getContext().getParentContext().asType(Expense.class); HRConfig hrConfig = hrConfigService.getHRConfig(expense.getCompany()); Product expenseProduct = hrConfigService.getKilometricExpenseProduct(hrConfig); logger.debug("Get Kilometric expense product : {}", expenseProduct); response.setValue("expenseProduct",expenseProduct); } catch(Exception e) { TraceBackService.trace(response, e); } } @Transactional public void insertKMExpenses(ActionRequest request, ActionResponse response){ User user = AuthUtils.getUser(); if(user != null){ Expense expense = Beans.get(ExpenseRepository.class).all().filter("self.statusSelect = 1 AND self.user.id = ?1", user.getId()).order("-id").fetchOne(); if(expense == null){ expense = new Expense(); expense.setUser(user); expense.setCompany(user.getActiveCompany()); expense.setStatusSelect(TimesheetRepository.STATUS_DRAFT); } ExpenseLine expenseLine = new ExpenseLine(); expenseLine.setDistance(new BigDecimal(request.getData().get("kmNumber").toString())); expenseLine.setFromCity(request.getData().get("locationFrom").toString()); expenseLine.setToCity(request.getData().get("locationTo").toString()); expenseLine.setKilometricTypeSelect(new Integer(request.getData().get("allowanceTypeSelect").toString())); expenseLine.setComments(request.getData().get("comments").toString()); expenseLine.setExpenseDate(new LocalDate(request.getData().get("date").toString())); if(user.getEmployee() != null && user.getEmployee().getKilometricAllowParam() != null){ expenseLine.setKilometricAllowParam(user.getEmployee().getKilometricAllowParam()); KilometricAllowanceRate kilometricAllowanceRate = Beans.get(KilometricAllowanceRateRepository.class).findByVehicleKillometricAllowanceParam(user.getEmployee().getKilometricAllowParam()); if(kilometricAllowanceRate != null){ BigDecimal rate = kilometricAllowanceRate.getRate(); if(rate != null){ expenseLine.setTotalAmount(rate.multiply(expenseLine.getDistance())); } } } expense.addExpenseLineListItem(expenseLine); Beans.get(ExpenseRepository.class).save(expense); } } }