First commit waiting for Budget Alert

This commit is contained in:
2025-09-04 13:37:35 +01:00
commit 2d681f27f5
4563 changed files with 1061534 additions and 0 deletions

View File

@ -0,0 +1,62 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.db.repo;
import com.axelor.apps.account.db.Account;
import com.axelor.db.JPA;
import java.util.Set;
import javax.persistence.PersistenceException;
public class AccountAccountRepository extends AccountRepository {
@Override
public Account save(Account account) {
try {
if (account.getId() == null) {
return super.save(account);
}
if (account.getReconcileOk()) {
Set<Account> accountList = account.getCompatibleAccountSet();
if (accountList != null) {
for (Account acc : accountList) {
acc.setReconcileOk(true);
acc.addCompatibleAccountSetItem(account);
JPA.save(acc);
}
}
} else {
if (account.getCompatibleAccountSet() != null) {
for (Account acc : account.getCompatibleAccountSet()) {
acc.removeCompatibleAccountSetItem(account);
if (acc.getCompatibleAccountSet().size() == 0) {
acc.setReconcileOk(false);
}
JPA.save(acc);
}
account.getCompatibleAccountSet().clear();
}
}
return super.save(account);
} catch (Exception e) {
throw new PersistenceException(e.getLocalizedMessage());
}
}
}

View File

@ -0,0 +1,30 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.db.repo;
import com.axelor.apps.account.db.AccountingBatch;
public class AccountingBatchAccountRepository extends AccountingBatchRepository {
@Override
public AccountingBatch copy(AccountingBatch entity, boolean deep) {
AccountingBatch copy = super.copy(entity, deep);
copy.setBatchList(null);
return copy;
}
}

View File

@ -0,0 +1,65 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.db.repo;
import com.axelor.apps.account.db.AccountingReport;
import com.axelor.apps.account.service.AccountingReportService;
import com.axelor.db.JPA;
import com.axelor.exception.service.TraceBackService;
import com.google.inject.Inject;
import java.math.BigDecimal;
import javax.persistence.PersistenceException;
public class AccountingReportManagementRepository extends AccountingReportRepository {
@Inject protected AccountingReportService accountingReportService;
@Override
public AccountingReport save(AccountingReport accountingReport) {
try {
if (accountingReport.getRef() == null) {
String seq = accountingReportService.getSequence(accountingReport);
accountingReportService.setSequence(accountingReport, seq);
}
return super.save(accountingReport);
} catch (Exception e) {
JPA.em().getTransaction().rollback();
JPA.runInTransaction(() -> TraceBackService.trace(e));
JPA.em().getTransaction().begin();
throw new PersistenceException(e.getLocalizedMessage());
}
}
@Override
public AccountingReport copy(AccountingReport entity, boolean deep) {
AccountingReport copy = super.copy(entity, deep);
copy.setRef(null);
copy.setStatusSelect(this.STATUS_DRAFT);
copy.setPublicationDateTime(null);
copy.setTotalDebit(BigDecimal.ZERO);
copy.setTotalCredit(BigDecimal.ZERO);
copy.setBalance(BigDecimal.ZERO);
return copy;
}
}

View File

@ -0,0 +1,30 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.db.repo;
import com.axelor.apps.account.db.AnalyticMoveLine;
public class AnalyticMoveLineMngtRepository extends AnalyticMoveLineRepository {
@Override
public AnalyticMoveLine copy(AnalyticMoveLine entity, boolean deep) {
AnalyticMoveLine copy = super.copy(entity, deep);
copy.setMoveLine(null);
copy.setInvoiceLine(null);
return copy;
}
}

View File

@ -0,0 +1,75 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.db.repo;
import com.axelor.apps.account.db.DepositSlip;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.base.db.Sequence;
import com.axelor.apps.base.db.repo.SequenceRepository;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.exception.service.TraceBackService;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.common.base.Strings;
import javax.persistence.PersistenceException;
public class DepositSlipAccountRepository extends DepositSlipRepository {
@Override
public DepositSlip save(DepositSlip entity) {
try {
if (Strings.isNullOrEmpty(entity.getDepositNumber())) {
setDepositNumber(entity);
}
return super.save(entity);
} catch (Exception e) {
TraceBackService.trace(e);
throw new PersistenceException(e.getLocalizedMessage());
}
}
private void setDepositNumber(DepositSlip entity) throws AxelorException {
SequenceService sequenceService = Beans.get(SequenceService.class);
String depositNumber =
sequenceService.getSequenceNumber(SequenceRepository.DEPOSIT_SLIP, entity.getCompany());
if (Strings.isNullOrEmpty(depositNumber)) {
throw new AxelorException(
Sequence.class,
TraceBackRepository.CATEGORY_NO_VALUE,
I18n.get(IExceptionMessage.DEPOSIT_SLIP_MISSING_SEQUENCE),
entity.getCompany().getName());
}
entity.setDepositNumber(depositNumber);
}
@Override
public void remove(DepositSlip entity) {
if (entity.getPublicationDate() != null) {
throw new PersistenceException(I18n.get(IExceptionMessage.DEPOSIT_SLIP_CANNOT_DELETE));
}
entity.clearPaymentVoucherList();
super.remove(entity);
}
}

View File

@ -0,0 +1,72 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.db.repo;
import com.axelor.apps.account.db.FixedAsset;
import com.axelor.apps.account.service.FixedAssetService;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.inject.Beans;
import com.google.common.base.Strings;
import java.math.BigDecimal;
import javax.persistence.PersistenceException;
public class FixedAssetManagementRepository extends FixedAssetRepository {
@Override
public FixedAsset save(FixedAsset fixedAsset) {
try {
computeReference(fixedAsset);
computeDepreciation(fixedAsset);
return super.save(fixedAsset);
} catch (Exception e) {
e.printStackTrace();
throw new PersistenceException(e);
}
}
private void computeReference(FixedAsset fixedAsset) {
try {
if (fixedAsset.getId() != null && Strings.isNullOrEmpty(fixedAsset.getReference())) {
fixedAsset.setReference(
Beans.get(SequenceService.class).getDraftSequenceNumber(fixedAsset));
}
} catch (Exception e) {
throw new PersistenceException(e.getLocalizedMessage());
}
}
private void computeDepreciation(FixedAsset fixedAsset) {
if ((fixedAsset.getFixedAssetLineList() == null || fixedAsset.getFixedAssetLineList().isEmpty())
&& fixedAsset.getGrossValue().compareTo(BigDecimal.ZERO) > 0) {
Beans.get(FixedAssetService.class).generateAndcomputeLines(fixedAsset);
}
}
@Override
public FixedAsset copy(FixedAsset entity, boolean deep) {
FixedAsset copy = super.copy(entity, deep);
copy.setStatusSelect(STATUS_DRAFT);
copy.setReference(null);
copy.setResidualValue(entity.getGrossValue());
copy.setFixedAssetLineList(null);
return copy;
}
}

View File

@ -0,0 +1,30 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.db.repo;
import com.axelor.apps.account.db.InvoiceBatch;
public class InvoiceBatchAccountRepository extends InvoiceBatchRepository {
@Override
public InvoiceBatch copy(InvoiceBatch entity, boolean deep) {
InvoiceBatch copy = super.copy(entity, deep);
copy.setBatchList(null);
return copy;
}
}

View File

@ -0,0 +1,102 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.db.repo;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.SubrogationRelease;
import com.axelor.apps.account.service.invoice.InvoiceService;
import com.axelor.exception.service.TraceBackService;
import com.axelor.inject.Beans;
import java.math.BigDecimal;
import java.util.Map;
import javax.persistence.PersistenceException;
public class InvoiceManagementRepository extends InvoiceRepository {
@Override
public Invoice copy(Invoice entity, boolean deep) {
Invoice copy = super.copy(entity, deep);
copy.setStatusSelect(STATUS_DRAFT);
copy.setInvoiceId(null);
copy.setInvoiceDate(null);
copy.setDueDate(null);
copy.setValidatedByUser(null);
copy.setMove(null);
copy.setOriginalInvoice(null);
copy.setCompanyInTaxTotalRemaining(BigDecimal.ZERO);
copy.setAmountPaid(BigDecimal.ZERO);
copy.setIrrecoverableStatusSelect(IRRECOVERABLE_STATUS_NOT_IRRECOUVRABLE);
copy.setAmountRejected(BigDecimal.ZERO);
copy.clearBatchSet();
copy.setDebitNumber(null);
copy.setDirectDebitManagement(null);
copy.setDoubtfulCustomerOk(false);
copy.setMove(null);
copy.setInterbankCodeLine(null);
copy.setPaymentMove(null);
copy.clearRefundInvoiceList();
copy.setRejectDate(null);
copy.setOriginalInvoice(null);
copy.setUsherPassageOk(false);
copy.setAlreadyPrintedOk(false);
copy.setCanceledPaymentSchedule(null);
copy.setDirectDebitAmount(BigDecimal.ZERO);
copy.setImportId(null);
copy.setPartnerAccount(null);
copy.setJournal(null);
copy.clearInvoicePaymentList();
copy.setPrintedPDF(null);
copy.setValidatedDate(null);
copy.setVentilatedByUser(null);
copy.setVentilatedDate(null);
copy.setPfpValidateStatusSelect(PFP_STATUS_AWAITING);
copy.setDecisionPfpTakenDate(null);
return copy;
}
@Override
public Invoice save(Invoice invoice) {
try {
invoice = super.save(invoice);
Beans.get(InvoiceService.class).setSequence(invoice);
return invoice;
} catch (Exception e) {
throw new PersistenceException(e.getLocalizedMessage());
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
public Map<String, Object> populate(Map<String, Object> json, Map<String, Object> context) {
try {
if (context.get("_model") != null
&& context.get("_model").toString().contains("SubrogationRelease")) {
long id = (long) context.get("id");
SubrogationRelease subrogationRelease =
Beans.get(SubrogationReleaseRepository.class).find(id);
json.put("$subrogationStatusSelect", subrogationRelease.getStatusSelect());
}
} catch (Exception e) {
TraceBackService.trace(e);
}
return super.populate(json, context);
}
}

View File

@ -0,0 +1,38 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.db.repo;
import com.axelor.apps.account.db.InvoicePayment;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentValidateService;
import com.axelor.exception.service.TraceBackService;
import com.axelor.inject.Beans;
import javax.persistence.PersistenceException;
public class InvoicePaymentManagementRepository extends InvoicePaymentRepository {
@Override
public InvoicePayment save(InvoicePayment invoicePayment) {
try {
Beans.get(InvoicePaymentValidateService.class).validate(invoicePayment);
return super.save(invoicePayment);
} catch (Exception e) {
TraceBackService.trace(e);
throw new PersistenceException(e);
}
}
}

View File

@ -0,0 +1,34 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.db.repo;
import com.axelor.apps.account.db.Journal;
public class JournalManagementRepository extends JournalRepository {
@Override
public Journal copy(Journal entity, boolean deep) {
Journal copy = super.copy(entity, deep);
copy.setStatusSelect(JournalRepository.STATUS_INACTIVE);
copy.setSequence(null);
return copy;
}
}

View File

@ -0,0 +1,65 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.db.repo;
import com.axelor.apps.account.db.AnalyticMoveLine;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.move.MoveLineService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import java.util.List;
import javax.persistence.PersistenceException;
public class MoveLineManagementRepository extends MoveLineRepository {
@Override
public void remove(MoveLine entity) {
if (!entity.getMove().getStatusSelect().equals(MoveRepository.STATUS_NEW)) {
try {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.MOVE_REMOVE_NOT_OK),
entity.getMove().getReference());
} catch (AxelorException e) {
throw new PersistenceException(e);
}
} else {
super.remove(entity);
}
}
@Override
public MoveLine save(MoveLine entity) {
List<AnalyticMoveLine> analyticMoveLineList = entity.getAnalyticMoveLineList();
if (analyticMoveLineList != null) {
for (AnalyticMoveLine analyticMoveLine : analyticMoveLineList) {
analyticMoveLine.setAccount(entity.getAccount());
analyticMoveLine.setAccountType(entity.getAccount().getAccountType());
}
}
try {
Beans.get(MoveLineService.class).validateMoveLine(entity);
} catch (Exception e) {
throw new PersistenceException(e);
}
return super.save(entity);
}
}

View File

@ -0,0 +1,132 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.db.repo;
import com.axelor.apps.account.db.AnalyticMoveLine;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.move.MoveSequenceService;
import com.axelor.apps.account.service.move.MoveValidateService;
import com.axelor.apps.base.db.Period;
import com.axelor.apps.base.db.repo.YearRepository;
import com.axelor.apps.base.service.PeriodService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import java.time.LocalDate;
import java.util.List;
import javax.persistence.PersistenceException;
public class MoveManagementRepository extends MoveRepository {
@Override
public Move copy(Move entity, boolean deep) {
Move copy = super.copy(entity, deep);
copy.setDate(Beans.get(AppBaseService.class).getTodayDate());
Period period = null;
try {
period =
Beans.get(PeriodService.class)
.getActivePeriod(copy.getDate(), entity.getCompany(), YearRepository.TYPE_FISCAL);
} catch (AxelorException e) {
throw new PersistenceException(e.getLocalizedMessage());
}
copy.setStatusSelect(STATUS_NEW);
copy.setReference(null);
copy.setExportNumber(null);
copy.setExportDate(null);
copy.setAccountingReport(null);
copy.setValidationDate(null);
copy.setPeriod(period);
copy.setAccountingOk(false);
copy.setIgnoreInDebtRecoveryOk(false);
copy.setPaymentVoucher(null);
copy.setRejectOk(false);
copy.setInvoice(null);
List<MoveLine> moveLineList = copy.getMoveLineList();
if (moveLineList != null) {
moveLineList.forEach(moveLine -> resetMoveLine(moveLine, copy.getDate()));
}
return copy;
}
public void resetMoveLine(MoveLine moveLine, LocalDate date) {
moveLine.setInvoiceReject(null);
moveLine.setDate(date);
moveLine.setExportedDirectDebitOk(false);
moveLine.setReimbursementStatusSelect(MoveLineRepository.REIMBURSEMENT_STATUS_NULL);
List<AnalyticMoveLine> analyticMoveLineList = moveLine.getAnalyticMoveLineList();
if (analyticMoveLineList != null) {
moveLine.getAnalyticMoveLineList().forEach(line -> line.setDate(moveLine.getDate()));
}
}
@Override
public Move save(Move move) {
try {
if (move.getStatusSelect() == MoveRepository.STATUS_DAYBOOK) {
Beans.get(MoveValidateService.class).checkPreconditions(move);
}
Beans.get(MoveSequenceService.class).setDraftSequence(move);
List<MoveLine> moveLineList = move.getMoveLineList();
if (moveLineList != null) {
for (MoveLine moveLine : moveLineList) {
List<AnalyticMoveLine> analyticMoveLineList = moveLine.getAnalyticMoveLineList();
if (analyticMoveLineList != null) {
for (AnalyticMoveLine analyticMoveLine : analyticMoveLineList) {
analyticMoveLine.setAccount(moveLine.getAccount());
analyticMoveLine.setAccountType(moveLine.getAccount().getAccountType());
}
}
}
}
return super.save(move);
} catch (Exception e) {
throw new PersistenceException(e.getLocalizedMessage());
}
}
@Override
public void remove(Move entity) {
if (!entity.getStatusSelect().equals(MoveRepository.STATUS_NEW)) {
try {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.MOVE_REMOVE_NOT_OK),
entity.getReference());
} catch (AxelorException e) {
throw new PersistenceException(e);
}
} else {
super.remove(entity);
}
}
}

View File

@ -0,0 +1,86 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.db.repo;
import com.axelor.apps.account.db.AccountingSituation;
import com.axelor.apps.account.service.AccountingSituationService;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.repo.PartnerBaseRepository;
import com.axelor.apps.base.db.repo.PartnerRepository;
import com.axelor.apps.base.service.app.AppService;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import javax.persistence.PersistenceException;
import org.apache.commons.collections.CollectionUtils;
@Singleton
public class PartnerAccountRepository extends PartnerBaseRepository {
private AppService appService;
private AccountingSituationService accountingSituationService;
@Inject
public PartnerAccountRepository(
AppService appService, AccountingSituationService accountingSituationService) {
this.appService = appService;
this.accountingSituationService = accountingSituationService;
}
@Override
public Partner save(Partner partner) {
try {
if (partner.getId() == null) {
partner = super.save(partner);
}
if (appService.isApp("account")) {
if (partner.getIsContact() == false || partner.getIsEmployee()) {
// Create & fill
Beans.get(AccountingSituationService.class)
.createAccountingSituation(Beans.get(PartnerRepository.class).find(partner.getId()));
}
// We do this for contacts too as it seems this is the way employees are handled
if (CollectionUtils.isNotEmpty(partner.getAccountingSituationList())) {
for (AccountingSituation situation : partner.getAccountingSituationList()) {
accountingSituationService.createPartnerAccounts(situation);
}
}
}
return super.save(partner);
} catch (Exception e) {
throw new PersistenceException(e);
}
}
@Override
public Partner copy(Partner partner, boolean deep) {
Partner copy = super.copy(partner, deep);
if (appService.isApp("account")) {
copy.setAccountingSituationList(null);
}
return copy;
}
}

View File

@ -0,0 +1,69 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.db.repo;
import com.axelor.apps.account.db.PaymentVoucher;
import com.axelor.apps.account.service.payment.paymentvoucher.PaymentVoucherSequenceService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.exception.service.TraceBackService;
import com.axelor.inject.Beans;
import javax.persistence.PersistenceException;
public class PaymentVoucherManagementRepository extends PaymentVoucherRepository {
@Override
public PaymentVoucher copy(PaymentVoucher entity, boolean deep) {
/**
* copy set are commented because there is a lot of vouchers that contains the same element to pay but partially
*/
PaymentVoucher copy = super.copy(entity, deep);
copy.setStatusSelect(STATUS_DRAFT);
copy.setRef(null);
copy.setPaymentDate(Beans.get(AppBaseService.class).getTodayDate());
// copy.clearPayVoucherDueElementList();
// copy.clearPayVoucherElementToPayList();
copy.setGeneratedMove(null);
copy.setBankCardTransactionNumber(null);
copy.clearBatchSet();
copy.setImportId(null);
copy.setReceiptNo(null);
// copy.setRemainingAmount(null);
// copy.setRemainingAllocatedAmount(null);
copy.setToSaveEmailOk(false);
copy.setDefaultEmailOk(false);
copy.setEmail(null);
return copy;
}
@Override
public PaymentVoucher save(PaymentVoucher paymentVoucher) {
try {
Beans.get(PaymentVoucherSequenceService.class).setReference(paymentVoucher);
return super.save(paymentVoucher);
} catch (Exception e) {
TraceBackService.trace(e);
throw new PersistenceException(e.getLocalizedMessage());
}
}
}

View File

@ -0,0 +1,40 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.db.repo;
import com.axelor.apps.account.db.ReconcileGroup;
import com.axelor.apps.account.service.ReconcileGroupSequenceService;
import com.axelor.inject.Beans;
import com.google.common.base.Strings;
import javax.persistence.PersistenceException;
public class ReconcileGroupAccountRepository extends ReconcileGroupRepository {
/** On first reconcile group save (e.g. when the code is not filled), we fill the sequence. */
@Override
public ReconcileGroup save(ReconcileGroup reconcileGroup) {
try {
if (Strings.isNullOrEmpty(reconcileGroup.getCode())) {
Beans.get(ReconcileGroupSequenceService.class).fillCodeFromSequence(reconcileGroup);
}
return super.save(reconcileGroup);
} catch (Exception e) {
throw new PersistenceException(e.getLocalizedMessage());
}
}
}

View File

@ -0,0 +1,72 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.db.repo;
import com.axelor.apps.account.db.Reconcile;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.ReconcileSequenceService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import javax.persistence.PersistenceException;
public class ReconcileManagementRepository extends ReconcileRepository {
@Override
public Reconcile save(Reconcile reconcile) {
try {
Beans.get(ReconcileSequenceService.class).setDraftSequence(reconcile);
return super.save(reconcile);
} catch (Exception e) {
throw new PersistenceException(e.getLocalizedMessage());
}
}
@Override
public Reconcile copy(Reconcile reconcile, boolean deep) {
Reconcile copy = super.copy(reconcile, deep);
copy.setCanBeZeroBalanceOk(false);
copy.setMustBeZeroBalanceOk(false);
copy.setReconcileSeq(null);
copy.setStatusSelect(ReconcileRepository.STATUS_DRAFT);
return copy;
}
@Override
public void remove(Reconcile entity) {
if (!entity.getStatusSelect().equals(ReconcileRepository.STATUS_DRAFT)) {
try {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.RECONCILE_CAN_NOT_BE_REMOVE),
entity.getReconcileSeq());
} catch (AxelorException e) {
throw new PersistenceException(e);
}
} else {
super.remove(entity);
}
}
}

View File

@ -0,0 +1,34 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.db.repo;
import com.axelor.apps.account.db.SubrogationRelease;
public class SubrogationReleaseManagementRepository extends SubrogationReleaseRepository {
@Override
public SubrogationRelease copy(SubrogationRelease entity, boolean deep) {
SubrogationRelease srCopy = super.copy(entity, deep);
srCopy.setStatusSelect(STATUS_NEW);
srCopy.clearInvoiceSet();
return srCopy;
}
}

View File

@ -0,0 +1,804 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.exception;
/**
* Interface of Exceptions. Enum all exception of axelor-account.
*
* @author dubaux
*/
public interface IExceptionMessage {
static final String INVOICE_LINE_TAX_LINE = /*$$(*/ "A tax line is missing" /*)*/;
/** Bank statement service */
static final String BANK_STATEMENT_1 = /*$$(*/
"%s : Computed balance and Ending Balance must be equal" /*)*/;
static final String BANK_STATEMENT_2 = /*$$(*/
"%s : MoveLine amount is not equals with bank statement line %s" /*)*/;
static final String BANK_STATEMENT_3 = /*$$(*/
"%s : Bank statement line %s amount can't be null" /*)*/;
/** Move service */
static final String NO_MOVES_SELECTED = /*$$(*/
"Please select 'Draft' or 'Simulated' moves" /*)*/;
static final String MOVE_VALIDATION_NOT_OK = /*$$(*/
"Error in move validation, please check the log" /*)*/;
static final String MOVE_VALIDATION_OK = /*$$(*/ "Moves validated successfully" /*)*/;
static final String MOVE_ARCHIVE_NOT_OK = /*$$(*/ "You can't archive this move %s" /*)*/;
static final String MOVE_REMOVE_NOT_OK = /*$$(*/ "You can't remove this move %s" /*)*/;
static final String MOVE_REMOVED_OK = /*$$(*/ "Move(s) has been removed successfully" /*)*/;
static final String MOVE_ARCHIVE_OK = /*$$(*/ "Move(s) has been archived successfully" /*)*/;
static final String NO_MOVE_TO_REMOVE_OR_ARCHIVE = /*$$(*/
"Please select 'Draft' or 'Daybook' or 'Canceled' moves" /*)*/;
static final String MOVE_ARCHIVE_OR_REMOVE_OK = /*$$(*/
"Move(s) has been removed or archived successfully" /*)*/;
static final String MOVE_ARCHIVE_OR_REMOVE_NOT_OK = /*$$(*/
"Error in move deleting or archiving, please check the log" /*)*/;
static final String MOVE_ARCHIVE_NOT_OK_BECAUSE_OF_LINK_WITH = /*$$(*/
"This move %s can not be archived because it is linked to another piece named %s." /*)*/;
static final String MOVE_LINE_ARCHIVE_NOT_OK_BECAUSE_OF_LINK_WITH = /*$$(*/
"This move line %s can not be archived because it is linked to another piece named %s." /*)*/;
static final String MOVE_ARCHIVE_OR_REMOVE_NOT_OK_NB = /*$$(*/
"%d moves couldn't be deleted or archived, please check the logs." /*)*/;
/** Account management service */
static final String ACCOUNT_MANAGEMENT_1_ACCOUNT = /*$$(*/
"Accounting configuration is missing for Product: %s (company: %s)" /*)*/;
/** AccountingSituationService * */
static final String ACCOUNTING_SITUATION_1 = /*$$(*/
"You have to enter a prefix for automatic customer account creation in accounting application parameters of company %s" /*)*/;
static final String ACCOUNTING_SITUATION_2 = /*$$(*/
"You have to select a sequence for automatic customer account creation in accounting application parameters of company %s" /*)*/;
static final String ACCOUNTING_SITUATION_3 = /*$$(*/
"Invalid automatic partner account creation mode, this is a bug that should be reported." /*)*/;
static final String ACCOUNTING_SITUATION_4 = /*$$(*/
"You have to enter a prefix for automatic supplier account creation in accounting application parameters of company %s" /*)*/;
static final String ACCOUNTING_SITUATION_5 = /*$$(*/
"You have to select a sequence for automatic supplier account creation in accounting application parameters of company %s" /*)*/;
static final String ACCOUNTING_SITUATION_6 = /*$$(*/
"You have to enter a prefix for automatic employee account creation in accounting application parameters of company %s" /*)*/;
static final String ACCOUNTING_SITUATION_7 = /*$$(*/
"You have to select a sequence for automatic employee account creation in accounting application parameters of company %s" /*)*/;
/** Mail service */
static final String MAIL_1 = /*$$(*/
"%s : Please define an email template for cash register (company: %s)" /*)*/;
/** Account clearance service and controller */
static final String ACCOUNT_CLEARANCE_1 = /*$$(*/
"%s : You must configure account informations for the company %s" /*)*/;
static final String ACCOUNT_CLEARANCE_2 = /*$$(*/
"%s : You must configure a financial account for then company %s" /*)*/;
static final String ACCOUNT_CLEARANCE_3 = /*$$(*/
"%s : You must configure a tax standard rate for the company %s" /*)*/;
static final String ACCOUNT_CLEARANCE_4 = /*$$(*/
"%s : You must configure account clearance for the company %s" /*)*/;
static final String ACCOUNT_CLEARANCE_5 = /*$$(*/
"%s : You must configure a clearance sequence of the overpayments for the company %s" /*)*/;
static final String ACCOUNT_CLEARANCE_6 = /*$$(*/
"%s : You must configure an overpayment account clearance journal for the company %s" /*)*/;
static final String ACCOUNT_CLEARANCE_7 = /*$$(*/ "Move lines generated" /*)*/;
/** Account customer service */
static final String ACCOUNT_CUSTOMER_1 = /*$$(*/
"%s : A customer account is missing for the company %s" /*)*/;
static final String ACCOUNT_CUSTOMER_2 = /*$$(*/
"%s : A supplier account is missing for the company %s" /*)*/;
/** Check rejection service */
static final String CHECK_REJECTION_1 = /*$$(*/
"%s : You must configure a cheque rejection sequence for the company %s" /*)*/;
/** Irrecoverable service and controller */
static final String IRRECOVERABLE_1 = /*$$(*/ "Timetable line %s" /*)*/;
static final String IRRECOVERABLE_2 = /*$$(*/
"%s : Error generated on invoice creation shift to irrecoverable %s" /*)*/;
static final String IRRECOVERABLE_3 = /*$$(*/
"%s : The invoice %s has no accounting document whose the remainder to be paid is positive" /*)*/;
static final String IRRECOVERABLE_4 = /*$$(*/
"%s : You must configure shit to irrecoverable sequence for the company %s" /*)*/;
static final String IRRECOVERABLE_5 = /*$$(*/ "Treatment finished" /*)*/;
static final String IRRECOVERABLE_6 = /*$$(*/ "Anomalies generated" /*)*/;
static final String IRRECOVERABLE_7 = /*$$(*/ "You must select a printing type" /*)*/;
/** Journal service */
static final String JOURNAL_1 = /*$$(*/ "Invoice type missing on invoice %s" /*)*/;
/** Move line export service */
static final String MOVE_LINE_EXPORT_1 = /*$$(*/
"%s : Error : You must configure a sale interface sequence for the company %s" /*)*/;
static final String MOVE_LINE_EXPORT_2 = /*$$(*/
"%s : Error : You must configure a credit note interface sequence for the company %s" /*)*/;
static final String MOVE_LINE_EXPORT_3 = /*$$(*/
"%s : Error : You must configure a treasury interface sequence for the company %s" /*)*/;
static final String MOVE_LINE_EXPORT_4 = /*$$(*/
"%s : Error : You must configure a purchase interface sequence for the company %s" /*)*/;
static final String MOVE_LINE_EXPORT_YEAR_OR_PERIOD_OR_DATE_IS_NULL = /*$$(*/
"Year or period or date is null, you must set a period." /*)*/;
/** Accounting report service and controller */
static final String ACCOUNTING_REPORT_1 = /*$$(*/
"%s : Error : You must configure an account reporting sequence for the company %s" /*)*/;
static final String ACCOUNTING_REPORT_2 = /*$$(*/
"%s : Error : You must configure an account export sequence for the company %s" /*)*/;
static final String ACCOUNTING_REPORT_3 = /*$$(*/ "Move lines recovered" /*)*/;
static final String ACCOUNTING_REPORT_4 = /*$$(*/ "You must select an export type" /*)*/;
static final String ACCOUNTING_REPORT_6 = /*$$(*/ "Moves exported" /*)*/;
static final String ACCOUNTING_REPORT_UNKNOWN_ACCOUNTING_REPORT_TYPE = /*$$(*/
"Unknown accounting report type: %d" /*)*/;
static final String ACCOUNTING_REPORT_ANALYTIC_REPORT = /*$$(*/
"%s : Error : You must configure an analytic report sequence for the company %s" /*)*/;
/** Move line service */
static final String MOVE_LINE_1 = /*$$(*/ "Partner is missing on the invoice %s" /*)*/;
static final String MOVE_LINE_2 = /*$$(*/ "Partner account missing on the invoice %s" /*)*/;
static final String MOVE_LINE_4 = /*$$(*/
"Account missing on configuration for line : %s (company : %s)" /*)*/;
static final String MOVE_LINE_5 = /*$$(*/
"Analytic account %s associated to sales account for the product %s is not configured : (company : %s)" /*)*/;
static final String MOVE_LINE_6 = /*$$(*/
"Account missing on the tax line : %s (company : %s)" /*)*/;
static final String ANALYTIC_DISTRIBUTION_MISSING = /*$$(*/
"Analytic distribution is missing on configuration for line : %s (company : %s)" /*)*/;
static final String MOVE_LINE_7 = /*$$(*/
"The accounting move line on the account %s can't have an amount equals to zero" /*)*/;
/** Move service */
static final String MOVE_1 = /*$$(*/ "Invoice type missing on invoice %s" /*)*/;
static final String MOVE_2 = /*$$(*/ "You must select a journal for the move %s" /*)*/;
static final String MOVE_3 = /*$$(*/ "You must select a company for the move %s" /*)*/;
static final String MOVE_4 = /*$$(*/ "You must select a period for the move %s" /*)*/;
static final String MOVE_5 = /*$$(*/
"Journal %s does not have any account move sequence configured" /*)*/;
static final String MOVE_6 = /*$$(*/ "Move account sens %s can't be determined" /*)*/;
static final String MOVE_7 = /*$$(*/
"Account move %s has a total debit different than total credit : %s <> %s" /*)*/;
static final String MOVE_8 = /*$$(*/ "The move %s cannot be empty" /*)*/;
static final String MOVE_9 = /*$$(*/
"Tax is mandatory for the account %s on the move line %s" /*)*/;
static final String MOVE_10 = /*$$(*/
"Analytic distribution template is mandatory for the account %s on the move line %s." /*)*/;
static final String MOVE_11 = /*$$(*/
"An analytic distribution is set in move line %s but the account used do not allow analytic distribution" /*)*/;
static final String MOVE_VALIDATION_FISCAL_PERIOD_CLOSED = /*$$(*/
"Accounting move can not be validated because its fiscal period is closed." /*)*/;
/** Payment schedule export service */
static final String PAYMENT_SCHEDULE_1 = /*$$(*/
"%s : You must configure a RIB for payment timetable %s" /*)*/;
static final String PAYMENT_SCHEDULE_2 = /*$$(*/
"%s : You must configure a RIB for the partner %s" /*)*/;
static final String PAYMENT_SCHEDULE_3 = /*$$(*/
"%s : Error : You must configure a direct debit date for the %s batch configuration" /*)*/;
static final String PAYMENT_SCHEDULE_4 = /*$$(*/
"%s : You must configure a direct debit reject sequence\n for the company %s for the journal %s" /*)*/;
static final String PAYMENT_SCHEDULE_5 = /*$$(*/
"You must configure a timetable sequence for the company %s" /*)*/;
static final String PAYMENT_SCHEDULE_6 = /*$$(*/
"%s : Error : You must, at first, create timetable lines for the timetable %s" /*)*/;
static final String PAYMENT_SCHEDULE_LINE_AMOUNT_MISMATCH = /*$$(*/
"The sum of line amounts (%s) must match the amount of the payment schedule (%s)." /*)*/;
/** Reconcile service */
static final String RECONCILE_1 = /*$$(*/
"%s : Reconciliation : You must fill concerned moves lines." /*)*/;
static final String RECONCILE_2 = /*$$(*/
"%s : Reconciliation : Move line accounts are not compatible." /*)*/;
static final String RECONCILE_3 = /*$$(*/
"(Debit %s account %s amount %s - Credit %s account %s amount %s)" /*)*/;
static final String RECONCILE_4 = /*$$(*/
"%s : Reconciliation %s: Reconciliated amount must be different than zero. (Debit %s account %s - Credit %s account %s)" /*)*/;
static final String RECONCILE_5 = /*$$(*/
"%s : Reconciliation %s: Reconciliated amount (%s) must be lower or equal to remaining amount to reconciliate from moves lines." /*)*/;
static final String RECONCILE_6 = /*$$(*/
"%s : Error : You must configure a reconciliation sequence for the company %s" /*)*/;
static final String RECONCILE_7 = /*$$(*/
"Reconciliation : Selected moves lines must concern the same company. Reconcile : %s company \n Debit move line : %s company \n Credit move line : %s company" /*)*/;
static final String RECONCILE_CAN_NOT_BE_REMOVE = /*$$(*/
"The reconcile %s cannot be removed, please select draft reconcile(s)" /*)*/;
/** Reimbursement service and controller */
static final String REIMBURSEMENT_1 = /*$$(*/
"%s : You must configure a reimbursement sequence for the company %s" /*)*/;
static final String REIMBURSEMENT_2 = /*$$(*/
"Export reimbursement folder (SEPA format) has not been configured for the company %s." /*)*/;
static final String REIMBURSEMENT_3 = /*$$(*/
"No reimbursement found for the ref %s and the company %s." /*)*/;
static final String REIMBURSEMENT_4 = /*$$(*/ "You must configure a RIB." /*)*/;
/** Year service */
static final String YEAR_1 = /*$$(*/
"%s : You must configure a company for the fiscal year %s" /*)*/;
/** Batch Account customer */
static final String BATCH_ACCOUNT_1 = /*$$(*/ "Accounting situation %s" /*)*/;
static final String BATCH_ACCOUNT_2 = /*$$(*/
"Contact's account balances determination's reporting :" /*)*/;
static final String BATCH_ACCOUNT_3 = /*$$(*/ "* %s Account(s) situation(s) treated" /*)*/;
static final String BATCH_ACCOUNT_4 = /*$$(*/
"Account balances of %s accounting situation has not been updated, you must run the contact account batch update." /*)*/;
static final String BATCH_ACCOUNT_5 = /*$$(*/
"Account balances from all accounts situations (%s) has been updated." /*)*/;
/** Batch doubtful customer */
static final String BATCH_DOUBTFUL_1 = /*$$(*/
"Doubtful account's determination's reporting" /*)*/;
static final String BATCH_DOUBTFUL_2 = /*$$(*/ "* %s Invoice(s) treated" /*)*/;
/** Batch move line export */
static final String BATCH_MOVELINE_EXPORT_1 = /*$$(*/
"%s : Error : You must configure a company for the batch configurator %s" /*)*/;
static final String BATCH_MOVELINE_EXPORT_2 = /*$$(*/
"%s : Error : You must configure a due date for the batch configurator %s" /*)*/;
static final String BATCH_MOVELINE_EXPORT_3 = /*$$(*/
"%s : Error : You must configure an export type for the batch configurator %s" /*)*/;
static final String BATCH_MOVELINE_EXPORT_4 = /*$$(*/ "Moves export batch's reporting :" /*)*/;
static final String BATCH_MOVELINE_EXPORT_5 = /*$$(*/ "Moves Lines (Moves) exported" /*)*/;
/** Batch payment schedule import/export */
static final String BATCH_PAYMENT_SCHEDULE_1 = /*$$(*/
"Unknowned data type for the treatment %s" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_2 = /*$$(*/ "Direct debit's export batch %s" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_3 = /*$$(*/ "Due date's direct debit %s" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_4 = /*$$(*/
"Export reporting to invoices direct debits :" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_5 = /*$$(*/ "Invoice(s) direct debit(s) treated" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_6 = /*$$(*/
"Export reporting to monthly direct debits :" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_7 = /*$$(*/ "Monthly direct debit(s) treated" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_8 = /*$$(*/
"%s : No timetable nor invoice found for the direct debit number : %s" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_9 = /*$$(*/ "Reject %s" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_10 = /*$$(*/
"Timetable's reject move's creation %s" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_11 = /*$$(*/
"Invoice's reject move's creation %s" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_12 = /*$$(*/
"Reporting to direct debit reject's import :" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_13 = /*$$(*/ "Direct debit(s) rejected" /*)*/;
/** Batch reimbursement export/import */
static final String BATCH_REIMBURSEMENT_1 = /*$$(*/
"Bug(Anomaly) generated during SEPA export - Batch %s" /*)*/;
static final String BATCH_REIMBURSEMENT_2 = /*$$(*/ "Reporting to reimbursement creation :" /*)*/;
static final String BATCH_REIMBURSEMENT_3 = /*$$(*/ "Reimbursement(s) created" /*)*/;
static final String BATCH_REIMBURSEMENT_4 = /*$$(*/ "Reporting to reimbursement's export :" /*)*/;
static final String BATCH_REIMBURSEMENT_5 = /*$$(*/ "Reimbursement(s) treated" /*)*/;
static final String BATCH_REIMBURSEMENT_6 = /*$$(*/ "Reimbursement's import's batch %s" /*)*/;
static final String BATCH_REIMBURSEMENT_7 = /*$$(*/ "Reimbursement reject %s" /*)*/;
static final String BATCH_REIMBURSEMENT_8 = /*$$(*/
"Reporting to reimbursement reject's import :" /*)*/;
static final String BATCH_REIMBURSEMENT_9 = /*$$(*/ "Reimbursement(s) rejected" /*)*/;
static final String BATCH_REIMBURSEMENT_10 = /*$$(*/ "Total Amount" /*)*/;
/** Batch debt recovery */
static final String BATCH_DEBT_RECOVERY_1 = /*$$(*/ "Debt recovery's reporting :" /*)*/;
static final String BATCH_DEBT_RECOVERY_2 = /*$$(*/ "Partner(s) treated" /*)*/;
/** Batch credit transfer */
static final String BATCH_CREDIT_TRANSFER_REPORT_TITLE = /*$$(*/
"Report for credit transfer batch:" /*)*/;
static final String BATCH_CREDIT_TRANSFER_INVOICE_DONE_SINGULAR = /*$$(*/
"%d invoice treated successfully," /*)*/;
static final String BATCH_CREDIT_TRANSFER_INVOICE_DONE_PLURAL = /*$$(*/
"%d invoices treated successfully," /*)*/;
static final String BATCH_CREDIT_TRANSFER_REIMBURSEMENT_DONE_SINGULAR = /*$$(*/
"%d reimbursement created successfully," /*)*/;
static final String BATCH_CREDIT_TRANSFER_REIMBURSEMENT_DONE_PLURAL = /*$$(*/
"%d reimbursements created successfully," /*)*/;
static final String BATCH_CREDIT_TRANSFER_ANOMALY_SINGULAR = /*$$(*/ "%d anomaly." /*)*/;
static final String BATCH_CREDIT_TRANSFER_ANOMALY_PLURAL = /*$$(*/ "%d anomalies." /*)*/;
/** Batch strategy */
static final String BATCH_STRATEGY_1 = /*$$(*/
"%s : You must configure a RIB for batch's configurator %s" /*)*/;
/** Batch realize fixed asset lines */
static final String BATCH_REALIZED_FIXED_ASSET_LINE = /*$$(*/ "Realized fixed asset lines" /*)*/;
/** Batch close / open the year account */
static final String BATCH_CLOSE_OPEN_ANNUAL_ACCOUNT_REPORT_TITLE = /*$$(*/
"Report for close/open annual accounts batch:" /*)*/;
static final String BATCH_CLOSE_OPEN_ANNUAL_ACCOUNT_DONE_SINGULAR = /*$$(*/
"%d account treated successfully," /*)*/;
static final String BATCH_CLOSE_OPEN_ANNUAL_ACCOUNT_DONE_PLURAL = /*$$(*/
"%d accounts treated successfully," /*)*/;
/** Cfonb export service */
static final String CFONB_EXPORT_1 = /*$$(*/
"You must configure a RIB for the reimbursement" /*)*/;
static final String CFONB_EXPORT_2 = /*$$(*/
"%s : Error detected during CFONB file's writing : %s" /*)*/;
static final String CFONB_EXPORT_3 = /*$$(*/
"%s : You must configure a Sort Code for the RIB %s of third-payer %s" /*)*/;
static final String CFONB_EXPORT_4 = /*$$(*/
"%s : You must configure a number's account for the RIB %s of third-payer %s" /*)*/;
static final String CFONB_EXPORT_5 = /*$$(*/
"%s : You must configure a Bank Code for the RIB %s of third-payer %s" /*)*/;
static final String CFONB_EXPORT_6 = /*$$(*/
"%s : You must configure a Bank Address for the RIB %s of third-payer %s" /*)*/;
/** Cfonb import service */
static final String CFONB_IMPORT_1 = /*$$(*/
"%s : You must configure a reject/return reason's code's list relating to Card cashing, Direct debit and TIP in general configuration" /*)*/;
static final String CFONB_IMPORT_2 = /*$$(*/
"%s : A header record is missing in the file %s" /*)*/;
static final String CFONB_IMPORT_3 = /*$$(*/
"%s : One or several detail records are missing in the file %s" /*)*/;
static final String CFONB_IMPORT_4 = /*$$(*/ "%s : A record is missing in the file %s" /*)*/;
static final String CFONB_IMPORT_5 = /*$$(*/
"%s : The total amount for the following record isn't correct (file %s) :\n %s" /*)*/;
static final String CFONB_IMPORT_6 = /*$$(*/
"%s : No payment mode found for the code %s and the company %s" /*)*/;
/** Cfonb tool service */
static final String CFONB_TOOL_NB_OF_CHAR_PER_LINE = /*$$(*/
"The record is not %s characters" /*)*/;
static final String CFONB_TOOL_EMPTY_ZONE = /*$$(*/ "Zone %s is empty" /*)*/;
static final String CFONB_TOOL_DIGITAL_ZONE_NOT_CORRECT = /*$$(*/
"Zone %s (%s) must be of the numeric type" /*)*/;
static final String CFONB_TOOL_1 = /*$$(*/
"%s : Anomaly detected (value isn't numeric : %s) for sender" /*)*/;
static final String CFONB_TOOL_2 = /*$$(*/
"%s : Anomaly detected (value isn't numeric : %s) for the receiver" /*)*/;
static final String CFONB_TOOL_3 = /*$$(*/
"%s : Anomaly detected (value isn't numeric : %s) for the total" /*)*/;
static final String CFONB_TOOL_4 = /*$$(*/
"%s : Anomaly detected (the record doesn't have %s characters : %s) for the record %s, company %s" /*)*/;
static final String COMPANY_CURRENCY = /*$$(*/
"%s : Please, configure a currency for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_1 = /*$$(*/
"%s : You must configure account's informations for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_2 = /*$$(*/
"%s : You must configure a CFONB format reimbursement's export's folder for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_3 = /*$$(*/
"%s : You must configure a CFONB format direct debit's export's folder for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_4 = /*$$(*/
"%s : You must configure a TIP and cheque TIP payment's import path for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_5 = /*$$(*/
"%s : You must configure a TIP and cheque TIP temporary import path for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_6 = /*$$(*/
"%s : You must configure a TIP and cheque TIP payment rejects path for the import file for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_7 = /*$$(*/
"%s : You must configure a TIP and cheque TIP temporary path for the payment reject's file for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_8 = /*$$(*/
"%s : You must configure a path for the reject's file for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_9 = /*$$(*/
"%s : You must configure a path for the temporary reject's file for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_10 = /*$$(*/
"%s : You must configure a path for the reimbursements rejects import's file for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_11 = /*$$(*/
"%s : You must configure a path for the reimbursement rejects import's temporary file for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_12 = /*$$(*/
"%s : You must configure a rejects journal for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_13 = /*$$(*/
"%s : You must configure an irrevocable journal for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_14 = /*$$(*/
"%s : You must configure a Supplier purchase journal for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_15 = /*$$(*/
"%s : You must configure a Supplier credit note journal for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_16 = /*$$(*/
"%s : You must configure a Sales journal for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_17 = /*$$(*/
"%s : You must configure a Customer credit note journal for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_18 = /*$$(*/
"%s : You must configure a Misc. Operation journal for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_19 = /*$$(*/
"%s : You must configure a Reimbursement journal for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_20 = /*$$(*/
"%s : You must configure a Sales journal type for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_21 = /*$$(*/
"%s : You must configure a Credit note journal type for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_22 = /*$$(*/
"%s : You must configure a Cash journal type for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_23 = /*$$(*/
"%s : You must configure a Purchase journal type for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_24 = /*$$(*/
"%s : You must configure an irrevocable doubtful account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_25 = /*$$(*/
"%s : You must configure a customer account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_26 = /*$$(*/
"%s : You must configure a supplier account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_27 = /*$$(*/
"%s : You must configure a cash difference account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_28 = /*$$(*/
"%s : You must configure a reimbursement account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_29 = /*$$(*/
"%s : You must configure a doubtful customer account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_30 = /*$$(*/
"%s : You must configure a direct debit payment mode for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_31 = /*$$(*/
"%s : You must configure a payment mode after reject for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_32 = /*$$(*/
"%s : You must configure a shift to irrecoverable's reason for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_34 = /*$$(*/
"%s : You must configure a reject import letter template for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_35 = /*$$(*/
"%s : You must configure a shifting reason (debt more than six months) for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_36 = /*$$(*/
"%s : You must configure a shifting reason (debt more than three months) for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_37 = /*$$(*/
"%s : You must configure a debt recovery tab for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_38 = /*$$(*/
"%s : You must configure an advance payment account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_39 = /*$$(*/
"%s : You must configure a file name for the export of move file for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_40 = /*$$(*/
"%s : You must configure an employee account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_41 = /*$$(*/
"%s : You must configure a factor credit account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_42 = /*$$(*/
"%s : You must configure a factor debit account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_43 = /*$$(*/
"%s : You must configure a year opening account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_44 = /*$$(*/
"%s : You must configure a year closure account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_45 = /*$$(*/
"%s : You must configure a reported balance journal for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_SEQUENCE_1 = /*$$(*/
"%s : Please, configure a sequence for the customer invoices and the company %s" /*)*/;
static final String ACCOUNT_CONFIG_SEQUENCE_2 = /*$$(*/
"%s : Please, configure a sequence for the customer refunds and the company %s" /*)*/;
static final String ACCOUNT_CONFIG_SEQUENCE_3 = /*$$(*/
"%s : Please, configure a sequence for the supplier invoices and the company %s" /*)*/;
static final String ACCOUNT_CONFIG_SEQUENCE_4 = /*$$(*/
"%s : Please, configure a sequence for the supplier refunds and the company %s" /*)*/;
/** Cfonb config service */
static final String CFONB_CONFIG_1 = /*$$(*/
"%s : You must configure CFONB for the company %s" /*)*/;
static final String CFONB_CONFIG_2 = /*$$(*/
"%s : You must configure a CFONB sender code register for the company %s" /*)*/;
static final String CFONB_CONFIG_3 = /*$$(*/
"%s : You must configure a CFONB sender's number for the company %s" /*)*/;
static final String CFONB_CONFIG_4 = /*$$(*/
"%s : You must configure a CFONB sender's name/corporate name for the company %s" /*)*/;
static final String CFONB_CONFIG_5 = /*$$(*/
"%s : You must configure a CFONB receiver code register for the company %s" /*)*/;
static final String CFONB_CONFIG_6 = /*$$(*/
"%s : You must configure a CFONB total code register for the company %s" /*)*/;
static final String CFONB_CONFIG_7 = /*$$(*/
"%s : You must configure a CFONB internet payment code for the company %s" /*)*/;
static final String CFONB_CONFIG_8 = /*$$(*/
"%s : You must configure a CFONB direct debit code for the company %s" /*)*/;
static final String CFONB_CONFIG_9 = /*$$(*/
"%s : You must configure a CFONB header code register for the company %s" /*)*/;
static final String CFONB_CONFIG_10 = /*$$(*/
"%s : You must configure a CFONB detail code register for the company %s" /*)*/;
static final String CFONB_CONFIG_11 = /*$$(*/
"%s : You must configure a CFONB code register end for the company %s" /*)*/;
static final String CFONB_CONFIG_12 = /*$$(*/
"%s : You must configure a CFONB rejected direct debit code for the company %s" /*)*/;
static final String CFONB_CONFIG_13 = /*$$(*/
"%s : You must configure a CFONB unpaid direct debit code fir the company %s" /*)*/;
static final String CFONB_CONFIG_14 = /*$$(*/
"%s : You must configure a CFONB unpaid TIP code for the company %s" /*)*/;
static final String CFONB_CONFIG_15 = /*$$(*/
"%s : You must configure a CFONB TIP and cheque TIP code for the company %s" /*)*/;
static final String CFONB_CONFIG_16 = /*$$(*/
"%s : You must configure a CFONB TIP code for the company %s" /*)*/;
/** Payer quality service */
static final String PAYER_QUALITY_1 = /*$$(*/
"%s : Error : You must configure a weight table in general configuration" /*)*/;
/** Debt recovery action service */
static final String DEBT_RECOVERY_ACTION_1 = /*$$(*/ "Debt recovery method missing." /*)*/;
static final String DEBT_RECOVERY_ACTION_2 = /*$$(*/ "Debt recovery line missing." /*)*/;
static final String DEBT_RECOVERY_ACTION_3 = /*$$(*/
"%s : Letter template missing for debt recovery matrix %s (Partner %s, Level %s)." /*)*/;
static final String DEBT_RECOVERY_ACTION_4 = /*$$(*/
"Email is not sent. Please check email account configuration." /*)*/;
/** Debt recovery service */
static final String DEBT_RECOVERY_1 = /*$$(*/ "There's no accounting situation." /*)*/;
static final String DEBT_RECOVERY_2 = /*$$(*/ "Reference date undefined." /*)*/;
static final String DEBT_RECOVERY_3 = /*$$(*/
"Debt recovery method missing for the configuration." /*)*/;
static final String DEBT_RECOVERY_4 = /*$$(*/ "Debt recovery level waiting for approval." /*)*/;
static final String DEBT_RECOVERY_DEBT_RECOVERY_LEVEL_NOT_FOUND = /*$$(*/
"Debt recovery method line not found" /*)*/;
/** Debt recovery session service */
static final String DEBT_RECOVERY_SESSION_1 = /*$$(*/ "Debt recovery method line missing." /*)*/;
/** Invoice batch service */
static final String INVOICE_BATCH_1 = /*$$(*/ "State %s unknown for treatment %s" /*)*/;
/** Invoice generator */
static final String INVOICE_GENERATOR_1 = /*$$(*/ "%s : Invoice's type is not filled %s" /*)*/;
static final String INVOICE_GENERATOR_2 = /*$$(*/ "%s : There's no partner selected" /*)*/;
static final String INVOICE_GENERATOR_3 = /*$$(*/ "%s : Payment condition missing" /*)*/;
static final String INVOICE_GENERATOR_4 = /*$$(*/ "%s : Payment mode missing" /*)*/;
static final String INVOICE_GENERATOR_5 = /*$$(*/ "%s : Invoicing address missing" /*)*/;
static final String INVOICE_GENERATOR_6 = /*$$(*/ "%s : Currency missing" /*)*/;
/** Merge Invoice */
public static final String INVOICE_MERGE_ERROR_CURRENCY = /*$$(*/
"The currency is required and must be the same for all invoices" /*)*/;
public static final String INVOICE_MERGE_ERROR_PARTNER = /*$$(*/
"The partner is required and must be the same for all invoices" /*)*/;
public static final String INVOICE_MERGE_ERROR_COMPANY = /*$$(*/
"The company is required and must be the same for all invoices" /*)*/;
public static final String INVOICE_MERGE_ERROR_SALEORDER = /*$$(*/
"The sale order must be the same for all invoices" /*)*/;
public static final String INVOICE_MERGE_ERROR_PROJECT = /*$$(*/
"The project must be the same for all invoices" /*)*/;
public static final String INVOICE_MASS_PAYMENT_ERROR_PFP_LITIGATION = /*$$(*/
"Their is at least one invoice selected that it is not validated to pay" /*)*/;
/** Invoice line generator */
static final String INVOICE_LINE_GENERATOR_1 = /*$$(*/
"You must select a currency for partner %s (%s)" /*)*/;
static final String INVOICE_LINE_GENERATOR_2 = /*$$(*/
"You must select a currency for company %s" /*)*/;
public static final String INVOICE_LINE_ERROR_FIXED_ASSET_CATEGORY = /*$$(*/
"Fixed asset category is missing on invoice line for product %s" /*)*/;
/** Batch validation */
static final String BATCH_VALIDATION_1 = /*$$(*/ "Invoice validation's reporting :" /*)*/;
static final String BATCH_VALIDATION_2 = /*$$(*/ "Invoice(s) validated" /*)*/;
/** Batch ventilation */
static final String BATCH_VENTILATION_1 = /*$$(*/ "Invoice ventilation's reporting :" /*)*/;
static final String BATCH_VENTILATION_2 = /*$$(*/ "Invoice(s) ventilated" /*)*/;
/** Refund invoice */
static final String REFUND_INVOICE_1 = /*$$(*/
"%s : Payment mode must be filled either in the partner or in the company configuration." /*)*/;
/** Validate state */
static final String INVOICE_VALIDATE_1 = /*$$(*/
"The payment mode is not in adequacy with the invoice type" /*)*/;
static final String INVOICE_VALIDATE_BLOCKING = /*$$(*/
"The partner is blocked for invoicing." /*)*/;
/** Cancel state */
static final String MOVE_CANCEL_1 = /*$$(*/
"Move should be unreconcile before to cancel the invoice" /*)*/;
static final String MOVE_CANCEL_2 = /*$$(*/
"Move is ventilated on a closed period, and can't be canceled" /*)*/;
static final String MOVE_CANCEL_3 = /*$$(*/
"So many accounting operations are used on this move, so move can't be canceled" /*)*/;
static final String INVOICE_CANCEL_1 = /*$$(*/
"Invoice is passed in doubfult debit, and can't be canceled" /*)*/;
static final String INVOICE_PAYMENT_CANCEL = /*$$(*/
"The bank order linked to this invoice payment has already been carried out/rejected, and thus can't be canceled" /*)*/;
/** Ventilate state */
static final String VENTILATE_STATE_1 = /*$$(*/
"Invoice's or credit note's date can't be previous last invoice ventilated's date" /*)*/;
static final String VENTILATE_STATE_2 = /*$$(*/
"Invoice's or credit note's date can't be previous last invoice ventilated on month's date" /*)*/;
static final String VENTILATE_STATE_3 = /*$$(*/
"Invoice's or credit note's date can't be previous last invoice ventilated on year's date" /*)*/;
static final String VENTILATE_STATE_4 = /*$$(*/
"Company %s does not have any invoice's nor credit note's sequence" /*)*/;
static final String VENTILATE_STATE_5 = /*$$(*/
"The partner account can not be determined. Please set up the partner account on the invoice or configure the partner's accounting situation." /*)*/;
static final String VENTILATE_STATE_6 = /*$$(*/
"The account of a product could not be determined or is not filled. Please fill the missing account on invoice line %s" /*)*/;
static final String VENTILATE_STATE_7 = /*$$(*/
"An analytic distribution is set in product but the account used do not allow analytic distribution" /*)*/;
static final String VENTILATE_STATE_FUTURE_DATE = /*$$(*/
"Invoice date can't be in the future." /*)*/;
static final String VENTILATE_STATE_FUTURE_ORIGIN_DATE = /*$$(*/
"Invoice date of origin can't be in the future." /*)*/;
static final String VENTILATE_STATE_MISSING_ORIGIN_DATE = /*$$(*/
"Origin date is missing on the invoice" /*)*/;
/** Workflow ventilation */
String AMOUNT_ADVANCE_PAYMENTS_TOO_HIGH = /*$$(*/
"Sum of advance payments amounts is higher than the total of this invoice." /*)*/;
static final String PAYMENT_AMOUNT_EXCEEDING = /*$$(*/
"%s : Caution - You can't pay for an amount higher than selected invoices" /*)*/;
/** Payment mode service */
static final String PAYMENT_MODE_1 = /*$$(*/ "Associated account not configured" /*)*/;
static final String PAYMENT_MODE_2 = /*$$(*/
"%s : Error : You must configure a sequence for the company %s and a payment mode %s" /*)*/;
static final String PAYMENT_MODE_3 = /*$$(*/
"%s : Error : You must configure a journal for the company %s and a payment mode %s" /*)*/;
/** Payment voucher control service */
static final String PAYMENT_VOUCHER_CONTROL_PAID_AMOUNT = /*$$(*/
"%s : Payment voucher n° %s, the paid amount should be positive" /*)*/;
static final String PAYMENT_VOUCHER_CONTROL_1 = /*$$(*/
"%s : Caution, payment entry nb %s, total line's amount imputed is higher than customer's amount paid." /*)*/;
static final String PAYMENT_VOUCHER_CONTROL_2 = /*$$(*/ "%s : There's no line to pay." /*)*/;
static final String PAYMENT_VOUCHER_CONTROL_3 = /*$$(*/
"%s : You must add a journal and a treasury account into payment mode." /*)*/;
/** Payment voucher load service */
static final String PAYMENT_VOUCHER_LOAD_1 = /*$$(*/ "%s : You must add an amount paid." /*)*/;
/** Payment voucher sequence service */
static final String PAYMENT_VOUCHER_SEQUENCE_1 = /*$$(*/
"%s : You must configure a receipt number (Payment entry) for the company %s" /*)*/;
/** Payment voucher tool service */
static final String PAYMENT_VOUCHER_TOOL_1 = /*$$(*/
"Payment entry's type missing from payment entry %s" /*)*/;
/** Payment schedule line service */
String PAYMENT_SCHEDULE_LINE_NO_DIRECT_DEBIT_PAYMENT_MODE = /*$$(*/
"Missing direct debit payment mode in the company's account configuration" /*)*/;
/** Account chart controller */
static final String ACCOUNT_CHART_1 = /*$$(*/
"The chart of account has been loaded successfully" /*)*/;
static final String ACCOUNT_CHART_2 = /*$$(*/
"Error in account chart import please check the log" /*)*/;
static final String ACCOUNT_CHART_3 = /*$$(*/
"A chart or chart structure of accounts already exists, please delete the hierarchy between accounts in order to import a new chart." /*)*/;
/** Address controller */
static final String ADDRESS_1 = /*$$(*/ "Sales map" /*)*/;
static final String ADDRESS_2 = /*$$(*/ "Not implemented for OSM" /*)*/;
/** Invoice controller */
static final String INVOICE_1 = /*$$(*/ "Invoice canceled" /*)*/;
static final String INVOICE_2 = /*$$(*/ "Credit note created" /*)*/;
static final String INVOICE_3 = /*$$(*/ "Please select the invoice(s) to print." /*)*/;
static final String INVOICE_4 = /*$$(*/ "Refunds from invoice %s" /*)*/;
static final String INVOICE_NO_INVOICE_TO_PAY = /*$$(*/ "No invoice to pay" /*)*/;
/** Move template controller */
static final String MOVE_TEMPLATE_1 = /*$$(*/ "Template move is not balanced" /*)*/;
static final String MOVE_TEMPLATE_2 = /*$$(*/ "Error in move generation" /*)*/;
static final String MOVE_TEMPLATE_3 = /*$$(*/ "Generated moves" /*)*/;
static final String MOVE_TEMPLATE_4 = /*$$(*/ "Please fill input lines" /*)*/;
/** Budget service */
static final String BUDGET_1 = /*$$(*/ "Too much iterations." /*)*/;
static final String USER_PARTNER = /*$$(*/ "You must create a contact for user %s" /*)*/;
/*
* Deposit slip
*/
static final String DEPOSIT_SLIP_MISSING_SEQUENCE = /*$$(*/
"Missing deposit slip sequence for company %s" /*)*/;
static final String DEPOSIT_SLIP_CANNOT_DELETE = /*$$(*/
"You cannot delete this deposit slip." /*)*/;
static final String DEPOSIT_SLIP_ALREADY_PUBLISHED = /*$$(*/
"The deposit slip has already been published." /*)*/;
static final String DEPOSIT_SLIP_UNSUPPORTED_PAYMENT_MODE_TYPE = /*$$(*/
"Unsupported payment mode type" /*)*/;
/*
* Partner
*/
String PARTNER_BANK_DETAILS_MISSING = /*$$(*/ "Bank details are missing for partner %s." /*)*/;
/*
* Invoice printing
*/
String INVOICE_MISSING_PRINTING_SETTINGS = /*$$(*/
"Please fill printing settings on invoice %s." /*)*/;
String INVOICES_MISSING_PRINTING_SETTINGS = /*$$(*/
"Please fill printing settings on following invoices: %s" /*)*/;
String INVOICE_PRINTING_IO_ERROR = /*$$(*/ "Error on uploading printed invoice:" /*)*/;
/*
* Reconcile Group
*/
String RECONCILE_GROUP_VALIDATION_NO_LINES = /*$$(*/
"The reconcile group cannot be validated since there is no lines." /*)*/;
String RECONCILE_GROUP_NO_TEMP_SEQUENCE = /*$$(*/
"There is no configured sequence for temporary reconcile group" /*)*/;
String RECONCILE_GROUP_NO_FINAL_SEQUENCE = /*$$(*/
"There is no configured sequence for final reconcile group" /*)*/;
/*
* Subrogation Release
*/
static final String SUBROGATION_RELEASE_MISSING_SEQUENCE = /*$$(*/
"Missing subrogation release sequence for company %s" /*)*/;
/** MoveLine */
static final String NO_MOVE_LINE_SELECTED = /*$$(*/ "No Lines selected" /*)*/;
/** User */
static final String USER_PFP_VALIDATOR_COMPANY_SET_NOT_EQUAL = /*$$(*/
"%s has not exaclty the same internal companies as %s." /*)*/;
static final String USER_PFP_VALIDATOR_UPDATED = /*$$(*/
"Pfp validator changed successfully" /*)*/;
static final String USER_PFP_VALIDATOR_NO_RELATED_ACCOUNTING_SITUATION = /*$$(*/
"No Accounting Situation related to %s." /*)*/;
/* Check refunds */
String INVOICE_NOT_IMPUTED_CLIENT_REFUNDS = /*$$(*/
"Note: there are existing not imputed client refunds."; /*)*/
String INVOICE_NOT_IMPUTED_SUPPLIER_REFUNDS = /*$$(*/
"Note: there are existing not imputed supplier refunds."; /*)*/
public static final String FIXED_ASSET_DISPOSAL_DATE_ERROR_1 = /*$$(*/
"Disposal date must be after the date of the last depreciation." /*)*/;
public static final String FIXED_ASSET_DISPOSAL_DATE_ERROR_2 = /*$$(*/
"Disposal date shouldn't be after the next planned depreciation date. Please realize all depreciations that happened before the disposal." /*)*/;
/* MOVE REVERSE*/
static final String REVERSE_DATE_SELECT_UNKNOW_TYPE = /*$$(*/
"There is no reverse date select value of value %d" /*)*/;
/*Check not lettered advance move lines*/
public static final String INVOICE_NOT_LETTERED_SUPPLIER_ADVANCE_MOVE_LINES = /*$$(*/
"There is at least one advance payment or payment that can be imputed to this invoice." /*)*/;
static final String CLOSE_NO_REPORTED_BALANCE_DATE = /*$$(*/
"Please set a reported balance date on fiscal year" /*)*/;
String CASH_INVENTORY_MISSING_SEQUENCE = /*$$(*/
"There is no configured sequence for cash inventory" /*)*/;
}

View File

@ -0,0 +1,262 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.module;
import com.axelor.app.AxelorModule;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.repo.AccountAccountRepository;
import com.axelor.apps.account.db.repo.AccountRepository;
import com.axelor.apps.account.db.repo.AccountingBatchAccountRepository;
import com.axelor.apps.account.db.repo.AccountingBatchRepository;
import com.axelor.apps.account.db.repo.AccountingReportManagementRepository;
import com.axelor.apps.account.db.repo.AccountingReportRepository;
import com.axelor.apps.account.db.repo.AnalyticMoveLineMngtRepository;
import com.axelor.apps.account.db.repo.AnalyticMoveLineRepository;
import com.axelor.apps.account.db.repo.DepositSlipAccountRepository;
import com.axelor.apps.account.db.repo.DepositSlipRepository;
import com.axelor.apps.account.db.repo.FixedAssetManagementRepository;
import com.axelor.apps.account.db.repo.FixedAssetRepository;
import com.axelor.apps.account.db.repo.InvoiceBatchAccountRepository;
import com.axelor.apps.account.db.repo.InvoiceBatchRepository;
import com.axelor.apps.account.db.repo.InvoiceManagementRepository;
import com.axelor.apps.account.db.repo.InvoicePaymentManagementRepository;
import com.axelor.apps.account.db.repo.InvoicePaymentRepository;
import com.axelor.apps.account.db.repo.InvoiceRepository;
import com.axelor.apps.account.db.repo.JournalManagementRepository;
import com.axelor.apps.account.db.repo.JournalRepository;
import com.axelor.apps.account.db.repo.MoveLineManagementRepository;
import com.axelor.apps.account.db.repo.MoveLineRepository;
import com.axelor.apps.account.db.repo.MoveManagementRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.db.repo.PartnerAccountRepository;
import com.axelor.apps.account.db.repo.PaymentVoucherManagementRepository;
import com.axelor.apps.account.db.repo.PaymentVoucherRepository;
import com.axelor.apps.account.db.repo.ReconcileGroupAccountRepository;
import com.axelor.apps.account.db.repo.ReconcileGroupRepository;
import com.axelor.apps.account.db.repo.ReconcileManagementRepository;
import com.axelor.apps.account.db.repo.ReconcileRepository;
import com.axelor.apps.account.db.repo.SubrogationReleaseManagementRepository;
import com.axelor.apps.account.db.repo.SubrogationReleaseRepository;
import com.axelor.apps.account.service.AccountManagementAccountService;
import com.axelor.apps.account.service.AccountManagementServiceAccountImpl;
import com.axelor.apps.account.service.AccountingCloseAnnualService;
import com.axelor.apps.account.service.AccountingCloseAnnualServiceImpl;
import com.axelor.apps.account.service.AccountingReportService;
import com.axelor.apps.account.service.AccountingReportServiceImpl;
import com.axelor.apps.account.service.AccountingSituationService;
import com.axelor.apps.account.service.AccountingSituationServiceImpl;
import com.axelor.apps.account.service.AddressServiceAccountImpl;
import com.axelor.apps.account.service.AnalyticMoveLineService;
import com.axelor.apps.account.service.AnalyticMoveLineServiceImpl;
import com.axelor.apps.account.service.BankDetailsServiceAccountImpl;
import com.axelor.apps.account.service.DepositSlipService;
import com.axelor.apps.account.service.DepositSlipServiceImpl;
import com.axelor.apps.account.service.FiscalPositionAccountService;
import com.axelor.apps.account.service.FiscalPositionAccountServiceImpl;
import com.axelor.apps.account.service.FixedAssetLineService;
import com.axelor.apps.account.service.FixedAssetLineServiceImpl;
import com.axelor.apps.account.service.FixedAssetService;
import com.axelor.apps.account.service.FixedAssetServiceImpl;
import com.axelor.apps.account.service.MoveLineExportService;
import com.axelor.apps.account.service.MoveLineExportServiceImpl;
import com.axelor.apps.account.service.NotificationService;
import com.axelor.apps.account.service.NotificationServiceImpl;
import com.axelor.apps.account.service.PaymentScheduleLineService;
import com.axelor.apps.account.service.PaymentScheduleLineServiceImpl;
import com.axelor.apps.account.service.PaymentScheduleService;
import com.axelor.apps.account.service.PaymentScheduleServiceImpl;
import com.axelor.apps.account.service.PeriodServiceAccount;
import com.axelor.apps.account.service.PeriodServiceAccountImpl;
import com.axelor.apps.account.service.ReconcileGroupSequenceService;
import com.axelor.apps.account.service.ReconcileGroupSequenceServiceImpl;
import com.axelor.apps.account.service.ReconcileGroupService;
import com.axelor.apps.account.service.ReconcileGroupServiceImpl;
import com.axelor.apps.account.service.ReconcileService;
import com.axelor.apps.account.service.ReconcileServiceImpl;
import com.axelor.apps.account.service.SubrogationReleaseService;
import com.axelor.apps.account.service.SubrogationReleaseServiceImpl;
import com.axelor.apps.account.service.TaxPaymentMoveLineService;
import com.axelor.apps.account.service.TaxPaymentMoveLineServiceImpl;
import com.axelor.apps.account.service.TemplateMessageAccountService;
import com.axelor.apps.account.service.TemplateMessageAccountServiceImpl;
import com.axelor.apps.account.service.app.AppAccountService;
import com.axelor.apps.account.service.app.AppAccountServiceImpl;
import com.axelor.apps.account.service.extract.ExtractContextMoveService;
import com.axelor.apps.account.service.extract.ExtractContextMoveServiceImpl;
import com.axelor.apps.account.service.invoice.InvoiceLineService;
import com.axelor.apps.account.service.invoice.InvoiceLineServiceImpl;
import com.axelor.apps.account.service.invoice.InvoiceService;
import com.axelor.apps.account.service.invoice.InvoiceServiceImpl;
import com.axelor.apps.account.service.invoice.print.InvoicePrintService;
import com.axelor.apps.account.service.invoice.print.InvoicePrintServiceImpl;
import com.axelor.apps.account.service.invoice.workflow.cancel.WorkflowCancelService;
import com.axelor.apps.account.service.invoice.workflow.cancel.WorkflowCancelServiceImpl;
import com.axelor.apps.account.service.invoice.workflow.validate.WorkflowValidationService;
import com.axelor.apps.account.service.invoice.workflow.validate.WorkflowValidationServiceImpl;
import com.axelor.apps.account.service.invoice.workflow.ventilate.WorkflowVentilationService;
import com.axelor.apps.account.service.invoice.workflow.ventilate.WorkflowVentilationServiceImpl;
import com.axelor.apps.account.service.move.MoveService;
import com.axelor.apps.account.service.move.MoveServiceImpl;
import com.axelor.apps.account.service.payment.PaymentModeService;
import com.axelor.apps.account.service.payment.PaymentModeServiceImpl;
import com.axelor.apps.account.service.payment.PaymentService;
import com.axelor.apps.account.service.payment.PaymentServiceImpl;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCancelService;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCancelServiceImpl;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCreateService;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCreateServiceImpl;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentToolService;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentToolServiceImpl;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentValidateService;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentValidateServiceImpl;
import com.axelor.apps.account.service.umr.UmrNumberService;
import com.axelor.apps.account.service.umr.UmrNumberServiceImpl;
import com.axelor.apps.base.db.repo.PartnerAddressRepository;
import com.axelor.apps.base.db.repo.PartnerBaseRepository;
import com.axelor.apps.base.service.BankDetailsServiceImpl;
import com.axelor.apps.base.service.PeriodServiceImpl;
import com.axelor.apps.base.service.tax.AccountManagementServiceImpl;
import com.axelor.apps.base.service.tax.FiscalPositionServiceImpl;
import com.axelor.apps.message.service.TemplateMessageService;
import com.axelor.apps.message.service.TemplateMessageServiceImpl;
public class AccountModule extends AxelorModule {
@Override
protected void configure() {
bind(AddressServiceAccountImpl.class);
bind(AccountManagementServiceImpl.class).to(AccountManagementServiceAccountImpl.class);
bind(AccountManagementAccountService.class).to(AccountManagementServiceAccountImpl.class);
bind(FiscalPositionServiceImpl.class).to(FiscalPositionAccountServiceImpl.class);
bind(FiscalPositionAccountService.class).to(FiscalPositionAccountServiceImpl.class);
bind(TemplateMessageService.class).to(TemplateMessageServiceImpl.class);
bind(InvoiceRepository.class).to(InvoiceManagementRepository.class);
bind(MoveRepository.class).to(MoveManagementRepository.class);
bind(MoveLineRepository.class).to(MoveLineManagementRepository.class);
bind(AccountingReportRepository.class).to(AccountingReportManagementRepository.class);
bind(AccountingReportService.class).to(AccountingReportServiceImpl.class);
bind(JournalRepository.class).to(JournalManagementRepository.class);
bind(PaymentVoucherRepository.class).to(PaymentVoucherManagementRepository.class);
bind(InvoiceService.class).to(InvoiceServiceImpl.class);
bind(InvoicePrintService.class).to(InvoicePrintServiceImpl.class);
bind(PartnerBaseRepository.class).to(PartnerAccountRepository.class);
bind(AnalyticMoveLineService.class).to(AnalyticMoveLineServiceImpl.class);
bind(InvoicePaymentRepository.class).to(InvoicePaymentManagementRepository.class);
bind(InvoicePaymentValidateService.class).to(InvoicePaymentValidateServiceImpl.class);
bind(InvoicePaymentCreateService.class).to(InvoicePaymentCreateServiceImpl.class);
bind(InvoicePaymentCancelService.class).to(InvoicePaymentCancelServiceImpl.class);
bind(InvoicePaymentToolService.class).to(InvoicePaymentToolServiceImpl.class);
bind(AnalyticMoveLineRepository.class).to(AnalyticMoveLineMngtRepository.class);
bind(ReconcileService.class).to(ReconcileServiceImpl.class);
bind(ReconcileRepository.class).to(ReconcileManagementRepository.class);
bind(AppAccountService.class).to(AppAccountServiceImpl.class);
bind(AccountingSituationService.class).to(AccountingSituationServiceImpl.class);
bind(PaymentModeService.class).to(PaymentModeServiceImpl.class);
bind(BankDetailsServiceImpl.class).to(BankDetailsServiceAccountImpl.class);
bind(MoveLineExportService.class).to(MoveLineExportServiceImpl.class);
bind(AccountingBatchRepository.class).to(AccountingBatchAccountRepository.class);
bind(InvoiceBatchRepository.class).to(InvoiceBatchAccountRepository.class);
bind(AccountRepository.class).to(AccountAccountRepository.class);
bind(WorkflowVentilationService.class).to(WorkflowVentilationServiceImpl.class);
bind(WorkflowCancelService.class).to(WorkflowCancelServiceImpl.class);
bind(WorkflowValidationService.class).to(WorkflowValidationServiceImpl.class);
bind(SubrogationReleaseService.class).to(SubrogationReleaseServiceImpl.class);
bind(NotificationService.class).to(NotificationServiceImpl.class);
bind(PaymentScheduleService.class).to(PaymentScheduleServiceImpl.class);
bind(PaymentScheduleLineService.class).to(PaymentScheduleLineServiceImpl.class);
bind(DepositSlipRepository.class).to(DepositSlipAccountRepository.class);
bind(DepositSlipService.class).to(DepositSlipServiceImpl.class);
bind(InvoiceLineService.class).to(InvoiceLineServiceImpl.class);
bind(TemplateMessageAccountService.class).to(TemplateMessageAccountServiceImpl.class);
PartnerAddressRepository.modelPartnerFieldMap.put(Invoice.class.getName(), "partner");
bind(UmrNumberService.class).to(UmrNumberServiceImpl.class);
bind(ReconcileGroupSequenceService.class).to(ReconcileGroupSequenceServiceImpl.class);
bind(ReconcileGroupRepository.class).to(ReconcileGroupAccountRepository.class);
bind(ReconcileGroupService.class).to(ReconcileGroupServiceImpl.class);
bind(SubrogationReleaseRepository.class).to(SubrogationReleaseManagementRepository.class);
bind(PeriodServiceImpl.class).to(PeriodServiceAccountImpl.class);
bind(FixedAssetRepository.class).to(FixedAssetManagementRepository.class);
bind(FixedAssetService.class).to(FixedAssetServiceImpl.class);
bind(FixedAssetLineService.class).to(FixedAssetLineServiceImpl.class);
bind(ExtractContextMoveService.class).to(ExtractContextMoveServiceImpl.class);
bind(AccountingCloseAnnualService.class).to(AccountingCloseAnnualServiceImpl.class);
bind(PeriodServiceAccount.class).to(PeriodServiceAccountImpl.class);
bind(MoveService.class).to(MoveServiceImpl.class);
bind(TaxPaymentMoveLineService.class).to(TaxPaymentMoveLineServiceImpl.class);
bind(PaymentService.class).to(PaymentServiceImpl.class);
}
}

View File

@ -0,0 +1,33 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.report;
public interface IReport {
public static final String ACCOUNTING_REPORT_TYPE = "AccountingReportType%s.rptdesign";
public static final String PAYMENT_VOUCHER = "PaymentVoucher.rptdesign";
public static final String IRRECOVERABLE = "Irrecoverable.rptdesign";
public static final String INVOICE = "Invoice.rptdesign";
public static final String SALE_INVOICES_DETAILS = "SaleInvoicesDetails.rptdesign";
public static final String PURCHASE_INVOICES_DETAILS = "PurchaseInvoicesDetails.rptdesign";
public static final String ACCOUNT_MOVE = "AccountMove.rptdesign";
public static final String SUBROGATION_RELEASE = "SubrogationRelease.rptdesign";
public static final String CHEQUE_DEPOSIT_SLIP = "ChequeDepositSlip.rptdesign";
public static final String CASH_DEPOSIT_SLIP = "CashDepositSlip.rptdesign";
public static final String CASH_INVENTORY = "CashInventory%s.rptdesign";
}

View File

@ -0,0 +1,510 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.report;
public interface ITranslation {
public static final String INVOICE_ADVANCE_PAYMENTS = /*$$(*/ "Invoice.advancePayments"; /*)*/
public static final String INVOICE_DATE = /*$$(*/ "Invoice.date"; /*)*/
public static final String INVOICE_PAYMENT_TERMS = /*$$(*/ "Invoice.paymentTerms"; /*)*/
public static final String INVOICE_DUE_DATE = /*$$(*/ "Invoice.dueDate"; /*)*/
public static final String INVOICE_DOCUMENT_REF = /*$$(*/ "Invoice.documentRef"; /*)*/
public static final String INVOICE_SUPPLIER = /*$$(*/ "Invoice.supplier"; /*)*/
public static final String INVOICE_DESCRIPTION = /*$$(*/ "Invoice.description"; /*)*/
public static final String INVOICE_TAX = /*$$(*/ "Invoice.tax"; /*)*/
public static final String INVOICE_QTY_UNIT = /*$$(*/ "Invoice.qtyUnit"; /*)*/
public static final String INVOICE_UNIT_PRICE = /*$$(*/ "Invoice.unitPrice"; /*)*/
public static final String INVOICE_PRICE_EXCL_TAX = /*$$(*/ "Invoice.priceExclTax"; /*)*/
public static final String INVOICE_PRICE_INCL_TAX = /*$$(*/ "Invoice.priceInclTax"; /*)*/
public static final String INVOICE_BASE = /*$$(*/ "Invoice.base"; /*)*/
public static final String INVOICE_TAX_AMOUNT = /*$$(*/ "Invoice.taxAmount"; /*)*/
public static final String INVOICE_TOTAL_EXCL_TAX = /*$$(*/ "Invoice.totalExclTax"; /*)*/
public static final String INVOICE_TOTAL_EXCL_TAX_WITHOUT_DISCOUNT = /*$$(*/
"Invoice.totalExclTaxWithoutDiscount"; /*)*/
public static final String INVOICE_TOTAL_TAX = /*$$(*/ "Invoice.totalTax"; /*)*/
public static final String INVOICE_TOTAL_INCL_TAX = /*$$(*/ "Invoice.totalInclTax"; /*)*/
public static final String INVOICE_TOTAL_DISCOUNT = /*$$(*/ "Invoice.totalDiscount"; /*)*/
public static final String INVOICE_AFTER_DISCOUNT = /*$$(*/ "Invoice.afterDiscount"; /*)*/
public static final String INVOICE_NOTE = /*$$(*/ "Invoice.note"; /*)*/
public static final String INVOICE_CHEQUE = /*$$(*/ "Invoice.cheque"; /*)*/
public static final String INVOICE_BANK_DETAILS = /*$$(*/ "Invoice.bankDetails"; /*)*/
public static final String INVOICE_BANKING_INFO = /*$$(*/ "Invoice.bankingInfo"; /*)*/
public static final String INVOICE_CLIENT_REF = /*$$(*/ "Invoice.clientRef"; /*)*/
public static final String INVOICE_SUPPLY_REF = /*$$(*/ "Invoice.supplyRef"; /*)*/
public static final String INVOICE_PURCHASE_INVOICE_NO = /*$$(*/
"Invoice.purchaseInvoiceNo"; /*)*/
public static final String INVOICE_PURCHASE_INVOICE_ADV_PAYMENT_NO = /*$$(*/
"Invoice.purchaseInvoiceAdvPaymentNo"; /*)*/
public static final String INVOICE_PURCHASE_INVOICE_BALANCE_NO = /*$$(*/
"Invoice.purchaseInvoiceBalanceNo"; /*)*/
public static final String INVOICE_PURCHASE_REFUND_NO = /*$$(*/ "Invoice.purchaseRefundNo"; /*)*/
public static final String INVOICE_INVOICE_NO = /*$$(*/ "Invoice.invoiceNo"; /*)*/
public static final String INVOICE_INVOICE_ADV_PAYMENT_NO = /*$$(*/
"Invoice.invoiceAdvPaymentNo"; /*)*/
public static final String INVOICE_INVOICE_BALANCE_NO = /*$$(*/ "Invoice.invoiceBalanceNo"; /*)*/
public static final String INVOICE_DRAFT_INVOICE_NO = /*$$(*/ "Invoice.draftInvoiceNo"; /*)*/
public static final String INVOICE_REFUND_NO = /*$$(*/ "Invoice.refundNo"; /*)*/
public static final String INVOICE_DISCOUNT_AMOUNT = /*$$(*/ "Invoice.discountAmount"; /*)*/
public static final String INVOICE_ADVANCE_PAYMENT = /*$$(*/ "Invoice.advancePayment"; /*)*/
public static final String INVOICE_OF = /*$$(*/ "Invoice.of"; /*)*/
public static final String INVOICE_IMPUTED_ON = /*$$(*/ "Invoice.imputedOn"; /*)*/
public static final String INVOICE_TOTAL_TO_PAY = /*$$(*/ "Invoice.totalToPay"; /*)*/
public static final String INVOICE_CANCEL_INVOICE_NO = /*$$(*/ "Invoice.cancelInvoiceNo"; /*)*/
public static final String INVOICE_TIMESHEET_TITLE = /*$$(*/ "Invoice.timesheetTitle"; /*)*/
public static final String INVOICE_EXPENSE_TITLE = /*$$(*/ "Invoice.expenseTitle"; /*)*/
public static final String INVOICE_TIMESHEET_USER = /*$$(*/ "Invoice.timesheetUser"; /*)*/
public static final String INVOICE_TIMESHEET_ACTIVITY = /*$$(*/ "Invoice.timesheetActivity"; /*)*/
public static final String INVOICE_TIMESHEET_DURATION = /*$$(*/ "Invoice.timesheetDuration"; /*)*/
public static final String INVOICE_EXPENSE_TOTAL_AMOUNT = /*$$(*/
"Invoice.expenseTotalAmount"; /*)*/
public static final String INVOICE_EXPENSE_TAX_AMOUNT = /*$$(*/ "Invoice.expenseTaxAmount"; /*)*/
public static final String INVOICE_EXPENSE_PRODUCT = /*$$(*/ "Invoice.expenseProduct"; /*)*/
public static final String INVOICE_PRODUCT_CODE = /*$$(*/ "Invoice.productCode"; /*)*/
public static final String INVOICE_TERMS_AND_CONDITIONS = /*$$(*/
"Invoice.termsAndConditions"; /*)*/
public static final String INVOICE_SUBSCRIPTION_PERIOD = /*$$(*/
"Invoice.subscriptionPeriod"; /*)*/
public static final String INVOICE_CUSTOMER_PARTNER_SEQ = /*$$(*/
"Invoice.customerPartnerSeq"; /*)*/
public static final String INVOICE_SUPPLIER_PARTNER_SEQ = /*$$(*/
"Invoice.supplierPartnerSeq"; /*)*/
public static final String INVOICE_CUSTOMER_TAX_NUMBER = /*$$(*/
"Invoice.customerTaxNumber"; /*)*/
public static final String INVOICE_AMOUNT_REMAINING = /*$$(*/ "Invoice.amountRemaining"; /*)*/
public static final String INVOICE_PROFORMA_INVOICE = /*$$(*/ "Invoice.proformaInvoice"; /*)*/
public static final String ACCOUNTING_REPORT_EDITION_DATE = /*$$(*/
"AccountingReport.editionDate"; /*)*/
public static final String ACCOUNTING_REPORT_RECAP_BY_ACCOUNT = /*$$(*/
"AccountingReport.recapByAccount"; /*)*/
public static final String ACCOUNTING_REPORT_TOTAL_DEBIT_ACCOUNT = /*$$(*/
"AccountingReport.totalDebitAccount"; /*)*/
public static final String ACCOUNTING_REPORT_TOTAL_CREDIT_ACCOUNT = /*$$(*/
"AccountingReport.totalCreditAccount"; /*)*/
public static final String ACCOUNTING_REPORT_CONTROL = /*$$(*/ "AccountingReport.control"; /*)*/
public static final String ACCOUNTING_REPORT_1_TITLE = /*$$(*/
"AccountingReportType1.title"; /*)*/
public static final String ACCOUNTING_REPORT_1_JOURNAL = /*$$(*/
"AccountingReportType1.journal"; /*)*/
public static final String ACCOUNTING_REPORT_1_COMPANY = /*$$(*/
"AccountingReportType1.company"; /*)*/
public static final String ACCOUNTING_REPORT_1_END_DATE = /*$$(*/
"AccountingReportType1.endDate"; /*)*/
public static final String ACCOUNTING_REPORT_1_FROM = /*$$(*/ "AccountingReportType1.from"; /*)*/
public static final String ACCOUNTING_REPORT_1_TO = /*$$(*/ "AccountingReportType1.to"; /*)*/
public static final String ACCOUNTING_REPORT_1_PERIOD = /*$$(*/
"AccountingReportType1.period"; /*)*/
public static final String ACCOUNTING_REPORT_1_PAYMENT_MODE = /*$$(*/
"AccountingReportType1.paymentMode"; /*)*/
public static final String ACCOUNTING_REPORT_1_DATE = /*$$(*/ "AccountingReportType1.date"; /*)*/
public static final String ACCOUNTING_REPORT_1_CODE = /*$$(*/ "AccountingReportType1.code"; /*)*/
public static final String ACCOUNTING_REPORT_1_NAME = /*$$(*/ "AccountingReportType1.name"; /*)*/
public static final String ACCOUNTING_REPORT_1_DESCRIPTION = /*$$(*/
"AccountingReportType1.description"; /*)*/
public static final String ACCOUNTING_REPORT_1_PARTNER = /*$$(*/
"AccountingReportType1.partner"; /*)*/
public static final String ACCOUNTING_REPORT_1_BALANCE = /*$$(*/
"AccountingReportType1.balance"; /*)*/
public static final String ACCOUNTING_REPORT_1_DEBIT = /*$$(*/
"AccountingReportType1.debit"; /*)*/
public static final String ACCOUNTING_REPORT_1_CREDIT = /*$$(*/
"AccountingReportType1.credit"; /*)*/
public static final String ACCOUNTING_REPORT_1_TOTAL = /*$$(*/
"AccountingReportType1.total"; /*)*/
public static final String ACCOUNTING_REPORT_7_TITLE = /*$$(*/
"AccountingReportType7.title"; /*)*/
public static final String ACCOUNTING_REPORT_7_DUE_DATE = /*$$(*/
"AccountingReportType7.dueDate"; /*)*/
public static final String ACCOUNTING_REPORT_7_RECONCILE_GROUP = /*$$(*/
"AccountingReportType7.reconcileGroup"; /*)*/
public static final String ACCOUNTING_REPORT_7_JOURNAL_DATE = /*$$(*/
"AccountingReportType7.journalCode"; /*)*/
public static final String ACCOUNTING_REPORT_7_JOURNAL = /*$$(*/
"AccountingReportType1.journal"; /*)*/
public static final String ACCOUNTING_REPORT_7_COMPANY = /*$$(*/
"AccountingReportType1.company"; /*)*/
public static final String ACCOUNTING_REPORT_7_END_DATE = /*$$(*/
"AccountingReportType1.endDate"; /*)*/
public static final String ACCOUNTING_REPORT_7_FROM = /*$$(*/ "AccountingReportType1.from"; /*)*/
public static final String ACCOUNTING_REPORT_7_TO = /*$$(*/ "AccountingReportType1.to"; /*)*/
public static final String ACCOUNTING_REPORT_7_PERIOD = /*$$(*/
"AccountingReportType1.period"; /*)*/
public static final String ACCOUNTING_REPORT_7_PAYMENT_MODE = /*$$(*/
"AccountingReportType1.paymentMode"; /*)*/
public static final String ACCOUNTING_REPORT_7_DATE = /*$$(*/ "AccountingReportType1.date"; /*)*/
public static final String ACCOUNTING_REPORT_7_DESCRIPTION = /*$$(*/
"AccountingReportType1.description"; /*)*/
public static final String ACCOUNTING_REPORT_7_PARTNER = /*$$(*/
"AccountingReportType1.partner"; /*)*/
public static final String ACCOUNTING_REPORT_7_BALANCE = /*$$(*/
"AccountingReportType1.balance"; /*)*/
public static final String ACCOUNTING_REPORT_7_DEBIT = /*$$(*/
"AccountingReportType1.debit"; /*)*/
public static final String ACCOUNTING_REPORT_7_CREDIT = /*$$(*/
"AccountingReportType1.credit"; /*)*/
public static final String ACCOUNTING_REPORT_7_TOTAL = /*$$(*/
"AccountingReportType1.total"; /*)*/
public static final String ACCOUNTING_REPORT_2_TITLE = /*$$(*/
"AccountingReportType2.title"; /*)*/
public static final String ACCOUNTING_REPORT_2_JOURNAL = /*$$(*/
"AccountingReportType2.journal"; /*)*/
public static final String ACCOUNTING_REPORT_2_COMPANY = /*$$(*/
"AccountingReportType2.company"; /*)*/
public static final String ACCOUNTING_REPORT_2_END_DATE = /*$$(*/
"AccountingReportType2.endDate"; /*)*/
public static final String ACCOUNTING_REPORT_2_FROM = /*$$(*/ "AccountingReportType2.from"; /*)*/
public static final String ACCOUNTING_REPORT_2_TO = /*$$(*/ "AccountingReportType2.to"; /*)*/
public static final String ACCOUNTING_REPORT_2_PERIOD = /*$$(*/
"AccountingReportType2.period"; /*)*/
public static final String ACCOUNTING_REPORT_2_PAYMENT_MODE = /*$$(*/
"AccountingReportType2.paymentMode"; /*)*/
public static final String ACCOUNTING_REPORT_2_ACCOUNT = /*$$(*/
"AccountingReportType2.account"; /*)*/
public static final String ACCOUNTING_REPORT_2_ACCOUNT_LABEL = /*$$(*/
"AccountingReportType2.accountLabel"; /*)*/
public static final String ACCOUNTING_REPORT_2_TOTAL_DEBIT = /*$$(*/
"AccountingReportType2.totalDebit"; /*)*/
public static final String ACCOUNTING_REPORT_2_TOTAL_CREDIT = /*$$(*/
"AccountingReportType2.totalCredit"; /*)*/
public static final String ACCOUNTING_REPORT_2_BALANCE = /*$$(*/
"AccountingReportType2.balance"; /*)*/
public static final String ACCOUNTING_REPORT_2_DEBIT = /*$$(*/
"AccountingReportType2.debit"; /*)*/
public static final String ACCOUNTING_REPORT_2_CREDIT = /*$$(*/
"AccountingReportType2.credit"; /*)*/
public static final String ACCOUNTING_REPORT_2_GENERAL_BALANCE = /*$$(*/
"AccountingReportType2.generalBalance"; /*)*/
public static final String ACCOUNTING_REPORT_6_TITLE = /*$$(*/
"AccountingReportType6.title"; /*)*/
public static final String ACCOUNTING_REPORT_15_TITLE = /*$$(*/
"AccountingReportType15.title"; /*)*/
public static final String ACCOUNTING_REPORT_15_COMPANY = /*$$(*/
"AccountingReportType15.company"; /*)*/
public static final String ACCOUNTING_REPORT_15_FROM = /*$$(*/
"AccountingReportType15.from"; /*)*/
public static final String ACCOUNTING_REPORT_15_TO = /*$$(*/ "AccountingReportType15.to"; /*)*/
public static final String ACCOUNTING_REPORT_15_YEAR = /*$$(*/
"AccountingReportType15.year"; /*)*/
public static final String ACCOUNTING_REPORT_15_VAT_TOTAL = /*$$(*/
"AccountingReportType15.vatTotal"; /*)*/
public static final String ACCOUNTING_REPORT_15_PRINT_DATE = /*$$(*/
"AccountingReportType15.printDate"; /*)*/
public static final String ACCOUNTING_REPORT_15_CURRENCY = /*$$(*/
"AccountingReportType15.currency"; /*)*/
public static final String ACCOUNTING_REPORT_15_TAX_CODE = /*$$(*/
"AccountingReportType15.taxCode"; /*)*/
public static final String ACCOUNTING_REPORT_15_NAME = /*$$(*/
"AccountingReportType15.name"; /*)*/
public static final String ACCOUNTING_REPORT_15_MOVE_LINE = /*$$(*/
"AccountingReportType15.moveLine"; /*)*/
public static final String ACCOUNTING_REPORT_15_DATE = /*$$(*/
"AccountingReportType15.date"; /*)*/
public static final String ACCOUNTING_REPORT_15_MOVE_LINE_ACCOUNT = /*$$(*/
"AccountingReportType15.moveLineAccount"; /*)*/
public static final String ACCOUNTING_REPORT_15_ACCOUNT_NAME = /*$$(*/
"AccountingReportType15.accountName"; /*)*/
public static final String ACCOUNTING_REPORT_15_BASE = /*$$(*/
"AccountingReportType15.base"; /*)*/
public static final String ACCOUNTING_REPORT_15_VAT_CASH_ACCOUNTING_SCHEME = /*$$(*/
"AccountingReportType15.vatCashAccountingScheme"; /*)*/
public static final String ACCOUNTING_REPORT_15_PAYABLE_VAT = /*$$(*/
"AccountingReportType15.payableVAT"; /*)*/
public static final String ACCOUNTING_REPORT_15_DEDUCTIBLE_VAT = /*$$(*/
"AccountingReportType15.deductibleVAT"; /*)*/
public static final String ACCOUNTING_REPORT_15_REPORT_DATE_EDITION = /*$$(*/
"AccountingReportType15.reportDateEdition"; /*)*/
public static final String ACCOUNTING_REPORT_15_TOTAL = /*$$(*/
"AccountingReportType15.total"; /*)*/
public static final String ACCOUNTING_REPORT_15_BLANCE = /*$$(*/
"AccountingReportType15.balance"; /*)*/
public static final String ACCOUNTING_REPORT_15_AMOUNT = /*$$(*/
"AccountingReportType15.amount"; /*)*/
public static final String ACCOUNTING_REPORT_15_TAX_RATE = /*$$(*/
"AccountingReportType15.taxRate"; /*)*/
public static final String ACCOUNTING_REPORT_11_JOURNAL = /*$$(*/
"AccountingReportType11.daySubTotal"; /*)*/
public static final String ACCOUNTING_REPORT_2000_TITLE = /*$$(*/
"AccountingReportType2000.title"; /*)*/
public static final String ACCOUNTING_REPORT_2000_ANALYTIC_JOURNAL = /*$$(*/
"AccountingReportType2000.analyticJournal"; /*)*/
public static final String ACCOUNTING_REPORT_2000_COMPANY = /*$$(*/
"AccountingReportType2000.company"; /*)*/
public static final String ACCOUNTING_REPORT_2000_END_DATE = /*$$(*/
"AccountingReportType2000.endDate"; /*)*/
public static final String ACCOUNTING_REPORT_2000_FROM = /*$$(*/
"AccountingReportType2000.from"; /*)*/
public static final String ACCOUNTING_REPORT_2000_TO = /*$$(*/
"AccountingReportType2000.to"; /*)*/
public static final String ACCOUNTING_REPORT_2000_ANALYTIC_AXIS = /*$$(*/
"AccountingReportType2000.analyticAxis"; /*)*/
public static final String ACCOUNTING_REPORT_2000_ANALYTIC_AXIS_CODE = /*$$(*/
"AccountingReportType2000.analyticAxisCode"; /*)*/
public static final String ACCOUNTING_REPORT_2000_ANALYTIC_AXIS_NAME = /*$$(*/
"AccountingReportType2000.analyticAxisName"; /*)*/
public static final String ACCOUNTING_REPORT_2000_ANALYTIC_ACCOUNT = /*$$(*/
"AccountingReportType2000.analyticAccount"; /*)*/
public static final String ACCOUNTING_REPORT_2000_ANALYTIC_ACCOUNT_CODE = /*$$(*/
"AccountingReportType2000.analyticAccountCode"; /*)*/
public static final String ACCOUNTING_REPORT_2000_ANALYTIC_ACCOUNT_NAME = /*$$(*/
"AccountingReportType2000.analyticAccountName"; /*)*/
public static final String ACCOUNTING_REPORT_2000_ACCOUNT_TYPE = /*$$(*/
"AccountingReportType2000.accountType"; /*)*/
public static final String ACCOUNTING_REPORT_2000_AMOUNT = /*$$(*/
"AccountingReportType2000.amount"; /*)*/
public static final String ACCOUNTING_REPORT_2000_PERCENTAGE = /*$$(*/
"AccountingReportType2000.percentage"; /*)*/
public static final String ACCOUNTING_REPORT_2000_TOTAL_PER_ANALYTIC_JOURNAL = /*$$(*/
"AccountingReportType2000.totalPerAnalyticJournal"; /*)*/
public static final String ACCOUNTING_REPORT_2000_TOTAL_PER_ANALYTIC_AXIS = /*$$(*/
"AccountingReportType2000.totalPerAnalyticAxis"; /*)*/
public static final String ACCOUNTING_REPORT_2000_TOTAL_PER_ANALYTIC_ACCOUNT = /*$$(*/
"AccountingReportType2000.totalPerAnalyticAccount"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_TITLE = /*$$(*/
"SaleInvoicesDetails.title"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_COMPANY = /*$$(*/
"SaleInvoicesDetails.company"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_PUBLICATION_DATE = /*$$(*/
"SaleInvoicesDetails.publicationDate"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_PRODUCT_CATEGORIES = /*$$(*/
"SaleInvoicesDetails.productCategories"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_INVOICED = /*$$(*/
"SaleInvoicesDetails.invoiced"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_ORDERED = /*$$(*/
"SaleInvoicesDetails.ordered"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_SUBTOTAL = /*$$(*/
"SaleInvoicesDetails.subtotal"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_SUM_BY_PARTNER = /*$$(*/
"SaleInvoicesDetails.sumByPartner"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_SUM_BY_PRODUCT = /*$$(*/
"SaleInvoicesDetails.sumByProduct"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_TOTAL_ORDER = /*$$(*/
"SaleInvoicesDetails.totalOrder"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_TOTAL_INVOICE = /*$$(*/
"SaleInvoicesDetails.totalInvoice"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_TOTAL_TURNOVER = /*$$(*/
"SaleInvoicesDetails.totalTurnover"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_TITLE = /*$$(*/
"PurchaseInvoicesDetails.title"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_COMPANY = /*$$(*/
"PurchaseInvoicesDetails.company"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_PUBLICATION_DATE = /*$$(*/
"PurchaseInvoicesDetails.publicationDate"; /*)*/
public static final String PURCHASE_INVOICE_ETAILS_REPORT_PRODUCT_CATEGORIES = /*$$(*/
"PurchaseInvoicesDetails.productCategories"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_INVOICED = /*$$(*/
"PurchaseInvoicesDetails.invoiced"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_ORDERED = /*$$(*/
"PurchaseInvoicesDetails.ordered"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_SUBTOTAL = /*$$(*/
"PurchaseInvoicesDetails.subtotal"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_SUM_BY_PARTNER = /*$$(*/
"PurchaseInvoicesDetails.sumByPartner"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_SUM_BY_PRODUCT = /*$$(*/
"PurchaseInvoicesDetails.sumByProduct"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_TOTAL_ORDER = /*$$(*/
"PurchaseInvoicesDetails.totalOrder"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_TOTAL_INVOICE = /*$$(*/
"PurchaseInvoicesDetails.totalInvoice"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_TOTAL_TURNOVER = /*$$(*/
"PurchaseInvoicesDetails.totalTurnover"; /*)*/
public static final String ACCOUNT_MOVE_TITLE = /*$$(*/ "move.title"; /*)*/
public static final String ACCOUNT_MOVE_REFERENCE = /*$$(*/ "move.reference"; /*)*/
public static final String ACCOUNT_MOVE_JOURNAL = /*$$(*/ "move.journal"; /*)*/
public static final String ACCOUNT_MOVE_PARTNER = /*$$(*/ "move.partner"; /*)*/
public static final String ACCOUNT_MOVE_TECHNICAL_ORIGIN = /*$$(*/ "move.technical.origin"; /*)*/
public static final String ACCOUNT_MOVE_PERIOD = /*$$(*/ "move.period"; /*)*/
public static final String ACCOUNT_MOVE_CURRENCY = /*$$(*/ "move.currency"; /*)*/
public static final String ACCOUNT_MOVE_COMPANY = /*$$(*/ "move.company"; /*)*/
public static final String ACCOUNT_MOVE_LINE_DATE = /*$$(*/ "moveLine.date"; /*)*/
public static final String ACCOUNT_MOVE_LINE_PARTNER = /*$$(*/ "moveLine.partner"; /*)*/
public static final String ACCOUNT_MOVE_LINE_ACCOUNT = /*$$(*/ "moveLine.account"; /*)*/
public static final String ACCOUNT_MOVE_LINE_DEBIT = /*$$(*/ "moveLine.debit"; /*)*/
public static final String ACCOUNT_MOVE_LINE_CREDIT = /*$$(*/ "moveLine.credit"; /*)*/
public static final String ACCOUNT_MOVE_LINE_CURRENCY_AMOUNT = /*$$(*/
"moveLine.currency.amount"; /*)*/
public static final String ACCOUNT_MOVE_LINE_TAX_RATE = /*$$(*/ "moveLine.tax.rate"; /*)*/
public static final String ACCOUNT_MOVE_LINE_RECONCILE_LIST = /*$$(*/
"moveLine.reconcile.list"; /*)*/
public static final String ACCOUNT_MOVE_LINE_DESC = /*$$(*/ "moveLine.description"; /*)*/
public static final String ACCOUNT_MOVE_LINE_ORIGIN = /*$$(*/ "moveLine.origin"; /*)*/
public static final String ACCOUNT_MOVE_LINE_RECONCILE_GROUP = /*$$(*/
"moveLine.reconcileGroup"; /*)*/
public static final String ACCOUNT_MOVE_LINE_TOTAL_LINES = /*$$(*/ "moveLine.totalLines"; /*)*/
public static final String ACCOUNT_MOVE_LINE_TOTAL_DEBIT = /*$$(*/ "moveLine.totalDebit"; /*)*/
public static final String ACCOUNT_MOVE_LINE_TOTAL_CREDIT = /*$$(*/ "moveLine.totalCredit"; /*)*/
public static final String ACCOUNT_MOVE_LINE_DIFFERENCE = /*$$(*/ "moveLine.difference"; /*)*/
public static final String SUBROGATION_RELEASE_TITLE = /*$$(*/ "SubrogationRelease.title"; /*)*/
public static final String SUBROGATION_RELEASE_SELLER_CODE = /*$$(*/
"SubrogationRelease.sellerCode"; /*)*/
public static final String SUBROGATION_RELEASE_FACTOR = /*$$(*/ "SubrogationRelease.factor"; /*)*/
public static final String SUBROGATION_RELEASE_PARTNER_SEQ = /*$$(*/
"SubrogationRelease.partnerSeq"; /*)*/
public static final String SUBROGATION_RELEASE_INVOICE_ID = /*$$(*/
"SubrogationRelease.invoiceId"; /*)*/
public static final String SUBROGATION_RELEASE_INVOICE_DATE = /*$$(*/
"SubrogationRelease.invoiceDate"; /*)*/
public static final String SUBROGATION_RELEASE_DUE_DATE = /*$$(*/
"SubrogationRelease.dueDate"; /*)*/
public static final String SUBROGATION_RELEASE_IN_TAX_TOTAL = /*$$(*/
"SubrogationRelease.inTaxtTotal"; /*)*/
public static final String SUBROGATION_RELEASE_CURRENCY_CODE = /*$$(*/
"SubrogationRelease.currencyCode"; /*)*/
public static final String SUBROGATION_RELEASE_INVOICE_TOTAL = /*$$(*/
"SubrogationRelease.invoiceTotal"; /*)*/
public static final String SUBROGATION_RELEASE_CREDIT_TOTAL = /*$$(*/
"SubrogationRelease.creditTotal"; /*)*/
public static final String SUBROGATION_RELEASE_GRAND_TOTAL = /*$$(*/
"SubrogationRelease.grandTotal"; /*)*/
public static final String SUBROGATION_RELEASE_COMPANY_NAME = /*$$(*/
"SubrogationRelease.company"; /*)*/
public static final String SUBROGATION_RELEASE_SEQUENCE_NUMBER = /*$$(*/
"SubrogationRelease.sequenceNumber"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_TITLE = /*$$(*/ "ChequeDepositSlip.title"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_PRINTED_ON = /*$$(*/
"ChequeDepositSlip.printedOn"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_NUMBER = /*$$(*/ "ChequeDepositSlip.number"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_DATE = /*$$(*/
"ChequeDepositSlip.depositDate"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_CHEQUE_NUMBERS = /*$$(*/
"ChequeDepositSlip.chequeNumbers"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_BANK = /*$$(*/ "ChequeDepositSlip.bank"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_ACCOUNT_NUMBER = /*$$(*/
"ChequeDepositSlip.accountNumber"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_INDIVIDUAL = /*$$(*/
"ChequeDepositSlip.individual"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_ISSUER = /*$$(*/ "ChequeDepositSlip.issuer"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_PAYER = /*$$(*/ "ChequeDepositSlip.payer"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_CHEQUE_NUMBER = /*$$(*/
"ChequeDepositSlip.chequeNumber"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_PAYMENT_DATE = /*$$(*/
"ChequeDepositSlip.paymentDate"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_CHEQUE_DATE = /*$$(*/
"ChequeDepositSlip.chequeDate"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_AMOUNT = /*$$(*/ "ChequeDepositSlip.amount"; /*)*/
public static final String ACCOUNTING_REPORT_16_TITLE =
/*$$(*/ "AccountingReportType16.title"; /*)*/
public static final String ACCOUNTING_REPORT_16_COMPANY =
/*$$(*/ "AccountingReportType16.company"; /*)*/
public static final String ACCOUNTING_REPORT_16_CURRENCY =
/*$$(*/ "AccountingReportType16.currency"; /*)*/
public static final String ACCOUNTING_REPORT_16_END_DATE =
/*$$(*/ "AccountingReportType16.endDate"; /*)*/
public static final String ACCOUNTING_REPORT_16_YEAR =
/*$$(*/ "AccountingReportType16.year"; /*)*/
public static final String ACCOUNTING_REPORT_16_PERIOD =
/*$$(*/ "AccountingReportType16.period"; /*)*/
public static final String ACCOUNTING_REPORT_16_FROM_DATE =
/*$$(*/ "AccountingReportType16.from"; /*)*/
public static final String ACCOUNTING_REPORT_16_TO_DATE =
/*$$(*/ "AccountingReportType16.to"; /*)*/
public static final String ACCOUNTING_REPORT_16_REFERENCE =
/*$$(*/ "AccountingReportType16.reference"; /*)*/
public static final String ACCOUNTING_REPORT_16_ASSET_NAME =
/*$$(*/ "AccountingReportType16.asset_name"; /*)*/
public static final String ACCOUNTING_REPORT_16_ACCOUNT_NAME =
/*$$(*/ "AccountingReportType16.account_name"; /*)*/
public static final String ACCOUNTING_REPORT_16_COMPUTATION_METHOD =
/*$$(*/ "AccountingReportType16.computaion_method"; /*)*/
public static final String ACCOUNTING_REPORT_16_DURATION =
/*$$(*/ "AccountingReportType16.duration"; /*)*/
public static final String ACCOUNTING_REPORT_16_ACQISITION_DATE =
/*$$(*/ "AccountingReportType16.acquisition_date"; /*)*/
public static final String ACCOUNTING_REPORT_16_GROSS_VALUE =
/*$$(*/ "AccountingReportType16.gross_value"; /*)*/
public static final String ACCOUNTING_REPORT_ASSET_COMPUTATION_METHOD_LINEAR =
/*$$(*/ "linear"; /*)*/
public static final String ACCOUNTING_REPORT_ASSET_COMPUTATION_METHOD_DIGRESSIVE =
/*$$(*/ "degressive"; /*)*/
public static final String ACCOUNTING_REPORT_17_TITLE =
/*$$(*/ "AccountingReportType17.title"; /*)*/
public static final String ACCOUNTING_REPORT_17_COMPANY =
/*$$(*/ "AccountingReportType17.company"; /*)*/
public static final String ACCOUNTING_REPORT_17_CURRENCY =
/*$$(*/ "AccountingReportType17.currency"; /*)*/
public static final String ACCOUNTING_REPORT_17_END_DATE =
/*$$(*/ "AccountingReportType17.endDate"; /*)*/
public static final String ACCOUNTING_REPORT_17_YEAR =
/*$$(*/ "AccountingReportType17.year"; /*)*/
public static final String ACCOUNTING_REPORT_17_PERIOD =
/*$$(*/ "AccountingReportType17.period"; /*)*/
public static final String ACCOUNTING_REPORT_17_FROM_DATE =
/*$$(*/ "AccountingReportType17.from"; /*)*/
public static final String ACCOUNTING_REPORT_17_TO_DATE =
/*$$(*/ "AccountingReportType17.to"; /*)*/
public static final String ACCOUNTING_REPORT_17_REFERENCE =
/*$$(*/ "AccountingReportType17.reference"; /*)*/
public static final String ACCOUNTING_REPORT_17_ASSET_NAME =
/*$$(*/ "AccountingReportType17.asset_name"; /*)*/
public static final String ACCOUNTING_REPORT_17_COMPUTATION_METHOD =
/*$$(*/ "AccountingReportType17.computation_method"; /*)*/
public static final String ACCOUNTING_REPORT_17_DURATION =
/*$$(*/ "AccountingReportType17.duration"; /*)*/
public static final String ACCOUNTING_REPORT_17_ACQISITION_DATE =
/*$$(*/ "AccountingReportType17.acquisition_date"; /*)*/
public static final String ACCOUNTING_REPORT_17_RESIDUAL_VALUE =
/*$$(*/ "AccountingReportType17.residual_value"; /*)*/
public static final String ACCOUNTING_REPORT_17_GROSS_VALUES =
/*$$(*/ "AccountingReportType17.gross_values"; /*)*/
public static final String ACCOUNTING_REPORT_17_ORIGINAL_VALUE =
/*$$(*/ "AccountingReportType17.original_value"; /*)*/
public static final String ACCOUNTING_REPORT_17_ACQISITION =
/*$$(*/ "AccountingReportType17.acquisition"; /*)*/
public static final String ACCOUNTING_REPORT_17_ASSET_DISPOSAL =
/*$$(*/ "AccountingReportType17.asset_disposal"; /*)*/
public static final String ACCOUNTING_REPORT_17_YEAR_END_VALUE =
/*$$(*/ "AccountingReportType17.year_end_value"; /*)*/
public static final String ACCOUNTING_REPORT_17_DEPRECIATION =
/*$$(*/ "AccountingReportType17.depreciation"; /*)*/
public static final String ACCOUNTING_REPORT_17_YEAR_START_VALUE =
/*$$(*/ "AccountingReportType17.year_start_value"; /*)*/
public static final String ACCOUNTING_REPORT_17_DEPRECIATION_CHARGE =
/*$$(*/ "AccountingReportType17.depreciation_charge"; /*)*/
public static final String INVOICE_PAYMENT_DATE = /*$$(*/ "InvoicePayment.date"; /*)*/
public static final String INVOICE_PAYMENT_TYPE = /*$$(*/ "InvoicePayment.type"; /*)*/
public static final String INVOICE_PAYMENT_PAYMENT_MODE = /*$$(*/
"InvoicePayment.payment_mode"; /*)*/
public static final String INVOICE_PAYMENT_AMOUNT = /*$$(*/ "InvoicePayment.amount"; /*)*/
}

View File

@ -0,0 +1,134 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.AccountChart;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.repo.AccountChartRepository;
import com.axelor.apps.account.db.repo.AccountConfigRepository;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.ImportConfiguration;
import com.axelor.apps.base.db.repo.CompanyRepository;
import com.axelor.apps.base.service.imports.importer.FactoryImporter;
import com.axelor.exception.AxelorException;
import com.axelor.exception.service.TraceBackService;
import com.axelor.meta.MetaFiles;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apache.commons.io.FileUtils;
public class AccountChartService {
@Inject private FactoryImporter factoryImporter;
@Inject private MetaFiles metaFiles;
protected AccountConfigRepository accountConfigRepo;
protected CompanyRepository companyRepo;
protected AccountChartRepository accountChartRepository;
@Inject
public AccountChartService(
AccountConfigRepository accountConfigRepo,
CompanyRepository companyRepo,
AccountChartRepository accountChartRepository) {
this.accountConfigRepo = accountConfigRepo;
this.companyRepo = companyRepo;
this.accountChartRepository = accountChartRepository;
}
public Boolean installAccountChart(AccountChart act, Company company, AccountConfig accountConfig)
throws AxelorException {
try {
if (act.getMetaFile() == null) {
return false;
}
InputStream inputStream = this.getClass().getResourceAsStream("/l10n/chart-config.xml");
if (inputStream == null) {
return false;
}
File configFile = createConfigFile(inputStream);
Map<String, Object> importContext = new HashMap<String, Object>();
importContext.put("_companyId", company.getId());
importAccountChartData(act, configFile, importContext);
updateChartCompany(act, company, accountConfig);
FileUtils.forceDelete(configFile);
return true;
} catch (IOException e) {
TraceBackService.trace(e);
return false;
}
}
private File createConfigFile(InputStream inputStream) throws IOException, FileNotFoundException {
File configFile = File.createTempFile("input-config", ".xml");
FileOutputStream outputStream = new FileOutputStream(configFile);
int read = 0;
byte[] bytes = new byte[1024];
while ((read = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
outputStream.close();
return configFile;
}
@Transactional
public void updateChartCompany(AccountChart act, Company company, AccountConfig accountConfig) {
accountConfig = accountConfigRepo.find(accountConfig.getId());
accountConfig.setHasChartImported(true);
accountConfigRepo.save(accountConfig);
act = accountChartRepository.find(act.getId());
company = companyRepo.find(company.getId());
Set<Company> companySet = act.getCompanySet();
companySet.add(company);
act.setCompanySet(companySet);
accountChartRepository.save(act);
}
public void importAccountChartData(
AccountChart act, File configFile, Map<String, Object> importContext)
throws IOException, AxelorException {
ImportConfiguration importConfiguration = new ImportConfiguration();
importConfiguration.setDataMetaFile(act.getMetaFile());
importConfiguration.setBindMetaFile(metaFiles.upload(configFile));
factoryImporter.createImporter(importConfiguration).run(importContext);
}
}

View File

@ -0,0 +1,319 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountClearance;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.Journal;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.Reconcile;
import com.axelor.apps.account.db.Tax;
import com.axelor.apps.account.db.repo.AccountClearanceRepository;
import com.axelor.apps.account.db.repo.MoveLineRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.move.MoveLineService;
import com.axelor.apps.account.service.move.MoveService;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.repo.SequenceRepository;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.base.service.tax.TaxService;
import com.axelor.apps.base.service.user.UserService;
import com.axelor.auth.db.User;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AccountClearanceService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected MoveService moveService;
protected MoveLineService moveLineService;
protected MoveLineRepository moveLineRepo;
protected SequenceService sequenceService;
protected ReconcileService reconcileService;
protected TaxService taxService;
protected TaxAccountService taxAccountService;
protected AccountClearanceRepository accountClearanceRepo;
protected AppBaseService appBaseService;
protected User user;
@Inject
public AccountClearanceService(
UserService userService,
AppBaseService appBaseService,
MoveService moveService,
MoveLineService moveLineService,
MoveLineRepository moveLineRepo,
SequenceService sequenceService,
ReconcileService reconcileService,
TaxService taxService,
TaxAccountService taxAccountService,
AccountClearanceRepository accountClearanceRepo) {
this.appBaseService = appBaseService;
this.user = userService.getUser();
this.moveService = moveService;
this.moveLineService = moveLineService;
this.moveLineRepo = moveLineRepo;
this.sequenceService = sequenceService;
this.reconcileService = reconcileService;
this.taxService = taxService;
this.taxAccountService = taxAccountService;
this.accountClearanceRepo = accountClearanceRepo;
}
public List<? extends MoveLine> getExcessPayment(AccountClearance accountClearance)
throws AxelorException {
Company company = accountClearance.getCompany();
this.testCompanyField(company);
List<? extends MoveLine> moveLineList =
moveLineRepo
.all()
.filter(
"self.company = ?1 AND self.account.useForPartnerBalance = 'true' "
+ "AND (self.move.statusSelect = ?2 OR self.move.statusSelect = ?3) "
+ "AND self.amountRemaining > 0 AND self.amountRemaining <= ?4 AND self.credit > 0 AND self.account in ?5 AND self.date <= ?6",
company,
MoveRepository.STATUS_VALIDATED,
MoveRepository.STATUS_DAYBOOK,
accountClearance.getAmountThreshold(),
company.getAccountConfig().getClearanceAccountSet(),
accountClearance.getDateThreshold())
.fetch();
log.debug("Liste des trop perçus récupérés : {}", moveLineList);
return moveLineList;
}
@SuppressWarnings("unchecked")
@Transactional(rollbackOn = {Exception.class})
public void setExcessPayment(AccountClearance accountClearance) throws AxelorException {
accountClearance.setMoveLineSet(new HashSet<MoveLine>());
List<MoveLine> moveLineList = (List<MoveLine>) this.getExcessPayment(accountClearance);
if (moveLineList != null && moveLineList.size() != 0) {
accountClearance.getMoveLineSet().addAll(moveLineList);
}
accountClearanceRepo.save(accountClearance);
}
@Transactional(rollbackOn = {Exception.class})
public void validateAccountClearance(AccountClearance accountClearance) throws AxelorException {
Company company = accountClearance.getCompany();
AccountConfig accountConfig = company.getAccountConfig();
Tax tax = accountConfig.getStandardRateTax();
BigDecimal taxRate =
taxService.getTaxRate(tax, appBaseService.getTodayDateTime().toLocalDate());
Account taxAccount = taxAccountService.getAccount(tax, company, false, false);
Account profitAccount = accountConfig.getProfitAccount();
Journal journal = accountConfig.getAccountClearanceJournal();
Set<MoveLine> moveLineList = accountClearance.getMoveLineSet();
for (MoveLine moveLine : moveLineList) {
Move move =
this.createAccountClearanceMove(
moveLine, taxRate, taxAccount, profitAccount, company, journal, accountClearance);
moveService.getMoveValidateService().validate(move);
}
accountClearance.setStatusSelect(AccountClearanceRepository.STATUS_VALIDATED);
accountClearance.setDateTime(appBaseService.getTodayDateTime());
accountClearance.setName(
sequenceService.getSequenceNumber(SequenceRepository.ACCOUNT_CLEARANCE, company));
accountClearanceRepo.save(accountClearance);
}
public Move createAccountClearanceMove(
MoveLine moveLine,
BigDecimal taxRate,
Account taxAccount,
Account profitAccount,
Company company,
Journal journal,
AccountClearance accountClearance)
throws AxelorException {
Partner partner = moveLine.getPartner();
// Move
Move move =
moveService
.getMoveCreateService()
.createMove(
journal, company, null, partner, null, MoveRepository.TECHNICAL_ORIGIN_AUTOMATIC);
// Debit MoveLine 411
BigDecimal amount = moveLine.getAmountRemaining();
MoveLine debitMoveLine =
moveLineService.createMoveLine(
move,
partner,
moveLine.getAccount(),
amount,
true,
appBaseService.getTodayDateTime().toLocalDate(),
1,
null,
null);
move.getMoveLineList().add(debitMoveLine);
// Credit MoveLine 77. (profit account)
BigDecimal divid = taxRate.add(BigDecimal.ONE);
BigDecimal profitAmount =
amount
.divide(divid, AppBaseService.DEFAULT_NB_DECIMAL_DIGITS, RoundingMode.HALF_EVEN)
.setScale(AppBaseService.DEFAULT_NB_DECIMAL_DIGITS, RoundingMode.HALF_EVEN);
MoveLine creditMoveLine1 =
moveLineService.createMoveLine(
move,
partner,
profitAccount,
profitAmount,
false,
appBaseService.getTodayDateTime().toLocalDate(),
2,
null,
null);
move.getMoveLineList().add(creditMoveLine1);
// Credit MoveLine 445 (Tax account)
BigDecimal taxAmount = amount.subtract(profitAmount);
MoveLine creditMoveLine2 =
moveLineService.createMoveLine(
move,
partner,
taxAccount,
taxAmount,
false,
appBaseService.getTodayDateTime().toLocalDate(),
3,
null,
null);
move.getMoveLineList().add(creditMoveLine2);
Reconcile reconcile = reconcileService.createReconcile(debitMoveLine, moveLine, amount, false);
if (reconcile != null) {
reconcileService.confirmReconcile(reconcile, true);
}
debitMoveLine.setAccountClearance(accountClearance);
creditMoveLine1.setAccountClearance(accountClearance);
creditMoveLine2.setAccountClearance(accountClearance);
return move;
}
public AccountClearance createAccountClearance(
Company company,
String name,
BigDecimal amountThreshold,
LocalDate dateThreshold,
List<MoveLine> moveLineSet) {
AccountClearance accountClearance = new AccountClearance();
accountClearance.setAmountThreshold(amountThreshold);
accountClearance.setCompany(company);
accountClearance.setDateThreshold(dateThreshold);
accountClearance.getMoveLineSet().addAll(moveLineSet);
accountClearance.setName(name);
accountClearance.setDateTime(appBaseService.getTodayDateTime());
accountClearance.setUser(this.user);
accountClearance.setStatusSelect(AccountClearanceRepository.STATUS_VALIDATED);
return accountClearance;
}
/**
* Procédure permettant de vérifier les champs d'une société
*
* @param company Une société
* @throws AxelorException
*/
public void testCompanyField(Company company) throws AxelorException {
AccountConfig accountConfig = company.getAccountConfig();
if (accountConfig == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNT_CLEARANCE_1),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
company.getName());
}
if (accountConfig.getProfitAccount() == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNT_CLEARANCE_2),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
company.getName());
}
if (accountConfig.getStandardRateTax() == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNT_CLEARANCE_3),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
company.getName());
}
if (accountConfig.getClearanceAccountSet() == null
|| accountConfig.getClearanceAccountSet().size() == 0) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNT_CLEARANCE_4),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
company.getName());
}
if (!sequenceService.hasSequence(SequenceRepository.ACCOUNT_CLEARANCE, company)) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNT_CLEARANCE_5),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
company.getName());
}
if (accountConfig.getAccountClearanceJournal() == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNT_CLEARANCE_6),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
company.getName());
}
}
}

View File

@ -0,0 +1,383 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.AccountingSituation;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.repo.AccountingSituationRepository;
import com.axelor.apps.account.db.repo.MoveLineRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.db.JPA;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.List;
import javax.persistence.Query;
import javax.persistence.TemporalType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AccountCustomerService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected AccountingSituationService accountingSituationService;
protected AccountingSituationRepository accSituationRepo;
protected AppBaseService appBaseService;
@Inject
public AccountCustomerService(
AccountingSituationService accountingSituationService,
AccountingSituationRepository accSituationRepo,
AppBaseService appBaseService) {
this.accountingSituationService = accountingSituationService;
this.accSituationRepo = accSituationRepo;
this.appBaseService = appBaseService;
}
public AccountingSituationService getAccountingSituationService() {
return this.accountingSituationService;
}
/**
* Fonction permettant de calculer le solde total d'un tiers
*
* @param partner Un tiers
* @param company Une société
* @return Le solde total
*/
public BigDecimal getBalance(Partner partner, Company company) {
log.debug("Compute balance (Partner : {}, Company : {})", partner.getName(), company.getName());
Query query =
JPA.em()
.createNativeQuery(
"SELECT SUM(COALESCE(m1.sum_remaining,0) - COALESCE(m2.sum_remaining,0) ) "
+ "FROM public.account_move_line AS ml "
+ "LEFT OUTER JOIN ( "
+ "SELECT moveline.amount_remaining AS sum_remaining, moveline.id AS moveline_id "
+ "FROM public.account_move_line AS moveline "
+ "WHERE moveline.debit > 0 GROUP BY moveline.id, moveline.amount_remaining) AS m1 ON (m1.moveline_id = ml.id) "
+ "LEFT OUTER JOIN ( "
+ "SELECT moveline.amount_remaining AS sum_remaining, moveline.id AS moveline_id "
+ "FROM public.account_move_line AS moveline "
+ "WHERE moveline.credit > 0 GROUP BY moveline.id, moveline.amount_remaining) AS m2 ON (m2.moveline_id = ml.id) "
+ "LEFT OUTER JOIN public.account_account AS account ON (ml.account = account.id) "
+ "LEFT OUTER JOIN public.account_move AS move ON (ml.move = move.id) "
+ "WHERE ml.partner = ?1 AND move.company = ?2 AND move.ignore_in_accounting_ok IN ('false', null)"
+ "AND account.use_for_partner_balance = 'true'"
+ "AND (move.status_select = ?3 or move.status_select = ?4) AND ml.amount_remaining > 0 ")
.setParameter(1, partner)
.setParameter(2, company)
.setParameter(3, MoveRepository.STATUS_VALIDATED)
.setParameter(4, MoveRepository.STATUS_DAYBOOK);
BigDecimal balance = (BigDecimal) query.getSingleResult();
if (balance == null) {
balance = BigDecimal.ZERO;
}
log.debug("Balance : {}", balance);
return balance;
}
/**
* Fonction permettant de calculer le solde exigible d'un tiers
*
* <p>Calcul du solde exigible du tiers : Montant Total des factures et des échéances rejetées
* échues (date du jour >= date de léchéance)
*
* @param partner Un tiers
* @param company Une société
* @return Le solde exigible
*/
public BigDecimal getBalanceDue(Partner partner, Company company) {
log.debug(
"Compute balance due (Partner : {}, Company : {})", partner.getName(), company.getName());
Query query =
JPA.em()
.createNativeQuery(
"SELECT SUM( COALESCE(m1.sum_remaining,0) - COALESCE(m2.sum_remaining,0) ) "
+ "FROM public.account_move_line AS ml "
+ "LEFT OUTER JOIN ( "
+ "SELECT moveline.amount_remaining AS sum_remaining, moveline.id AS moveline_id "
+ "FROM public.account_move_line AS moveline "
+ "WHERE moveline.debit > 0 "
+ "AND ((moveline.due_date IS NULL AND moveline.date_val <= ?1) OR (moveline.due_date IS NOT NULL AND moveline.due_date <= ?1)) "
+ "GROUP BY moveline.id, moveline.amount_remaining) AS m1 on (m1.moveline_id = ml.id) "
+ "LEFT OUTER JOIN ( "
+ "SELECT moveline.amount_remaining AS sum_remaining, moveline.id AS moveline_id "
+ "FROM public.account_move_line AS moveline "
+ "WHERE moveline.credit > 0 "
+ "GROUP BY moveline.id, moveline.amount_remaining) AS m2 ON (m2.moveline_id = ml.id) "
+ "LEFT OUTER JOIN public.account_account AS account ON (ml.account = account.id) "
+ "LEFT OUTER JOIN public.account_move AS move ON (ml.move = move.id) "
+ "WHERE ml.partner = ?2 AND move.company = ?3 AND move.ignore_in_debt_recovery_ok IN ('false', null) "
+ "AND move.ignore_in_accounting_ok IN ('false', null) AND account.use_for_partner_balance = 'true'"
+ "AND (move.status_select = ?4 OR move.status_select = ?5) AND ml.amount_remaining > 0 ")
.setParameter(
1,
Date.from(
appBaseService
.getTodayDate()
.atStartOfDay()
.atZone(ZoneOffset.UTC)
.toInstant()),
TemporalType.DATE)
.setParameter(2, partner)
.setParameter(3, company)
.setParameter(4, MoveRepository.STATUS_VALIDATED)
.setParameter(5, MoveRepository.STATUS_DAYBOOK);
BigDecimal balance = (BigDecimal) query.getSingleResult();
if (balance == null) {
balance = BigDecimal.ZERO;
}
log.debug("Balance due : {}", balance);
return balance;
}
/**
* **************************************** 2. Calcul du solde exigible (relançable) du tiers
* *****************************************
*/
/**
* solde des factures exigibles non bloquées en relance et dont « la date de facture » + « délai
* dacheminement(X) » <« date du jour » si la date de facture = date d'échéance de facture, sinon
* pas de prise en compte du délai d'acheminement **
*/
/**
* solde des échéances rejetées qui ne sont pas bloqués
* *****************************************************
*/
public BigDecimal getBalanceDueDebtRecovery(Partner partner, Company company) {
log.debug(
"Compute balance due debt recovery (Partner : {}, Company : {})",
partner.getName(),
company.getName());
int mailTransitTime = 0;
AccountConfig accountConfig = company.getAccountConfig();
if (accountConfig != null) {
mailTransitTime = accountConfig.getMailTransitTime();
}
// TODO: Replace native query to standard JPQL query
Query query =
JPA.em()
.createNativeQuery(
"SELECT SUM( COALESCE(m1.sum_remaining,0) - COALESCE(m2.sum_remaining,0) ) "
+ "FROM public.account_move_line as ml "
+ "LEFT OUTER JOIN ( "
+ "SELECT moveline.amount_remaining AS sum_remaining, moveline.id AS moveline_id "
+ "FROM public.account_move_line AS moveline "
+ "WHERE moveline.debit > 0 AND (( moveline.date_val = moveline.due_date AND (moveline.due_date + ?1 ) < ?2 ) "
+ "OR (moveline.due_date IS NOT NULL AND moveline.date_val != moveline.due_date AND moveline.due_date < ?2)"
+ "OR (moveline.due_date IS NULL AND moveline.date_val < ?2)) "
+ "GROUP BY moveline.id, moveline.amount_remaining) AS m1 ON (m1.moveline_id = ml.id) "
+ "LEFT OUTER JOIN ( "
+ "SELECT moveline.amount_remaining AS sum_remaining, moveline.id AS moveline_id "
+ "FROM public.account_move_line AS moveline "
+ "WHERE moveline.credit > 0 "
+ "GROUP BY moveline.id, moveline.amount_remaining) AS m2 ON (m2.moveline_id = ml.id) "
+ "LEFT OUTER JOIN public.account_account AS account ON (ml.account = account.id) "
+ "LEFT OUTER JOIN public.account_move AS move ON (ml.move = move.id) "
+ "LEFT JOIN public.account_invoice AS invoice ON (move.invoice = invoice.id) "
+ "WHERE ml.partner = ?3 AND move.company = ?4 AND move.ignore_in_debt_recovery_ok in ('false', null) "
+ "AND move.ignore_in_accounting_ok IN ('false', null) AND account.use_for_partner_balance = 'true'"
+ "AND (move.status_select = ?5 OR move.status_select = ?6) AND ml.amount_remaining > 0 AND invoice.debt_recovery_blocking_ok = FALSE ")
.setParameter(1, mailTransitTime)
.setParameter(
2,
Date.from(
appBaseService
.getTodayDate()
.atStartOfDay()
.atZone(ZoneOffset.UTC)
.toInstant()),
TemporalType.DATE)
.setParameter(3, partner)
.setParameter(4, company)
.setParameter(5, MoveRepository.STATUS_VALIDATED)
.setParameter(6, MoveRepository.STATUS_DAYBOOK);
BigDecimal balance = (BigDecimal) query.getSingleResult();
if (balance == null) {
balance = BigDecimal.ZERO;
}
log.debug("Balance due debt recovery : {}", balance);
return balance;
}
/**
* Méthode permettant de récupérer l'ensemble des lignes d'écriture pour une société et un tiers
*
* @param partner Un tiers
* @param company Une société
* @return
*/
public List<? extends MoveLine> getMoveLine(Partner partner, Company company) {
return Beans.get(MoveLineRepository.class)
.all()
.filter("self.partner = ?1 AND self.move.company = ?2", partner, company)
.fetch();
}
/**
* Procédure mettant à jour les soldes du compte client des tiers pour une société
*
* @param partnerList Une liste de tiers à mettre à jour
* @param company Une société
*/
public void updatePartnerAccountingSituation(
List<Partner> partnerList,
Company company,
boolean updateCustAccount,
boolean updateDueCustAccount,
boolean updateDueDebtRecoveryCustAccount)
throws AxelorException {
for (Partner partner : partnerList) {
AccountingSituation accountingSituation =
accountingSituationService.getAccountingSituation(partner, company);
if (accountingSituation == null) {
accountingSituation =
accountingSituationService.createAccountingSituation(partner, company);
}
if (accountingSituation != null) {
this.updateAccountingSituationCustomerAccount(
accountingSituation,
updateCustAccount,
updateDueCustAccount,
updateDueDebtRecoveryCustAccount);
}
}
}
@Transactional(rollbackOn = {Exception.class})
public void flagPartners(List<Partner> partnerList, Company company) throws AxelorException {
for (Partner partner : partnerList) {
AccountingSituation accountingSituation =
accountingSituationService.getAccountingSituation(partner, company);
if (accountingSituation == null) {
accountingSituation =
accountingSituationService.createAccountingSituation(partner, company);
}
if (accountingSituation != null) {
accountingSituation.setCustAccountMustBeUpdateOk(true);
accSituationRepo.save(accountingSituation);
}
}
}
@Transactional(rollbackOn = {Exception.class})
public AccountingSituation updateAccountingSituationCustomerAccount(
AccountingSituation accountingSituation,
boolean updateCustAccount,
boolean updateDueCustAccount,
boolean updateDueDebtRecoveryCustAccount)
throws AxelorException {
Partner partner = accountingSituation.getPartner();
Company company = accountingSituation.getCompany();
log.debug(
"Update customer account (Partner : {}, Company : {}, Update balance : {}, balance due : {}, balance due debt recovery : {})",
partner.getName(),
company.getName(),
updateCustAccount,
updateDueCustAccount,
updateDueDebtRecoveryCustAccount);
if (updateCustAccount) {
accountingSituation.setBalanceCustAccount(this.getBalance(partner, company));
}
if (updateDueCustAccount) {
accountingSituation.setBalanceDueCustAccount(this.getBalanceDue(partner, company));
}
if (updateDueDebtRecoveryCustAccount) {
accountingSituation.setBalanceDueDebtRecoveryCustAccount(
this.getBalanceDueDebtRecovery(partner, company));
}
accountingSituation.setCustAccountMustBeUpdateOk(false);
accSituationRepo.save(accountingSituation);
return accountingSituation;
}
public Account getPartnerAccount(Partner partner, Company company, boolean isSupplierInvoice)
throws AxelorException {
return isSupplierInvoice
? getSupplierAccount(partner, company)
: getCustomerAccount(partner, company);
}
protected Account getCustomerAccount(Partner partner, Company company) throws AxelorException {
Account customerAccount = accountingSituationService.getCustomerAccount(partner, company);
if (customerAccount == null) {
throw new AxelorException(
partner,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNT_CUSTOMER_1),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
company.getName());
}
return customerAccount;
}
protected Account getSupplierAccount(Partner partner, Company company) throws AxelorException {
Account supplierAccount = accountingSituationService.getSupplierAccount(partner, company);
if (supplierAccount == null) {
throw new AxelorException(
partner,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNT_CUSTOMER_2),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
company.getName());
}
return supplierAccount;
}
}

View File

@ -0,0 +1,71 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AnalyticDistributionTemplate;
import com.axelor.apps.account.db.FiscalPosition;
import com.axelor.apps.account.db.FixedAssetCategory;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Product;
import com.axelor.apps.base.service.tax.AccountManagementService;
import com.axelor.exception.AxelorException;
public interface AccountManagementAccountService extends AccountManagementService {
/**
* Get the product tax according to the fiscal position
*
* @param product
* @param company
* @param fiscalPosition
* @param isPurchase Specify if we want get the tax for purchase or sale
* @param fixedAsset Specify if we should get the purchase account for fixed asset or not. Used
* only if isPurchase param is true.
* @return the tax defined for the product, according to the fiscal position
* @throws AxelorException
*/
public Account getProductAccount(
Product product,
Company company,
FiscalPosition fiscalPosition,
boolean isPurchase,
boolean fixedAsset)
throws AxelorException;
/**
* Get the product analytic distribution template
*
* @param product
* @param company
* @return
* @throws AxelorException
*/
public AnalyticDistributionTemplate getAnalyticDistributionTemplate(
Product product, Company company);
/**
* Get the product fixed asset category
*
* @param product
* @param company
* @return
* @throws AxelorException
*/
public FixedAssetCategory getProductFixedAssetCategory(Product product, Company company);
}

View File

@ -0,0 +1,225 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountManagement;
import com.axelor.apps.account.db.AnalyticDistributionTemplate;
import com.axelor.apps.account.db.FiscalPosition;
import com.axelor.apps.account.db.FixedAssetCategory;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Product;
import com.axelor.apps.base.service.tax.AccountManagementServiceImpl;
import com.axelor.apps.base.service.tax.FiscalPositionService;
import com.axelor.apps.base.service.tax.TaxService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.meta.CallMethod;
import com.google.inject.Inject;
import java.lang.invoke.MethodHandles;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AccountManagementServiceAccountImpl extends AccountManagementServiceImpl
implements AccountManagementAccountService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@Inject
public AccountManagementServiceAccountImpl(
FiscalPositionService fiscalPositionService, TaxService taxService) {
super(fiscalPositionService, taxService);
}
/**
* Get the product tax according to the fiscal position
*
* @param product
* @param company
* @param fiscalPosition
* @param isPurchase Specify if we want get the tax for purchase or sale
* @param fixedAsset Specify if we should get the purchase account for fixed asset or not. Used
* only if isPurchase param is true.
* @return the tax defined for the product, according to the fiscal position
* @throws AxelorException
*/
public Account getProductAccount(
Product product,
Company company,
FiscalPosition fiscalPosition,
boolean isPurchase,
boolean fixedAsset)
throws AxelorException {
log.debug(
"Get the account for the product {} (company : {}, purchase : {}, fixed asset : {}, fiscal position : {})",
new Object[] {
product.getCode(),
company.getName(),
isPurchase,
fixedAsset,
fiscalPosition != null ? fiscalPosition.getCode() : null
});
Account generalAccount =
this.getProductAccount(product, company, isPurchase, fixedAsset, CONFIG_OBJECT_PRODUCT);
Account account =
new FiscalPositionAccountServiceImpl().getAccount(fiscalPosition, generalAccount);
if (account != null) {
return account;
}
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNT_MANAGEMENT_1_ACCOUNT),
product.getCode(),
company.getName());
}
/**
* Get the product tax
*
* @param product
* @param company
* @param isPurchase
* @param fixedAsset Specify if we should get the purchase account for fixed asset or not. Used
* only if isPurchase param is true.
* @param configObject Specify if we want get the tax from the product or its product family
* <li>1 : product
* <li>2 : product family
* @return
* @throws AxelorException
*/
@CallMethod
protected Account getProductAccount(
Product product, Company company, boolean isPurchase, boolean fixedAsset, int configObject) {
AccountManagement accountManagement = this.getAccountManagement(product, company, configObject);
Account account = null;
if (accountManagement != null) {
if (isPurchase) {
if (fixedAsset) {
account = accountManagement.getPurchFixedAssetsAccount();
} else {
account = accountManagement.getPurchaseAccount();
}
} else {
account = accountManagement.getSaleAccount();
}
}
if (account == null && configObject == CONFIG_OBJECT_PRODUCT) {
return getProductAccount(
product, company, isPurchase, fixedAsset, CONFIG_OBJECT_PRODUCT_FAMILY);
}
return account;
}
/**
* Get the product analytic distribution template
*
* @param product
* @param company
* @return
* @throws AxelorException
*/
public AnalyticDistributionTemplate getAnalyticDistributionTemplate(
Product product, Company company) {
return getAnalyticDistributionTemplate(product, company, CONFIG_OBJECT_PRODUCT);
}
/**
* Get the product analytic distribution template
*
* @param product
* @param compan
* @param configObject Specify if we want get the tax from the product or its product family
* <li>1 : product
* <li>2 : product family
* @return
* @throws AxelorException
*/
protected AnalyticDistributionTemplate getAnalyticDistributionTemplate(
Product product, Company company, int configObject) {
AccountManagement accountManagement = this.getAccountManagement(product, company, configObject);
AnalyticDistributionTemplate analyticDistributionTemplate = null;
if (accountManagement != null) {
analyticDistributionTemplate = accountManagement.getAnalyticDistributionTemplate();
}
if (analyticDistributionTemplate == null && configObject == CONFIG_OBJECT_PRODUCT) {
return getAnalyticDistributionTemplate(product, company, CONFIG_OBJECT_PRODUCT_FAMILY);
}
return analyticDistributionTemplate;
}
/**
* Get the product fixed asset category
*
* @param product
* @param company
* @return
* @throws AxelorException
*/
public FixedAssetCategory getProductFixedAssetCategory(Product product, Company company) {
return getProductFixedAssetCategory(product, company, CONFIG_OBJECT_PRODUCT);
}
/**
* Get the product fixed asset category
*
* @param product
* @param company
* @param configObject Specify if we want get the fixed asset category from the product or its
* product family
* <li>1 : product
* <li>2 : product family
* @return
* @throws AxelorException
*/
protected FixedAssetCategory getProductFixedAssetCategory(
Product product, Company company, int configObject) {
AccountManagement accountManagement = this.getAccountManagement(product, company, configObject);
FixedAssetCategory fixedAssetCategory = null;
if (accountManagement != null) {
fixedAssetCategory = accountManagement.getFixedAssetCategory();
}
if (fixedAssetCategory == null && configObject == CONFIG_OBJECT_PRODUCT) {
return getProductFixedAssetCategory(product, company, CONFIG_OBJECT_PRODUCT_FAMILY);
}
return fixedAssetCategory;
}
}

View File

@ -0,0 +1,122 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.repo.AccountRepository;
import com.axelor.db.JPA;
import com.google.inject.Inject;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import javax.persistence.Query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AccountService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
/** Debit balance = debit - credit */
public static final Integer BALANCE_TYPE_DEBIT_BALANCE = 1;
/** Credit balance = credit - debit */
public static final Integer BALANCE_TYPE_CREDIT_BALANCE = 2;
public static final int MAX_LEVEL_OF_ACCOUNT = 20;
protected AccountRepository accountRepository;
@Inject
public AccountService(AccountRepository accountRepository) {
this.accountRepository = accountRepository;
}
/**
* Compute the balance of the account, depending of the balance type
*
* @param account Account
* @param balanceType
* <p>1 : debit balance = debit - credit
* <p>2 : credit balance = credit - debit
* @return The balance (debit balance or credit balance)
*/
public BigDecimal computeBalance(Account account, int balanceType) {
Query balanceQuery =
JPA.em()
.createQuery(
"select sum(self.debit - self.credit) from MoveLine self where self.account = :account "
+ "and self.move.ignoreInAccountingOk IN ('false', null) and self.move.statusSelect IN (2, 3)");
balanceQuery.setParameter("account", account);
BigDecimal balance = (BigDecimal) balanceQuery.getSingleResult();
if (balance != null) {
if (balanceType == BALANCE_TYPE_CREDIT_BALANCE) {
balance = balance.negate();
}
log.debug("Account balance : {}", balance);
return balance;
} else {
return BigDecimal.ZERO;
}
}
public List<Long> getAllAccountsSubAccountIncluded(List<Long> accountList) {
return getAllAccountsSubAccountIncluded(accountList, 0);
}
public List<Long> getAllAccountsSubAccountIncluded(List<Long> accountList, int counter) {
if (counter > MAX_LEVEL_OF_ACCOUNT) {
return new ArrayList<>();
}
counter++;
List<Long> allAccountsSubAccountIncluded = new ArrayList<>();
if (accountList != null && !accountList.isEmpty()) {
allAccountsSubAccountIncluded.addAll(accountList);
for (Long accountId : accountList) {
allAccountsSubAccountIncluded.addAll(
getAllAccountsSubAccountIncluded(getSubAccounts(accountId), counter));
}
}
return allAccountsSubAccountIncluded;
}
public List<Long> getSubAccounts(Long accountId) {
return accountRepository
.all()
.filter("self.parentAccount.id = ?1", accountId)
.select("id")
.fetch(0, 0)
.stream()
.map(m -> (Long) m.get("id"))
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,51 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.Year;
import com.axelor.exception.AxelorException;
import com.google.inject.persist.Transactional;
import java.time.LocalDate;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.tuple.Pair;
public interface AccountingCloseAnnualService {
@Transactional(rollbackOn = {AxelorException.class, RuntimeException.class})
public List<Move> generateCloseAnnualAccount(
Year year,
Account account,
Partner partner,
LocalDate endOfYearDate,
LocalDate reportedBalanceDate,
String origin,
String moveDescription,
boolean closeYear,
boolean openYear,
boolean allocatePerPartner)
throws AxelorException;
public List<Long> getAllAccountOfYear(Set<Account> accountSet, Year year);
public List<Pair<Long, Long>> assignPartner(
List<Long> accountIdList, Year year, boolean allocatePerPartner);
}

View File

@ -0,0 +1,373 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.repo.AccountRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.account.service.move.MoveCreateService;
import com.axelor.apps.account.service.move.MoveLineService;
import com.axelor.apps.account.service.move.MoveValidateService;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.Year;
import com.axelor.db.JPA;
import com.axelor.exception.AxelorException;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.persistence.Query;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AccountingCloseAnnualServiceImpl implements AccountingCloseAnnualService {
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected MoveCreateService moveCreateService;
protected MoveLineService moveLineService;
protected AccountConfigService accountConfigService;
protected MoveRepository moveRepository;
protected MoveValidateService moveValidateService;
protected ReconcileService reconcileService;
protected AccountService accountService;
protected AccountRepository accountRepository;
protected int counter = 0;
@Inject
public AccountingCloseAnnualServiceImpl(
MoveCreateService moveCreateService,
MoveLineService moveLineService,
AccountConfigService accountConfigService,
MoveRepository moveRepository,
MoveValidateService moveValidateService,
ReconcileService reconcileService,
AccountService accountService,
AccountRepository accountRepository) {
this.moveCreateService = moveCreateService;
this.moveLineService = moveLineService;
this.accountConfigService = accountConfigService;
this.moveRepository = moveRepository;
this.moveValidateService = moveValidateService;
this.reconcileService = reconcileService;
this.accountService = accountService;
this.accountRepository = accountRepository;
}
@Transactional(rollbackOn = {AxelorException.class, RuntimeException.class})
public List<Move> generateCloseAnnualAccount(
Year year,
Account account,
Partner partner,
LocalDate endOfYearDate,
LocalDate reportedBalanceDate,
String origin,
String moveDescription,
boolean closeYear,
boolean openYear,
boolean allocatePerPartner)
throws AxelorException {
List<Move> moveList = new ArrayList<>();
Move closeYearMove = null;
Move openYearMove = null;
if (closeYear) {
closeYearMove =
generateCloseAnnualAccountMove(
year,
account,
endOfYearDate,
endOfYearDate,
origin,
moveDescription,
partner,
false,
allocatePerPartner);
if (closeYearMove == null) {
return null;
}
moveList.add(closeYearMove);
}
if (openYear) {
openYearMove =
generateCloseAnnualAccountMove(
year,
account,
reportedBalanceDate,
endOfYearDate,
origin,
moveDescription,
partner,
true,
allocatePerPartner);
if (openYearMove == null) {
return null;
}
moveList.add(openYearMove);
}
if (closeYearMove != null && openYearMove != null) {
reconcile(closeYearMove, openYearMove);
}
return moveList;
}
protected Move generateCloseAnnualAccountMove(
Year year,
Account account,
LocalDate moveDate,
LocalDate originDate,
String origin,
String moveDescription,
Partner partner,
boolean isReverse,
boolean allocatePerPartner)
throws AxelorException {
Company company = account.getCompany();
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
BigDecimal balance = computeBalance(year, account, partner, allocatePerPartner);
if (balance.compareTo(BigDecimal.ZERO) == 0) {
return null;
}
Integer functionalOriginSelect = null;
if (isReverse) {
balance = balance.negate();
functionalOriginSelect = MoveRepository.FUNCTIONAL_ORIGIN_OPENING;
} else {
functionalOriginSelect = MoveRepository.FUNCTIONAL_ORIGIN_CLOSURE;
}
Move move =
moveCreateService.createMove(
accountConfigService.getReportedBalanceJournal(accountConfig),
company,
company.getCurrency(),
partner,
moveDate,
null,
MoveRepository.TECHNICAL_ORIGIN_AUTOMATIC,
false,
false,
!isReverse);
move.setFunctionalOriginSelect(functionalOriginSelect);
counter = 0;
this.generateCloseAnnualMoveLine(
move, origin, account, moveDescription, originDate, balance.negate());
this.generateCloseAnnualMoveLine(
move,
origin,
getYearClosureOrOpeningAccount(accountConfig, isReverse),
moveDescription,
originDate,
balance);
if (move.getMoveLineList() != null && !move.getMoveLineList().isEmpty()) {
moveValidateService.validate(move);
} else {
moveRepository.remove(move);
return null;
}
return move;
}
protected Account getYearClosureOrOpeningAccount(AccountConfig accountConfig, boolean isReverse)
throws AxelorException {
if (isReverse) {
return accountConfigService.getYearOpeningAccount(accountConfig);
} else {
return accountConfigService.getYearClosureAccount(accountConfig);
}
}
protected MoveLine generateCloseAnnualMoveLine(
Move move,
String origin,
Account account,
String moveDescription,
LocalDate originDate,
BigDecimal balance)
throws AxelorException {
LocalDate moveDate = move.getDate();
MoveLine moveLine =
moveLineService.createMoveLine(
move,
move.getPartner(),
account,
balance.abs(),
balance.abs(),
null,
balance.compareTo(BigDecimal.ZERO) == 1,
moveDate,
moveDate,
originDate,
++counter,
origin,
moveDescription);
move.addMoveLineListItem(moveLine);
return moveLine;
}
protected BigDecimal computeBalance(
Year year, Account account, Partner partner, boolean allocatePerPartner) {
String prepareQuery =
"select SUM(self.debit - self.credit) FROM MoveLine as self "
+ "WHERE self.move.ignoreInAccountingOk = false AND self.move.period.year = ?1 AND self.account = ?2 "
+ "AND self.move.statusSelect = ?3 AND self.move.autoYearClosureMove is not true";
if (allocatePerPartner && account.getUseForPartnerBalance()) {
if (partner != null) {
prepareQuery += " AND self.partner = ?4";
} else {
prepareQuery += " AND self.partner is null";
}
}
Query q = JPA.em().createQuery(prepareQuery, BigDecimal.class);
q.setParameter(1, year);
q.setParameter(2, account);
q.setParameter(3, MoveRepository.STATUS_VALIDATED);
if (partner != null) {
q.setParameter(4, partner);
}
BigDecimal result = (BigDecimal) q.getSingleResult();
LOG.debug(
"Balance : {} for the account : {} and the year : {}",
result,
account.getCode(),
year.getCode());
if (result != null) {
return result;
} else {
return BigDecimal.ZERO;
}
}
protected void reconcile(Move move, Move reverseMove) throws AxelorException {
List<MoveLine> moveLineSortedList = move.getMoveLineList();
Collections.sort(moveLineSortedList, Comparator.comparing(MoveLine::getCounter));
List<MoveLine> reverseMoveLineSortedList = reverseMove.getMoveLineList();
Collections.sort(reverseMoveLineSortedList, Comparator.comparing(MoveLine::getCounter));
Iterator<MoveLine> reverseMoveLinesIt = reverseMoveLineSortedList.iterator();
for (MoveLine moveLine : moveLineSortedList) {
MoveLine reverseMoveLine = reverseMoveLinesIt.next();
reconcileService.reconcile(moveLine, reverseMoveLine, false, false);
}
}
public List<Long> getAllAccountOfYear(Set<Account> accountSet, Year year) {
List<Long> accountIdList =
accountService.getAllAccountsSubAccountIncluded(
accountSet.stream().map(Account::getId).collect(Collectors.toList()));
Query q =
JPA.em()
.createQuery(
"select distinct(self.account.id) FROM MoveLine as self "
+ "WHERE self.move.ignoreInAccountingOk = false AND self.move.period.year = ?1 AND self.account.id in (?2) "
+ "AND self.move.statusSelect = ?3 AND self.move.autoYearClosureMove is not true",
Long.class);
q.setParameter(1, year);
q.setParameter(2, accountIdList);
q.setParameter(3, MoveRepository.STATUS_VALIDATED);
List<Long> result = q.getResultList();
return result;
}
public List<Pair<Long, Long>> assignPartner(
List<Long> accountIdList, Year year, boolean allocatePerPartner) {
List<Pair<Long, Long>> accountAndPartnerPair = new ArrayList<>();
for (Long accountId : accountIdList) {
if (allocatePerPartner && accountRepository.find(accountId).getUseForPartnerBalance()) {
for (Long partnerId : getPartner(accountId, year)) {
accountAndPartnerPair.add(Pair.of(accountId, partnerId));
}
} else {
accountAndPartnerPair.add(Pair.of(accountId, null));
}
}
return accountAndPartnerPair;
}
protected List<Long> getPartner(Long accountId, Year year) {
Query q =
JPA.em()
.createQuery(
"select distinct(self.partner.id) FROM MoveLine as self "
+ "WHERE self.move.ignoreInAccountingOk = false AND self.move.period.year = ?1 AND self.account.id = ?2 "
+ "AND self.move.statusSelect = ?3 AND self.move.autoYearClosureMove is not true",
Long.class);
q.setParameter(1, year);
q.setParameter(2, accountId);
q.setParameter(3, MoveRepository.STATUS_VALIDATED);
List<Long> result = q.getResultList();
return result;
}
}

View File

@ -0,0 +1,78 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountingReport;
import com.axelor.apps.account.db.JournalType;
import com.axelor.exception.AxelorException;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
public interface AccountingReportService {
public String getMoveLineList(AccountingReport accountingReport) throws AxelorException;
public String buildQuery(AccountingReport accountingReport) throws AxelorException;
public String addParams(String paramQuery, Object param);
public String addParams(String paramQuery);
@Transactional
public void setSequence(AccountingReport accountingReport, String sequence);
public String getSequence(AccountingReport accountingReport) throws AxelorException;
public JournalType getJournalType(AccountingReport accountingReport) throws AxelorException;
public Account getAccount(AccountingReport accountingReport);
@Transactional
public void setStatus(AccountingReport accountingReport);
/** @param accountingReport */
@Transactional
public void setPublicationDateTime(AccountingReport accountingReport);
/**
* @param queryFilter
* @return
*/
public BigDecimal getDebitBalance();
/**
* @param queryFilter
* @return
*/
public BigDecimal getCreditBalance();
public BigDecimal getDebitBalanceType4();
public BigDecimal getCreditBalance(AccountingReport accountingReport, String queryFilter);
public BigDecimal getCreditBalanceType4();
public String getReportFileLink(AccountingReport accountingReport, String name)
throws AxelorException;
public boolean isThereTooManyLines(AccountingReport accountingReport) throws AxelorException;
public void testReportedDateField(LocalDate reportedDate) throws AxelorException;
}

View File

@ -0,0 +1,681 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.ReportFactory;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.AccountingReport;
import com.axelor.apps.account.db.JournalType;
import com.axelor.apps.account.db.repo.AccountRepository;
import com.axelor.apps.account.db.repo.AccountingReportRepository;
import com.axelor.apps.account.db.repo.AnalyticMoveLineRepository;
import com.axelor.apps.account.db.repo.FixedAssetRepository;
import com.axelor.apps.account.db.repo.MoveLineRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.db.repo.PaymentModeRepository;
import com.axelor.apps.account.db.repo.TaxPaymentMoveLineRepository;
import com.axelor.apps.account.db.repo.TaxRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.report.IReport;
import com.axelor.apps.account.service.app.AppAccountService;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.repo.SequenceRepository;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.report.engine.ReportSettings;
import com.axelor.db.JPA;
import com.axelor.db.Model;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.persistence.Query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AccountingReportServiceImpl implements AccountingReportService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected AccountingReportRepository accountingReportRepo;
protected AppBaseService appBaseService;
protected String query = "";
protected AccountRepository accountRepo;
protected List<Object> params = new ArrayList<Object>();
protected int paramNumber = 1;
@Inject
public AccountingReportServiceImpl(
AppAccountService appBaseService,
AccountingReportRepository accountingReportRepo,
AccountRepository accountRepo) {
this.accountingReportRepo = accountingReportRepo;
this.accountRepo = accountRepo;
this.appBaseService = appBaseService;
}
@SuppressWarnings("unchecked")
public String getMoveLineList(AccountingReport accountingReport) throws AxelorException {
this.buildQuery(accountingReport);
return this.buildDomainFromQuery();
}
protected String buildDomainFromQuery() {
int i = 1;
String domainQuery = this.query;
for (Object param : params.toArray()) {
String paramStr = "";
if (param instanceof Model) {
paramStr = ((Model) param).getId().toString();
} else if (param instanceof Set) {
Set<Object> paramSet = (Set<Object>) param;
for (Object object : paramSet) {
if (!paramStr.isEmpty()) {
paramStr += ",";
}
paramStr += ((Model) object).getId().toString();
}
} else if (param instanceof LocalDate) {
paramStr = "'" + param.toString() + "'";
} else {
paramStr = param.toString();
}
domainQuery = domainQuery.replace("?" + i, paramStr);
i++;
}
log.debug("domainQuery : {}", domainQuery);
return domainQuery;
}
public String buildQuery(AccountingReport accountingReport) throws AxelorException {
this.initQuery();
if (accountingReport.getCompany() != null) {
this.addParams("self.move.company = ?%d", accountingReport.getCompany());
}
if (accountingReport.getCurrency() != null) {
this.addParams("self.move.companyCurrency = ?%d", accountingReport.getCurrency());
}
if (accountingReport.getDateFrom() != null) {
this.addParams("self.date >= ?%d", accountingReport.getDateFrom());
}
if (accountingReport.getDateTo() != null) {
this.addParams("self.date <= ?%d", accountingReport.getDateTo());
}
if (accountingReport.getDate() != null) {
this.addParams("self.date <= ?%d", accountingReport.getDate());
}
if (accountingReport.getJournal() != null) {
this.addParams("self.move.journal = ?%d", accountingReport.getJournal());
}
if (accountingReport.getPeriod() != null) {
this.addParams("self.move.period = ?%d", accountingReport.getPeriod());
}
if (accountingReport.getAccountSet() != null && !accountingReport.getAccountSet().isEmpty()) {
this.addParams(
"(self.account in (?%d) or self.account.parentAccount in (?%d) "
+ "or self.account.parentAccount.parentAccount in (?%d) or self.account.parentAccount.parentAccount.parentAccount in (?%d) "
+ "or self.account.parentAccount.parentAccount.parentAccount.parentAccount in (?%d) or self.account.parentAccount.parentAccount.parentAccount.parentAccount.parentAccount in (?%d) "
+ "or self.account.parentAccount.parentAccount.parentAccount.parentAccount.parentAccount.parentAccount in (?%d))",
accountingReport.getAccountSet());
}
if (accountingReport.getPartnerSet() != null && !accountingReport.getPartnerSet().isEmpty()) {
this.addParams("self.partner in (?%d)", accountingReport.getPartnerSet());
}
if (accountingReport.getYear() != null) {
this.addParams("self.move.period.year = ?%d", accountingReport.getYear());
}
if (accountingReport.getPaymentMode() != null) {
this.addParams("self.move.paymentMode = ?%d", accountingReport.getPaymentMode());
}
if (accountingReport.getTypeSelect() == AccountingReportRepository.REPORT_CHEQUE_DEPOSIT) {
this.addParams("self.amountPaid > 0 AND self.credit > 0");
}
if (accountingReport.getTypeSelect() == AccountingReportRepository.REPORT_AGED_BALANCE) {
this.addParams("self.account is null or self.account.reconcileOk = 'true'");
this.addParams("self.amountRemaining > 0 AND self.debit > 0");
}
if (accountingReport.getTypeSelect()
== AccountingReportRepository.REPORT_PARNER_GENERAL_LEDGER) {
this.addParams("self.account.useForPartnerBalance = 'true'");
}
if (accountingReport.getTypeSelect() == AccountingReportRepository.REPORT_BALANCE) {
this.addParams("self.account is null or self.account.reconcileOk = 'true'");
}
if (accountingReport.getTypeSelect() == AccountingReportRepository.REPORT_CASH_PAYMENTS) {
this.addParams("self.move.paymentMode.typeSelect = ?%d", PaymentModeRepository.TYPE_CASH);
this.addParams("self.credit > 0");
this.addParams("self.account is null or self.account.reconcileOk = 'true'");
}
if (accountingReport.getTypeSelect() == AccountingReportRepository.REPORT_PAYMENT_DIFFERENCES) {
this.addParams(
"self.account = ?%d",
Beans.get((AccountConfigService.class))
.getAccountConfig(accountingReport.getCompany())
.getCashPositionVariationAccount());
}
if (accountingReport.getTypeSelect()
== AccountingReportRepository.REPORT_VAT_STATEMENT_INVOICE) {
this.addParams("self.taxLine is not null");
this.addParams("self.taxLine.tax.typeSelect = ?%d", TaxRepository.TAX_TYPE_DEBIT);
}
this.addParams("self.move.ignoreInAccountingOk = 'false'");
this.addParams(
"(self.move.statusSelect = "
+ MoveRepository.STATUS_DAYBOOK
+ " OR self.move.statusSelect = "
+ MoveRepository.STATUS_VALIDATED
+ ")");
// FOR EXPORT ONLY :
if (accountingReport.getTypeSelect()
> AccountingReportRepository.EXPORT_PAYROLL_JOURNAL_ENTRY) {
this.addParams(
"(self.move.accountingOk = false OR (self.move.accountingOk = true and self.move.accountingReport = ?%d))",
accountingReport);
}
if (accountingReport.getTypeSelect()
>= AccountingReportRepository.EXPORT_PAYROLL_JOURNAL_ENTRY) {
this.addParams("self.move.journal.notExportOk = false ");
}
if (accountingReport.getTypeSelect()
> AccountingReportRepository.EXPORT_PAYROLL_JOURNAL_ENTRY) {
JournalType journalType = this.getJournalType(accountingReport);
if (journalType != null) {
this.addParams("self.move.journal.journalType = ?%d", journalType);
}
}
if (accountingReport.getTypeSelect() >= AccountingReportRepository.REPORT_PARNER_GENERAL_LEDGER
&& accountingReport.getDisplayOnlyNotCompletelyLetteredMoveLines()) {
this.addParams("self.amountRemaining > 0");
}
log.debug("Query : {}", this.query);
return this.query;
}
protected void initQuery() {
query = "";
paramNumber = 1;
params = new ArrayList<Object>();
this.query = "";
this.params.clear();
this.paramNumber = 1;
}
public String addParams(String paramQuery, Object param) {
log.debug("requete et param : {} : {}", paramQuery, paramNumber);
this.addParams(paramQuery.replaceAll("%d", String.valueOf(paramNumber++)));
this.params.add(param);
return this.query;
}
public String addParams(String paramQuery) {
if (!this.query.equals("")) {
this.query += " AND ";
}
this.query += paramQuery;
return this.query;
}
public void setSequence(AccountingReport accountingReport, String sequence) {
accountingReport.setRef(sequence);
}
public String getSequence(AccountingReport accountingReport) throws AxelorException {
SequenceService sequenceService = Beans.get(SequenceService.class);
int accountingReportTypeSelect = accountingReport.getTypeSelect();
if (accountingReportTypeSelect >= 0 && accountingReportTypeSelect < 1000) {
String seq =
sequenceService.getSequenceNumber(
SequenceRepository.ACCOUNTING_REPORT, accountingReport.getCompany());
if (seq == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNTING_REPORT_1),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
accountingReport.getCompany().getName());
}
return seq;
} else if (accountingReportTypeSelect >= 1000 && accountingReportTypeSelect < 2000) {
String seq =
sequenceService.getSequenceNumber(
SequenceRepository.MOVE_LINE_EXPORT, accountingReport.getCompany());
if (seq == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNTING_REPORT_2),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
accountingReport.getCompany().getName());
}
return seq;
} else if (accountingReportTypeSelect >= 2000 && accountingReportTypeSelect < 3000) {
String seq =
sequenceService.getSequenceNumber(
SequenceRepository.ANALYTIC_REPORT, accountingReport.getCompany());
if (seq == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNTING_REPORT_ANALYTIC_REPORT),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
accountingReport.getCompany().getName());
}
return seq;
}
throw new AxelorException(
accountingReport,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNTING_REPORT_UNKNOWN_ACCOUNTING_REPORT_TYPE),
accountingReport.getTypeSelect());
}
public JournalType getJournalType(AccountingReport accountingReport) throws AxelorException {
Company company = accountingReport.getCompany();
AccountConfigService accountConfigService = Beans.get(AccountConfigService.class);
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
switch (accountingReport.getTypeSelect()) {
case AccountingReportRepository.EXPORT_SALES:
return accountConfigService.getSaleJournalType(accountConfig);
case AccountingReportRepository.EXPORT_REFUNDS:
return accountConfigService.getCreditNoteJournalType(accountConfig);
case AccountingReportRepository.EXPORT_TREASURY:
return accountConfigService.getCashJournalType(accountConfig);
case AccountingReportRepository.EXPORT_PURCHASES:
return accountConfigService.getPurchaseJournalType(accountConfig);
default:
break;
}
return null;
}
public Account getAccount(AccountingReport accountingReport) {
if (accountingReport.getTypeSelect() == AccountingReportRepository.REPORT_PAYMENT_DIFFERENCES
&& accountingReport.getCompany() != null) {
return accountRepo
.all()
.filter("self.company = ?1 AND self.code LIKE '58%'", accountingReport.getCompany())
.fetchOne();
}
return null;
}
@Transactional
public void setStatus(AccountingReport accountingReport) {
accountingReport.setStatusSelect(AccountingReportRepository.STATUS_VALIDATED);
accountingReportRepo.save(accountingReport);
}
/** @param accountingReport */
@Transactional
public void setPublicationDateTime(AccountingReport accountingReport) {
accountingReport.setPublicationDateTime(appBaseService.getTodayDateTime());
accountingReportRepo.save(accountingReport);
}
/**
* @param queryFilter
* @return
*/
public BigDecimal getDebitBalance() {
Query q =
JPA.em()
.createQuery(
"select SUM(self.debit) FROM MoveLine as self WHERE " + query, BigDecimal.class);
int i = 1;
for (Object param : params.toArray()) {
q.setParameter(i++, param);
}
BigDecimal result = (BigDecimal) q.getSingleResult();
log.debug("Total debit : {}", result);
if (result != null) {
return result;
} else {
return BigDecimal.ZERO;
}
}
/**
* @param queryFilter
* @return
*/
public BigDecimal getCreditBalance() {
Query q =
JPA.em()
.createQuery(
"select SUM(self.credit) FROM MoveLine as self WHERE " + query, BigDecimal.class);
int i = 1;
for (Object param : params.toArray()) {
q.setParameter(i++, param);
}
BigDecimal result = (BigDecimal) q.getSingleResult();
log.debug("Total debit : {}", result);
if (result != null) {
return result;
} else {
return BigDecimal.ZERO;
}
}
public BigDecimal getDebitBalanceType4() {
Query q =
JPA.em()
.createQuery(
"select SUM(self.amountRemaining) FROM MoveLine as self WHERE " + query,
BigDecimal.class);
int i = 1;
for (Object param : params.toArray()) {
q.setParameter(i++, param);
}
BigDecimal result = (BigDecimal) q.getSingleResult();
log.debug("Total debit : {}", result);
if (result != null) {
return result;
} else {
return BigDecimal.ZERO;
}
}
public BigDecimal getCreditBalance(AccountingReport accountingReport, String queryFilter) {
if (accountingReport.getTypeSelect() == AccountingReportRepository.REPORT_AGED_BALANCE) {
return this.getCreditBalanceType4();
} else {
return this.getCreditBalance();
}
}
public BigDecimal getCreditBalanceType4() {
return this.getDebitBalance().subtract(this.getDebitBalanceType4());
}
public void testReportedDateField(LocalDate reportedDate) throws AxelorException {
if (reportedDate == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.CLOSE_NO_REPORTED_BALANCE_DATE));
}
}
@Override
public String getReportFileLink(AccountingReport accountingReport, String name)
throws AxelorException {
return ReportFactory.createReport(
String.format(IReport.ACCOUNTING_REPORT_TYPE, accountingReport.getTypeSelect()),
name + "-${date}")
.addParam("AccountingReportId", accountingReport.getId())
.addParam("Locale", ReportSettings.getPrintingLocale(null))
.addFormat(accountingReport.getExportTypeSelect())
.toAttach(accountingReport)
.generate()
.getFileLink();
}
public boolean isThereTooManyLines(AccountingReport accountingReport) throws AxelorException {
AccountConfig accountConfig =
Beans.get(AccountConfigService.class).getAccountConfig(accountingReport.getCompany());
Integer lineMinBeforeLongReportGenerationMessageNumber =
accountConfig.getLineMinBeforeLongReportGenerationMessageNumber();
if (lineMinBeforeLongReportGenerationMessageNumber != null
&& lineMinBeforeLongReportGenerationMessageNumber > 0) {
Integer typeSelect = accountingReport.getTypeSelect();
long count = 0;
if (typeSelect > 0 && typeSelect <= AccountingReportRepository.REPORT_GENERAL_LEDGER2) {
count =
Beans.get(MoveLineRepository.class)
.all()
.filter(this.getMoveLineList(accountingReport))
.count();
} else if (typeSelect == AccountingReportRepository.REPORT_VAT_STATEMENT_RECEIVED) {
count =
Beans.get(TaxPaymentMoveLineRepository.class)
.all()
.filter(this.getTaxPaymentMoveLineList(accountingReport))
.count();
} else if (typeSelect == AccountingReportRepository.REPORT_ACQUISITIONS) {
count =
Beans.get(FixedAssetRepository.class)
.all()
.filter(this.getFixedAssetList(accountingReport))
.count();
count +=
JPA.em()
.createQuery(
"Select invoiceLine FROM InvoiceLine invoiceLine LEFT JOIN FixedAsset fixedAsset on fixedAsset.invoiceLine = invoiceLine.id WHERE invoiceLine.fixedAssets = true and fixedAsset.invoiceLine is null ")
.getResultList()
.size();
} else if (typeSelect == AccountingReportRepository.REPORT_GROSS_VALUES_AND_DEPRECIATION) {
count =
Beans.get(FixedAssetRepository.class)
.all()
.filter(this.getFixedAssetList(accountingReport))
.count();
} else if (typeSelect == AccountingReportRepository.REPORT_ANALYTIC_BALANCE) {
count =
Beans.get(AnalyticMoveLineRepository.class)
.all()
.filter(this.getAnalyticMoveLineList(accountingReport))
.count();
} else {
return false;
}
return count > lineMinBeforeLongReportGenerationMessageNumber;
} else {
return false;
}
}
protected String getAnalyticMoveLineList(AccountingReport accountingReport) {
this.buildAnalyticMoveLineQuery(accountingReport);
return this.buildDomainFromQuery();
}
protected void buildAnalyticMoveLineQuery(AccountingReport accountingReport) {
this.initQuery();
this.addParams("self.moveLine.move.companyCurrency = ?%d", accountingReport.getCurrency());
if (accountingReport.getJournal() != null) {
this.addParams("self.moveLine.move.journal = ?%d", accountingReport.getJournal());
}
if (accountingReport.getDateFrom() != null) {
this.addParams("self.date >= ?%d", accountingReport.getDateFrom());
}
if (accountingReport.getDateTo() != null) {
this.addParams("self.date <= ?%d", accountingReport.getDateTo());
}
this.addParams("self.date <= ?%d", accountingReport.getDate());
if (accountingReport.getAnalyticJournal() != null) {
this.addParams("self.analyticJournal = ?%d", accountingReport.getAnalyticJournal());
}
this.addParams("self.typeSelect = ?%d", AnalyticMoveLineRepository.STATUS_REAL_ACCOUNTING);
this.addParams("self.moveLine.move.ignoreInAccountingOk = 'false'");
this.addParams(
"(self.moveLine.move.statusSelect = "
+ MoveRepository.STATUS_DAYBOOK
+ " OR self.moveLine.move.statusSelect = "
+ MoveRepository.STATUS_VALIDATED
+ ")");
log.debug("Query : {}", this.query);
}
protected String getFixedAssetList(AccountingReport accountingReport) {
this.buildFixedAssetQuery(accountingReport);
return this.buildDomainFromQuery();
}
protected void buildFixedAssetQuery(AccountingReport accountingReport) {
this.initQuery();
this.addParams(
"(self.statusSelect = "
+ FixedAssetRepository.STATUS_VALIDATED
+ " OR self.statusSelect = "
+ FixedAssetRepository.STATUS_DEPRECIATED
+ ")");
if (accountingReport.getTypeSelect() == AccountingReportRepository.REPORT_ACQUISITIONS) {
if (accountingReport.getDateFrom() != null) {
this.addParams("self.acquisitionDate >= ?%d", accountingReport.getDateFrom());
}
if (accountingReport.getDateTo() != null) {
this.addParams("self.acquisitionDate <= ?%d", accountingReport.getDateTo());
}
}
if (accountingReport.getTypeSelect()
== AccountingReportRepository.REPORT_GROSS_VALUES_AND_DEPRECIATION) {
this.query += " OR ( self.statusSelect = " + FixedAssetRepository.STATUS_TRANSFERRED + " ";
if (accountingReport.getDateFrom() != null) {
this.addParams("self.disposalDate >= ?%d", accountingReport.getDateFrom());
}
if (accountingReport.getDateTo() != null) {
this.addParams("self.disposalDate <= ?%d", accountingReport.getDateTo());
}
this.query += " ) ";
}
log.debug("Query : {}", this.query);
}
protected String getTaxPaymentMoveLineList(AccountingReport accountingReport) {
this.buildTaxPaymentQuery(accountingReport);
return this.buildDomainFromQuery();
}
protected String buildTaxPaymentQuery(AccountingReport accountingReport) {
this.initQuery();
if (accountingReport.getCompany() != null) {
this.addParams("self.moveLine.move.company = ?%d", accountingReport.getCompany());
}
if (accountingReport.getCurrency() != null) {
this.addParams("self.moveLine.move.companyCurrency = ?%d", accountingReport.getCurrency());
}
if (accountingReport.getDateFrom() != null) {
this.addParams("self.moveLine.date >= ?%d", accountingReport.getDateFrom());
}
if (accountingReport.getDateTo() != null) {
this.addParams("self.moveLine.date <= ?%d", accountingReport.getDateTo());
}
this.addParams("self.moveLine.move.ignoreInAccountingOk = 'false'");
this.addParams(
"(self.moveLine.move.statusSelect = "
+ MoveRepository.STATUS_DAYBOOK
+ " OR self.moveLine.move.statusSelect = "
+ MoveRepository.STATUS_VALIDATED
+ ")");
this.addParams("self.originTaxLine.tax.typeSelect = ?%d", TaxRepository.TAX_TYPE_COLLECTION);
log.debug("Query : {}", this.query);
return this.query;
}
}

View File

@ -0,0 +1,39 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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;
public class AccountingService {
private static boolean DEFAULT_UPDATE_CUSTOMER_ACCOUNT = true;
private static final ThreadLocal<Boolean> threadLocal = new ThreadLocal<Boolean>();
public static void setUpdateCustomerAccount(boolean updateCustomerAccount) {
threadLocal.set(updateCustomerAccount);
}
public static boolean getUpdateCustomerAccount() {
if (threadLocal.get() != null) {
return threadLocal.get();
}
return DEFAULT_UPDATE_CUSTOMER_ACCOUNT;
}
}

View File

@ -0,0 +1,99 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountingSituation;
import com.axelor.apps.base.db.BankDetails;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.exception.AxelorException;
import com.axelor.meta.CallMethod;
import java.util.List;
public interface AccountingSituationService {
boolean checkAccountingSituationList(
List<AccountingSituation> accountingSituationList, Company company);
/**
* Creates unexisting accounting situations for a given partner. Created situations will be
* appended to the partner's AccountingSituationList
*
* @param partner Partner to create accounting situation for.
* @return The created accounting situations (which is the same as calling
* partner.getAccountingSituationList())
* @throws AxelorException In case of configuration issue
*/
List<AccountingSituation> createAccountingSituation(Partner partner) throws AxelorException;
AccountingSituation getAccountingSituation(Partner partner, Company company);
AccountingSituation createAccountingSituation(Partner partner, Company company)
throws AxelorException;
/**
* Automatically creates supplier/customer/employee accounts based on situation's company
* configuration.
*
* @param situation Situation on which accounts should be created.
*/
void createPartnerAccounts(AccountingSituation situation) throws AxelorException;
String createDomainForBankDetails(
AccountingSituation accountingSituation, boolean isInBankDetails);
void updateCustomerCredit(Partner partner) throws AxelorException;
/**
* Get customer account from accounting situation or account config.
*
* @param partner
* @param company
* @return
*/
Account getCustomerAccount(Partner partner, Company company) throws AxelorException;
/**
* Get supplier account from accounting situation or account config.
*
* @param partner
* @param company
* @return
*/
Account getSupplierAccount(Partner partner, Company company) throws AxelorException;
/**
* Get employee account from accounting situation or account config.
*
* @param partner
* @param company
* @return
*/
Account getEmployeeAccount(Partner partner, Company company) throws AxelorException;
/**
* Return bank details for sales to <code>partner</code> (took from SaleOrder.xml).
*
* @param company
* @param partner
* @return
*/
@CallMethod
BankDetails getCompanySalesBankDetails(Company company, Partner partner);
}

View File

@ -0,0 +1,496 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.AccountType;
import com.axelor.apps.account.db.AccountingSituation;
import com.axelor.apps.account.db.PaymentMode;
import com.axelor.apps.account.db.repo.AccountConfigRepository;
import com.axelor.apps.account.db.repo.AccountRepository;
import com.axelor.apps.account.db.repo.AccountTypeRepository;
import com.axelor.apps.account.db.repo.AccountingSituationRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.app.AppAccountService;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.account.service.payment.PaymentModeService;
import com.axelor.apps.base.db.AppAccount;
import com.axelor.apps.base.db.BankDetails;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.Sequence;
import com.axelor.apps.base.db.repo.AppAccountRepository;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.apps.tool.StringTool;
import com.axelor.common.StringUtils;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class AccountingSituationServiceImpl implements AccountingSituationService {
protected AccountConfigService accountConfigService;
protected SequenceService sequenceService;
protected AccountingSituationRepository accountingSituationRepo;
@Inject
public AccountingSituationServiceImpl(
AccountConfigService accountConfigService,
SequenceService sequenceService,
AccountingSituationRepository accountingSituationRepo) {
this.accountConfigService = accountConfigService;
this.sequenceService = sequenceService;
this.accountingSituationRepo = accountingSituationRepo;
}
@Override
public boolean checkAccountingSituationList(
List<AccountingSituation> accountingSituationList, Company company) {
if (accountingSituationList != null) {
for (AccountingSituation accountingSituation : accountingSituationList) {
if (accountingSituation.getCompany().equals(company)) {
return true;
}
}
}
return false;
}
@Override
@Transactional(rollbackOn = {Exception.class})
public List<AccountingSituation> createAccountingSituation(Partner partner)
throws AxelorException {
Set<Company> companySet = partner.getCompanySet();
if (companySet != null) {
for (Company company : companySet) {
if (!checkAccountingSituationList(partner.getAccountingSituationList(), company)) {
createAccountingSituation(partner, company);
}
}
}
return partner.getAccountingSituationList();
}
@Override
@Transactional(rollbackOn = {Exception.class})
public AccountingSituation createAccountingSituation(Partner partner, Company company)
throws AxelorException {
AccountingSituation accountingSituation = new AccountingSituation();
accountingSituation.setCompany(company);
partner.addCompanySetItem(company);
PaymentMode inPaymentMode = partner.getInPaymentMode();
PaymentMode outPaymentMode = partner.getOutPaymentMode();
BankDetails defaultBankDetails = company.getDefaultBankDetails();
if (inPaymentMode != null) {
List<BankDetails> authorizedInBankDetails =
Beans.get(PaymentModeService.class).getCompatibleBankDetailsList(inPaymentMode, company);
if (authorizedInBankDetails.contains(defaultBankDetails)) {
accountingSituation.setCompanyInBankDetails(defaultBankDetails);
}
}
if (outPaymentMode != null) {
List<BankDetails> authorizedOutBankDetails =
Beans.get(PaymentModeService.class).getCompatibleBankDetailsList(outPaymentMode, company);
if (authorizedOutBankDetails.contains(defaultBankDetails)) {
accountingSituation.setCompanyOutBankDetails(defaultBankDetails);
}
}
Account acc = this.createPartnerAccount(partner, company);
AccountConfig accountConfig = Beans.get(AccountConfigService.class).getAccountConfig(company);
accountingSituation.setInvoiceAutomaticMail(accountConfig.getInvoiceAutomaticMail());
accountingSituation.setInvoiceMessageTemplate(accountConfig.getInvoiceMessageTemplate());
if (acc != null) {
if (partner.getIsCustomer()) {
accountingSituation.setCustomerAccount(acc);
} else if (partner.getIsSupplier()) {
accountingSituation.setSupplierAccount(acc);
}
}
partner.addAccountingSituationListItem(accountingSituation);
return accountingSituationRepo.save(accountingSituation);
}
// sophal creating account
@Transactional
private Account createPartnerAccount(Partner partner, Company company) {
Account sAccount = new Account();
AppAccount appAccount = Beans.get(AppAccountService.class).getAppAccount();
int partnerCode = appAccount.getSupplierCodeSequence() + 1;
appAccount.setSupplierCodeSequence(partnerCode);
String accounString = "Fournisseurs";
if (partner.getIsCustomer()) {
accounString = "Clients";
partnerCode = appAccount.getClientCodeSequence() + 1;
appAccount.setClientCodeSequence(partnerCode);
}
AccountType accountType = Beans.get(AccountTypeRepository.class).findByName(accounString);
Account parenAccount = Beans.get(AccountRepository.class).findByCode("0");
sAccount.setAccountType(accountType);
sAccount.setCode(String.valueOf(partnerCode));
sAccount.setName(partner.getName());
sAccount.setReconcileOk(true);
sAccount.setUseForPartnerBalance(true);
sAccount.setCompany(company);
sAccount.setParentAccount(parenAccount);
Beans.get(AppAccountRepository.class).save(appAccount);
return sAccount;
}
@Override
public AccountingSituation getAccountingSituation(Partner partner, Company company) {
if (partner == null || partner.getAccountingSituationList() == null) {
return null;
}
for (AccountingSituation accountingSituation : partner.getAccountingSituationList()) {
if (accountingSituation.getCompany() != null
&& accountingSituation.getCompany().equals(company)) {
return accountingSituation;
}
}
return null;
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void createPartnerAccounts(AccountingSituation situation) throws AxelorException {
AccountConfig accountConfig = situation.getCompany().getAccountConfig();
int creationMode;
if (accountConfig == null
|| (creationMode = accountConfig.getPartnerAccountGenerationModeSelect())
== AccountConfigRepository.AUTOMATIC_ACCOUNT_CREATION_NONE) {
// Ignore even if account config is null since this means no automatic creation
return;
}
createCustomerAccount(accountConfig, situation, creationMode);
createSupplierAccount(accountConfig, situation, creationMode);
createEmployeeAccount(accountConfig, situation, creationMode);
}
protected void createCustomerAccount(
AccountConfig accountConfig, AccountingSituation situation, int creationMode)
throws AxelorException {
Partner partner = situation.getPartner();
if (partner.getIsCustomer() == Boolean.FALSE || situation.getCustomerAccount() != null) return;
if (accountConfig.getCustomerAccount() == null) {
throw new AxelorException(
partner,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNT_CUSTOMER_1),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
situation.getCompany().getName());
}
final String accountCode;
if (creationMode == AccountConfigRepository.AUTOMATIC_ACCOUNT_CREATION_PREFIX) {
final String prefix = accountConfig.getCustomerAccountPrefix();
if (StringUtils.isBlank(prefix)) {
throw new AxelorException(
situation,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNTING_SITUATION_1),
situation.getCompany().getName());
}
accountCode = getPrefixedAccountCode(prefix, partner);
} else if (creationMode == AccountConfigRepository.AUTOMATIC_ACCOUNT_CREATION_SEQUENCE) {
final Sequence sequence = accountConfig.getCustomerAccountSequence();
if (sequence == null) {
throw new AxelorException(
situation,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNTING_SITUATION_2),
situation.getCompany().getName());
}
accountCode = sequenceService.getSequenceNumber(sequence);
} else {
throw new AxelorException(
situation,
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.ACCOUNTING_SITUATION_3),
situation.getCompany().getName());
}
Account account = new Account();
account.setName(partner.getFullName());
account.setCode(accountCode);
account.setParentAccount(accountConfig.getCustomerAccount());
account.setAccountType(accountConfig.getCustomerAccount().getAccountType());
account.setReconcileOk(true);
account.setCompany(situation.getCompany());
account.setUseForPartnerBalance(true);
account.setCompatibleAccountSet(new HashSet<>());
situation.setCustomerAccount(account);
}
protected void createSupplierAccount(
AccountConfig accountConfig, AccountingSituation situation, int creationMode)
throws AxelorException {
Partner partner = situation.getPartner();
if (partner.getIsSupplier() == Boolean.FALSE || situation.getSupplierAccount() != null) return;
if (accountConfig.getSupplierAccount() == null) {
throw new AxelorException(
partner,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNT_CUSTOMER_2),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
situation.getCompany().getName());
}
final String accountCode;
if (creationMode == AccountConfigRepository.AUTOMATIC_ACCOUNT_CREATION_PREFIX) {
final String prefix = accountConfig.getSupplierAccountPrefix();
if (StringUtils.isBlank(prefix)) {
throw new AxelorException(
situation,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNTING_SITUATION_4),
situation.getCompany().getName());
}
accountCode = getPrefixedAccountCode(prefix, partner);
} else if (creationMode == AccountConfigRepository.AUTOMATIC_ACCOUNT_CREATION_SEQUENCE) {
final Sequence sequence = accountConfig.getSupplierAccountSequence();
if (sequence == null) {
throw new AxelorException(
situation,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNTING_SITUATION_5),
situation.getCompany().getName());
}
accountCode = sequenceService.getSequenceNumber(sequence);
} else {
throw new AxelorException(
situation,
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.ACCOUNTING_SITUATION_3),
situation.getCompany().getName());
}
Account account = new Account();
account.setName(partner.getFullName());
account.setCode(accountCode);
account.setParentAccount(accountConfig.getSupplierAccount());
account.setAccountType(accountConfig.getSupplierAccount().getAccountType());
account.setReconcileOk(true);
account.setCompany(situation.getCompany());
account.setUseForPartnerBalance(true);
account.setCompatibleAccountSet(new HashSet<>());
situation.setSupplierAccount(account);
}
protected void createEmployeeAccount(
AccountConfig accountConfig, AccountingSituation situation, int creationMode)
throws AxelorException {
Partner partner = situation.getPartner();
if (partner.getIsEmployee() == Boolean.FALSE || situation.getEmployeeAccount() != null) return;
if (accountConfig.getEmployeeAccount() == null) {
throw new AxelorException(
partner,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNT_CONFIG_40),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
situation.getCompany().getName());
}
final String accountCode;
if (creationMode == AccountConfigRepository.AUTOMATIC_ACCOUNT_CREATION_PREFIX) {
final String prefix = accountConfig.getEmployeeAccountPrefix();
if (StringUtils.isBlank(prefix)) {
throw new AxelorException(
situation,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNTING_SITUATION_6),
situation.getCompany().getName());
}
accountCode = getPrefixedAccountCode(prefix, partner);
} else if (creationMode == AccountConfigRepository.AUTOMATIC_ACCOUNT_CREATION_SEQUENCE) {
final Sequence sequence = accountConfig.getEmployeeAccountSequence();
if (sequence == null) {
throw new AxelorException(
situation,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNTING_SITUATION_7),
situation.getCompany().getName());
}
accountCode = sequenceService.getSequenceNumber(sequence);
} else {
throw new AxelorException(
situation,
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.ACCOUNTING_SITUATION_3),
situation.getCompany().getName());
}
Account account = new Account();
account.setName(partner.getFullName());
account.setCode(accountCode);
account.setParentAccount(accountConfig.getEmployeeAccount());
account.setAccountType(accountConfig.getEmployeeAccount().getAccountType());
account.setReconcileOk(true);
account.setCompany(situation.getCompany());
account.setUseForPartnerBalance(true);
account.setCompatibleAccountSet(new HashSet<>());
situation.setEmployeeAccount(account);
}
/**
* Normalize partner's fullname to be usable as an account name. Name is appended to prefix, then
* uppercased and unaccented
*
* @param prefix Prefix to prepend to the generated account code
* @param partner Partner to generate account code for
* @return The generated account code.
*/
protected String getPrefixedAccountCode(String prefix, Partner partner) {
return (prefix + StringUtils.stripAccent(partner.getFullName()))
.toUpperCase()
.replaceAll("[^A-Z]", "");
}
/**
* Creates the domain for the bank details in Accounting Situation
*
* @param accountingSituation
* @param isInBankDetails true if the field is companyInBankDetails false if the field is
* companyOutBankDetails
* @return the domain of the bank details field
*/
@Override
public String createDomainForBankDetails(
AccountingSituation accountingSituation, boolean isInBankDetails) {
String domain = "";
List<BankDetails> authorizedBankDetails;
if (accountingSituation.getPartner() != null) {
if (isInBankDetails) {
authorizedBankDetails =
Beans.get(PaymentModeService.class)
.getCompatibleBankDetailsList(
accountingSituation.getPartner().getInPaymentMode(),
accountingSituation.getCompany());
} else {
authorizedBankDetails =
Beans.get(PaymentModeService.class)
.getCompatibleBankDetailsList(
accountingSituation.getPartner().getOutPaymentMode(),
accountingSituation.getCompany());
}
String idList = StringTool.getIdListString(authorizedBankDetails);
if (idList.equals("")) {
return domain;
}
domain = "self.id IN (" + idList + ") AND self.active = true";
}
return domain;
}
@Override
public void updateCustomerCredit(Partner partner) throws AxelorException {
// Nothing to do if the supplychain module is not loaded.
}
@Override
public Account getCustomerAccount(Partner partner, Company company) throws AxelorException {
Account account = null;
AccountingSituation accountingSituation = getAccountingSituation(partner, company);
if (accountingSituation != null) {
account = accountingSituation.getCustomerAccount();
}
if (account == null) {
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
account = accountConfigService.getCustomerAccount(accountConfig);
}
return account;
}
@Override
public Account getSupplierAccount(Partner partner, Company company) throws AxelorException {
Account account = null;
AccountingSituation accountingSituation = getAccountingSituation(partner, company);
if (accountingSituation != null) {
account = accountingSituation.getSupplierAccount();
}
if (account == null) {
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
account = accountConfigService.getSupplierAccount(accountConfig);
}
return account;
}
@Override
public Account getEmployeeAccount(Partner partner, Company company) throws AxelorException {
Account account = null;
AccountingSituation accountingSituation = getAccountingSituation(partner, company);
if (accountingSituation != null) {
account = accountingSituation.getEmployeeAccount();
}
if (account == null) {
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
account = accountConfigService.getEmployeeAccount(accountConfig);
}
return account;
}
@Override
public BankDetails getCompanySalesBankDetails(Company company, Partner partner) {
AccountingSituation situation = getAccountingSituation(partner, company);
if (situation != null
&& situation.getCompanyInBankDetails() != null
&& situation.getCompanyInBankDetails().getActive()) {
return situation.getCompanyInBankDetails();
}
return company.getDefaultBankDetails();
}
}

View File

@ -0,0 +1,34 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.Umr;
import com.axelor.apps.base.service.AddressServiceImpl;
import com.axelor.db.JPA;
public class AddressServiceAccountImpl extends AddressServiceImpl {
static {
registerCheckUsedFunc(AddressServiceAccountImpl::checkAddressUsedAccount);
}
private static boolean checkAddressUsedAccount(Long addressId) {
return JPA.all(Invoice.class).filter("self.address.id = ?1", addressId).fetchOne() != null
|| JPA.all(Umr.class).filter("self.debtorAddress.id = ?1", addressId).fetchOne() != null;
}
}

View File

@ -0,0 +1,46 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.AnalyticDistributionLine;
import com.axelor.apps.account.db.AnalyticDistributionTemplate;
import com.axelor.apps.account.db.AnalyticMoveLine;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.Product;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
public interface AnalyticMoveLineService {
public BigDecimal computeAmount(AnalyticMoveLine analyticMoveLine);
public List<AnalyticMoveLine> generateLines(
AnalyticDistributionTemplate analyticDistributionTemplate,
BigDecimal total,
int typeSelect,
LocalDate date);
public AnalyticDistributionTemplate getAnalyticDistributionTemplate(
Partner partner, Product product, Company company);
public void updateAnalyticMoveLine(
AnalyticMoveLine analyticMoveLine, BigDecimal total, LocalDate date);
public boolean validateLines(List<AnalyticDistributionLine> analyticDistributionLineList);
}

View File

@ -0,0 +1,156 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.AnalyticAxis;
import com.axelor.apps.account.db.AnalyticDistributionLine;
import com.axelor.apps.account.db.AnalyticDistributionTemplate;
import com.axelor.apps.account.db.AnalyticJournal;
import com.axelor.apps.account.db.AnalyticMoveLine;
import com.axelor.apps.account.service.app.AppAccountService;
import com.axelor.apps.base.db.AppAccount;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.Product;
import com.axelor.apps.base.db.repo.AppAccountRepository;
import com.google.inject.Inject;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class AnalyticMoveLineServiceImpl implements AnalyticMoveLineService {
protected AppAccountService appAccountService;
protected AccountManagementServiceAccountImpl accountManagementServiceAccountImpl;
@Inject
public AnalyticMoveLineServiceImpl(
AppAccountService appAccountService,
AccountManagementServiceAccountImpl accountManagementServiceAccountImpl) {
this.appAccountService = appAccountService;
this.accountManagementServiceAccountImpl = accountManagementServiceAccountImpl;
}
@Override
public BigDecimal computeAmount(AnalyticMoveLine analyticMoveLine) {
return analyticMoveLine
.getPercentage()
.multiply(analyticMoveLine.getOriginalPieceAmount())
.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
}
@Override
public List<AnalyticMoveLine> generateLines(
AnalyticDistributionTemplate analyticDistributionTemplate,
BigDecimal total,
int typeSelect,
LocalDate date) {
List<AnalyticMoveLine> analyticMoveLineList = new ArrayList<AnalyticMoveLine>();
if (analyticDistributionTemplate != null) {
for (AnalyticDistributionLine analyticDistributionLine :
analyticDistributionTemplate.getAnalyticDistributionLineList()) {
analyticMoveLineList.add(
this.createAnalyticMoveLine(analyticDistributionLine, total, typeSelect, date));
}
}
return analyticMoveLineList;
}
@Override
public AnalyticDistributionTemplate getAnalyticDistributionTemplate(
Partner partner, Product product, Company company) {
AppAccount appAccount = appAccountService.getAppAccount();
if (appAccount.getAnalyticDistributionTypeSelect()
== AppAccountRepository.DISTRIBUTION_TYPE_PARTNER
&& partner != null) {
return partner.getAnalyticDistributionTemplate();
} else if (appAccount.getAnalyticDistributionTypeSelect()
== AppAccountRepository.DISTRIBUTION_TYPE_PRODUCT) {
return accountManagementServiceAccountImpl.getAnalyticDistributionTemplate(product, company);
}
return null;
}
public AnalyticMoveLine createAnalyticMoveLine(
AnalyticDistributionLine analyticDistributionLine,
BigDecimal total,
int typeSelect,
LocalDate date) {
AnalyticMoveLine analyticMoveLine = new AnalyticMoveLine();
analyticMoveLine.setOriginalPieceAmount(total);
analyticMoveLine.setAnalyticAccount(analyticDistributionLine.getAnalyticAccount());
analyticMoveLine.setAnalyticAxis(analyticDistributionLine.getAnalyticAxis());
analyticMoveLine.setAnalyticJournal(analyticDistributionLine.getAnalyticJournal());
AnalyticJournal analyticJournal = analyticDistributionLine.getAnalyticJournal();
Company company = analyticJournal == null ? null : analyticJournal.getCompany();
if (company != null) {
analyticMoveLine.setCurrency(company.getCurrency());
}
analyticMoveLine.setDate(date);
analyticMoveLine.setPercentage(analyticDistributionLine.getPercentage());
analyticMoveLine.setAmount(computeAmount(analyticMoveLine));
analyticMoveLine.setTypeSelect(typeSelect);
return analyticMoveLine;
}
@Override
public void updateAnalyticMoveLine(
AnalyticMoveLine analyticMoveLine, BigDecimal total, LocalDate date) {
analyticMoveLine.setOriginalPieceAmount(total);
analyticMoveLine.setAmount(computeAmount(analyticMoveLine));
analyticMoveLine.setDate(date);
}
@Override
public boolean validateLines(List<AnalyticDistributionLine> analyticDistributionLineList) {
if (analyticDistributionLineList != null) {
Map<AnalyticAxis, BigDecimal> map = new HashMap<AnalyticAxis, BigDecimal>();
for (AnalyticDistributionLine analyticDistributionLine : analyticDistributionLineList) {
if (map.containsKey(analyticDistributionLine.getAnalyticAxis())) {
map.put(
analyticDistributionLine.getAnalyticAxis(),
map.get(analyticDistributionLine.getAnalyticAxis())
.add(analyticDistributionLine.getPercentage()));
} else {
map.put(
analyticDistributionLine.getAnalyticAxis(), analyticDistributionLine.getPercentage());
}
}
for (AnalyticAxis analyticAxis : map.keySet()) {
if (map.get(analyticAxis).compareTo(new BigDecimal(100)) > 0) {
return false;
}
}
}
return true;
}
}

View File

@ -0,0 +1,210 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.AccountManagement;
import com.axelor.apps.account.db.AccountingSituation;
import com.axelor.apps.account.db.PaymentMode;
import com.axelor.apps.account.db.repo.InvoiceRepository;
import com.axelor.apps.account.db.repo.PaymentModeRepository;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.account.service.payment.PaymentModeService;
import com.axelor.apps.base.db.BankDetails;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.repo.PartnerRepository;
import com.axelor.apps.base.service.BankDetailsServiceImpl;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.tool.StringTool;
import com.axelor.exception.AxelorException;
import com.axelor.inject.Beans;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class BankDetailsServiceAccountImpl extends BankDetailsServiceImpl {
/**
* In this implementation, we use the O2M in payment mode.
*
* @param company
* @param paymentMode
* @return
* @throws AxelorException
*/
@Override
public String createCompanyBankDetailsDomain(
Partner partner, Company company, PaymentMode paymentMode, Integer operationTypeSelect)
throws AxelorException {
if (!Beans.get(AppBaseService.class).getAppBase().getManageMultiBanks()) {
return super.createCompanyBankDetailsDomain(
partner, company, paymentMode, operationTypeSelect);
} else {
if (partner != null) {
partner = Beans.get(PartnerRepository.class).find(partner.getId());
}
List<BankDetails> authorizedBankDetails = new ArrayList<>();
if (partner != null
&& partner.getFactorizedCustomer()
&& operationTypeSelect != null
&& (operationTypeSelect.intValue() == InvoiceRepository.OPERATION_TYPE_CLIENT_SALE
|| operationTypeSelect.intValue()
== InvoiceRepository.OPERATION_TYPE_CLIENT_REFUND)) {
authorizedBankDetails = createCompanyBankDetailsDomainFromFactorPartner(company);
} else {
if (paymentMode == null) {
return "self.id IN (0)";
}
List<AccountManagement> accountManagementList = paymentMode.getAccountManagementList();
authorizedBankDetails = new ArrayList<>();
for (AccountManagement accountManagement : accountManagementList) {
if (accountManagement.getCompany() != null
&& accountManagement.getCompany().equals(company)) {
authorizedBankDetails.add(accountManagement.getBankDetails());
}
}
}
if (authorizedBankDetails.isEmpty()) {
return "self.id IN (0)";
} else {
return "self.id IN ("
+ StringTool.getIdListString(authorizedBankDetails)
+ ") AND self.active = true";
}
}
}
private List<BankDetails> createCompanyBankDetailsDomainFromFactorPartner(Company company)
throws AxelorException {
AccountConfig accountConfig = Beans.get(AccountConfigService.class).getAccountConfig(company);
List<BankDetails> bankDetailsList = accountConfig.getFactorPartner().getBankDetailsList();
return bankDetailsList
.stream()
.filter(bankDetails -> bankDetails.getActive())
.collect(Collectors.toList());
}
/**
* Find a default bank details.
*
* @param company
* @param paymentMode
* @param partner
* @return the default bank details in accounting situation if it is active and allowed by the
* payment mode, or an authorized bank details if he is the only one authorized.
* @throws AxelorException
*/
@Override
public BankDetails getDefaultCompanyBankDetails(
Company company, PaymentMode paymentMode, Partner partner, Integer operationTypeSelect)
throws AxelorException {
if (!Beans.get(AppBaseService.class).getAppBase().getManageMultiBanks()) {
return super.getDefaultCompanyBankDetails(company, paymentMode, partner, operationTypeSelect);
} else {
if (partner != null
&& partner.getFactorizedCustomer()
&& operationTypeSelect != null
&& (operationTypeSelect.intValue() == InvoiceRepository.OPERATION_TYPE_CLIENT_SALE
|| operationTypeSelect.intValue()
== InvoiceRepository.OPERATION_TYPE_CLIENT_REFUND)) {
return getDefaultCompanyBankDetailsFromFactorPartner(company);
} else {
if (paymentMode == null) {
return null;
}
BankDetails candidateBankDetails =
getDefaultCompanyBankDetailsFromPartner(company, paymentMode, partner);
List<BankDetails> authorizedBankDetails =
Beans.get(PaymentModeService.class).getCompatibleBankDetailsList(paymentMode, company);
if (candidateBankDetails != null
&& authorizedBankDetails.contains(candidateBankDetails)
&& candidateBankDetails.getActive()) {
return candidateBankDetails;
}
// we did not find a bank details in accounting situation
else {
if (authorizedBankDetails.size() == 1) {
return authorizedBankDetails.get(0);
}
}
}
return null;
}
}
private BankDetails getDefaultCompanyBankDetailsFromFactorPartner(Company company)
throws AxelorException {
AccountConfig accountConfig = Beans.get(AccountConfigService.class).getAccountConfig(company);
if (accountConfig.getFactorPartner() == null) {
return null;
}
List<BankDetails> bankDetailsList = accountConfig.getFactorPartner().getBankDetailsList();
return bankDetailsList
.stream()
.filter(bankDetails -> bankDetails.getIsDefault())
.findFirst()
.orElse(null);
}
/**
* Looks for the bank details in accounting situation.
*
* @param company
* @param paymentMode
* @param partner
* @return The bank details corresponding to the partner and the company with the right payment
* mode null if the partner is null or the accounting situation empty
*/
protected BankDetails getDefaultCompanyBankDetailsFromPartner(
Company company, PaymentMode paymentMode, Partner partner) {
if (partner == null) {
return null;
}
AccountingSituation accountingSituation =
Beans.get(AccountingSituationService.class).getAccountingSituation(partner, company);
if (accountingSituation == null) {
return null;
}
BankDetails candidateBankDetails = null;
if (paymentMode.getInOutSelect() == PaymentModeRepository.IN) {
candidateBankDetails = accountingSituation.getCompanyInBankDetails();
} else if (paymentMode.getInOutSelect() == PaymentModeRepository.OUT) {
candidateBankDetails = accountingSituation.getCompanyOutBankDetails();
}
return candidateBankDetails;
}
}

View File

@ -0,0 +1,238 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Budget;
import com.axelor.apps.account.db.BudgetDistribution;
import com.axelor.apps.account.db.BudgetLine;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.InvoiceLine;
import com.axelor.apps.account.db.repo.BudgetDistributionRepository;
import com.axelor.apps.account.db.repo.BudgetLineRepository;
import com.axelor.apps.account.db.repo.BudgetRepository;
import com.axelor.apps.account.db.repo.InvoiceRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class BudgetService {
protected BudgetLineRepository budgetLineRepository;
protected BudgetRepository budgetRepository;
@Inject
public BudgetService(
BudgetLineRepository budgetLineRepository, BudgetRepository budgetRepository) {
this.budgetLineRepository = budgetLineRepository;
this.budgetRepository = budgetRepository;
}
public BigDecimal compute(Budget budget) {
BigDecimal total = BigDecimal.ZERO;
if (budget.getBudgetLineList() != null) {
for (BudgetLine budgetLine : budget.getBudgetLineList()) {
total = total.add(budgetLine.getAmountExpected());
}
}
return total;
}
@Transactional
public BigDecimal computeTotalAmountRealized(Budget budget) {
List<BudgetLine> budgetLineList = budget.getBudgetLineList();
if (budgetLineList == null) {
return BigDecimal.ZERO;
}
BigDecimal totalAmountRealized =
budgetLineList
.stream()
.map(BudgetLine::getAmountRealized)
.reduce(BigDecimal.ZERO, BigDecimal::add);
budget.setTotalAmountRealized(totalAmountRealized);
return totalAmountRealized;
}
@Transactional
public List<BudgetLine> updateLines(Budget budget) {
if (budget.getBudgetLineList() != null && !budget.getBudgetLineList().isEmpty()) {
for (BudgetLine budgetLine : budget.getBudgetLineList()) {
budgetLine.setAmountRealized(BigDecimal.ZERO);
}
List<BudgetDistribution> budgetDistributionList =
Beans.get(BudgetDistributionRepository.class)
.all()
.filter(
"self.budget.id = ?1 AND (self.invoiceLine.invoice.statusSelect = ?2 OR self.invoiceLine.invoice.statusSelect = ?3)",
budget.getId(),
InvoiceRepository.STATUS_VALIDATED,
InvoiceRepository.STATUS_VENTILATED)
.fetch();
for (BudgetDistribution budgetDistribution : budgetDistributionList) {
Optional<LocalDate> optionaldate = getDate(budgetDistribution);
optionaldate.ifPresent(
date -> {
for (BudgetLine budgetLine : budget.getBudgetLineList()) {
LocalDate fromDate = budgetLine.getFromDate();
LocalDate toDate = budgetLine.getToDate();
if ((fromDate.isBefore(date) || fromDate.isEqual(date))
&& (toDate.isAfter(date) || toDate.isEqual(date))) {
budgetLine.setAmountRealized(
budgetLine.getAmountRealized().add(budgetDistribution.getAmount()));
break;
}
}
});
}
}
return budget.getBudgetLineList();
}
/**
* @param budgetDistribution
* @return returns an {@code Optional} because in some cases the child implementations can return
* a null value.
*/
protected Optional<LocalDate> getDate(BudgetDistribution budgetDistribution) {
Invoice invoice = budgetDistribution.getInvoiceLine().getInvoice();
LocalDate invoiceDate = invoice.getInvoiceDate();
if (invoiceDate != null) {
return Optional.of(invoiceDate);
}
return Optional.of(invoice.getValidatedDate());
}
public List<BudgetLine> generatePeriods(Budget budget) throws AxelorException {
if (budget.getBudgetLineList() != null && !budget.getBudgetLineList().isEmpty()) {
List<BudgetLine> budgetLineList = budget.getBudgetLineList();
budgetLineList.clear();
}
List<BudgetLine> budgetLineList = new ArrayList<BudgetLine>();
Integer duration = budget.getPeriodDurationSelect();
LocalDate fromDate = budget.getFromDate();
LocalDate toDate = budget.getToDate();
LocalDate budgetLineToDate = fromDate;
Integer budgetLineNumber = 1;
int c = 0;
int loopLimit = 1000;
while (budgetLineToDate.isBefore(toDate)) {
if (budgetLineNumber != 1) fromDate = fromDate.plusMonths(duration);
if (c >= loopLimit) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY, I18n.get(IExceptionMessage.BUDGET_1));
}
c += 1;
budgetLineToDate = fromDate.plusMonths(duration).minusDays(1);
if (budgetLineToDate.isAfter(toDate)) budgetLineToDate = toDate;
if (fromDate.isAfter(toDate)) continue;
BudgetLine budgetLine = new BudgetLine();
budgetLine.setFromDate(fromDate);
budgetLine.setToDate(budgetLineToDate);
budgetLine.setBudget(budget);
budgetLine.setAmountExpected(budget.getAmountForGeneration());
budgetLineList.add(budgetLine);
budgetLineNumber++;
}
return budgetLineList;
}
public void checkSharedDates(Budget budget) throws AxelorException {
if (budget.getBudgetLineList() == null) {
return;
}
List<BudgetLine> budgetLineList = budget.getBudgetLineList();
for (int i = 0; i < budgetLineList.size() - 1; i++) {
BudgetLine budgetLineA = budgetLineList.get(i);
LocalDate fromDateA = budgetLineA.getFromDate();
LocalDate toDateA = budgetLineA.getToDate();
for (int j = i + 1; j < budgetLineList.size(); j++) {
BudgetLine budgetLineB = budgetLineList.get(j);
LocalDate fromDateB = budgetLineB.getFromDate();
LocalDate toDateB = budgetLineB.getToDate();
if (fromDateA.equals(fromDateB) || toDateA.equals(toDateB)) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get("Two or more budget lines share dates"));
}
if (fromDateA.isBefore(fromDateB) && (!toDateA.isBefore(fromDateB))) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get("Two or more budget lines share dates"));
}
if (fromDateA.isAfter(fromDateB) && (!fromDateA.isAfter(toDateB))) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get("Two or more budget lines share dates"));
}
}
}
}
@Transactional
public void validate(Budget budget) {
budget.setStatusSelect(BudgetRepository.STATUS_VALIDATED);
}
@Transactional
public void draft(Budget budget) {
budget.setStatusSelect(BudgetRepository.STATUS_DRAFT);
}
public void updateBudgetLinesFromInvoice(Invoice invoice) {
List<InvoiceLine> invoiceLineList = invoice.getInvoiceLineList();
if (invoiceLineList == null) {
return;
}
invoiceLineList
.stream()
.filter(invoiceLine -> invoiceLine.getBudgetDistributionList() != null)
.flatMap(x -> x.getBudgetDistributionList().stream())
.forEach(
budgetDistribution -> {
Budget budget = budgetDistribution.getBudget();
updateLines(budget);
computeTotalAmountRealized(budget);
});
}
}

View File

@ -0,0 +1,150 @@
package com.axelor.apps.account.service;
import com.axelor.apps.account.db.CashInventory;
import com.axelor.apps.account.db.CashInventoryLine;
import com.axelor.apps.account.db.CashRegister;
import com.axelor.apps.account.db.repo.CashDenominationRepository;
import com.axelor.apps.account.db.repo.CashInventoryRepository;
import com.axelor.apps.account.db.repo.CashRegisterRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.auth.AuthUtils;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CashInventoryService {
private SequenceService sequenceService;
@Inject
public CashInventoryService(SequenceService sequenceService) {
this.sequenceService = sequenceService;
}
/**
* Initialize the theorical solde in words for a new cash inventory.
*
* @return the theorical solde in words as a BigDecimal
*/
public BigDecimal initThetoricalSolde() {
CashRegisterRepository casRegisterRepository = Beans.get(CashRegisterRepository.class);
CashRegister cashRegister = casRegisterRepository.all().order("-createdOn").fetchOne();
BigDecimal theoricalSolde = BigDecimal.ZERO;
if (cashRegister == null) {
theoricalSolde = BigDecimal.ZERO;
} else {
theoricalSolde = cashRegister.getTheoricalSolde();
}
return theoricalSolde;
}
/**
* Computes the totals for the cash inventory, including total bank notes, total
* coins, physical
* solde, and gap.
*
* @param cashInventory The cash inventory to compute totals for.
* @return A map containing the computed totals.
*/
public Map<String, BigDecimal> computeToTals(CashInventory cashInventory) {
HashMap<String, BigDecimal> map = new HashMap<>();
List<CashInventoryLine> cashInventoryLines = cashInventory.getCashInventoryLines();
BigDecimal theoricalSolde = cashInventory.getTheoricalSolde();
BigDecimal totalBankNotes = BigDecimal.ZERO;
BigDecimal totalCoins = BigDecimal.ZERO;
BigDecimal physicalSolde = BigDecimal.ZERO;
BigDecimal gap = BigDecimal.ZERO;
for (CashInventoryLine cashInventoryLine : cashInventoryLines) {
switch (cashInventoryLine.getCashDenomination().getTypeSelect()) {
case CashDenominationRepository.BANK_NOTE_TYPE:
totalBankNotes = totalBankNotes.add(cashInventoryLine.getTotalCashCount());
break;
case CashDenominationRepository.COINT_TYPE:
totalCoins = totalCoins.add(cashInventoryLine.getTotalCashCount());
break;
default:
totalBankNotes = BigDecimal.ZERO;
totalCoins = BigDecimal.ZERO;
break;
}
}
physicalSolde = physicalSolde.add(totalBankNotes).add(totalCoins);
gap = physicalSolde.subtract(theoricalSolde);
map.put("totalCoinsAmount", totalCoins);
map.put("totalBankNotesAmount", totalBankNotes);
map.put("totalCash", totalBankNotes);
map.put("physicalSolde", physicalSolde);
map.put("gap", gap);
return map;
}
public String getCashInventorySequence(CashInventory cashInventory) throws AxelorException {
Integer operationTypeSelect = cashInventory.getOperationTypeSelect();
Company company = cashInventory.getCompany();
String sequence = null;
if (operationTypeSelect != null) {
switch (operationTypeSelect) {
case 1: // Cash inventory daily
sequence = "CASH_INVENTORY_DAILY";
break;
case 2: // Cash inventory monthly
sequence = "CASH_INVENTORY_MONTHLY";
break;
case 3: // Cash inventory annual
sequence = "CASH_INVENTORY_ANNUAL";
break;
default:
sequence = "CASH_INVENTORY";
// Default case for other operation types
break;
}
} else {
sequence = "CASH_INVENTORY";
}
String ref = sequenceService.getSequenceNumber(sequence, company);
if (ref == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.CASH_INVENTORY_MISSING_SEQUENCE),
company.getName());
} else {
return ref;
}
}
@Transactional(rollbackOn = {Exception.class})
public void approveCashInventory(CashInventory cashInventory) {
CashRegisterRepository casRegisterRepository = Beans.get(CashRegisterRepository.class);
CashRegister cashRegister = casRegisterRepository.all().order("-createdOn").fetchOne();
// cashRegister.setTheoricalSolde(cashInventory.getPhysicalSolde());
cashRegister.setPhysicalSolde(cashInventory.getPhysicalSolde());
cashInventory.setValdiatedByUser(AuthUtils.getUser());
cashInventory.setValidattionDate(LocalDateTime.now());
cashInventory.setStatusSelect(3);
Beans.get(CashInventoryRepository.class).save(cashInventory);
casRegisterRepository.save(cashRegister);
}
}

View File

@ -0,0 +1,214 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.ChequeRejection;
import com.axelor.apps.account.db.InterbankCodeLine;
import com.axelor.apps.account.db.Journal;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.PaymentVoucher;
import com.axelor.apps.account.db.repo.ChequeRejectionRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.account.service.move.MoveLineService;
import com.axelor.apps.account.service.move.MoveService;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.repo.SequenceRepository;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
public class ChequeRejectionService {
protected MoveService moveService;
protected MoveLineService moveLineService;
protected SequenceService sequenceService;
protected AccountConfigService accountConfigService;
protected ChequeRejectionRepository chequeRejectionRepository;
@Inject
public ChequeRejectionService(
MoveService moveService,
MoveLineService moveLineService,
SequenceService sequenceService,
AccountConfigService accountConfigService,
ChequeRejectionRepository chequeRejectionRepository) {
this.moveService = moveService;
this.moveLineService = moveLineService;
this.sequenceService = sequenceService;
this.accountConfigService = accountConfigService;
this.chequeRejectionRepository = chequeRejectionRepository;
}
/**
* procédure de validation du rejet de chèque
*
* @param chequeRejection Un rejet de chèque brouillon
* @throws AxelorException
*/
@Transactional(rollbackOn = {Exception.class})
public void validateChequeRejection(ChequeRejection chequeRejection) throws AxelorException {
Company company = chequeRejection.getCompany();
this.testCompanyField(company);
this.setSequence(chequeRejection);
Move move = this.createChequeRejectionMove(chequeRejection, company);
chequeRejection.setMove(move);
chequeRejection.setStatusSelect(ChequeRejectionRepository.STATUS_VALIDATED);
chequeRejectionRepository.save(chequeRejection);
}
/**
* Méthode permettant de créer une écriture de rejet de chèque (L'extourne de l'écriture de
* paiement)
*
* @param chequeRejection Un rejet de cheque brouillon
* @param company Une société
* @return L'écriture de rejet de chèque
* @throws AxelorException
*/
public Move createChequeRejectionMove(ChequeRejection chequeRejection, Company company)
throws AxelorException {
this.testCompanyField(company);
Journal journal = company.getAccountConfig().getRejectJournal();
PaymentVoucher paymentVoucher = chequeRejection.getPaymentVoucher();
Move paymentMove = paymentVoucher.getGeneratedMove();
Partner partner = paymentVoucher.getPartner();
InterbankCodeLine interbankCodeLine = chequeRejection.getInterbankCodeLine();
String description = chequeRejection.getDescription();
LocalDate rejectionDate = chequeRejection.getRejectionDate();
// Move
Move move =
moveService
.getMoveCreateService()
.createMove(
journal,
company,
null,
partner,
rejectionDate,
null,
MoveRepository.TECHNICAL_ORIGIN_AUTOMATIC);
int ref = 1;
for (MoveLine moveLine : paymentMove.getMoveLineList()) {
if (moveLine.getCredit().compareTo(BigDecimal.ZERO) > 0) {
// Debit MoveLine
MoveLine debitMoveLine =
moveLineService.createMoveLine(
move,
partner,
moveLine.getAccount(),
moveLine.getCredit(),
true,
rejectionDate,
ref,
chequeRejection.getName(),
chequeRejection.getDescription());
move.getMoveLineList().add(debitMoveLine);
debitMoveLine.setInterbankCodeLine(interbankCodeLine);
debitMoveLine.setDescription(description);
} else {
// Credit MoveLine
MoveLine creditMoveLine =
moveLineService.createMoveLine(
move,
partner,
moveLine.getAccount(),
moveLine.getDebit(),
false,
rejectionDate,
ref,
chequeRejection.getName(),
chequeRejection.getDescription());
move.getMoveLineList().add(creditMoveLine);
creditMoveLine.setInterbankCodeLine(interbankCodeLine);
creditMoveLine.setDescription(description);
}
ref++;
}
move.setRejectOk(true);
moveService.getMoveValidateService().validate(move);
return move;
}
/**
* Procédure permettant de vérifier les champs d'une société
*
* @param company Une société
* @throws AxelorException
*/
public void testCompanyField(Company company) throws AxelorException {
accountConfigService.getRejectJournal(accountConfigService.getAccountConfig(company));
}
/**
* Procédure permettant d'assigner une séquence de rejet de chèque
*
* @param chequeRejection Un rejet de chèque
* @throws AxelorException
*/
public void setSequence(ChequeRejection chequeRejection) throws AxelorException {
String seq =
sequenceService.getSequenceNumber(
SequenceRepository.CHEQUE_REJECT, chequeRejection.getCompany());
if (seq == null) {
throw new AxelorException(
chequeRejection,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.CHECK_REJECTION_1),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
chequeRejection.getCompany().getName());
}
chequeRejection.setName(seq);
}
}

View File

@ -0,0 +1,51 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.DepositSlip;
import com.axelor.exception.AxelorException;
import java.io.IOException;
public interface DepositSlipService {
/**
* Load payments into deposit slip.
*
* @param depositSlip
* @throws AxelorException
*/
void loadPayments(DepositSlip depositSlip) throws AxelorException;
/**
* Publish deposit slip.
*
* @param depositSlip
* @return
* @throws AxelorException
* @throws IOException
*/
String publish(DepositSlip depositSlip) throws AxelorException;
/**
* Get report filename.
*
* @param depositSlip
* @return
* @throws AxelorException
*/
String getFilename(DepositSlip depositSlip) throws AxelorException;
}

View File

@ -0,0 +1,177 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.ReportFactory;
import com.axelor.apps.account.db.DepositSlip;
import com.axelor.apps.account.db.PaymentVoucher;
import com.axelor.apps.account.db.repo.PaymentModeRepository;
import com.axelor.apps.account.db.repo.PaymentVoucherRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.report.IReport;
import com.axelor.apps.account.service.payment.paymentvoucher.PaymentVoucherConfirmService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.report.engine.ReportSettings;
import com.axelor.apps.tool.QueryBuilder;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.util.List;
public class DepositSlipServiceImpl implements DepositSlipService {
@Override
@Transactional(rollbackOn = {Exception.class})
public void loadPayments(DepositSlip depositSlip) throws AxelorException {
if (depositSlip.getPublicationDate() != null) {
throw new AxelorException(
depositSlip,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.DEPOSIT_SLIP_ALREADY_PUBLISHED));
}
depositSlip.clearPaymentVoucherList();
fetchPaymentVouchers(depositSlip).forEach(depositSlip::addPaymentVoucherListItem);
compute(depositSlip);
}
@Override
@Transactional(rollbackOn = {Exception.class})
public String publish(DepositSlip depositSlip) throws AxelorException {
confirmPayments(depositSlip);
ReportSettings settings =
ReportFactory.createReport(getReportName(depositSlip), getFilename(depositSlip));
settings.addParam("DepositSlipId", depositSlip.getId());
settings.addParam("Locale", ReportSettings.getPrintingLocale(null));
settings.addFormat("pdf");
String fileLink = settings.toAttach(depositSlip).generate().getFileLink();
depositSlip.setPublicationDate(Beans.get(AppBaseService.class).getTodayDate());
return fileLink;
}
@Override
public String getFilename(DepositSlip depositSlip) throws AxelorException {
String name;
switch (depositSlip.getPaymentModeTypeSelect()) {
case PaymentModeRepository.TYPE_CHEQUE:
name = I18n.get("Cheque deposit slip");
break;
case PaymentModeRepository.TYPE_CASH:
name = I18n.get("Cash deposit slip");
break;
default:
throw new AxelorException(
depositSlip,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
IExceptionMessage.DEPOSIT_SLIP_UNSUPPORTED_PAYMENT_MODE_TYPE);
}
return String.format("%s - %s", name, depositSlip.getDepositNumber());
}
private String getReportName(DepositSlip depositSlip) throws AxelorException {
switch (depositSlip.getPaymentModeTypeSelect()) {
case PaymentModeRepository.TYPE_CHEQUE:
return IReport.CHEQUE_DEPOSIT_SLIP;
case PaymentModeRepository.TYPE_CASH:
return IReport.CASH_DEPOSIT_SLIP;
default:
throw new AxelorException(
depositSlip,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
IExceptionMessage.DEPOSIT_SLIP_UNSUPPORTED_PAYMENT_MODE_TYPE);
}
}
private void compute(DepositSlip depositSlip) {
if (depositSlip.getPaymentVoucherList() != null) {
List<PaymentVoucher> paymentVoucherList = depositSlip.getPaymentVoucherList();
BigDecimal totalAmount =
paymentVoucherList
.stream()
.map(PaymentVoucher::getPaidAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
depositSlip.setTotalAmount(totalAmount);
depositSlip.setChequeCount(paymentVoucherList.size());
}
}
private List<PaymentVoucher> fetchPaymentVouchers(DepositSlip depositSlip) {
QueryBuilder<PaymentVoucher> queryBuilder = QueryBuilder.of(PaymentVoucher.class);
if (depositSlip.getPaymentModeTypeSelect() != 0) {
queryBuilder.add("self.paymentMode.typeSelect = :paymentModeTypeSelect");
queryBuilder.bind("paymentModeTypeSelect", depositSlip.getPaymentModeTypeSelect());
}
if (depositSlip.getCompany() != null) {
queryBuilder.add("self.company = :company");
queryBuilder.bind("company", depositSlip.getCompany());
}
if (depositSlip.getCurrency() != null) {
queryBuilder.add("self.currency = :currency");
queryBuilder.bind("currency", depositSlip.getCurrency());
}
if (depositSlip.getCompanyBankDetails() != null
&& Beans.get(AppBaseService.class).getAppBase().getManageMultiBanks()) {
queryBuilder.add("self.companyBankDetails = :companyBankDetails");
queryBuilder.bind("companyBankDetails", depositSlip.getCompanyBankDetails());
}
if (depositSlip.getFromDate() != null) {
if (depositSlip.getToDate() != null) {
queryBuilder.add(
"self.chequeDate IS NULL OR self.chequeDate BETWEEN :fromDate AND :toDate");
queryBuilder.bind("fromDate", depositSlip.getFromDate());
queryBuilder.bind("toDate", depositSlip.getToDate());
} else {
queryBuilder.add("self.chequeDate IS NULL OR self.chequeDate >= :fromDate");
queryBuilder.bind("fromDate", depositSlip.getFromDate());
}
} else if (depositSlip.getToDate() != null) {
queryBuilder.add("self.chequeDate IS NULL OR self.chequeDate <= :toDate");
queryBuilder.bind("toDate", depositSlip.getToDate());
}
queryBuilder.add("self.depositSlip IS NULL");
queryBuilder.add("self.statusSelect = :statusSelect");
queryBuilder.bind("statusSelect", PaymentVoucherRepository.STATUS_WAITING_FOR_DEPOSIT_SLIP);
return queryBuilder.build().fetch();
}
private void confirmPayments(DepositSlip depositSlip) throws AxelorException {
if (depositSlip.getPaymentVoucherList() != null) {
PaymentVoucherConfirmService paymentVoucherConfirmService =
Beans.get(PaymentVoucherConfirmService.class);
for (PaymentVoucher paymentVoucher : depositSlip.getPaymentVoucherList()) {
paymentVoucherConfirmService.createMoveAndConfirm(paymentVoucher);
}
}
}
}

View File

@ -0,0 +1,34 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.FiscalPosition;
import com.axelor.apps.base.service.tax.FiscalPositionService;
public interface FiscalPositionAccountService extends FiscalPositionService {
/**
* Replace the account from the fiscal position account equiv list if match the given account
*
* @param fiscalPosition
* @param account
* @return
*/
public Account getAccount(FiscalPosition fiscalPosition, Account account);
}

View File

@ -0,0 +1,42 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountEquiv;
import com.axelor.apps.account.db.FiscalPosition;
import com.axelor.apps.base.service.tax.FiscalPositionServiceImpl;
public class FiscalPositionAccountServiceImpl extends FiscalPositionServiceImpl
implements FiscalPositionAccountService {
@Override
public Account getAccount(FiscalPosition fiscalPosition, Account account) {
if (fiscalPosition != null && fiscalPosition.getAccountEquivList() != null) {
for (AccountEquiv accountEquiv : fiscalPosition.getAccountEquivList()) {
if (accountEquiv.getFromAccount().equals(account) && accountEquiv.getToAccount() != null) {
return accountEquiv.getToAccount();
}
}
}
return account;
}
}

View File

@ -0,0 +1,28 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.FixedAssetLine;
import com.axelor.exception.AxelorException;
public interface FixedAssetLineService {
public void realize(FixedAssetLine fixedAssetLine) throws AxelorException;
public void generateDisposalMove(FixedAssetLine fixedAssetLine) throws AxelorException;
}

View File

@ -0,0 +1,249 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.FixedAsset;
import com.axelor.apps.account.db.FixedAssetLine;
import com.axelor.apps.account.db.Journal;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.repo.FixedAssetLineRepository;
import com.axelor.apps.account.db.repo.FixedAssetRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.service.move.MoveCreateService;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.exception.AxelorException;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FixedAssetLineServiceImpl implements FixedAssetLineService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@Inject private FixedAssetLineRepository fixedAssetLineRepo;
@Inject private MoveCreateService moveCreateService;
@Inject private MoveRepository moveRepo;
@Override
@Transactional(rollbackOn = {Exception.class})
public void realize(FixedAssetLine fixedAssetLine) throws AxelorException {
generateMove(fixedAssetLine);
fixedAssetLine.setStatusSelect(FixedAssetLineRepository.STATUS_REALIZED);
FixedAsset fixedAsset = fixedAssetLine.getFixedAsset();
BigDecimal residualValue = fixedAsset.getResidualValue();
fixedAsset.setResidualValue(residualValue.subtract(fixedAssetLine.getDepreciation()));
FixedAssetLine plannedFixedAssetLine =
fixedAsset
.getFixedAssetLineList()
.stream()
.filter(line -> line.getStatusSelect() == FixedAssetLineRepository.STATUS_PLANNED)
.findAny()
.orElse(null);
if (plannedFixedAssetLine == null
&& fixedAsset.getDisposalValue().compareTo(BigDecimal.ZERO) == 0) {
fixedAsset.setStatusSelect(FixedAssetRepository.STATUS_DEPRECIATED);
}
fixedAssetLineRepo.save(fixedAssetLine);
}
@Transactional(rollbackOn = {Exception.class})
private void generateMove(FixedAssetLine fixedAssetLine) throws AxelorException {
FixedAsset fixedAsset = fixedAssetLine.getFixedAsset();
Journal journal = fixedAsset.getJournal();
Company company = fixedAsset.getCompany();
Partner partner = fixedAsset.getPartner();
LocalDate date = fixedAsset.getAcquisitionDate();
log.debug(
"Creating an fixed asset line specific accounting entry {} (Company : {}, Journal : {})",
new Object[] {fixedAsset.getReference(), company.getName(), journal.getCode()});
// Creating move
Move move =
moveCreateService.createMove(
journal,
company,
company.getCurrency(),
partner,
date,
null,
MoveRepository.TECHNICAL_ORIGIN_AUTOMATIC);
if (move != null) {
List<MoveLine> moveLines = new ArrayList<MoveLine>();
String origin = fixedAsset.getReference();
Account debitLineAccount = fixedAsset.getFixedAssetCategory().getChargeAccount();
Account creditLineAccount = fixedAsset.getFixedAssetCategory().getDepreciationAccount();
BigDecimal amount = fixedAssetLine.getDepreciation();
// Creating accounting debit move line
MoveLine debitMoveLine =
new MoveLine(
move,
partner,
debitLineAccount,
date,
null,
1,
amount,
BigDecimal.ZERO,
fixedAsset.getName(),
origin,
null,
BigDecimal.ZERO,
date);
moveLines.add(debitMoveLine);
// Creating accounting debit move line
MoveLine creditMoveLine =
new MoveLine(
move,
partner,
creditLineAccount,
date,
null,
2,
BigDecimal.ZERO,
amount,
fixedAsset.getName(),
origin,
null,
BigDecimal.ZERO,
date);
moveLines.add(creditMoveLine);
move.getMoveLineList().addAll(moveLines);
}
moveRepo.save(move);
fixedAssetLine.setDepreciationAccountMove(move);
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void generateDisposalMove(FixedAssetLine fixedAssetLine) throws AxelorException {
FixedAsset fixedAsset = fixedAssetLine.getFixedAsset();
Journal journal = fixedAsset.getJournal();
Company company = fixedAsset.getCompany();
Partner partner = fixedAsset.getPartner();
LocalDate date = fixedAsset.getAcquisitionDate();
// Creating move
Move move =
moveCreateService.createMove(
journal,
company,
company.getCurrency(),
partner,
date,
null,
MoveRepository.TECHNICAL_ORIGIN_AUTOMATIC);
if (move != null) {
List<MoveLine> moveLines = new ArrayList<MoveLine>();
String origin = fixedAsset.getReference();
Account chargeAccount = fixedAsset.getFixedAssetCategory().getChargeAccount();
Account depreciationAccount = fixedAsset.getFixedAssetCategory().getDepreciationAccount();
Account purchaseAccount = fixedAsset.getPurchaseAccount();
BigDecimal chargeAmount = fixedAssetLine.getResidualValue();
BigDecimal cumulativeDepreciationAmount = fixedAssetLine.getCumulativeDepreciation();
// Creating accounting debit move line for charge account
MoveLine chargeAccountDebitMoveLine =
new MoveLine(
move,
partner,
chargeAccount,
date,
null,
1,
chargeAmount,
BigDecimal.ZERO,
fixedAsset.getName(),
origin,
null,
BigDecimal.ZERO,
date);
moveLines.add(chargeAccountDebitMoveLine);
// Creating accounting debit move line for deprecation account
MoveLine deprecationAccountDebitMoveLine =
new MoveLine(
move,
partner,
depreciationAccount,
date,
null,
1,
cumulativeDepreciationAmount,
BigDecimal.ZERO,
fixedAsset.getName(),
origin,
null,
BigDecimal.ZERO,
date);
moveLines.add(deprecationAccountDebitMoveLine);
// Creating accounting credit move line
MoveLine creditMoveLine =
new MoveLine(
move,
partner,
purchaseAccount,
date,
null,
2,
BigDecimal.ZERO,
fixedAsset.getGrossValue(),
fixedAsset.getName(),
origin,
null,
BigDecimal.ZERO,
date);
moveLines.add(creditMoveLine);
move.getMoveLineList().addAll(moveLines);
}
moveRepo.save(move);
fixedAsset.setDisposalMove(move);
}
}

View File

@ -0,0 +1,56 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.FixedAsset;
import com.axelor.apps.account.db.Invoice;
import com.axelor.exception.AxelorException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
public interface FixedAssetService {
/**
* Allow to generate and compute the fixed asset lines
*
* @param fixedAsset
* @return
*/
public FixedAsset generateAndcomputeLines(FixedAsset fixedAsset);
/**
* Allow to create fixed asset from invoice
*
* @param invoice
* @return
* @throws AxelorException
*/
public List<FixedAsset> createFixedAssets(Invoice invoice) throws AxelorException;
/**
* Allow to disposal remaining depreciation
*
* @param disposalDate
* @param disposalAmount
* @param fixedAsset
* @throws AxelorException
*/
public void disposal(LocalDate disposalDate, BigDecimal disposalAmount, FixedAsset fixedAsset)
throws AxelorException;
}

View File

@ -0,0 +1,329 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.FixedAsset;
import com.axelor.apps.account.db.FixedAssetLine;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.InvoiceLine;
import com.axelor.apps.account.db.repo.FixedAssetLineRepository;
import com.axelor.apps.account.db.repo.FixedAssetRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
public class FixedAssetServiceImpl implements FixedAssetService {
@Inject FixedAssetRepository fixedAssetRepo;
@Inject FixedAssetLineService fixedAssetLineService;
@Override
public FixedAsset generateAndcomputeLines(FixedAsset fixedAsset) {
BigDecimal depreciationValue = this.computeDepreciationValue(fixedAsset);
BigDecimal cumulativeValue = depreciationValue;
LocalDate depreciationDate = fixedAsset.getFirstDepreciationDate();
LocalDate acquisitionDate = fixedAsset.getAcquisitionDate();
int numberOfDepreciation = fixedAsset.getNumberOfDepreciation();
boolean isProrataTemporis = fixedAsset.getFixedAssetCategory().getIsProrataTemporis();
LocalDate endDate = depreciationDate.plusMonths(fixedAsset.getDurationInMonth());
int counter = 1;
int scale = Beans.get(AppBaseService.class).getNbDecimalDigitForUnitPrice();
numberOfDepreciation--;
while (depreciationDate.isBefore(endDate)) {
FixedAssetLine fixedAssetLine = new FixedAssetLine();
fixedAssetLine.setStatusSelect(FixedAssetLineRepository.STATUS_PLANNED);
fixedAssetLine.setDepreciationDate(depreciationDate);
fixedAssetLine.setDepreciation(depreciationValue);
fixedAssetLine.setCumulativeDepreciation(cumulativeValue);
fixedAssetLine.setResidualValue(
fixedAsset.getGrossValue().subtract(fixedAssetLine.getCumulativeDepreciation()));
fixedAsset.addFixedAssetLineListItem(fixedAssetLine);
if (counter == numberOfDepreciation) {
depreciationValue = fixedAssetLine.getResidualValue();
cumulativeValue = cumulativeValue.add(depreciationValue);
depreciationDate = depreciationDate.plusMonths(fixedAsset.getPeriodicityInMonth());
if (isProrataTemporis) {
endDate =
depreciationDate.minusDays(
ChronoUnit.DAYS.between(acquisitionDate, fixedAsset.getFirstDepreciationDate()));
depreciationDate = endDate.minusDays(1);
}
counter++;
continue;
}
if (fixedAsset.getComputationMethodSelect().equals("degressive")) {
if (counter > 2 && fixedAsset.getNumberOfDepreciation() > 3) {
if (counter == 3) {
int remainingYear = fixedAsset.getNumberOfDepreciation() - 3;
depreciationValue =
fixedAssetLine
.getResidualValue()
.divide(new BigDecimal(remainingYear), RoundingMode.HALF_EVEN);
}
} else {
depreciationValue =
this.computeDepreciation(fixedAsset, fixedAssetLine.getResidualValue(), false);
}
depreciationDate = depreciationDate.plusMonths(fixedAsset.getPeriodicityInMonth());
} else {
depreciationValue =
this.computeDepreciation(fixedAsset, fixedAsset.getResidualValue(), false);
depreciationDate = depreciationDate.plusMonths(fixedAsset.getPeriodicityInMonth());
}
depreciationValue = depreciationValue.setScale(scale, RoundingMode.HALF_EVEN);
cumulativeValue =
cumulativeValue.add(depreciationValue).setScale(scale, RoundingMode.HALF_EVEN);
counter++;
}
return fixedAsset;
}
private BigDecimal computeDepreciationValue(FixedAsset fixedAsset) {
BigDecimal depreciationValue = BigDecimal.ZERO;
depreciationValue = this.computeDepreciation(fixedAsset, fixedAsset.getGrossValue(), true);
return depreciationValue;
}
private BigDecimal computeProrataTemporis(FixedAsset fixedAsset, boolean isFirstYear) {
float prorataTemporis = 1;
if (isFirstYear && fixedAsset.getFixedAssetCategory().getIsProrataTemporis()) {
LocalDate acquisitionDate = fixedAsset.getAcquisitionDate();
LocalDate depreciationDate = fixedAsset.getFirstDepreciationDate();
long monthsBetweenDates =
ChronoUnit.MONTHS.between(
acquisitionDate.withDayOfMonth(1), depreciationDate.withDayOfMonth(1));
prorataTemporis = monthsBetweenDates / fixedAsset.getPeriodicityInMonth().floatValue();
}
return new BigDecimal(prorataTemporis);
}
private BigDecimal computeDepreciation(
FixedAsset fixedAsset, BigDecimal residualValue, boolean isFirstYear) {
int scale = Beans.get(AppBaseService.class).getNbDecimalDigitForUnitPrice();
int numberOfDepreciation =
fixedAsset.getFixedAssetCategory().getIsProrataTemporis()
? fixedAsset.getNumberOfDepreciation() - 1
: fixedAsset.getNumberOfDepreciation();
float depreciationRate = 1f / numberOfDepreciation * 100f;
BigDecimal ddRate = BigDecimal.ONE;
BigDecimal prorataTemporis = this.computeProrataTemporis(fixedAsset, isFirstYear);
if (fixedAsset.getComputationMethodSelect().equals("degressive")) {
ddRate = fixedAsset.getDegressiveCoef();
}
return residualValue
.multiply(new BigDecimal(depreciationRate))
.multiply(ddRate)
.multiply(prorataTemporis)
.divide(new BigDecimal(100), scale);
}
@Override
@Transactional(rollbackOn = {Exception.class})
public List<FixedAsset> createFixedAssets(Invoice invoice) throws AxelorException {
if (invoice == null || CollectionUtils.isEmpty(invoice.getInvoiceLineList())) {
return null;
}
AccountConfig accountConfig =
Beans.get(AccountConfigService.class).getAccountConfig(invoice.getCompany());
List<FixedAsset> fixedAssetList = new ArrayList<FixedAsset>();
for (InvoiceLine invoiceLine : invoice.getInvoiceLineList()) {
if (accountConfig.getFixedAssetCatReqOnInvoice()
&& invoiceLine.getFixedAssets()
&& invoiceLine.getFixedAssetCategory() == null) {
throw new AxelorException(
invoiceLine,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.INVOICE_LINE_ERROR_FIXED_ASSET_CATEGORY),
invoiceLine.getProductName());
}
if (!invoiceLine.getFixedAssets() || invoiceLine.getFixedAssetCategory() == null) {
continue;
}
FixedAsset fixedAsset = new FixedAsset();
fixedAsset.setFixedAssetCategory(invoiceLine.getFixedAssetCategory());
if (fixedAsset.getFixedAssetCategory().getIsValidateFixedAsset()) {
fixedAsset.setStatusSelect(FixedAssetRepository.STATUS_VALIDATED);
} else {
fixedAsset.setStatusSelect(FixedAssetRepository.STATUS_DRAFT);
}
fixedAsset.setAcquisitionDate(invoice.getInvoiceDate());
fixedAsset.setFirstDepreciationDate(invoice.getInvoiceDate());
fixedAsset.setReference(invoice.getInvoiceId());
fixedAsset.setName(invoiceLine.getProductName() + " (" + invoiceLine.getQty() + ")");
fixedAsset.setCompany(fixedAsset.getFixedAssetCategory().getCompany());
fixedAsset.setJournal(fixedAsset.getFixedAssetCategory().getJournal());
fixedAsset.setComputationMethodSelect(
fixedAsset.getFixedAssetCategory().getComputationMethodSelect());
fixedAsset.setDegressiveCoef(fixedAsset.getFixedAssetCategory().getDegressiveCoef());
fixedAsset.setNumberOfDepreciation(
fixedAsset.getFixedAssetCategory().getNumberOfDepreciation());
fixedAsset.setPeriodicityInMonth(fixedAsset.getFixedAssetCategory().getPeriodicityInMonth());
fixedAsset.setDurationInMonth(fixedAsset.getFixedAssetCategory().getDurationInMonth());
fixedAsset.setGrossValue(invoiceLine.getCompanyExTaxTotal());
fixedAsset.setPartner(invoice.getPartner());
fixedAsset.setPurchaseAccount(invoiceLine.getAccount());
fixedAsset.setInvoiceLine(invoiceLine);
this.generateAndcomputeLines(fixedAsset);
fixedAssetList.add(fixedAssetRepo.save(fixedAsset));
}
return fixedAssetList;
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void disposal(LocalDate disposalDate, BigDecimal disposalAmount, FixedAsset fixedAsset)
throws AxelorException {
Map<Integer, List<FixedAssetLine>> FixedAssetLineMap =
fixedAsset
.getFixedAssetLineList()
.stream()
.collect(Collectors.groupingBy(fa -> fa.getStatusSelect()));
List<FixedAssetLine> previousPlannedLineList =
FixedAssetLineMap.get(FixedAssetLineRepository.STATUS_PLANNED);
List<FixedAssetLine> previousRealizedLineList =
FixedAssetLineMap.get(FixedAssetLineRepository.STATUS_REALIZED);
FixedAssetLine previousPlannedLine =
previousPlannedLineList != null && !previousPlannedLineList.isEmpty()
? previousPlannedLineList.get(0)
: null;
FixedAssetLine previousRealizedLine =
previousRealizedLineList != null && !previousRealizedLineList.isEmpty()
? previousRealizedLineList.get(previousRealizedLineList.size() - 1)
: null;
if (previousPlannedLine != null
&& disposalDate.isAfter(previousPlannedLine.getDepreciationDate())) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.FIXED_ASSET_DISPOSAL_DATE_ERROR_2));
}
if (previousRealizedLine != null
&& disposalDate.isBefore(previousRealizedLine.getDepreciationDate())) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.FIXED_ASSET_DISPOSAL_DATE_ERROR_1));
}
if (disposalAmount.compareTo(BigDecimal.ZERO) != 0) {
FixedAssetLine depreciationFixedAssetLine =
generateProrataDepreciationLine(fixedAsset, disposalDate, previousRealizedLine);
fixedAssetLineService.realize(depreciationFixedAssetLine);
fixedAssetLineService.generateDisposalMove(depreciationFixedAssetLine);
} else {
if (disposalAmount.compareTo(fixedAsset.getResidualValue()) != 0) {
return;
}
}
List<FixedAssetLine> fixedAssetLineList =
fixedAsset
.getFixedAssetLineList()
.stream()
.filter(
fixedAssetLine ->
fixedAssetLine.getStatusSelect() == FixedAssetLineRepository.STATUS_PLANNED)
.collect(Collectors.toList());
for (FixedAssetLine fixedAssetLine : fixedAssetLineList) {
fixedAsset.removeFixedAssetLineListItem(fixedAssetLine);
}
fixedAsset.setStatusSelect(FixedAssetRepository.STATUS_TRANSFERRED);
fixedAsset.setDisposalDate(disposalDate);
fixedAsset.setDisposalValue(disposalAmount);
fixedAssetRepo.save(fixedAsset);
}
private FixedAssetLine generateProrataDepreciationLine(
FixedAsset fixedAsset, LocalDate disposalDate, FixedAssetLine previousRealizedLine) {
LocalDate previousRealizedDate =
previousRealizedLine != null
? previousRealizedLine.getDepreciationDate()
: fixedAsset.getFirstDepreciationDate();
long monthsBetweenDates =
ChronoUnit.MONTHS.between(
previousRealizedDate.withDayOfMonth(1), disposalDate.withDayOfMonth(1));
FixedAssetLine fixedAssetLine = new FixedAssetLine();
fixedAssetLine.setDepreciationDate(disposalDate);
BigDecimal prorataTemporis =
new BigDecimal(monthsBetweenDates / fixedAsset.getPeriodicityInMonth().floatValue());
int scale = Beans.get(AppBaseService.class).getNbDecimalDigitForUnitPrice();
int numberOfDepreciation =
fixedAsset.getFixedAssetCategory().getIsProrataTemporis()
? fixedAsset.getNumberOfDepreciation() - 1
: fixedAsset.getNumberOfDepreciation();
float depreciationRate = 1f / numberOfDepreciation * 100f;
BigDecimal ddRate = BigDecimal.ONE;
if (fixedAsset.getComputationMethodSelect().equals("degressive")) {
ddRate = fixedAsset.getDegressiveCoef();
}
BigDecimal deprecationValue =
fixedAsset
.getGrossValue()
.multiply(new BigDecimal(depreciationRate))
.multiply(ddRate)
.multiply(prorataTemporis)
.divide(new BigDecimal(100), scale);
fixedAssetLine.setDepreciation(deprecationValue);
BigDecimal cumulativeValue =
previousRealizedLine != null
? previousRealizedLine.getCumulativeDepreciation().add(deprecationValue)
: deprecationValue;
fixedAssetLine.setCumulativeDepreciation(cumulativeValue);
fixedAssetLine.setResidualValue(
fixedAsset.getGrossValue().subtract(fixedAssetLine.getCumulativeDepreciation()));
fixedAsset.addFixedAssetLineListItem(fixedAssetLine);
return fixedAssetLine;
}
}

View File

@ -0,0 +1,112 @@
package com.axelor.apps.account.service;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.InvoiceLine;
import com.axelor.apps.account.db.InvoiceTemplate;
import com.axelor.apps.account.db.InvoiceTemplateLine;
import com.axelor.apps.account.db.repo.InvoiceRepository;
import com.axelor.apps.account.service.invoice.generator.InvoiceGenerator;
import com.axelor.apps.account.service.invoice.generator.InvoiceLineGenerator;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.Product;
import com.axelor.exception.AxelorException;
import com.axelor.inject.Beans;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
public class InvoiceTemplateService {
@Transactional
public Invoice generateInvoiceFromTemplate(InvoiceTemplate invoiceTemplate)
throws AxelorException {
Partner partner = invoiceTemplate.getPartner();
Company company = invoiceTemplate.getCompany();
InvoiceGenerator invoiceGenerator =
new InvoiceGenerator(
InvoiceRepository.OPERATION_TYPE_SUPPLIER_PURCHASE,
company,
null,
null,
null,
partner,
partner,
partner.getCurrency(),
null,
"",
"",
null,
company.getDefaultBankDetails(),
null) {
@Override
public Invoice generate() throws AxelorException {
return super.createInvoiceHeader();
}
};
List<InvoiceLine> invoiceLineList = new ArrayList<>();
Invoice invoice = invoiceGenerator.generate();
int priority = 0;
for (InvoiceTemplateLine invoiceTemplateLine : invoiceTemplate.getMoveTemplateLineList()) {
invoiceLineList.addAll(createInvoiceLine(invoice, invoiceTemplateLine, priority));
priority++;
}
invoiceGenerator.populate(invoice, invoiceLineList);
Invoice returnInvoiced = Beans.get(InvoiceRepository.class).save(invoice);
return returnInvoiced;
}
protected List<InvoiceLine> createInvoiceLine(
Invoice invoice, InvoiceTemplateLine invoiceTemplateLine, int priority)
throws AxelorException {
Product product = invoiceTemplateLine.getProduct();
InvoiceLineGenerator invoiceLineGenerator =
new InvoiceLineGenerator(
invoice,
product,
invoiceTemplateLine.getProduct().getName(),
BigDecimal.ZERO,
BigDecimal.ZERO,
BigDecimal.ZERO,
"",
invoiceTemplateLine.getQty(),
invoiceTemplateLine.getProduct().getUnit(),
null,
priority,
BigDecimal.ZERO,
0,
BigDecimal.ZERO,
BigDecimal.ZERO,
false,
false,
null) {
@Override
public List<InvoiceLine> creates() throws AxelorException {
InvoiceLine invoiceLine = this.createInvoiceLine();
invoiceLine.setQty(BigDecimal.ONE);
invoiceLine.setPrice(BigDecimal.ZERO);
invoiceLine.setPriceDiscounted(BigDecimal.ZERO);
List<InvoiceLine> invoiceLines = new ArrayList<InvoiceLine>();
invoiceLines.add(invoiceLine);
return invoiceLines;
}
};
return invoiceLineGenerator.creates();
}
}

View File

@ -0,0 +1,72 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Journal;
import com.axelor.db.JPA;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import javax.persistence.Query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JournalService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
/** Debit balance = debit - credit */
public static final Integer BALANCE_TYPE_DEBIT_BALANCE = 1;
/** Credit balance = credit - debit */
public static final Integer BALANCE_TYPE_CREDIT_BALANCE = 1;
/**
* Compute the balance of the journal, depending of the account type and balance type
*
* @param journal Journal
* @param accountType Technical type select of AccountType
* @param balanceType
* <p>1 : debit balance = debit - credit
* <p>2 : credit balance = credit - debit
* @return The balance (debit balance or credit balance)
*/
public BigDecimal computeBalance(Journal journal, int accountType, int balanceType) {
Query balanceQuery =
JPA.em()
.createQuery(
"select sum(self.debit - self.credit) from MoveLine self where self.move.journal = :journal "
+ "and self.move.ignoreInAccountingOk IN ('false', null) and self.move.statusSelect IN (2, 3) and self.account.accountType.technicalTypeSelect = :accountType");
balanceQuery.setParameter("journal", journal);
balanceQuery.setParameter("accountType", accountType);
BigDecimal balance = (BigDecimal) balanceQuery.getSingleResult();
if (balance != null) {
if (balanceType == BALANCE_TYPE_CREDIT_BALANCE) {
balance = balance.negate();
}
log.debug("Account balance : {}", balance);
return balance;
} else {
return BigDecimal.ZERO;
}
}
}

View File

@ -0,0 +1,61 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.AccountingReport;
import com.axelor.apps.base.db.Company;
import com.axelor.exception.AxelorException;
import com.axelor.meta.db.MetaFile;
import java.io.IOException;
import java.time.LocalDate;
public interface MoveLineExportService {
public MetaFile exportMoveLine(AccountingReport accountingReport)
throws AxelorException, IOException;
public void replayExportMoveLine(AccountingReport accountingReport)
throws AxelorException, IOException;
public AccountingReport createAccountingReport(
Company company, int exportTypeSelect, LocalDate startDate, LocalDate endDate)
throws AxelorException;
public void exportMoveLineTypeSelect1006(AccountingReport mlr, boolean replay)
throws AxelorException, IOException;
public void exportMoveLineTypeSelect1007(AccountingReport accountingReport, boolean replay)
throws AxelorException, IOException;
public void exportMoveLineTypeSelect1008(AccountingReport accountingReport, boolean replay)
throws AxelorException, IOException;
public void exportMoveLineTypeSelect1009(AccountingReport accountingReport, boolean replay)
throws AxelorException, IOException;
/**
* Export general balance to CSV file.
*
* @param accountingReport
* @return
* @throws AxelorException
* @throws IOException
*/
void exportMoveLineTypeSelect1010(AccountingReport accountingReport)
throws AxelorException, IOException;
}

View File

@ -0,0 +1,28 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Notification;
import com.axelor.exception.AxelorException;
public interface NotificationService {
void populateNotificationItemList(Notification notification);
void validate(Notification notification) throws AxelorException;
}

View File

@ -0,0 +1,262 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.Journal;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.Notification;
import com.axelor.apps.account.db.NotificationItem;
import com.axelor.apps.account.db.SubrogationRelease;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.db.repo.NotificationRepository;
import com.axelor.apps.account.db.repo.SubrogationReleaseRepository;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.account.service.move.MoveService;
import com.axelor.apps.base.db.Company;
import com.axelor.db.JPA;
import com.axelor.exception.AxelorException;
import com.axelor.i18n.I18n;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.stream.Collectors;
import javax.persistence.TypedQuery;
public class NotificationServiceImpl implements NotificationService {
protected MoveService moveService;
protected ReconcileService reconcileService;
protected AccountConfigService accountConfigService;
protected SubrogationReleaseService subrogationReleaseService;
protected MoveRepository moveRepository;
@Inject
public NotificationServiceImpl(
MoveService moveService,
ReconcileService reconcileService,
AccountConfigService accountConfigService,
SubrogationReleaseService subrogationReleaseService,
MoveRepository moveRepository) {
this.moveService = moveService;
this.reconcileService = reconcileService;
this.accountConfigService = accountConfigService;
this.subrogationReleaseService = subrogationReleaseService;
this.moveRepository = moveRepository;
}
@Override
public void populateNotificationItemList(Notification notification) {
notification.clearNotificationItemList();
Comparator<Invoice> byInvoiceDate =
(i1, i2) -> i1.getInvoiceDate().compareTo(i2.getInvoiceDate());
Comparator<Invoice> byDueDate = (i1, i2) -> i1.getDueDate().compareTo(i2.getDueDate());
Comparator<Invoice> byInvoiceId = (i1, i2) -> i1.getInvoiceId().compareTo(i2.getInvoiceId());
List<Invoice> invoiceList = new ArrayList<Invoice>();
if (notification.getSubrogationRelease() != null) {
invoiceList =
notification
.getSubrogationRelease()
.getInvoiceSet()
.stream()
.sorted(byInvoiceDate.thenComparing(byDueDate).thenComparing(byInvoiceId))
.collect(Collectors.toList());
}
for (Invoice invoice : invoiceList) {
if (invoice.getAmountRemaining().signum() > 0) {
notification.addNotificationItemListItem(createNotificationItem(invoice));
}
}
}
protected NotificationItem createNotificationItem(Invoice invoice) {
return new NotificationItem(invoice, invoice.getAmountRemaining());
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void validate(Notification notification) throws AxelorException {
for (NotificationItem notificationItem : notification.getNotificationItemList()) {
this.createPaymentMove(notificationItem);
}
notification.setStatusSelect(NotificationRepository.STATUS_VALIDATED);
}
protected Journal getJournal(AccountConfig accountConfig) throws AxelorException {
return accountConfigService.getAutoMiscOpeJournal(accountConfig);
}
protected Account getAccount(AccountConfig accountConfig, NotificationItem notificationItem) {
Account account = accountConfig.getFactorCreditAccount();
if (notificationItem.getTypeSelect()
== NotificationRepository.TYPE_PAYMENT_TO_THE_FACTORE_AFTER_FACTORE_RETURN) {
account = accountConfig.getFactorDebitAccount();
}
return account;
}
@Transactional(rollbackOn = {Exception.class})
protected Move createPaymentMove(NotificationItem notificationItem) throws AxelorException {
Notification notification = notificationItem.getNotification();
Invoice invoice = notificationItem.getInvoice();
Company company = invoice.getCompany();
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
Journal journal = getJournal(accountConfig);
SubrogationRelease subrogationRelease = getSubrogationRelease(notificationItem);
String origin = computeOrigin(subrogationRelease, invoice);
BigDecimal amountPaid = notificationItem.getAmountPaid();
if (amountPaid.compareTo(BigDecimal.ZERO) == 0) {
return null;
}
Move paymentMove =
moveService
.getMoveCreateService()
.createMove(
journal,
company,
company.getCurrency(),
invoice.getPartner(),
notification.getPaymentDate(),
null,
MoveRepository.TECHNICAL_ORIGIN_AUTOMATIC);
MoveLine creditMoveLine, debitMoveLine;
Account account = getAccount(accountConfig, notificationItem);
debitMoveLine =
moveService
.getMoveLineService()
.createMoveLine(
paymentMove,
invoice.getPartner(),
account,
amountPaid,
true,
notification.getPaymentDate(),
null,
1,
origin,
invoice.getInvoiceId());
creditMoveLine =
moveService
.getMoveLineService()
.createMoveLine(
paymentMove,
invoice.getPartner(),
invoice.getPartnerAccount(),
amountPaid,
false,
notification.getPaymentDate(),
null,
2,
origin,
invoice.getInvoiceId());
paymentMove.addMoveLineListItem(debitMoveLine);
paymentMove.addMoveLineListItem(creditMoveLine);
paymentMove = moveRepository.save(paymentMove);
moveService.getMoveValidateService().validate(paymentMove);
MoveLine invoiceMoveLine = findInvoiceAccountMoveLine(invoice);
MoveLine subrogationReleaseMoveLine = findSubrogationReleaseAccountMoveLine(invoice);
if (invoiceMoveLine.getAmountRemaining().compareTo(BigDecimal.ZERO) == 1) {
reconcileService.reconcile(invoiceMoveLine, creditMoveLine, true, true);
if (subrogationReleaseMoveLine != null
&& notificationItem.getTypeSelect()
== NotificationRepository.TYPE_PAYMENT_TO_THE_FACTORE) {
reconcileService.reconcile(debitMoveLine, subrogationReleaseMoveLine, true, false);
}
}
notificationItem.setMove(paymentMove);
if (subrogationRelease != null) {
subrogationReleaseService.clear(subrogationRelease);
}
return paymentMove;
}
protected String computeOrigin(SubrogationRelease subrogationRelease, Invoice invoice) {
return subrogationRelease != null
? subrogationRelease.getSequenceNumber()
: I18n.get("Payment notification") + " " + invoice.getInvoiceId();
}
protected SubrogationRelease getSubrogationRelease(NotificationItem notificationItem) {
Invoice invoice = notificationItem.getInvoice();
TypedQuery<SubrogationRelease> query =
JPA.em()
.createQuery(
"SELECT self FROM SubrogationRelease self JOIN self.invoiceSet invoices WHERE self.statusSelect = :statusSelect AND invoices.id IN (:invoiceId)",
SubrogationRelease.class);
query.setParameter("statusSelect", SubrogationReleaseRepository.STATUS_ACCOUNTED);
query.setParameter("invoiceId", invoice.getId());
List<SubrogationRelease> subrogationReleaseResultList = query.getResultList();
if (subrogationReleaseResultList != null && !subrogationReleaseResultList.isEmpty()) {
return subrogationReleaseResultList.get(0);
}
return null;
}
protected MoveLine findInvoiceAccountMoveLine(Invoice invoice) {
for (MoveLine moveLine : invoice.getMove().getMoveLineList()) {
if (moveLine.getAccount().equals(invoice.getPartnerAccount())) {
return moveLine;
}
}
throw new NoSuchElementException();
}
protected MoveLine findSubrogationReleaseAccountMoveLine(Invoice invoice) throws AxelorException {
if (invoice.getSubrogationReleaseMove() != null) {
for (MoveLine moveLine : invoice.getSubrogationReleaseMove().getMoveLineList()) {
if (moveLine.getCredit().compareTo(BigDecimal.ZERO) == 1) {
return moveLine;
}
}
}
return null;
}
}

View File

@ -0,0 +1,34 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.FiscalPosition;
import com.axelor.apps.base.db.Partner;
public class PartnerAccountService {
public String getDefaultSpecificTaxNote(Partner partner) {
FiscalPosition fiscalPosition = partner.getFiscalPosition();
if (fiscalPosition == null || !fiscalPosition.getCustomerSpecificNote()) {
return "";
}
return fiscalPosition.getCustomerSpecificNoteText();
}
}

View File

@ -0,0 +1,54 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Move;
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.base.db.BankDetails;
import com.axelor.exception.AxelorException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
public interface PaymentScheduleLineService {
PaymentScheduleLine createPaymentScheduleLine(
PaymentSchedule paymentSchedule,
BigDecimal inTaxAmount,
int scheduleLineSeq,
LocalDate scheduleDate);
List<PaymentScheduleLine> createPaymentScheduleLines(PaymentSchedule paymentSchedule);
/**
* Create a payment move for a payment schedule line with the given company bank details.
*
* @param paymentScheduleLine
* @param companyBankDetails
* @param paymentMode
* @return
* @throws AxelorException
*/
Move createPaymentMove(
PaymentScheduleLine paymentScheduleLine,
BankDetails companyBankDetails,
PaymentMode paymentMode)
throws AxelorException;
}

View File

@ -0,0 +1,362 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.DirectDebitManagement;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.Journal;
import com.axelor.apps.account.db.Move;
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.MoveLineRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.db.repo.PaymentScheduleLineRepository;
import com.axelor.apps.account.db.repo.PaymentScheduleRepository;
import com.axelor.apps.account.service.move.MoveService;
import com.axelor.apps.account.service.move.MoveToolService;
import com.axelor.apps.account.service.payment.PaymentModeService;
import com.axelor.apps.account.service.payment.PaymentService;
import com.axelor.apps.base.db.BankDetails;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.exception.AxelorException;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PaymentScheduleLineServiceImpl implements PaymentScheduleLineService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected AppBaseService appBaseService;
protected PaymentScheduleService paymentScheduleService;
protected MoveService moveService;
protected PaymentModeService paymentModeService;
protected SequenceService sequenceService;
protected AccountingSituationService accountingSituationService;
protected MoveToolService moveToolService;
protected PaymentService paymentService;
protected MoveLineRepository moveLineRepo;
protected PaymentScheduleLineRepository paymentScheduleLineRepo;
@Inject
public PaymentScheduleLineServiceImpl(
AppBaseService appBaseService,
PaymentScheduleService paymentScheduleService,
MoveService moveService,
PaymentModeService paymentModeService,
SequenceService sequenceService,
AccountingSituationService accountingSituationService,
MoveToolService moveToolService,
PaymentService paymentService,
MoveLineRepository moveLineRepo,
PaymentScheduleLineRepository paymentScheduleLineRepo) {
this.appBaseService = appBaseService;
this.paymentScheduleService = paymentScheduleService;
this.moveService = moveService;
this.paymentModeService = paymentModeService;
this.sequenceService = sequenceService;
this.accountingSituationService = accountingSituationService;
this.moveToolService = moveToolService;
this.paymentService = paymentService;
this.moveLineRepo = moveLineRepo;
this.paymentScheduleLineRepo = paymentScheduleLineRepo;
}
/**
* Création d'une ligne d'échéancier
*
* @param paymentSchedule L'échéancié attaché.
* @param invoiceTerm La facture d'échéance.
* @param scheduleLineSeq Le numéro d'échéance.
* @param scheduleDate La date d'échéance.
* @return
*/
@Override
public PaymentScheduleLine createPaymentScheduleLine(
PaymentSchedule paymentSchedule,
BigDecimal inTaxAmount,
int scheduleLineSeq,
LocalDate scheduleDate) {
PaymentScheduleLine paymentScheduleLine = new PaymentScheduleLine();
paymentScheduleLine.setScheduleLineSeq(scheduleLineSeq);
paymentScheduleLine.setScheduleDate(scheduleDate);
paymentScheduleLine.setInTaxAmount(inTaxAmount);
paymentScheduleLine.setStatusSelect(PaymentScheduleLineRepository.STATUS_DRAFT);
if (paymentSchedule != null) {
paymentSchedule.addPaymentScheduleLineListItem(paymentScheduleLine);
}
log.debug(
"Création de la ligne de l'échéancier numéro {} pour la date du {} et la somme de {}",
new Object[] {
paymentScheduleLine.getScheduleLineSeq(),
paymentScheduleLine.getScheduleDate(),
paymentScheduleLine.getInTaxAmount()
});
return paymentScheduleLine;
}
/**
* En fonction des infos d'entête d'un échéancier, crée les lignes d'échéances
*
* @param paymentSchedule
*/
@Override
public List<PaymentScheduleLine> createPaymentScheduleLines(PaymentSchedule paymentSchedule) {
List<PaymentScheduleLine> paymentScheduleLines = new ArrayList<PaymentScheduleLine>();
int nbrTerm = paymentSchedule.getNbrTerm();
BigDecimal inTaxAmount = paymentSchedule.getInTaxAmount();
log.debug(
"Création de lignes pour l'échéancier numéro {} (nombre d'échéance : {}, montant : {})",
new Object[] {paymentSchedule.getPaymentScheduleSeq(), nbrTerm, inTaxAmount});
if (nbrTerm > 0 && inTaxAmount.compareTo(BigDecimal.ZERO) == 1) {
BigDecimal termAmount =
inTaxAmount.divide(new BigDecimal(nbrTerm), 2, RoundingMode.HALF_EVEN);
BigDecimal cumul = BigDecimal.ZERO;
for (int i = 1; i < nbrTerm + 1; i++) {
if (i == nbrTerm) {
termAmount = inTaxAmount.subtract(cumul);
} else {
cumul = cumul.add(termAmount);
}
paymentScheduleLines.add(
this.createPaymentScheduleLine(
paymentSchedule, termAmount, i, paymentSchedule.getStartDate().plusMonths(i - 1)));
}
}
return paymentScheduleLines;
}
@Override
@Transactional(rollbackOn = {Exception.class})
public Move createPaymentMove(
PaymentScheduleLine paymentScheduleLine,
BankDetails companyBankDetails,
PaymentMode paymentMode)
throws AxelorException {
Preconditions.checkNotNull(paymentScheduleLine);
Preconditions.checkNotNull(companyBankDetails);
PaymentSchedule paymentSchedule = paymentScheduleLine.getPaymentSchedule();
Company company = paymentSchedule.getCompany();
Partner partner = paymentSchedule.getPartner();
Journal journal =
paymentModeService.getPaymentModeJournal(paymentMode, company, companyBankDetails);
BigDecimal amount = paymentScheduleLine.getInTaxAmount();
String name = paymentScheduleLine.getName();
LocalDate todayDate = appBaseService.getTodayDate();
Account account = accountingSituationService.getCustomerAccount(partner, company);
Move move =
moveService
.getMoveCreateService()
.createMove(
journal,
company,
null,
partner,
paymentMode,
MoveRepository.TECHNICAL_ORIGIN_AUTOMATIC);
MoveLine creditMoveLine =
moveService
.getMoveLineService()
.createMoveLine(move, partner, account, amount, false, todayDate, 1, name, null);
move.addMoveLineListItem(creditMoveLine);
creditMoveLine = moveLineRepo.save(creditMoveLine);
Account paymentModeAccount =
paymentModeService.getPaymentModeAccount(paymentMode, company, companyBankDetails);
MoveLine debitMoveLine =
moveService
.getMoveLineService()
.createMoveLine(
move, partner, paymentModeAccount, amount, true, todayDate, 2, name, null);
move.addMoveLineListItem(debitMoveLine);
debitMoveLine = moveLineRepo.save(debitMoveLine);
moveService.getMoveValidateService().validate(move);
// Reconcile
if (paymentSchedule.getTypeSelect() == PaymentScheduleRepository.TYPE_TERMS
&& paymentSchedule.getInvoiceSet() != null) {
List<MoveLine> debitMoveLineList =
paymentSchedule
.getInvoiceSet()
.stream()
.sorted(Comparator.comparing(Invoice::getDueDate))
.map(invoice -> moveService.getMoveLineService().getDebitCustomerMoveLine(invoice))
.collect(Collectors.toList());
if (moveToolService.isSameAccount(debitMoveLineList, account)) {
List<MoveLine> creditMoveLineList = Lists.newArrayList(creditMoveLine);
paymentService.useExcessPaymentOnMoveLines(debitMoveLineList, creditMoveLineList);
}
}
paymentScheduleLine.setDirectDebitAmount(amount);
paymentScheduleLine.setInTaxAmountPaid(amount);
paymentScheduleLine.setAdvanceOrPaymentMove(move);
paymentScheduleLine.setAdvanceMoveLine(creditMoveLine);
paymentScheduleLine.setStatusSelect(PaymentScheduleLineRepository.STATUS_VALIDATED);
paymentScheduleService.closePaymentScheduleIfAllPaid(paymentSchedule);
return move;
}
/**
* Procédure permettant d'assigner un numéro de prélèvement à l'échéance à prélever Si plusieurs
* échéance d'un même échéancier sont à prélever, alors on utilise un objet de gestion de
* prélèvement encadrant l'ensemble des échéances en question Sinon on assigne simplement un
* numéro de prélèvement à l'échéance
*
* @param paymentScheduleLineList Une liste d'échéance à prélever
* @param paymentScheduleLine L'échéance traité
* @param company Une société
* @param paymentMode TODO
* @param journal Un journal (prélèvement mensu masse ou grand compte)
* @throws AxelorException
*/
protected void setDebitNumber(
List<PaymentScheduleLine> paymentScheduleLineList,
PaymentScheduleLine paymentScheduleLine,
Company company,
PaymentMode paymentMode)
throws AxelorException {
if (hasOtherPaymentScheduleLine(paymentScheduleLineList, paymentScheduleLine)) {
DirectDebitManagement directDebitManagement =
getDirectDebitManagement(paymentScheduleLineList, paymentScheduleLine);
if (directDebitManagement == null) {
directDebitManagement =
createDirectDebitManagement(getDirectDebitSequence(company, paymentMode), company);
}
paymentScheduleLine.setDirectDebitManagement(directDebitManagement);
directDebitManagement.getPaymentScheduleLineList().add(paymentScheduleLine);
} else {
paymentScheduleLine.setDebitNumber(getDirectDebitSequence(company, paymentMode));
}
}
protected void setDebitNumber(PaymentScheduleLine paymentScheduleLine, PaymentMode paymentMode)
throws AxelorException {
PaymentSchedule paymentSchedule = paymentScheduleLine.getPaymentSchedule();
List<PaymentScheduleLine> paymentScheduleLineList =
paymentSchedule.getPaymentScheduleLineList();
Company company = paymentSchedule.getCompany();
setDebitNumber(paymentScheduleLineList, paymentScheduleLine, company, paymentMode);
}
/**
* Y a-t-il d'autres échéance a exporter pour le même payeur ?
*
* @param pslList : une liste d'échéance
* @param psl
* @return
*/
protected boolean hasOtherPaymentScheduleLine(
List<PaymentScheduleLine> pslList, PaymentScheduleLine psl) {
int i = 0;
for (PaymentScheduleLine paymentScheduleLine : pslList) {
paymentScheduleLine = paymentScheduleLineRepo.find(paymentScheduleLine.getId());
if (psl.getPaymentSchedule().equals(paymentScheduleLine.getPaymentSchedule())) {
i++;
}
}
return i > 1;
}
/**
* Procédure permettant de récupérer l'objet de gestion déjà créé lors du prélèvement d'une autre
* échéance
*
* @param pslList La liste d'échéance à prélever
* @param psl L'échéance à prélever
* @return L'objet de gestion trouvé
*/
protected DirectDebitManagement getDirectDebitManagement(
List<PaymentScheduleLine> pslList, PaymentScheduleLine psl) {
for (PaymentScheduleLine paymentScheduleLine : pslList) {
paymentScheduleLine = paymentScheduleLineRepo.find(paymentScheduleLine.getId());
if (psl.getPaymentSchedule().equals(paymentScheduleLine.getPaymentSchedule())) {
if (paymentScheduleLine.getDirectDebitManagement() != null) {
return paymentScheduleLine.getDirectDebitManagement();
}
}
}
return null;
}
/**
* Procédure permettant de créer un objet de gestion de prélèvement
*
* @param sequence La séquence de prélèvement à utiliser
* @param company Une société
* @return
*/
protected DirectDebitManagement createDirectDebitManagement(String sequence, Company company) {
DirectDebitManagement directDebitManagement = new DirectDebitManagement();
directDebitManagement.setDebitNumber(sequence);
directDebitManagement.setInvoiceSet(new HashSet<Invoice>());
directDebitManagement.setPaymentScheduleLineList(new ArrayList<PaymentScheduleLine>());
directDebitManagement.setCompany(company);
return directDebitManagement;
}
protected String getDirectDebitSequence(Company company, PaymentMode paymentMode)
throws AxelorException {
// TODO manage multi bank
return sequenceService.getSequenceNumber(
paymentModeService.getPaymentModeSequence(paymentMode, company, null));
}
}

View File

@ -0,0 +1,117 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 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.base.db.BankDetails;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.exception.AxelorException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import java.util.Set;
public interface PaymentScheduleService {
PaymentSchedule createPaymentSchedule(
Partner partner, Company company, Set<Invoice> invoices, LocalDate startDate, int nbrTerm)
throws AxelorException;
PaymentSchedule createPaymentSchedule(
Partner partner,
Invoice invoice,
Company company,
LocalDate date,
LocalDate startDate,
int nbrTerm,
BankDetails bankDetails,
PaymentMode paymentMode)
throws AxelorException;
String getPaymentScheduleSequence(Company company) throws AxelorException;
BigDecimal getInvoiceTermTotal(PaymentSchedule paymentSchedule);
void updatePaymentSchedule(PaymentSchedule paymentSchedule, BigDecimal inTaxTotal);
PaymentSchedule createPaymentSchedule(
Partner partner,
Company company,
LocalDate date,
LocalDate firstTermDate,
BigDecimal initialInTaxAmount,
int nbrTerm,
BankDetails bankDetails,
PaymentMode paymentMode)
throws AxelorException;
List<MoveLine> getPaymentSchedulerMoveLineToPay(PaymentSchedule paymentSchedule);
void validatePaymentSchedule(PaymentSchedule paymentSchedule) throws AxelorException;
void updateInvoices(PaymentSchedule paymentSchedule);
void updateInvoice(Invoice invoice, PaymentSchedule paymentSchedule);
void cancelPaymentSchedule(PaymentSchedule paymentSchedule);
boolean isLastSchedule(PaymentScheduleLine paymentScheduleLine);
void closePaymentSchedule(PaymentSchedule paymentSchedule) throws AxelorException;
void closePaymentScheduleIfAllPaid(PaymentSchedule paymentSchedule) throws AxelorException;
LocalDate getMostOldDatePaymentScheduleLine(List<PaymentScheduleLine> paymentScheduleLineList);
LocalDate getMostRecentDatePaymentScheduleLine(List<PaymentScheduleLine> paymentScheduleLineList);
void createPaymentScheduleLines(PaymentSchedule paymentSchedule);
void initCollection(PaymentSchedule paymentSchedule);
void toCancelPaymentSchedule(PaymentSchedule paymentSchedule);
/**
* Get partner's bank details.
*
* @param paymentSchedule
* @return
* @throws AxelorException
*/
BankDetails getBankDetails(PaymentSchedule paymentSchedule) throws AxelorException;
/**
* Check total line amount.
*
* @param paymentSchedule
* @throws AxelorException
*/
void checkTotalLineAmount(PaymentSchedule paymentSchedule) throws AxelorException;
/**
* Get next payment schedule line sequence number.
*
* @param paymentSchedule
* @return
*/
int getNextScheduleLineSeq(PaymentSchedule paymentSchedule);
}

View File

@ -0,0 +1,608 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 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.account.service.app.AppAccountService;
import com.axelor.apps.base.db.BankDetails;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.repo.SequenceRepository;
import com.axelor.apps.base.service.PartnerService;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PaymentScheduleServiceImpl implements PaymentScheduleService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected PaymentScheduleLineService paymentScheduleLineService;
protected PaymentScheduleLineRepository paymentScheduleLineRepo;
protected SequenceService sequenceService;
protected PaymentScheduleRepository paymentScheduleRepo;
protected PartnerService partnerService;
protected AppAccountService appAccountService;
@Inject
public PaymentScheduleServiceImpl(
AppAccountService appAccountService,
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;
this.appAccountService = appAccountService;
}
/**
* Création d'un échéancier sans ces lignes.
*
* @param partner Le tiers.
* @param invoices Collection de factures.
* @param company La société.
* @param startDate Date de première échéance.
* @param nbrTerm Nombre d'échéances.
* @return L'échéancier créé.
* @throws AxelorException
*/
@Override
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,
appAccountService.getTodayDate(),
startDate,
nbrTerm,
partnerService.getDefaultBankDetails(partner),
partner.getInPaymentMode());
paymentSchedule.getInvoiceSet().addAll(invoices);
return paymentSchedule;
}
/**
* Création d'un échéancier sans ces lignes.
*
* @param partner Le tiers.
* @param invoice Facture globale permettant de définir la facture pour une échéance. L'échéancier
* est automatiquement associé à la facture si celle-ci existe.
* @param company La société.
* @param date Date de création.
* @param startDate Date de première échéance.
* @param nbrTerm Nombre d'échéances.
* @param bankDetails RIB.
* @param paymentMode Mode de paiement.
* @param payerPartner Tiers payeur.
* @param type Type de l'échéancier. <code>0 = paiement</code> <code>1 = mensu masse</code> <code>
* 2 = mensu grand-compte</code>
* @return L'échéancier créé.
* @throws AxelorException
*/
@Override
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.setPaymentScheduleSeq(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.addInvoiceSetItem(invoice);
invoice.setPaymentSchedule(paymentSchedule);
}
return paymentSchedule;
}
/**
* Fonction permettant de tester et de récupérer une séquence de prélèvement
*
* @param company Une société
* @param journal Un journal
* @return
* @throws AxelorException
*/
@Override
public String getPaymentScheduleSequence(Company company) throws AxelorException {
String seq = sequenceService.getSequenceNumber(SequenceRepository.PAYMENT_SCHEDULE, company);
if (seq == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
"%s :\n" + I18n.get(IExceptionMessage.PAYMENT_SCHEDULE_5),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
company.getName());
}
return seq;
}
/**
* Obtenir le total des factures des lignes d'un échéancier.
*
* @param paymentSchedule L'échéancier cible.
* @return Le somme des montants TTC des lignes de l'échéancier.
*/
@Override
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'échéancier {} : total = {}, ajout = {}",
new Object[] {
paymentSchedule.getPaymentScheduleSeq(),
totalAmount,
paymentScheduleLine.getInTaxAmount()
});
totalAmount = totalAmount.add(paymentScheduleLine.getInTaxAmount());
}
}
}
log.debug(
"Obtention de la somme TTC des lignes de l'échéancier {} : {}",
new Object[] {paymentSchedule.getPaymentScheduleSeq(), totalAmount});
return totalAmount;
}
/**
* Mise à jour d'un échéancier avec un nouveau montant d'échéance.
*
* @param paymentSchedule L'échéancier cible.
* @param inTaxTotal Nouveau montant d'une échéance.
*/
@Override
@Transactional
public void updatePaymentSchedule(PaymentSchedule paymentSchedule, BigDecimal inTaxTotal) {
log.debug(
"Mise à jour de l'échéancier {} : {}",
new Object[] {paymentSchedule.getPaymentScheduleSeq(), 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);
}
/**
* Création d'un échéancier avec ces lignes.
*
* @param company La société.
* @param date Date de création.
* @param firstTermDate Date de première échéance.
* @param initialInTaxAmount Montant d'une échéance.
* @param nbrTerm Nombre d'échéances.
* @param bankDetails RIB.
* @param paymentMode Mode de paiement.
* @param payerPartner Tiers payeur.
* @return L'échéancier créé.
* @throws AxelorException
*/
@Override
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
*/
@Override
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().getUseForPartnerBalance()
&& moveLine.getAmountRemaining().compareTo(BigDecimal.ZERO) > 0
&& moveLine.getDebit().compareTo(BigDecimal.ZERO) > 0) {
moveLines.add(moveLine);
}
}
}
}
log.debug("End getPaymentSchedulerMoveLineToPay.");
return moveLines;
}
@Override
public void checkTotalLineAmount(PaymentSchedule paymentSchedule) throws AxelorException {
BigDecimal total = getInvoiceTermTotal(paymentSchedule);
if (total.compareTo(paymentSchedule.getInTaxAmount()) != 0) {
throw new AxelorException(
paymentSchedule,
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.PAYMENT_SCHEDULE_LINE_AMOUNT_MISMATCH),
total,
paymentSchedule.getInTaxAmount());
}
}
/**
* Permet de valider un échéancier.
*
* @param paymentSchedule
* @throws AxelorException
*/
@Override
@Transactional(rollbackOn = {Exception.class})
public void validatePaymentSchedule(PaymentSchedule paymentSchedule) throws AxelorException {
log.debug("Validation de l'échéancier {}", paymentSchedule.getPaymentScheduleSeq());
if (paymentSchedule.getPaymentScheduleLineList() == null
|| paymentSchedule.getPaymentScheduleLineList().isEmpty()) {
throw new AxelorException(
paymentSchedule,
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.PAYMENT_SCHEDULE_6),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
paymentSchedule.getPaymentScheduleSeq());
}
checkTotalLineAmount(paymentSchedule);
for (PaymentScheduleLine paymentScheduleLine : paymentSchedule.getPaymentScheduleLineList()) {
paymentScheduleLine.setStatusSelect(PaymentScheduleLineRepository.STATUS_IN_PROGRESS);
}
this.updateInvoices(paymentSchedule);
paymentSchedule.setStatusSelect(PaymentScheduleRepository.STATUS_CONFIRMED);
}
@Override
public void updateInvoices(PaymentSchedule paymentSchedule) {
if (paymentSchedule.getInvoiceSet() != null) {
List<MoveLine> moveLineInvoiceToPay = this.getPaymentSchedulerMoveLineToPay(paymentSchedule);
for (MoveLine moveLineInvoice : moveLineInvoiceToPay) {
moveLineInvoice.getMove().setIgnoreInDebtRecoveryOk(true);
this.updateInvoice(moveLineInvoice.getMove().getInvoice(), paymentSchedule);
}
}
}
@Override
public void updateInvoice(Invoice invoice, PaymentSchedule paymentSchedule) {
invoice.setSchedulePaymentOk(true);
invoice.setPaymentSchedule(paymentSchedule);
}
/**
* Methode qui annule un échéancier
*
* @param paymentSchedule
*/
@Override
public void cancelPaymentSchedule(PaymentSchedule paymentSchedule) {
// L'échéancier est passé à annulé
paymentSchedule.setStatusSelect(PaymentScheduleRepository.STATUS_CANCELED);
for (PaymentScheduleLine paymentScheduleLine : paymentSchedule.getPaymentScheduleLineList()) {
// Si l'échéance n'est pas complètement payée
if (paymentScheduleLine.getInTaxAmountPaid().compareTo(paymentScheduleLine.getInTaxAmount())
!= 0) {
// L'échéance est passée à cloturé
paymentScheduleLine.setStatusSelect(PaymentScheduleLineRepository.STATUS_CLOSED);
}
}
for (Invoice invoice : paymentSchedule.getInvoiceSet()) {
// L'échéancier n'est plus selectionné sur la facture
invoice.setPaymentSchedule(null);
// L'échéancier est assigné dans un nouveau champs afin de garder un lien invisble pour
// l'utilisateur, mais utilisé pour le passage en irrécouvrable
invoice.setCanceledPaymentSchedule(paymentSchedule);
invoice.setSchedulePaymentOk(false);
}
}
/**
* Methode permettant de savoir si l'échéance passée en paramètre est la dernière de l'échéancier
*
* @param paymentScheduleLine
* @return
*/
@Override
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("Dernière échéance");
return true;
} else {
return false;
}
} else {
return false;
}
}
/**
* Méthode permettant de passer les statuts des lignes d'échéances et de l'échéancier à 'clo' ie
* cloturé
*
* @param invoice Une facture de fin de cycle
* @throws AxelorException
*/
@Override
public void closePaymentSchedule(PaymentSchedule paymentSchedule) throws AxelorException {
log.debug("Cloture de l'échéancier");
// On récupère un statut cloturé, afin de pouvoir changer l'état des lignes d'échéanciers
for (PaymentScheduleLine paymentScheduleLine : paymentSchedule.getPaymentScheduleLineList()) {
paymentScheduleLine.setStatusSelect(PaymentScheduleLineRepository.STATUS_CLOSED);
}
paymentSchedule.setStatusSelect(PaymentScheduleRepository.STATUS_CLOSED);
}
/**
* Close payment schedule if all paid.
*
* @param paymentSchedule
* @throws AxelorException
*/
@Override
public void closePaymentScheduleIfAllPaid(PaymentSchedule paymentSchedule)
throws AxelorException {
if (paymentSchedule.getPaymentScheduleLineList() == null) {
return;
}
for (PaymentScheduleLine paymentScheduleLine : paymentSchedule.getPaymentScheduleLineList()) {
if (paymentScheduleLine.getStatusSelect() < PaymentScheduleLineRepository.STATUS_VALIDATED) {
return;
}
}
paymentSchedule.setStatusSelect(PaymentScheduleRepository.STATUS_CLOSED);
}
@Override
public LocalDate getMostOldDatePaymentScheduleLine(
List<PaymentScheduleLine> paymentScheduleLineList) {
LocalDate minPaymentScheduleLineDate = LocalDate.now();
if (paymentScheduleLineList != null && !paymentScheduleLineList.isEmpty()) {
for (PaymentScheduleLine paymentScheduleLine : paymentScheduleLineList) {
if (minPaymentScheduleLineDate.isAfter(paymentScheduleLine.getScheduleDate())) {
minPaymentScheduleLineDate = paymentScheduleLine.getScheduleDate();
}
}
} else {
minPaymentScheduleLineDate = null;
}
return minPaymentScheduleLineDate;
}
@Override
public LocalDate getMostRecentDatePaymentScheduleLine(
List<PaymentScheduleLine> paymentScheduleLineList) {
LocalDate minPaymentScheduleLineDate = LocalDate.now();
if (paymentScheduleLineList != null && !paymentScheduleLineList.isEmpty()) {
for (PaymentScheduleLine paymentScheduleLine : paymentScheduleLineList) {
if (minPaymentScheduleLineDate.isBefore(paymentScheduleLine.getScheduleDate())) {
minPaymentScheduleLineDate = paymentScheduleLine.getScheduleDate();
}
}
} else {
minPaymentScheduleLineDate = null;
}
return minPaymentScheduleLineDate;
}
// Transactional
/**
* Créer des lignes d'échéancier à partir des lignes de factures de celui-ci.
*
* @param paymentSchedule
* @throws AxelorException
*/
@Override
@Transactional
public void createPaymentScheduleLines(PaymentSchedule paymentSchedule) {
this.initCollection(paymentSchedule);
paymentSchedule
.getPaymentScheduleLineList()
.addAll(paymentScheduleLineService.createPaymentScheduleLines(paymentSchedule));
paymentScheduleRepo.save(paymentSchedule);
}
@Override
public void initCollection(PaymentSchedule paymentSchedule) {
if (paymentSchedule.getPaymentScheduleLineList() == null) {
paymentSchedule.setPaymentScheduleLineList(new ArrayList<PaymentScheduleLine>());
} else {
paymentSchedule.getPaymentScheduleLineList().clear();
}
}
@Override
@Transactional
public void toCancelPaymentSchedule(PaymentSchedule paymentSchedule) {
this.cancelPaymentSchedule(paymentSchedule);
paymentScheduleRepo.save(paymentSchedule);
}
@Override
public BankDetails getBankDetails(PaymentSchedule paymentSchedule) throws AxelorException {
BankDetails bankDetails = paymentSchedule.getBankDetails();
if (bankDetails != null) {
return bankDetails;
}
Partner partner = paymentSchedule.getPartner();
Preconditions.checkNotNull(partner);
bankDetails = partnerService.getDefaultBankDetails(partner);
if (bankDetails != null) {
return bankDetails;
}
throw new AxelorException(
partner,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.PARTNER_BANK_DETAILS_MISSING),
partner.getName());
}
@Override
public int getNextScheduleLineSeq(PaymentSchedule paymentSchedule) {
List<PaymentScheduleLine> paymentScheduleLines =
MoreObjects.firstNonNull(
paymentSchedule.getPaymentScheduleLineList(), Collections.emptyList());
int currentMaxSequenceNumber =
paymentScheduleLines
.stream()
.mapToInt(PaymentScheduleLine::getScheduleLineSeq)
.max()
.orElse(0);
return currentMaxSequenceNumber + 1;
}
}

View File

@ -0,0 +1,27 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Move;
import com.axelor.apps.base.db.Period;
import com.axelor.db.Query;
public interface PeriodServiceAccount {
public Query<Move> getMoveListToValidateQuery(Period period);
}

View File

@ -0,0 +1,71 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.service.move.MoveValidateService;
import com.axelor.apps.base.db.Period;
import com.axelor.apps.base.db.repo.PeriodRepository;
import com.axelor.apps.base.db.repo.YearRepository;
import com.axelor.apps.base.service.AdjustHistoryService;
import com.axelor.apps.base.service.PeriodServiceImpl;
import com.axelor.db.Query;
import com.axelor.exception.AxelorException;
import com.google.inject.Inject;
import javax.inject.Singleton;
@Singleton
public class PeriodServiceAccountImpl extends PeriodServiceImpl implements PeriodServiceAccount {
protected MoveValidateService moveValidateService;
protected MoveRepository moveRepository;
@Inject
public PeriodServiceAccountImpl(
PeriodRepository periodRepo,
AdjustHistoryService adjustHistoryService,
MoveValidateService moveValidateService,
MoveRepository moveRepository) {
super(periodRepo, adjustHistoryService);
this.moveValidateService = moveValidateService;
this.moveRepository = moveRepository;
}
public void close(Period period) throws AxelorException {
if (period.getYear().getTypeSelect() == YearRepository.TYPE_FISCAL) {
moveValidateService.validateMultiple(getMoveListToValidateQuery(period));
period = periodRepo.find(period.getId());
}
super.close(period);
}
public Query<Move> getMoveListToValidateQuery(Period period) {
return moveRepository
.all()
.filter(
"self.period.id = ?1 AND (self.statusSelect NOT IN (?2,?3, ?4) OR (self.statusSelect = ?2 AND (self.archived = false OR self.archived is null)))",
period.getId(),
MoveRepository.STATUS_NEW,
MoveRepository.STATUS_VALIDATED,
MoveRepository.STATUS_CANCELED)
.order("date")
.order("id");
}
}

View File

@ -0,0 +1,30 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.ReconcileGroup;
import com.axelor.exception.AxelorException;
public interface ReconcileGroupSequenceService {
/**
* Set sequence for reconcile group, based on the status of the reconcile group, the sequence can
* be draft or final.
*/
void fillCodeFromSequence(ReconcileGroup reconcileGroup) throws AxelorException;
}

View File

@ -0,0 +1,56 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.ReconcileGroup;
import com.axelor.apps.account.db.repo.ReconcileGroupRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.base.db.repo.SequenceRepository;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
public class ReconcileGroupSequenceServiceImpl implements ReconcileGroupSequenceService {
@Override
public void fillCodeFromSequence(ReconcileGroup reconcileGroup) throws AxelorException {
String sequenceCode;
String exceptionMessage;
if (reconcileGroup.getStatusSelect() == ReconcileGroupRepository.STATUS_FINAL) {
sequenceCode = SequenceRepository.RECONCILE_GROUP_FINAL;
exceptionMessage = IExceptionMessage.RECONCILE_GROUP_NO_FINAL_SEQUENCE;
} else {
sequenceCode = SequenceRepository.RECONCILE_GROUP_DRAFT;
exceptionMessage = IExceptionMessage.RECONCILE_GROUP_NO_TEMP_SEQUENCE;
}
String code =
Beans.get(SequenceService.class)
.getSequenceNumber(sequenceCode, reconcileGroup.getCompany());
if (code == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(exceptionMessage),
reconcileGroup);
}
reconcileGroup.setCode(code);
}
}

View File

@ -0,0 +1,128 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Reconcile;
import com.axelor.apps.account.db.ReconcileGroup;
import com.axelor.apps.base.db.Company;
import com.axelor.exception.AxelorException;
import java.util.List;
import java.util.Optional;
public interface ReconcileGroupService {
/**
* Validate the given reconcile group. A reconcile Group can be validated if it is not empty and
* its lines are balanced.
*
* @param reconcileGroup a reconcile group.
* @param reconcileList a list of reconcile.
* @throws AxelorException if the reconcile list is empty.
*/
void validate(ReconcileGroup reconcileGroup, List<Reconcile> reconcileList)
throws AxelorException;
/**
* Check if the given reconcile lines are balanced.
*
* @param reconcileList a list of reconcile.
*/
boolean isBalanced(List<Reconcile> reconcileList) throws AxelorException;
/**
* Call {@link ReconcileGroupService#findOrMergeGroup} to get a reconcile group. If not found,
* create one with {@link ReconcileGroupService#createReconcileGroup}
*
* @param reconcile a confirmed reconcile
* @return the created or found group.
*/
ReconcileGroup findOrCreateGroup(Reconcile reconcile);
/**
* Find the corresponding group for a given reconcile. If two or more reconcile group are found,
* then return the merge between them.
*
* @param reconcile a confirmed reconcile.
* @return an optional with the reconcile group if it was found. Else an empty optional.
*/
Optional<ReconcileGroup> findOrMergeGroup(Reconcile reconcile);
/**
* Merge reconcile groups into one. The created reconcile group will have a new sequence and all
* reconcile lines from the groups.
*
* @param reconcileGroupList a non empty list of reconcile group to merge.
* @return the created reconcile group.
*/
ReconcileGroup mergeReconcileGroups(List<ReconcileGroup> reconcileGroupList);
/**
* Create a reconcile group with the given reconcile.
*
* @param company a confirmed reconcile.
* @return a new reconcile group.
*/
ReconcileGroup createReconcileGroup(Company company);
/**
* Add a reconcile to a group and validate the group if it is balanced.
*
* @param reconcileGroup a reconcileGroup.
* @param reconcile a reconcile.
*/
void addAndValidate(ReconcileGroup reconcileGroup, Reconcile reconcile) throws AxelorException;
/**
* Add a reconcile to a group and validate the group if it is balanced.
*
* @param reconcileGroup a reconcileGroup.
* @param List<reconcile> a list reconcile.
*/
public void addAllAndValidate(ReconcileGroup reconcileGroup, List<Reconcile> reconcileList)
throws AxelorException;
/**
* Add the reconcile and its move line to the reconcile group.
*
* @param reconcileGroup a reconcileGroup.
* @param reconcile the confirmed reconcile to be added.
*/
void addToReconcileGroup(ReconcileGroup reconcileGroup, Reconcile reconcile);
/**
* Remove a reconcile from a reconcile group then update the group.
*
* @param reconcile a reconcile with a reconcile group.
*/
void remove(Reconcile reconcile) throws AxelorException;
/**
* Update the status and the sequence of a reconcile group.
*
* @param reconcileGroup
*/
void updateStatus(ReconcileGroup reconcileGroup) throws AxelorException;
/**
* Unletter every moveline and update unlettering date.
*
* @param reconcileGroup
* @throws AxelorException
*/
void unletter(ReconcileGroup reconcileGroup) throws AxelorException;
}

View File

@ -0,0 +1,290 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.Reconcile;
import com.axelor.apps.account.db.ReconcileGroup;
import com.axelor.apps.account.db.repo.MoveLineRepository;
import com.axelor.apps.account.db.repo.ReconcileGroupRepository;
import com.axelor.apps.account.db.repo.ReconcileRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
public class ReconcileGroupServiceImpl implements ReconcileGroupService {
protected ReconcileGroupRepository reconcileGroupRepository;
protected ReconcileRepository reconcileRepository;
protected MoveLineRepository moveLineRepository;
protected ReconcileService reconcileService;
protected AppBaseService appBaseService;
protected ReconcileGroupSequenceService reconcileGroupSequenceService;
@Inject
public ReconcileGroupServiceImpl(
ReconcileGroupRepository reconcileGroupRepository,
ReconcileRepository reconcileRepository,
MoveLineRepository moveLineRepository,
ReconcileService reconcileService,
AppBaseService appBaseService,
ReconcileGroupSequenceService reconcileGroupSequenceService) {
this.reconcileGroupRepository = reconcileGroupRepository;
this.reconcileRepository = reconcileRepository;
this.moveLineRepository = moveLineRepository;
this.reconcileService = reconcileService;
this.appBaseService = appBaseService;
this.reconcileGroupSequenceService = reconcileGroupSequenceService;
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void validate(ReconcileGroup reconcileGroup, List<Reconcile> reconcileList)
throws AxelorException {
if (CollectionUtils.isEmpty(reconcileList)) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.RECONCILE_GROUP_VALIDATION_NO_LINES),
reconcileGroup);
}
reconcileGroup.setStatusSelect(ReconcileGroupRepository.STATUS_FINAL);
reconcileGroup.setDateOfLettering(appBaseService.getTodayDate());
reconcileGroupSequenceService.fillCodeFromSequence(reconcileGroup);
}
@Override
public boolean isBalanced(List<Reconcile> reconcileList) {
List<MoveLine> debitMoveLineList =
reconcileList
.stream()
.map(Reconcile::getDebitMoveLine)
.distinct()
.collect(Collectors.toList());
List<MoveLine> creditMoveLineList =
reconcileList
.stream()
.map(Reconcile::getCreditMoveLine)
.distinct()
.collect(Collectors.toList());
List<Account> accountList =
debitMoveLineList
.stream()
.map(MoveLine::getAccount)
.distinct()
.collect(Collectors.toList());
accountList.addAll(
creditMoveLineList
.stream()
.map(MoveLine::getAccount)
.distinct()
.collect(Collectors.toList()));
for (Account account : accountList) {
BigDecimal totalDebit =
debitMoveLineList
.stream()
.filter(moveLine -> moveLine.getAccount().equals(account))
.map(MoveLine::getDebit)
.reduce(BigDecimal::add)
.orElse(BigDecimal.ZERO);
BigDecimal totalCredit =
creditMoveLineList
.stream()
.filter(moveLine -> moveLine.getAccount().equals(account))
.map(MoveLine::getCredit)
.reduce(BigDecimal::add)
.orElse(BigDecimal.ZERO);
if (totalDebit.compareTo(totalCredit) != 0) {
return false;
}
}
return true;
}
@Override
public ReconcileGroup findOrCreateGroup(Reconcile reconcile) {
return findOrMergeGroup(reconcile)
.orElseGet(() -> createReconcileGroup(reconcile.getCompany()));
}
@Override
public Optional<ReconcileGroup> findOrMergeGroup(Reconcile reconcile) {
List<ReconcileGroup> otherReconcileGroupList;
MoveLine debitMoveLine = reconcile.getDebitMoveLine();
MoveLine creditMoveLine = reconcile.getCreditMoveLine();
otherReconcileGroupList = new ArrayList<>();
if (debitMoveLine.getReconcileGroup() != null) {
otherReconcileGroupList.add(debitMoveLine.getReconcileGroup());
}
if (creditMoveLine.getReconcileGroup() != null) {
otherReconcileGroupList.add(creditMoveLine.getReconcileGroup());
}
otherReconcileGroupList =
otherReconcileGroupList.stream().distinct().collect(Collectors.toList());
if (otherReconcileGroupList.isEmpty()) {
return Optional.empty();
} else if (otherReconcileGroupList.size() == 1) {
return Optional.of(otherReconcileGroupList.get(0));
} else {
return Optional.of(mergeReconcileGroups(otherReconcileGroupList));
}
}
@Override
@Transactional
public ReconcileGroup mergeReconcileGroups(List<ReconcileGroup> reconcileGroupList) {
Company company = reconcileGroupList.get(0).getCompany();
ReconcileGroup reconcileGroup = createReconcileGroup(company);
List<Reconcile> reconcileList =
reconcileRepository
.all()
.filter("self.reconcileGroup.id IN (:reconcileGroupIds)")
.bind(
"reconcileGroupIds",
reconcileGroupList.stream().map(ReconcileGroup::getId).collect(Collectors.toList()))
.fetch();
reconcileList.forEach(reconcile -> addToReconcileGroup(reconcileGroup, reconcile));
for (ReconcileGroup toDeleteReconcileGroup : reconcileGroupList) {
reconcileGroupRepository.remove(toDeleteReconcileGroup);
}
return reconcileGroupRepository.save(reconcileGroup);
}
@Override
@Transactional
public ReconcileGroup createReconcileGroup(Company company) {
ReconcileGroup reconcileGroup = new ReconcileGroup();
reconcileGroup.setCompany(company);
return reconcileGroupRepository.save(reconcileGroup);
}
@Override
public void addAndValidate(ReconcileGroup reconcileGroup, Reconcile reconcile)
throws AxelorException {
List<Reconcile> reconcileList = this.getReconcileList(reconcileGroup);
reconcileList.add(reconcile);
addToReconcileGroup(reconcileGroup, reconcile);
if (isBalanced(reconcileList)) {
validate(reconcileGroup, reconcileList);
}
}
@Override
public void addAllAndValidate(ReconcileGroup reconcileGroup, List<Reconcile> reconcileList)
throws AxelorException {
for (Reconcile reconcile : reconcileList) {
addToReconcileGroup(reconcileGroup, reconcile);
}
if (isBalanced(reconcileList)) {
validate(reconcileGroup, reconcileList);
}
}
@Override
public void addToReconcileGroup(ReconcileGroup reconcileGroup, Reconcile reconcile) {
reconcile.setReconcileGroup(reconcileGroup);
reconcile.getDebitMoveLine().setReconcileGroup(reconcileGroup);
reconcile.getCreditMoveLine().setReconcileGroup(reconcileGroup);
}
@Override
public void remove(Reconcile reconcile) throws AxelorException {
ReconcileGroup reconcileGroup = reconcile.getReconcileGroup();
// update move lines
List<MoveLine> moveLineToRemoveList =
moveLineRepository.findByReconcileGroup(reconcileGroup).fetch();
moveLineToRemoveList.forEach(moveLine -> moveLine.setReconcileGroup(null));
List<Reconcile> reconcileList = this.getReconcileList(reconcileGroup);
reconcileList
.stream()
.map(Reconcile::getDebitMoveLine)
.forEach(moveLine -> moveLine.setReconcileGroup(reconcileGroup));
reconcileList
.stream()
.map(Reconcile::getCreditMoveLine)
.forEach(moveLine -> moveLine.setReconcileGroup(reconcileGroup));
// update status
updateStatus(reconcileGroup);
}
@Override
public void updateStatus(ReconcileGroup reconcileGroup) throws AxelorException {
List<Reconcile> reconcileList = this.getReconcileList(reconcileGroup);
int status = reconcileGroup.getStatusSelect();
if (CollectionUtils.isNotEmpty(reconcileList)
&& isBalanced(reconcileList)
&& status == ReconcileGroupRepository.STATUS_TEMPORARY) {
validate(reconcileGroup, reconcileList);
} else if (status == ReconcileGroupRepository.STATUS_FINAL) {
// it is not balanced or the collection is empty.
if (CollectionUtils.isEmpty(reconcileList)) {
reconcileGroup.setStatusSelect(ReconcileGroupRepository.STATUS_UNLETTERED);
reconcileGroup.setUnletteringDate(appBaseService.getTodayDate());
reconcileGroupRepository.save(reconcileGroup);
} else {
reconcileGroup.setStatusSelect(ReconcileGroupRepository.STATUS_TEMPORARY);
reconcileGroupSequenceService.fillCodeFromSequence(reconcileGroup);
}
}
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void unletter(ReconcileGroup reconcileGroup) throws AxelorException {
List<Reconcile> reconcileList = this.getReconcileList(reconcileGroup);
for (Reconcile reconcile : reconcileList) {
reconcileService.unreconcile(reconcile);
}
reconcileGroup.setUnletteringDate(appBaseService.getTodayDate());
reconcileGroup.setStatusSelect(ReconcileGroupRepository.STATUS_UNLETTERED);
reconcileGroupRepository.save(reconcileGroup);
}
protected List<Reconcile> getReconcileList(ReconcileGroup reconcileGroup) {
return reconcileRepository
.all()
.filter("self.reconcileGroup.id = :reconcileGroupId AND self.statusSelect = :confirmed")
.bind("reconcileGroupId", reconcileGroup.getId())
.bind("confirmed", ReconcileRepository.STATUS_CONFIRMED)
.fetch();
}
}

View File

@ -0,0 +1,70 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Reconcile;
import com.axelor.apps.account.db.repo.ReconcileRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.base.db.repo.SequenceRepository;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.common.base.Strings;
import com.google.inject.Inject;
public class ReconcileSequenceService {
protected SequenceService sequenceService;
@Inject
public ReconcileSequenceService(SequenceService sequenceService) {
this.sequenceService = sequenceService;
}
public void setSequence(Reconcile reconcile) throws AxelorException {
reconcile.setReconcileSeq(this.getSequence(reconcile));
}
protected String getSequence(Reconcile reconcile) throws AxelorException {
SequenceService sequenceService = Beans.get(SequenceService.class);
String seq =
sequenceService.getSequenceNumber(
SequenceRepository.RECONCILE, reconcile.getDebitMoveLine().getMove().getCompany());
if (seq == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.RECONCILE_6),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
reconcile.getCompany().getName());
}
return seq;
}
public void setDraftSequence(Reconcile reconcile) throws AxelorException {
if (reconcile.getId() != null
&& Strings.isNullOrEmpty(reconcile.getReconcileSeq())
&& reconcile.getStatusSelect() == ReconcileRepository.STATUS_DRAFT) {
reconcile.setReconcileSeq(sequenceService.getDraftSequenceNumber(reconcile));
}
}
}

View File

@ -0,0 +1,81 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.Reconcile;
import com.axelor.apps.base.db.Partner;
import com.axelor.exception.AxelorException;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.util.List;
public interface ReconcileService {
@Transactional
public Reconcile createReconcile(
MoveLine debitMoveLine,
MoveLine creditMoveLine,
BigDecimal amount,
boolean canBeZeroBalanceOk);
@Transactional(rollbackOn = {Exception.class})
public Reconcile confirmReconcile(Reconcile reconcile, boolean updateInvoicePayments)
throws AxelorException;
@Transactional(rollbackOn = {Exception.class})
public Reconcile confirmPaymentVoucherReconcile(
Reconcile reconcile, boolean updateInvoicePayments) throws AxelorException;
public void reconcilePreconditions(Reconcile reconcile) throws AxelorException;
public void updatePartnerAccountingSituation(Reconcile reconcile) throws AxelorException;
public List<Partner> getPartners(Reconcile reconcile);
public Reconcile reconcile(
MoveLine debitMoveLine,
MoveLine creditMoveLine,
boolean canBeZeroBalanceOk,
boolean updateInvoicePayments)
throws AxelorException;
@Transactional(rollbackOn = {Exception.class})
public void unreconcile(Reconcile reconcile) throws AxelorException;
@Transactional(rollbackOn = {Exception.class})
public void canBeZeroBalance(Reconcile reconcile) throws AxelorException;
public void balanceCredit(MoveLine creditMoveLine) throws AxelorException;
public List<Reconcile> getReconciles(MoveLine moveLine);
/**
* Add a reconcile to an existing or created reconcile group.
*
* @param reconcile a confirmed reconcile.
*/
void addToReconcileGroup(Reconcile reconcile) throws AxelorException;
public static boolean isReconcilable(MoveLine acc1, MoveLine acc2) {
return acc1.getAccount().getReconcileOk()
&& acc2.getAccount().getReconcileOk()
&& (acc1.getAccount().equals(acc2.getAccount())
|| acc1.getAccount().getCompatibleAccountSet().contains(acc2.getAccount()));
}
}

View File

@ -0,0 +1,620 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.InvoicePayment;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.Reconcile;
import com.axelor.apps.account.db.ReconcileGroup;
import com.axelor.apps.account.db.repo.InvoicePaymentRepository;
import com.axelor.apps.account.db.repo.ReconcileRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.account.service.move.MoveAdjustementService;
import com.axelor.apps.account.service.move.MoveLineService;
import com.axelor.apps.account.service.move.MoveToolService;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCancelService;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCreateService;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ReconcileServiceImpl implements ReconcileService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected MoveToolService moveToolService;
protected AccountCustomerService accountCustomerService;
protected AccountConfigService accountConfigService;
protected ReconcileRepository reconcileRepository;
protected MoveAdjustementService moveAdjustementService;
protected ReconcileSequenceService reconcileSequenceService;
protected InvoicePaymentCreateService invoicePaymentCreateService;
protected InvoicePaymentCancelService invoicePaymentCancelService;
protected MoveLineService moveLineService;
@Inject
public ReconcileServiceImpl(
MoveToolService moveToolService,
AccountCustomerService accountCustomerService,
AccountConfigService accountConfigService,
ReconcileRepository reconcileRepository,
MoveAdjustementService moveAdjustementService,
ReconcileSequenceService reconcileSequenceService,
InvoicePaymentCancelService invoicePaymentCancelService,
InvoicePaymentCreateService invoicePaymentCreateService,
MoveLineService moveLineService) {
this.moveToolService = moveToolService;
this.accountCustomerService = accountCustomerService;
this.accountConfigService = accountConfigService;
this.reconcileRepository = reconcileRepository;
this.moveAdjustementService = moveAdjustementService;
this.reconcileSequenceService = reconcileSequenceService;
this.invoicePaymentCancelService = invoicePaymentCancelService;
this.invoicePaymentCreateService = invoicePaymentCreateService;
this.moveLineService = moveLineService;
}
/**
* Permet de créer une réconciliation en passant les paramètres qu'il faut
*
* @param lineDebit Une ligne d'écriture au débit
* @param lineCredit Une ligne d'écriture au crédit
* @param amount Le montant à reconciler
* @param canBeZeroBalanceOk Peut être soldé?
* @return Une reconciliation
*/
@Transactional
public Reconcile createReconcile(
MoveLine debitMoveLine,
MoveLine creditMoveLine,
BigDecimal amount,
boolean canBeZeroBalanceOk) {
if (ReconcileService.isReconcilable(debitMoveLine, creditMoveLine)
&& amount.compareTo(BigDecimal.ZERO) > 0) {
log.debug(
"Create Reconcile (Company : {}, Debit MoveLine : {}, Credit MoveLine : {}, Amount : {}, Can be zero balance ? {} )",
debitMoveLine.getMove().getCompany(),
debitMoveLine.getName(),
creditMoveLine.getName(),
amount,
canBeZeroBalanceOk);
Reconcile reconcile =
new Reconcile(
debitMoveLine.getMove().getCompany(),
amount.setScale(2, RoundingMode.HALF_EVEN),
debitMoveLine,
creditMoveLine,
ReconcileRepository.STATUS_DRAFT,
canBeZeroBalanceOk);
if (!moveToolService.isDebitMoveLine(debitMoveLine)) {
reconcile.setDebitMoveLine(creditMoveLine);
reconcile.setCreditMoveLine(debitMoveLine);
}
return reconcileRepository.save(reconcile);
}
return null;
}
/**
* Permet de confirmer une réconciliation On ne peut réconcilier que des moveLine ayant le même
* compte
*
* @param reconcile Une reconciliation
* @return L'etat de la reconciliation
* @throws AxelorException
*/
@Transactional(rollbackOn = {Exception.class})
public Reconcile confirmReconcile(Reconcile reconcile, boolean updateInvoicePayments)
throws AxelorException {
this.reconcilePreconditions(reconcile);
MoveLine debitMoveLine = reconcile.getDebitMoveLine();
MoveLine creditMoveLine = reconcile.getCreditMoveLine();
// Add the reconciled amount to the reconciled amount in the move line
creditMoveLine.setAmountPaid(creditMoveLine.getAmountPaid().add(reconcile.getAmount()));
debitMoveLine.setAmountPaid(debitMoveLine.getAmountPaid().add(reconcile.getAmount()));
reconcile = reconcileRepository.save(reconcile);
reconcile.setStatusSelect(ReconcileRepository.STATUS_CONFIRMED);
if (reconcile.getCanBeZeroBalanceOk()) {
// Alors nous utilisons la règle de gestion consitant à imputer l'écart sur un compte
// transitoire si le seuil est respecté
canBeZeroBalance(reconcile);
}
reconcile.setReconciliationDate(LocalDate.now());
reconcileSequenceService.setSequence(reconcile);
this.updatePartnerAccountingSituation(reconcile);
this.updateInvoiceCompanyInTaxTotalRemaining(reconcile);
this.udpatePaymentTax(reconcile);
if (updateInvoicePayments) {
this.updateInvoicePayments(reconcile);
}
// this.addToReconcileGroup(reconcile);
return reconcileRepository.save(reconcile);
}
public void addAllToReconcileGroup(List<Reconcile> reconciles) throws AxelorException {
ReconcileGroupService reconcileGroupService = Beans.get(ReconcileGroupService.class);
ReconcileGroup reconcileGroup = reconcileGroupService.findOrCreateGroup(reconciles.get(0));
reconcileGroupService.addAllAndValidate(reconcileGroup, reconciles);
for (Reconcile reconcile : reconciles) {
this.confirmReconcile(reconcile, true);
}
}
@Override
public void addToReconcileGroup(Reconcile reconcile) throws AxelorException {
ReconcileGroupService reconcileGroupService = Beans.get(ReconcileGroupService.class);
ReconcileGroup reconcileGroup = reconcileGroupService.findOrCreateGroup(reconcile);
reconcileGroupService.addAndValidate(reconcileGroup, reconcile);
}
public void reconcilePreconditions(Reconcile reconcile) throws AxelorException {
MoveLine debitMoveLine = reconcile.getDebitMoveLine();
MoveLine creditMoveLine = reconcile.getCreditMoveLine();
if (debitMoveLine == null || creditMoveLine == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.RECONCILE_1),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION));
}
// Check if move lines companies are the same as the reconcile company
Company reconcileCompany = reconcile.getCompany();
Company debitMoveLineCompany = debitMoveLine.getMove().getCompany();
Company creditMoveLineCompany = creditMoveLine.getMove().getCompany();
if (!debitMoveLineCompany.equals(reconcileCompany)
&& !creditMoveLineCompany.equals(reconcileCompany)) {
throw new AxelorException(
String.format(
I18n.get(IExceptionMessage.RECONCILE_7),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
debitMoveLineCompany,
creditMoveLineCompany,
reconcileCompany),
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR);
}
// Check if move lines accounts are the same (debit and credit)
if (!creditMoveLine.getAccount().equals(debitMoveLine.getAccount())) {
log.debug(
"Compte ligne de credit : {} , Compte ligne de debit : {}",
creditMoveLine.getAccount(),
debitMoveLine.getAccount());
// Check if move lines accounts are compatible
if (!debitMoveLine
.getAccount()
.getCompatibleAccountSet()
.contains(creditMoveLine.getAccount())) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.RECONCILE_2),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION));
}
}
// Check if the amount to reconcile is != zero
if (reconcile.getAmount() == null || reconcile.getAmount().compareTo(BigDecimal.ZERO) == 0) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.RECONCILE_4),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
reconcile.getReconcileSeq(),
debitMoveLine.getName(),
debitMoveLine.getAccount().getLabel(),
creditMoveLine.getName(),
creditMoveLine.getAccount().getLabel());
}
if ((reconcile
.getAmount()
.compareTo(creditMoveLine.getCredit().subtract(creditMoveLine.getAmountPaid()))
> 0
|| (reconcile
.getAmount()
.compareTo(debitMoveLine.getDebit().subtract(debitMoveLine.getAmountPaid()))
> 0))) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.RECONCILE_5) + " " + I18n.get(IExceptionMessage.RECONCILE_3),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
reconcile.getReconcileSeq(),
reconcile.getAmount(),
debitMoveLine.getName(),
debitMoveLine.getAccount().getLabel(),
debitMoveLine.getDebit().subtract(debitMoveLine.getAmountPaid()),
creditMoveLine.getName(),
creditMoveLine.getAccount().getLabel(),
creditMoveLine.getCredit().subtract(creditMoveLine.getAmountPaid()));
}
}
public void updatePartnerAccountingSituation(Reconcile reconcile) throws AxelorException {
List<Partner> partnerList = this.getPartners(reconcile);
if (partnerList != null && !partnerList.isEmpty()) {
Company company = reconcile.getDebitMoveLine().getMove().getCompany();
if (AccountingService.getUpdateCustomerAccount()) {
accountCustomerService.updatePartnerAccountingSituation(
partnerList, company, true, true, false);
} else {
accountCustomerService.flagPartners(partnerList, company);
}
}
}
public List<Partner> getPartners(Reconcile reconcile) {
List<Partner> partnerList = Lists.newArrayList();
Partner debitPartner = reconcile.getDebitMoveLine().getPartner();
Partner creditPartner = reconcile.getCreditMoveLine().getPartner();
if (debitPartner != null && creditPartner != null && debitPartner.equals(creditPartner)) {
partnerList.add(debitPartner);
} else if (debitPartner != null) {
partnerList.add(debitPartner);
} else if (creditPartner != null) {
partnerList.add(creditPartner);
}
return partnerList;
}
public void updateInvoiceCompanyInTaxTotalRemaining(Reconcile reconcile) throws AxelorException {
Invoice debitInvoice = reconcile.getDebitMoveLine().getMove().getInvoice();
Invoice creditInvoice = reconcile.getCreditMoveLine().getMove().getInvoice();
// Update amount remaining on invoice or refund
if (debitInvoice != null) {
debitInvoice.setCompanyInTaxTotalRemaining(
moveToolService.getInTaxTotalRemaining(debitInvoice));
}
if (creditInvoice != null) {
creditInvoice.setCompanyInTaxTotalRemaining(
moveToolService.getInTaxTotalRemaining(creditInvoice));
}
}
public void updateInvoicePayments(Reconcile reconcile) throws AxelorException {
MoveLine debitMoveLine = reconcile.getDebitMoveLine();
MoveLine creditMoveLine = reconcile.getCreditMoveLine();
Move debitMove = debitMoveLine.getMove();
Move creditMove = creditMoveLine.getMove();
Invoice debitInvoice = debitMove.getInvoice();
Invoice creditInvoice = creditMove.getInvoice();
BigDecimal amount = reconcile.getAmount();
if (debitInvoice != null
&& debitMoveLine.getAccount().getUseForPartnerBalance()
&& creditMoveLine.getAccount().getUseForPartnerBalance()) {
InvoicePayment debitInvoicePayment =
invoicePaymentCreateService.createInvoicePayment(debitInvoice, amount, creditMove);
debitInvoicePayment.setReconcile(reconcile);
}
if (creditInvoice != null
&& debitMoveLine.getAccount().getUseForPartnerBalance()
&& creditMoveLine.getAccount().getUseForPartnerBalance()) {
InvoicePayment creditInvoicePayment =
invoicePaymentCreateService.createInvoicePayment(creditInvoice, amount, debitMove);
creditInvoicePayment.setReconcile(reconcile);
}
}
protected void udpatePaymentTax(Reconcile reconcile) throws AxelorException {
Move debitMove = reconcile.getDebitMoveLine().getMove();
Move creditMove = reconcile.getCreditMoveLine().getMove();
Invoice debitInvoice = debitMove.getInvoice();
Invoice creditInvoice = creditMove.getInvoice();
if (debitInvoice != null && creditInvoice == null) {
moveLineService.generateTaxPaymentMoveLineList(
reconcile.getCreditMoveLine(), debitInvoice, reconcile);
}
if (creditInvoice != null && debitInvoice == null) {
moveLineService.generateTaxPaymentMoveLineList(
reconcile.getDebitMoveLine(), creditInvoice, reconcile);
}
}
/**
* Méthode permettant de lettrer une écriture au débit avec une écriture au crédit
*
* @param debitMoveLine
* @param creditMoveLine
* @throws AxelorException
*/
public Reconcile reconcile(
MoveLine debitMoveLine,
MoveLine creditMoveLine,
boolean canBeZeroBalanceOk,
boolean updateInvoicePayments)
throws AxelorException {
BigDecimal amount = debitMoveLine.getAmountRemaining().min(creditMoveLine.getAmountRemaining());
Reconcile reconcile =
this.createReconcile(debitMoveLine, creditMoveLine, amount, canBeZeroBalanceOk);
if (reconcile != null) {
this.confirmReconcile(reconcile, updateInvoicePayments);
return reconcile;
}
return null;
}
/**
* Permet de déréconcilier
*
* @param reconcile Une reconciliation
* @return L'etat de la réconciliation
* @throws AxelorException
*/
@Transactional(rollbackOn = {Exception.class})
public void unreconcile(Reconcile reconcile) throws AxelorException {
log.debug("unreconcile : reconcile : {}", reconcile);
MoveLine debitMoveLine = reconcile.getDebitMoveLine();
MoveLine creditMoveLine = reconcile.getCreditMoveLine();
// Change the state
reconcile.setStatusSelect(ReconcileRepository.STATUS_CANCELED);
// Add the reconciled amount to the reconciled amount in the move line
creditMoveLine.setAmountPaid(creditMoveLine.getAmountPaid().subtract(reconcile.getAmount()));
debitMoveLine.setAmountPaid(debitMoveLine.getAmountPaid().subtract(reconcile.getAmount()));
reconcileRepository.save(reconcile);
// Update amount remaining on invoice or refund
this.updatePartnerAccountingSituation(reconcile);
this.updateInvoiceCompanyInTaxTotalRemaining(reconcile);
this.updateInvoicePaymentsCanceled(reconcile);
this.reverseTaxPaymentMoveLines(reconcile);
// Update reconcile group
Beans.get(ReconcileGroupService.class).remove(reconcile);
}
@Transactional(rollbackOn = {Exception.class})
public void unreconcile2(Reconcile reconcile) throws AxelorException {
log.debug("unreconcile : reconcile : {}", reconcile);
MoveLine debitMoveLine = reconcile.getDebitMoveLine();
MoveLine creditMoveLine = reconcile.getCreditMoveLine();
// Change the state
reconcile.setStatusSelect(ReconcileRepository.STATUS_CANCELED);
// Add the reconciled amount to the reconciled amount in the move line
creditMoveLine.setAmountPaid(creditMoveLine.getAmountPaid().subtract(reconcile.getAmount()));
debitMoveLine.setAmountPaid(debitMoveLine.getAmountPaid().subtract(reconcile.getAmount()));
reconcileRepository.save(reconcile);
// Update amount remaining on invoice or refund
this.updatePartnerAccountingSituation(reconcile);
this.updateInvoiceCompanyInTaxTotalRemaining(reconcile);
this.updateInvoicePaymentsCanceled(reconcile);
this.reverseTaxPaymentMoveLines(reconcile);
// Update reconcile group
// Beans.get(ReconcileGroupService.class).remove(reconcile);
}
protected void reverseTaxPaymentMoveLines(Reconcile reconcile) throws AxelorException {
Move debitMove = reconcile.getDebitMoveLine().getMove();
Move creditMove = reconcile.getCreditMoveLine().getMove();
Invoice debitInvoice = debitMove.getInvoice();
Invoice creditInvoice = creditMove.getInvoice();
if (debitInvoice == null) {
moveLineService.reverseTaxPaymentMoveLines(reconcile.getDebitMoveLine(), reconcile);
}
if (creditInvoice == null) {
moveLineService.reverseTaxPaymentMoveLines(reconcile.getCreditMoveLine(), reconcile);
}
}
public void updateInvoicePaymentsCanceled(Reconcile reconcile) throws AxelorException {
log.debug("updateInvoicePaymentsCanceled : reconcile : {}", reconcile);
List<InvoicePayment> invoicePaymentList =
Beans.get(InvoicePaymentRepository.class)
.all()
.filter("self.reconcile = ?1", reconcile)
.fetch();
for (InvoicePayment invoicePayment : invoicePaymentList) {
invoicePaymentCancelService.updateCancelStatus(invoicePayment);
}
}
/**
* Procédure permettant de gérer les écarts de règlement, check sur la case à cocher 'Peut être
* soldé' Alors nous utilisons la règle de gestion consitant à imputer l'écart sur un compte
* transitoire si le seuil est respecté
*
* @param reconcile Une reconciliation
* @throws AxelorException
*/
@Transactional(rollbackOn = {Exception.class})
public void canBeZeroBalance(Reconcile reconcile) throws AxelorException {
MoveLine debitMoveLine = reconcile.getDebitMoveLine();
BigDecimal debitAmountRemaining = debitMoveLine.getAmountRemaining();
log.debug("Montant à payer / à lettrer au débit : {}", debitAmountRemaining);
if (debitAmountRemaining.compareTo(BigDecimal.ZERO) > 0) {
Company company = reconcile.getDebitMoveLine().getMove().getCompany();
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
if (debitAmountRemaining.plus().compareTo(accountConfig.getThresholdDistanceFromRegulation())
< 0
|| reconcile.getMustBeZeroBalanceOk()) {
log.debug("Seuil respecté");
log.debug("Entrain de se cree");
MoveLine creditAdjustMoveLine =
moveAdjustementService.createAdjustmentCreditMove(debitMoveLine);
// Création de la réconciliation
Reconcile newReconcile =
this.createReconcile(debitMoveLine, creditAdjustMoveLine, debitAmountRemaining, false);
if (newReconcile != null) {
this.confirmReconcile(newReconcile, true);
reconcileRepository.save(newReconcile);
}
}
}
reconcile.setCanBeZeroBalanceOk(false);
log.debug("Fin de la gestion des écarts de règlement");
}
/**
* Solder le trop-perçu si il respect les règles de seuil
*
* @param creditMoveLine
* @param company
* @throws AxelorException
*/
public void balanceCredit(MoveLine creditMoveLine) throws AxelorException {
if (creditMoveLine != null) {
BigDecimal creditAmountRemaining = creditMoveLine.getAmountRemaining();
log.debug("Montant à payer / à lettrer au crédit : {}", creditAmountRemaining);
log.debug("creditMoveLine: {}", creditMoveLine.toString());
if (creditAmountRemaining.compareTo(BigDecimal.ZERO) > 0) {
AccountConfig accountConfig =
accountConfigService.getAccountConfig(creditMoveLine.getMove().getCompany());
if (creditAmountRemaining
.plus()
.compareTo(accountConfig.getThresholdDistanceFromRegulation())
< 0) {
log.debug("Seuil respecté");
MoveLine debitAdjustmentMoveLine =
moveAdjustementService.createAdjustmentDebitMove(creditMoveLine);
log.debug("/////////////// {}", creditAmountRemaining);
// Création de la réconciliation
Reconcile newReconcile =
this.createReconcile(
debitAdjustmentMoveLine, creditMoveLine, creditAmountRemaining, false);
if (newReconcile != null) {
this.confirmReconcile(newReconcile, true);
reconcileRepository.save(newReconcile);
}
}
}
}
}
public List<Reconcile> getReconciles(MoveLine moveLine) {
List<Reconcile> debitReconcileList = moveLine.getDebitReconcileList();
List<Reconcile> creditReconcileList = moveLine.getCreditReconcileList();
if (moveToolService.isDebitMoveLine(moveLine)) {
return debitReconcileList;
} else if (debitReconcileList != null && !creditReconcileList.isEmpty()) {
return creditReconcileList;
}
return Lists.newArrayList();
}
@Override
public Reconcile confirmPaymentVoucherReconcile(
Reconcile reconcile, boolean updateInvoicePayments) throws AxelorException {
this.reconcilePreconditions(reconcile);
MoveLine debitMoveLine = reconcile.getDebitMoveLine();
MoveLine creditMoveLine = reconcile.getCreditMoveLine();
// Add the reconciled amount to the reconciled amount in the move line
creditMoveLine.setAmountPaid(creditMoveLine.getAmountPaid().add(reconcile.getAmount()));
debitMoveLine.setAmountPaid(debitMoveLine.getAmountPaid().add(reconcile.getAmount()));
reconcile = reconcileRepository.save(reconcile);
reconcile.setStatusSelect(ReconcileRepository.STATUS_CONFIRMED);
if (reconcile.getCanBeZeroBalanceOk()) {
// Alors nous utilisons la règle de gestion consitant à imputer l'écart sur un compte
// transitoire si le seuil est respecté
canBeZeroBalance(reconcile);
}
reconcile.setReconciliationDate(LocalDate.now());
reconcileSequenceService.setSequence(reconcile);
this.updatePartnerAccountingSituation(reconcile);
this.updateInvoiceCompanyInTaxTotalRemaining(reconcile);
this.udpatePaymentTax(reconcile);
if (updateInvoicePayments) {
this.updateInvoicePayments(reconcile);
}
this.addToReconcileGroup(reconcile);
return reconcileRepository.save(reconcile);
}
}

View File

@ -0,0 +1,569 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.AccountConfig;
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.Reconcile;
import com.axelor.apps.account.db.Reimbursement;
import com.axelor.apps.account.db.repo.MoveLineRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.db.repo.ReimbursementRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.app.AppAccountService;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.account.service.move.MoveLineService;
import com.axelor.apps.account.service.move.MoveService;
import com.axelor.apps.base.db.BankDetails;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.repo.BlockingRepository;
import com.axelor.apps.base.db.repo.PartnerRepository;
import com.axelor.apps.base.db.repo.SequenceRepository;
import com.axelor.apps.base.service.BlockingService;
import com.axelor.apps.base.service.PartnerService;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ReimbursementExportService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected MoveService moveService;
protected MoveRepository moveRepo;
protected MoveLineService moveLineService;
protected ReconcileService reconcileService;
protected SequenceService sequenceService;
protected ReimbursementRepository reimbursementRepo;
protected AccountConfigService accountConfigService;
protected PartnerService partnerService;
protected PartnerRepository partnerRepository;
protected AppAccountService appAccountService;
@Inject
public ReimbursementExportService(
MoveService moveService,
MoveRepository moveRepo,
MoveLineService moveLineService,
ReconcileService reconcileService,
SequenceService sequenceService,
ReimbursementRepository reimbursementRepo,
AccountConfigService accountConfigService,
PartnerService partnerService,
AppAccountService appAccountService,
PartnerRepository partnerRepository) {
this.moveService = moveService;
this.moveRepo = moveRepo;
this.moveLineService = moveLineService;
this.reconcileService = reconcileService;
this.sequenceService = sequenceService;
this.reimbursementRepo = reimbursementRepo;
this.accountConfigService = accountConfigService;
this.partnerService = partnerService;
this.partnerRepository = partnerRepository;
this.appAccountService = appAccountService;
}
/** @param reimbursementExport */
public void fillMoveLineSet(
Reimbursement reimbursement, List<MoveLine> moveLineList, BigDecimal total) {
log.debug("In fillMoveLineSet");
log.debug("Nombre de trop-perçus trouvés : {}", moveLineList.size());
for (MoveLine moveLine : moveLineList) {
// On passe les lignes d'écriture (trop perçu) à l'état 'en cours de remboursement'
moveLine.setReimbursementStatusSelect(MoveLineRepository.REIMBURSEMENT_STATUS_REIMBURSING);
}
reimbursement.setMoveLineSet(new HashSet<MoveLine>());
reimbursement.getMoveLineSet().addAll(moveLineList);
log.debug("End fillMoveLineSet");
}
/**
* @param reimbursementExport
* @throws AxelorException
*/
@Transactional(rollbackOn = {Exception.class})
public Reimbursement runCreateReimbursement(
List<MoveLine> moveLineList, Company company, Partner partner) throws AxelorException {
log.debug("In runReimbursementProcess");
BigDecimal total = this.getTotalAmountRemaining(moveLineList);
AccountConfig accountConfig = company.getAccountConfig();
// Seuil bas respecté et remboursement manuel autorisé
if (total.compareTo(accountConfig.getLowerThresholdReimbursement()) > 0) {
Reimbursement reimbursement = createReimbursement(partner, company);
fillMoveLineSet(reimbursement, moveLineList, total);
if (total.compareTo(accountConfig.getUpperThresholdReimbursement()) > 0
|| reimbursement.getBankDetails() == null) {
// Seuil haut dépassé
reimbursement.setStatusSelect(ReimbursementRepository.STATUS_TO_VALIDATE);
} else {
reimbursement.setStatusSelect(ReimbursementRepository.STATUS_VALIDATED);
}
reimbursement = reimbursementRepo.save(reimbursement);
return reimbursement;
}
log.debug("End runReimbursementProcess");
return null;
}
/**
* Fonction permettant de calculer le montant total restant à payer / à lettrer
*
* @param movelineList Une liste de ligne d'écriture
* @return Le montant total restant à payer / à lettrer
*/
public BigDecimal getTotalAmountRemaining(List<MoveLine> moveLineList) {
BigDecimal total = BigDecimal.ZERO;
for (MoveLine moveLine : moveLineList) {
total = total.add(moveLine.getAmountRemaining());
}
log.debug("Total Amount Remaining : {}", total);
return total;
}
/**
* Methode permettant de créer l'écriture de remboursement
*
* @param reimbursementExport Un objet d'export des prélèvements
* @throws AxelorException
*/
public void createReimbursementMove(Reimbursement reimbursement, Company company)
throws AxelorException {
reimbursement = reimbursementRepo.find(reimbursement.getId());
Partner partner = null;
Move newMove = null;
boolean first = true;
AccountConfig accountConfig = company.getAccountConfig();
if (reimbursement.getMoveLineSet() != null && !reimbursement.getMoveLineSet().isEmpty()) {
int seq = 1;
for (MoveLine moveLine : reimbursement.getMoveLineSet()) {
BigDecimal amountRemaining = moveLine.getAmountRemaining();
if (amountRemaining.compareTo(BigDecimal.ZERO) > 0) {
partner = moveLine.getPartner();
// On passe les lignes d'écriture (trop perçu) à l'état 'remboursé'
moveLine.setReimbursementStatusSelect(MoveLineRepository.REIMBURSEMENT_STATUS_REIMBURSED);
if (first) {
newMove =
moveService
.getMoveCreateService()
.createMove(
accountConfig.getReimbursementJournal(),
company,
null,
partner,
null,
MoveRepository.TECHNICAL_ORIGIN_AUTOMATIC);
first = false;
}
// Création d'une ligne au débit
MoveLine newDebitMoveLine =
moveLineService.createMoveLine(
newMove,
partner,
moveLine.getAccount(),
amountRemaining,
true,
appAccountService.getTodayDate(),
seq,
reimbursement.getRef(),
reimbursement.getDescription());
newMove.getMoveLineList().add(newDebitMoveLine);
if (reimbursement.getDescription() != null && !reimbursement.getDescription().isEmpty()) {
newDebitMoveLine.setDescription(reimbursement.getDescription());
}
seq++;
// Création de la réconciliation
Reconcile reconcile =
reconcileService.createReconcile(newDebitMoveLine, moveLine, amountRemaining, false);
if (reconcile != null) {
reconcileService.confirmReconcile(reconcile, true);
}
}
}
// Création de la ligne au crédit
MoveLine newCreditMoveLine =
moveLineService.createMoveLine(
newMove,
partner,
accountConfig.getReimbursementAccount(),
reimbursement.getAmountReimbursed(),
false,
appAccountService.getTodayDate(),
seq,
reimbursement.getRef(),
reimbursement.getDescription());
newMove.getMoveLineList().add(newCreditMoveLine);
if (reimbursement.getDescription() != null && !reimbursement.getDescription().isEmpty()) {
newCreditMoveLine.setDescription(reimbursement.getDescription());
}
moveService.getMoveValidateService().validate(newMove);
moveRepo.save(newMove);
}
}
/**
* Procédure permettant de tester la présence des champs et des séquences nécessaire aux
* remboursements.
*
* @param company Une société
* @throws AxelorException
*/
public void testCompanyField(Company company) throws AxelorException {
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
accountConfigService.getReimbursementAccount(accountConfig);
accountConfigService.getReimbursementJournal(accountConfig);
accountConfigService.getReimbursementExportFolderPath(accountConfig);
if (!sequenceService.hasSequence(SequenceRepository.REIMBOURSEMENT, company)) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.REIMBURSEMENT_1),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
company.getName());
}
}
@Transactional(rollbackOn = {Exception.class})
public void reimburse(Reimbursement reimbursement, Company company) throws AxelorException {
reimbursement.setAmountReimbursed(reimbursement.getAmountToReimburse());
this.createReimbursementMove(reimbursement, company);
reimbursement.setStatusSelect(ReimbursementRepository.STATUS_REIMBURSED);
reimbursementRepo.save(reimbursement);
}
/**
* Méthode permettant de créer un remboursement
*
* @param partner Un tiers
* @param company Une société
* @param reimbursementExport Un export des remboursement
* @return Le remboursmeent créé
* @throws AxelorException
*/
public Reimbursement createReimbursement(Partner partner, Company company)
throws AxelorException {
Reimbursement reimbursement = new Reimbursement();
reimbursement.setPartner(partner);
reimbursement.setCompany(company);
BankDetails bankDetails = partnerService.getDefaultBankDetails(partner);
reimbursement.setBankDetails(bankDetails);
reimbursement.setRef(
sequenceService.getSequenceNumber(SequenceRepository.REIMBOURSEMENT, company));
return reimbursement;
}
/**
* Checks if the partner can be reimbursed
*
* @return true if partner can be reimbursed, false otherwise
*/
public boolean canBeReimbursed(Partner partner, Company company) {
return Beans.get(BlockingService.class)
.getBlocking(partner, company, BlockingRepository.REIMBURSEMENT_BLOCKING)
== null;
}
/**
* Procédure permettant de mettre à jour la liste des RIBs du tiers
*
* @param reimbursement Un remboursement
*/
@Transactional
public void updatePartnerCurrentRIB(Reimbursement reimbursement) {
BankDetails bankDetails = reimbursement.getBankDetails();
Partner partner = reimbursement.getPartner();
BankDetails defaultBankDetails = partnerService.getDefaultBankDetails(partner);
if (partner != null && bankDetails != null && !bankDetails.equals(defaultBankDetails)) {
bankDetails.setIsDefault(true);
defaultBankDetails.setIsDefault(false);
partner.addBankDetailsListItem(bankDetails);
partnerRepository.save(partner);
}
}
/*
/**
* Méthode permettant de créer un fichier xml de virement au format SEPA
* @param export
* @param datetime
* @param reimbursementList
* @throws AxelorException
* @throws DatatypeConfigurationException
* @throws JAXBException
* @throws IOException
public void exportSepa(Company company, ZonedDateTime datetime, List<Reimbursement> reimbursementList, BankDetails bankDetails) throws AxelorException, DatatypeConfigurationException, JAXBException, IOException {
String exportFolderPath = accountConfigService.getReimbursementExportFolderPath(accountConfigService.getAccountConfig(company));
if (exportFolderPath == null) {
throw new AxelorException(TraceBackRepository.CATEGORY_MISSING_FIELD, I18n.get(IExceptionMessage.REIMBURSEMENT_2), company.getName());
}
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
Date date = Date.from(datetime.toInstant());
BigDecimal ctrlSum = BigDecimal.ZERO;
int nbOfTxs = 0;
/**
* Création du documemnt XML en mémoire
-/
ObjectFactory factory = new ObjectFactory();
// Débit
// Paiement
ServiceLevel2Choice svcLvl = factory.createServiceLevel2Choice();
svcLvl.setCd(ServiceLevel1Code.SEPA);
PaymentTypeInformation1 pmtTpInf = factory.createPaymentTypeInformation1();
pmtTpInf.setSvcLvl(svcLvl);
// Payeur
PartyIdentification8 dbtr = factory.createPartyIdentification8();
dbtr.setNm(bankDetails.getOwnerName());
// IBAN
AccountIdentification3Choice iban = factory.createAccountIdentification3Choice();
iban.setIBAN(bankDetails.getIban());
CashAccount7 dbtrAcct = factory.createCashAccount7();
dbtrAcct.setId(iban);
// BIC
FinancialInstitutionIdentification5Choice finInstnId = factory.createFinancialInstitutionIdentification5Choice();
finInstnId.setBIC(bankDetails.getBank().getCode());
BranchAndFinancialInstitutionIdentification3 dbtrAgt = factory.createBranchAndFinancialInstitutionIdentification3();
dbtrAgt.setFinInstnId(finInstnId);
// Lot
PaymentInstructionInformation1 pmtInf = factory.createPaymentInstructionInformation1();
pmtInf.setPmtMtd(PaymentMethod3Code.TRF);
pmtInf.setPmtTpInf(pmtTpInf);
pmtInf.setReqdExctnDt(datatypeFactory.newXMLGregorianCalendar(dateFormat.format(date)));
pmtInf.setDbtr(dbtr);
pmtInf.setDbtrAcct(dbtrAcct);
pmtInf.setDbtrAgt(dbtrAgt);
// Crédit
CreditTransferTransactionInformation1 cdtTrfTxInf = null; PaymentIdentification1 pmtId = null;
AmountType2Choice amt = null; CurrencyAndAmount instdAmt = null;
PartyIdentification8 cbtr = null; CashAccount7 cbtrAcct = null;
BranchAndFinancialInstitutionIdentification3 cbtrAgt = null;
RemittanceInformation1 rmtInf = null;
for (Reimbursement reimbursement : reimbursementList){
reimbursement = reimbursementRepo.find(reimbursement.getId());
nbOfTxs++;
ctrlSum = ctrlSum.add(reimbursement.getAmountReimbursed());
bankDetails = reimbursement.getBankDetails();
// Paiement
pmtId = factory.createPaymentIdentification1();
pmtId.setEndToEndId(reimbursement.getRef());
// Montant
instdAmt = factory.createCurrencyAndAmount();
instdAmt.setCcy("EUR");
instdAmt.setValue(reimbursement.getAmountReimbursed());
amt = factory.createAmountType2Choice();
amt.setInstdAmt(instdAmt);
// Débiteur
cbtr = factory.createPartyIdentification8();
cbtr.setNm(bankDetails.getOwnerName());
// IBAN
iban = factory.createAccountIdentification3Choice();
iban.setIBAN(bankDetails.getIban());
cbtrAcct = factory.createCashAccount7();
cbtrAcct.setId(iban);
// BIC
finInstnId = factory.createFinancialInstitutionIdentification5Choice();
finInstnId.setBIC(bankDetails.getBank().getCode());
cbtrAgt = factory.createBranchAndFinancialInstitutionIdentification3();
cbtrAgt.setFinInstnId(finInstnId);
rmtInf = factory.createRemittanceInformation1();
rmtInf.getUstrd().add(reimbursement.getDescription());
// Transaction
cdtTrfTxInf = factory.createCreditTransferTransactionInformation1();
cdtTrfTxInf.setPmtId(pmtId);
cdtTrfTxInf.setAmt(amt);
cdtTrfTxInf.setCdtr(cbtr);
cdtTrfTxInf.setCdtrAcct(cbtrAcct);
cdtTrfTxInf.setCdtrAgt(cbtrAgt);
cdtTrfTxInf.setRmtInf(rmtInf);
pmtInf.getCdtTrfTxInf().add(cdtTrfTxInf);
}
// En-tête
dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
GroupHeader1 grpHdr = factory.createGroupHeader1();
grpHdr.setCreDtTm(datatypeFactory.newXMLGregorianCalendar(dateFormat.format(date)));
grpHdr.setNbOfTxs(Integer.toString(nbOfTxs));
grpHdr.setCtrlSum(ctrlSum);
grpHdr.setGrpg(Grouping1Code.MIXD);
grpHdr.setInitgPty(dbtr);
// Parent
Pain00100102 pain00100102 = factory.createPain00100102();
pain00100102.setGrpHdr(grpHdr);
pain00100102.getPmtInf().add(pmtInf);
// Document
Document xml = factory.createDocument();
xml.setPain00100102(pain00100102);
/**
* Création du documemnt XML physique
-/
Marschaller.marschalFile(factory.createDocument(xml), "com.axelor.apps.xsd.sepa",
exportFolderPath, String.format("%s.xml", dateFormat.format(date)));
}
*/
/**
* *********************** Remboursement lors d'une facture fin de cycle
* ********************************
*/
/**
* Procédure permettant de créer un remboursement si un trop perçu est généré à la facture fin de
* cycle
*
* @param partner Un tiers
* @param company Une société
* @param moveLine Un trop-perçu
* @throws AxelorException
*/
@SuppressWarnings("unchecked")
@Transactional(rollbackOn = {Exception.class})
public void createReimbursementInvoice(
Partner partner, Company company, List<? extends MoveLine> moveLineList)
throws AxelorException {
BigDecimal total = this.getTotalAmountRemaining((List<MoveLine>) moveLineList);
if (total.compareTo(BigDecimal.ZERO) > 0) {
this.testCompanyField(company);
Reimbursement reimbursement = this.createReimbursement(partner, company);
this.fillMoveLineSet(reimbursement, (List<MoveLine>) moveLineList, total);
if (total.compareTo(company.getAccountConfig().getUpperThresholdReimbursement()) > 0
|| reimbursement.getBankDetails() == null) {
// Seuil haut dépassé
reimbursement.setStatusSelect(ReimbursementRepository.STATUS_TO_VALIDATE);
} else {
// Seuil haut non dépassé
reimbursement.setStatusSelect(ReimbursementRepository.STATUS_VALIDATED);
}
reimbursementRepo.save(reimbursement);
}
}
/**
* Procédure permettant de créer un remboursement si un trop perçu est généré à la facture fin de
* cycle grand comptes
*
* @param invoice Une facture
* @throws AxelorException
*/
@Transactional(rollbackOn = {Exception.class})
public void createReimbursementInvoice(Invoice invoice) throws AxelorException {
Company company = invoice.getCompany();
Partner partner = invoice.getPartner();
MoveLineRepository moveLineRepo = Beans.get(MoveLineRepository.class);
// récupération des trop-perçus du tiers
List<? extends MoveLine> moveLineList =
moveLineRepo
.all()
.filter(
"self.account.useForPartnerBalance = 'true' "
+ "AND (self.move.statusSelect = ?1 OR self.move.statusSelect = ?2) AND self.amountRemaining > 0 AND self.credit > 0 AND self.partner = ?3 AND self.reimbursementStatusSelect = ?4 ",
MoveRepository.STATUS_VALIDATED,
MoveRepository.STATUS_DAYBOOK,
partner,
MoveLineRepository.REIMBURSEMENT_STATUS_NULL)
.fetch();
this.createReimbursementInvoice(partner, company, moveLineList);
}
}

View File

@ -0,0 +1,248 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.InterbankCodeLine;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.Reimbursement;
import com.axelor.apps.account.db.repo.MoveLineRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.db.repo.ReimbursementRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.account.service.move.MoveLineService;
import com.axelor.apps.account.service.move.MoveService;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ReimbursementImportService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected MoveService moveService;
protected MoveRepository moveRepo;
protected MoveLineService moveLineService;
protected RejectImportService rejectImportService;
protected AccountConfigService accountConfigService;
protected ReimbursementRepository reimbursementRepo;
@Inject
public ReimbursementImportService(
MoveService moveService,
MoveRepository moveRepo,
MoveLineService moveLineService,
RejectImportService rejectImportService,
AccountConfigService accountConfigService,
ReimbursementRepository reimbursementRepo) {
this.moveService = moveService;
this.moveRepo = moveRepo;
this.moveLineService = moveLineService;
this.rejectImportService = rejectImportService;
this.accountConfigService = accountConfigService;
this.reimbursementRepo = reimbursementRepo;
}
@Transactional(rollbackOn = {Exception.class})
public void runReimbursementImport(Company company) throws AxelorException, IOException {
this.testCompanyField(company);
AccountConfig accountConfig = company.getAccountConfig();
this.createReimbursementRejectMove(
rejectImportService.getCFONBFile(
accountConfig.getReimbursementImportFolderPathCFONB(),
accountConfig.getTempReimbImportFolderPathCFONB(),
company,
0),
company);
}
public void createReimbursementRejectMove(List<String[]> rejectList, Company company)
throws AxelorException {
int seq = 1;
if (rejectList != null && !rejectList.isEmpty()) {
LocalDate rejectDate = rejectImportService.createRejectDate(rejectList.get(0)[0]);
Move move = this.createMoveReject(company, rejectDate);
for (String[] reject : rejectList) {
this.createReimbursementRejectMoveLine(reject, company, seq, move, rejectDate);
seq++;
}
if (move != null) {
// Création d'une ligne au débit
MoveLine debitMoveLine =
moveLineService.createMoveLine(
move,
null,
company.getAccountConfig().getReimbursementAccount(),
this.getTotalAmount(move),
true,
rejectDate,
seq,
null,
null);
move.getMoveLineList().add(debitMoveLine);
this.validateMove(move);
}
}
}
@Transactional(rollbackOn = {Exception.class})
public Reimbursement createReimbursementRejectMoveLine(
String[] reject, Company company, int seq, Move move, LocalDate rejectDate)
throws AxelorException {
String refReject = reject[1];
// String amountReject = reject[2];
InterbankCodeLine causeReject = rejectImportService.getInterbankCodeLine(reject[3], 0);
MoveLineRepository moveLineRepo = Beans.get(MoveLineRepository.class);
Reimbursement reimbursement =
reimbursementRepo
.all()
.filter("UPPER(self.ref) = ?1 AND self.company = ?2", refReject, company)
.fetchOne();
if (reimbursement == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.REIMBURSEMENT_3),
refReject,
company.getName());
}
Partner partner = reimbursement.getPartner();
BigDecimal amount = reimbursement.getAmountReimbursed();
// Création de la ligne au crédit
MoveLine creditMoveLine =
moveLineService.createMoveLine(
move,
partner,
company.getAccountConfig().getCustomerAccount(),
amount,
false,
rejectDate,
seq,
refReject,
null);
move.getMoveLineList().add(creditMoveLine);
moveLineRepo.save(creditMoveLine);
moveRepo.save(move);
creditMoveLine.setInterbankCodeLine(causeReject);
reimbursement.setRejectedOk(true);
reimbursement.setRejectDate(rejectDate);
reimbursement.setRejectMoveLine(creditMoveLine);
reimbursement.setInterbankCodeLine(causeReject);
reimbursementRepo.save(reimbursement);
return reimbursement;
}
@Transactional(rollbackOn = {Exception.class})
public Move createMoveReject(Company company, LocalDate date) throws AxelorException {
return moveRepo.save(
moveService
.getMoveCreateService()
.createMove(
company.getAccountConfig().getRejectJournal(),
company,
null,
null,
date,
null,
MoveRepository.TECHNICAL_ORIGIN_IMPORT));
}
public BigDecimal getTotalAmount(Move move) {
BigDecimal totalAmount = BigDecimal.ZERO;
for (MoveLine moveLine : move.getMoveLineList()) {
totalAmount = totalAmount.add(moveLine.getCredit());
}
return totalAmount;
}
@Transactional(rollbackOn = {Exception.class})
public MoveLine createOppositeRejectMoveLine(Move move, int seq, LocalDate rejectDate)
throws AxelorException {
// Création d'une ligne au débit
MoveLine debitMoveLine =
moveLineService.createMoveLine(
move,
null,
move.getCompany().getAccountConfig().getReimbursementAccount(),
this.getTotalAmount(move),
true,
rejectDate,
seq,
null,
null);
move.getMoveLineList().add(debitMoveLine);
moveRepo.save(move);
return debitMoveLine;
}
@Transactional(rollbackOn = {Exception.class})
public void validateMove(Move move) throws AxelorException {
moveService.getMoveValidateService().validate(move);
moveRepo.save(move);
}
@Transactional
public void deleteMove(Move move) {
moveRepo.remove(move);
}
/**
* Procédure permettant de tester la présence des champs et des séquences nécessaire aux rejets de
* remboursement.
*
* @param company Une société
* @throws AxelorException
*/
public void testCompanyField(Company company) throws AxelorException {
log.debug("Test de la société {}", company.getName());
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
accountConfigService.getReimbursementAccount(accountConfig);
accountConfigService.getRejectJournal(accountConfig);
accountConfigService.getReimbursementImportFolderPathCFONB(accountConfig);
accountConfigService.getTempReimbImportFolderPathCFONB(accountConfig);
}
}

View File

@ -0,0 +1,58 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Reimbursement;
import com.axelor.apps.base.db.BankDetails;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.repo.PartnerRepository;
import com.axelor.apps.base.service.PartnerService;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
public class ReimbursementService {
protected PartnerRepository partnerRepository;
protected PartnerService partnerService;
@Inject
public ReimbursementService(PartnerRepository partnerRepository, PartnerService partnerService) {
this.partnerRepository = partnerRepository;
this.partnerService = partnerService;
}
/**
* Procédure permettant de mettre à jour la liste des RIBs du tiers
*
* @param reimbursement Un remboursement
*/
@Transactional
public void updatePartnerCurrentRIB(Reimbursement reimbursement) {
BankDetails bankDetails = reimbursement.getBankDetails();
Partner partner = reimbursement.getPartner();
BankDetails defaultBankDetails = partnerService.getDefaultBankDetails(partner);
if (bankDetails != null && partner != null && !bankDetails.equals(defaultBankDetails)) {
defaultBankDetails.setIsDefault(false);
bankDetails.setIsDefault(true);
partner.addBankDetailsListItem(bankDetails);
partnerRepository.save(partner);
}
}
}

View File

@ -0,0 +1,216 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.InterbankCodeLine;
import com.axelor.apps.account.db.repo.InterbankCodeLineRepository;
import com.axelor.apps.account.service.app.AppAccountService;
import com.axelor.apps.account.service.bankorder.file.cfonb.CfonbImportService;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.tool.file.FileTool;
import com.axelor.exception.AxelorException;
import com.google.common.io.Files;
import com.google.inject.Inject;
import java.io.File;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RejectImportService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected AppAccountService appAccountService;
protected CfonbImportService cfonbImportService;
protected InterbankCodeLineRepository interbankCodeLineRepo;
@Inject
public RejectImportService(
AppAccountService appAccountService,
CfonbImportService cfonbImportService,
InterbankCodeLineRepository interbankCodeLineRepo) {
this.appAccountService = appAccountService;
this.cfonbImportService = cfonbImportService;
this.interbankCodeLineRepo = interbankCodeLineRepo;
}
public String getDestFilename(String src, String dest) {
// chemin du fichier de destination :
log.debug("Chemin de destination : {}", dest);
String newDest = ((dest).split("\\."))[0];
String timeString = appAccountService.getTodayDateTime().toString();
timeString = timeString.replace("-", "");
timeString = timeString.replace(":", "");
timeString = timeString.replace(".", "");
timeString = timeString.replace("+", "");
newDest += "_" + timeString + ".";
if (dest.split("\\.").length == 2) {
newDest += dest.split("\\.")[1];
} else {
newDest += src.split("\\.")[1];
}
log.debug("Chemin de destination généré : {}", newDest);
return newDest;
}
public String getDestCFONBFile(String src, String temp) throws AxelorException, IOException {
String dest = this.getDestFilename(src, temp);
this.createFilePath(dest);
// copie du fichier d'import dans un repetoire temporaire
FileTool.copy(src, dest);
return dest;
}
/**
* @param src
* @param temp
* @param company
* @param operation Le type d'opération :
* <ul>
* <li>0 = Virement
* <li>1 = Prélèvement
* </ul>
*
* @return
* @throws AxelorException
* @throws IOException
*/
public List<String[]> getCFONBFile(String src, String temp, Company company, int operation)
throws AxelorException, IOException {
String dest = this.getDestCFONBFile(src, temp);
return cfonbImportService.importCFONB(dest, company, operation);
}
/**
* @param src
* @param temp
* @param company
* @param operation Le type d'opération :
* <ul>
* <li>0 = Virement
* <li>1 = Prélèvement
* </ul>
*
* @return
* @throws AxelorException
* @throws IOException
*/
public Map<List<String[]>, String> getCFONBFileByLot(
String src, String temp, Company company, int operation) throws AxelorException, IOException {
String dest = this.getDestCFONBFile(src, temp);
return cfonbImportService.importCFONBByLot(dest, company, operation);
}
/**
* Fonction permettant de récupérer le motif de rejet/retour
*
* @param reasonCode Un code motifs de rejet/retour
* @param interbankCodeOperation Le type d'opération :
* <ul>
* <li>0 = Virement
* <li>1 = Prélèvement/TIP/Télérèglement
* <li>2 = Prélèvement SEPA
* <li>3 = LCR/BOR
* <li>4 = Cheque
* </ul>
*
* @return Un motif de rejet/retour
*/
public InterbankCodeLine getInterbankCodeLine(String reasonCode, int interbankCodeOperation) {
switch (interbankCodeOperation) {
case 0:
return interbankCodeLineRepo
.all()
.filter(
"self.code = ?1 AND self.interbankCode = ?2 AND self.transferCfonbOk = 'true'",
reasonCode,
appAccountService.getAppAccount().getTransferAndDirectDebitInterbankCode())
.fetchOne();
case 1:
return interbankCodeLineRepo
.all()
.filter(
"self.code = ?1 AND self.interbankCode = ?2 AND self.directDebitAndTipCfonbOk = 'true'",
reasonCode,
appAccountService.getAppAccount().getTransferAndDirectDebitInterbankCode())
.fetchOne();
case 2:
return interbankCodeLineRepo
.all()
.filter(
"self.code = ?1 AND self.interbankCode = ?2 AND self.directDebitSepaOk = 'true'",
reasonCode,
appAccountService.getAppAccount().getTransferAndDirectDebitInterbankCode())
.fetchOne();
case 3:
return interbankCodeLineRepo
.all()
.filter(
"self.code = ?1 AND self.interbankCode = ?2 AND self.lcrBorOk = 'true'",
reasonCode,
appAccountService.getAppAccount().getTransferAndDirectDebitInterbankCode())
.fetchOne();
case 4:
return interbankCodeLineRepo
.all()
.filter(
"self.code = ?1 AND self.interbankCode = ?2 AND self.chequeOk = 'true'",
reasonCode,
appAccountService.getAppAccount().getChequeInterbankCode())
.fetchOne();
default:
return null;
}
}
/**
* Méthode permettant de construire une date de rejet depuis le texte récupéré du fichier CFONB
*
* @param dateReject
* @return
*/
public LocalDate createRejectDate(String dateReject) {
return LocalDate.of(
Integer.parseInt(dateReject.substring(4, 6)) + 2000,
Integer.parseInt(dateReject.substring(2, 4)),
Integer.parseInt(dateReject.substring(0, 2)));
}
public void createFilePath(String path) throws IOException {
File file = new File(path);
Files.createParentDirs(file);
file.createNewFile();
}
}

View File

@ -0,0 +1,87 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.SubrogationRelease;
import com.axelor.apps.base.db.Company;
import com.axelor.exception.AxelorException;
import java.io.IOException;
import java.util.List;
public interface SubrogationReleaseService {
/**
* Retrieve ventilated invoices from factorized customers.
*
* @param company
* @return
*/
List<Invoice> retrieveInvoices(Company company);
/**
* Transmit a subrogation release (generate a sequence number and change status).
*
* @param subrogationRelease
* @throws AxelorException
*/
void transmitRelease(SubrogationRelease subrogationRelease) throws AxelorException;
/**
* Generate a PDF export.
*
* @param subrogationRelease
* @param name
* @return
* @throws AxelorException
*/
String printToPDF(SubrogationRelease subrogationRelease, String name) throws AxelorException;
/**
* Generate a CSV export.
*
* @param subrogationRelease
* @return
* @throws AxelorException
* @throws IOException
*/
String exportToCSV(SubrogationRelease subrogationRelease) throws AxelorException, IOException;
/**
* Enter a subrogation release in the accounts (create moves).
*
* @param subrogationRelease
* @throws AxelorException
*/
void enterReleaseInTheAccounts(SubrogationRelease subrogationRelease) throws AxelorException;
/**
* Clear the subrogation release
*
* @param subrogationRelease
*/
void clear(SubrogationRelease subrogationRelease);
/**
* Check if the all invoice of the subrogation release are completely cleared
*
* @param subrogationRelease
* @return
*/
boolean isSubrogationReleaseCompletelyPaid(SubrogationRelease subrogationRelease);
}

View File

@ -0,0 +1,304 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.ReportFactory;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.Journal;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.SubrogationRelease;
import com.axelor.apps.account.db.repo.InvoiceRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.db.repo.SubrogationReleaseRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.report.IReport;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.account.service.invoice.InvoiceToolService;
import com.axelor.apps.account.service.move.MoveService;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Sequence;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.report.engine.ReportSettings;
import com.axelor.apps.tool.file.CsvTool;
import com.axelor.db.Query;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.axelor.meta.MetaFiles;
import com.google.common.base.Strings;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class SubrogationReleaseServiceImpl implements SubrogationReleaseService {
protected AppBaseService appBaseService;
protected InvoiceRepository invoiceRepository;
@Inject
public SubrogationReleaseServiceImpl(
AppBaseService appBaseService, InvoiceRepository invoiceRepository) {
this.appBaseService = appBaseService;
this.invoiceRepository = invoiceRepository;
}
@Override
public List<Invoice> retrieveInvoices(Company company) {
Query<Invoice> query =
invoiceRepository
.all()
.filter(
"self.company = :company AND self.partner.factorizedCustomer = TRUE "
+ "AND self.statusSelect = :invoiceStatusVentilated "
+ "AND self.id not in ("
+ " select Invoices.id "
+ " from SubrogationRelease as SR "
+ " join SR.invoiceSet as Invoices "
+ " where SR.statusSelect in (:subrogationReleaseStatusTransmitted, :subrogationReleaseStatusAccounted, :subrogationReleaseStatusCleared))"
+ "AND ((self.amountRemaining > 0 AND self.hasPendingPayments = FALSE)"
+ " OR self.originalInvoice.id in ("
+ " select Invoices.id "
+ " from SubrogationRelease as SR "
+ " join SR.invoiceSet as Invoices "
+ " where SR.statusSelect in (:subrogationReleaseStatusTransmitted, :subrogationReleaseStatusAccounted, :subrogationReleaseStatusCleared)))")
.order("invoiceDate")
.order("dueDate")
.order("invoiceId");
query.bind("company", company);
query.bind("invoiceStatusVentilated", InvoiceRepository.STATUS_VENTILATED);
query.bind(
"subrogationReleaseStatusTransmitted", SubrogationReleaseRepository.STATUS_TRANSMITTED);
query.bind("subrogationReleaseStatusAccounted", SubrogationReleaseRepository.STATUS_ACCOUNTED);
query.bind("subrogationReleaseStatusCleared", SubrogationReleaseRepository.STATUS_CLEARED);
List<Invoice> invoiceList = query.fetch();
return invoiceList;
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void transmitRelease(SubrogationRelease subrogationRelease) throws AxelorException {
SequenceService sequenceService = Beans.get(SequenceService.class);
String sequenceNumber =
sequenceService.getSequenceNumber("subrogationRelease", subrogationRelease.getCompany());
if (Strings.isNullOrEmpty(sequenceNumber)) {
throw new AxelorException(
Sequence.class,
TraceBackRepository.CATEGORY_NO_VALUE,
I18n.get(IExceptionMessage.SUBROGATION_RELEASE_MISSING_SEQUENCE),
subrogationRelease.getCompany().getName());
}
subrogationRelease.setSequenceNumber(sequenceNumber);
subrogationRelease.setStatusSelect(SubrogationReleaseRepository.STATUS_TRANSMITTED);
subrogationRelease.setTransmissionDate(appBaseService.getTodayDate());
}
@Override
public String printToPDF(SubrogationRelease subrogationRelease, String name)
throws AxelorException {
ReportSettings reportSettings = ReportFactory.createReport(IReport.SUBROGATION_RELEASE, name);
reportSettings.addParam("SubrogationReleaseId", subrogationRelease.getId());
reportSettings.addParam("Locale", ReportSettings.getPrintingLocale(null));
reportSettings.addFormat("pdf");
reportSettings.toAttach(subrogationRelease);
reportSettings.generate();
return reportSettings.getFileLink();
}
@Override
public String exportToCSV(SubrogationRelease subrogationRelease)
throws AxelorException, IOException {
List<String[]> allMoveLineData = new ArrayList<>();
Comparator<Invoice> byInvoiceDate =
(i1, i2) -> i1.getInvoiceDate().compareTo(i2.getInvoiceDate());
Comparator<Invoice> byDueDate = (i1, i2) -> i1.getDueDate().compareTo(i2.getDueDate());
Comparator<Invoice> byInvoiceId = (i1, i2) -> i1.getInvoiceId().compareTo(i2.getInvoiceId());
List<Invoice> releaseDetails =
subrogationRelease
.getInvoiceSet()
.stream()
.sorted(byInvoiceDate.thenComparing(byDueDate).thenComparing(byInvoiceId))
.collect(Collectors.toList());
for (Invoice invoice : releaseDetails) {
String[] items = new String[6];
BigDecimal inTaxTotal = invoice.getInTaxTotal().abs();
if (InvoiceToolService.isOutPayment(invoice)) {
inTaxTotal = inTaxTotal.negate();
}
items[0] = invoice.getPartner().getPartnerSeq();
items[1] = invoice.getInvoiceId();
items[2] = invoice.getInvoiceDate().toString();
items[3] = invoice.getDueDate().toString();
items[4] = inTaxTotal.toString();
items[5] = invoice.getCurrency().getCode();
allMoveLineData.add(items);
}
AccountConfigService accountConfigService = Beans.get(AccountConfigService.class);
String filePath =
accountConfigService.getAccountConfig(subrogationRelease.getCompany()).getExportPath();
if (filePath == null) {
filePath = com.google.common.io.Files.createTempDir().getAbsolutePath();
} else {
new File(filePath).mkdirs();
}
String fileName =
String.format(
"%s %s.csv", I18n.get("Subrogation release"), subrogationRelease.getSequenceNumber());
Files.createDirectories(Paths.get(filePath));
Path path = Paths.get(filePath, fileName);
CsvTool.csvWriter(filePath, fileName, ';', null, allMoveLineData);
try (InputStream is = new FileInputStream(path.toFile())) {
Beans.get(MetaFiles.class).attach(is, fileName, subrogationRelease);
}
return path.toString();
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void enterReleaseInTheAccounts(SubrogationRelease subrogationRelease)
throws AxelorException {
MoveService moveService = Beans.get(MoveService.class);
MoveRepository moveRepository = Beans.get(MoveRepository.class);
AccountConfigService accountConfigService = Beans.get(AccountConfigService.class);
AppBaseService appBaseService = Beans.get(AppBaseService.class);
Company company = subrogationRelease.getCompany();
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
Journal journal = accountConfigService.getAutoMiscOpeJournal(accountConfig);
Account factorCreditAccount = accountConfigService.getFactorCreditAccount(accountConfig);
Account factorDebitAccount = accountConfigService.getFactorDebitAccount(accountConfig);
if (subrogationRelease.getAccountingDate() == null) {
subrogationRelease.setAccountingDate(appBaseService.getTodayDate());
}
for (Invoice invoice : subrogationRelease.getInvoiceSet()) {
if (invoice.getCompanyInTaxTotalRemaining().compareTo(BigDecimal.ZERO) == 0) {
continue;
}
boolean isRefund = false;
if (invoice.getOperationTypeSelect() == InvoiceRepository.OPERATION_TYPE_CLIENT_REFUND) {
isRefund = true;
}
LocalDate date = subrogationRelease.getAccountingDate();
Move move =
moveService
.getMoveCreateService()
.createMove(
journal,
company,
company.getCurrency(),
invoice.getPartner(),
date,
null,
MoveRepository.TECHNICAL_ORIGIN_AUTOMATIC);
MoveLine creditMoveLine, debitMoveLine;
debitMoveLine =
moveService
.getMoveLineService()
.createMoveLine(
move,
invoice.getPartner(),
factorDebitAccount,
invoice.getCompanyInTaxTotalRemaining(),
!isRefund,
date,
null,
1,
subrogationRelease.getSequenceNumber(),
invoice.getInvoiceId());
creditMoveLine =
moveService
.getMoveLineService()
.createMoveLine(
move,
invoice.getPartner(),
factorCreditAccount,
invoice.getCompanyInTaxTotalRemaining(),
isRefund,
date,
null,
2,
subrogationRelease.getSequenceNumber(),
invoice.getInvoiceId());
move.addMoveLineListItem(debitMoveLine);
move.addMoveLineListItem(creditMoveLine);
move = moveRepository.save(move);
moveService.getMoveValidateService().validate(move);
invoice.setSubrogationRelease(subrogationRelease);
invoice.setSubrogationReleaseMove(move);
subrogationRelease.addMoveListItem(move);
}
subrogationRelease.setStatusSelect(SubrogationReleaseRepository.STATUS_ACCOUNTED);
}
@Override
@Transactional
public void clear(SubrogationRelease subrogationRelease) {
if (isSubrogationReleaseCompletelyPaid(subrogationRelease)) {
subrogationRelease.setStatusSelect(SubrogationReleaseRepository.STATUS_CLEARED);
}
}
@Override
public boolean isSubrogationReleaseCompletelyPaid(SubrogationRelease subrogationRelease) {
return subrogationRelease
.getInvoiceSet()
.stream()
.filter(p -> p.getAmountRemaining().compareTo(BigDecimal.ZERO) == 1)
.count()
== 0;
}
}

View File

@ -0,0 +1,58 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountManagement;
import com.axelor.apps.account.db.Tax;
import com.axelor.apps.base.db.Company;
public class TaxAccountService {
public Account getAccount(Tax tax, Company company, boolean isPurchase, boolean isFixedAssets) {
AccountManagement accountManagement = this.getTaxAccount(tax, company);
if (accountManagement != null) {
if (isPurchase) {
if (isFixedAssets) {
return accountManagement.getPurchFixedAssetsAccount();
}
return accountManagement.getPurchaseAccount();
}
return accountManagement.getSaleAccount();
}
return null;
}
protected AccountManagement getTaxAccount(Tax tax, Company company) {
if (tax != null && tax.getAccountManagementList() != null) {
for (AccountManagement accountManagement : tax.getAccountManagementList()) {
if (accountManagement.getCompany().equals(company)) {
return accountManagement;
}
}
}
return null;
}
}

View File

@ -0,0 +1,30 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.TaxPaymentMoveLine;
import com.axelor.exception.AxelorException;
public interface TaxPaymentMoveLineService {
public TaxPaymentMoveLine computeTaxAmount(TaxPaymentMoveLine taxPaymentMoveLine)
throws AxelorException;
public TaxPaymentMoveLine getReverseTaxPaymentMoveLine(TaxPaymentMoveLine taxPaymentMoveLine)
throws AxelorException;
}

View File

@ -0,0 +1,54 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.TaxPaymentMoveLine;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.exception.AxelorException;
import com.axelor.inject.Beans;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class TaxPaymentMoveLineServiceImpl implements TaxPaymentMoveLineService {
@Override
public TaxPaymentMoveLine computeTaxAmount(TaxPaymentMoveLine taxPaymentMoveLine)
throws AxelorException {
BigDecimal taxRate = taxPaymentMoveLine.getTaxRate();
BigDecimal base = taxPaymentMoveLine.getDetailPaymentAmount();
taxPaymentMoveLine.setTaxAmount(base.multiply(taxRate).setScale(2, RoundingMode.HALF_UP));
return taxPaymentMoveLine;
}
@Override
public TaxPaymentMoveLine getReverseTaxPaymentMoveLine(TaxPaymentMoveLine taxPaymentMoveLine)
throws AxelorException {
TaxPaymentMoveLine reversetaxPaymentMoveLine =
new TaxPaymentMoveLine(
taxPaymentMoveLine.getMoveLine(),
taxPaymentMoveLine.getOriginTaxLine(),
taxPaymentMoveLine.getReconcile(),
taxPaymentMoveLine.getTaxRate(),
taxPaymentMoveLine.getDetailPaymentAmount().negate(),
Beans.get(AppBaseService.class).getTodayDate());
reversetaxPaymentMoveLine = this.computeTaxAmount(reversetaxPaymentMoveLine);
reversetaxPaymentMoveLine.setIsAlreadyReverse(true);
taxPaymentMoveLine.setIsAlreadyReverse(true);
return reversetaxPaymentMoveLine;
}
}

View File

@ -0,0 +1,43 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.DebtRecoveryHistory;
import com.axelor.apps.message.db.Message;
import com.axelor.apps.message.db.Template;
import com.axelor.exception.AxelorException;
import java.io.IOException;
public interface TemplateMessageAccountService {
/**
* Generate message and set second related entity to DebtRecoveryHistory Partner and add message
* to DebtRecoveryHistory message list.
*
* @param debtRecoveryHistory
* @param template
* @return
* @throws ClassNotFoundException
* @throws IOException
* @throws InstantiationException
* @throws AxelorException
* @throws IllegalAccessException
*/
Message generateMessage(DebtRecoveryHistory debtRecoveryHistory, Template template)
throws ClassNotFoundException, IOException, InstantiationException, AxelorException,
IllegalAccessException;
}

View File

@ -0,0 +1,50 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.DebtRecoveryHistory;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.message.db.Message;
import com.axelor.apps.message.db.Template;
import com.axelor.apps.message.service.TemplateMessageService;
import com.axelor.exception.AxelorException;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.io.IOException;
public class TemplateMessageAccountServiceImpl implements TemplateMessageAccountService {
protected TemplateMessageService templateMessageService;
@Inject
public TemplateMessageAccountServiceImpl(TemplateMessageService templateMessageService) {
this.templateMessageService = templateMessageService;
}
@Override
@Transactional(rollbackOn = {Exception.class})
public Message generateMessage(DebtRecoveryHistory debtRecoveryHistory, Template template)
throws ClassNotFoundException, IOException, InstantiationException, AxelorException,
IllegalAccessException {
Message message = this.templateMessageService.generateMessage(debtRecoveryHistory, template);
message.setRelatedTo2Select(Partner.class.getCanonicalName());
message.setRelatedTo2SelectId(
debtRecoveryHistory.getDebtRecovery().getAccountingSituation().getPartner().getId());
return message;
}
}

View File

@ -0,0 +1,24 @@
package com.axelor.apps.account.service;
import java.math.BigDecimal;
public class Test {
public static void main(String[] args) {
BigDecimal debitTotalRemaining = BigDecimal.ZERO;
System.out.println(debitTotalRemaining);
setData(debitTotalRemaining);
System.out.println(debitTotalRemaining);
}
public static void setData(BigDecimal debitTotalRemaining){
debitTotalRemaining = debitTotalRemaining.add(BigDecimal.TEN);
}
}

View File

@ -0,0 +1,41 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.repo.AccountingSituationRepository;
import com.axelor.apps.base.service.user.UserServiceImpl;
import com.axelor.auth.db.User;
import com.axelor.exception.AxelorException;
import com.axelor.inject.Beans;
import com.google.inject.persist.Transactional;
public class UserServiceAccountImpl extends UserServiceImpl {
@Transactional(rollbackOn = {AxelorException.class, Exception.class})
public int changePfpValidator(User pfpValidatorUser, User newPfpValidatorUser) {
return Beans.get(AccountingSituationRepository.class)
.all()
.filter(
"self.pfpValidatorUser = ? and self.company in ? and self.company in ?",
pfpValidatorUser,
pfpValidatorUser.getCompanySet(),
newPfpValidatorUser.getCompanySet())
.update("pfpValidatorUser", newPfpValidatorUser);
}
}

View File

@ -0,0 +1,252 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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 com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountingSituation;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.ReportedBalanceLine;
import com.axelor.apps.account.db.repo.MoveLineRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.db.repo.ReportedBalanceLineRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.base.db.AdjustHistory;
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.AdjustHistoryService;
import com.axelor.apps.base.service.YearServiceImpl;
import com.axelor.db.JPA;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import javax.persistence.Query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class YearServiceAccountImpl extends YearServiceImpl {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected ReportedBalanceLineRepository reportedBalanceLineRepo;
protected AdjustHistoryService adjustHistoryService;
protected PartnerRepository partnerRepository;
protected PeriodServiceAccountImpl periodServiceAccountImpl;
@Inject
public YearServiceAccountImpl(
PartnerRepository partnerRepository,
ReportedBalanceLineRepository reportedBalanceLineRepo,
YearRepository yearRepository,
AdjustHistoryService adjustHistoryService,
PeriodServiceAccountImpl periodServiceAccountImpl) {
super(yearRepository);
this.partnerRepository = partnerRepository;
this.reportedBalanceLineRepo = reportedBalanceLineRepo;
this.adjustHistoryService = adjustHistoryService;
this.periodServiceAccountImpl = periodServiceAccountImpl;
}
/**
* Procédure permettant de cloturer un exercice comptable
*
* @param year Un exercice comptable
* @throws AxelorException
*/
public void closeYearProcess(Year year) throws AxelorException {
year = yearRepository.find(year.getId());
for (Period period : year.getPeriodList()) {
if (period.getStatusSelect() == PeriodRepository.STATUS_ADJUSTING) {
adjustHistoryService.setEndDate(period);
}
period.setStatusSelect(PeriodRepository.STATUS_CLOSED);
period.setClosureDateTime(LocalDateTime.now());
}
Company company = year.getCompany();
if (company == null) {
throw new AxelorException(
year,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.YEAR_1),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
year.getName());
}
Query q;
if (year.getStatusSelect() == YearRepository.STATUS_ADJUSTING) {
AdjustHistory adjustHistory = adjustHistoryService.setEndDate(year);
q =
JPA.em()
.createQuery(
"select DISTINCT(ml.partner) FROM MoveLine as self WHERE self.move.ignoreInAccountingOk = false AND self.move.year = ?1 "
+ "AND self.move.statusSelect = ?2 AND self.move.adjustingMove = true AND self.date >= ?3 AND self.date <= ?4");
q.setParameter(1, year);
q.setParameter(2, MoveRepository.STATUS_VALIDATED);
q.setParameter(3, adjustHistory.getStartDate().toLocalDate());
q.setParameter(4, adjustHistory.getEndDate().toLocalDate());
} else {
q =
JPA.em()
.createQuery(
"select DISTINCT(ml.partner) FROM MoveLine as self WHERE self.move.ignoreInAccountingOk = false AND self.move.year = ?1 "
+ "AND self.move.statusSelect = ?2 AND self.date >= ?3 AND self.date <= ?4");
q.setParameter(1, year);
q.setParameter(2, MoveRepository.STATUS_VALIDATED);
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());
for (Partner partner : partnerList) {
partner = partnerRepository.find(partner.getId());
year = yearRepository.find(year.getId());
log.debug("Tiers en cours de traitement : {}", partner.getName());
for (AccountingSituation accountingSituation : partner.getAccountingSituationList()) {
if (accountingSituation.getCompany().equals(year.getCompany())) {
log.debug("On ajoute une ligne à la Situation comptable trouvée");
BigDecimal reportedBalanceAmount =
this.computeReportedBalance(year.getFromDate(), year.getToDate(), partner, year);
this.createReportedBalanceLine(accountingSituation, reportedBalanceAmount, year);
break;
}
}
JPA.clear();
}
closeYear(year);
}
@Transactional
public void closeYear(Year year) {
year.setStatusSelect(YearRepository.STATUS_CLOSED);
year.setClosureDateTime(LocalDateTime.now());
yearRepository.save(year);
}
/**
* Procédure permettant de rectifier un exercice comptable
*
* @param year Un exercice comptable
* @throws AxelorException
*/
@Transactional
public void adjust(Year year) {
year = yearRepository.find(year.getId());
adjustHistoryService.setStartDate(year);
year.setStatusSelect(YearRepository.STATUS_ADJUSTING);
yearRepository.save(year);
}
@Transactional
public ReportedBalanceLine createReportedBalanceLine(
AccountingSituation accountingSituation, BigDecimal amount, Year year) {
ReportedBalanceLine reportedBalanceLine = new ReportedBalanceLine();
accountingSituation.addReportedBalanceLineListItem(reportedBalanceLine);
reportedBalanceLine.setAmount(amount);
reportedBalanceLine.setYear(year);
reportedBalanceLineRepo.save(reportedBalanceLine);
return reportedBalanceLine;
}
public BigDecimal computeReportedBalance(
LocalDate fromDate, LocalDate toDate, Partner partner, Year year) {
Query q =
JPA.em()
.createQuery(
"select SUM(self.debit - self.credit) FROM MoveLine as self "
+ "WHERE self.partner = ?1 AND self.move.ignoreInAccountingOk = false AND self.date >= ?2 AND self.date <= ?3 "
+ "AND self.move.year = ?4 AND self.move.statusSelect = ?5 AND self.account.useForPartnerBalance is true",
BigDecimal.class);
q.setParameter(1, partner);
q.setParameter(2, fromDate);
q.setParameter(3, toDate);
q.setParameter(4, year);
q.setParameter(5, MoveRepository.STATUS_VALIDATED);
BigDecimal result = (BigDecimal) q.getSingleResult();
log.debug("Annual balance : {} for partner : {}", result, partner.getPartnerSeq());
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;
}
}

View File

@ -0,0 +1,34 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.app;
import com.axelor.apps.base.db.AppAccount;
import com.axelor.apps.base.db.AppBudget;
import com.axelor.apps.base.db.AppInvoice;
import com.axelor.apps.base.service.app.AppBaseService;
public interface AppAccountService extends AppBaseService {
public AppAccount getAppAccount();
public AppBudget getAppBudget();
public AppInvoice getAppInvoice();
public void generateAccountConfigurations();
}

View File

@ -0,0 +1,76 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.app;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.repo.AccountConfigRepository;
import com.axelor.apps.base.db.AppAccount;
import com.axelor.apps.base.db.AppBudget;
import com.axelor.apps.base.db.AppInvoice;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.repo.AppAccountRepository;
import com.axelor.apps.base.db.repo.AppBudgetRepository;
import com.axelor.apps.base.db.repo.AppInvoiceRepository;
import com.axelor.apps.base.db.repo.CompanyRepository;
import com.axelor.apps.base.service.app.AppBaseServiceImpl;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.persist.Transactional;
import java.util.List;
@Singleton
public class AppAccountServiceImpl extends AppBaseServiceImpl implements AppAccountService {
@Inject private AppAccountRepository appAccountRepo;
@Inject private AppBudgetRepository appBudgetRepo;
@Inject private AppInvoiceRepository appInvoiceRepo;
@Inject private AccountConfigRepository accountConfigRepo;
@Inject private CompanyRepository companyRepo;
@Override
public AppAccount getAppAccount() {
return appAccountRepo.all().fetchOne();
}
@Override
public AppBudget getAppBudget() {
return appBudgetRepo.all().fetchOne();
}
@Override
public AppInvoice getAppInvoice() {
return appInvoiceRepo.all().fetchOne();
}
@Transactional
@Override
public void generateAccountConfigurations() {
List<Company> companies = companyRepo.all().filter("self.accountConfig is null").fetch();
for (Company company : companies) {
AccountConfig config = new AccountConfig();
config.setCompany(company);
accountConfigRepo.save(config);
}
}
}

View File

@ -0,0 +1,933 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.bankorder.file.cfonb;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.CfonbConfig;
import com.axelor.apps.account.db.DirectDebitManagement;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.PaymentSchedule;
import com.axelor.apps.account.db.PaymentScheduleLine;
import com.axelor.apps.account.db.Reimbursement;
import com.axelor.apps.account.db.repo.InvoiceRepository;
import com.axelor.apps.account.db.repo.PaymentScheduleLineRepository;
import com.axelor.apps.account.db.repo.ReimbursementRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.PaymentScheduleService;
import com.axelor.apps.account.service.config.CfonbConfigService;
import com.axelor.apps.base.db.BankDetails;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.service.PartnerService;
import com.axelor.apps.tool.StringTool;
import com.axelor.apps.tool.file.FileTool;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
public class CfonbExportService {
protected CfonbConfig cfonbConfig;
protected CfonbConfigService cfonbConfigService;
protected ReimbursementRepository reimbursementRepo;
protected PaymentScheduleLineRepository paymentScheduleLineRepo;
protected InvoiceRepository invoiceRepo;
protected PartnerService partnerService;
private boolean sepa;
@Inject
public CfonbExportService(
CfonbConfigService cfonbConfigService,
ReimbursementRepository reimbursementRepo,
PaymentScheduleLineRepository paymentScheduleLineRepo,
InvoiceRepository invoiceRepo,
PartnerService partnerService) {
this.cfonbConfigService = cfonbConfigService;
this.reimbursementRepo = reimbursementRepo;
this.paymentScheduleLineRepo = paymentScheduleLineRepo;
this.invoiceRepo = invoiceRepo;
this.partnerService = partnerService;
}
private void init(CfonbConfig cfonbConfig) {
this.cfonbConfig = cfonbConfig;
}
public void setSepa(boolean sepa) {
this.sepa = sepa;
}
/**
* ************************************** Export CFONB
* ****************************************************
*/
/**
* Méthode permettant d'exporter les remboursements au format CFONB
*
* @param reimbursementExport
* @param ZonedDateTime
* @param reimbursementList
* @throws AxelorException
*/
public void exportCFONB(
Company company,
ZonedDateTime datetime,
List<Reimbursement> reimbursementList,
BankDetails bankDetails)
throws AxelorException {
this.testCompanyExportCFONBField(company);
// paramètre obligatoire : au minimum
// un enregistrement emetteur par date de règlement (code 03)
// un enregistrement destinataire (code 06)
// un enregistrement total (code 08)
String senderCFONB = this.createSenderReimbursementCFONB(datetime, bankDetails);
List<String> multiRecipientCFONB = new ArrayList<String>();
for (Reimbursement reimbursement : reimbursementList) {
reimbursement = reimbursementRepo.find(reimbursement.getId());
multiRecipientCFONB.add(this.createRecipientCFONB(reimbursement));
}
String totalCFONB =
this.createReimbursementTotalCFONB(
this.getTotalAmountReimbursementExport(reimbursementList));
// cfonbToolService.testLength(senderCFONB, totalCFONB, multiRecipientCFONB, company);
// List<String> cFONB = this.createCFONBExport(senderCFONB, multiRecipientCFONB, totalCFONB);
// Mise en majuscule des enregistrement
// cFONB = this.toUpperCase(cFONB);
// this.createCFONBFile(cFONB, datetime,
// company.getAccountConfig().getReimbursementExportFolderPathCFONB(), "virement");
}
/**
* Méthode permettant d'exporter les prélèvements d'échéance de mensu au format CFONB
*
* @param paymentScheduleExport
* @param paymentScheduleLineList
* @param company
* @throws AxelorException
*/
public void exportPaymentScheduleCFONB(
ZonedDateTime processingDateTime,
LocalDate scheduleDate,
List<PaymentScheduleLine> paymentScheduleLineList,
Company company,
BankDetails bankDetails)
throws AxelorException {
if (paymentScheduleLineList == null || paymentScheduleLineList.isEmpty()) {
return;
}
this.testCompanyExportCFONBField(company);
// paramètre obligatoire : au minimum
// un enregistrement emetteur par date de règlement (code 03)
// un enregistrement destinataire (code 06)
// un enregistrement total (code 08)
String senderCFONB = this.createSenderMonthlyExportCFONB(scheduleDate, bankDetails);
List<String> multiRecipientCFONB = new ArrayList<String>();
List<DirectDebitManagement> directDebitManagementList = new ArrayList<DirectDebitManagement>();
for (PaymentScheduleLine paymentScheduleLine : paymentScheduleLineList) {
paymentScheduleLine = paymentScheduleLineRepo.find(paymentScheduleLine.getId());
if (paymentScheduleLine.getDirectDebitManagement() == null) {
multiRecipientCFONB.add(this.createRecipientCFONB(paymentScheduleLine, true));
} else {
if (!directDebitManagementList.contains(paymentScheduleLine.getDirectDebitManagement())) {
directDebitManagementList.add(paymentScheduleLine.getDirectDebitManagement());
}
}
}
for (DirectDebitManagement directDebitManagement : directDebitManagementList) {
multiRecipientCFONB.add(this.createRecipientCFONB(directDebitManagement, false));
}
String totalCFONB =
this.createPaymentScheduleTotalCFONB(
company, this.getTotalAmountPaymentSchedule(paymentScheduleLineList));
// cfonbToolService.testLength(senderCFONB, totalCFONB, multiRecipientCFONB, company);
// List<String> cFONB = this.createCFONBExport(senderCFONB, multiRecipientCFONB, totalCFONB);
// Mise en majuscule des enregistrement
// cFONB = this.toUpperCase(cFONB);
// this.createCFONBFile(cFONB, processingDateTime,
// company.getAccountConfig().getPaymentScheduleExportFolderPathCFONB(), "prelevement");
}
/**
* Méthode permettant d'exporter les prélèvements de facture au format CFONB
*
* @param paymentScheduleExport
* @param paymentScheduleLineList
* @param invoiceList
* @param company
* @throws AxelorException
*/
public void exportInvoiceCFONB(
ZonedDateTime processingDateTime,
LocalDate scheduleDate,
List<Invoice> invoiceList,
Company company,
BankDetails bankDetails)
throws AxelorException {
if ((invoiceList == null || invoiceList.isEmpty())) {
return;
}
this.testCompanyExportCFONBField(company);
// paramètre obligatoire : au minimum
// un enregistrement emetteur par date de règlement (code 03)
// un enregistrement destinataire (code 06)
// un enregistrement total (code 08)
String senderCFONB = this.createSenderMonthlyExportCFONB(scheduleDate, bankDetails);
List<String> multiRecipientCFONB = new ArrayList<String>();
List<DirectDebitManagement> directDebitManagementList = new ArrayList<DirectDebitManagement>();
for (Invoice invoice : invoiceList) {
invoice = invoiceRepo.find(invoice.getId());
if (invoice.getDirectDebitManagement() == null) {
multiRecipientCFONB.add(this.createRecipientCFONB(company, invoice));
} else {
if (!directDebitManagementList.contains(invoice.getDirectDebitManagement())) {
directDebitManagementList.add(invoice.getDirectDebitManagement());
}
}
}
for (DirectDebitManagement directDebitManagement : directDebitManagementList) {
multiRecipientCFONB.add(this.createRecipientCFONB(directDebitManagement, true));
}
BigDecimal amount = this.getTotalAmountInvoice(invoiceList);
String totalCFONB = this.createPaymentScheduleTotalCFONB(company, amount);
// cfonbToolService.testLength(senderCFONB, totalCFONB, multiRecipientCFONB, company);
// List<String> cFONB = this.createCFONBExport(senderCFONB, multiRecipientCFONB, totalCFONB);
// Mise en majuscule des enregistrement
// cFONB = this.toUpperCase(cFONB);
// this.createCFONBFile(cFONB, processingDateTime,
// company.getAccountConfig().getPaymentScheduleExportFolderPathCFONB(), "prelevement");
}
/**
* Méthode permettant d'exporter les prélèvements de facture et d'échéance de paiement au format
* CFONB
*
* @param paymentScheduleExport
* @param paymentScheduleLineList
* @param invoiceList
* @param company
* @throws AxelorException
*/
public void exportCFONB(
ZonedDateTime processingDateTime,
LocalDate scheduleDate,
List<PaymentScheduleLine> paymentScheduleLineList,
List<Invoice> invoiceList,
Company company,
BankDetails bankDetails)
throws AxelorException {
if ((paymentScheduleLineList == null || paymentScheduleLineList.isEmpty())
&& (invoiceList == null || invoiceList.isEmpty())) {
return;
}
this.testCompanyExportCFONBField(company);
// paramètre obligatoire : au minimum
// un enregistrement emetteur par date de règlement (code 03)
// un enregistrement destinataire (code 06)
// un enregistrement total (code 08)
String senderCFONB = this.createSenderMonthlyExportCFONB(scheduleDate, bankDetails);
List<String> multiRecipientCFONB = new ArrayList<String>();
// Echéanciers
List<DirectDebitManagement> directDebitManagementList = new ArrayList<DirectDebitManagement>();
for (PaymentScheduleLine paymentScheduleLine : paymentScheduleLineList) {
paymentScheduleLine = paymentScheduleLineRepo.find(paymentScheduleLine.getId());
if (paymentScheduleLine.getDirectDebitManagement() == null) {
multiRecipientCFONB.add(this.createRecipientCFONB(paymentScheduleLine, false));
} else {
if (!directDebitManagementList.contains(paymentScheduleLine.getDirectDebitManagement())) {
directDebitManagementList.add(paymentScheduleLine.getDirectDebitManagement());
}
}
}
for (DirectDebitManagement directDebitManagement : directDebitManagementList) {
multiRecipientCFONB.add(this.createRecipientCFONB(directDebitManagement, false));
}
// Factures
directDebitManagementList = new ArrayList<DirectDebitManagement>();
for (Invoice invoice : invoiceList) {
invoice = invoiceRepo.find(invoice.getId());
if (invoice.getDirectDebitManagement() == null) {
multiRecipientCFONB.add(this.createRecipientCFONB(company, invoice));
} else {
if (!directDebitManagementList.contains(invoice.getDirectDebitManagement())) {
directDebitManagementList.add(invoice.getDirectDebitManagement());
}
}
}
for (DirectDebitManagement directDebitManagement : directDebitManagementList) {
multiRecipientCFONB.add(this.createRecipientCFONB(directDebitManagement, true));
}
BigDecimal amount =
this.getTotalAmountPaymentSchedule(paymentScheduleLineList)
.add(this.getTotalAmountInvoice(invoiceList));
String totalCFONB = this.createPaymentScheduleTotalCFONB(company, amount);
// cfonbToolService.testLength(senderCFONB, totalCFONB, multiRecipientCFONB, company);
// List<String> cFONB = this.createCFONBExport(senderCFONB, multiRecipientCFONB, totalCFONB);
// Mise en majuscule des enregistrement
// cFONB = this.toUpperCase(cFONB);
// this.createCFONBFile(cFONB, processingDateTime,
// company.getAccountConfig().getPaymentScheduleExportFolderPathCFONB(), "prelevement");
}
/**
* Fonction permettant de créer un enregistrement 'émetteur' pour un virement des remboursements
*
* @param company Une société
* @param ZonedDateTime Une heure
* @return Un enregistrement 'emetteur'
* @throws AxelorException
*/
private String createSenderReimbursementCFONB(
ZonedDateTime zonedDateTime, BankDetails bankDetails) throws AxelorException {
DateFormat ddmmFormat = new SimpleDateFormat("ddMM");
String date = ddmmFormat.format(zonedDateTime.toLocalDate());
date +=
String.format("%s", StringTool.truncLeft(String.format("%s", zonedDateTime.getYear()), 1));
// Récupération des valeurs
String a = this.cfonbConfig.getSenderRecordCodeExportCFONB(); // Code enregistrement
String b1 = this.cfonbConfig.getTransferOperationCodeExportCFONB(); // Code opération
String b2 = ""; // Zone réservée
String b3 = this.cfonbConfig.getSenderNumExportCFONB(); // Numéro d'émetteur
String c1One = ""; // Code CCD
String c1Two = ""; // Zone réservée
String c1Three = date; // Date d'échéance
String c2 =
this.cfonbConfig.getSenderNameCodeExportCFONB(); // Nom/Raison sociale du donneur d'ordre
String d1One = ""; // Référence de la remise
String d1Two = ""; // Zone réservée
String d2One = ""; // Zone réservée
String d2Two = "E"; // Code monnaie
String d2Three = ""; // Zone réservée
String d3 = bankDetails.getSortCode(); // Code guichet de la banque du donneur d'ordre
String d4 = bankDetails.getAccountNbr(); // Numéro de compte du donneur dordre
String e = ""; // Identifiant du donneur d'ordre
String f = ""; // Zone réservée
String g1 = bankDetails.getBankCode(); // Code établissement de la banque du donneur d'ordre
String g2 = ""; // Zone réservée
// Tronquage / remplissage à droite (chaine de caractère)
b2 = StringTool.fillStringRight(b2, ' ', 8);
b3 = StringTool.fillStringRight(b3, ' ', 6);
c1One = StringTool.fillStringRight(c1One, ' ', 1);
c1Two = StringTool.fillStringRight(c1Two, ' ', 6);
c2 = StringTool.fillStringRight(c2, ' ', 24);
d1One = StringTool.fillStringRight(d1One, ' ', 7);
d1Two = StringTool.fillStringRight(d1Two, ' ', 17);
d2One = StringTool.fillStringRight(d2One, ' ', 2);
d2Three = StringTool.fillStringRight(d2Three, ' ', 5);
d4 = StringTool.fillStringRight(d4, ' ', 11);
e = StringTool.fillStringRight(e, ' ', 16);
f = StringTool.fillStringRight(f, ' ', 31);
g2 = StringTool.fillStringRight(g2, ' ', 6);
// Tronquage / remplissage à gauche (nombre)
a = StringTool.fillStringLeft(a, '0', 2);
b1 = StringTool.fillStringLeft(b1, '0', 2);
c1Three = StringTool.fillStringLeft(c1Three, '0', 5);
d3 = StringTool.fillStringLeft(d3, '0', 5);
g1 = StringTool.fillStringLeft(g1, '0', 5);
// Vérification AN / N / A
// cfonbToolService.testDigital(a, "");
// cfonbToolService.testDigital(b1, "");
// cfonbToolService.testDigital(d3, "");
// cfonbToolService.testDigital(g1, "");
// création de l'enregistrement
return a + b1 + b2 + b3 + c1One + c1Two + c1Three + c2 + d1One + d1Two + d2One + d2Two + d2Three
+ d3 + d4 + e + f + g1 + g2;
}
/**
* Fonction permettant de créer un enregistrement 'émetteur' pour un export de prélèvement de
* mensu
*
* @param company Une société
* @param localDate Une date
* @return Un enregistrement 'emetteur'
* @throws AxelorException
*/
private String createSenderMonthlyExportCFONB(LocalDate localDate, BankDetails bankDetails)
throws AxelorException {
DateFormat ddmmFormat = new SimpleDateFormat("ddMM");
String date = ddmmFormat.format(localDate.atTime(LocalTime.now()).toLocalDate());
date += String.format("%s", StringTool.truncLeft(String.format("%s", localDate.getYear()), 1));
// Récupération des valeurs
String a = this.cfonbConfig.getSenderRecordCodeExportCFONB(); // Code enregistrement
String b1 = this.cfonbConfig.getDirectDebitOperationCodeExportCFONB(); // Code opération
String b2 = ""; // Zone réservée
String b3 = this.cfonbConfig.getSenderNumExportCFONB(); // Numéro d'émetteur
String c1One = ""; // Zone réservée
String c1Two = date; // Date d'échéance
String c2 =
this.cfonbConfig.getSenderNameCodeExportCFONB(); // Nom/Raison sociale du donneur d'ordre
String d1One = ""; // Référence de la remise
String d1Two = ""; // Zone réservée
String d2 = ""; // Zone réservée
String d3 = bankDetails.getSortCode(); // Code guichet de la banque du donneur d'ordre
String d4 = bankDetails.getAccountNbr(); // Numéro de compte du donneur dordre
String e = ""; // Zone réservée
String f = ""; // Zone réservée
String g1 = bankDetails.getBankCode(); // Code établissement de la banque du donneur d'ordre
String g2 = ""; // Zone réservée
// Tronquage / remplissage à droite (chaine de caractère)
b2 = StringTool.fillStringRight(b2, ' ', 8);
b3 = StringTool.fillStringRight(b3, ' ', 6);
c1One = StringTool.fillStringRight(c1One, ' ', 7);
c2 = StringTool.fillStringRight(c2, ' ', 24);
d1One = StringTool.fillStringRight(d1One, ' ', 7);
d1Two = StringTool.fillStringRight(d1Two, ' ', 17);
d2 = StringTool.fillStringRight(d2, ' ', 8);
d4 = StringTool.fillStringRight(d4, ' ', 11);
e = StringTool.fillStringRight(e, ' ', 16);
f = StringTool.fillStringRight(f, ' ', 31);
g2 = StringTool.fillStringRight(g2, ' ', 6);
// Tronquage / remplissage à gauche (nombre)
a = StringTool.fillStringLeft(a, '0', 2);
b1 = StringTool.fillStringLeft(b1, '0', 2);
c1Two = StringTool.fillStringLeft(c1Two, '0', 5);
d3 = StringTool.fillStringLeft(d3, '0', 5);
g1 = StringTool.fillStringLeft(g1, '0', 5);
// Vérification AN / N / A
// cfonbToolService.testDigital(a, "");
// cfonbToolService.testDigital(b1, "");
// cfonbToolService.testDigital(d3, "");
// cfonbToolService.testDigital(g1, "");
// création de l'enregistrement
return a + b1 + b2 + b3 + c1One + c1Two + c2 + d1One + d1Two + d2 + d3 + d4 + e + f + g1 + g2;
}
/**
* Fonction permettant de créer un enregistrement 'destinataire' pour un virement de remboursement
*
* @param company Une société
* @param reimbursement Un remboursement
* @return Un enregistrement 'destinataire'
* @throws AxelorException
*/
private String createRecipientCFONB(Reimbursement reimbursement) throws AxelorException {
BankDetails bankDetails = reimbursement.getBankDetails();
if (bankDetails == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
"%s :\n " + I18n.get(IExceptionMessage.CFONB_EXPORT_1) + " %s",
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
reimbursement.getRef());
}
BigDecimal amount = reimbursement.getAmountReimbursed();
String ref = reimbursement.getRef(); // Référence
String partner =
this.getPayeurPartnerName(reimbursement.getPartner()); // Nom/Raison sociale du bénéficiaire
String operationCode = this.cfonbConfig.getTransferOperationCodeExportCFONB(); // Code opération
return this.createRecipientCFONB(amount, ref, partner, bankDetails, operationCode);
}
/**
* Fonction permettant de créer un enregistrement 'destinataire' pour un export de prélèvement
* d'une échéance
*
* @param company Une société
* @param paymentScheduleLine Une échéance
* @return Un enregistrement 'destinataire'
* @throws AxelorException
*/
private String createRecipientCFONB(PaymentScheduleLine paymentScheduleLine, boolean mensu)
throws AxelorException {
PaymentSchedule paymentSchedule = paymentScheduleLine.getPaymentSchedule();
Partner partner = paymentSchedule.getPartner();
BankDetails bankDetails =
Beans.get(PaymentScheduleService.class).getBankDetails(paymentSchedule);
BigDecimal amount = paymentScheduleLine.getDirectDebitAmount();
String ref = paymentScheduleLine.getDebitNumber(); // Référence
String partnerName = this.getPayeurPartnerName(partner); // Nom/Raison sociale du débiteur
String operationCode =
this.cfonbConfig.getDirectDebitOperationCodeExportCFONB(); // Code opération
return this.createRecipientCFONB(amount, ref, partnerName, bankDetails, operationCode);
}
/**
* Fonction permettant de créer un enregistrement 'destinataire' pour un export de prélèvement de
* plusieurs échéances par le biais d'un objet de gestion de prélèvement
*
* @param company Une société
* @param paymentScheduleLine Une échéance
* @return Un enregistrement 'destinataire'
* @throws AxelorException
*/
private String createRecipientCFONB(
DirectDebitManagement directDebitManagement, boolean isForInvoice) throws AxelorException {
BankDetails bankDetails = null;
String partnerName = "";
if (isForInvoice) {
Invoice invoice = (Invoice) directDebitManagement.getInvoiceSet().toArray()[0];
Partner partner = invoice.getPartner();
bankDetails = partnerService.getDefaultBankDetails(partner);
partnerName =
this.getPayeurPartnerName(invoice.getPartner()); // Nom/Raison sociale du débiteur
if (bankDetails == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.PAYMENT_SCHEDULE_2),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
partner.getName());
}
} else {
PaymentSchedule paymentSchedule =
directDebitManagement.getPaymentScheduleLineList().get(0).getPaymentSchedule();
Partner partner = paymentSchedule.getPartner();
partnerName = this.getPayeurPartnerName(partner); // Nom/Raison sociale du débiteur
bankDetails = Beans.get(PaymentScheduleService.class).getBankDetails(paymentSchedule);
}
BigDecimal amount = this.getAmount(directDebitManagement, isForInvoice);
String ref = directDebitManagement.getDebitNumber(); // Référence
String operationCode =
this.cfonbConfig.getDirectDebitOperationCodeExportCFONB(); // Code opération
return this.createRecipientCFONB(amount, ref, partnerName, bankDetails, operationCode);
}
private BigDecimal getAmount(DirectDebitManagement directDebitManagement, boolean isForInvoice) {
BigDecimal amount = BigDecimal.ZERO;
if (isForInvoice) {
for (Invoice invoice : directDebitManagement.getInvoiceSet()) {
amount = amount.add(invoice.getDirectDebitAmount());
}
} else {
for (PaymentScheduleLine paymentScheduleLine :
directDebitManagement.getPaymentScheduleLineList()) {
amount = amount.add(paymentScheduleLine.getDirectDebitAmount());
}
}
return amount;
}
/**
* Fonction permettant de créer un enregistrement 'destinataire' pour un export de prélèvement
* d'une facture
*
* @param company Une société
* @param moveLine L' écriture d'export des prélèvement d'une facture
* @return Un enregistrement 'destinataire'
* @throws AxelorException
*/
private String createRecipientCFONB(Company company, Invoice invoice) throws AxelorException {
Partner partner = invoice.getPartner();
BankDetails bankDetails = partnerService.getDefaultBankDetails(partner);
if (bankDetails == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.PAYMENT_SCHEDULE_2),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
partner.getName());
}
BigDecimal amount = invoice.getDirectDebitAmount();
String ref = invoice.getDebitNumber(); // Référence
String partnerName = this.getPayeurPartnerName(partner); // Nom/Raison sociale du débiteur
String operationCode =
this.cfonbConfig.getDirectDebitOperationCodeExportCFONB(); // Code opération
return this.createRecipientCFONB(amount, ref, partnerName, bankDetails, operationCode);
}
/**
* Fonction permettant de créer un enregistrement 'destinataire'
*
* @param company Une société
* @param amount Le montant de l'enregistrement
* @param ref Une référence de prélèvement
* @param label Un libellé
* @param partner Un tiers payeur
* @param bankDetails Un RIB
* @param operationCode Le code d'opération défini par société
* @return L'enregistrement 'destinataire'
* @throws AxelorException
*/
private String createRecipientCFONB(
BigDecimal amount, String ref, String partner, BankDetails bankDetails, String operationCode)
throws AxelorException {
this.testBankDetailsField(bankDetails);
String amountFixed = amount.setScale(2).toString().replace(".", "");
// Récupération des valeurs
String a = this.cfonbConfig.getRecipientRecordCodeExportCFONB(); // Code enregistrement
String b1 = operationCode; // Code opération
String b2 = ""; // Zone réservée
String b3 = this.cfonbConfig.getSenderNumExportCFONB(); // Numéro d'émetteur
String c1 = ref; // Référence
String c2 = partner; // Nom/Raison sociale du bénéficiaire
String d1 = bankDetails.getBankAddress().getAddress(); // Domiciliation
String d2 = ""; // Déclaration de la balance des paiement
String d3 =
bankDetails.getSortCode(); // Code guichet de la banque du donneur d'ordre / du débiteur
String d4 = bankDetails.getAccountNbr(); // Numéro de compte du bénéficiaire / du débiteur
String e = amountFixed; // Montant du virement
String f = ref; // Libellé
String g1 =
bankDetails
.getBankCode(); // Code établissement de la banque du donneur d'ordre / du débiteur
String g2 = ""; // Zone réservée
// Tronquage / remplissage à droite (chaine de caractère)
b2 = StringTool.fillStringRight(b2, ' ', 8);
b3 = StringTool.fillStringRight(b3, ' ', 6);
c1 = StringTool.fillStringRight(c1, ' ', 12);
c2 = StringTool.fillStringRight(c2, ' ', 24);
d1 = StringTool.fillStringRight(d1, ' ', 24);
d2 = StringTool.fillStringRight(d2, ' ', 8);
d4 = StringTool.fillStringRight(d4, ' ', 11);
f = StringTool.fillStringRight(f, ' ', 31);
g2 = StringTool.fillStringRight(g2, ' ', 6);
// Tronquage / remplissage à gauche (nombre)
a = StringTool.fillStringLeft(a, '0', 2);
b1 = StringTool.fillStringLeft(b1, '0', 2);
d3 = StringTool.fillStringLeft(d3, '0', 5);
e = StringTool.fillStringLeft(e, '0', 16);
g1 = StringTool.fillStringLeft(g1, '0', 5);
return a + b1 + b2 + b3 + c1 + c2 + d1 + d2 + d3 + d4 + e + f + g1 + g2;
}
/**
* Fonction permettant de créer un enregistrement 'total' au format CFONB pour un remboursement
*
* @param company Une société
* @param amount Le montant total des enregistrements 'destinataire'
* @return
*/
private String createReimbursementTotalCFONB(BigDecimal amount) {
// Code opération
String operationCode = this.cfonbConfig.getTransferOperationCodeExportCFONB();
return this.createTotalCFONB(amount, operationCode);
}
/**
* Fonction permettant de créer un enregistrement 'total' au format CFONB pour un échéancier
*
* @param company Une société
* @param amount Le montant total des enregistrements 'destinataire'
* @return L'enregistrement 'total'
*/
private String createPaymentScheduleTotalCFONB(Company company, BigDecimal amount) {
// Code opération
String operationCode = this.cfonbConfig.getDirectDebitOperationCodeExportCFONB();
return this.createTotalCFONB(amount, operationCode);
}
/**
* Fonction permettant de créer un enregistrement 'total' au format CFONB
*
* @param company Une société
* @param amount Le montant total des enregistrements 'destinataire'
* @param operationCode Le type d'opération :
* <ul>
* <li>0 = Virement
* <li>1 = Prélèvement
* </ul>
*
* @return L'enregistrement 'total'
*/
private String createTotalCFONB(BigDecimal amount, String operationCode) {
String totalAmount = amount.setScale(2).toString().replace(".", "");
// Récupération des valeurs
String a = this.cfonbConfig.getTotalRecordCodeExportCFONB(); // Code enregistrement
String b1 = operationCode; // Code opération
String b2 = ""; // Zone réservée
String b3 = this.cfonbConfig.getSenderNumExportCFONB(); // Numéro d'émetteur
String c1 = ""; // Zone réservée
String c2 = ""; // Zone réservée
String d1 = ""; // Zone réservée
String d2 = ""; // Zone réservée
String d3 = ""; // Zone réservée
String d4 = ""; // Zone réservée
String e = totalAmount; // Montant de la remise
String f = ""; // Zone réservée
String g1 = ""; // Zone réservée
String g2 = ""; // Zone réservée
// Tronquage / remplissage à droite (chaine de caractère)
b2 = StringTool.fillStringRight(b2, ' ', 8);
b3 = StringTool.fillStringRight(b3, ' ', 6);
c1 = StringTool.fillStringRight(c1, ' ', 12);
c2 = StringTool.fillStringRight(c2, ' ', 24);
d1 = StringTool.fillStringRight(d1, ' ', 24);
d2 = StringTool.fillStringRight(d2, ' ', 8);
d3 = StringTool.fillStringRight(d3, ' ', 5);
d4 = StringTool.fillStringRight(d4, ' ', 11);
f = StringTool.fillStringRight(f, ' ', 31);
g1 = StringTool.fillStringRight(g1, ' ', 5);
g2 = StringTool.fillStringRight(g2, ' ', 6);
// Tronquage / remplissage à gauche (nombre)
a = StringTool.fillStringLeft(a, '0', 2);
b1 = StringTool.fillStringLeft(b1, '0', 2);
e = StringTool.fillStringLeft(e, '0', 16);
return a + b1 + b2 + b3 + c1 + c2 + d1 + d2 + d3 + d4 + e + f + g1 + g2;
}
/**
* Procédure permettant de créer un fichier CFONB au format .dat
*
* @param cFONB Le contenu du fichier, des enregistrements CFONB
* @param ZonedDateTime La date permettant de déterminer le nom du fichier créé
* @param destinationFolder Le répertoire de destination
* @param prefix Le préfix utilisé
* @throws AxelorException
*/
private void createCFONBFile(
List<String> cFONB, ZonedDateTime zonedDateTime, String destinationFolder, String prefix)
throws AxelorException {
DateFormat yyyyMMddHHmmssFormat = new SimpleDateFormat("yyyyMMddHHmmss");
String dateFileName = yyyyMMddHHmmssFormat.format(zonedDateTime);
String fileName = String.format("%s%s.dat", prefix, dateFileName);
try {
FileTool.writer(destinationFolder, fileName, cFONB);
} catch (IOException e) {
throw new AxelorException(
e.getCause(),
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.CFONB_EXPORT_2),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
e);
}
}
/**
* Méthode permettant de construire le Nom/Raison sociale du tiers payeur d'un mémoire
*
* @param memory Un mémoire
* @return Civilité + Nom + Prénom si c'est une personne physique Civilité + Nom sinon
*/
private String getPayeurPartnerName(Partner partner) {
if (partner.getTitleSelect() != null) {
return String.format("%s %s", partner.getTitleSelect(), partner.getName());
} else {
return String.format("%s", partner.getName());
}
}
/**
* Méthode permettant de calculer le montant total des remboursements
*
* @param reimbursementList Une liste de remboursement
* @return Le montant total
*/
private BigDecimal getTotalAmountReimbursementExport(List<Reimbursement> reimbursementList) {
BigDecimal totalAmount = BigDecimal.ZERO;
for (Reimbursement reimbursement : reimbursementList) {
reimbursement = reimbursementRepo.find(reimbursement.getId());
totalAmount = totalAmount.add(reimbursement.getAmountReimbursed());
}
return totalAmount;
}
/**
* Fonction permettant de récupérer le montant total à prélever d'une liste d'échéance de mensu
*
* @param paymentScheduleLineList Une liste d'échéance de mensu
* @return Le montant total à prélever
*/
private BigDecimal getTotalAmountPaymentSchedule(
List<PaymentScheduleLine> paymentScheduleLineList) {
BigDecimal totalAmount = BigDecimal.ZERO;
for (PaymentScheduleLine paymentScheduleLine : paymentScheduleLineList) {
totalAmount =
totalAmount.add(
paymentScheduleLineRepo.find(paymentScheduleLine.getId()).getDirectDebitAmount());
}
return totalAmount;
}
/**
* Fonction permettant de récupérer le montant total à prélever d'une liste d'échéance de mensu
*
* @param paymentScheduleLineList Une liste d'échéance de mensu
* @return Le montant total à prélever
*/
private BigDecimal getTotalAmountInvoice(List<Invoice> invoiceList) {
BigDecimal totalAmount = BigDecimal.ZERO;
for (Invoice invoice : invoiceList) {
totalAmount = totalAmount.add(invoiceRepo.find(invoice.getId()).getDirectDebitAmount());
}
return totalAmount;
}
/**
* Procédure permettant de vérifier la conformité des champs en rapport avec les exports CFONB
* d'une société
*
* @param company La société
* @throws AxelorException
*/
public void testCompanyExportCFONBField(Company company) throws AxelorException {
AccountConfig accountConfig = cfonbConfigService.getAccountConfig(company);
cfonbConfigService.getReimbursementExportFolderPathCFONB(accountConfig);
cfonbConfigService.getPaymentScheduleExportFolderPathCFONB(accountConfig);
this.init(cfonbConfigService.getCfonbConfig(company));
cfonbConfigService.getSenderRecordCodeExportCFONB(this.cfonbConfig);
cfonbConfigService.getSenderNumExportCFONB(this.cfonbConfig);
cfonbConfigService.getSenderNameCodeExportCFONB(this.cfonbConfig);
cfonbConfigService.getRecipientRecordCodeExportCFONB(this.cfonbConfig);
cfonbConfigService.getTotalRecordCodeExportCFONB(this.cfonbConfig);
cfonbConfigService.getTransferOperationCodeExportCFONB(this.cfonbConfig);
cfonbConfigService.getDirectDebitOperationCodeExportCFONB(this.cfonbConfig);
}
/**
* Procédure permettant de vérifier la conformité des champs d'un RIB
*
* @param bankDetails Le RIB
* @throws AxelorException
*/
public void testBankDetailsField(BankDetails bankDetails) throws AxelorException {
if (bankDetails.getSortCode() == null || bankDetails.getSortCode().isEmpty()) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.CFONB_EXPORT_3),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
bankDetails.getIban(),
bankDetails.getPartner().getName());
}
if (bankDetails.getAccountNbr() == null || bankDetails.getAccountNbr().isEmpty()) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.CFONB_EXPORT_4),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
bankDetails.getIban(),
bankDetails.getPartner().getName());
}
if (bankDetails.getBankCode() == null || bankDetails.getBankCode().isEmpty()) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.CFONB_EXPORT_5),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
bankDetails.getIban(),
bankDetails.getPartner().getName());
}
String bankAddress = bankDetails.getBankAddress().getAddress();
if (bankAddress == null || bankAddress.isEmpty()) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.CFONB_EXPORT_6),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
bankDetails.getIban(),
bankDetails.getPartner().getName());
}
}
}

View File

@ -0,0 +1,593 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.bankorder.file.cfonb;
import com.axelor.apps.account.db.CfonbConfig;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.app.AppAccountService;
import com.axelor.apps.account.service.config.CfonbConfigService;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.tool.file.FileTool;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.google.inject.Inject;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CfonbImportService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected CfonbConfigService cfonbConfigService;
protected AppAccountService appAccountService;
protected CfonbConfig cfonbConfig;
protected List<String> importFile;
@Inject
public CfonbImportService(
CfonbConfigService cfonbConfigService, AppAccountService appAccountService) {
this.cfonbConfigService = cfonbConfigService;
this.appAccountService = appAccountService;
}
private void init(CfonbConfig cfonbConfig) {
this.cfonbConfig = cfonbConfig;
}
private void init(Company company) throws AxelorException {
this.init(cfonbConfigService.getCfonbConfig(company));
}
/**
* @param fileName
* @param company
* @param operation Le type d'opération :
* <ul>
* <li>0 = Virement
* <li>1 = Prélèvement
* </ul>
*
* @return
* @throws AxelorException
* @throws IOException
*/
public List<String[]> importCFONB(String fileName, Company company, int operation)
throws AxelorException, IOException {
return this.importCFONB(fileName, company, operation, 999);
}
/**
* Récupération par lots
*
* @param fileName
* @param company
* @param operation Le type d'opération :
* <ul>
* <li>0 = Virement
* <li>1 = Prélèvement
* </ul>
*
* @return
* @throws AxelorException
* @throws IOException
*/
public Map<List<String[]>, String> importCFONBByLot(
String fileName, Company company, int operation) throws AxelorException, IOException {
return this.importCFONBByLot(fileName, company, operation, 999);
}
/**
* @param fileName
* @param company
* @param operation Le type d'opération :
* <ul>
* <li>0 = Virement
* <li>1 = Prélèvement
* </ul>
*
* @return
* @throws AxelorException
* @throws IOException
*/
public List<String[]> importCFONB(
String fileName, Company company, int operation, int optionalOperation)
throws AxelorException, IOException {
// un enregistrement "en-tête" (code 31)
// un enregistrement "détail" (code 34)
// un enregistrement "fin" (code 39)
this.testCompanyImportCFONBField(company);
this.importFile = FileTool.reader(fileName);
if (appAccountService.getAppAccount().getTransferAndDirectDebitInterbankCode() == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.CFONB_IMPORT_1),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION));
}
String headerCFONB = null;
List<String> multiDetailsCFONB = null;
String endingCFONB = null;
List<String[]> importDataList = new ArrayList<String[]>();
// Pour chaque sequence, on récupère les enregistrements, et on les vérifie.
// Ensuite on supprime les lignes traitées du fichier chargé en mémoire
// Et on recommence l'opération jusqu'à ne plus avoir de ligne à traiter
while (this.importFile != null && this.importFile.size() != 0) {
headerCFONB = this.getHeaderCFONB(this.importFile, operation, optionalOperation);
if (headerCFONB == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.CFONB_IMPORT_2),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
fileName);
}
this.importFile.remove(headerCFONB);
multiDetailsCFONB = this.getDetailsCFONB(this.importFile, operation, optionalOperation);
if (multiDetailsCFONB.isEmpty()) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.CFONB_IMPORT_3),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
fileName);
}
for (String detail : multiDetailsCFONB) {
this.importFile.remove(detail);
}
endingCFONB = this.getEndingCFONB(this.importFile, operation, optionalOperation);
if (endingCFONB == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.CFONB_IMPORT_4),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
fileName);
}
this.importFile.remove(endingCFONB);
this.testLength(headerCFONB, multiDetailsCFONB, endingCFONB, company);
importDataList.addAll(
this.getDetailDataAndCheckAmount(
operation, headerCFONB, multiDetailsCFONB, endingCFONB, fileName));
}
return importDataList;
}
/**
* Récupération par lots
*
* @param fileName
* @param company
* @param operation Le type d'opération :
* <ul>
* <li>0 = Virement
* <li>1 = Prélèvement
* </ul>
*
* @return
* @throws AxelorException
* @throws IOException
*/
public Map<List<String[]>, String> importCFONBByLot(
String fileName, Company company, int operation, int optionalOperation)
throws AxelorException, IOException {
// un enregistrement "en-tête" (code 31)
// un enregistrement "détail" (code 34)
// un enregistrement "fin" (code 39)
this.testCompanyImportCFONBField(company);
this.importFile = FileTool.reader(fileName);
if (appAccountService.getAppAccount().getTransferAndDirectDebitInterbankCode() == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.CFONB_IMPORT_1),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION));
}
String headerCFONB = null;
List<String> multiDetailsCFONB = null;
String endingCFONB = null;
Map<List<String[]>, String> importDataList = new HashMap<List<String[]>, String>();
// Pour chaque sequence, on récupère les enregistrements, et on les vérifie.
// Ensuite on supprime les lignes traitées du fichier chargé en mémoire
// Et on recommence l'opération jusqu'à ne plus avoir de ligne à traiter
while (this.importFile != null && this.importFile.size() != 0) {
headerCFONB = this.getHeaderCFONB(this.importFile, operation, optionalOperation);
if (headerCFONB == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.CFONB_IMPORT_2),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
fileName);
}
this.importFile.remove(headerCFONB);
multiDetailsCFONB = this.getDetailsCFONB(this.importFile, operation, optionalOperation);
if (multiDetailsCFONB.isEmpty()) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.CFONB_IMPORT_3),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
fileName);
}
for (String detail : multiDetailsCFONB) {
this.importFile.remove(detail);
}
endingCFONB = this.getEndingCFONB(this.importFile, operation, optionalOperation);
if (endingCFONB == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.CFONB_IMPORT_4),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
fileName);
}
this.importFile.remove(endingCFONB);
this.testLength(headerCFONB, multiDetailsCFONB, endingCFONB, company);
importDataList.put(
this.getDetailDataAndCheckAmount(
operation, headerCFONB, multiDetailsCFONB, endingCFONB, fileName),
this.getHeaderDate(headerCFONB));
}
return importDataList;
}
private List<String[]> getDetailDataAndCheckAmount(
int operation,
String headerCFONB,
List<String> multiDetailsCFONB,
String endingCFONB,
String fileName)
throws AxelorException {
List<String[]> importDataList = new ArrayList<String[]>();
switch (operation) {
case 0:
for (String detailCFONB : multiDetailsCFONB) {
importDataList.add(this.getDetailData(detailCFONB));
}
this.checkTotalAmount(multiDetailsCFONB, endingCFONB, fileName, 228, 240);
break;
case 1:
for (String detailCFONB : multiDetailsCFONB) {
importDataList.add(this.getDetailData(detailCFONB));
}
this.checkTotalAmount(multiDetailsCFONB, endingCFONB, fileName, 228, 240);
break;
default:
break;
}
return importDataList;
}
private void checkTotalAmount(
List<String> multiDetailsCFONB,
String endingCFONB,
String fileName,
int amountPosStart,
int amountPosEnd)
throws AxelorException {
int totalAmount = 0;
for (String detailCFONB : multiDetailsCFONB) {
totalAmount += Integer.parseInt(detailCFONB.substring(amountPosStart, amountPosEnd));
}
int totalRecord = Integer.parseInt(endingCFONB.substring(amountPosStart, amountPosEnd));
log.debug(
"Controle du montant total des enregistrement détail ({}) et du montant de l'enregistrement total ({})",
new Object[] {totalAmount, totalRecord});
if (totalAmount != totalRecord) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.CFONB_IMPORT_5),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
fileName,
endingCFONB);
}
}
private void testLength(
String headerCFONB, List<String> multiDetailsCFONB, String endingCFONB, Company company)
throws AxelorException {
// cfonbToolService.testLength(headerCFONB, 240);
// cfonbToolService.testLength(endingCFONB, 240);
// for(String detailCFONB : multiDetailsCFONB) {
// cfonbToolService.testLength(detailCFONB, 240);
// }
}
/**
* Fonction permettant de récupérer les infos de rejet d'un prélèvement ou virement
*
* @param detailCFONB Un enregistrement 'détail' d'un rejet de prélèvement au format CFONB
* @return Les infos de rejet d'un prélèvement ou virement
*/
private String[] getDetailData(String detailCFONB) {
String[] detailData = new String[4];
log.debug("detailCFONB : {}", detailCFONB);
detailData[0] = detailCFONB.substring(214, 220); // Date de rejet
detailData[1] =
detailCFONB.substring(152, 183).split("/")[0].trim(); // Ref prélèvement ou remboursement
detailData[2] =
detailCFONB.substring(228, 240).substring(0, 10)
+ "."
+ detailCFONB.substring(228, 240).substring(10); // Montant rejeté
detailData[3] = detailCFONB.substring(226, 228); // Motif du rejet
log.debug(
"Obtention des données d'un enregistrement détail CFONB: Date de rejet = {}, Ref prélèvement = {}, Montant rejeté = {}, Motif du rejet = {}",
new Object[] {detailData[0], detailData[1], detailData[2], detailData[3]});
return detailData;
}
/**
* Fonction permettant de récupérer la date de rejet de l'en-tête d'un lot de rejet de prélèvement
* ou virement
*
* @param detailCFONB Un enregistrement 'détail' d'un rejet de prélèvement au format CFONB
* @return Les infos de rejet d'un prélèvement ou virement
*/
private String getHeaderDate(String headerCFONB) {
return headerCFONB.substring(10, 16);
}
/**
* Procédure permettant de vérifier la conformité des champs en rapport avec les imports CFONB
* d'une société
*
* @param company Une société
* @throws AxelorException
*/
public void testCompanyImportCFONBField(Company company) throws AxelorException {
this.init(company);
cfonbConfigService.getHeaderRecordCodeImportCFONB(this.cfonbConfig);
cfonbConfigService.getDetailRecordCodeImportCFONB(this.cfonbConfig);
cfonbConfigService.getEndingRecordCodeImportCFONB(this.cfonbConfig);
cfonbConfigService.getTransferOperationCodeImportCFONB(this.cfonbConfig);
cfonbConfigService.getDirectDebitOperationCodeImportCFONB(this.cfonbConfig);
}
/**
* @param file
* @param company
* @param operation Le type d'opération :
* <ul>
* <li>0 = Virement
* <li>1 = Prélèvement
* </ul>
*
* @return
*/
private String getHeaderCFONB(List<String> file, int operation, int optionalOperation) {
String recordCode = this.getHeaderRecordCode(operation);
String optionalRecordCode = this.getHeaderRecordCode(optionalOperation);
String operationCode = this.getImportOperationCode(operation);
String optionalOperationCode = this.getImportOperationCode(optionalOperation);
log.debug(
"Obtention enregistrement en-tête CFONB: recordCode = {}, operationCode = {}, optionalRecordCode = {}, optionalOperationCode = {}",
new Object[] {recordCode, operationCode, optionalRecordCode, optionalOperationCode});
for (String s : file) {
log.debug("file line : {}", s);
log.debug("s.substring(0, 2) : {}", s.substring(0, 2));
if (s.substring(0, 2).equals(recordCode) || s.substring(0, 2).equals(optionalRecordCode)) {
log.debug("s.substring(8, 10) : {}", s.substring(8, 10));
log.debug("s.substring(2, 4) : {}", s.substring(2, 4));
if ((s.substring(8, 10).equals(operationCode) && optionalOperation == 999)
|| s.substring(2, 4).equals(operationCode)
|| s.substring(2, 4).equals(optionalOperationCode)) {
return s;
}
} else {
break;
}
}
return null;
}
/**
* Fonction permettant de récupérer le code d'enregistrement en-tête
*
* @param company Une société
* @param operation Le type d'opération :
* <ul>
* <li>0 = Virement
* <li>1 = Prélèvement
* </ul>
*
* @return 999 si operation non correct
*/
private String getHeaderRecordCode(int operation) {
if (operation == 0 || operation == 1 || operation == 2) {
return this.cfonbConfig.getHeaderRecordCodeImportCFONB();
} else if (operation == 3 || operation == 4) {
return this.cfonbConfig.getSenderRecordCodeExportCFONB();
}
return "999";
}
/**
* @param file
* @param company
* @param operation Le type d'opération :
* <ul>
* <li>0 = Virement
* <li>1 = Prélèvement
* </ul>
*
* @return
*/
private List<String> getDetailsCFONB(List<String> file, int operation, int optionalOperation) {
List<String> stringList = new ArrayList<String>();
String recordCode = this.getDetailRecordCode(operation);
String operationCode = this.getImportOperationCode(operation);
String optionalRecordCode = this.getDetailRecordCode(optionalOperation);
String optionalOperationCode = this.getImportOperationCode(optionalOperation);
log.debug(
"Obtention enregistrement détails CFONB: recordCode = {}, operationCode = {}, optionalRecordCode = {}, optionalOperationCode = {}",
new Object[] {recordCode, operationCode, optionalRecordCode, optionalOperationCode});
for (String s : file) {
if (s.substring(0, 2).equals(recordCode) || s.substring(0, 2).equals(optionalRecordCode)) {
if ((s.substring(8, 10).equals(operationCode) && optionalOperation == 999)
|| s.substring(2, 4).equals(operationCode)
|| s.substring(2, 4).equals(optionalOperationCode)) {
stringList.add(s);
}
} else {
break;
}
}
return stringList;
}
/**
* Fonction permettant de récupérer le code d'enregistrement détail
*
* @param company Une société
* @param operation Le type d'opération :
* <ul>
* <li>0 = Virement
* <li>1 = Prélèvement
* </ul>
*
* @return 999 si operation non correct
*/
private String getDetailRecordCode(int operation) {
if (operation == 0 || operation == 1 || operation == 2) {
return this.cfonbConfig.getDetailRecordCodeImportCFONB();
} else if (operation == 3 || operation == 4) {
return this.cfonbConfig.getRecipientRecordCodeExportCFONB();
}
return "999";
}
/**
* @param file
* @param company
* @param operation Le type d'opération :
* <ul>
* <li>0 = Virement
* <li>1 = Prélèvement
* </ul>
*
* @return
*/
private String getEndingCFONB(List<String> file, int operation, int optionalOperation) {
String operationCode = this.getImportOperationCode(operation);
String recordCode = this.getEndingRecordCode(operation);
String optionalRecordCode = this.getEndingRecordCode(optionalOperation);
String optionalOperationCode = this.getImportOperationCode(optionalOperation);
log.debug(
"Obtention enregistrement fin CFONB: recordCode = {}, operationCode = {}, optionalRecordCode = {}, optionalOperationCode = {}",
new Object[] {recordCode, operationCode, optionalRecordCode, optionalOperationCode});
for (String s : file) {
if (s.substring(0, 2).equals(recordCode) || s.substring(0, 2).equals(optionalRecordCode)) {
if ((s.substring(8, 10).equals(operationCode) && optionalOperation == 999)
|| s.substring(2, 4).equals(operationCode)
|| s.substring(2, 4).equals(optionalOperationCode)) {
return s;
}
} else {
break;
}
}
return null;
}
/**
* Fonction permettant de récupérer le code d'enregistrement fin
*
* @param company Une société
* @param operation Le type d'opération :
* <ul>
* <li>0 = Virement
* <li>1 = Prélèvement
* </ul>
*
* @return 999 si operation non correct
*/
private String getEndingRecordCode(int operation) {
if (operation == 0 || operation == 1 || operation == 2) {
return this.cfonbConfig.getEndingRecordCodeImportCFONB();
} else if (operation == 3 || operation == 4) {
return this.cfonbConfig.getTotalRecordCodeExportCFONB();
}
return "999";
}
/**
* Méthode permettant de récupérer le code "opération" défini par société en fonction du type
* d'opération souhaité
*
* @param company La société
* @param operation Le type d'opération :
* <ul>
* <li>0 = Virement
* <li>1 = Prélèvement
* </ul>
*
* @return Le code opération
*/
private String getImportOperationCode(int operation) {
String operationCode = "";
switch (operation) {
case 0:
operationCode = this.cfonbConfig.getTransferOperationCodeImportCFONB();
break;
case 1:
operationCode = this.cfonbConfig.getDirectDebitOperationCodeImportCFONB();
break;
default:
break;
}
return operationCode;
}
}

View File

@ -0,0 +1,159 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.batch;
import com.axelor.apps.account.db.AccountingBatch;
import com.axelor.apps.account.db.repo.AccountingBatchRepository;
import com.axelor.apps.base.db.Batch;
import com.axelor.apps.base.exceptions.IExceptionMessage;
import com.axelor.apps.base.service.administration.AbstractBatchService;
import com.axelor.db.Model;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
public class AccountingBatchService extends AbstractBatchService {
@Override
protected Class<? extends Model> getModelClass() {
return AccountingBatch.class;
}
@Override
public Batch run(Model batchModel) throws AxelorException {
Batch batch;
AccountingBatch accountingBatch = (AccountingBatch) batchModel;
switch (accountingBatch.getActionSelect()) {
case AccountingBatchRepository.ACTION_REIMBURSEMENT:
if (accountingBatch.getReimbursementTypeSelect()
== AccountingBatchRepository.REIMBURSEMENT_TYPE_EXPORT) {
batch = reimbursementExport(accountingBatch);
} else if (accountingBatch.getReimbursementTypeSelect()
== AccountingBatchRepository.REIMBURSEMENT_TYPE_IMPORT) {
batch = reimbursementImport(accountingBatch);
}
batch = null;
break;
case AccountingBatchRepository.ACTION_DEBT_RECOVERY:
batch = debtRecovery(accountingBatch);
break;
case AccountingBatchRepository.ACTION_DOUBTFUL_CUSTOMER:
batch = doubtfulCustomer(accountingBatch);
break;
case AccountingBatchRepository.ACTION_ACCOUNT_CUSTOMER:
batch = accountCustomer(accountingBatch);
break;
case AccountingBatchRepository.ACTION_MOVE_LINE_EXPORT:
batch = moveLineExport(accountingBatch);
break;
case AccountingBatchRepository.ACTION_CREDIT_TRANSFER:
batch = creditTransfer(accountingBatch);
break;
case AccountingBatchRepository.ACTION_REALIZE_FIXED_ASSET_LINES:
batch = realizeFixedAssetLines(accountingBatch);
break;
default:
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.BASE_BATCH_1),
accountingBatch.getActionSelect(),
accountingBatch.getCode());
}
return batch;
}
public Batch debtRecovery(AccountingBatch accountingBatch) {
return Beans.get(BatchDebtRecovery.class).run(accountingBatch);
}
public Batch doubtfulCustomer(AccountingBatch accountingBatch) {
return Beans.get(BatchDoubtfulCustomer.class).run(accountingBatch);
}
public Batch reimbursementExport(AccountingBatch accountingBatch) {
return Beans.get(BatchReimbursementExport.class).run(accountingBatch);
}
public Batch reimbursementImport(AccountingBatch accountingBatch) {
return Beans.get(BatchReimbursementImport.class).run(accountingBatch);
}
public Batch accountCustomer(AccountingBatch accountingBatch) {
return Beans.get(BatchAccountCustomer.class).run(accountingBatch);
}
public Batch moveLineExport(AccountingBatch accountingBatch) {
return Beans.get(BatchMoveLineExport.class).run(accountingBatch);
}
public Batch creditTransfer(AccountingBatch accountingBatch) {
Class<? extends BatchStrategy> batchStrategyClass;
switch (accountingBatch.getCreditTransferTypeSelect()) {
case AccountingBatchRepository.CREDIT_TRANSFER_EXPENSE_PAYMENT:
batchStrategyClass = BatchCreditTransferExpensePayment.class;
break;
case AccountingBatchRepository.CREDIT_TRANSFER_SUPPLIER_PAYMENT:
batchStrategyClass = BatchCreditTransferSupplierPayment.class;
break;
case AccountingBatchRepository.CREDIT_TRANSFER_CUSTOMER_REIMBURSEMENT:
switch (accountingBatch.getCustomerReimbursementTypeSelect()) {
case AccountingBatchRepository.CUSTOMER_REIMBURSEMENT_CUSTOMER_REFUND:
batchStrategyClass = BatchCreditTransferCustomerRefund.class;
break;
case AccountingBatchRepository.CUSTOMER_REIMBURSEMENT_PARTNER_CREDIT_BALANCE:
batchStrategyClass = BatchCreditTransferPartnerReimbursement.class;
break;
default:
throw new IllegalArgumentException("Unknown customer reimbursement type");
}
break;
default:
throw new IllegalArgumentException(
String.format(
"Unknown credit transfer type: %d", accountingBatch.getCreditTransferTypeSelect()));
}
return Beans.get(batchStrategyClass).run(accountingBatch);
}
public Batch directDebit(AccountingBatch accountingBatch) {
throw new UnsupportedOperationException(
I18n.get("This batch requires the bank payment module."));
}
public Batch realizeFixedAssetLines(AccountingBatch accountingBatch) {
return Beans.get(BatchRealizeFixedAssetLine.class).run(accountingBatch);
}
public Batch closeAnnualAccounts(AccountingBatch accountingBatch) {
return Beans.get(BatchCloseAnnualAccounts.class).run(accountingBatch);
}
}

View File

@ -0,0 +1,194 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.batch;
import com.axelor.apps.account.db.AccountingBatch;
import com.axelor.apps.account.db.AccountingSituation;
import com.axelor.apps.account.db.repo.AccountingSituationRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.AccountCustomerService;
import com.axelor.apps.base.db.Company;
import com.axelor.db.JPA;
import com.axelor.exception.db.repo.ExceptionOriginRepository;
import com.axelor.exception.service.TraceBackService;
import com.axelor.i18n.I18n;
import com.google.inject.Inject;
import java.lang.invoke.MethodHandles;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BatchAccountCustomer extends BatchStrategy {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected AccountingSituationRepository accountingSituationRepo;
@Inject
public BatchAccountCustomer(
AccountCustomerService accountCustomerService,
AccountingSituationRepository accountingSituationRepo) {
super(accountCustomerService);
this.accountingSituationRepo = accountingSituationRepo;
}
@Override
protected void start() throws IllegalAccessException {
super.start();
checkPoint();
}
@Override
public void process() {
AccountingBatch accountingBatch = batch.getAccountingBatch();
Company company = accountingBatch.getCompany();
boolean updateCustAccountOk = accountingBatch.getUpdateCustAccountOk();
boolean updateDueCustAccountOk = accountingBatch.getUpdateDueCustAccountOk();
boolean updateDueDebtRecoveryCustAccountOk =
accountingBatch.getUpdateDueDebtRecoveryCustAccountOk();
List<AccountingSituation> accountingSituationList =
accountingSituationRepo.all().filter("self.company = ?1", company).fetch();
int i = 0;
JPA.clear();
for (AccountingSituation accountingSituation : accountingSituationList) {
try {
accountingSituation =
accountCustomerService.updateAccountingSituationCustomerAccount(
accountingSituationRepo.find(accountingSituation.getId()),
updateCustAccountOk,
updateDueCustAccountOk,
updateDueDebtRecoveryCustAccountOk);
if (accountingSituation != null) {
this.updateAccountingSituation(accountingSituation);
i++;
}
} catch (Exception e) {
TraceBackService.trace(
new Exception(
String.format(
I18n.get(IExceptionMessage.BATCH_ACCOUNT_1),
accountingSituationRepo.find(accountingSituation.getId()).getName()),
e),
ExceptionOriginRepository.ACCOUNT_CUSTOMER,
batch.getId());
incrementAnomaly();
log.error(
"Bug(Anomalie) généré(e) pour la situation compable {}",
accountingSituationRepo.find(accountingSituation.getId()).getName());
} finally {
if (i % 1 == 0) {
JPA.clear();
}
}
}
}
/**
* As {@code batch} entity can be detached from the session, call {@code Batch.find()} get the
* entity in the persistant context. Warning : {@code batch} entity have to be saved before.
*/
@Override
protected void stop() {
String comment = "";
comment = I18n.get(IExceptionMessage.BATCH_ACCOUNT_2) + "\n";
comment +=
String.format("\t" + I18n.get(IExceptionMessage.BATCH_ACCOUNT_3) + "\n", batch.getDone());
comment +=
String.format(
"\t" + I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.ALARM_ENGINE_BATCH_4),
batch.getAnomaly());
super.stop();
addComment(comment);
}
public String updateAccountingSituationMarked(Company company) {
int anomaly = 0;
List<AccountingSituation> accountingSituationList = null;
if (company != null) {
accountingSituationList =
accountingSituationRepo
.all()
.filter("self.company = ?1 and self.custAccountMustBeUpdateOk = 'true'", company)
.fetch();
} else {
accountingSituationList =
accountingSituationRepo.all().filter("self.custAccountMustBeUpdateOk = 'true'").fetch();
}
int i = 0;
JPA.clear();
for (AccountingSituation accountingSituation : accountingSituationList) {
try {
accountingSituation =
accountCustomerService.updateAccountingSituationCustomerAccount(
accountingSituationRepo.find(accountingSituation.getId()), true, true, false);
if (accountingSituation != null) {
i++;
}
} catch (Exception e) {
TraceBackService.trace(
new Exception(
String.format(
I18n.get(IExceptionMessage.BATCH_ACCOUNT_1),
accountingSituationRepo.find(accountingSituation.getId()).getName()),
e),
ExceptionOriginRepository.ACCOUNT_CUSTOMER,
batch.getId());
anomaly++;
log.error(
"Bug(Anomalie) généré(e) pour le compte client {}",
accountingSituationRepo.find(accountingSituation.getId()));
} finally {
if (i % 5 == 0) {
JPA.clear();
}
}
}
if (anomaly != 0) {
return String.format(I18n.get(IExceptionMessage.BATCH_ACCOUNT_4), anomaly);
} else {
return String.format(I18n.get(IExceptionMessage.BATCH_ACCOUNT_5), i);
}
}
}

View File

@ -0,0 +1,177 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.batch;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountingBatch;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.repo.AccountRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.AccountingCloseAnnualService;
import com.axelor.apps.account.service.AccountingReportService;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.Year;
import com.axelor.apps.base.db.repo.PartnerRepository;
import com.axelor.apps.base.db.repo.YearRepository;
import com.axelor.db.JPA;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.ExceptionOriginRepository;
import com.axelor.exception.service.TraceBackService;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import java.time.LocalDate;
import java.util.List;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BatchCloseAnnualAccounts extends BatchStrategy {
protected final Logger log = LoggerFactory.getLogger(getClass());
protected PartnerRepository partnerRepository;
protected YearRepository yearRepository;
protected AccountRepository accountRepository;
protected AccountingCloseAnnualService accountingCloseAnnualService;
protected boolean stop = false;
@Inject
public BatchCloseAnnualAccounts(
PartnerRepository partnerRepository,
YearRepository yearRepository,
AccountRepository accountRepository,
AccountingCloseAnnualService accountingCloseAnnualService) {
this.partnerRepository = partnerRepository;
this.yearRepository = yearRepository;
this.accountRepository = accountRepository;
this.accountingCloseAnnualService = accountingCloseAnnualService;
}
@Override
protected void start() throws IllegalAccessException {
super.start();
try {
Beans.get(AccountingReportService.class)
.testReportedDateField(batch.getAccountingBatch().getYear().getReportedBalanceDate());
} catch (AxelorException e) {
TraceBackService.trace(
new AxelorException(e, e.getCategory(), ""),
ExceptionOriginRepository.REPORTED_BALANCE,
batch.getId());
incrementAnomaly();
stop = true;
}
}
protected void process() {
if (!stop) {
AccountingBatch accountingBatch = batch.getAccountingBatch();
boolean allocatePerPartner = accountingBatch.getAllocatePerPartner();
boolean closeYear = accountingBatch.getCloseYear();
boolean openYear = accountingBatch.getOpenYear();
Year year = accountingBatch.getYear();
LocalDate endOfYearDate = year.getToDate();
LocalDate reportedBalanceDate = year.getReportedBalanceDate();
String origin = accountingBatch.getCode();
String moveDescription = accountingBatch.getMoveDescription();
List<Long> accountIdList =
accountingCloseAnnualService.getAllAccountOfYear(accountingBatch.getAccountSet(), year);
List<Pair<Long, Long>> accountAndPartnerPairList =
accountingCloseAnnualService.assignPartner(accountIdList, year, allocatePerPartner);
Account account = null;
Partner partner = null;
for (Pair<Long, Long> accountAndPartnerPair : accountAndPartnerPairList) {
try {
account = accountRepository.find(accountAndPartnerPair.getLeft());
if (accountAndPartnerPair.getRight() != null) {
partner = partnerRepository.find(accountAndPartnerPair.getRight());
} else {
partner = null;
}
List<Move> generateMoves =
accountingCloseAnnualService.generateCloseAnnualAccount(
yearRepository.find(year.getId()),
account,
partner,
endOfYearDate,
reportedBalanceDate,
origin,
moveDescription,
closeYear,
openYear,
allocatePerPartner);
if (generateMoves != null && !generateMoves.isEmpty()) {
updateAccount(account);
for (Move move : generateMoves) {
updateAccountMove(move, false);
}
}
} catch (AxelorException e) {
TraceBackService.trace(
new AxelorException(
e, e.getCategory(), I18n.get("Account") + " %s", account.getCode()),
null,
batch.getId());
incrementAnomaly();
break;
} catch (Exception e) {
TraceBackService.trace(
new Exception(String.format(I18n.get("Account") + " %s", account.getCode()), e),
null,
batch.getId());
incrementAnomaly();
LOG.error("Anomaly generated for the account {}", account.getCode());
break;
} finally {
JPA.clear();
}
}
}
}
@Override
protected void stop() {
StringBuilder sb = new StringBuilder();
sb.append(I18n.get(IExceptionMessage.BATCH_CLOSE_OPEN_ANNUAL_ACCOUNT_REPORT_TITLE)).append(" ");
sb.append(
String.format(
I18n.get(
IExceptionMessage.BATCH_CLOSE_OPEN_ANNUAL_ACCOUNT_DONE_SINGULAR,
IExceptionMessage.BATCH_CLOSE_OPEN_ANNUAL_ACCOUNT_DONE_PLURAL,
batch.getDone())
+ " ",
batch.getDone()));
sb.append(
String.format(
I18n.get(
com.axelor.apps.base.exceptions.IExceptionMessage.ABSTRACT_BATCH_ANOMALY_SINGULAR,
com.axelor.apps.base.exceptions.IExceptionMessage.ABSTRACT_BATCH_ANOMALY_PLURAL,
batch.getAnomaly()),
batch.getAnomaly()));
addComment(sb.toString());
super.stop();
}
}

View File

@ -0,0 +1,41 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.batch;
import com.axelor.apps.account.db.repo.InvoicePaymentRepository;
import com.axelor.apps.account.db.repo.InvoiceRepository;
import com.axelor.apps.account.service.app.AppAccountService;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCreateService;
import com.google.inject.Inject;
public class BatchCreditTransferCustomerRefund extends BatchCreditTransferInvoice {
@Inject
public BatchCreditTransferCustomerRefund(
AppAccountService appAccountService,
InvoiceRepository invoiceRepo,
InvoicePaymentCreateService invoicePaymentCreateService,
InvoicePaymentRepository invoicePaymentRepository) {
super(appAccountService, invoiceRepo, invoicePaymentCreateService, invoicePaymentRepository);
}
@Override
protected void process() {
processInvoices(InvoiceRepository.OPERATION_TYPE_CLIENT_REFUND);
}
}

View File

@ -0,0 +1,29 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.batch;
import com.axelor.i18n.I18n;
public class BatchCreditTransferExpensePayment extends BatchStrategy {
@Override
protected void process() {
throw new UnsupportedOperationException(
I18n.get("This batch requires the human resources module."));
}
}

View File

@ -0,0 +1,176 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.batch;
import com.axelor.apps.account.db.AccountingBatch;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.InvoicePayment;
import com.axelor.apps.account.db.repo.InvoicePaymentRepository;
import com.axelor.apps.account.db.repo.InvoiceRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.app.AppAccountService;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCreateService;
import com.axelor.apps.base.db.BankDetails;
import com.axelor.apps.base.db.repo.BankDetailsRepository;
import com.axelor.db.JPA;
import com.axelor.db.Query;
import com.axelor.exception.db.repo.ExceptionOriginRepository;
import com.axelor.exception.service.TraceBackService;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class BatchCreditTransferInvoice extends BatchStrategy {
protected final Logger log = LoggerFactory.getLogger(getClass());
protected final AppAccountService appAccountService;
protected final InvoiceRepository invoiceRepo;
protected final InvoicePaymentCreateService invoicePaymentCreateService;
protected final InvoicePaymentRepository invoicePaymentRepository;
@Inject
public BatchCreditTransferInvoice(
AppAccountService appAccountService,
InvoiceRepository invoiceRepo,
InvoicePaymentCreateService invoicePaymentCreateService,
InvoicePaymentRepository invoicePaymentRepository) {
this.appAccountService = appAccountService;
this.invoiceRepo = invoiceRepo;
this.invoicePaymentCreateService = invoicePaymentCreateService;
this.invoicePaymentRepository = invoicePaymentRepository;
}
/**
* Process invoices of the specified document type.
*
* @param operationTypeSelect
* @return
*/
protected List<InvoicePayment> processInvoices(int operationTypeSelect) {
List<InvoicePayment> doneList = new ArrayList<>();
List<Long> anomalyList = Lists.newArrayList(0L); // Can't pass an empty collection to the query
AccountingBatch accountingBatch = batch.getAccountingBatch();
boolean manageMultiBanks = appAccountService.getAppBase().getManageMultiBanks();
StringBuilder filter = new StringBuilder();
filter.append(
"self.operationTypeSelect = :operationTypeSelect "
+ "AND self.statusSelect = :statusSelect "
+ "AND self.amountRemaining > 0 "
+ "AND self.hasPendingPayments = FALSE "
+ "AND self.company = :company "
+ "AND self.dueDate <= :dueDate "
+ "AND self.paymentMode = :paymentMode "
+ "AND self.id NOT IN (:anomalyList)"
+ "AND self.pfpValidateStatusSelect != :pfpValidateStatusSelect");
if (manageMultiBanks) {
filter.append(" AND self.companyBankDetails IN (:bankDetailsSet)");
}
if (accountingBatch.getCurrency() != null) {
filter.append(" AND self.currency = :currency");
}
Query<Invoice> query =
invoiceRepo
.all()
.filter(filter.toString())
.bind("operationTypeSelect", operationTypeSelect)
.bind("statusSelect", InvoiceRepository.STATUS_VENTILATED)
.bind("company", accountingBatch.getCompany())
.bind("dueDate", accountingBatch.getDueDate())
.bind("paymentMode", accountingBatch.getPaymentMode())
.bind("anomalyList", anomalyList)
.bind("pfpValidateStatusSelect", InvoiceRepository.PFP_STATUS_LITIGATION);
if (manageMultiBanks) {
Set<BankDetails> bankDetailsSet = Sets.newHashSet(accountingBatch.getBankDetails());
if (accountingBatch.getIncludeOtherBankAccounts()) {
bankDetailsSet.addAll(accountingBatch.getCompany().getBankDetailsSet());
}
query.bind("bankDetailsSet", bankDetailsSet);
}
if (accountingBatch.getCurrency() != null) {
query.bind("currency", accountingBatch.getCurrency());
}
BankDetailsRepository bankDetailsRepo = Beans.get(BankDetailsRepository.class);
BankDetails companyBankDetails = accountingBatch.getBankDetails();
for (List<Invoice> invoiceList;
!(invoiceList = query.fetch(FETCH_LIMIT)).isEmpty();
JPA.clear()) {
if (!JPA.em().contains(companyBankDetails)) {
companyBankDetails = bankDetailsRepo.find(companyBankDetails.getId());
}
for (Invoice invoice : invoiceList) {
try {
doneList.add(
invoicePaymentCreateService.createInvoicePayment(invoice, companyBankDetails));
incrementDone();
} catch (Exception ex) {
incrementAnomaly();
anomalyList.add(invoice.getId());
query.bind("anomalyList", anomalyList);
TraceBackService.trace(ex, ExceptionOriginRepository.CREDIT_TRANSFER, batch.getId());
ex.printStackTrace();
log.error(
String.format(
"Credit transfer batch for invoices: anomaly for invoice %s",
invoice.getInvoiceId()));
break;
}
}
}
return doneList;
}
@Override
protected void stop() {
StringBuilder sb = new StringBuilder();
sb.append(I18n.get(IExceptionMessage.BATCH_CREDIT_TRANSFER_REPORT_TITLE)).append(" ");
sb.append(
String.format(
I18n.get(
IExceptionMessage.BATCH_CREDIT_TRANSFER_INVOICE_DONE_SINGULAR,
IExceptionMessage.BATCH_CREDIT_TRANSFER_INVOICE_DONE_PLURAL,
batch.getDone())
+ " ",
batch.getDone()));
sb.append(
String.format(
I18n.get(
com.axelor.apps.base.exceptions.IExceptionMessage.ABSTRACT_BATCH_ANOMALY_SINGULAR,
com.axelor.apps.base.exceptions.IExceptionMessage.ABSTRACT_BATCH_ANOMALY_PLURAL,
batch.getAnomaly()),
batch.getAnomaly()));
addComment(sb.toString());
super.stop();
}
}

View File

@ -0,0 +1,147 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.batch;
import com.axelor.apps.account.db.AccountingBatch;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.Reimbursement;
import com.axelor.apps.account.db.repo.MoveLineRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.ReimbursementExportService;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.repo.PartnerRepository;
import com.axelor.apps.base.service.PartnerService;
import com.axelor.db.JPA;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.ExceptionOriginRepository;
import com.axelor.exception.service.TraceBackService;
import com.axelor.i18n.I18n;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.util.List;
import javax.persistence.TypedQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BatchCreditTransferPartnerReimbursement extends BatchStrategy {
protected final Logger log = LoggerFactory.getLogger(getClass());
protected PartnerRepository partnerRepo;
protected PartnerService partnerService;
protected ReimbursementExportService reimbursementExportService;
@Inject
public BatchCreditTransferPartnerReimbursement(
PartnerRepository partnerRepo,
PartnerService partnerService,
ReimbursementExportService reimbursementExportService) {
this.partnerRepo = partnerRepo;
this.partnerService = partnerService;
this.reimbursementExportService = reimbursementExportService;
}
@Override
protected void process() {
AccountingBatch accountingBatch = batch.getAccountingBatch();
// Fetch all partners that have a credit balance for the specified company.
TypedQuery<Partner> partnerQuery =
JPA.em()
.createQuery(
"SELECT self FROM Partner self JOIN self.accountingSituationList accountingSituation "
+ "WHERE accountingSituation.company = :company AND accountingSituation.balanceCustAccount < 0",
Partner.class);
partnerQuery.setParameter("company", accountingBatch.getCompany());
List<Partner> partnerList = partnerQuery.getResultList();
for (Partner partner : partnerList) {
try {
partner = partnerRepo.find(partner.getId());
Reimbursement reimbursement = createReimbursement(partner, accountingBatch.getCompany());
if (reimbursement != null) {
incrementDone();
}
} catch (Exception ex) {
incrementAnomaly();
TraceBackService.trace(ex, ExceptionOriginRepository.CREDIT_TRANSFER, batch.getId());
ex.printStackTrace();
log.error(
String.format(
"Credit transfer batch for partner credit balance reimbursement: anomaly for partner %s",
partner.getName()));
}
JPA.clear();
}
}
@Override
protected void stop() {
StringBuilder sb = new StringBuilder();
sb.append(I18n.get(IExceptionMessage.BATCH_CREDIT_TRANSFER_REPORT_TITLE)).append(" ");
sb.append(
String.format(
I18n.get(
IExceptionMessage.BATCH_CREDIT_TRANSFER_REIMBURSEMENT_DONE_SINGULAR,
IExceptionMessage.BATCH_CREDIT_TRANSFER_REIMBURSEMENT_DONE_PLURAL,
batch.getDone())
+ " ",
batch.getDone()));
sb.append(
String.format(
I18n.get(
com.axelor.apps.base.exceptions.IExceptionMessage.ABSTRACT_BATCH_ANOMALY_SINGULAR,
com.axelor.apps.base.exceptions.IExceptionMessage.ABSTRACT_BATCH_ANOMALY_PLURAL,
batch.getAnomaly()),
batch.getAnomaly()));
addComment(sb.toString());
super.stop();
}
/**
* Create a reimbursement for the specified partner and from the specified company.
*
* @param partner
* @param company
* @return
* @throws AxelorException
*/
@Transactional(rollbackOn = {Exception.class})
protected Reimbursement createReimbursement(Partner partner, Company company)
throws AxelorException {
List<MoveLine> moveLineList =
moveLineRepo
.all()
.filter(
"self.account.reconcileOk = true AND (self.move.statusSelect = ?1 OR self.move.statusSelect = ?2) "
+ "AND self.amountRemaining > 0 AND self.credit > 0 "
+ "AND self.move.partner = ?3 AND self.move.company = ?4 "
+ "AND self.reimbursementStatusSelect = ?5",
MoveRepository.STATUS_VALIDATED,
MoveRepository.STATUS_DAYBOOK,
partner,
company,
MoveLineRepository.REIMBURSEMENT_STATUS_NULL)
.fetch();
Reimbursement reimbursement =
reimbursementExportService.runCreateReimbursement(moveLineList, company, partner);
return reimbursement;
}
}

View File

@ -0,0 +1,41 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.batch;
import com.axelor.apps.account.db.repo.InvoicePaymentRepository;
import com.axelor.apps.account.db.repo.InvoiceRepository;
import com.axelor.apps.account.service.app.AppAccountService;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCreateService;
import com.google.inject.Inject;
public class BatchCreditTransferSupplierPayment extends BatchCreditTransferInvoice {
@Inject
public BatchCreditTransferSupplierPayment(
AppAccountService appAccountService,
InvoiceRepository invoiceRepo,
InvoicePaymentCreateService invoicePaymentCreateService,
InvoicePaymentRepository invoicePaymentRepository) {
super(appAccountService, invoiceRepo, invoicePaymentCreateService, invoicePaymentRepository);
}
@Override
protected void process() {
processInvoices(InvoiceRepository.OPERATION_TYPE_SUPPLIER_PURCHASE);
}
}

View File

@ -0,0 +1,201 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.batch;
import com.axelor.apps.account.db.DebtRecovery;
import com.axelor.apps.account.db.repo.DebtRecoveryRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.debtrecovery.DebtRecoveryActionService;
import com.axelor.apps.account.service.debtrecovery.DebtRecoveryService;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.repo.BlockingRepository;
import com.axelor.apps.base.db.repo.PartnerRepository;
import com.axelor.apps.base.service.BlockingService;
import com.axelor.apps.message.db.repo.MessageRepository;
import com.axelor.db.EntityHelper;
import com.axelor.db.JPA;
import com.axelor.db.Model;
import com.axelor.db.Query;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.ExceptionOriginRepository;
import com.axelor.exception.service.TraceBackService;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import java.util.List;
import javax.persistence.Table;
public class BatchDebtRecovery extends BatchStrategy {
protected boolean stopping = false;
protected PartnerRepository partnerRepository;
protected MessageRepository messageRepository;
protected DebtRecoveryRepository debtRecoveryRepository;
protected DebtRecoveryActionService debtRecoveryActionService;
@Inject
public BatchDebtRecovery(
DebtRecoveryService debtRecoveryService,
PartnerRepository partnerRepository,
DebtRecoveryRepository debtRecoveryRepository,
DebtRecoveryActionService debtRecoveryActionService,
MessageRepository messageRepository) {
super(debtRecoveryService);
this.partnerRepository = partnerRepository;
this.debtRecoveryRepository = debtRecoveryRepository;
this.debtRecoveryActionService = debtRecoveryActionService;
this.messageRepository = messageRepository;
}
@Override
protected void start() throws IllegalAccessException {
super.start();
Company company = batch.getAccountingBatch().getCompany();
try {
debtRecoveryService.testCompanyField(company);
} catch (AxelorException e) {
TraceBackService.trace(
new AxelorException(e, e.getCategory(), ""),
ExceptionOriginRepository.DEBT_RECOVERY,
batch.getId());
incrementAnomaly();
stopping = true;
}
checkPoint();
}
@Override
protected void process() {
if (!stopping) {
this.debtRecoveryPartner();
}
}
public void debtRecoveryPartner() {
Company company = batch.getAccountingBatch().getCompany();
Query<Partner> query =
partnerRepository
.all()
.filter(
"self.isContact = false "
+ "AND :_company MEMBER OF self.companySet "
+ "AND self.accountingSituationList IS NOT EMPTY "
+ "AND self.isCustomer = true "
+ "AND self.id NOT IN ("
+ Beans.get(BlockingService.class)
.listOfBlockedPartner(company, BlockingRepository.REMINDER_BLOCKING)
+ ")")
.bind("_company", company)
.order("id");
int offset = 0;
List<Partner> partnerList;
while (!(partnerList = query.fetch(FETCH_LIMIT, offset)).isEmpty()) {
findBatch();
for (Partner partner : partnerList) {
++offset;
try {
boolean remindedOk = debtRecoveryService.debtRecoveryGenerate(partner, company);
if (remindedOk) {
DebtRecovery debtRecovery = debtRecoveryService.getDebtRecovery(partner, company);
addBatchToModel(debtRecovery);
incrementDone(partner);
}
} catch (AxelorException e) {
TraceBackService.trace(
new AxelorException(
e, e.getCategory(), I18n.get("Partner") + " %s", partner.getName()),
ExceptionOriginRepository.DEBT_RECOVERY,
batch.getId());
incrementAnomaly(partner);
break;
} catch (Exception e) {
TraceBackService.trace(
new Exception(String.format(I18n.get("Partner") + " %s", partner.getName()), e),
ExceptionOriginRepository.DEBT_RECOVERY,
batch.getId());
incrementAnomaly(partner);
break;
}
}
JPA.clear();
}
}
protected void incrementDone(Partner partner) {
addBatchToModel(partner);
_incrementDone();
}
protected void incrementAnomaly(Partner partner) {
findBatch();
partner = partnerRepository.find(partner.getId());
// addBatchToModel(partner);
_incrementAnomaly();
}
protected void addBatchToModel(Model model) {
String tableName = getBatchSetTableName(model);
// Insert using native query for performance reasons in case of big batch set.
String sqlString = String.format("INSERT INTO %s VALUES (:modelId, :batchId)", tableName);
javax.persistence.Query query = JPA.em().createNativeQuery(sqlString);
query.setParameter("modelId", model.getId());
query.setParameter("batchId", batch.getId());
JPA.runInTransaction(query::executeUpdate);
}
private String getBatchSetTableName(Model model) {
String modelTableName = EntityHelper.getEntityClass(model).getAnnotation(Table.class).name();
return modelTableName + "_BATCH_SET";
}
/**
* As {@code batch} entity can be detached from the session, call {@code Batch.find()} get the
* entity in the persistant context. Warning : {@code batch} entity have to be saved before.
*/
@Override
protected void stop() {
String comment = I18n.get(IExceptionMessage.BATCH_DEBT_RECOVERY_1);
comment +=
String.format(
"\t* %s " + I18n.get(IExceptionMessage.BATCH_DEBT_RECOVERY_2) + "\n", batch.getDone());
comment +=
String.format(
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.ALARM_ENGINE_BATCH_4),
batch.getAnomaly());
super.stop();
addComment(comment);
}
}

View File

@ -0,0 +1,277 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.batch;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.repo.AccountRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.AccountingService;
import com.axelor.apps.account.service.debtrecovery.DoubtfulCustomerService;
import com.axelor.apps.base.db.Company;
import com.axelor.db.JPA;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.ExceptionOriginRepository;
import com.axelor.exception.service.TraceBackService;
import com.axelor.i18n.I18n;
import com.google.inject.Inject;
import java.lang.invoke.MethodHandles;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BatchDoubtfulCustomer extends BatchStrategy {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected boolean stop = false;
protected String updateCustomerAccountLog = "";
protected AccountRepository accountRepo;
@Inject
public BatchDoubtfulCustomer(
DoubtfulCustomerService doubtfulCustomerService,
BatchAccountCustomer batchAccountCustomer,
AccountRepository accountRepo) {
super(doubtfulCustomerService, batchAccountCustomer);
this.accountRepo = accountRepo;
AccountingService.setUpdateCustomerAccount(false);
}
@Override
protected void start() throws IllegalAccessException {
super.start();
Company company = batch.getAccountingBatch().getCompany();
try {
doubtfulCustomerService.testCompanyField(company);
} catch (AxelorException e) {
TraceBackService.trace(
new AxelorException(e, e.getCategory(), ""),
ExceptionOriginRepository.DOUBTFUL_CUSTOMER,
batch.getId());
incrementAnomaly();
stop = true;
}
checkPoint();
}
@SuppressWarnings("unchecked")
@Override
protected void process() {
if (!stop) {
Company company = batch.getAccountingBatch().getCompany();
AccountConfig accountConfig = company.getAccountConfig();
Account doubtfulCustomerAccount = accountConfig.getDoubtfulCustomerAccount();
String sixMonthDebtPassReason = accountConfig.getSixMonthDebtPassReason();
String threeMonthDebtPassReason = accountConfig.getThreeMonthDebtPassReason();
// FACTURES
List<Move> moveList = doubtfulCustomerService.getMove(0, doubtfulCustomerAccount, company);
log.debug(
"Nombre d'écritures de facture concernées (Créance de + 6 mois) au 411 : {} ",
moveList.size());
this.createDoubtFulCustomerMove(moveList, doubtfulCustomerAccount, sixMonthDebtPassReason);
moveList = doubtfulCustomerService.getMove(1, doubtfulCustomerAccount, company);
log.debug(
"Nombre d'écritures de facture concernées (Créance de + 3 mois) au 411 : {} ",
moveList.size());
this.createDoubtFulCustomerMove(moveList, doubtfulCustomerAccount, threeMonthDebtPassReason);
// FACTURES REJETES
List<MoveLine> moveLineList =
(List<MoveLine>)
doubtfulCustomerService.getRejectMoveLine(0, doubtfulCustomerAccount, company);
log.debug(
"Nombre de lignes d'écriture de rejet concernées (Créance de + 6 mois) au 411 : {} ",
moveLineList.size());
this.createDoubtFulCustomerRejectMove(
moveLineList, doubtfulCustomerAccount, sixMonthDebtPassReason);
moveLineList =
(List<MoveLine>)
doubtfulCustomerService.getRejectMoveLine(1, doubtfulCustomerAccount, company);
log.debug(
"Nombre de lignes d'écriture de rejet concernées (Créance de + 3 mois) au 411 : {} ",
moveLineList.size());
this.createDoubtFulCustomerRejectMove(
moveLineList, doubtfulCustomerAccount, threeMonthDebtPassReason);
updateCustomerAccountLog +=
batchAccountCustomer.updateAccountingSituationMarked(companyRepo.find(company.getId()));
}
}
/**
* Procédure permettant de créer les écritures de passage en client douteux pour chaque écriture
* de facture
*
* @param moveLineList Une liste d'écritures de facture
* @param doubtfulCustomerAccount Un compte client douteux
* @param debtPassReason Un motif de passage en client douteux
* @throws AxelorException
*/
public void createDoubtFulCustomerMove(
List<Move> moveList, Account doubtfulCustomerAccount, String debtPassReason) {
int i = 0;
for (Move move : moveList) {
try {
doubtfulCustomerService.createDoubtFulCustomerMove(
moveRepo.find(move.getId()),
accountRepo.find(doubtfulCustomerAccount.getId()),
debtPassReason);
updateInvoice(moveRepo.find(move.getId()).getInvoice());
} catch (AxelorException e) {
TraceBackService.trace(
new AxelorException(
e, e.getCategory(), I18n.get("Invoice") + " %s", move.getInvoice().getInvoiceId()),
ExceptionOriginRepository.DOUBTFUL_CUSTOMER,
batch.getId());
incrementAnomaly();
} catch (Exception e) {
TraceBackService.trace(
new Exception(
String.format(I18n.get("Invoice") + " %s", move.getInvoice().getInvoiceId()), e),
ExceptionOriginRepository.DOUBTFUL_CUSTOMER,
batch.getId());
incrementAnomaly();
log.error(
"Bug(Anomalie) généré(e) pour la facture {}",
moveRepo.find(move.getId()).getInvoice().getInvoiceId());
} finally {
if (i % 10 == 0) {
JPA.clear();
}
}
}
}
/**
* Procédure permettant de créer les écritures de passage en client douteux pour chaque ligne
* d'écriture de rejet de facture
*
* @param moveLineList Une liste de lignes d'écritures de rejet de facture
* @param doubtfulCustomerAccount Un compte client douteux
* @param debtPassReason Un motif de passage en client douteux
* @throws AxelorException
*/
public void createDoubtFulCustomerRejectMove(
List<MoveLine> moveLineList, Account doubtfulCustomerAccount, String debtPassReason) {
int i = 0;
for (MoveLine moveLine : moveLineList) {
try {
doubtfulCustomerService.createDoubtFulCustomerRejectMove(
moveLineRepo.find(moveLine.getId()),
accountRepo.find(doubtfulCustomerAccount.getId()),
debtPassReason);
updateInvoice(moveLineRepo.find(moveLine.getId()).getInvoiceReject());
i++;
} catch (AxelorException e) {
TraceBackService.trace(
new AxelorException(
e,
e.getCategory(),
I18n.get("Invoice") + " %s",
moveLine.getInvoiceReject().getInvoiceId()),
ExceptionOriginRepository.DOUBTFUL_CUSTOMER,
batch.getId());
incrementAnomaly();
} catch (Exception e) {
TraceBackService.trace(
new Exception(
String.format(
I18n.get("Invoice") + " %s", moveLine.getInvoiceReject().getInvoiceId()),
e),
ExceptionOriginRepository.DOUBTFUL_CUSTOMER,
batch.getId());
incrementAnomaly();
log.error(
"Bug(Anomalie) généré(e) pour la facture {}",
moveLineRepo.find(moveLine.getId()).getInvoiceReject().getInvoiceId());
} finally {
if (i % 10 == 0) {
JPA.clear();
}
}
}
}
/**
* As {@code batch} entity can be detached from the session, call {@code Batch.find()} get the
* entity in the persistant context. Warning : {@code batch} entity have to be saved before.
*/
@Override
protected void stop() {
AccountingService.setUpdateCustomerAccount(true);
String comment = I18n.get(IExceptionMessage.BATCH_DOUBTFUL_1) + " :\n";
comment +=
String.format("\t" + I18n.get(IExceptionMessage.BATCH_DOUBTFUL_2) + "\n", batch.getDone());
comment +=
String.format(
"\t" + I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.ALARM_ENGINE_BATCH_4),
batch.getAnomaly());
comment += String.format("\t* ------------------------------- \n");
comment += String.format("\t* %s ", updateCustomerAccountLog);
super.stop();
addComment(comment);
}
}

View File

@ -0,0 +1,184 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.batch;
import com.axelor.apps.account.db.AccountingBatch;
import com.axelor.apps.account.db.AccountingReport;
import com.axelor.apps.account.db.repo.AccountingReportRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.MoveLineExportService;
import com.axelor.apps.base.db.Company;
import com.axelor.db.JPA;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.ExceptionOriginRepository;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.exception.service.TraceBackService;
import com.axelor.i18n.I18n;
import com.google.inject.Inject;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.time.LocalDate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BatchMoveLineExport extends BatchStrategy {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected boolean stop = false;
protected long moveLineDone = 0;
protected long moveDone = 0;
protected BigDecimal debit = BigDecimal.ZERO;
protected BigDecimal credit = BigDecimal.ZERO;
protected BigDecimal balance = BigDecimal.ZERO;
protected AccountingReportRepository accountingReportRepository;
@Inject
public BatchMoveLineExport(
MoveLineExportService moveLineExportService,
AccountingReportRepository accountingReportRepository) {
super(moveLineExportService);
this.accountingReportRepository = accountingReportRepository;
}
@Override
protected void start() throws IllegalAccessException {
super.start();
try {
this.testAccountingBatchField();
} catch (AxelorException e) {
TraceBackService.trace(
new AxelorException(e, e.getCategory(), ""),
ExceptionOriginRepository.MOVE_LINE_EXPORT_ORIGIN,
batch.getId());
incrementAnomaly();
stop = true;
}
checkPoint();
}
@Override
protected void process() {
if (!stop) {
try {
Company company = batch.getAccountingBatch().getCompany();
LocalDate startDate = batch.getAccountingBatch().getStartDate();
LocalDate endDate = batch.getAccountingBatch().getEndDate();
int exportTypeSelect = batch.getAccountingBatch().getMoveLineExportTypeSelect();
AccountingReport accountingReport =
moveLineExportService.createAccountingReport(
company, exportTypeSelect, startDate, endDate);
moveLineExportService.exportMoveLine(accountingReport);
JPA.clear();
accountingReport = accountingReportRepository.find(accountingReport.getId());
moveLineDone =
moveLineRepo.all().filter("self.move.accountingReport = ?1", accountingReport).count();
moveDone = moveRepo.all().filter("self.accountingReport = ?1", accountingReport).count();
debit = accountingReport.getTotalDebit();
credit = accountingReport.getTotalCredit();
balance = accountingReport.getBalance();
updateAccountingReport(accountingReport);
} catch (AxelorException e) {
TraceBackService.trace(
new AxelorException(e, e.getCategory(), String.format("%s", e)),
ExceptionOriginRepository.MOVE_LINE_EXPORT_ORIGIN,
batch.getId());
incrementAnomaly();
} catch (Exception e) {
TraceBackService.trace(
new Exception(String.format("%s", e), e),
ExceptionOriginRepository.MOVE_LINE_EXPORT_ORIGIN,
batch.getId());
incrementAnomaly();
log.error("Bug(Anomalie) généré(e) pour le batch {}", batch.getId());
}
}
}
public void testAccountingBatchField() throws AxelorException {
AccountingBatch accountingBatch = batch.getAccountingBatch();
if (accountingBatch.getCompany() == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.BATCH_MOVELINE_EXPORT_1),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
accountingBatch.getCode());
}
if (accountingBatch.getEndDate() == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.BATCH_MOVELINE_EXPORT_2),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
accountingBatch.getCode());
}
if (accountingBatch.getMoveLineExportTypeSelect() == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.BATCH_MOVELINE_EXPORT_3),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
accountingBatch.getCode());
}
}
/**
* As {@code batch} entity can be detached from the session, call {@code Batch.find()} get the
* entity in the persistant context. Warning : {@code batch} entity have to be saved before.
*/
@Override
protected void stop() {
String comment = I18n.get(IExceptionMessage.BATCH_MOVELINE_EXPORT_4) + "\n";
comment +=
String.format(
"\t* %s (%s)" + I18n.get(IExceptionMessage.BATCH_MOVELINE_EXPORT_5) + "\n",
moveLineDone,
moveDone);
comment += String.format("\t* " + I18n.get("Debit") + " : %s\n", debit);
comment += String.format("\t* " + I18n.get("Credit") + " : %s\n", credit);
comment += String.format("\t* " + I18n.get("Balance") + " : %s\n", balance);
comment +=
String.format(
"\t" + I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.ALARM_ENGINE_BATCH_4),
batch.getAnomaly());
super.stop();
addComment(comment);
}
}

View File

@ -0,0 +1,85 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 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.batch;
import com.axelor.apps.account.db.FixedAssetLine;
import com.axelor.apps.account.db.repo.FixedAssetLineRepository;
import com.axelor.apps.account.db.repo.FixedAssetRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.FixedAssetLineService;
import com.axelor.apps.base.service.administration.AbstractBatch;
import com.axelor.db.JPA;
import com.axelor.exception.service.TraceBackService;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import java.time.LocalDate;
import java.util.List;
public class BatchRealizeFixedAssetLine extends AbstractBatch {
private FixedAssetLineService fixedAssetLineService;
@Inject FixedAssetLineRepository fixedAssetLineRepo;
@Inject
public BatchRealizeFixedAssetLine(FixedAssetLineService fixedAssetLineService) {
this.fixedAssetLineService = fixedAssetLineService;
}
@Override
protected void process() {
List<FixedAssetLine> fixedAssetLineList =
Beans.get(FixedAssetLineRepository.class)
.all()
.filter(
"self.statusSelect = ?1 and self.depreciationDate < ?2",
FixedAssetLineRepository.STATUS_PLANNED,
LocalDate.now())
.fetch();
for (FixedAssetLine fixedAssetLine : fixedAssetLineList) {
try {
fixedAssetLine = fixedAssetLineRepo.find(fixedAssetLine.getId());
if (fixedAssetLine.getFixedAsset().getStatusSelect() > FixedAssetRepository.STATUS_DRAFT) {
fixedAssetLineService.realize(fixedAssetLine);
incrementDone();
}
} catch (Exception e) {
incrementAnomaly();
TraceBackService.trace(e);
}
JPA.clear();
}
}
@Override
protected void stop() {
String comment =
String.format(
"\t* %s " + I18n.get(IExceptionMessage.BATCH_REALIZED_FIXED_ASSET_LINE) + "\n",
batch.getDone());
comment +=
String.format(
"\t" + I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.ALARM_ENGINE_BATCH_4),
batch.getAnomaly());
addComment(comment);
super.stop();
}
}

Some files were not shown because too many files have changed in this diff Show More