/** * 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; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import javax.persistence.Query; import org.joda.time.LocalDate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.axelor.apps.account.db.Account; import com.axelor.apps.account.db.AccountConfig; import com.axelor.apps.account.db.MoveLine; import com.axelor.apps.account.db.ReportedBalance; import com.axelor.apps.account.db.ReportedBalanceLine; import com.axelor.apps.account.db.repo.MoveLineRepository; import com.axelor.apps.account.db.repo.ReportedBalanceLineRepository; import com.axelor.apps.account.db.repo.ReportedBalanceRepository; import com.axelor.apps.account.exception.IExceptionMessage; import com.axelor.apps.account.service.config.AccountConfigService; import com.axelor.apps.base.db.Company; import com.axelor.apps.base.db.Partner; import com.axelor.apps.base.db.Period; import com.axelor.apps.base.db.Year; import com.axelor.apps.base.db.repo.PartnerRepository; import com.axelor.apps.base.db.repo.PeriodRepository; import com.axelor.apps.base.db.repo.YearRepository; import com.axelor.apps.base.service.administration.GeneralServiceImpl; import com.axelor.db.JPA; 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 YearService { private final Logger log = LoggerFactory.getLogger( getClass() ); protected AccountConfigService accountConfigService; protected PartnerRepository partnerRepository; protected ReportedBalanceRepository reportedBalanceRepo; protected ReportedBalanceLineRepository reportedBalanceLineRepo; protected YearRepository yearRepo; @Inject public YearService(AccountConfigService accountConfigService, PartnerRepository partnerRepository, ReportedBalanceRepository reportedBalanceRepo, ReportedBalanceLineRepository reportedBalanceLineRepo, YearRepository yearRepo) { this.accountConfigService = accountConfigService; this.partnerRepository = partnerRepository; this.reportedBalanceRepo = reportedBalanceRepo; this.reportedBalanceLineRepo = reportedBalanceLineRepo; this.yearRepo = yearRepo; } /** * Procédure permettant de cloturer un exercice comptable * @param year * Un exercice comptable * @throws AxelorException */ @Transactional(rollbackOn = {AxelorException.class, Exception.class}) public void closeYear(Year year) throws AxelorException { year = yearRepo.find(year.getId()); for (Period period : year.getPeriodList()) { period.setStatusSelect(PeriodRepository.STATUS_CLOSED); } Company company = year.getCompany(); if(company == null) { throw new AxelorException(String.format(I18n.get(IExceptionMessage.YEAR_1), GeneralServiceImpl.EXCEPTION,year.getName()), IException.CONFIGURATION_ERROR); } Query q = JPA.em().createQuery("select DISTINCT(ml.partner) FROM MoveLine as ml WHERE ml.date >= ?1 AND ml.date <= ?2 AND ml.move.company = ?3"); q.setParameter(1, year.getFromDate()); q.setParameter(2, year.getToDate()); q.setParameter(3, year.getCompany()); @SuppressWarnings("unchecked") List<Partner> partnerList = q.getResultList(); List<? extends Partner> partnerListAll = partnerRepository.all().fetch(); log.debug("Nombre total de tiers : {}", partnerListAll.size()); log.debug("Nombre de tiers récupéré : {}", partnerList.size()); AccountConfig accountConfig = accountConfigService.getAccountConfig(company); Account customerAccount = accountConfigService.getCustomerAccount(accountConfig); Account doubtfulCustomerAccount = accountConfigService.getDoubtfulCustomerAccount(accountConfig); for(Partner partner : partnerList) { partner = partnerRepository.find(partner.getId()); log.debug("Tiers en cours de traitement : {}", partner.getName()); boolean find = false; for(ReportedBalance reportedBalance : partner.getReportedBalanceList()) { if(reportedBalance.getCompany().equals(company)) { // On ajoute une ligne au A nouveau trouvé log.debug("On ajoute une ligne au A nouveau trouvé"); ReportedBalanceLine reportedBalanceLine = this.createReportedBalanceLine( reportedBalance, this.computeReportedBalance(year.getFromDate(), year.getToDate(), partner, customerAccount, doubtfulCustomerAccount), year); log.debug("ReportedBalanceLine : {}",reportedBalanceLine); reportedBalance.getReportedBalanceLineList().add(reportedBalanceLine); // year.getReportedBalanceLineList().add(reportedBalanceLine); // reportedBalance.save(); find = true; } } if(!find) { // On crée un A nouveau et on lui ajoute une ligne log.debug("On crée un A nouveau et on lui ajoute une ligne"); ReportedBalance reportedBalance = this.createReportedBalance(company, partner); ReportedBalanceLine reportedBalanceLine = this.createReportedBalanceLine( reportedBalance, this.computeReportedBalance(year.getFromDate(), year.getToDate(), partner, customerAccount, doubtfulCustomerAccount), year); // year.getReportedBalanceLineList().add(reportedBalanceLine); log.debug("ReportedBalanceLine : {}",reportedBalanceLine); reportedBalance.getReportedBalanceLineList().add(reportedBalanceLine); reportedBalanceRepo.save(reportedBalance); } partnerRepository.save(partner); } year.setStatusSelect(YearRepository.STATUS_CLOSED); yearRepo.save(year); } /** * Fonction permettant de créer un A nouveau * @param company * Une société * @return * Un A nouveau */ @Transactional(rollbackOn = {AxelorException.class, Exception.class}) public ReportedBalance createReportedBalance(Company company, Partner partner) { ReportedBalance reportedBalance = new ReportedBalance(); reportedBalance.setCompany(company); reportedBalance.setPartner(partner); reportedBalance.setReportedBalanceLineList(new ArrayList<ReportedBalanceLine>()); reportedBalanceRepo.save(reportedBalance); return reportedBalance; } /** * Fonction permettant de créer un Solde rapporté * @param reportedBalance * Un A nouveau */ @Transactional(rollbackOn = {AxelorException.class, Exception.class}) public ReportedBalanceLine createReportedBalanceLine(ReportedBalance reportedBalance, BigDecimal amount, Year year) { ReportedBalanceLine reportedBalanceLine = new ReportedBalanceLine(); reportedBalanceLine.setReportedBalance(reportedBalance); reportedBalanceLine.setAmount(amount); reportedBalanceLine.setYear(year); reportedBalanceLineRepo.save(reportedBalanceLine); return reportedBalanceLine; } /** * Fonction permettant de calculer le solde rapporté * @param fromDate * La date de début d'exercice comptable * @param toDate * La date de fin d'exercice comptable * @param partner * Un client payeur * @param account * Le compte client * @return * Le solde rapporté */ public BigDecimal computeReportedBalance(LocalDate fromDate, LocalDate toDate, Partner partner, Account account, Account account2) { Query q = JPA.em().createQuery("select SUM(ml.credit-ml.debit) FROM MoveLine as ml " + "WHERE ml.partner = ?1 AND ml.ignoreInAccountingOk = false AND ml.date >= ?2 AND ml.date <= ?3 AND (ml.account = ?4 OR ml.account = ?5) ", BigDecimal.class); q.setParameter(1, partner); q.setParameter(2, fromDate); q.setParameter(3, toDate); q.setParameter(4, account); q.setParameter(5, account2); BigDecimal result = (BigDecimal) q.getSingleResult(); log.debug("Solde rapporté (result) : {}", result); if(result != null) { return result; } else { return BigDecimal.ZERO; } } @Deprecated public BigDecimal computeReportedBalance2(LocalDate fromDate, LocalDate toDate, Partner partner, Account account) { MoveLineRepository moveLineRepo = Beans.get(MoveLineRepository.class); List<? extends MoveLine> moveLineList = moveLineRepo.all() .filter("self.partner = ?1 AND self.ignoreInAccountingOk = 'false' AND self.date >= ?2 AND self.date <= ?3 AND self.account = ?4", partner, fromDate, toDate, account).fetch(); BigDecimal reportedBalanceAmount = BigDecimal.ZERO; for(MoveLine moveLine : moveLineList) { if(moveLine.getDebit().compareTo(BigDecimal.ZERO) > 0) { reportedBalanceAmount = reportedBalanceAmount.subtract(moveLine.getAmountRemaining()); } else if(moveLine.getCredit().compareTo(BigDecimal.ZERO) > 0) { reportedBalanceAmount = reportedBalanceAmount.add(moveLine.getAmountRemaining()); } } if (log.isDebugEnabled()) { log.debug("Solde rapporté : {}", reportedBalanceAmount); } return reportedBalanceAmount; } public List<Period> generatePeriods(Year year){ List<Period> periods = new ArrayList<Period>(); Integer duration = year.getPeriodDurationSelect(); LocalDate fromDate = year.getFromDate(); LocalDate toDate = year.getToDate(); LocalDate periodToDate = fromDate; Integer periodNumber = 1; while(periodToDate.isBefore(toDate)){ if(periodNumber != 1) fromDate = fromDate.plusMonths(duration); periodToDate = fromDate.plusMonths(duration).minusDays(1); if(periodToDate.isAfter(toDate)) periodToDate = toDate; if(fromDate.isAfter(toDate)) continue; Period period = new Period(); period.setFromDate(fromDate); period.setToDate(periodToDate); period.setYear(year); period.setName(String.format("%02d", periodNumber)+"/"+year.getCode()); period.setCode(String.format("%02d", periodNumber)+"/"+year.getCode()+"_"+year.getCompany().getCode()); period.setCompany(year.getCompany()); period.setStatusSelect(year.getStatusSelect()); periods.add(period); periodNumber ++; } return periods; } }