com.axelor.apps.account.service.PaymentScheduleService.java Source code

Java tutorial

Introduction

Here is the source code for com.axelor.apps.account.service.PaymentScheduleService.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;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.joda.time.LocalDate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.PaymentMode;
import com.axelor.apps.account.db.PaymentSchedule;
import com.axelor.apps.account.db.PaymentScheduleLine;
import com.axelor.apps.account.db.repo.PaymentScheduleLineRepository;
import com.axelor.apps.account.db.repo.PaymentScheduleRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.base.db.BankDetails;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.IAdministration;
import com.axelor.apps.base.db.Partner;
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.apps.base.service.administration.SequenceService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.IException;
import com.axelor.i18n.I18n;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;

public class PaymentScheduleService {

    private final Logger log = LoggerFactory.getLogger(getClass());

    protected PaymentScheduleLineService paymentScheduleLineService;
    protected PaymentScheduleLineRepository paymentScheduleLineRepo;
    protected SequenceService sequenceService;
    protected PaymentScheduleRepository paymentScheduleRepo;
    protected PartnerService partnerService;

    protected LocalDate date;

    @Inject
    public PaymentScheduleService(GeneralService generalService,
            PaymentScheduleLineService paymentScheduleLineService,
            PaymentScheduleLineRepository paymentScheduleLineRepo, SequenceService sequenceService,
            PaymentScheduleRepository paymentScheduleRepo, PartnerService partnerService) {
        this.paymentScheduleLineService = paymentScheduleLineService;
        this.paymentScheduleLineRepo = paymentScheduleLineRepo;
        this.sequenceService = sequenceService;
        this.paymentScheduleRepo = paymentScheduleRepo;
        this.partnerService = partnerService;

        date = generalService.getTodayDate();
    }

    /**
     * Cration d'un chancier sans ces lignes.
     *
     * @param partner
     *          Le tiers.
     * @param invoices
     *         Collection de factures.
     * @param company
     *          La socit.
     * @param startDate
     *          Date de premire chance.
     * @param nbrTerm
     *          Nombre d'chances.
     *
     * @return
     *          L'chancier cr.
     * @throws AxelorException
     */
    public PaymentSchedule createPaymentSchedule(Partner partner, Company company, Set<Invoice> invoices,
            LocalDate startDate, int nbrTerm) throws AxelorException {

        Invoice invoice = null;

        PaymentSchedule paymentSchedule = this.createPaymentSchedule(partner, invoice, company, date, startDate,
                nbrTerm, partnerService.getDefaultBankDetails(partner), partner.getPaymentMode());

        paymentSchedule.getInvoiceSet().addAll(invoices);

        return paymentSchedule;
    }

    /**
     * Cration d'un chancier sans ces lignes.
     *
     * @param partner
     *          Le tiers.
     * @param invoice
     *          Facture globale permettant de dfinir la facture pour une chance.
     *          L'chancier est automatiquement associ  la facture si celle-ci existe.
     * @param company
     *          La socit.
     * @param date
     *          Date de cration.
     * @param startDate
     *          Date de premire chance.
     * @param nbrTerm
     *          Nombre d'chances.
     * @param bankDetails
     *          RIB.
     * @param paymentMode
     *          Mode de paiement.
     * @param payerPartner
     *          Tiers payeur.
     * @param type
     *          Type de l'chancier.
     *          <code>0 = paiement</code>
     *          <code>1 = mensu masse</code>
     *          <code>2 = mensu grand-compte</code>
     *
     * @return
     *          L'chancier cr.
     * @throws AxelorException
     */
    public PaymentSchedule createPaymentSchedule(Partner partner, Invoice invoice, Company company, LocalDate date,
            LocalDate startDate, int nbrTerm, BankDetails bankDetails, PaymentMode paymentMode)
            throws AxelorException {

        PaymentSchedule paymentSchedule = new PaymentSchedule();

        paymentSchedule.setCompany(company);
        paymentSchedule.setScheduleId(this.getPaymentScheduleSequence(company));
        paymentSchedule.setCreationDate(date);
        paymentSchedule.setStartDate(startDate);
        paymentSchedule.setNbrTerm(nbrTerm);
        paymentSchedule.setBankDetails(bankDetails);
        paymentSchedule.setPaymentMode(paymentMode);
        paymentSchedule.setPartner(partner);

        if (paymentSchedule.getInvoiceSet() == null) {
            paymentSchedule.setInvoiceSet(new HashSet<Invoice>());
        } else {
            paymentSchedule.getInvoiceSet().clear();
        }

        if (invoice != null) {
            paymentSchedule.setInvoice(invoice);
            invoice.setPaymentSchedule(paymentSchedule);
        }

        return paymentSchedule;
    }

