Skip to content

Commit

Permalink
83398 - Manage non deductible tax on move (#13984)
Browse files Browse the repository at this point in the history
  • Loading branch information
paa-axelor authored Feb 17, 2025
1 parent 4802100 commit 64edf94
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1813,4 +1813,7 @@ private AccountExceptionMessage() {}

public static final String SUM_OF_NON_DEDUCTIBLE_TAXES_EXCEEDS_ONE_HUNDRED = /*$$(*/
"The sum of non-deductible taxes should not exceed 100%." /*)*/;

public static final String MOVE_LINE_WITH_NON_DEDUCTIBLE_TAX_NOT_AUTHORIZED = /*$$(*/
"Non-deductible tax only authorized when functional origin is purchase. Please remove the non-deductible tax on move line." /*)*/;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@

import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.TaxLine;
import com.axelor.apps.base.AxelorException;
import java.util.List;
import java.util.Set;

public interface MoveLineCheckService {
void checkAnalyticByTemplate(MoveLine moveLine) throws AxelorException;
Expand All @@ -35,4 +37,8 @@ public interface MoveLineCheckService {
void checkAnalyticAccount(List<MoveLine> moveLineList) throws AxelorException;

void checkAnalyticMoveLinesPercentage(MoveLine moveLine) throws AxelorException;

void nonDeductibleTaxAuthorized(Move move, MoveLine moveLine) throws AxelorException;

void checkMoveLineTaxes(Set<TaxLine> taxLineSet) throws AxelorException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,34 +20,43 @@

import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.TaxLine;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.exception.AccountExceptionMessage;
import com.axelor.apps.account.service.AccountService;
import com.axelor.apps.account.service.TaxAccountService;
import com.axelor.apps.account.service.analytic.AnalyticDistributionTemplateService;
import com.axelor.apps.account.service.analytic.AnalyticMoveLineService;
import com.axelor.apps.base.AxelorException;
import com.axelor.apps.base.db.repo.TraceBackRepository;
import com.axelor.common.ObjectUtils;
import com.axelor.i18n.I18n;
import com.google.inject.Inject;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import org.apache.commons.collections.CollectionUtils;

public class MoveLineCheckServiceImpl implements MoveLineCheckService {
protected AccountService accountService;
protected AnalyticMoveLineService analyticMoveLineService;
protected AnalyticDistributionTemplateService analyticDistributionTemplateService;
protected MoveLineToolService moveLineToolService;
protected TaxAccountService taxAccountService;

@Inject
public MoveLineCheckServiceImpl(
AccountService accountService,
AnalyticMoveLineService analyticMoveLineService,
AnalyticDistributionTemplateService analyticDistributionTemplateService,
MoveLineToolService moveLineToolService) {
MoveLineToolService moveLineToolService,
TaxAccountService taxAccountService) {
this.accountService = accountService;
this.analyticMoveLineService = analyticMoveLineService;
this.analyticDistributionTemplateService = analyticDistributionTemplateService;
this.moveLineToolService = moveLineToolService;
this.taxAccountService = taxAccountService;
}

@Override
Expand Down Expand Up @@ -120,4 +129,19 @@ public void checkAnalyticMoveLinesPercentage(MoveLine moveLine) throws AxelorExc
I18n.get(AccountExceptionMessage.INVALID_ANALYTIC_MOVE_LINE));
}
}

public void nonDeductibleTaxAuthorized(Move move, MoveLine moveLine) throws AxelorException {
int technicalType = Optional.of(move.getFunctionalOriginSelect()).orElse(0);
if (technicalType != MoveRepository.FUNCTIONAL_ORIGIN_PURCHASE) {
this.checkMoveLineTaxes(moveLine.getTaxLineSet());
}
}

public void checkMoveLineTaxes(Set<TaxLine> taxLineSet) throws AxelorException {
if (ObjectUtils.notEmpty(taxLineSet) && taxAccountService.isNonDeductibleTaxesSet(taxLineSet)) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(AccountExceptionMessage.MOVE_LINE_WITH_NON_DEDUCTIBLE_TAX_NOT_AUTHORIZED));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ MoveLine createMoveLineForAutoTax(
TaxLine taxLine,
String accountType,
Account newAccount,
boolean percentMoveTemplate)
boolean percentMoveTemplate,
List<TaxLine> nonDeductibleTaxList)
throws AxelorException;

