FINERACT-2425: Tax component and Tax Group refactoring

This commit is contained in:
Jose Alberto Hernandez
2026-01-03 01:56:47 +01:00
committed by Adam Saghy
parent cbf8a4f5ab
commit b7306f19d0
33 changed files with 525 additions and 295 deletions
@@ -119,6 +119,10 @@ public enum GLAccountType {
return name();
}
public EnumOptionData toEnumOptionData() {
return new EnumOptionData((long) value, code, code);
}
public boolean isAssetType() {
return this.value.equals(GLAccountType.ASSET.getValue());
}
@@ -20,6 +20,7 @@ package org.apache.fineract.accounting.glaccount.domain;
import java.util.HashMap;
import java.util.Map;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
public enum GLAccountUsage {
@@ -81,4 +82,8 @@ public enum GLAccountUsage {
return name().toString();
}
public EnumOptionData toEnumOptionData() {
return new EnumOptionData((long) value, code, code);
}
}
@@ -0,0 +1,69 @@
/**
* 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.accounting.glaccount.mapper;
import java.util.List;
import org.apache.fineract.accounting.glaccount.data.GLAccountData;
import org.apache.fineract.accounting.glaccount.domain.GLAccount;
import org.apache.fineract.accounting.glaccount.domain.GLAccountType;
import org.apache.fineract.accounting.glaccount.domain.GLAccountUsage;
import org.apache.fineract.infrastructure.codes.mapper.CodeValueMapper;
import org.apache.fineract.infrastructure.core.config.MapstructMapperConfig;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
@Mapper(config = MapstructMapperConfig.class, uses = { CodeValueMapper.class })
public interface GlAccountMapper {
@Mapping(target = "usage", source = "glAccount.usage", qualifiedByName = "glAccountUsage")
@Mapping(target = "type", source = "glAccount.type", qualifiedByName = "glAccountType")
@Mapping(target = "name", source = "glAccount.name")
@Mapping(target = "nameDecorated", source = "glAccount.name")
@Mapping(target = "parentId", source = "glAccount.parent.id")
@Mapping(target = "tagId", source = "glAccount.tagId")
@Mapping(target = "accountTypeOptions", ignore = true)
@Mapping(target = "usageOptions", ignore = true)
@Mapping(target = "assetHeaderAccountOptions", ignore = true)
@Mapping(target = "liabilityHeaderAccountOptions", ignore = true)
@Mapping(target = "equityHeaderAccountOptions", ignore = true)
@Mapping(target = "incomeHeaderAccountOptions", ignore = true)
@Mapping(target = "expenseHeaderAccountOptions", ignore = true)
@Mapping(target = "allowedAssetsTagOptions", ignore = true)
@Mapping(target = "allowedLiabilitiesTagOptions", ignore = true)
@Mapping(target = "allowedEquityTagOptions", ignore = true)
@Mapping(target = "allowedIncomeTagOptions", ignore = true)
@Mapping(target = "allowedExpensesTagOptions", ignore = true)
@Mapping(target = "organizationRunningBalance", ignore = true)
@Mapping(target = "rowIndex", ignore = true)
GLAccountData map(GLAccount glAccount);
List<GLAccountData> map(List<GLAccount> glAccounts);
@Named("glAccountType")
default EnumOptionData glAccountType(Integer typeId) {
return GLAccountType.fromInt(typeId).toEnumOptionData();
}
@Named("glAccountUsage")
default EnumOptionData glAccountUsage(Integer usageId) {
return GLAccountUsage.fromInt(usageId).toEnumOptionData();
}
}
@@ -0,0 +1,35 @@
/**
* 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.accounting.glaccount.mapper;
import org.apache.fineract.accounting.glaccount.domain.GLAccountType;
import org.apache.fineract.infrastructure.core.config.MapstructMapperConfig;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@Mapper(config = MapstructMapperConfig.class)
public interface GlAccountTypeMapper {
@Mapping(target = "id", expression = "java((long) glAccountType.getValue())")
@Mapping(target = "code", source = "glAccountType.code")
@Mapping(target = "description", source = "glAccountType.code")
EnumOptionData map(GLAccountType glAccountType);
}
@@ -0,0 +1,35 @@
/**
* 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.accounting.glaccount.mapper;
import org.apache.fineract.accounting.glaccount.domain.GLAccountUsage;
import org.apache.fineract.infrastructure.core.config.MapstructMapperConfig;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@Mapper(config = MapstructMapperConfig.class)
public interface GlAccountUsageMapper {
@Mapping(target = "id", expression = "java((long) glAccountUsage.getValue())")
@Mapping(target = "code", source = "glAccountUsage.code")
@Mapping(target = "description", source = "glAccountUsage.code")
EnumOptionData map(GLAccountUsage glAccountUsage);
}
@@ -49,25 +49,25 @@ public final class TaxComponentData implements Serializable {
private final Collection<EnumOptionData> glAccountTypeOptions;
public static TaxComponentData instance(final Long id, final String name, final BigDecimal percentage,
final EnumOptionData debitAccountType, final GLAccountData debitAcount, final EnumOptionData creditAccountType,
final GLAccountData creditAcount, final LocalDate startDate, final Collection<TaxComponentHistoryData> taxComponentHistories) {
final EnumOptionData debitAccountType, final GLAccountData debitAccount, final EnumOptionData creditAccountType,
final GLAccountData creditAccount, final LocalDate startDate, final Collection<TaxComponentHistoryData> taxComponentHistories) {
final Map<String, List<GLAccountData>> glAccountOptions = null;
final Collection<EnumOptionData> glAccountTypeOptions = null;
return new TaxComponentData(id, name, percentage, debitAccountType, debitAcount, creditAccountType, creditAcount, startDate,
return new TaxComponentData(id, name, percentage, debitAccountType, debitAccount, creditAccountType, creditAccount, startDate,
taxComponentHistories, glAccountOptions, glAccountTypeOptions);
}
public static TaxComponentData lookup(final Long id, final String name) {
final BigDecimal percentage = null;
final EnumOptionData debitAccountType = null;
final GLAccountData debitAcount = null;
final GLAccountData debitAccount = null;
final EnumOptionData creditAccountType = null;
final GLAccountData creditAcount = null;
final GLAccountData creditAccount = null;
final LocalDate startDate = null;
final Collection<TaxComponentHistoryData> taxComponentHistories = null;
final Map<String, List<GLAccountData>> glAccountOptions = null;
final Collection<EnumOptionData> glAccountTypeOptions = null;
return new TaxComponentData(id, name, percentage, debitAccountType, debitAcount, creditAccountType, creditAcount, startDate,
return new TaxComponentData(id, name, percentage, debitAccountType, debitAccount, creditAccountType, creditAccount, startDate,
taxComponentHistories, glAccountOptions, glAccountTypeOptions);
}
@@ -77,24 +77,24 @@ public final class TaxComponentData implements Serializable {
final String name = null;
final BigDecimal percentage = null;
final EnumOptionData debitAccountType = null;
final GLAccountData debitAcount = null;
final GLAccountData debitAccount = null;
final EnumOptionData creditAccountType = null;
final GLAccountData creditAcount = null;
final GLAccountData creditAccount = null;
final LocalDate startDate = null;
final Collection<TaxComponentHistoryData> taxComponentHistories = null;
return new TaxComponentData(id, name, percentage, debitAccountType, debitAcount, creditAccountType, creditAcount, startDate,
return new TaxComponentData(id, name, percentage, debitAccountType, debitAccount, creditAccountType, creditAccount, startDate,
taxComponentHistories, glAccountOptions, glAccountTypeOptions);
}
private TaxComponentData(final Long id, final BigDecimal percentage, final GLAccountData debitAcount,
final GLAccountData creditAcount) {
private TaxComponentData(final Long id, final BigDecimal percentage, final GLAccountData debitAccount,
final GLAccountData creditAccount) {
this.id = id;
this.percentage = percentage;
this.name = null;
this.debitAccountType = null;
this.debitAccount = debitAcount;
this.debitAccount = debitAccount;
this.creditAccountType = null;
this.creditAccount = creditAcount;
this.creditAccount = creditAccount;
this.startDate = null;
this.taxComponentHistories = null;
this.glAccountOptions = null;
@@ -40,7 +40,7 @@ public class TaxComponentRequest implements Serializable {
private Integer debitAccountType;
private Long debitAccountId;
private Integer creditAccountType;
private Long creditAcountId;
private Long creditAccountId;
private String startDate;
private String dateFormat;
private String locale;
@@ -61,7 +61,7 @@ public class TaxAssembler {
final BigDecimal percentage = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(TaxApiConstants.percentageParamName, element);
final Integer debitAccountType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(TaxApiConstants.debitAccountTypeParamName,
element);
final Long debitAccountId = this.fromApiJsonHelper.extractLongNamed(TaxApiConstants.debitAcountIdParamName, element);
final Long debitAccountId = this.fromApiJsonHelper.extractLongNamed(TaxApiConstants.debitAccountIdParamName, element);
GLAccountType debitGlAccountType = null;
if (debitAccountType != null) {
debitGlAccountType = GLAccountType.fromInt(debitAccountType);
@@ -70,7 +70,7 @@ public class TaxAssembler {
if (debitAccountId != null) {
debitGlAccount = this.glAccountRepositoryWrapper.findOneWithNotFoundDetection(debitAccountId);
if (!debitGlAccount.getType().equals(debitAccountType) || debitGlAccount.isHeaderAccount()) {
baseDataValidator.parameter(TaxApiConstants.debitAcountIdParamName).value(debitAccountId)
baseDataValidator.parameter(TaxApiConstants.debitAccountIdParamName).value(debitAccountId)
.failWithCode("not.a.valid.account");
}
}
@@ -81,12 +81,12 @@ public class TaxAssembler {
if (creditAccountType != null) {
creditGlAccountType = GLAccountType.fromInt(creditAccountType);
}
final Long creditAccountId = this.fromApiJsonHelper.extractLongNamed(TaxApiConstants.creditAcountIdParamName, element);
final Long creditAccountId = this.fromApiJsonHelper.extractLongNamed(TaxApiConstants.creditAccountIdParamName, element);
GLAccount creditGlAccount = null;
if (creditAccountId != null) {
creditGlAccount = this.glAccountRepositoryWrapper.findOneWithNotFoundDetection(creditAccountId);
if (!creditGlAccount.getType().equals(creditAccountType) || creditGlAccount.isHeaderAccount()) {
baseDataValidator.parameter(TaxApiConstants.creditAcountIdParamName).value(creditAccountId)
baseDataValidator.parameter(TaxApiConstants.creditAccountIdParamName).value(creditAccountId)
.failWithCode("not.a.valid.account");
}
}
@@ -18,47 +18,34 @@
*/
package org.apache.fineract.portfolio.tax.service;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.accounting.common.AccountingDropdownReadPlatformService;
import org.apache.fineract.accounting.common.AccountingEnumerations;
import org.apache.fineract.accounting.glaccount.data.GLAccountData;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.portfolio.tax.data.TaxComponentData;
import org.apache.fineract.portfolio.tax.data.TaxComponentHistoryData;
import org.apache.fineract.portfolio.tax.data.TaxGroupData;
import org.apache.fineract.portfolio.tax.data.TaxGroupMappingsData;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.apache.fineract.portfolio.tax.domain.TaxComponentRepository;
import org.apache.fineract.portfolio.tax.domain.TaxGroupRepository;
import org.apache.fineract.portfolio.tax.mapper.TaxComponentMapper;
import org.apache.fineract.portfolio.tax.mapper.TaxGroupMapper;
@RequiredArgsConstructor
public class TaxReadPlatformServiceImpl implements TaxReadPlatformService {
private static final TaxComponentMapper TAX_COMPONENT_MAPPER = new TaxComponentMapper();
private static final TaxGroupMapper TAX_GROUP_MAPPER = new TaxGroupMapper();
private static final TaxComponentLookUpMapper TAX_COMPONENT_LOOK_UP_MAPPER = new TaxComponentLookUpMapper();
private static final TaxGroupLookUpMapper TAX_GROUP_LOOK_UP_MAPPER = new TaxGroupLookUpMapper();
private final JdbcTemplate jdbcTemplate;
private final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService;
private final TaxComponentRepository taxComponentRepository;
private final TaxComponentMapper taxComponentMapper;
private final TaxGroupRepository taxGroupRepository;
private final TaxGroupMapper taxGroupMapper;
@Override
public List<TaxComponentData> retrieveAllTaxComponents() {
String sql = "select " + TAX_COMPONENT_MAPPER.getSchema();
return this.jdbcTemplate.query(sql, TAX_COMPONENT_MAPPER); // NOSONAR
return taxComponentMapper.map(taxComponentRepository.findAll());
}
@Override
public TaxComponentData retrieveTaxComponentData(final Long id) {
String sql = "select " + TAX_COMPONENT_MAPPER.getSchema() + " where tc.id=?";
return this.jdbcTemplate.queryForObject(sql, TAX_COMPONENT_MAPPER, id); // NOSONAR
return taxComponentMapper.map(taxComponentRepository.getReferenceById(id));
}
@Override
@@ -69,14 +56,12 @@ public class TaxReadPlatformServiceImpl implements TaxReadPlatformService {
@Override
public List<TaxGroupData> retrieveAllTaxGroups() {
String sql = "select " + TAX_GROUP_MAPPER.getSchema();
return this.jdbcTemplate.query(sql, TAX_GROUP_MAPPER); // NOSONAR
return taxGroupMapper.map(taxGroupRepository.findAll());
}
@Override
public TaxGroupData retrieveTaxGroupData(final Long id) {
String sql = "select " + TAX_GROUP_MAPPER.getSchema() + " where tg.id=?";
return this.jdbcTemplate.queryForObject(sql, TAX_GROUP_MAPPER, id); // NOSONAR
return taxGroupMapper.map(taxGroupRepository.getReferenceById(id));
}
@Override
@@ -92,205 +77,12 @@ public class TaxReadPlatformServiceImpl implements TaxReadPlatformService {
}
private Collection<TaxComponentData> retrieveTaxComponentsForLookUp() {
String sql = "select " + TAX_COMPONENT_LOOK_UP_MAPPER.getSchema();
return this.jdbcTemplate.query(sql, TAX_COMPONENT_LOOK_UP_MAPPER); // NOSONAR
return taxComponentMapper.map(taxComponentRepository.findAll());
}
@Override
public List<TaxGroupData> retrieveTaxGroupsForLookUp() {
String sql = "select " + TAX_GROUP_LOOK_UP_MAPPER.getSchema();
return this.jdbcTemplate.query(sql, TAX_GROUP_LOOK_UP_MAPPER); // NOSONAR
}
private static final class TaxComponentMapper implements RowMapper<TaxComponentData> {
private final String schema;
private final TaxComponentHistoryDataMapper componentHistoryDataMapper = new TaxComponentHistoryDataMapper();
TaxComponentMapper() {
StringBuilder sb = new StringBuilder();
sb.append("tc.id as id, tc.name as name,");
sb.append("tc.percentage as percentage, tc.start_date as startDate,");
sb.append("tc.debit_account_type_enum as debitAccountTypeEnum,");
sb.append("dgl.id as debitAccountId, dgl.name as debitAccountName, dgl.gl_code as debitAccountGlCode,");
sb.append("tc.credit_account_type_enum as creditAccountTypeEnum,");
sb.append("cgl.id as creditAccountId, cgl.name as creditAccountName, cgl.gl_code as creditAccountGlCode,");
sb.append("history.percentage as historyPercentage, history.start_date as historyStartDate,");
sb.append("history.end_date as historyEndDate");
sb.append(" from m_tax_component tc ");
sb.append(" left join acc_gl_account dgl on dgl.id = tc.debit_account_id");
sb.append(" left join acc_gl_account cgl on cgl.id = tc.credit_account_id");
sb.append(" left join m_tax_component_history history on history.tax_component_id = tc.id");
this.schema = sb.toString();
}
@Override
public TaxComponentData mapRow(ResultSet rs, int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final String name = rs.getString("name");
final BigDecimal percentage = rs.getBigDecimal("percentage");
final Integer debitAccountTypeEnum = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "debitAccountTypeEnum");
EnumOptionData debitAccountType = null;
if (debitAccountTypeEnum != null) {
debitAccountType = AccountingEnumerations.gLAccountType(debitAccountTypeEnum);
}
GLAccountData debitAccountData = null;
if (debitAccountTypeEnum != null && debitAccountTypeEnum > 0) {
final Long debitAccountId = rs.getLong("debitAccountId");
final String debitAccountName = rs.getString("debitAccountName");
final String debitAccountGlCode = rs.getString("debitAccountGlCode");
debitAccountData = new GLAccountData().setId(debitAccountId).setName(debitAccountName).setGlCode(debitAccountGlCode);
}
final Integer creditAccountTypeEnum = JdbcSupport.getIntegerDefaultToNullIfZero(rs, "creditAccountTypeEnum");
EnumOptionData creditAccountType = null;
if (creditAccountTypeEnum != null) {
creditAccountType = AccountingEnumerations.gLAccountType(creditAccountTypeEnum);
}
GLAccountData creditAccountData = null;
if (creditAccountTypeEnum != null && creditAccountTypeEnum > 0) {
final Long creditAccountId = rs.getLong("creditAccountId");
final String creditAccountName = rs.getString("creditAccountName");
final String creditAccountGlCode = rs.getString("creditAccountGlCode");
creditAccountData = new GLAccountData().setId(creditAccountId).setName(creditAccountName).setGlCode(creditAccountGlCode);
}
final LocalDate startDate = JdbcSupport.getLocalDate(rs, "startDate");
Collection<TaxComponentHistoryData> historyDatas = new ArrayList<>();
historyDatas.add(componentHistoryDataMapper.mapRow(rs, rowNum));
while (rs.next()) {
if (id.equals(rs.getLong("id"))) {
historyDatas.add(componentHistoryDataMapper.mapRow(rs, rowNum));
} else {
rs.previous();
break;
}
}
return TaxComponentData.instance(id, name, percentage, debitAccountType, debitAccountData, creditAccountType, creditAccountData,
startDate, historyDatas);
}
public String getSchema() {
return this.schema;
}
}
private static final class TaxComponentHistoryDataMapper implements RowMapper<TaxComponentHistoryData> {
@Override
public TaxComponentHistoryData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException {
final BigDecimal percentage = rs.getBigDecimal("historyPercentage");
final LocalDate startDate = JdbcSupport.getLocalDate(rs, "historyStartDate");
final LocalDate endDate = JdbcSupport.getLocalDate(rs, "historyEndDate");
return new TaxComponentHistoryData(percentage, startDate, endDate);
}
}
private static final class TaxGroupMapper implements RowMapper<TaxGroupData> {
private final String schema;
private final TaxGroupMappingsDataMapper taxGroupMappingsDataMapper = new TaxGroupMappingsDataMapper();
TaxGroupMapper() {
StringBuilder sb = new StringBuilder();
sb.append("tg.id as id, tg.name as name,");
sb.append("tgm.id as mappingId,");
sb.append("tc.id as taxComponentId, tc.name as taxComponentName,");
sb.append("tgm.start_date as startDate, tgm.end_date as endDate ");
sb.append(" from m_tax_group tg ");
sb.append(" inner join m_tax_group_mappings tgm on tgm.tax_group_id = tg.id ");
sb.append(" inner join m_tax_component tc on tc.id = tgm.tax_component_id ");
this.schema = sb.toString();
}
@Override
public TaxGroupData mapRow(ResultSet rs, int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final String name = rs.getString("name");
final Collection<TaxGroupMappingsData> taxAssociations = new ArrayList<>();
taxAssociations.add(this.taxGroupMappingsDataMapper.mapRow(rs, rowNum));
while (rs.next()) {
if (id.equals(rs.getLong("id"))) {
taxAssociations.add(this.taxGroupMappingsDataMapper.mapRow(rs, rowNum));
} else {
rs.previous();
break;
}
}
return new TaxGroupData(id, name, taxAssociations, null);
}
public String getSchema() {
return this.schema;
}
}
private static final class TaxGroupMappingsDataMapper implements RowMapper<TaxGroupMappingsData> {
@Override
public TaxGroupMappingsData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException {
final Long mappingId = rs.getLong("mappingId");
final Long id = rs.getLong("taxComponentId");
final String name = rs.getString("taxComponentName");
TaxComponentData componentData = TaxComponentData.lookup(id, name);
final LocalDate startDate = JdbcSupport.getLocalDate(rs, "startDate");
final LocalDate endDate = JdbcSupport.getLocalDate(rs, "endDate");
return new TaxGroupMappingsData(mappingId, componentData, startDate, endDate);
}
}
private static final class TaxComponentLookUpMapper implements RowMapper<TaxComponentData> {
private final String schema;
TaxComponentLookUpMapper() {
StringBuilder sb = new StringBuilder();
sb.append("tc.id as id, tc.name as name ");
sb.append(" from m_tax_component tc ");
this.schema = sb.toString();
}
public String getSchema() {
return this.schema;
}
@Override
public TaxComponentData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final String name = rs.getString("name");
return TaxComponentData.lookup(id, name);
}
}
private static final class TaxGroupLookUpMapper implements RowMapper<TaxGroupData> {
private final String schema;
TaxGroupLookUpMapper() {
StringBuilder sb = new StringBuilder();
sb.append("tg.id as id, tg.name as name ");
sb.append(" from m_tax_group tg ");
this.schema = sb.toString();
}
public String getSchema() {
return this.schema;
}
@Override
public TaxGroupData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final String name = rs.getString("name");
return TaxGroupData.lookup(id, name);
}
return taxGroupMapper.map(taxGroupRepository.findAll());
}
}
@@ -25,6 +25,8 @@ import org.apache.fineract.portfolio.tax.domain.TaxComponentRepository;
import org.apache.fineract.portfolio.tax.domain.TaxComponentRepositoryWrapper;
import org.apache.fineract.portfolio.tax.domain.TaxGroupRepository;
import org.apache.fineract.portfolio.tax.domain.TaxGroupRepositoryWrapper;
import org.apache.fineract.portfolio.tax.mapper.TaxComponentMapper;
import org.apache.fineract.portfolio.tax.mapper.TaxGroupMapper;
import org.apache.fineract.portfolio.tax.serialization.TaxValidator;
import org.apache.fineract.portfolio.tax.service.TaxAssembler;
import org.apache.fineract.portfolio.tax.service.TaxReadPlatformService;
@@ -34,7 +36,6 @@ import org.apache.fineract.portfolio.tax.service.TaxWritePlatformServiceImpl;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
@Configuration
public class TaxConfiguration {
@@ -48,9 +49,11 @@ public class TaxConfiguration {
@Bean
@ConditionalOnMissingBean(TaxReadPlatformService.class)
public TaxReadPlatformService taxReadPlatformService(JdbcTemplate jdbcTemplate,
public TaxReadPlatformService taxReadPlatformService(final TaxComponentRepository taxComponentRepository,
final TaxComponentMapper taxComponentMapper, final TaxGroupRepository taxGroupRepository, final TaxGroupMapper taxGroupMapper,
AccountingDropdownReadPlatformService accountingDropdownReadPlatformService) {
return new TaxReadPlatformServiceImpl(jdbcTemplate, accountingDropdownReadPlatformService);
return new TaxReadPlatformServiceImpl(accountingDropdownReadPlatformService, taxComponentRepository, taxComponentMapper,
taxGroupRepository, taxGroupMapper);
}
@Bean
@@ -44729,7 +44729,7 @@ No Request Body:
</td>
</tr>
<tr class=alt>
<td>debitAcountId</td>
<td>debitAccountId</td>
</tr>
<tr>
<td class=fielddesc>
@@ -44742,7 +44742,7 @@ No Request Body:
</td>
</tr>
<tr class=alt>
<td>debitAcountId</td>
<td>debitAccountId</td>
</tr>
<tr>
<td class=fielddesc>
@@ -44786,13 +44786,13 @@ No Request Body:
<td>debitAccountType</td>
</tr>
<tr class=alt>
<td>debitAcountId</td>
<td>debitAccountId</td>
</tr>
<tr class=alt>
<td>creditAccountType</td>
</tr>
<tr class=alt>
<td>creditAcountId</td>
<td>creditAccountId</td>
</tr>
<tr class=alt>
<td>startDate</td>
@@ -44811,7 +44811,7 @@ No Request Body:
"name": "tax component 1",
"percentage": "10",
"creditAccountType": 2,
"creditAcountId": 4,
"creditAccountId": 4,
"locale": "en",
"dateFormat": "dd MMMM yyyy",
"startDate": "11 April 2016"
@@ -23,9 +23,9 @@ public interface TaxApiConstants {
String nameParamName = "name";
String percentageParamName = "percentage";
String debitAccountTypeParamName = "debitAccountType";
String debitAcountIdParamName = "debitAcountId";
String debitAccountIdParamName = "debitAccountId";
String creditAccountTypeParamName = "creditAccountType";
String creditAcountIdParamName = "creditAcountId";
String creditAccountIdParamName = "creditAccountId";
String startDateParamName = "startDate";
String endDateParamName = "endDate";
@@ -99,7 +99,7 @@ public class TaxComponentApiResource {
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Create a new Tax Component", description = "Creates a new Tax Component\n\n"
+ "Mandatory Fields: name, percentage\n\n"
+ "Optional Fields: debitAccountType, debitAcountId, creditAccountType, creditAcountId, startDate")
+ "Optional Fields: debitAccountType, debitAccountId, creditAccountType, creditAccountId, startDate")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = TaxComponentApiResourceSwagger.PostTaxesComponentsRequest.class)))
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = TaxComponentApiResourceSwagger.PostTaxesComponentsResponse.class))) })
@@ -86,9 +86,13 @@ final class TaxComponentApiResourceSwagger {
@Schema(example = "10")
public Float percentage;
@Schema(example = "2")
public Integer debitAccountType;
@Schema(example = "4")
public Long debitAccountId;
@Schema(example = "4")
public Integer creditAccountType;
@Schema(example = "4")
public Long creditAcountId;
public Long creditAccountId;
@Schema(example = "en")
public String locale;
@Schema(example = "dd MMMM yyyy")
@@ -35,6 +35,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.accounting.glaccount.domain.GLAccount;
import org.apache.fineract.accounting.glaccount.domain.GLAccountType;
@@ -44,6 +45,7 @@ import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.portfolio.tax.api.TaxApiConstants;
@Entity
@Getter
@Table(name = "m_tax_component")
public class TaxComponent extends AbstractAuditableCustom {
@@ -58,14 +60,14 @@ public class TaxComponent extends AbstractAuditableCustom {
@ManyToOne
@JoinColumn(name = "debit_account_id")
private GLAccount debitAcount;
private GLAccount debitAccount;
@Column(name = "credit_account_type_enum")
private Integer creditAccountType;
@ManyToOne
@JoinColumn(name = "credit_account_id")
private GLAccount creditAcount;
private GLAccount creditAccount;
@Column(name = "start_date", nullable = false)
private LocalDate startDate;
@@ -81,24 +83,24 @@ public class TaxComponent extends AbstractAuditableCustom {
}
private TaxComponent(final String name, final BigDecimal percentage, final GLAccountType debitAccountType, final GLAccount debitAcount,
final GLAccountType creditAccountType, final GLAccount creditAcount, final LocalDate startDate) {
private TaxComponent(final String name, final BigDecimal percentage, final GLAccountType debitAccountType, final GLAccount debitAccount,
final GLAccountType creditAccountType, final GLAccount creditAccount, final LocalDate startDate) {
this.name = name;
this.percentage = percentage;
if (debitAccountType != null) {
this.debitAccountType = debitAccountType.getValue();
}
this.debitAcount = debitAcount;
this.debitAccount = debitAccount;
if (creditAccountType != null) {
this.creditAccountType = creditAccountType.getValue();
}
this.creditAcount = creditAcount;
this.creditAccount = creditAccount;
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);
final GLAccount debitAccount, final GLAccountType creditAccountType, final GLAccount creditAccount, final LocalDate startDate) {
return new TaxComponent(name, percentage, debitAccountType, debitAccount, creditAccountType, creditAccount, startDate);
}
public Map<String, Object> update(final JsonCommand command) {
@@ -193,7 +195,7 @@ public class TaxComponent extends AbstractAuditableCustom {
}
public GLAccount getDebitAcount() {
return this.debitAcount;
return this.debitAccount;
}
public Integer getCreditAccountType() {
@@ -201,6 +203,6 @@ public class TaxComponent extends AbstractAuditableCustom {
}
public GLAccount getCreditAcount() {
return this.creditAcount;
return this.creditAccount;
}
}
@@ -27,11 +27,13 @@ import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.Getter;
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
@Getter
@Table(name = "m_tax_group_mappings")
public class TaxGroupMappings extends AbstractAuditableCustom {
@@ -18,25 +18,21 @@
*/
package org.apache.fineract.portfolio.tax.handler;
import lombok.AllArgsConstructor;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.tax.service.TaxWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@AllArgsConstructor
@CommandType(entity = "TAXCOMPONENT", action = "CREATE")
public class CreateTaxComponentCommandHandler implements NewCommandSourceHandler {
private final TaxWritePlatformService taxWritePlatformService;
@Autowired
public CreateTaxComponentCommandHandler(final TaxWritePlatformService taxWritePlatformService) {
this.taxWritePlatformService = taxWritePlatformService;
}
@Override
public CommandProcessingResult processCommand(JsonCommand jsonCommand) {
return this.taxWritePlatformService.createTaxComponent(jsonCommand);
@@ -18,25 +18,21 @@
*/
package org.apache.fineract.portfolio.tax.handler;
import lombok.AllArgsConstructor;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.tax.service.TaxWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@AllArgsConstructor
@CommandType(entity = "TAXGROUP", action = "CREATE")
public class CreateTaxGroupCommandHandler implements NewCommandSourceHandler {
private final TaxWritePlatformService taxWritePlatformService;
@Autowired
public CreateTaxGroupCommandHandler(final TaxWritePlatformService taxWritePlatformService) {
this.taxWritePlatformService = taxWritePlatformService;
}
@Override
public CommandProcessingResult processCommand(JsonCommand jsonCommand) {
return this.taxWritePlatformService.createTaxGroup(jsonCommand);
@@ -18,25 +18,21 @@
*/
package org.apache.fineract.portfolio.tax.handler;
import lombok.AllArgsConstructor;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.tax.service.TaxWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@AllArgsConstructor
@CommandType(entity = "TAXCOMPONENT", action = "UPDATE")
public class UpdateTaxComponentCommandHandler implements NewCommandSourceHandler {
private final TaxWritePlatformService taxWritePlatformService;
@Autowired
public UpdateTaxComponentCommandHandler(final TaxWritePlatformService taxWritePlatformService) {
this.taxWritePlatformService = taxWritePlatformService;
}
@Override
public CommandProcessingResult processCommand(JsonCommand jsonCommand) {
return this.taxWritePlatformService.updateTaxComponent(jsonCommand.entityId(), jsonCommand);
@@ -18,25 +18,21 @@
*/
package org.apache.fineract.portfolio.tax.handler;
import lombok.AllArgsConstructor;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.tax.service.TaxWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@AllArgsConstructor
@CommandType(entity = "TAXGROUP", action = "UPDATE")
public class UpdateTaxGroupCommandHandler implements NewCommandSourceHandler {
private final TaxWritePlatformService taxWritePlatformService;
@Autowired
public UpdateTaxGroupCommandHandler(final TaxWritePlatformService taxWritePlatformService) {
this.taxWritePlatformService = taxWritePlatformService;
}
@Override
public CommandProcessingResult processCommand(JsonCommand jsonCommand) {
return this.taxWritePlatformService.updateTaxGroup(jsonCommand.entityId(), jsonCommand);
@@ -0,0 +1,44 @@
/**
* 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.mapper;
import java.util.List;
import org.apache.fineract.accounting.glaccount.mapper.GlAccountMapper;
import org.apache.fineract.accounting.glaccount.mapper.GlAccountTypeMapper;
import org.apache.fineract.infrastructure.core.config.MapstructMapperConfig;
import org.apache.fineract.portfolio.tax.data.TaxComponentData;
import org.apache.fineract.portfolio.tax.domain.TaxComponent;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@Mapper(config = MapstructMapperConfig.class, uses = { GlAccountMapper.class, GlAccountTypeMapper.class })
public interface TaxComponentMapper {
@Mapping(target = "creditAccount", source = "taxComponent.creditAccount")
@Mapping(target = "debitAccount", source = "taxComponent.debitAccount")
@Mapping(target = "creditAccountType", source = "taxComponent.creditAccountType")
@Mapping(target = "debitAccountType", source = "taxComponent.debitAccountType")
@Mapping(target = "glAccountOptions", ignore = true)
@Mapping(target = "glAccountTypeOptions", ignore = true)
@Mapping(target = "taxComponentHistories", ignore = true)
TaxComponentData map(TaxComponent taxComponent);
List<TaxComponentData> map(List<TaxComponent> taxComponents);
}
@@ -0,0 +1,37 @@
/**
* 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.mapper;
import java.util.List;
import org.apache.fineract.infrastructure.core.config.MapstructMapperConfig;
import org.apache.fineract.portfolio.tax.data.TaxGroupData;
import org.apache.fineract.portfolio.tax.domain.TaxGroup;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@Mapper(config = MapstructMapperConfig.class, uses = { TaxGroupMappingsMapper.class })
public interface TaxGroupMapper {
@Mapping(target = "taxAssociations", source = "taxGroup.taxGroupMappings")
@Mapping(target = "taxComponents", ignore = true)
TaxGroupData map(TaxGroup taxGroup);
List<TaxGroupData> map(List<TaxGroup> taxGroups);
}
@@ -0,0 +1,34 @@
/**
* 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.mapper;
import java.util.List;
import org.apache.fineract.infrastructure.core.config.MapstructMapperConfig;
import org.apache.fineract.portfolio.tax.data.TaxGroupMappingsData;
import org.apache.fineract.portfolio.tax.domain.TaxGroupMappings;
import org.mapstruct.Mapper;
@Mapper(config = MapstructMapperConfig.class, uses = { TaxComponentMapper.class })
public interface TaxGroupMappingsMapper {
TaxGroupMappingsData map(TaxGroupMappings taxGroupMapping);
List<TaxGroupMappingsData> map(List<TaxGroupMappings> taxGroupMappings);
}
@@ -63,8 +63,8 @@ public class TaxValidator {
public static final String COMPONENT_START_DATE = "component.start.date";
private static final Set<String> SUPPORTED_TAX_COMPONENT_CREATE_PARAMETERS = new HashSet<>(
Arrays.asList(DATE_FORMAT, LOCALE, TaxApiConstants.nameParamName, TaxApiConstants.percentageParamName,
TaxApiConstants.startDateParamName, TaxApiConstants.debitAccountTypeParamName, TaxApiConstants.debitAcountIdParamName,
TaxApiConstants.creditAccountTypeParamName, TaxApiConstants.creditAcountIdParamName));
TaxApiConstants.startDateParamName, TaxApiConstants.debitAccountTypeParamName, TaxApiConstants.debitAccountIdParamName,
TaxApiConstants.creditAccountTypeParamName, TaxApiConstants.creditAccountIdParamName));
private static final Set<String> SUPPORTED_TAX_COMPONENT_UPDATE_PARAMETERS = new HashSet<>(Arrays.asList(DATE_FORMAT, LOCALE,
TaxApiConstants.nameParamName, TaxApiConstants.percentageParamName, TaxApiConstants.startDateParamName));
private static final Set<String> SUPPORTED_TAX_GROUP_PARAMETERS = new HashSet<>(
@@ -111,11 +111,11 @@ public class TaxValidator {
.isOneOfTheseValues(GLAccountType.ASSET.getValue(), GLAccountType.LIABILITY.getValue(), GLAccountType.EQUITY.getValue(),
GLAccountType.INCOME.getValue(), GLAccountType.EXPENSE.getValue());
final Long debitAccountId = this.fromApiJsonHelper.extractLongNamed(TaxApiConstants.debitAcountIdParamName, element);
baseDataValidator.reset().parameter(TaxApiConstants.debitAcountIdParamName).value(debitAccountId).longGreaterThanZero();
final Long debitAccountId = this.fromApiJsonHelper.extractLongNamed(TaxApiConstants.debitAccountIdParamName, element);
baseDataValidator.reset().parameter(TaxApiConstants.debitAccountIdParamName).value(debitAccountId).longGreaterThanZero();
if (debitAccountType != null || debitAccountId != null) {
baseDataValidator.reset().parameter(TaxApiConstants.debitAccountTypeParamName).value(debitAccountType).notBlank();
baseDataValidator.reset().parameter(TaxApiConstants.debitAcountIdParamName).value(debitAccountId).notBlank();
baseDataValidator.reset().parameter(TaxApiConstants.debitAccountIdParamName).value(debitAccountId).notBlank();
}
final Integer creditAccountType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(TaxApiConstants.creditAccountTypeParamName,
@@ -124,10 +124,10 @@ public class TaxValidator {
.isOneOfTheseValues(GLAccountType.ASSET.getValue(), GLAccountType.LIABILITY.getValue(), GLAccountType.EQUITY.getValue(),
GLAccountType.INCOME.getValue(), GLAccountType.EXPENSE.getValue());
final Long creditAccountId = this.fromApiJsonHelper.extractLongNamed(TaxApiConstants.creditAcountIdParamName, element);
baseDataValidator.reset().parameter(TaxApiConstants.creditAcountIdParamName).value(creditAccountId).longGreaterThanZero();
final Long creditAccountId = this.fromApiJsonHelper.extractLongNamed(TaxApiConstants.creditAccountIdParamName, element);
baseDataValidator.reset().parameter(TaxApiConstants.creditAccountIdParamName).value(creditAccountId).longGreaterThanZero();
if (creditAccountType != null || creditAccountId != null) {
baseDataValidator.reset().parameter(TaxApiConstants.creditAcountIdParamName).value(creditAccountId).notBlank();
baseDataValidator.reset().parameter(TaxApiConstants.creditAccountIdParamName).value(creditAccountId).notBlank();
baseDataValidator.reset().parameter(TaxApiConstants.creditAccountTypeParamName).value(creditAccountType).notBlank();
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
@@ -0,0 +1,117 @@
/**
* 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.integrationtests;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.fineract.client.models.GetTaxesComponentsResponse;
import org.apache.fineract.client.models.GetTaxesGroupResponse;
import org.apache.fineract.client.models.GetTaxesGroupTaxAssociations;
import org.apache.fineract.client.models.PostTaxesComponentsRequest;
import org.apache.fineract.client.models.PostTaxesComponentsResponse;
import org.apache.fineract.client.models.PostTaxesGroupRequest;
import org.apache.fineract.client.models.PostTaxesGroupResponse;
import org.apache.fineract.client.models.PostTaxesGroupTaxComponents;
import org.apache.fineract.integrationtests.common.TaxComponentHelper;
import org.apache.fineract.integrationtests.common.TaxGroupHelper;
import org.apache.fineract.integrationtests.common.Utils;
import org.apache.fineract.integrationtests.common.accounting.Account;
import org.apache.fineract.integrationtests.common.accounting.AccountHelper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class TaxesTest {
@Test
public void createTaxComponentTest() {
Long taxComponentId = createTaxComponentWithLiabilityToCredit("taxComponent");
GetTaxesComponentsResponse taxComponentDetails = TaxComponentHelper.retrieveTaxComponent(taxComponentId);
Assertions.assertNotNull(taxComponentDetails);
Assertions.assertNotNull(taxComponentDetails.getId());
Assertions.assertEquals(taxComponentId, taxComponentDetails.getId());
taxComponentId = createTaxComponentWithLiabilityToDebit("taxComponent");
taxComponentDetails = TaxComponentHelper.retrieveTaxComponent(taxComponentId);
Assertions.assertNotNull(taxComponentDetails);
Assertions.assertNotNull(taxComponentDetails.getId());
Assertions.assertEquals(taxComponentId, taxComponentDetails.getId());
}
@Test
public void createTaxGroupTest() {
List<GetTaxesGroupResponse> allTaxGroups = TaxGroupHelper.retrieveAllTaxGroups();
Assertions.assertNotNull(allTaxGroups);
final Long taxComponentId = createTaxComponentWithLiabilityToCredit("taxComponent");
final Set<PostTaxesGroupTaxComponents> taxComponentsSet = new HashSet<>();
taxComponentsSet.add(new PostTaxesGroupTaxComponents().taxComponentId(taxComponentId).startDate("01 January 2023"));
final PostTaxesGroupRequest taxGroupRequest = new PostTaxesGroupRequest().name(Utils.randomStringGenerator("TAX_GRP_", 4))
.taxComponents(taxComponentsSet).dateFormat("dd MMMM yyyy").locale("en");
final PostTaxesGroupResponse taxGroupResponse = TaxGroupHelper.createTaxGroup(taxGroupRequest);
Assertions.assertNotNull(taxGroupResponse);
Assertions.assertNotNull(taxGroupResponse.getResourceId());
final GetTaxesGroupResponse taxGroupDetails = TaxGroupHelper.retrieveTaxGroup(taxGroupResponse.getResourceId());
Assertions.assertNotNull(taxGroupDetails);
Assertions.assertEquals(taxGroupResponse.getResourceId(), taxGroupDetails.getId());
Assertions.assertFalse(taxGroupDetails.getTaxAssociations().isEmpty());
GetTaxesGroupTaxAssociations taxAssociation = taxGroupDetails.getTaxAssociations().iterator().next();
Assertions.assertNotNull(taxAssociation);
Assertions.assertEquals(taxComponentId, taxAssociation.getTaxComponent().getId());
allTaxGroups = TaxGroupHelper.retrieveAllTaxGroups();
Assertions.assertNotNull(allTaxGroups);
Assertions.assertTrue(allTaxGroups.size() > 0);
}
private Long createTaxComponentWithLiabilityToCredit(final String taxComponentPrefix) {
final Account taxComponentGlAccount = AccountHelper.createLiabilityGlAccount(taxComponentPrefix);
final PostTaxesComponentsRequest taxComponentRequest = new PostTaxesComponentsRequest()
.name(Utils.randomStringGenerator(taxComponentPrefix, 4)).percentage(12.0f).startDate("01 January 2023")
.creditAccountType(Integer.valueOf(taxComponentGlAccount.getAccountType().toString()))
.creditAccountId(taxComponentGlAccount.getAccountID().longValue()).dateFormat(Utils.DATE_FORMAT).locale(Utils.LOCALE);
final PostTaxesComponentsResponse taxComponentRespose = TaxComponentHelper.createTaxComponent(taxComponentRequest);
Assertions.assertNotNull(taxComponentRespose);
Assertions.assertNotNull(taxComponentRespose.getResourceId());
return taxComponentRespose.getResourceId();
}
private Long createTaxComponentWithLiabilityToDebit(final String taxComponentPrefix) {
final Account taxComponentGlAccount = AccountHelper.createLiabilityGlAccount(taxComponentPrefix);
final PostTaxesComponentsRequest taxComponentRequest = new PostTaxesComponentsRequest()
.name(Utils.randomStringGenerator(taxComponentPrefix, 4)).percentage(12.0f).startDate("01 January 2023")
.debitAccountType(Integer.valueOf(taxComponentGlAccount.getAccountType().toString()))
.debitAccountId(taxComponentGlAccount.getAccountID().longValue()).dateFormat(Utils.DATE_FORMAT).locale(Utils.LOCALE);
final PostTaxesComponentsResponse taxComponentRespose = TaxComponentHelper.createTaxComponent(taxComponentRequest);
Assertions.assertNotNull(taxComponentRespose);
Assertions.assertNotNull(taxComponentRespose.getResourceId());
return taxComponentRespose.getResourceId();
}
}
@@ -22,6 +22,7 @@ import com.google.gson.Gson;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
import java.util.HashMap;
import org.apache.fineract.client.models.GetTaxesComponentsResponse;
import org.apache.fineract.client.models.PostTaxesComponentsRequest;
import org.apache.fineract.client.models.PostTaxesComponentsResponse;
import org.apache.fineract.client.util.Calls;
@@ -57,7 +58,7 @@ public final class TaxComponentHelper {
final HashMap<String, String> map = getBasicTaxComponentMap(percentage);
if (creditAccountId != null) {
map.put("creditAccountType", Account.AccountType.LIABILITY.toString());
map.put("creditAcountId", String.valueOf(creditAccountId));
map.put("creditAccountId", String.valueOf(creditAccountId));
}
LOG.info("map : {}", map);
return new Gson().toJson(map);
@@ -81,4 +82,8 @@ public final class TaxComponentHelper {
return Calls.ok(FineractClientHelper.getFineractClient().taxComponents.createTaxComponent(request));
}
public static GetTaxesComponentsResponse retrieveTaxComponent(Long taxComponentId) {
return Calls.ok(FineractClientHelper.getFineractClient().taxComponents.retrieveTaxComponent(taxComponentId));
}
}
@@ -25,6 +25,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import org.apache.fineract.client.models.GetTaxesGroupResponse;
import org.apache.fineract.client.models.PostTaxesGroupRequest;
import org.apache.fineract.client.models.PostTaxesGroupResponse;
import org.apache.fineract.client.util.Calls;
@@ -91,4 +92,12 @@ public final class TaxGroupHelper {
return Calls.ok(FineractClientHelper.getFineractClient().taxGroups.createTaxGroup(request));
}
public static GetTaxesGroupResponse retrieveTaxGroup(Long taxGroupId) {
return Calls.ok(FineractClientHelper.getFineractClient().taxGroups.retrieveTaxGroup(taxGroupId));
}
public static List<GetTaxesGroupResponse> retrieveAllTaxGroups() {
return Calls.ok(FineractClientHelper.getFineractClient().taxGroups.retrieveAllTaxGroups());
}
}
@@ -88,6 +88,7 @@ public final class Utils {
public static final String TENANT_TIME_ZONE = "Asia/Kolkata";
public static final String DATE_FORMAT = "dd MMMM yyyy";
public static final String DATE_TIME_FORMAT = "dd MMMM yyyy HH:mm";
public static final String LOCALE = "en";
public static final DateTimeFormatter dateFormatter = new DateTimeFormatterBuilder().appendPattern(DATE_FORMAT).toFormatter();
public static final DateTimeFormatter dateTimeFormatter = new DateTimeFormatterBuilder().appendPattern(DATE_TIME_FORMAT).toFormatter();
private static final Logger LOG = LoggerFactory.getLogger(Utils.class);
@@ -21,7 +21,9 @@ package org.apache.fineract.integrationtests.common.accounting;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import org.apache.fineract.accounting.glaccount.domain.GLAccountType;
import org.apache.fineract.client.models.DeleteGLAccountsResponse;
import org.apache.fineract.client.models.GetGLAccountsResponse;
import org.apache.fineract.client.models.PostGLAccountsRequest;
@@ -31,6 +33,7 @@ import org.apache.fineract.client.models.PutGLAccountsResponse;
import org.apache.fineract.client.util.Calls;
import org.apache.fineract.integrationtests.common.FineractClientHelper;
import org.apache.fineract.integrationtests.common.Utils;
import org.junit.jupiter.api.Assertions;
@SuppressWarnings("rawtypes")
public class AccountHelper {
@@ -161,4 +164,49 @@ public class AccountHelper {
public static GetGLAccountsResponse getGLAccount(final Long glAccountId) {
return Calls.ok(FineractClientHelper.getFineractClient().glAccounts.retreiveAccount(glAccountId, false));
}
public static Account createAssetGlAccount(final String glAccountName) {
PostGLAccountsResponse postGLAccountsResponse = createGLAccount(
createGlAccount(GLAccountType.ASSET, Utils.uniqueRandomStringGenerator(glAccountName, 6), null));
Assertions.assertNotNull(postGLAccountsResponse);
return new Account(postGLAccountsResponse.getResourceId().intValue(), Account.AccountType.ASSET);
}
public static Account createLiabilityGlAccount(final String glAccountName) {
PostGLAccountsResponse postGLAccountsResponse = createGLAccount(
createGlAccount(GLAccountType.LIABILITY, Utils.uniqueRandomStringGenerator(glAccountName, 6), null));
Assertions.assertNotNull(postGLAccountsResponse);
return new Account(postGLAccountsResponse.getResourceId().intValue(), Account.AccountType.LIABILITY);
}
public static Account createIncomeGlAccount(final String glAccountName) {
PostGLAccountsResponse postGLAccountsResponse = createGLAccount(
createGlAccount(GLAccountType.INCOME, Utils.uniqueRandomStringGenerator(glAccountName, 6), null));
Assertions.assertNotNull(postGLAccountsResponse);
return new Account(postGLAccountsResponse.getResourceId().intValue(), Account.AccountType.INCOME);
}
public static Account createExpenseGlAccount(final String glAccountName) {
PostGLAccountsResponse postGLAccountsResponse = createGLAccount(
createGlAccount(GLAccountType.EXPENSE, Utils.uniqueRandomStringGenerator(glAccountName, 6), null));
Assertions.assertNotNull(postGLAccountsResponse);
return new Account(postGLAccountsResponse.getResourceId().intValue(), Account.AccountType.EXPENSE);
}
public static Account createEquityGlAccount(final String glAccountName) {
PostGLAccountsResponse postGLAccountsResponse = createGLAccount(
createGlAccount(GLAccountType.EQUITY, Utils.uniqueRandomStringGenerator(glAccountName, 6), null));
Assertions.assertNotNull(postGLAccountsResponse);
return new Account(postGLAccountsResponse.getResourceId().intValue(), Account.AccountType.EQUITY);
}
public static PostGLAccountsRequest createGlAccount(final GLAccountType glAccountType, final String glAccountName,
final Long parentAccountId) {
return new PostGLAccountsRequest().type(glAccountType.getValue()).glCode(createGlCode(glAccountType)).manualEntriesAllowed(true)
.usage(1).parentId(parentAccountId).description(glAccountName).name(glAccountName);
}
public static String createGlCode(final GLAccountType glAccountType) {
return Utils.uniqueRandomStringGenerator(glAccountType.getValue().toString() + Calendar.getInstance().getTimeInMillis(), 2);
}
}