    /**
     * Fonction permettant de tester et de rcuprer une squence de prlvement
     * @param company
     *          Une socit
     * @param journal
     *          Un journal
     * @return
     * @throws AxelorException
     */
    public String getPaymentScheduleSequence(Company company) throws AxelorException {
        String seq = sequenceService.getSequenceNumber(IAdministration.PAYMENT_SCHEDULE, company);
        if (seq == null) {
            throw new AxelorException(
                    String.format("%s :\n" + I18n.get(IExceptionMessage.PAYMENT_SCHEDULE_5) + " %s",
                            GeneralServiceImpl.EXCEPTION, company.getName()),
                    IException.CONFIGURATION_ERROR);
        }
        return seq;
    }

    /**
     * Obtenir le total des factures des lignes d'un chancier.
     *
     * @param paymentSchedule
     *          L'chancier cible.
     *
     * @return
     *          Le somme des montants TTC des lignes de l'chancier.
     */
    public BigDecimal getInvoiceTermTotal(PaymentSchedule paymentSchedule) {

        BigDecimal totalAmount = BigDecimal.ZERO;

        if (paymentSchedule != null && paymentSchedule.getPaymentScheduleLineList() != null
                && !paymentSchedule.getPaymentScheduleLineList().isEmpty()) {
            for (PaymentScheduleLine paymentScheduleLine : paymentSchedule.getPaymentScheduleLineList()) {
                if (paymentScheduleLine.getInTaxAmount() != null) {

                    log.debug("Somme TTC des lignes de l'chancier {} : total = {}, ajout = {}", new Object[] {
                            paymentSchedule.getScheduleId(), totalAmount, paymentScheduleLine.getInTaxAmount() });

                    totalAmount = totalAmount.add(paymentScheduleLine.getInTaxAmount());
                }
            }
        }

        log.debug("Obtention de la somme TTC des lignes de l'chancier {} : {}",
                new Object[] { paymentSchedule.getScheduleId(), totalAmount });

        return totalAmount;

    }

    /**
     * Mise  jour d'un chancier avec un nouveau montant d'chance.
     *
     * @param paymentSchedule
     *          L'chancier cible.
     * @param inTaxTotal
     *          Nouveau montant d'une chance.
     */
    @Transactional
    public void updatePaymentSchedule(PaymentSchedule paymentSchedule, BigDecimal inTaxTotal) {

        log.debug("Mise  jour de l'chancier {} : {}",
                new Object[] { paymentSchedule.getScheduleId(), inTaxTotal });

        for (PaymentScheduleLine paymentScheduleLine : paymentSchedule.getPaymentScheduleLineList()) {

            if (paymentScheduleLine.getStatusSelect() == PaymentScheduleLineRepository.STATUS_IN_PROGRESS
                    && !paymentScheduleLine.getRejectedOk()) {

                log.debug("Mise  jour de la ligne {} ", paymentScheduleLine.getName());

                paymentScheduleLine.setInTaxAmount(inTaxTotal);
            }
        }

        paymentScheduleRepo.save(paymentSchedule);

    }

    /**
     * Cration d'un chancier avec ces lignes.
     *
     * @param company
     *          La socit.
     * @param date
     *          Date de cration.
     * @param firstTermDate
     *          Date de premire chance.
     * @param initialInTaxAmount
     *          Montant d'une chance.
     * @param nbrTerm
     *          Nombre d'chances.
     * @param bankDetails
     *          RIB.
     * @param paymentMode
     *          Mode de paiement.
     * @param payerPartner
     *          Tiers payeur.
     *
     * @return
     *          L'chancier cr.
     * @throws AxelorException
     */
    public PaymentSchedule createPaymentSchedule(Partner partner, Company company, LocalDate date,
            LocalDate firstTermDate, BigDecimal initialInTaxAmount, int nbrTerm, BankDetails bankDetails,
            PaymentMode paymentMode) throws AxelorException {

        Invoice invoice = null;
        PaymentSchedule paymentSchedule = this.createPaymentSchedule(partner, invoice, company, date, firstTermDate,
                nbrTerm, bankDetails, paymentMode);

        paymentSchedule.setPaymentScheduleLineList(new ArrayList<PaymentScheduleLine>());

        for (int term = 1; term < nbrTerm + 1; term++) {
            paymentSchedule.getPaymentScheduleLineList().add(paymentScheduleLineService.createPaymentScheduleLine(
                    paymentSchedule, initialInTaxAmount, term, firstTermDate.plusMonths(term - 1)));
        }

        return paymentSchedule;
    }

