diff --git a/axelor-budget/src/main/java/com/axelor/apps/budget/service/invoice/WorkflowVentilationBudgetServiceImpl.java b/axelor-budget/src/main/java/com/axelor/apps/budget/service/invoice/WorkflowVentilationBudgetServiceImpl.java index b3d02c893d2..c71adf63add 100644 --- a/axelor-budget/src/main/java/com/axelor/apps/budget/service/invoice/WorkflowVentilationBudgetServiceImpl.java +++ b/axelor-budget/src/main/java/com/axelor/apps/budget/service/invoice/WorkflowVentilationBudgetServiceImpl.java @@ -33,6 +33,7 @@ import com.axelor.apps.budget.service.AppBudgetService; import com.axelor.apps.businessproject.db.repo.InvoicingProjectRepository; import com.axelor.apps.businessproject.service.WorkflowVentilationProjectServiceImpl; +import com.axelor.apps.contract.service.ContractVersionService; import com.axelor.apps.hr.db.repo.TimesheetLineRepository; import com.axelor.apps.purchase.db.repo.PurchaseOrderRepository; import com.axelor.apps.sale.db.repo.SaleOrderRepository; @@ -75,7 +76,8 @@ public WorkflowVentilationBudgetServiceImpl( InvoiceFinancialDiscountService invoiceFinancialDiscountService, InvoiceTermService invoiceTermService, AppBudgetService appBudgetService, - BudgetInvoiceService budgetInvoiceService) { + BudgetInvoiceService budgetInvoiceService, + ContractVersionService contractVersionService) { super( accountConfigService, invoicePaymentRepo, @@ -96,7 +98,8 @@ public WorkflowVentilationBudgetServiceImpl( stockMoveLineRepository, appAccountService, invoiceFinancialDiscountService, - invoiceTermService); + invoiceTermService, + contractVersionService); this.appBudgetService = appBudgetService; this.budgetInvoiceService = budgetInvoiceService; } diff --git a/axelor-business-project/src/main/java/com/axelor/apps/businessproject/module/BusinessProjectModule.java b/axelor-business-project/src/main/java/com/axelor/apps/businessproject/module/BusinessProjectModule.java index 0a8fb0f8820..9d345d3f4e0 100644 --- a/axelor-business-project/src/main/java/com/axelor/apps/businessproject/module/BusinessProjectModule.java +++ b/axelor-business-project/src/main/java/com/axelor/apps/businessproject/module/BusinessProjectModule.java @@ -117,6 +117,7 @@ import com.axelor.apps.contract.service.ContractInvoicingServiceImpl; import com.axelor.apps.contract.service.ContractLineServiceImpl; import com.axelor.apps.contract.service.WorkflowCancelServiceContractImpl; +import com.axelor.apps.contract.service.WorkflowVentilationContractServiceImpl; import com.axelor.apps.hr.db.repo.ProjectTaskHRRepository; import com.axelor.apps.hr.event.ICalendarEventObserver; import com.axelor.apps.hr.service.expense.ExpenseInvoiceLineServiceImpl; @@ -146,7 +147,6 @@ import com.axelor.apps.supplychain.service.saleorder.SaleOrderInvoiceServiceImpl; import com.axelor.apps.supplychain.service.saleorder.SaleOrderPurchaseServiceImpl; import com.axelor.apps.supplychain.service.saleorderline.SaleOrderLineInitValueSupplychainServiceImpl; -import com.axelor.apps.supplychain.service.workflow.WorkflowVentilationServiceSupplychainImpl; import com.axelor.studio.db.repo.AppBusinessProjectRepository; public class BusinessProjectModule extends AxelorModule { @@ -177,7 +177,7 @@ protected void configure() { bind(ExpenseLineProjectService.class).to(ExpenseLineProjectServiceImpl.class); bind(InvoiceLineProjectService.class).to(InvoiceLineProjectServiceImpl.class); bind(InvoiceSupplychainRepository.class).to(InvoiceProjectRepository.class); - bind(WorkflowVentilationServiceSupplychainImpl.class) + bind(WorkflowVentilationContractServiceImpl.class) .to(WorkflowVentilationProjectServiceImpl.class); bind(TimesheetLineBusinessService.class).to(TimesheetLineProjectServiceImpl.class); bind(WorkflowValidationServiceImpl.class).to(WorkflowValidationServiceProjectImpl.class); diff --git a/axelor-business-project/src/main/java/com/axelor/apps/businessproject/service/WorkflowVentilationProjectServiceImpl.java b/axelor-business-project/src/main/java/com/axelor/apps/businessproject/service/WorkflowVentilationProjectServiceImpl.java index d1d63597c2d..1ca84426d87 100644 --- a/axelor-business-project/src/main/java/com/axelor/apps/businessproject/service/WorkflowVentilationProjectServiceImpl.java +++ b/axelor-business-project/src/main/java/com/axelor/apps/businessproject/service/WorkflowVentilationProjectServiceImpl.java @@ -33,6 +33,8 @@ import com.axelor.apps.businessproject.db.InvoicingProject; import com.axelor.apps.businessproject.db.repo.InvoicingProjectRepository; import com.axelor.apps.businessproject.service.app.AppBusinessProjectService; +import com.axelor.apps.contract.service.ContractVersionService; +import com.axelor.apps.contract.service.WorkflowVentilationContractServiceImpl; import com.axelor.apps.hr.db.ExpenseLine; import com.axelor.apps.hr.db.TimesheetLine; import com.axelor.apps.hr.db.repo.TimesheetLineRepository; @@ -49,15 +51,13 @@ import com.axelor.apps.supplychain.service.app.AppSupplychainService; import com.axelor.apps.supplychain.service.config.SupplyChainConfigService; import com.axelor.apps.supplychain.service.saleorder.SaleOrderInvoiceService; -import com.axelor.apps.supplychain.service.workflow.WorkflowVentilationServiceSupplychainImpl; import com.axelor.inject.Beans; import com.google.inject.Inject; import com.google.inject.persist.Transactional; import java.math.BigDecimal; import java.util.Objects; -public class WorkflowVentilationProjectServiceImpl - extends WorkflowVentilationServiceSupplychainImpl { +public class WorkflowVentilationProjectServiceImpl extends WorkflowVentilationContractServiceImpl { protected InvoicingProjectRepository invoicingProjectRepo; @@ -84,7 +84,8 @@ public WorkflowVentilationProjectServiceImpl( StockMoveLineRepository stockMoveLineRepository, AppAccountService appAccountService, InvoiceFinancialDiscountService invoiceFinancialDiscountService, - InvoiceTermService invoiceTermService) { + InvoiceTermService invoiceTermService, + ContractVersionService contractVersionService) { super( accountConfigService, invoicePaymentRepo, @@ -103,7 +104,8 @@ public WorkflowVentilationProjectServiceImpl( stockMoveLineRepository, appAccountService, invoiceFinancialDiscountService, - invoiceTermService); + invoiceTermService, + contractVersionService); this.invoicingProjectRepo = invoicingProjectRepo; this.timesheetLineRepo = timesheetLineRepo; } diff --git a/axelor-contract/src/main/java/com/axelor/apps/contract/module/ContractModule.java b/axelor-contract/src/main/java/com/axelor/apps/contract/module/ContractModule.java index fffd7b921b7..212b2dc92d6 100644 --- a/axelor-contract/src/main/java/com/axelor/apps/contract/module/ContractModule.java +++ b/axelor-contract/src/main/java/com/axelor/apps/contract/module/ContractModule.java @@ -62,7 +62,9 @@ import com.axelor.apps.contract.service.InvoiceLineAnalyticContractServiceImpl; import com.axelor.apps.contract.service.InvoiceLinePricingService; import com.axelor.apps.contract.service.InvoiceLinePricingServiceImpl; +import com.axelor.apps.contract.service.InvoicePaymentToolServiceContractImpl; import com.axelor.apps.contract.service.WorkflowCancelServiceContractImpl; +import com.axelor.apps.contract.service.WorkflowVentilationContractServiceImpl; import com.axelor.apps.contract.service.attributes.ContractLineAttrsService; import com.axelor.apps.contract.service.attributes.ContractLineAttrsServiceImpl; import com.axelor.apps.contract.service.pricing.ContractPricingService; @@ -72,8 +74,10 @@ import com.axelor.apps.contract.service.record.ContractLineRecordSetServiceImpl; import com.axelor.apps.sale.service.PricingGroupSaleServiceImpl; import com.axelor.apps.supplychain.service.AnalyticMoveLineSupplychainServiceImpl; +import com.axelor.apps.supplychain.service.InvoicePaymentToolServiceSupplychainImpl; import com.axelor.apps.supplychain.service.invoice.InvoiceLineAnalyticSupplychainServiceImpl; import com.axelor.apps.supplychain.service.workflow.WorkflowCancelServiceSupplychainImpl; +import com.axelor.apps.supplychain.service.workflow.WorkflowVentilationServiceSupplychainImpl; public class ContractModule extends AxelorModule { @@ -110,5 +114,9 @@ protected void configure() { bind(AccountManagementContractService.class).to(AccountManagementContractServiceImpl.class); bind(ContractLineContextToolService.class).to(ContractLineContextToolServiceImpl.class); bind(ContractInvoicingService.class).to(ContractInvoicingServiceImpl.class); + bind(WorkflowVentilationServiceSupplychainImpl.class) + .to(WorkflowVentilationContractServiceImpl.class); + bind(InvoicePaymentToolServiceSupplychainImpl.class) + .to(InvoicePaymentToolServiceContractImpl.class); } } diff --git a/axelor-contract/src/main/java/com/axelor/apps/contract/service/ContractVersionService.java b/axelor-contract/src/main/java/com/axelor/apps/contract/service/ContractVersionService.java index 79f75efe9af..29e1bdeddaa 100644 --- a/axelor-contract/src/main/java/com/axelor/apps/contract/service/ContractVersionService.java +++ b/axelor-contract/src/main/java/com/axelor/apps/contract/service/ContractVersionService.java @@ -18,6 +18,7 @@ */ package com.axelor.apps.contract.service; +import com.axelor.apps.account.db.Invoice; import com.axelor.apps.base.AxelorException; import com.axelor.apps.contract.db.Contract; import com.axelor.apps.contract.db.ContractVersion; @@ -97,4 +98,10 @@ default ContractVersion getContractVersion(Contract contract, LocalDate date) { } return contract.getCurrentContractVersion(); } + + ContractVersion getContractVersion(Invoice invoice); + + void computeTotalInvoicedAmount(ContractVersion contractVersion); + + void computeTotalPaidAmount(ContractVersion contractVersion); } diff --git a/axelor-contract/src/main/java/com/axelor/apps/contract/service/ContractVersionServiceImpl.java b/axelor-contract/src/main/java/com/axelor/apps/contract/service/ContractVersionServiceImpl.java index 25ec7dfd641..cae02d4f213 100644 --- a/axelor-contract/src/main/java/com/axelor/apps/contract/service/ContractVersionServiceImpl.java +++ b/axelor-contract/src/main/java/com/axelor/apps/contract/service/ContractVersionServiceImpl.java @@ -46,6 +46,7 @@ import java.util.Objects; import java.util.Optional; import java.util.stream.Stream; +import org.apache.commons.collections.CollectionUtils; public class ContractVersionServiceImpl implements ContractVersionService { @@ -218,26 +219,48 @@ public void computeTotals(ContractVersion contractVersion) { } contractVersion.setInitialExTaxTotalPerYear(initialExTaxTotalPerYear); contractVersion.setYearlyExTaxTotalRevalued(yearlyExTaxTotalRevalued); + computeTotalInvoicedAmount(contractVersion); + computeTotalPaidAmount(contractVersion); + } + + @Override + public ContractVersion getContractVersion(Invoice invoice) { + List invoiceLineList = invoice.getInvoiceLineList(); + if (CollectionUtils.isEmpty(invoiceLineList)) { + return null; + } + return invoiceLineList.stream() + .filter(invoiceLine -> invoiceLine.getContractLine() != null) + .map(InvoiceLine::getContractLine) + .map(ContractLine::getContractVersion) + .findFirst() + .orElse(null); + } + @Override + public void computeTotalInvoicedAmount(ContractVersion contractVersion) { List invoiceLineList = invoiceLineRepository .all() .filter("self.contractLine.contractVersion = :contractVersion") .bind("contractVersion", contractVersion) .fetch(); + if (CollectionUtils.isEmpty(invoiceLineList)) { + return; + } contractVersion.setTotalInvoicedAmount( invoiceLineList.stream() .filter( - invoiceLine -> { - if (invoiceLine != null && invoiceLine.getInvoice() != null) { - return invoiceLine.getInvoice().getStatusSelect() - == InvoiceRepository.STATUS_VENTILATED; - } - return false; - }) + invoiceLine -> + invoiceLine.getInvoice().getStatusSelect() + == InvoiceRepository.STATUS_VENTILATED) .map(InvoiceLine::getInTaxTotal) .reduce(BigDecimal::add) .orElse(BigDecimal.ZERO)); + } + + @Override + public void computeTotalPaidAmount(ContractVersion contractVersion) { List invoiceList = invoiceRepository .all() @@ -246,6 +269,9 @@ public void computeTotals(ContractVersion contractVersion) { .bind("contractVersion", contractVersion) .bind("ventilatedStatus", InvoiceRepository.STATUS_VENTILATED) .fetch(); + if (CollectionUtils.isEmpty(invoiceList)) { + return; + } contractVersion.setTotalPaidAmount( invoiceList.stream() .map(Invoice::getAmountPaid) diff --git a/axelor-contract/src/main/java/com/axelor/apps/contract/service/InvoicePaymentToolServiceContractImpl.java b/axelor-contract/src/main/java/com/axelor/apps/contract/service/InvoicePaymentToolServiceContractImpl.java new file mode 100644 index 00000000000..aa358df2653 --- /dev/null +++ b/axelor-contract/src/main/java/com/axelor/apps/contract/service/InvoicePaymentToolServiceContractImpl.java @@ -0,0 +1,100 @@ +/* + * Axelor Business Solutions + * + * Copyright (C) 2005-2025 Axelor (). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 . + */ +package com.axelor.apps.contract.service; + +import com.axelor.apps.account.db.Invoice; +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.invoice.InvoiceTermFilterService; +import com.axelor.apps.account.service.invoice.InvoiceTermToolService; +import com.axelor.apps.account.service.move.MoveToolService; +import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentFinancialDiscountService; +import com.axelor.apps.account.service.payment.invoice.payment.InvoiceTermPaymentService; +import com.axelor.apps.account.service.payment.invoice.payment.InvoiceTermPaymentToolService; +import com.axelor.apps.account.service.reconcile.foreignexchange.ForeignExchangeGapToolService; +import com.axelor.apps.base.AxelorException; +import com.axelor.apps.base.service.CurrencyScaleService; +import com.axelor.apps.base.service.CurrencyService; +import com.axelor.apps.base.service.app.AppBaseService; +import com.axelor.apps.contract.db.ContractVersion; +import com.axelor.apps.purchase.service.PurchaseOrderService; +import com.axelor.apps.sale.service.saleorder.SaleOrderComputeService; +import com.axelor.apps.supplychain.service.InvoicePaymentToolServiceSupplychainImpl; +import com.axelor.apps.supplychain.service.PartnerSupplychainService; +import com.google.inject.Inject; + +public class InvoicePaymentToolServiceContractImpl + extends InvoicePaymentToolServiceSupplychainImpl { + + protected AppBaseService appBaseService; + protected ContractVersionService contractVersionService; + + @Inject + public InvoicePaymentToolServiceContractImpl( + InvoiceRepository invoiceRepo, + MoveToolService moveToolService, + InvoicePaymentRepository invoicePaymentRepo, + InvoiceTermPaymentService invoiceTermPaymentService, + CurrencyService currencyService, + PartnerSupplychainService partnerSupplychainService, + SaleOrderComputeService saleOrderComputeService, + PurchaseOrderService purchaseOrderService, + AppAccountService appAccountService, + InvoicePaymentFinancialDiscountService invoicePaymentFinancialDiscountService, + CurrencyScaleService currencyScaleService, + InvoiceTermFilterService invoiceTermFilterService, + InvoiceTermToolService invoiceTermToolService, + InvoiceTermPaymentToolService invoiceTermPaymentToolService, + ForeignExchangeGapToolService foreignExchangeGapToolService, + AppBaseService appBaseService, + ContractVersionService contractVersionService) { + super( + invoiceRepo, + moveToolService, + invoicePaymentRepo, + invoiceTermPaymentService, + currencyService, + partnerSupplychainService, + saleOrderComputeService, + purchaseOrderService, + appAccountService, + invoicePaymentFinancialDiscountService, + currencyScaleService, + invoiceTermFilterService, + invoiceTermToolService, + invoiceTermPaymentToolService, + foreignExchangeGapToolService); + this.appBaseService = appBaseService; + this.contractVersionService = contractVersionService; + } + + @Override + public void updateAmountPaid(Invoice invoice) throws AxelorException { + super.updateAmountPaid(invoice); + if (!appBaseService.isApp("contract")) { + return; + } + ContractVersion contractVersion = contractVersionService.getContractVersion(invoice); + if (contractVersion == null) { + return; + } + contractVersionService.computeTotalPaidAmount(contractVersion); + } +} diff --git a/axelor-contract/src/main/java/com/axelor/apps/contract/service/WorkflowVentilationContractServiceImpl.java b/axelor-contract/src/main/java/com/axelor/apps/contract/service/WorkflowVentilationContractServiceImpl.java new file mode 100644 index 00000000000..13385d46f80 --- /dev/null +++ b/axelor-contract/src/main/java/com/axelor/apps/contract/service/WorkflowVentilationContractServiceImpl.java @@ -0,0 +1,105 @@ +/* + * Axelor Business Solutions + * + * Copyright (C) 2005-2025 Axelor (). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 . + */ +package com.axelor.apps.contract.service; + +import com.axelor.apps.account.db.Invoice; +import com.axelor.apps.account.db.repo.InvoicePaymentRepository; +import com.axelor.apps.account.service.app.AppAccountService; +import com.axelor.apps.account.service.config.AccountConfigService; +import com.axelor.apps.account.service.invoice.InvoiceFinancialDiscountService; +import com.axelor.apps.account.service.invoice.InvoiceService; +import com.axelor.apps.account.service.invoice.InvoiceTermService; +import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCreateService; +import com.axelor.apps.base.AxelorException; +import com.axelor.apps.base.service.UnitConversionService; +import com.axelor.apps.base.service.app.AppBaseService; +import com.axelor.apps.contract.db.ContractVersion; +import com.axelor.apps.purchase.db.repo.PurchaseOrderRepository; +import com.axelor.apps.sale.db.repo.SaleOrderRepository; +import com.axelor.apps.stock.db.repo.StockMoveLineRepository; +import com.axelor.apps.supplychain.service.AccountingSituationSupplychainService; +import com.axelor.apps.supplychain.service.PurchaseOrderInvoiceService; +import com.axelor.apps.supplychain.service.StockMoveInvoiceService; +import com.axelor.apps.supplychain.service.app.AppSupplychainService; +import com.axelor.apps.supplychain.service.config.SupplyChainConfigService; +import com.axelor.apps.supplychain.service.saleorder.SaleOrderInvoiceService; +import com.axelor.apps.supplychain.service.workflow.WorkflowVentilationServiceSupplychainImpl; +import com.google.inject.Inject; + +public class WorkflowVentilationContractServiceImpl + extends WorkflowVentilationServiceSupplychainImpl { + + protected ContractVersionService contractVersionService; + + @Inject + public WorkflowVentilationContractServiceImpl( + AccountConfigService accountConfigService, + InvoicePaymentRepository invoicePaymentRepo, + InvoicePaymentCreateService invoicePaymentCreateService, + InvoiceService invoiceService, + SaleOrderInvoiceService saleOrderInvoiceService, + PurchaseOrderInvoiceService purchaseOrderInvoiceService, + SaleOrderRepository saleOrderRepository, + PurchaseOrderRepository purchaseOrderRepository, + AccountingSituationSupplychainService accountingSituationSupplychainService, + AppSupplychainService appSupplychainService, + StockMoveInvoiceService stockMoveInvoiceService, + UnitConversionService unitConversionService, + AppBaseService appBaseService, + SupplyChainConfigService supplyChainConfigService, + StockMoveLineRepository stockMoveLineRepository, + AppAccountService appAccountService, + InvoiceFinancialDiscountService invoiceFinancialDiscountService, + InvoiceTermService invoiceTermService, + ContractVersionService contractVersionService) { + super( + accountConfigService, + invoicePaymentRepo, + invoicePaymentCreateService, + invoiceService, + saleOrderInvoiceService, + purchaseOrderInvoiceService, + saleOrderRepository, + purchaseOrderRepository, + accountingSituationSupplychainService, + appSupplychainService, + stockMoveInvoiceService, + unitConversionService, + appBaseService, + supplyChainConfigService, + stockMoveLineRepository, + appAccountService, + invoiceFinancialDiscountService, + invoiceTermService); + this.contractVersionService = contractVersionService; + } + + @Override + public void afterVentilation(Invoice invoice) throws AxelorException { + super.afterVentilation(invoice); + if (!appBaseService.isApp("contract")) { + return; + } + ContractVersion contractVersion = contractVersionService.getContractVersion(invoice); + if (contractVersion == null) { + return; + } + contractVersionService.computeTotalInvoicedAmount(contractVersion); + } +} diff --git a/changelogs/unreleased/89381.yml b/changelogs/unreleased/89381.yml new file mode 100644 index 00000000000..09965711af5 --- /dev/null +++ b/changelogs/unreleased/89381.yml @@ -0,0 +1,3 @@ +--- +title: "Contract version: fixed computation process for totalInvoicedAmount and totalPaidAmount." +module: axelor-contract