FINERACT-1932: Fineract modularization - fineract-tax

This commit is contained in:
Jose Alberto Hernandez
2024-06-17 23:06:07 +02:00
committed by Adam Saghy
parent 35ff4363a8
commit 0292171f6f
28 changed files with 289 additions and 20 deletions
@@ -1,38 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.tax.api;
public interface TaxApiConstants {
String nameParamName = "name";
String percentageParamName = "percentage";
String debitAccountTypeParamName = "debitAccountType";
String debitAcountIdParamName = "debitAcountId";
String creditAccountTypeParamName = "creditAccountType";
String creditAcountIdParamName = "creditAcountId";
String startDateParamName = "startDate";
String endDateParamName = "endDate";
String chargeIncludesTaxParamName = "chargeIncludesTax";
String taxComponentsParamName = "taxComponents";
String idParamName = "id";
String taxComponentIdParamName = "taxComponentId";
}
@@ -1,206 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.tax.domain;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.accounting.glaccount.domain.GLAccount;
import org.apache.fineract.accounting.glaccount.domain.GLAccountType;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.portfolio.tax.api.TaxApiConstants;
@Entity
@Table(name = "m_tax_component")
public class TaxComponent extends AbstractAuditableCustom {
@Column(name = "name", length = 100)
private String name;
@Column(name = "percentage", scale = 6, precision = 19, nullable = false)
private BigDecimal percentage;
@Column(name = "debit_account_type_enum")
private Integer debitAccountType;
@ManyToOne
@JoinColumn(name = "debit_account_id")
private GLAccount debitAcount;
@Column(name = "credit_account_type_enum")
private Integer creditAccountType;
@ManyToOne
@JoinColumn(name = "credit_account_id")
private GLAccount creditAcount;
@Column(name = "start_date", nullable = false)
private LocalDate startDate;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
@JoinColumn(name = "tax_component_id", referencedColumnName = "id", nullable = false)
private Set<TaxComponentHistory> taxComponentHistories = new HashSet<>();
@OneToMany(cascade = CascadeType.DETACH, mappedBy = "taxComponent", orphanRemoval = false, fetch = FetchType.EAGER)
private Set<TaxGroupMappings> taxGroupMappings = new HashSet<>();
protected TaxComponent() {
}
private TaxComponent(final String name, final BigDecimal percentage, final GLAccountType debitAccountType, final GLAccount debitAcount,
final GLAccountType creditAccountType, final GLAccount creditAcount, final LocalDate startDate) {
this.name = name;
this.percentage = percentage;
if (debitAccountType != null) {
this.debitAccountType = debitAccountType.getValue();
}
this.debitAcount = debitAcount;
if (creditAccountType != null) {
this.creditAccountType = creditAccountType.getValue();
}
this.creditAcount = creditAcount;
this.startDate = startDate;
}
public static TaxComponent createTaxComponent(final String name, final BigDecimal percentage, final GLAccountType debitAccountType,
final GLAccount debitAcount, final GLAccountType creditAccountType, final GLAccount creditAcount, final LocalDate startDate) {
return new TaxComponent(name, percentage, debitAccountType, debitAcount, creditAccountType, creditAcount, startDate);
}
public Map<String, Object> update(final JsonCommand command) {
final Map<String, Object> changes = new HashMap<>();
if (command.isChangeInStringParameterNamed(TaxApiConstants.nameParamName, this.name)) {
final String newValue = command.stringValueOfParameterNamed(TaxApiConstants.nameParamName);
changes.put(TaxApiConstants.nameParamName, newValue);
this.name = StringUtils.defaultIfEmpty(newValue, null);
}
if (command.isChangeInBigDecimalParameterNamed(TaxApiConstants.percentageParamName, this.percentage)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(TaxApiConstants.percentageParamName);
changes.put(TaxApiConstants.percentageParamName, newValue);
LocalDate oldStartDate = this.startDate;
updateStartDate(command, changes, true);
LocalDate newStartDate = this.startDate;
TaxComponentHistory history = TaxComponentHistory.createTaxComponentHistory(this.percentage, oldStartDate, newStartDate);
this.taxComponentHistories.add(history);
this.percentage = newValue;
}
return changes;
}
private void updateStartDate(final JsonCommand command, final Map<String, Object> changes, boolean setAsCurrentDate) {
LocalDate startDate = DateUtils.getBusinessLocalDate();
if (command.parameterExists(TaxApiConstants.startDateParamName)) {
LocalDate startDateFromUI = command.localDateValueOfParameterNamed(TaxApiConstants.startDateParamName);
if (startDateFromUI != null) {
startDate = startDateFromUI;
}
this.startDate = startDate;
changes.put(TaxApiConstants.startDateParamName, startDate);
} else if (setAsCurrentDate) {
changes.put(TaxApiConstants.startDateParamName, startDate);
this.startDate = startDate;
}
}
public BigDecimal getPercentage() {
return this.percentage;
}
public LocalDate startDate() {
return this.startDate;
}
public BigDecimal getApplicablePercentage(final LocalDate date) {
BigDecimal percentage = null;
if (occursOnDayFrom(date)) {
percentage = getPercentage();
} else {
for (TaxComponentHistory componentHistory : taxComponentHistories) {
if (componentHistory.occursOnDayFromAndUpToAndIncluding(date)) {
percentage = componentHistory.getPercentage();
break;
}
}
}
return percentage;
}
private boolean occursOnDayFrom(final LocalDate target) {
return DateUtils.isAfter(target, startDate());
}
public Set<TaxComponentHistory> getTaxComponentHistories() {
return this.taxComponentHistories;
}
public Set<TaxGroupMappings> getTaxGroupMappings() {
return this.taxGroupMappings;
}
public Collection<LocalDate> allStartDates() {
List<LocalDate> dates = new ArrayList<>();
dates.add(startDate());
for (TaxComponentHistory componentHistory : taxComponentHistories) {
dates.add(componentHistory.startDate());
}
return dates;
}
public Integer getDebitAccountType() {
return this.debitAccountType;
}
public GLAccount getDebitAcount() {
return this.debitAcount;
}
public Integer getCreditAccountType() {
return this.creditAccountType;
}
public GLAccount getCreditAcount() {
return this.creditAcount;
}
}
@@ -1,73 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.tax.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDate;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
@Entity
@Table(name = "m_tax_component_history")
public class TaxComponentHistory extends AbstractAuditableCustom {
@Column(name = "percentage", scale = 6, precision = 19, nullable = false)
private BigDecimal percentage;
@Column(name = "start_date", nullable = false)
private LocalDate startDate;
@Column(name = "end_date", nullable = false)
private LocalDate endDate;
protected TaxComponentHistory() {
}
private TaxComponentHistory(final BigDecimal percentage, final LocalDate startDate, final LocalDate endDate) {
this.percentage = percentage;
this.startDate = startDate;
this.endDate = endDate;
}
public static TaxComponentHistory createTaxComponentHistory(final BigDecimal percentage, final LocalDate startDate,
final LocalDate endDate) {
return new TaxComponentHistory(percentage, startDate, endDate);
}
public LocalDate startDate() {
return this.startDate;
}
public LocalDate endDate() {
return this.endDate;
}
public boolean occursOnDayFromAndUpToAndIncluding(final LocalDate target) {
return DateUtils.isAfter(target, startDate()) && (endDate == null || !DateUtils.isAfter(target, endDate()));
}
public BigDecimal getPercentage() {
return this.percentage;
}
}
@@ -1,26 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.tax.domain;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface TaxComponentRepository extends JpaRepository<TaxComponent, Long>, JpaSpecificationExecutor<TaxComponent> {
}
@@ -1,39 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.tax.domain;
import org.apache.fineract.portfolio.tax.exception.TaxComponentNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class TaxComponentRepositoryWrapper {
private final TaxComponentRepository repository;
@Autowired
public TaxComponentRepositoryWrapper(final TaxComponentRepository repository) {
this.repository = repository;
}
public TaxComponent findOneWithNotFoundDetection(final Long id) {
return this.repository.findById(id).orElseThrow(() -> new TaxComponentNotFoundException(id));
}
}
@@ -1,115 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.tax.domain;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom;
import org.apache.fineract.portfolio.tax.api.TaxApiConstants;
import org.apache.fineract.portfolio.tax.exception.TaxMappingNotFoundException;
@Entity
@Table(name = "m_tax_group")
public class TaxGroup extends AbstractAuditableCustom {
@Column(name = "name", length = 100)
private String name;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "taxGroup")
private Set<TaxGroupMappings> taxGroupMappings = new HashSet<>();
protected TaxGroup() {
}
private TaxGroup(final String name, final Set<TaxGroupMappings> taxGroupMappings) {
this.name = name;
this.taxGroupMappings = taxGroupMappings;
taxGroupMappings.forEach(m -> m.setTaxGroup(this));
}
public static TaxGroup createTaxGroup(final String name, final Set<TaxGroupMappings> taxGroupMappings) {
return new TaxGroup(name, taxGroupMappings);
}
public Map<String, Object> update(final JsonCommand command, final Set<TaxGroupMappings> taxGroupMappings) {
final Map<String, Object> changes = new HashMap<>();
if (command.isChangeInStringParameterNamed(TaxApiConstants.nameParamName, this.name)) {
final String newValue = command.stringValueOfParameterNamed(TaxApiConstants.nameParamName);
changes.put(TaxApiConstants.nameParamName, newValue);
this.name = StringUtils.defaultIfEmpty(newValue, null);
}
List<Long> taxComponentList = new ArrayList<>();
final List<Map<String, Object>> modifications = new ArrayList<>();
for (TaxGroupMappings groupMappings : taxGroupMappings) {
TaxGroupMappings mappings = findOneBy(groupMappings);
if (mappings == null) {
this.taxGroupMappings.add(groupMappings);
taxComponentList.add(groupMappings.getTaxComponent().getId());
} else {
mappings.update(groupMappings.getEndDate(), modifications);
}
}
if (!taxComponentList.isEmpty()) {
changes.put("addComponents", taxComponentList);
}
if (!modifications.isEmpty()) {
changes.put("modifiedComponents", modifications);
}
return changes;
}
public TaxGroupMappings findOneBy(final TaxGroupMappings groupMapping) {
if (groupMapping.getId() != null) {
for (TaxGroupMappings groupMappings : this.taxGroupMappings) {
if (groupMappings.getId().equals(groupMapping.getId())) {
return groupMappings;
}
}
throw new TaxMappingNotFoundException(groupMapping.getId());
}
return null;
}
public Set<TaxGroupMappings> getTaxGroupMappings() {
return this.taxGroupMappings;
}
public String getName() {
return this.name;
}
}
@@ -1,111 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.tax.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.portfolio.tax.api.TaxApiConstants;
@Entity
@Table(name = "m_tax_group_mappings")
public class TaxGroupMappings extends AbstractAuditableCustom {
@ManyToOne
@JoinColumn(name = "tax_group_id", nullable = false)
private TaxGroup taxGroup;
@ManyToOne
@JoinColumn(name = "tax_component_id", nullable = false)
private TaxComponent taxComponent;
@Column(name = "start_date", nullable = false)
private LocalDate startDate;
@Column(name = "end_date", nullable = true)
private LocalDate endDate;
protected TaxGroupMappings() {}
private TaxGroupMappings(final TaxComponent taxComponent, final LocalDate startDate, final LocalDate endDate) {
this.taxComponent = taxComponent;
this.startDate = startDate;
this.endDate = endDate;
}
public static TaxGroupMappings createTaxGroupMappings(final TaxComponent taxComponent, final LocalDate startDate) {
final LocalDate endDate = null;
return new TaxGroupMappings(taxComponent, startDate, endDate);
}
public static TaxGroupMappings createTaxGroupMappings(final Long id, final TaxComponent taxComponent, final LocalDate endDate) {
final LocalDate startDate = null;
TaxGroupMappings groupMappings = new TaxGroupMappings(taxComponent, startDate, endDate);
groupMappings.setId(id);
return groupMappings;
}
public void update(final LocalDate endDate, final List<Map<String, Object>> changes) {
if (endDate != null && this.endDate == null) {
this.endDate = endDate;
Map<String, Object> map = new HashMap<>(2);
map.put(TaxApiConstants.endDateParamName, endDate);
map.put(TaxApiConstants.taxComponentIdParamName, this.getTaxComponent().getId());
changes.add(map);
}
}
public boolean occursOnDayFromAndUpToAndIncluding(final LocalDate target) {
return DateUtils.isAfter(target, startDate()) && (endDate == null || !DateUtils.isAfter(target, endDate()));
}
public TaxComponent getTaxComponent() {
return this.taxComponent;
}
public LocalDate getEndDate() {
return this.endDate;
}
public LocalDate startDate() {
return this.startDate;
}
public LocalDate endDate() {
return this.endDate;
}
public TaxGroup getTaxGroup() {
return taxGroup;
}
public void setTaxGroup(TaxGroup taxGroup) {
this.taxGroup = taxGroup;
}
}
@@ -1,26 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.tax.domain;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface TaxGroupRepository extends JpaRepository<TaxGroup, Long>, JpaSpecificationExecutor<TaxGroup> {
}
@@ -1,38 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.tax.domain;
import org.apache.fineract.portfolio.tax.exception.TaxGroupNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class TaxGroupRepositoryWrapper {
private final TaxGroupRepository repository;
@Autowired
public TaxGroupRepositoryWrapper(final TaxGroupRepository repository) {
this.repository = repository;
}
public TaxGroup findOneWithNotFoundDetection(final Long id) {
return this.repository.findById(id).orElseThrow(() -> new TaxGroupNotFoundException(id));
}
}
@@ -1,28 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.tax.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
public class TaxComponentNotFoundException extends AbstractPlatformResourceNotFoundException {
public TaxComponentNotFoundException(final Long id) {
super("error.msg.tax.component.id.invalid", "tax component with identifier " + id + " does not exist", id);
}
}
@@ -1,28 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.tax.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
public class TaxGroupNotFoundException extends AbstractPlatformResourceNotFoundException {
public TaxGroupNotFoundException(final Long id) {
super("error.msg.tax.group.id.invalid", "tax group with identifier " + id + " does not exist", id);
}
}
@@ -1,33 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.tax.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
/**
* {@link AbstractPlatformDomainRuleException} thrown when tax group mapping does not exist.
*/
public class TaxMappingNotFoundException extends AbstractPlatformResourceNotFoundException {
public TaxMappingNotFoundException(final Long id) {
super("error.msg.tax.group.id.invalid", "Tax group mapping with identifier " + id + " does not exist", id);
}
}
@@ -1,129 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.tax.service;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
import org.apache.fineract.portfolio.tax.data.TaxComponentData;
import org.apache.fineract.portfolio.tax.data.TaxGroupMappingsData;
import org.apache.fineract.portfolio.tax.domain.TaxComponent;
import org.apache.fineract.portfolio.tax.domain.TaxGroupMappings;
public final class TaxUtils {
private TaxUtils() {
}
public static Map<TaxComponent, BigDecimal> splitTax(final BigDecimal amount, final LocalDate date,
final Set<TaxGroupMappings> taxGroupMappings, final int scale) {
Map<TaxComponent, BigDecimal> map = new HashMap<>(3);
if (amount != null) {
final double amountVal = amount.doubleValue();
double cent_percentage = Double.parseDouble("100.0");
for (TaxGroupMappings groupMappings : taxGroupMappings) {
if (groupMappings.occursOnDayFromAndUpToAndIncluding(date)) {
TaxComponent component = groupMappings.getTaxComponent();
BigDecimal percentage = component.getApplicablePercentage(date);
if (percentage != null) {
double percentageVal = percentage.doubleValue();
double tax = amountVal * percentageVal / cent_percentage;
map.put(component, BigDecimal.valueOf(tax).setScale(scale, MoneyHelper.getRoundingMode()));
}
}
}
}
return map;
}
public static Map<TaxComponentData, BigDecimal> splitTaxData(final BigDecimal amount, final LocalDate date,
final Set<TaxGroupMappingsData> taxGroupMappings, final int scale) {
Map<TaxComponentData, BigDecimal> map = new HashMap<>(3);
if (amount != null) {
final double amountVal = amount.doubleValue();
double cent_percentage = Double.parseDouble("100.0");
for (TaxGroupMappingsData groupMappings : taxGroupMappings) {
if (groupMappings.occursOnDayFromAndUpToAndIncluding(date)) {
TaxComponentData component = groupMappings.getTaxComponent();
BigDecimal percentage = component.getApplicablePercentage(date);
if (percentage != null) {
double percentageVal = percentage.doubleValue();
double tax = amountVal * percentageVal / cent_percentage;
map.put(component, BigDecimal.valueOf(tax).setScale(scale, MoneyHelper.getRoundingMode()));
}
}
}
}
return map;
}
public static BigDecimal incomeAmount(final BigDecimal amount, final LocalDate date, final Set<TaxGroupMappings> taxGroupMappings,
final int scale) {
Map<TaxComponent, BigDecimal> map = splitTax(amount, date, taxGroupMappings, scale);
return incomeAmount(amount, map);
}
public static BigDecimal incomeAmount(final BigDecimal amount, final Map<TaxComponent, BigDecimal> map) {
BigDecimal totalTax = totalTaxAmount(map);
return amount.subtract(totalTax);
}
public static BigDecimal totalTaxAmount(final Map<TaxComponent, BigDecimal> map) {
BigDecimal totalTax = BigDecimal.ZERO;
for (BigDecimal tax : map.values()) {
totalTax = totalTax.add(tax);
}
return totalTax;
}
public static BigDecimal totalTaxDataAmount(final Map<TaxComponentData, BigDecimal> map) {
BigDecimal totalTax = BigDecimal.ZERO;
for (BigDecimal tax : map.values()) {
totalTax = totalTax.add(tax);
}
return totalTax;
}
public static BigDecimal addTax(final BigDecimal amount, final LocalDate date, final List<TaxGroupMappings> taxGroupMappings,
final int scale) {
BigDecimal totalAmount = null;
if (amount != null && amount.compareTo(BigDecimal.ZERO) > 0) {
double percentageVal = 0;
double amountVal = amount.doubleValue();
double cent_percentage = Double.parseDouble("100.0");
for (TaxGroupMappings groupMappings : taxGroupMappings) {
if (groupMappings.occursOnDayFromAndUpToAndIncluding(date)) {
TaxComponent component = groupMappings.getTaxComponent();
BigDecimal percentage = component.getApplicablePercentage(date);
if (percentage != null) {
percentageVal = percentageVal + percentage.doubleValue();
}
}
}
double total = amountVal * cent_percentage / (cent_percentage - percentageVal);
totalAmount = BigDecimal.valueOf(total).setScale(scale, MoneyHelper.getRoundingMode());
}
return totalAmount;
}
}