MoveLine createTaxMoveLine(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,8 @@ public MoveLine createMoveLineForAutoTax(
TaxLine taxLine,
String accountType,
Account newAccount,
boolean percentMoveTemplate)
boolean percentMoveTemplate,
List<TaxLine> nonDeductibleTaxList)
throws AxelorException {
BigDecimal debit = moveLine.getDebit();
BigDecimal credit = moveLine.getCredit();
Expand Down Expand Up @@ -760,7 +761,7 @@ public MoveLine createMoveLineForAutoTax(
move.getJournal(), move.getOrigin(), move.getDescription())));
moveLineToolService.setDecimals(newOrUpdatedMoveLine, move);

BigDecimal taxLineValue = taxLine.getValue();
BigDecimal taxLineValue = this.computeTaxLineValue(taxLine, nonDeductibleTaxList);

if (percentMoveTemplate) {
debit = sumMoveLinesByAccountType(move.getMoveLineList(), AccountTypeRepository.TYPE_PAYABLE);
Expand Down Expand Up @@ -808,6 +809,51 @@ public MoveLine createMoveLineForAutoTax(
return newOrUpdatedMoveLine;
}

protected BigDecimal computeTaxLineValue(TaxLine taxLine, List<TaxLine> nonDeductibleTaxList) {
BigDecimal taxValue = taxLine.getValue();
if (taxLine.getTax().getIsNonDeductibleTax()) {
taxValue = this.getAdjustedNonDeductibleTaxValue(taxValue, nonDeductibleTaxList);
} else {
taxValue = this.getAdjustedTaxValue(taxValue, nonDeductibleTaxList);
}

return taxValue;
}

protected BigDecimal getAdjustedTaxValue(
BigDecimal taxValue, List<TaxLine> nonDeductibleTaxList) {
BigDecimal deductibleTaxValue =
nonDeductibleTaxList.stream()
.map(TaxLine::getValue)
.reduce(BigDecimal::multiply)
.orElse(BigDecimal.ZERO)
.divide(
BigDecimal.valueOf(100), AppBaseService.COMPUTATION_SCALING, RoundingMode.HALF_UP);

return BigDecimal.ONE
.subtract(deductibleTaxValue)
.multiply(taxValue)
.setScale(AppBaseService.COMPUTATION_SCALING, RoundingMode.HALF_UP);
}

protected BigDecimal getAdjustedNonDeductibleTaxValue(
BigDecimal taxValue, List<TaxLine> deductibleTaxList) {
BigDecimal nonDeductibleTaxValue = BigDecimal.ZERO;

for (TaxLine taxLine : deductibleTaxList) {
nonDeductibleTaxValue =
nonDeductibleTaxValue.add(
taxValue.multiply(
taxLine
.getValue()
.divide(
BigDecimal.valueOf(100),
AppBaseService.COMPUTATION_SCALING,
RoundingMode.HALF_UP)));
}
return nonDeductibleTaxValue.setScale(AppBaseService.COMPUTATION_SCALING, RoundingMode.HALF_UP);
}

protected void createMoveLineRCForAutoTax(
Move move,
Map<String, MoveLine> map,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@
import com.axelor.apps.account.db.repo.MoveLineRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.exception.AccountExceptionMessage;
import com.axelor.apps.account.service.TaxAccountService;
import com.axelor.apps.account.service.TaxPaymentMoveLineService;
import com.axelor.apps.account.util.TaxAccountToolService;
import com.axelor.apps.base.AxelorException;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.repo.TraceBackRepository;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.base.service.tax.TaxService;
import com.axelor.common.ObjectUtils;
import com.axelor.i18n.I18n;
import com.google.common.collect.Lists;
Expand All @@ -54,6 +54,7 @@
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;

@RequestScoped
Expand All @@ -66,7 +67,8 @@ public class MoveLineTaxServiceImpl implements MoveLineTaxService {
protected MoveRepository moveRepository;
protected TaxAccountToolService taxAccountToolService;
protected MoveLineToolService moveLineToolService;
protected TaxService taxService;
protected TaxAccountService taxAccountService;
protected MoveLineCheckService moveLineCheckService;

@Inject
public MoveLineTaxServiceImpl(
Expand All @@ -77,15 +79,17 @@ public MoveLineTaxServiceImpl(
MoveRepository moveRepository,
TaxAccountToolService taxAccountToolService,
MoveLineToolService moveLineToolService,
TaxService taxService) {
TaxAccountService taxAccountService,
MoveLineCheckService moveLineCheckService) {
this.moveLineRepository = moveLineRepository;
this.taxPaymentMoveLineService = taxPaymentMoveLineService;
this.appBaseService = appBaseService;
this.moveLineCreateService = moveLineCreateService;
this.moveRepository = moveRepository;
this.taxAccountToolService = taxAccountToolService;
this.moveLineToolService = moveLineToolService;
this.taxService = taxService;
this.taxAccountService = taxAccountService;
this.moveLineCheckService = moveLineCheckService;
}

@Override
Expand Down Expand Up @@ -113,7 +117,7 @@ public MoveLine generateTaxPaymentMoveLineList(

} else if (!moveLineToolService.isMoveLineTaxAccount(invoiceMoveLine)
&& CollectionUtils.isNotEmpty(invoiceMoveLine.getTaxLineSet())
&& taxService
&& taxAccountService
.getTotalTaxRateInPercentage(invoiceMoveLine.getTaxLineSet())
.compareTo(BigDecimal.ZERO)
== 0) {
Expand Down Expand Up @@ -327,20 +331,78 @@ public int compare(MoveLine o1, MoveLine o2) {
continue;
}

if (CollectionUtils.isNotEmpty(taxLineSet))
for (TaxLine taxLine : taxLineSet) {
if (taxLine != null && taxLine.getValue().signum() != 0) {
String accountType = moveLine.getAccount().getAccountType().getTechnicalTypeSelect();
taxAccountService.checkTaxLinesNotOnlyNonDeductibleTaxes(taxLineSet);
taxAccountService.checkSumOfNonDeductibleTaxes(taxLineSet);
if (CollectionUtils.isNotEmpty(taxLineSet)) {
List<TaxLine> deductibleTaxList =
moveLineList.stream()
.map(MoveLine::getTaxLineSet)
.flatMap(Set::stream)
.filter(it -> !this.isNonDeductibleTax(it))
.collect(Collectors.toList());
List<TaxLine> nonDeductibleTaxList =
moveLineList.stream()
.map(MoveLine::getTaxLineSet)
.flatMap(Set::stream)
.filter(this::isNonDeductibleTax)
.collect(Collectors.toList());

this.computeMoveLineTax(
move,
map,
newMap,
moveLine,
account,
percentMoveTemplate,
nonDeductibleTaxList,
deductibleTaxList);
this.computeMoveLineTax(
move,
map,
newMap,
moveLine,
account,
percentMoveTemplate,
deductibleTaxList,
nonDeductibleTaxList);
}
}

if (this.isGenerateMoveLineForAutoTax(moveLine)) {
moveLineCreateService.createMoveLineForAutoTax(
move, map, newMap, moveLine, taxLine, accountType, account, percentMoveTemplate);
}
}
moveLineList.addAll(newMap.values());
}

protected void computeMoveLineTax(
Move move,
Map<String, MoveLine> map,
Map<String, MoveLine> newMap,
MoveLine moveLine,
Account account,
boolean percentMoveTemplate,
List<TaxLine> taxLineList,
List<TaxLine> otherTaxLineList)
throws AxelorException {
for (TaxLine taxLine : taxLineList) {
if (taxLine != null && taxLine.getValue().signum() != 0) {
String accountType = moveLine.getAccount().getAccountType().getTechnicalTypeSelect();
if (this.isGenerateMoveLineForAutoTax(moveLine)) {
moveLineCheckService.nonDeductibleTaxAuthorized(move, moveLine);
moveLineCreateService.createMoveLineForAutoTax(
move,
map,
newMap,
moveLine,
taxLine,
accountType,
account,
percentMoveTemplate,
otherTaxLineList);
}
}
}
}

moveLineList.addAll(newMap.values());
protected boolean isNonDeductibleTax(TaxLine taxLine) {
return Optional.of(taxLine.getTax().getIsNonDeductibleTax()).orElse(false);
}

@Override
Expand Down
1 change: 1 addition & 0 deletions axelor-account/src/main/resources/i18n/messages.csv
Original file line number Diff line number Diff line change
Expand Up @@ -2363,6 +2363,7 @@
"No style",,,
"No value",,,
"Non deductible tax",,,
"Non-deductible tax only authorized when functional origin is purchase. Please remove the non-deductible tax on move line.",,,
"None",,,
"None of the payment due dates have been exceeded.",,,
"Not implemented for OSM",,,
Expand Down
1 change: 1 addition & 0 deletions axelor-account/src/main/resources/i18n/messages_en.csv
Original file line number Diff line number Diff line change
Expand Up @@ -2363,6 +2363,7 @@
"No style",,,
"No value",,,
"Non deductible tax",,,
"Non-deductible tax only authorized when functional origin is purchase. Please remove the non-deductible tax on move line.",,,
"None",,,
"None of the payment due dates have been exceeded.",,,
"Not implemented for OSM",,,
Expand Down
1 change: 1 addition & 0 deletions axelor-account/src/main/resources/i18n/messages_fr.csv
Original file line number Diff line number Diff line change
Expand Up @@ -2364,6 +2364,7 @@ e a été payée ou qu'elle est reliée à une session de paiement.</Badge></>",
"No style","Aucun style",,
"No value","Aucune valeur",,
"Non deductible tax","Taxe non déductible",,
"Non-deductible tax only authorized when functional origin is purchase. Please remove the non-deductible tax on move line.","Les taxes non déductibles sont autorisées uniquement pour les origines fonctionnelles Achat. Veuillez retirer la/les taxe(s) non déductible(s) de la ligne d'écriture.",,
"None","Aucun",,
"None of the payment due dates have been exceeded.","Aucune des échéances de paiement n'a été dépassée",,
"Not implemented for OSM","Non implémenté pour OSM",,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.repo.MoveLineRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.service.TaxAccountService;
import com.axelor.apps.account.service.TaxPaymentMoveLineService;
import com.axelor.apps.account.service.moveline.MoveLineCheckService;
import com.axelor.apps.account.service.moveline.MoveLineCreateService;
import com.axelor.apps.account.service.moveline.MoveLineTaxServiceImpl;
import com.axelor.apps.account.service.moveline.MoveLineToolService;
import com.axelor.apps.account.util.TaxAccountToolService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.base.service.tax.TaxService;
import com.google.inject.Inject;

public class MoveLineTaxHRServiceImpl extends MoveLineTaxServiceImpl {
Expand All @@ -41,7 +42,8 @@ public MoveLineTaxHRServiceImpl(
MoveRepository moveRepository,
TaxAccountToolService taxAccountToolService,
MoveLineToolService moveLineToolService,
TaxService taxService) {
TaxAccountService taxAccountService,
MoveLineCheckService moveLineCheckService) {
super(
moveLineRepository,
taxPaymentMoveLineService,
Expand All @@ -50,7 +52,8 @@ public MoveLineTaxHRServiceImpl(
moveRepository,
taxAccountToolService,
moveLineToolService,
taxService);
taxAccountService,
moveLineCheckService);
}

@Override
Expand Down

0 comments on commit 64edf94

Please sign in to comment.