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