    /**
     * This method is used to get the movelines to be paid based on a paymentSchedule
     * It loops on the invoice M2M content and gets the movelines which are to pay
     * @param ps
     * @return
     */
    public List<MoveLine> getPaymentSchedulerMoveLineToPay(PaymentSchedule paymentSchedule) {
        log.debug("In getPaymentSchedulerMoveLineToPay ....");
        List<MoveLine> moveLines = new ArrayList<MoveLine>();
        for (Invoice invoice : paymentSchedule.getInvoiceSet()) {
            if (invoice.getCompanyInTaxTotalRemaining().compareTo(BigDecimal.ZERO) > 0 && invoice.getMove() != null
                    && invoice.getMove().getMoveLineList() != null) {
                for (MoveLine moveLine : invoice.getMove().getMoveLineList()) {
                    if (moveLine.getAccount().getReconcileOk()
                            && moveLine.getAmountRemaining().compareTo(BigDecimal.ZERO) > 0
                            && moveLine.getDebit().compareTo(BigDecimal.ZERO) > 0) {
                        moveLines.add(moveLine);
                    }
                }
            }
        }
        log.debug("End getPaymentSchedulerMoveLineToPay.");
        return moveLines;
    }

    /**
     * Permet de valider un chancier.
      *
     * @param paymentSchedule
     * @throws AxelorException
     */
    @Transactional(rollbackOn = { AxelorException.class, Exception.class })
    public void validatePaymentSchedule(PaymentSchedule paymentSchedule) throws AxelorException {

        log.debug("Validation de l'chancier {}", paymentSchedule.getScheduleId());

        if (paymentSchedule.getPaymentScheduleLineList() == null
                || paymentSchedule.getPaymentScheduleLineList().size() == 0) {
            throw new AxelorException(String.format(I18n.get(IExceptionMessage.PAYMENT_SCHEDULE_6),
                    GeneralServiceImpl.EXCEPTION, paymentSchedule.getScheduleId()), IException.INCONSISTENCY);
        }

        //      this.updateInvoices(paymentSchedule); //TODO

        paymentSchedule.setStatusSelect(PaymentScheduleRepository.STATUS_CONFIRMED);

        paymentScheduleRepo.save(paymentSchedule);
    }

    public void updateInvoices(PaymentSchedule paymentSchedule) {

        if (paymentSchedule.getInvoiceSet() != null) {

            List<MoveLine> moveLineInvoiceToPay = this.getPaymentSchedulerMoveLineToPay(paymentSchedule);

            for (MoveLine moveLineInvoice : moveLineInvoiceToPay) {

                moveLineInvoice.getMove().setIgnoreInReminderOk(true);
                this.updateInvoice(moveLineInvoice.getMove().getInvoice(), paymentSchedule);

            }
        }
    }

    public void updateInvoice(Invoice invoice, PaymentSchedule paymentSchedule) {

        invoice.setSchedulePaymentOk(true);
        invoice.setPaymentSchedule(paymentSchedule);
    }

    /**
     * Methode qui annule un chancier
     *
     * @param paymentSchedule
     */
    public void cancelPaymentSchedule(PaymentSchedule paymentSchedule) {

        // L'chancier est pass  annul
        paymentSchedule.setStatusSelect(PaymentScheduleRepository.STATUS_CANCELED);

        for (PaymentScheduleLine paymentScheduleLine : paymentSchedule.getPaymentScheduleLineList()) {

            // Si l'chance n'est pas compltement paye
            if (paymentScheduleLine.getInTaxAmountPaid().compareTo(paymentScheduleLine.getInTaxAmount()) != 0) {

                // L'chance est passe  clotur
                paymentScheduleLine.setStatusSelect(PaymentScheduleLineRepository.STATUS_CLOSED);
            }
        }

        for (Invoice invoice : paymentSchedule.getInvoiceSet()) {
            // L'chancier n'est plus selectionn sur la facture
            invoice.setPaymentSchedule(null);

            // L'chancier est assign dans un nouveau champs afin de garder un lien invisble pour l'utilisateur, mais utilis pour le passage en irrcouvrable
            invoice.setCanceledPaymentSchedule(paymentSchedule);
            invoice.setSchedulePaymentOk(false);
        }

    }

