Repository: incubator-fineract
Updated Branches:
  refs/heads/develop 446ff4403 -> 9fedac2ba


http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/3015747f/fineract-provider/src/main/java/org/apache/fineract/portfolio/tax/service/TaxReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/tax/service/TaxReadPlatformServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/tax/service/TaxReadPlatformServiceImpl.java
new file mode 100644
index 0000000..743efd6
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/tax/service/TaxReadPlatformServiceImpl.java
@@ -0,0 +1,305 @@
+/**
+ * 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.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+
+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.infrastructure.core.service.RoutingDataSource;
+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.joda.time.LocalDate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.stereotype.Service;
+
+@Service
+public class TaxReadPlatformServiceImpl implements TaxReadPlatformService {
+
+    final TaxComponentMapper taxComponentMapper = new TaxComponentMapper();
+    final TaxGroupMapper taxGroupMapper = new TaxGroupMapper();
+    final TaxComponentLookUpMapper taxComponentLookUpMapper = new 
TaxComponentLookUpMapper();
+    final TaxGroupLookUpMapper taxGroupLookUpMapper = new 
TaxGroupLookUpMapper();
+
+    private final JdbcTemplate jdbcTemplate;
+    private final AccountingDropdownReadPlatformService 
accountingDropdownReadPlatformService;
+
+    @Autowired
+    public TaxReadPlatformServiceImpl(final RoutingDataSource dataSource,
+            final AccountingDropdownReadPlatformService 
accountingDropdownReadPlatformService) {
+        this.jdbcTemplate = new JdbcTemplate(dataSource);
+        this.accountingDropdownReadPlatformService = 
accountingDropdownReadPlatformService;
+    }
+
+    @Override
+    public Collection<TaxComponentData> retrieveAllTaxComponents() {
+        String sql = "select " + this.taxComponentMapper.getSchema();
+        return this.jdbcTemplate.query(sql, this.taxComponentMapper);
+    }
+
+    @Override
+    public TaxComponentData retrieveTaxComponentData(final Long id) {
+        String sql = "select " + this.taxComponentMapper.getSchema() + " where 
tc.id=?";
+        return this.jdbcTemplate.queryForObject(sql, this.taxComponentMapper, 
new Object[] { id });
+    }
+
+    @Override
+    public TaxComponentData retrieveTaxComponentTemplate() {
+        return 
TaxComponentData.template(this.accountingDropdownReadPlatformService.retrieveAccountMappingOptions(),
+                
this.accountingDropdownReadPlatformService.retrieveGLAccountTypeOptions());
+    }
+
+    @Override
+    public Collection<TaxGroupData> retrieveAllTaxGroups() {
+        String sql = "select " + this.taxGroupMapper.getSchema();
+        return this.jdbcTemplate.query(sql, this.taxGroupMapper);
+    }
+
+    @Override
+    public TaxGroupData retrieveTaxGroupData(final Long id) {
+        String sql = "select " + this.taxGroupMapper.getSchema() + " where 
tg.id=?";
+        return this.jdbcTemplate.queryForObject(sql, this.taxGroupMapper, new 
Object[] { id });
+    }
+
+    @Override
+    public TaxGroupData retrieveTaxGroupWithTemplate(final Long id) {
+        TaxGroupData taxGroupData = retrieveTaxGroupData(id);
+        taxGroupData = TaxGroupData.template(taxGroupData, 
retrieveTaxComponentsForLookUp());
+        return taxGroupData;
+    }
+
+    @Override
+    public TaxGroupData retrieveTaxGroupTemplate() {
+        return TaxGroupData.template(retrieveTaxComponentsForLookUp());
+    }
+
+    private Collection<TaxComponentData> retrieveTaxComponentsForLookUp() {
+        String sql = "select " + this.taxComponentLookUpMapper.getSchema();
+        return this.jdbcTemplate.query(sql, this.taxComponentLookUpMapper);
+    }
+
+    @Override
+    public Collection<TaxGroupData> retrieveTaxGroupsForLookUp() {
+        String sql = "select " + this.taxGroupLookUpMapper.getSchema();
+        return this.jdbcTemplate.query(sql, this.taxGroupLookUpMapper);
+    }
+
+    private static final class TaxComponentMapper implements 
RowMapper<TaxComponentData> {
+
+        private final String schema;
+        private TaxComponentHistoryDataMapper componentHistoryDataMapper = new 
TaxComponentHistoryDataMapper();
+
+        public 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(debitAccountId, 
debitAccountName, 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(creditAccountId, 
creditAccountName, 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();
+
+        public 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 TaxGroupData.instance(id, name, taxAssociations);
+        }
+
+        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;
+
+        public 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;
+
+        public 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);
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/3015747f/fineract-provider/src/main/java/org/apache/fineract/portfolio/tax/service/TaxUtils.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/tax/service/TaxUtils.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/tax/service/TaxUtils.java
new file mode 100644
index 0000000..02368df
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/tax/service/TaxUtils.java
@@ -0,0 +1,94 @@
+/**
+ * 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.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
+import org.apache.fineract.portfolio.tax.domain.TaxComponent;
+import org.apache.fineract.portfolio.tax.domain.TaxGroupMappings;
+import org.joda.time.LocalDate;
+
+public class TaxUtils {
+
+    public static Map<TaxComponent, BigDecimal> splitTax(final BigDecimal 
amount, final LocalDate date,
+            final List<TaxGroupMappings> taxGroupMappings, final int scale) {
+        Map<TaxComponent, BigDecimal> map = new HashMap<>(3);
+        if (amount != null) {
+            final double amountVal = amount.doubleValue();
+            double cent_percentage = Double.valueOf("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 BigDecimal incomeAmount(final BigDecimal amount, final 
LocalDate date, final List<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 addTax(final BigDecimal amount, final LocalDate 
date, final List<TaxGroupMappings> taxGroupMappings,
+            final int scale) {
+        BigDecimal totalAmount = null;
+        if (amount != null && amount.compareTo(BigDecimal.ZERO) == 1) {
+            double percentageVal = 0;
+            double amountVal = amount.doubleValue();
+            double cent_percentage = Double.valueOf("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;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/3015747f/fineract-provider/src/main/java/org/apache/fineract/portfolio/tax/service/TaxWritePlatformService.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/tax/service/TaxWritePlatformService.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/tax/service/TaxWritePlatformService.java
new file mode 100644
index 0000000..950b62b
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/tax/service/TaxWritePlatformService.java
@@ -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.service;
+
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+
+public interface TaxWritePlatformService {
+
+    public CommandProcessingResult createTaxComponent(JsonCommand command);
+
+    public CommandProcessingResult updateTaxComponent(final Long id, final 
JsonCommand command);
+
+    public CommandProcessingResult createTaxGroup(JsonCommand command);
+
+    public CommandProcessingResult updateTaxGroup(final Long id, final 
JsonCommand command);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/3015747f/fineract-provider/src/main/java/org/apache/fineract/portfolio/tax/service/TaxWritePlatformServiceImpl.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/tax/service/TaxWritePlatformServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/tax/service/TaxWritePlatformServiceImpl.java
new file mode 100644
index 0000000..a96b57d
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/tax/service/TaxWritePlatformServiceImpl.java
@@ -0,0 +1,111 @@
+/**
+ * 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.util.List;
+import java.util.Map;
+
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import 
org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
+import org.apache.fineract.portfolio.tax.domain.TaxComponent;
+import org.apache.fineract.portfolio.tax.domain.TaxComponentRepository;
+import org.apache.fineract.portfolio.tax.domain.TaxComponentRepositoryWrapper;
+import org.apache.fineract.portfolio.tax.domain.TaxGroup;
+import org.apache.fineract.portfolio.tax.domain.TaxGroupMappings;
+import org.apache.fineract.portfolio.tax.domain.TaxGroupRepository;
+import org.apache.fineract.portfolio.tax.domain.TaxGroupRepositoryWrapper;
+import org.apache.fineract.portfolio.tax.serialization.TaxValidator;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class TaxWritePlatformServiceImpl implements TaxWritePlatformService {
+
+    private final TaxValidator validator;
+    private final TaxAssembler taxAssembler;
+    private final TaxComponentRepository taxComponentRepository;
+    private final TaxComponentRepositoryWrapper taxComponentRepositoryWrapper;
+    private final TaxGroupRepository taxGroupRepository;
+    private final TaxGroupRepositoryWrapper taxGroupRepositoryWrapper;
+
+    @Autowired
+    public TaxWritePlatformServiceImpl(final TaxValidator validator, final 
TaxAssembler taxAssembler,
+            final TaxComponentRepository taxComponentRepository, final 
TaxGroupRepository taxGroupRepository,
+            final TaxComponentRepositoryWrapper taxComponentRepositoryWrapper, 
final TaxGroupRepositoryWrapper taxGroupRepositoryWrapper) {
+        this.validator = validator;
+        this.taxAssembler = taxAssembler;
+        this.taxComponentRepository = taxComponentRepository;
+        this.taxGroupRepository = taxGroupRepository;
+        this.taxComponentRepositoryWrapper = taxComponentRepositoryWrapper;
+        this.taxGroupRepositoryWrapper = taxGroupRepositoryWrapper;
+    }
+
+    @Override
+    public CommandProcessingResult createTaxComponent(final JsonCommand 
command) {
+        this.validator.validateForTaxComponentCreate(command.json());
+        TaxComponent taxComponent = 
this.taxAssembler.assembleTaxComponentFrom(command);
+        this.taxComponentRepository.save(taxComponent);
+        return new CommandProcessingResultBuilder() //
+                .withCommandId(command.commandId()) //
+                .withEntityId(taxComponent.getId()) //
+                .build();
+    }
+
+    @Override
+    public CommandProcessingResult updateTaxComponent(final Long id, final 
JsonCommand command) {
+        this.validator.validateForTaxComponentUpdate(command.json());
+        final TaxComponent taxComponent = 
this.taxComponentRepositoryWrapper.findOneWithNotFoundDetection(id);
+        this.validator.validateStartDate(taxComponent.startDate(), command);
+        Map<String, Object> changes = taxComponent.update(command);
+        this.validator.validateTaxComponentForUpdate(taxComponent);
+        this.taxComponentRepository.save(taxComponent);
+        return new CommandProcessingResultBuilder() //
+                .withEntityId(id) //
+                .with(changes).build();
+    }
+
+    @Override
+    public CommandProcessingResult createTaxGroup(final JsonCommand command) {
+        this.validator.validateForTaxGroupCreate(command.json());
+        final TaxGroup taxGroup = 
this.taxAssembler.assembleTaxGroupFrom(command);
+        this.validator.validateTaxGroup(taxGroup);
+        this.taxGroupRepository.save(taxGroup);
+        return new CommandProcessingResultBuilder() //
+                .withCommandId(command.commandId()) //
+                .withEntityId(taxGroup.getId()) //
+                .build();
+    }
+
+    @Override
+    public CommandProcessingResult updateTaxGroup(final Long id, final 
JsonCommand command) {
+        this.validator.validateForTaxGroupUpdate(command.json());
+        final TaxGroup taxGroup = 
this.taxGroupRepositoryWrapper.findOneWithNotFoundDetection(id);
+        final boolean isUpdate = true;
+        List<TaxGroupMappings> groupMappings = 
this.taxAssembler.assembleTaxGroupMappingsFrom(command, isUpdate);
+        this.validator.validateTaxGroupEndDateAndTaxComponent(taxGroup, 
groupMappings);
+        Map<String, Object> changes = taxGroup.update(command, groupMappings);
+        this.validator.validateTaxGroup(taxGroup);
+        this.taxGroupRepository.save(taxGroup);
+        return new CommandProcessingResultBuilder() //
+                .withEntityId(id) //
+                .with(changes).build();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/3015747f/fineract-provider/src/main/resources/sql/migrations/core_db/V298__savings_interest_tax.sql
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/resources/sql/migrations/core_db/V298__savings_interest_tax.sql
 
b/fineract-provider/src/main/resources/sql/migrations/core_db/V298__savings_interest_tax.sql
new file mode 100644
index 0000000..1bc0854
--- /dev/null
+++ 
b/fineract-provider/src/main/resources/sql/migrations/core_db/V298__savings_interest_tax.sql
@@ -0,0 +1,111 @@
+CREATE TABLE `m_tax_component` (
+       `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
+       `name` VARCHAR(50) NOT NULL,
+       `percentage` DECIMAL(19,6) NOT NULL,
+       `debit_account_type_enum` SMALLINT(2) NULL DEFAULT NULL,
+       `debit_account_id` BIGINT(20) NULL DEFAULT NULL,
+       `credit_account_type_enum` SMALLINT(2) NULL DEFAULT NULL,
+       `credit_account_id` BIGINT(20) NULL DEFAULT NULL,
+       `start_date` DATE NOT NULL,
+       `createdby_id` BIGINT(20) NOT NULL,
+       `created_date` DATETIME NOT NULL,
+       `lastmodifiedby_id` BIGINT(20) NOT NULL,
+       `lastmodified_date` DATETIME NOT NULL,
+       PRIMARY KEY (`id`),
+       INDEX `FK_tax_component_debit_gl_account` (`debit_account_id`),
+       INDEX `FK_tax_component_credit_gl_account` (`credit_account_id`),
+       INDEX `FK_tax_component_createdby` (`createdby_id`),
+       INDEX `FK_tax_component_lastmodifiedby` (`lastmodifiedby_id`),
+       CONSTRAINT `FK_tax_component_createdby` FOREIGN KEY (`createdby_id`) 
REFERENCES `m_appuser` (`id`),
+       CONSTRAINT `FK_tax_component_credit_gl_account` FOREIGN KEY 
(`credit_account_id`) REFERENCES `acc_gl_account` (`id`),
+       CONSTRAINT `FK_tax_component_debit_gl_account` FOREIGN KEY 
(`debit_account_id`) REFERENCES `acc_gl_account` (`id`),
+       CONSTRAINT `FK_tax_component_lastmodifiedby` FOREIGN KEY 
(`lastmodifiedby_id`) REFERENCES `m_appuser` (`id`)
+);
+
+CREATE TABLE `m_tax_component_history` (
+       `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
+       `tax_component_id` BIGINT(20) NOT NULL,
+       `percentage` DECIMAL(19,6) NOT NULL,
+       `start_date` DATE NOT NULL,
+       `end_date` DATE NOT NULL,
+       `createdby_id` BIGINT(20) NOT NULL,
+       `created_date` DATETIME NOT NULL,
+       `lastmodifiedby_id` BIGINT(20) NOT NULL,
+       `lastmodified_date` DATETIME NOT NULL,
+       PRIMARY KEY (`id`),
+       INDEX `FK_tax_component_history_tax_component_id` (`tax_component_id`),
+       INDEX `FK_tax_component_history_createdby` (`createdby_id`),
+       INDEX `FK_tax_component_history_lastmodifiedby` (`lastmodifiedby_id`),
+       CONSTRAINT `FK_tax_component_history_createdby` FOREIGN KEY 
(`createdby_id`) REFERENCES `m_appuser` (`id`),
+       CONSTRAINT `FK_tax_component_history_lastmodifiedby` FOREIGN KEY 
(`lastmodifiedby_id`) REFERENCES `m_appuser` (`id`),
+       CONSTRAINT `FK_tax_component_history_tax_component_id` FOREIGN KEY 
(`tax_component_id`) REFERENCES `m_tax_component` (`id`)
+);
+
+CREATE TABLE `m_tax_group` (
+       `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
+       `name` VARCHAR(50) NOT NULL,
+       `createdby_id` BIGINT(20) NOT NULL,
+       `created_date` DATETIME NOT NULL,
+       `lastmodifiedby_id` BIGINT(20) NOT NULL,
+       `lastmodified_date` DATETIME NOT NULL,
+       PRIMARY KEY (`id`),
+       INDEX `FK_tax_group_createdby` (`createdby_id`),
+       INDEX `FK_tax_group_lastmodifiedby` (`lastmodifiedby_id`),
+       CONSTRAINT `FK_tax_group_createdby` FOREIGN KEY (`createdby_id`) 
REFERENCES `m_appuser` (`id`),
+       CONSTRAINT `FK_tax_group_lastmodifiedby` FOREIGN KEY 
(`lastmodifiedby_id`) REFERENCES `m_appuser` (`id`)        
+);
+
+CREATE TABLE `m_tax_group_mappings` (
+       `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
+       `tax_group_id` BIGINT(20) NOT NULL,
+       `tax_component_id` BIGINT(20) NOT NULL,
+       `start_date` DATE NOT NULL,
+       `end_date` DATE NULL DEFAULT NULL,
+       `createdby_id` BIGINT(20) NOT NULL,
+       `created_date` DATETIME NOT NULL,
+       `lastmodifiedby_id` BIGINT(20) NOT NULL,
+       `lastmodified_date` DATETIME NOT NULL,
+       PRIMARY KEY (`id`),
+       INDEX `FK_tax_group_mappings_tax_group` (`tax_group_id`),
+       INDEX `FK_tax_group_mappings_tax_component` (`tax_component_id`),
+       INDEX `FK_tax_group_mappings_createdby` (`createdby_id`),
+       INDEX `FK_tax_group_mappings_lastmodifiedby` (`lastmodifiedby_id`),
+       CONSTRAINT `FK_tax_group_mappings_createdby` FOREIGN KEY 
(`createdby_id`) REFERENCES `m_appuser` (`id`),
+       CONSTRAINT `FK_tax_group_mappings_lastmodifiedby` FOREIGN KEY 
(`lastmodifiedby_id`) REFERENCES `m_appuser` (`id`),
+       CONSTRAINT `FK_tax_group_mappings_tax_component` FOREIGN KEY 
(`tax_component_id`) REFERENCES `m_tax_component` (`id`),
+       CONSTRAINT `FK_tax_group_mappings_tax_group` FOREIGN KEY 
(`tax_group_id`) REFERENCES `m_tax_group` (`id`)
+);
+
+ALTER TABLE `m_charge`
+       ADD COLUMN `tax_group_id` BIGINT(20) NULL DEFAULT NULL,
+       ADD CONSTRAINT `FK_m_charge_m_tax_group` FOREIGN KEY (`tax_group_id`) 
REFERENCES `m_tax_group` (`id`);
+       
+ALTER TABLE `m_savings_product`
+       ADD COLUMN `withhold_tax` TINYINT NOT NULL DEFAULT '0',
+       ADD COLUMN `tax_group_id` BIGINT NULL DEFAULT NULL,
+       ADD CONSTRAINT `FK_savings_product_tax_group` FOREIGN KEY 
(`tax_group_id`) REFERENCES `m_tax_group` (`id`);
+       
+ALTER TABLE `m_savings_account`
+       ADD COLUMN `withhold_tax` TINYINT NOT NULL DEFAULT '0',
+       ADD COLUMN `tax_group_id` BIGINT NULL DEFAULT NULL,
+       ADD COLUMN `total_withhold_tax_derived` DECIMAL(19,6) NULL DEFAULT NULL 
AFTER `total_overdraft_interest_derived`,
+       ADD CONSTRAINT `FK_savings_account_tax_group` FOREIGN KEY 
(`tax_group_id`) REFERENCES `m_tax_group` (`id`);     
+       
+CREATE TABLE `m_savings_account_transaction_tax_details` (
+       `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
+       `savings_transaction_id` BIGINT(20) NOT NULL,
+       `tax_component_id` BIGINT(20) NOT NULL,
+       `amount` DECIMAL(19,6) NOT NULL,
+       PRIMARY KEY (`id`),
+       CONSTRAINT 
`FK_savings_account_transaction_tax_details_savings_transaction` FOREIGN KEY 
(`savings_transaction_id`) REFERENCES `m_savings_account_transaction` (`id`),
+       CONSTRAINT `FK_savings_account_transaction_tax_details_tax_component` 
FOREIGN KEY (`tax_component_id`) REFERENCES `m_tax_component` (`id`)
+);
+
+       
+
+INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, 
`can_maker_checker`) VALUES ('organisation', 'READ_TAXCOMPONENT', 
'TAXCOMPONENT', 'READ', 0),('organisation', 'CREATE_TAXCOMPONENT', 
'TAXCOMPONENT', 'CREATE', 0),('organisation', 'CREATE_TAXCOMPONENT_CHECKER', 
'TAXCOMPONENT', 'CREATE_CHECKER', 0), ('organisation', 'UPDATE_TAXCOMPONENT', 
'TAXCOMPONENT', 'UPDATE', 0),('organisation', 'UPDATE_TAXCOMPONENT_CHECKER', 
'TAXCOMPONENT', 'UPDATE_CHECKER', 0),('organisation', 'READ_TAXGROUP', 
'TAXGROUP', 'READ', 0),('organisation', 'CREATE_TAXGROUP', 'TAXGROUP', 
'CREATE', 0),('organisation', 'CREATE_TAXGROUP_CHECKER', 'TAXGROUP', 
'CREATE_CHECKER', 0), ('organisation', 'UPDATE_TAXGROUP', 'TAXGROUP', 'UPDATE', 
0),('organisation', 'UPDATE_TAXGROUP_CHECKER', 'TAXGROUP', 'UPDATE_CHECKER', 
0),('portfolio', 'UPDATEWITHHOLDTAX_SAVINGSACCOUNT', 'SAVINGSACCOUNT', 
'UPDATEWITHHOLDTAX', 0),('portfolio', 
'UPDATEWITHHOLDTAX_SAVINGSACCOUNT_CHECKER', 'SAVINGSACCOUNT', 'UPDATEWITHHOLD
 TAX_CHECKER', 0);
+
+
+
+
+

Reply via email to