/** * 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.businessproject.service; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; import java.util.List; import com.axelor.apps.account.db.AccountConfig; import com.axelor.apps.account.db.Invoice; import com.axelor.apps.account.db.InvoiceLine; import com.axelor.apps.account.db.repo.InvoiceRepository; import com.axelor.apps.account.service.AnalyticMoveLineService; import com.axelor.apps.account.service.config.AccountConfigService; import com.axelor.apps.account.service.invoice.generator.InvoiceGenerator; import com.axelor.apps.account.service.invoice.generator.InvoiceLineGenerator; import com.axelor.apps.account.util.InvoiceLineComparator; import com.axelor.apps.base.db.Company; import com.axelor.apps.base.db.IPriceListLine; import com.axelor.apps.base.db.Partner; import com.axelor.apps.base.db.Product; import com.axelor.apps.base.service.PartnerService; import com.axelor.apps.businessproject.db.ElementsToInvoice; import com.axelor.apps.businessproject.db.InvoicingProject; import com.axelor.apps.businessproject.db.repo.ElementsToInvoiceRepository; import com.axelor.apps.businessproject.db.repo.InvoicingProjectRepository; import com.axelor.apps.businessproject.exception.IExceptionMessage; import com.axelor.apps.hr.db.ExpenseLine; import com.axelor.apps.hr.db.TimesheetLine; import com.axelor.apps.hr.db.repo.ExpenseLineRepository; import com.axelor.apps.hr.db.repo.TimesheetLineRepository; import com.axelor.apps.hr.service.expense.ExpenseService; import com.axelor.apps.hr.service.timesheet.TimesheetServiceImpl; import com.axelor.apps.project.db.ProjectTask; import com.axelor.apps.project.db.repo.ProjectTaskRepository; import com.axelor.apps.project.service.ProjectTaskService; import com.axelor.apps.purchase.db.PurchaseOrderLine; import com.axelor.apps.purchase.db.repo.PurchaseOrderLineRepository; import com.axelor.apps.sale.db.SaleOrderLine; import com.axelor.apps.sale.db.repo.SaleOrderLineRepository; import com.axelor.apps.supplychain.service.PurchaseOrderInvoiceServiceImpl; import com.axelor.apps.supplychain.service.SaleOrderInvoiceServiceImpl; import com.axelor.apps.supplychain.service.invoice.generator.InvoiceLineGeneratorSupplyChain; import com.axelor.exception.AxelorException; import com.axelor.exception.db.IException; import com.axelor.i18n.I18n; import com.axelor.inject.Beans; import com.google.inject.Inject; import com.google.inject.persist.Transactional; public class InvoicingProjectService { @Inject protected SaleOrderInvoiceServiceImpl saleOrderInvoiceServiceImpl; @Inject protected PurchaseOrderInvoiceServiceImpl purchaseOrderInvoiceServiceImpl; @Inject protected TimesheetServiceImpl timesheetServiceImpl; @Inject protected ExpenseService expenseService; @Inject protected ElementsToInvoiceService elementsToInvoiceService; protected AnalyticMoveLineService analyticMoveLineService; @Inject protected PartnerService partnerService; @Inject protected InvoicingProjectRepository invoicingProjectRepo; protected int MAX_LEVEL_OF_PROJECT = 10; protected int sequence = 0; @Transactional public Invoice generateInvoice(InvoicingProject invoicingProject) throws AxelorException{ ProjectTask projectTask = invoicingProject.getProjectTask(); Partner customer = projectTask.getClientPartner(); Company company = this.getRootCompany(projectTask); if(company == null){ throw new AxelorException(String.format(I18n.get(IExceptionMessage.INVOICING_PROJECT_PROJECT_TASK_COMPANY)), IException.CONFIGURATION_ERROR); } projectTask.getAssignedTo(); InvoiceGenerator invoiceGenerator = new InvoiceGenerator(InvoiceRepository.OPERATION_TYPE_CLIENT_SALE, company, customer.getPaymentCondition(), customer.getPaymentMode(), partnerService.getInvoicingAddress(customer), customer, null, customer.getCurrency(), customer.getSalePriceList(), null, null, null, null){ @Override public Invoice generate() throws AxelorException { return super.createInvoiceHeader(); } }; Invoice invoice = invoiceGenerator.generate(); AccountConfigService accountConfigService = Beans.get(AccountConfigService.class); AccountConfig accountConfig = accountConfigService.getAccountConfig(company); invoice.setDisplayTimesheetOnPrinting(accountConfig.getDisplayTimesheetOnPrinting()); invoice.setDisplayExpenseOnPrinting(accountConfig.getDisplayExpenseOnPrinting()); invoiceGenerator.populate(invoice,this.populate(invoice,invoicingProject)); Beans.get(InvoiceRepository.class).save(invoice); this.setInvoiced(invoicingProject); invoicingProject.setInvoice(invoice); invoicingProjectRepo.save(invoicingProject); return invoice; } public List<InvoiceLine> populate(Invoice invoice,InvoicingProject folder) throws AxelorException{ List<SaleOrderLine> saleOrderLineList = new ArrayList<SaleOrderLine>(folder.getSaleOrderLineSet()); List<PurchaseOrderLine> purchaseOrderLineList = new ArrayList<PurchaseOrderLine>(folder.getPurchaseOrderLineSet()); List<TimesheetLine> timesheetLineList = new ArrayList<TimesheetLine>(folder.getLogTimesSet()); List<ExpenseLine> expenseLineList = new ArrayList<ExpenseLine>(folder.getExpenseLineSet()); List<ElementsToInvoice> elementsToInvoiceList = new ArrayList<ElementsToInvoice>(folder.getElementsToInvoiceSet()); List<ProjectTask> projectTaskList = new ArrayList<ProjectTask>(folder.getProjectTaskSet()); List<InvoiceLine> invoiceLineList = new ArrayList<InvoiceLine>(); invoiceLineList.addAll(this.createSaleOrderInvoiceLines(invoice, saleOrderLineList, folder.getSaleOrderLineSetPrioritySelect())); invoiceLineList.addAll(this.createPurchaseOrderInvoiceLines(invoice, purchaseOrderLineList, folder.getPurchaseOrderLineSetPrioritySelect())); invoiceLineList.addAll(timesheetServiceImpl.createInvoiceLines(invoice, timesheetLineList, folder.getLogTimesSetPrioritySelect())); invoiceLineList.addAll(expenseService.createInvoiceLines(invoice, expenseLineList, folder.getExpenseLineSetPrioritySelect())); invoiceLineList.addAll(elementsToInvoiceService.createInvoiceLines(invoice, elementsToInvoiceList, folder.getElementsToInvoiceSetPrioritySelect())); invoiceLineList.addAll(this.createInvoiceLines(invoice, projectTaskList, folder.getProjectTaskSetPrioritySelect())); Collections.sort(invoiceLineList, new InvoiceLineComparator()); for (InvoiceLine invoiceLine : invoiceLineList) { invoiceLine.setSequence(sequence); sequence++; invoiceLine.setSaleOrder(invoiceLine.getInvoice().getSaleOrder()); } return invoiceLineList; } public List<InvoiceLine> createSaleOrderInvoiceLines(Invoice invoice, List<SaleOrderLine> saleOrderLineList, int priority) throws AxelorException { List<InvoiceLine> invoiceLineList = new ArrayList<InvoiceLine>(); int count = 1; for(SaleOrderLine saleOrderLine : saleOrderLineList) { invoiceLineList.addAll(this.createInvoiceLine(invoice, saleOrderLine,priority*100+count)); count++; saleOrderLine.setInvoiced(true); } return invoiceLineList; } public List<InvoiceLine> createInvoiceLine(Invoice invoice, SaleOrderLine saleOrderLine, int priority) throws AxelorException { Product product = saleOrderLine.getProduct(); InvoiceLineGenerator invoiceLineGenerator = new InvoiceLineGeneratorSupplyChain(invoice, product, saleOrderLine.getProductName(), saleOrderLine.getDescription(), saleOrderLine.getQty(), saleOrderLine.getUnit(), priority, false, saleOrderLine, null, null, null) { @Override public List<InvoiceLine> creates() throws AxelorException { InvoiceLine invoiceLine = this.createInvoiceLine(); List<InvoiceLine> invoiceLines = new ArrayList<InvoiceLine>(); invoiceLines.add(invoiceLine); return invoiceLines; } }; return invoiceLineGenerator.creates(); } public List<InvoiceLine> createPurchaseOrderInvoiceLines(Invoice invoice, List<PurchaseOrderLine> purchaseOrderLineList, int priority) throws AxelorException { List<InvoiceLine> invoiceLineList = new ArrayList<InvoiceLine>(); for(PurchaseOrderLine purchaseOrderLine : purchaseOrderLineList) { invoiceLineList.addAll(Beans.get(PurchaseOrderInvoiceProjectServiceImpl.class).createInvoiceLine(invoice, purchaseOrderLine)); purchaseOrderLine.setInvoiced(true); } return invoiceLineList; } public List<InvoiceLine> createInvoiceLine(Invoice invoice, PurchaseOrderLine purchaseOrderLine, int priority) throws AxelorException { Product product = purchaseOrderLine.getProduct(); InvoiceLineGeneratorSupplyChain invoiceLineGenerator = new InvoiceLineGeneratorSupplyChain(invoice, product, purchaseOrderLine.getProductName(), purchaseOrderLine.getDescription(), purchaseOrderLine.getQty(), purchaseOrderLine.getUnit(), priority, false, null, purchaseOrderLine, null) { @Override public List<InvoiceLine> creates() throws AxelorException { InvoiceLine invoiceLine = this.createInvoiceLine(); List<InvoiceLine> invoiceLines = new ArrayList<InvoiceLine>(); invoiceLines.add(invoiceLine); return invoiceLines; } }; return invoiceLineGenerator.creates(); } public List<InvoiceLine> createInvoiceLines(Invoice invoice, List<ProjectTask> projectTaskList, int priority) throws AxelorException { List<InvoiceLine> invoiceLineList = new ArrayList<InvoiceLine>(); int count = 0; for(ProjectTask projectTask : projectTaskList) { invoiceLineList.addAll(this.createInvoiceLine(invoice, projectTask, priority*100+count)); count++; projectTask.setInvoiced(true); invoiceLineList.get(invoiceLineList.size()-1).setProject(projectTask); } return invoiceLineList; } public List<InvoiceLine> createInvoiceLine(Invoice invoice, ProjectTask projectTask, int priority) throws AxelorException { Product product = projectTask.getProduct(); if(product == null){ throw new AxelorException(String.format(I18n.get(IExceptionMessage.INVOICING_PROJECT_PROJECT_TASK_PRODUCT),projectTask.getFullName()), IException.CONFIGURATION_ERROR); } InvoiceLineGenerator invoiceLineGenerator = new InvoiceLineGenerator(invoice, product, projectTask.getName(), projectTask.getPrice(), projectTask.getPrice(),null,projectTask.getQty(),projectTask.getUnit(), null,priority,BigDecimal.ZERO,IPriceListLine.AMOUNT_TYPE_NONE, projectTask.getPrice().multiply(projectTask.getQty()), null,false) { @Override public List<InvoiceLine> creates() throws AxelorException { InvoiceLine invoiceLine = this.createInvoiceLine(); List<InvoiceLine> invoiceLines = new ArrayList<InvoiceLine>(); invoiceLines.add(invoiceLine); return invoiceLines; } }; return invoiceLineGenerator.creates(); } public void setInvoiced(InvoicingProject invoicingProject){ for (SaleOrderLine saleOrderLine : invoicingProject.getSaleOrderLineSet()) { saleOrderLine.setInvoiced(true); } for (PurchaseOrderLine purchaseOrderLine : invoicingProject.getPurchaseOrderLineSet()) { purchaseOrderLine.setInvoiced(true); } for (TimesheetLine timesheetLine : invoicingProject.getLogTimesSet()) { timesheetLine.setInvoiced(true); } for (ExpenseLine expenseLine : invoicingProject.getExpenseLineSet()) { expenseLine.setInvoiced(true); } for (ElementsToInvoice elementsToInvoice : invoicingProject.getElementsToInvoiceSet()) { elementsToInvoice.setInvoiced(true); } for (ProjectTask projectTask : invoicingProject.getProjectTaskSet()) { projectTask.setInvoiced(true); } } public void setLines(InvoicingProject invoicingProject,ProjectTask projectTask, int counter){ if(counter > ProjectTaskService.MAX_LEVEL_OF_PROJECT) { return; } counter++; this.fillLines(invoicingProject, projectTask); List<ProjectTask> projectTaskChildrenList = Beans.get(ProjectTaskRepository.class).all().filter("self.project = ?1", projectTask).fetch(); for (ProjectTask projectTaskChild : projectTaskChildrenList) { this.setLines(invoicingProject, projectTaskChild, counter); } return; } public void fillLines(InvoicingProject invoicingProject,ProjectTask projectTask){ if(projectTask.getProjTaskInvTypeSelect() == ProjectTaskRepository.INVOICING_TYPE_FLAT_RATE || projectTask.getProjTaskInvTypeSelect() == ProjectTaskRepository.INVOICING_TYPE_TIME_BASED) { invoicingProject.getSaleOrderLineSet().addAll(Beans.get(SaleOrderLineRepository.class) .all().filter("self.saleOrder.project = ?1 AND self.toInvoice = true AND self.invoiced = false AND (self.saleOrder.creationDate < ?2 or ?3 is null)", projectTask, invoicingProject.getDeadlineDate(),invoicingProject.getDeadlineDate()).fetch()); invoicingProject.getPurchaseOrderLineSet().addAll(Beans.get(PurchaseOrderLineRepository.class) .all().filter("self.projectTask = ?1 AND self.toInvoice = true AND self.invoiced = false AND (self.purchaseOrder.orderDate < ?2 or ?3 is null)", projectTask, invoicingProject.getDeadlineDate(),invoicingProject.getDeadlineDate()).fetch()); invoicingProject.getLogTimesSet().addAll(Beans.get(TimesheetLineRepository.class) .all().filter("self.timesheet.statusSelect = 3 AND self.projectTask = ?1 AND self.toInvoice = true AND self.invoiced = false AND (self.date < ?2 or ?3 is null)", projectTask, invoicingProject.getDeadlineDate(),invoicingProject.getDeadlineDate()).fetch()); invoicingProject.getExpenseLineSet().addAll(Beans.get(ExpenseLineRepository.class) .all().filter("self.projectTask = ?1 AND self.toInvoice = true AND self.invoiced = false AND (self.expenseDate < ?2 or ?3 is null)", projectTask, invoicingProject.getDeadlineDate(),invoicingProject.getDeadlineDate()).fetch()); invoicingProject.getElementsToInvoiceSet().addAll(Beans.get(ElementsToInvoiceRepository.class) .all().filter("self.project = ?1 AND self.toInvoice = true AND self.invoiced = false AND (self.date < ?2 or ?3 is null)", projectTask, invoicingProject.getDeadlineDate(),invoicingProject.getDeadlineDate()).fetch()); if(projectTask.getProjTaskInvTypeSelect() == ProjectTaskRepository.INVOICING_TYPE_FLAT_RATE && !projectTask.getInvoiced()) invoicingProject.addProjectTaskSetItem(projectTask); } } public void clearLines(InvoicingProject invoicingProject){ invoicingProject.clearSaleOrderLineSet(); invoicingProject.clearPurchaseOrderLineSet(); invoicingProject.clearLogTimesSet(); invoicingProject.clearExpenseLineSet(); invoicingProject.clearElementsToInvoiceSet(); invoicingProject.clearProjectTaskSet(); } public Company getRootCompany(ProjectTask projectTask){ if(projectTask.getProject() == null){ return projectTask.getCompany(); } else{ return getRootCompany(projectTask.getProject()); } } }