/** * 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.account.service.invoice.generator; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import org.joda.time.LocalDate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.axelor.apps.account.db.AccountConfig; import com.axelor.apps.account.db.AccountingSituation; import com.axelor.apps.account.db.Invoice; import com.axelor.apps.account.db.InvoiceLine; import com.axelor.apps.account.db.InvoiceLineTax; import com.axelor.apps.account.db.PaymentCondition; import com.axelor.apps.account.db.PaymentMode; import com.axelor.apps.account.db.repo.AccountConfigRepository; import com.axelor.apps.account.db.repo.InvoiceRepository; import com.axelor.apps.account.exception.IExceptionMessage; import com.axelor.apps.account.service.AccountCustomerService; import com.axelor.apps.account.service.AccountingSituationService; import com.axelor.apps.account.service.JournalService; import com.axelor.apps.account.service.config.AccountConfigService; import com.axelor.apps.account.service.invoice.InvoiceToolService; import com.axelor.apps.account.service.invoice.generator.tax.TaxInvoiceLine; import com.axelor.apps.base.db.Address; import com.axelor.apps.base.db.BankDetails; import com.axelor.apps.base.db.Company; import com.axelor.apps.base.db.Currency; import com.axelor.apps.base.db.Partner; import com.axelor.apps.base.db.PriceList; import com.axelor.apps.base.service.PartnerService; import com.axelor.apps.base.service.administration.GeneralService; import com.axelor.apps.base.service.administration.GeneralServiceImpl; import com.axelor.exception.AxelorException; import com.axelor.exception.db.IException; import com.axelor.i18n.I18n; import com.axelor.inject.Beans; public abstract class InvoiceGenerator { private final Logger logger = LoggerFactory.getLogger(getClass()); protected JournalService journalService; protected boolean months30days; protected int operationType; protected Company company; protected PaymentCondition paymentCondition; protected PaymentMode paymentMode; protected Address mainInvoicingAddress; protected Partner partner; protected Partner contactPartner; protected Currency currency; protected LocalDate today; protected PriceList priceList; protected String internalReference; protected String externalReference; protected Boolean inAti; protected BankDetails companyBankDetails; protected InvoiceGenerator(int operationType, Company company, PaymentCondition paymentCondition, PaymentMode paymentMode, Address mainInvoicingAddress, Partner partner, Partner contactPartner, Currency currency, PriceList priceList, String internalReference, String externalReference, Boolean inAti, BankDetails companyBankDetails) throws AxelorException { this.operationType = operationType; this.company = company; this.paymentCondition = paymentCondition; this.paymentMode = paymentMode; this.mainInvoicingAddress = mainInvoicingAddress; this.partner = partner; this.contactPartner = contactPartner; this.currency = currency; this.priceList = priceList; this.internalReference = internalReference; this.externalReference = externalReference; this.inAti = inAti; this.companyBankDetails = companyBankDetails; this.today = Beans.get(GeneralService.class).getTodayDate(); this.journalService = new JournalService(); } /** * PaymentCondition, Paymentmode, MainInvoicingAddress, Currency récupérés du tiers * @param operationType * @param company * @param partner * @param contactPartner * @throws AxelorException */ protected InvoiceGenerator(int operationType, Company company, Partner partner, Partner contactPartner, PriceList priceList, String internalReference, String externalReference, Boolean inAti) throws AxelorException { this.operationType = operationType; this.company = company; this.partner = partner; this.contactPartner = contactPartner; this.priceList = priceList; this.internalReference = internalReference; this.externalReference = externalReference; this.inAti = inAti; this.today = Beans.get(GeneralService.class).getTodayDate(); this.journalService = new JournalService(); } protected InvoiceGenerator() { this.today = Beans.get(GeneralService.class).getTodayDate(); this.journalService = new JournalService(); } protected int inverseOperationType(int operationType) throws AxelorException { switch(operationType) { case InvoiceRepository.OPERATION_TYPE_SUPPLIER_PURCHASE: return InvoiceRepository.OPERATION_TYPE_SUPPLIER_REFUND; case InvoiceRepository.OPERATION_TYPE_SUPPLIER_REFUND: return InvoiceRepository.OPERATION_TYPE_SUPPLIER_PURCHASE; case InvoiceRepository.OPERATION_TYPE_CLIENT_SALE: return InvoiceRepository.OPERATION_TYPE_CLIENT_REFUND; case InvoiceRepository.OPERATION_TYPE_CLIENT_REFUND: return InvoiceRepository.OPERATION_TYPE_CLIENT_SALE; default: throw new AxelorException(String.format(I18n.get(IExceptionMessage.INVOICE_GENERATOR_1), GeneralServiceImpl.EXCEPTION), IException.MISSING_FIELD); } } abstract public Invoice generate() throws AxelorException; protected Invoice createInvoiceHeader() throws AxelorException { Invoice invoice = new Invoice(); invoice.setCompany(company); invoice.setOperationTypeSelect(operationType); if(partner == null) { throw new AxelorException(String.format(I18n.get(IExceptionMessage.INVOICE_GENERATOR_2), GeneralServiceImpl.EXCEPTION), IException.MISSING_FIELD); } invoice.setPartner(partner); if(paymentCondition == null) { paymentCondition = partner.getPaymentCondition(); } if(paymentCondition == null) { throw new AxelorException(String.format(I18n.get(IExceptionMessage.INVOICE_GENERATOR_3), GeneralServiceImpl.EXCEPTION), IException.MISSING_FIELD); } invoice.setPaymentCondition(paymentCondition); if(paymentMode == null) { paymentMode = partner.getPaymentMode(); } if(paymentMode == null) { throw new AxelorException(String.format(I18n.get(IExceptionMessage.INVOICE_GENERATOR_4), GeneralServiceImpl.EXCEPTION), IException.MISSING_FIELD); } invoice.setPaymentMode(paymentMode); if(mainInvoicingAddress == null) { mainInvoicingAddress = Beans.get(PartnerService.class).getInvoicingAddress(partner); } if(mainInvoicingAddress == null && partner.getIsCustomer()) { throw new AxelorException(String.format(I18n.get(IExceptionMessage.INVOICE_GENERATOR_5), GeneralServiceImpl.EXCEPTION), IException.MISSING_FIELD); } invoice.setAddress(mainInvoicingAddress); invoice.setContactPartner(contactPartner); if(currency == null) { currency = partner.getCurrency(); } if(currency == null) { throw new AxelorException(String.format(I18n.get(IExceptionMessage.INVOICE_GENERATOR_6), GeneralServiceImpl.EXCEPTION), IException.MISSING_FIELD); } invoice.setCurrency(currency); invoice.setPartnerAccount(Beans.get(AccountCustomerService.class).getPartnerAccount(partner, company, operationType == InvoiceRepository.OPERATION_TYPE_SUPPLIER_PURCHASE || operationType == InvoiceRepository.OPERATION_TYPE_SUPPLIER_REFUND)); invoice.setJournal(journalService.getJournal(invoice)); invoice.setStatusSelect(InvoiceRepository.STATUS_DRAFT); if(priceList == null) { if(InvoiceToolService.isPurchase(invoice)) { priceList = partner.getPurchasePriceList(); } else { priceList = partner.getSalePriceList(); } } invoice.setPriceList(priceList); invoice.setInternalReference(internalReference); invoice.setExternalReference(externalReference); // Set ATI mode on invoice AccountConfigService accountConfigService = Beans.get(AccountConfigService.class); AccountConfig accountConfig = accountConfigService.getAccountConfig(company); int atiChoice = accountConfig.getInvoiceInAtiSelect(); if(inAti == null) { invoice.setInAti(accountConfigService.getInvoiceInAti(accountConfig)); } else if(atiChoice == AccountConfigRepository.INVOICE_ATI_DEFAULT || atiChoice == AccountConfigRepository.INVOICE_WT_DEFAULT) { invoice.setInAti(inAti); } else if(atiChoice == AccountConfigRepository.INVOICE_ATI_ALWAYS) { invoice.setInAti(true); } else { invoice.setInAti(false); } // Set Company bank details if(companyBankDetails == null) { AccountingSituation accountingSituation = Beans.get(AccountingSituationService.class).getAccountingSituation(partner, company); if(accountingSituation != null) { companyBankDetails = accountingSituation.getCompanyBankDetails(); } else { companyBankDetails = company.getDefaultBankDetails(); } } invoice.setCompanyBankDetails(companyBankDetails); initCollections(invoice); return invoice; } /** * Peupler une facture. * <p> * Cette fonction permet de déterminer de déterminer les tva d'une facture à partir des lignes de factures en paramètres. * </p> * * @param invoice * @param invoiceLines * * @throws AxelorException */ public void populate(Invoice invoice, List<InvoiceLine> invoiceLines) throws AxelorException { logger.debug("Peupler une facture => lignes de factures: {} ", new Object[] { invoiceLines.size() }); initCollections( invoice ); invoice.getInvoiceLineList().addAll(invoiceLines); // create Tva lines invoice.getInvoiceLineTaxList().addAll((new TaxInvoiceLine(invoice, invoiceLines)).creates()); computeInvoice(invoice); } /** * Initialiser l'ensemble des Collections d'une facture * * @param invoice */ protected void initCollections(Invoice invoice){ initInvoiceLineTaxList(invoice); initInvoiceLineList(invoice); } /** * Initialiser l'ensemble des listes de ligne de facture d'une facture * * @param invoice */ protected void initInvoiceLineList(Invoice invoice) { if (invoice.getInvoiceLineList() == null) { invoice.setInvoiceLineList(new ArrayList<InvoiceLine>()); } else { invoice.getInvoiceLineList().clear(); } } /** * Initialiser l'ensemble des listes de ligne de tva d'une facture * * @param invoice */ protected void initInvoiceLineTaxList(Invoice invoice) { if (invoice.getInvoiceLineTaxList() == null) { invoice.setInvoiceLineTaxList(new ArrayList<InvoiceLineTax>()); } else { invoice.getInvoiceLineTaxList().clear(); } } /** * Calculer le montant d'une facture. * <p> * Le calcul est basé sur les lignes de TVA préalablement créées. * </p> * * @param invoice * @throws AxelorException */ public void computeInvoice(Invoice invoice) throws AxelorException { // Dans la devise de la comptabilité du tiers invoice.setExTaxTotal( BigDecimal.ZERO ); invoice.setTaxTotal( BigDecimal.ZERO ); invoice.setInTaxTotal( BigDecimal.ZERO ); // Dans la devise de la facture invoice.setCompanyExTaxTotal(BigDecimal.ZERO); invoice.setCompanyTaxTotal(BigDecimal.ZERO); invoice.setCompanyInTaxTotal(BigDecimal.ZERO); for (InvoiceLineTax invoiceLineTax : invoice.getInvoiceLineTaxList()) { // Dans la devise de la comptabilité du tiers invoice.setExTaxTotal(invoice.getExTaxTotal().add( invoiceLineTax.getExTaxBase() )); invoice.setTaxTotal(invoice.getTaxTotal().add( invoiceLineTax.getTaxTotal() )); invoice.setInTaxTotal(invoice.getInTaxTotal().add( invoiceLineTax.getInTaxTotal() )); // Dans la devise de la facture invoice.setCompanyExTaxTotal(invoice.getCompanyExTaxTotal().add( invoiceLineTax.getCompanyExTaxBase() )); invoice.setCompanyTaxTotal(invoice.getCompanyTaxTotal().add( invoiceLineTax.getCompanyTaxTotal() )); invoice.setCompanyInTaxTotal(invoice.getCompanyInTaxTotal().add( invoiceLineTax.getCompanyInTaxTotal() )); } logger.debug("Montant de la facture: HT = {}, TVA = {}, TTC = {}", new Object[] { invoice.getExTaxTotal(), invoice.getTaxTotal(), invoice.getInTaxTotal() }); } }