Java tutorial
/** * Axelor Business Solutions * * Copyright (C) 2015 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.debtrecovery; import java.io.IOException; import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashSet; 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.Move; import com.axelor.apps.account.db.MoveLine; import com.axelor.apps.account.db.PaymentScheduleLine; import com.axelor.apps.account.db.Reminder; import com.axelor.apps.account.db.repo.AccountingSituationRepository; import com.axelor.apps.account.db.repo.MoveLineRepository; import com.axelor.apps.account.db.repo.PaymentScheduleLineRepository; import com.axelor.apps.account.db.repo.ReminderRepository; import com.axelor.apps.account.exception.IExceptionMessage; import com.axelor.apps.account.service.AccountCustomerService; 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.service.administration.GeneralService; import com.axelor.apps.base.service.administration.GeneralServiceImpl; import com.axelor.apps.tool.date.DateTool; 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.google.inject.Inject; import com.google.inject.persist.Transactional; public class ReminderService { private final Logger log = LoggerFactory.getLogger(getClass()); protected ReminderSessionService reminderSessionService; protected ReminderActionService reminderActionService; protected AccountCustomerService accountCustomerService; protected MoveLineRepository moveLineRepo; protected PaymentScheduleLineRepository paymentScheduleLineRepo; protected AccountConfigService accountConfigService; protected ReminderRepository reminderRepo; protected LocalDate today; @Inject public ReminderService(ReminderSessionService reminderSessionService, ReminderActionService reminderActionService, AccountCustomerService accountCustomerService, MoveLineRepository moveLineRepo, PaymentScheduleLineRepository paymentScheduleLineRepo, AccountConfigService accountConfigService, ReminderRepository reminderRepo, GeneralService generalService) { this.reminderSessionService = reminderSessionService; this.reminderActionService = reminderActionService; this.accountCustomerService = accountCustomerService; this.moveLineRepo = moveLineRepo; this.paymentScheduleLineRepo = paymentScheduleLineRepo; this.accountConfigService = accountConfigService; this.reminderRepo = reminderRepo; this.today = generalService.getTodayDate(); } public void testCompanyField(Company company) throws AxelorException { AccountConfig accountConfig = accountConfigService.getAccountConfig(company); accountConfigService.getReminderConfigLineList(accountConfig); } /** * Fonction permettant de calculer le solde exigible relanable d'un tiers * @param reminder * Une relance * @return * Le solde exigible relanable */ public BigDecimal getBalanceDueReminder(List<MoveLine> moveLineList, Partner partner) { BigDecimal balanceSubstract = this.getSubstractBalanceDue(partner); BigDecimal balanceDueReminder = BigDecimal.ZERO; for (MoveLine moveLine : moveLineList) { balanceDueReminder = balanceDueReminder.add(moveLine.getAmountRemaining()); } balanceDueReminder = balanceDueReminder.add(balanceSubstract); return balanceDueReminder; } public BigDecimal getSubstractBalanceDue(Partner partner) { List<? extends MoveLine> moveLineQuery = moveLineRepo.all().filter("self.partner = ?1", partner).fetch(); BigDecimal balance = BigDecimal.ZERO; for (MoveLine moveLine : moveLineQuery) { if (moveLine.getCredit().compareTo(BigDecimal.ZERO) > 0) { if (moveLine.getAccount() != null && moveLine.getAccount().getReconcileOk()) { balance = balance.subtract(moveLine.getAmountRemaining()); } } } return balance; } /** * Fonction qui rcupre la plus ancienne date d'chance d'une liste de lignes d'criture * @param moveLineList * Une liste de lignes d'criture * @return * la plus ancienne date d'chance */ public LocalDate getOldDateMoveLine(List<MoveLine> moveLineList) { LocalDate minMoveLineDate = new LocalDate(); if (moveLineList != null && !moveLineList.isEmpty()) { for (MoveLine moveLine : moveLineList) { if (minMoveLineDate.isAfter(moveLine.getDueDate())) { minMoveLineDate = moveLine.getDueDate(); } } } else { minMoveLineDate = null; } return minMoveLineDate; } /** * Fonction qui rcupre la plus rcente date entre deux date * @param date1 * Une date * @param date2 * Une date * @return minDate * La plus ancienne date */ public LocalDate getLastDate(LocalDate date1, LocalDate date2) { LocalDate minDate = new LocalDate(); if (date1 != null && date2 != null) { if (date1.isAfter(date2)) { minDate = date1; } else { minDate = date2; } } else if (date1 != null) { minDate = date1; } else if (date2 != null) { minDate = date2; } else { minDate = null; } return minDate; } /** * Fonction qui permet de rcuprer la date de relance la plus rcente * @param reminder * Une relance * @return * La date de relance la plus rcente */ public LocalDate getLastDateReminder(Reminder reminder) { return reminder.getReminderDate(); } /** * Fonction qui dtermine la date de rfrence * @param reminder * Une relance * @return * La date de rfrence */ public LocalDate getReferenceDate(Reminder reminder) { AccountingSituation accountingSituation = reminder.getAccountingSituation(); List<MoveLine> moveLineList = this.getMoveLineReminder(accountingSituation.getPartner(), accountingSituation.getCompany()); // Date la plus ancienne des lignes d'criture LocalDate minMoveLineDate = getOldDateMoveLine(moveLineList); log.debug("minMoveLineDate : {}", minMoveLineDate); // 2: Date la plus rcente des relances LocalDate reminderLastDate = getLastDateReminder(reminder); log.debug("reminderLastDate : {}", reminderLastDate); // Date de rfrence : Date la plus rcente des deux ensembles (1 et 2) LocalDate reminderRefDate = getLastDate(minMoveLineDate, reminderLastDate); log.debug("reminderRefDate : {}", reminderRefDate); return reminderRefDate; } /** * Fonction permettant de rcuperer une liste de ligne d'criture exigible relanable d'un tiers * @param partner * Un tiers * @param company * Une socit * @return * La liste de ligne d'criture */ public List<MoveLine> getMoveLineReminder(Partner partner, Company company) { List<MoveLine> moveLineList = new ArrayList<MoveLine>(); List<MoveLine> moveLineQuery = (List<MoveLine>) this.getMoveLine(partner, company); int mailTransitTime = company.getAccountConfig().getMailTransitTime(); for (MoveLine moveLine : moveLineQuery) { if (moveLine.getMove() != null && !moveLine.getMove().getIgnoreInReminderOk()) { Move move = moveLine.getMove(); //facture exigibles non bloque en relance et dont la date de facture + dlai d'acheminement < date du jour if (move.getInvoice() != null && !move.getInvoice().getReminderBlockingOk() && !move.getInvoice().getSchedulePaymentOk() && ((move.getInvoice().getInvoiceDate()).plusDays(mailTransitTime)).isBefore(today)) { if ((moveLine.getDebit().compareTo(BigDecimal.ZERO) > 0) && moveLine.getDueDate() != null && (today.isAfter(moveLine.getDueDate()) || today.isEqual(moveLine.getDueDate()))) { if (moveLine.getAccount() != null && moveLine.getAccount().getReconcileOk()) { if (moveLine.getAmountRemaining().compareTo(BigDecimal.ZERO) > 0) { moveLineList.add(moveLine); } } } } //chances rejetes qui ne sont pas bloqus else if (move.getInvoice() == null) { if (moveLine.getPaymentScheduleLine() != null && (moveLine.getDebit().compareTo(BigDecimal.ZERO) > 0) && moveLine.getDueDate() != null && (today.isAfter(moveLine.getDueDate()) || today.isEqual(moveLine.getDueDate()))) { if (moveLine.getAccount() != null && moveLine.getAccount().getReconcileOk()) { if (moveLine.getAmountRemaining().compareTo(BigDecimal.ZERO) > 0) { moveLineList.add(moveLine); } } } } } } return moveLineList; } public List<Invoice> getInvoiceList(List<MoveLine> moveLineList) { List<Invoice> invoiceList = new ArrayList<Invoice>(); for (MoveLine moveLine : moveLineList) { if (moveLine.getMove().getInvoice() != null && !moveLine.getMove().getInvoice().getReminderBlockingOk()) { invoiceList.add(moveLine.getMove().getInvoice()); } } return invoiceList; } public List<PaymentScheduleLine> getPaymentScheduleList(List<MoveLine> moveLineList, Partner partner) { List<PaymentScheduleLine> paymentScheduleLineList = new ArrayList<PaymentScheduleLine>(); for (MoveLine moveLine : moveLineList) { if (moveLine.getMove().getInvoice() == null) { // Ajout la liste des chances exigibles relanables PaymentScheduleLine paymentScheduleLine = getPaymentScheduleFromMoveLine(partner, moveLine); if (paymentScheduleLine != null) { // Si un montant reste payer, c'est dire une chance rejet if (moveLine.getAmountRemaining().compareTo(BigDecimal.ZERO) > 0) { paymentScheduleLineList.add(paymentScheduleLine); } } } } return paymentScheduleLineList; } /** * Mthode permettant de rcuprer l'ensemble des lignes d'criture d'un tiers * @param partner * Un tiers * @param company * Une socit * @return */ public List<? extends MoveLine> getMoveLine(Partner partner, Company company) { return moveLineRepo.all().filter("self.partner = ?1 and self.move.company = ?2", partner, company).fetch(); } /** * Mthode permettant de rcuprer une ligne d'chancier depuis une ligne d'criture * @param partner * Un tiers * @param moveLine * @return */ public PaymentScheduleLine getPaymentScheduleFromMoveLine(Partner partner, MoveLine moveLine) { return paymentScheduleLineRepo.all().filter("self.rejectMoveLine = ?1", moveLine).fetchOne(); } /** * Procdure permettant de tester si aujourd'hui nous sommes dans une priode particulire * @param dayBegin * Le jour du dbut de la priode * @param dayEnd * Le jour de fin de la priode * @param monthBegin * Le mois de dbut de la priode * @param monthEnd * Le mois de fin de la priode * @return * Sommes-nous dans la priode? */ public boolean periodOk(int dayBegin, int dayEnd, int monthBegin, int monthEnd) { return DateTool.dateInPeriod(today, dayBegin, monthBegin, dayEnd, monthEnd); } public Reminder getReminder(Partner partner, Company company) throws AxelorException { AccountingSituationRepository accSituationRepo = Beans.get(AccountingSituationRepository.class); AccountingSituation accountingSituation = accSituationRepo.all() .filter("self.partner = ?1 and self.company = ?2", partner, company).fetchOne(); if (accountingSituation != null) { if (accountingSituation.getReminder() != null) { return accountingSituation.getReminder(); } else { return this.createReminder(accountingSituation); } } else { throw new AxelorException(String.format( "%s :\n" + I18n.get("Tiers") + " %s, " + I18n.get("Socit") + " %s : " + I18n.get(IExceptionMessage.REMINDER_1), GeneralServiceImpl.EXCEPTION, partner.getName(), company.getName()), IException.CONFIGURATION_ERROR); } } @Transactional(rollbackOn = { AxelorException.class, Exception.class }) public Reminder createReminder(AccountingSituation accountingSituation) { Reminder reminder = new Reminder(); reminder.setAccountingSituation(accountingSituation); reminderRepo.save(reminder); return reminder; } /** * Mthode de relance en masse * @param partner * Un tiers * @param company * Une socit * @throws AxelorException * @throws IllegalAccessException * @throws InstantiationException * @throws ClassNotFoundException * @throws IOException */ @Transactional(rollbackOn = { AxelorException.class, Exception.class }) public boolean reminderGenerate(Partner partner, Company company) throws AxelorException, ClassNotFoundException, InstantiationException, IllegalAccessException, IOException { boolean remindedOk = false; Reminder reminder = this.getReminder(partner, company); // ou getReminder si existe BigDecimal balanceDue = accountCustomerService.getBalanceDue(partner, company); if (balanceDue.compareTo(BigDecimal.ZERO) > 0) { reminder.setBalanceDue(balanceDue); log.debug("balanceDue : {} ", balanceDue); BigDecimal balanceDueReminder = accountCustomerService.getBalanceDueReminder(partner, company); if (balanceDueReminder.compareTo(BigDecimal.ZERO) > 0) { log.debug("balanceDueReminder : {} ", balanceDueReminder); remindedOk = true; List<MoveLine> moveLineList = this.getMoveLineReminder(partner, company); this.updateInvoiceReminder(reminder, this.getInvoiceList(moveLineList)); this.updatePaymentScheduleLineReminder(reminder, this.getPaymentScheduleList(moveLineList, partner)); reminder.setBalanceDueReminder(balanceDueReminder); Integer levelReminder = 0; if (reminder.getReminderMethodLine() != null) { levelReminder = reminder.getReminderMethodLine().getReminderLevel().getName(); } LocalDate referenceDate = this.getReferenceDate(reminder); if (referenceDate != null) { log.debug("date de rfrence : {} ", referenceDate); reminder.setReferenceDate(referenceDate); } else { throw new AxelorException(String.format( "%s :\n" + I18n.get("Tiers") + " %s, " + I18n.get("Socit") + " %s : " + I18n.get(IExceptionMessage.REMINDER_2), GeneralServiceImpl.EXCEPTION, partner.getName(), company.getName()), IException.CONFIGURATION_ERROR); } if (reminder.getReminderMethod() == null) { if (reminderSessionService.getReminderMethod(reminder) != null) { reminder.setReminderMethod(reminderSessionService.getReminderMethod(reminder)); reminderSessionService.reminderSession(reminder); } else { throw new AxelorException( String.format( "%s :\n" + I18n.get("Tiers") + " %s, " + I18n.get("Socit") + " %s : " + I18n.get(IExceptionMessage.REMINDER_3), GeneralServiceImpl.EXCEPTION, partner.getName(), company.getName()), IException.CONFIGURATION_ERROR); } } else { reminderSessionService.reminderSession(reminder); } if (reminder.getWaitReminderMethodLine() == null) { // Si le niveau de relance volu if (reminder.getReminderMethodLine() != null && reminder.getReminderMethodLine().getReminderLevel() != null && reminder.getReminderMethodLine().getReminderLevel().getName() > levelReminder) { reminderActionService.runAction(reminder); } } else { log.debug("Tiers {}, Socit {} - Niveau de relance en attente ", partner.getName(), company.getName()); // TODO Alarm ? TraceBackService .trace(new AxelorException( String.format( "%s :\n" + I18n.get("Tiers") + " %s, " + I18n.get("Socit") + " %s : " + I18n.get(IExceptionMessage.REMINDER_4), GeneralServiceImpl.EXCEPTION, partner.getName(), company.getName()), IException.INCONSISTENCY)); } } } else { reminderSessionService.reminderInitialisation(reminder); } return remindedOk; } public void updateInvoiceReminder(Reminder reminder, List<Invoice> invoiceList) { reminder.setInvoiceReminderSet(new HashSet<Invoice>()); reminder.getInvoiceReminderSet().addAll(invoiceList); } public void updatePaymentScheduleLineReminder(Reminder reminder, List<PaymentScheduleLine> paymentSchedueLineList) { reminder.setPaymentScheduleLineReminderSet(new HashSet<PaymentScheduleLine>()); reminder.getPaymentScheduleLineReminderSet().addAll(paymentSchedueLineList); } }