    /**
     * Methode permettant de savoir si l'chance passe en paramtre est la dernire de l'chancier
     * @param paymentScheduleLine
     * @return
     */
    public boolean isLastSchedule(PaymentScheduleLine paymentScheduleLine) {
        if (paymentScheduleLine != null) {
            if (paymentScheduleLineRepo.all()
                    .filter("self.paymentSchedule = ?1 and self.scheduleDate > ?2 and self.statusSelect = ?3",
                            paymentScheduleLine.getPaymentSchedule(), paymentScheduleLine.getScheduleDate(),
                            PaymentScheduleLineRepository.STATUS_IN_PROGRESS)
                    .fetchOne() == null) {
                log.debug("Dernire chance");
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * Mthode permettant de passer les statuts des lignes d'chances et de l'chancier  'clo' ie clotur
     * @param invoice
     *          Une facture de fin de cycle
     * @throws AxelorException
     */
    public void closePaymentSchedule(PaymentSchedule paymentSchedule) throws AxelorException {

        log.debug("Cloture de l'chancier");

        //On rcupre un statut clotur, afin de pouvoir changer l'tat des lignes d'chanciers

        for (PaymentScheduleLine paymentScheduleLine : paymentSchedule.getPaymentScheduleLineList()) {
            paymentScheduleLine.setStatusSelect(PaymentScheduleLineRepository.STATUS_CLOSED);
        }
        paymentSchedule.setStatusSelect(PaymentScheduleRepository.STATUS_CLOSED);

    }

    public LocalDate getMostOldDatePaymentScheduleLine(List<PaymentScheduleLine> paymentScheduleLineList) {
        LocalDate minPaymentScheduleLineDate = new LocalDate();

        if (paymentScheduleLineList != null && !paymentScheduleLineList.isEmpty()) {
            for (PaymentScheduleLine paymentScheduleLine : paymentScheduleLineList) {
                if (minPaymentScheduleLineDate.isAfter(paymentScheduleLine.getScheduleDate())) {
                    minPaymentScheduleLineDate = paymentScheduleLine.getScheduleDate();
                }
            }
        } else {
            minPaymentScheduleLineDate = null;
        }
        return minPaymentScheduleLineDate;
    }

    public LocalDate getMostRecentDatePaymentScheduleLine(List<PaymentScheduleLine> paymentScheduleLineList) {
        LocalDate minPaymentScheduleLineDate = new LocalDate();

        if (paymentScheduleLineList != null && !paymentScheduleLineList.isEmpty()) {
            for (PaymentScheduleLine paymentScheduleLine : paymentScheduleLineList) {
                if (minPaymentScheduleLineDate.isBefore(paymentScheduleLine.getScheduleDate())) {
                    minPaymentScheduleLineDate = paymentScheduleLine.getScheduleDate();
                }
            }
        } else {
            minPaymentScheduleLineDate = null;
        }
        return minPaymentScheduleLineDate;
    }

    // Transactional

    /**
     * Crer des lignes d'chancier  partir des lignes de factures de celui-ci.
     *
     * @param paymentSchedule
     * @throws AxelorException
     */
    @Transactional
    public void createPaymentScheduleLines(PaymentSchedule paymentSchedule) {

        this.initCollection(paymentSchedule);

        paymentSchedule.getPaymentScheduleLineList()
                .addAll(paymentScheduleLineService.createPaymentScheduleLines(paymentSchedule));
        paymentScheduleRepo.save(paymentSchedule);

    }

    public void initCollection(PaymentSchedule paymentSchedule) {

        if (paymentSchedule.getPaymentScheduleLineList() == null) {
            paymentSchedule.setPaymentScheduleLineList(new ArrayList<PaymentScheduleLine>());
        } else {
            paymentSchedule.getPaymentScheduleLineList().clear();
        }

    }

    @Transactional(rollbackOn = { AxelorException.class, Exception.class })
    public void toCancelPaymentSchedule(PaymentSchedule paymentSchedule) {
        this.cancelPaymentSchedule(paymentSchedule);
        paymentScheduleRepo.save(paymentSchedule);
    }

}