com.axelor.apps.account.service.debtrecovery.ReminderService.java Source code

Java tutorial

Introduction

Here is the source code for com.axelor.apps.account.service.debtrecovery.ReminderService.java

Source

/**
 * 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);
    }

}