http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/3015747f/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RecurringDepositProduct.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RecurringDepositProduct.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RecurringDepositProduct.java index 0410a8b..e297472 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RecurringDepositProduct.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RecurringDepositProduct.java @@ -47,6 +47,7 @@ import org.apache.fineract.portfolio.savings.SavingsInterestCalculationDaysInYea import org.apache.fineract.portfolio.savings.SavingsInterestCalculationType; import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType; import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType; +import org.apache.fineract.portfolio.tax.domain.TaxGroup; @Entity @DiscriminatorValue("300") @@ -67,7 +68,7 @@ public class RecurringDepositProduct extends FixedDepositProduct { final SavingsPeriodFrequencyType lockinPeriodFrequencyType, final AccountingRuleType accountingRuleType, final Set<Charge> charges, final DepositProductTermAndPreClosure productTermAndPreClosure, final DepositProductRecurringDetail recurringDetail, final Set<InterestRateChart> charts, - BigDecimal minBalanceForInterestCalculation) { + BigDecimal minBalanceForInterestCalculation, final TaxGroup taxGroup, final boolean withHoldTax) { final BigDecimal minRequiredOpeningBalance = null; final boolean withdrawalFeeApplicableForTransfer = false; @@ -77,7 +78,8 @@ public class RecurringDepositProduct extends FixedDepositProduct { return new RecurringDepositProduct(name, shortName, description, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, accountingRuleType, charges, - productTermAndPreClosure, recurringDetail, charts, allowOverdraft, overdraftLimit, minBalanceForInterestCalculation); + productTermAndPreClosure, recurringDetail, charts, allowOverdraft, overdraftLimit, minBalanceForInterestCalculation, + withHoldTax, taxGroup); } protected RecurringDepositProduct(final String name, final String shortName, final String description, final MonetaryCurrency currency, @@ -88,12 +90,12 @@ public class RecurringDepositProduct extends FixedDepositProduct { final boolean withdrawalFeeApplicableForTransfer, final AccountingRuleType accountingRuleType, final Set<Charge> charges, final DepositProductTermAndPreClosure productTermAndPreClosure, final DepositProductRecurringDetail recurringDetail, final Set<InterestRateChart> charts, final boolean allowOverdraft, final BigDecimal overdraftLimit, - final BigDecimal minBalanceForInterestCalculation) { + final BigDecimal minBalanceForInterestCalculation, final boolean withHoldTax, final TaxGroup taxGroup) { super(name, shortName, description, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, accountingRuleType, charges, productTermAndPreClosure, - charts, allowOverdraft, overdraftLimit, minBalanceForInterestCalculation); + charts, allowOverdraft, overdraftLimit, minBalanceForInterestCalculation, withHoldTax, taxGroup); this.recurringDetail = recurringDetail; }
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/3015747f/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java index d7493d5..053f438 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java @@ -29,6 +29,7 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.minOverd import static org.apache.fineract.portfolio.savings.SavingsApiConstants.minRequiredBalanceParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateOverdraftParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.overdraftLimitParamName; +import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withHoldTaxParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName; import java.math.BigDecimal; @@ -102,6 +103,9 @@ import org.apache.fineract.portfolio.savings.exception.SavingsOfficerAssignmentD import org.apache.fineract.portfolio.savings.exception.SavingsOfficerUnassignmentDateException; import org.apache.fineract.portfolio.savings.exception.SavingsTransferTransactionsCannotBeUndoneException; import org.apache.fineract.portfolio.savings.service.SavingsEnumerations; +import org.apache.fineract.portfolio.tax.domain.TaxComponent; +import org.apache.fineract.portfolio.tax.domain.TaxGroup; +import org.apache.fineract.portfolio.tax.service.TaxUtils; import org.apache.fineract.useradministration.domain.AppUser; import org.hibernate.annotations.LazyCollection; import org.hibernate.annotations.LazyCollectionOption; @@ -310,6 +314,13 @@ public class SavingsAccount extends AbstractPersistable<Long> { @Column(name = "min_balance_for_interest_calculation", scale = 6, precision = 19, nullable = true) private BigDecimal minBalanceForInterestCalculation; + @Column(name = "withhold_tax", nullable = false) + protected boolean withHoldTax; + + @ManyToOne + @JoinColumn(name = "tax_group_id") + private TaxGroup taxGroup; + protected SavingsAccount() { // } @@ -324,14 +335,14 @@ public class SavingsAccount extends AbstractPersistable<Long> { final boolean withdrawalFeeApplicableForTransfer, final Set<SavingsAccountCharge> savingsAccountCharges, final boolean allowOverdraft, final BigDecimal overdraftLimit, final boolean enforceMinRequiredBalance, final BigDecimal minRequiredBalance, final BigDecimal nominalAnnualInterestRateOverdraft, - final BigDecimal minOverdraftForInterestCalculation) { + final BigDecimal minOverdraftForInterestCalculation, final boolean withHoldTax) { final SavingsAccountStatusType status = SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL; return new SavingsAccount(client, group, product, fieldOfficer, accountNo, externalId, status, accountType, submittedOnDate, submittedBy, interestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, savingsAccountCharges, allowOverdraft, overdraftLimit, enforceMinRequiredBalance, - minRequiredBalance, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation); + minRequiredBalance, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax); } protected SavingsAccount(final Client client, final Group group, final SavingsProduct product, final Staff fieldOfficer, @@ -342,11 +353,12 @@ public class SavingsAccount extends AbstractPersistable<Long> { final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType, final boolean withdrawalFeeApplicableForTransfer, final Set<SavingsAccountCharge> savingsAccountCharges, - final boolean allowOverdraft, final BigDecimal overdraftLimit) { + final boolean allowOverdraft, final BigDecimal overdraftLimit, boolean withHoldTax) { this(client, group, product, fieldOfficer, accountNo, externalId, status, accountType, submittedOnDate, submittedBy, nominalAnnualInterestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, - withdrawalFeeApplicableForTransfer, savingsAccountCharges, allowOverdraft, overdraftLimit, false, null, null, null); + withdrawalFeeApplicableForTransfer, savingsAccountCharges, allowOverdraft, overdraftLimit, false, null, null, null, + withHoldTax); } protected SavingsAccount(final Client client, final Group group, final SavingsProduct product, final Staff savingsOfficer, @@ -359,7 +371,7 @@ public class SavingsAccount extends AbstractPersistable<Long> { final boolean withdrawalFeeApplicableForTransfer, final Set<SavingsAccountCharge> savingsAccountCharges, final boolean allowOverdraft, final BigDecimal overdraftLimit, final boolean enforceMinRequiredBalance, final BigDecimal minRequiredBalance, final BigDecimal nominalAnnualInterestRateOverdraft, - final BigDecimal minOverdraftForInterestCalculation) { + final BigDecimal minOverdraftForInterestCalculation, boolean withHoldTax) { this.client = client; this.group = group; this.product = product; @@ -404,6 +416,8 @@ public class SavingsAccount extends AbstractPersistable<Long> { this.minRequiredBalance = minRequiredBalance; this.minBalanceForInterestCalculation = product.minBalanceForInterestCalculation(); this.savingsOfficerHistory = null; + this.withHoldTax = withHoldTax; + this.taxGroup = product.getTaxGroup(); } /** @@ -458,6 +472,9 @@ public class SavingsAccount extends AbstractPersistable<Long> { Money interestPostedToDate = Money.zero(this.currency); boolean recalucateDailyBalanceDetails = false; + boolean applyWithHoldTax = isWithHoldTaxApplicableForInterestPosting(); + final List<SavingsAccountTransaction> withholdTransactions = new ArrayList<>(); + withholdTransactions.addAll(findWithHoldTransactions()); for (final PostingPeriod interestPostingPeriod : postingPeriods) { @@ -479,6 +496,9 @@ public class SavingsAccount extends AbstractPersistable<Long> { interestEarnedToBePostedForPeriod.negated()); } this.transactions.add(newPostingTransaction); + if (applyWithHoldTax) { + createWithHoldTransaction(interestEarnedToBePostedForPeriod.getAmount(), interestPostingTransactionDate); + } recalucateDailyBalanceDetails = true; } else { boolean correctionRequired = false; @@ -488,7 +508,14 @@ public class SavingsAccount extends AbstractPersistable<Long> { correctionRequired = postingTransaction.hasNotAmount(interestEarnedToBePostedForPeriod.negated()); } if (correctionRequired) { + boolean applyWithHoldTaxForOldTransaction = false; postingTransaction.reverse(); + final SavingsAccountTransaction withholdTransaction = findTransactionFor(interestPostingTransactionDate, + withholdTransactions); + if (withholdTransaction != null) { + withholdTransaction.reverse(); + applyWithHoldTaxForOldTransaction = true; + } SavingsAccountTransaction newPostingTransaction; if (interestEarnedToBePostedForPeriod.isGreaterThanOrEqualTo(Money.zero(currency))) { newPostingTransaction = SavingsAccountTransaction.interestPosting(this, office(), @@ -498,6 +525,9 @@ public class SavingsAccount extends AbstractPersistable<Long> { interestPostingTransactionDate, interestEarnedToBePostedForPeriod.negated()); } this.transactions.add(newPostingTransaction); + if (applyWithHoldTaxForOldTransaction) { + createWithHoldTransaction(interestEarnedToBePostedForPeriod.getAmount(), interestPostingTransactionDate); + } recalucateDailyBalanceDetails = true; } } @@ -518,10 +548,22 @@ public class SavingsAccount extends AbstractPersistable<Long> { this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions); } - protected SavingsAccountTransaction findInterestPostingTransactionFor(final LocalDate postingDate) { + protected List<SavingsAccountTransaction> findWithHoldTransactions() { + final List<SavingsAccountTransaction> withholdTransactions = new ArrayList<>(); + for (final SavingsAccountTransaction transaction : this.transactions) { + if ((transaction.isWithHoldTaxAndNotReversed())) { + withholdTransactions.add(transaction); + } + } + return withholdTransactions; + } - SavingsAccountTransaction postingTransation = null; + private boolean isWithHoldTaxApplicableForInterestPosting() { + return this.withHoldTax() && this.depositAccountType().isSavingsDeposit(); + } + protected SavingsAccountTransaction findInterestPostingTransactionFor(final LocalDate postingDate) { + SavingsAccountTransaction postingTransation = null; for (final SavingsAccountTransaction transaction : this.transactions) { if ((transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed()) && transaction.occursOn(postingDate)) { @@ -529,10 +571,59 @@ public class SavingsAccount extends AbstractPersistable<Long> { break; } } - return postingTransation; } + protected SavingsAccountTransaction findTransactionFor(final LocalDate postingDate, final List<SavingsAccountTransaction> transactions) { + SavingsAccountTransaction transaction = null; + for (final SavingsAccountTransaction savingsAccountTransaction : transactions) { + if (savingsAccountTransaction.occursOn(postingDate)) { + transaction = savingsAccountTransaction; + break; + } + } + return transaction; + } + + protected boolean createWithHoldTransaction(final BigDecimal amount, final LocalDate date) { + boolean isTaxAdded = false; + if (this.taxGroup != null && amount.compareTo(BigDecimal.ZERO) == 1) { + Map<TaxComponent, BigDecimal> taxSplit = TaxUtils.splitTax(amount, date, this.taxGroup.getTaxGroupMappings(), amount.scale()); + BigDecimal totalTax = TaxUtils.totalTaxAmount(taxSplit); + if (totalTax.compareTo(BigDecimal.ZERO) == 1) { + SavingsAccountTransaction withholdTransaction = SavingsAccountTransaction.withHoldTax(this, office(), date, + Money.of(currency, totalTax), taxSplit); + this.transactions.add(withholdTransaction); + isTaxAdded = true; + } + } + return isTaxAdded; + } + + protected boolean updateWithHoldTransaction(final BigDecimal amount, final SavingsAccountTransaction withholdTransaction) { + boolean isTaxAdded = false; + if (this.taxGroup != null && amount.compareTo(BigDecimal.ZERO) == 1) { + Map<TaxComponent, BigDecimal> taxSplit = TaxUtils.splitTax(amount, withholdTransaction.transactionLocalDate(), + this.taxGroup.getTaxGroupMappings(), amount.scale()); + BigDecimal totalTax = TaxUtils.totalTaxAmount(taxSplit); + if (totalTax.compareTo(BigDecimal.ZERO) == 1) { + if (withholdTransaction.getId() == null) { + withholdTransaction.updateAmount(Money.of(currency, totalTax)); + withholdTransaction.getTaxDetails().clear(); + SavingsAccountTransaction.updateTaxDetails(taxSplit, withholdTransaction); + isTaxAdded = true; + } else if (totalTax.compareTo(withholdTransaction.getAmount()) != 0) { + withholdTransaction.reverse(); + SavingsAccountTransaction newWithholdTransaction = SavingsAccountTransaction.withHoldTax(this, office(), + withholdTransaction.transactionLocalDate(), Money.of(currency, totalTax), taxSplit); + this.transactions.add(newWithholdTransaction); + isTaxAdded = true; + } + } + } + return isTaxAdded; + } + // Determine the last transaction for given day protected SavingsAccountTransaction findLastTransaction(final LocalDate date) { @@ -1231,6 +1322,15 @@ public class SavingsAccount extends AbstractPersistable<Long> { this.minRequiredBalance = newValue; } + if (command.isChangeInBooleanParameterNamed(withHoldTaxParamName, this.withHoldTax)) { + final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(withHoldTaxParamName); + actualChanges.put(withHoldTaxParamName, newValue); + this.withHoldTax = newValue; + if (this.withHoldTax && this.taxGroup == null) { + baseDataValidator.reset().parameter(withHoldTaxParamName).failWithCode("not.supported.for.this.account"); + } + } + validateLockinDetails(baseDataValidator); esnureOverdraftLimitsSetForOverdraftAccounts(); } @@ -2605,4 +2705,32 @@ public class SavingsAccount extends AbstractPersistable<Long> { public BigDecimal getWithdrawableBalance() { return getAccountBalance().subtract(minRequiredBalanceDerived(getCurrency()).getAmount()).subtract(this.getOnHoldFunds()); } + + public TaxGroup getTaxGroup() { + return this.taxGroup; + } + + public boolean withHoldTax() { + return this.withHoldTax; + } + + public void setWithHoldTax(boolean withHoldTax) { + this.withHoldTax = withHoldTax; + } + + protected boolean applyWithholdTaxForDepositAccounts(final LocalDate interestPostingUpToDate, boolean recalucateDailyBalance) { + final List<SavingsAccountTransaction> withholdTransactions = findWithHoldTransactions(); + SavingsAccountTransaction withholdTransaction = findTransactionFor(interestPostingUpToDate, withholdTransactions); + final BigDecimal totalInterestPosted = this.savingsAccountTransactionSummaryWrapper.calculateTotalInterestPosted(this.currency, + this.transactions); + if (withholdTransaction == null && this.withHoldTax()) { + boolean isWithholdTaxAdded = createWithHoldTransaction(totalInterestPosted, interestPostingUpToDate); + recalucateDailyBalance = recalucateDailyBalance || isWithholdTaxAdded; + } else { + boolean isWithholdTaxAdded = updateWithHoldTransaction(totalInterestPosted, withholdTransaction); + recalucateDailyBalance = recalucateDailyBalance || isWithholdTaxAdded; + } + + return recalucateDailyBalance; + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/3015747f/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountAssembler.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountAssembler.java index ec30ea8..c26bb52 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountAssembler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountAssembler.java @@ -40,12 +40,15 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominalA import static org.apache.fineract.portfolio.savings.SavingsApiConstants.overdraftLimitParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.productIdParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.submittedOnDateParamName; +import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withHoldTaxParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName; import java.math.BigDecimal; +import java.util.Arrays; import java.util.Set; import org.apache.fineract.infrastructure.core.api.JsonCommand; +import org.apache.fineract.infrastructure.core.exception.UnsupportedParameterException; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.organisation.staff.domain.Staff; @@ -240,16 +243,18 @@ public class SavingsAccountAssembler { BigDecimal nominalAnnualInterestRateOverdraft = BigDecimal.ZERO; if (command.parameterExists(nominalAnnualInterestRateOverdraftParamName)) { - nominalAnnualInterestRateOverdraft = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(nominalAnnualInterestRateOverdraftParamName); + nominalAnnualInterestRateOverdraft = command + .bigDecimalValueOfParameterNamedDefaultToNullIfZero(nominalAnnualInterestRateOverdraftParamName); } else { - nominalAnnualInterestRateOverdraft = product.nominalAnnualInterestRateOverdraft(); + nominalAnnualInterestRateOverdraft = product.nominalAnnualInterestRateOverdraft(); } BigDecimal minOverdraftForInterestCalculation = BigDecimal.ZERO; if (command.parameterExists(minOverdraftForInterestCalculationParamName)) { - minOverdraftForInterestCalculation = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(minOverdraftForInterestCalculationParamName); + minOverdraftForInterestCalculation = command + .bigDecimalValueOfParameterNamedDefaultToNullIfZero(minOverdraftForInterestCalculationParamName); } else { - minOverdraftForInterestCalculation = product.minOverdraftForInterestCalculation(); + minOverdraftForInterestCalculation = product.minOverdraftForInterestCalculation(); } boolean enforceMinRequiredBalance = false; @@ -266,12 +271,20 @@ public class SavingsAccountAssembler { minRequiredBalance = product.minRequiredBalance(); } + boolean withHoldTax = product.withHoldTax(); + if (command.parameterExists(withHoldTaxParamName)) { + withHoldTax = command.booleanPrimitiveValueOfParameterNamed(withHoldTaxParamName); + if(withHoldTax && product.getTaxGroup() == null){ + throw new UnsupportedParameterException(Arrays.asList(withHoldTaxParamName)); + } + } + final SavingsAccount account = SavingsAccount.createNewApplicationForSubmittal(client, group, product, fieldOfficer, accountNo, externalId, accountType, submittedOnDate, submittedBy, interestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, iswithdrawalFeeApplicableForTransfer, charges, allowOverdraft, - overdraftLimit, enforceMinRequiredBalance, minRequiredBalance, - nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation); + overdraftLimit, enforceMinRequiredBalance, minRequiredBalance, nominalAnnualInterestRateOverdraft, + minOverdraftForInterestCalculation, withHoldTax); account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper); account.validateNewApplicationState(DateUtils.getLocalDateOfTenant(), SAVINGS_ACCOUNT_RESOURCE_NAME); @@ -319,14 +332,13 @@ public class SavingsAccountAssembler { } final Set<SavingsAccountCharge> charges = this.savingsAccountChargeAssembler.fromSavingsProduct(product); - final SavingsAccount account = SavingsAccount.createNewApplicationForSubmittal(client, group, product, null, null, null, accountType, appliedonDate, appliedBy, product.nominalAnnualInterestRate(), product.interestCompoundingPeriodType(), product.interestPostingPeriodType(), product.interestCalculationType(), product.interestCalculationDaysInYearType(), product.minRequiredOpeningBalance(), product.lockinPeriodFrequency(), product.lockinPeriodFrequencyType(), product.isWithdrawalFeeApplicableForTransfer(), charges, product.isAllowOverdraft(), product.overdraftLimit(), product.isMinRequiredBalanceEnforced(), product.minRequiredBalance(), product.nominalAnnualInterestRateOverdraft(), - product.minOverdraftForInterestCalculation()); + product.minOverdraftForInterestCalculation(), product.withHoldTax()); account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper); account.validateNewApplicationState(DateUtils.getLocalDateOfTenant(), SAVINGS_ACCOUNT_RESOURCE_NAME); http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/3015747f/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSummary.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSummary.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSummary.java index 5a93704..7a2b5f2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSummary.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSummary.java @@ -71,7 +71,10 @@ public final class SavingsAccountSummary { private BigDecimal totalPenaltyChargesWaived = BigDecimal.ZERO; @Column(name = "total_overdraft_interest_derived", scale = 6, precision = 19) - private BigDecimal totalOverdraftInterestDerived; + private BigDecimal totalOverdraftInterestDerived; + + @Column(name = "total_withhold_tax_derived", scale = 6, precision = 19) + private BigDecimal totalWithholdTax; protected SavingsAccountSummary() { // @@ -90,10 +93,12 @@ public final class SavingsAccountSummary { this.totalFeeChargesWaived = wrapper.calculateTotalFeesChargeWaived(currency, transactions); this.totalPenaltyChargesWaived = wrapper.calculateTotalPenaltyChargeWaived(currency, transactions); this.totalOverdraftInterestDerived = wrapper.calculateTotalOverdraftInterest(currency, transactions); + this.totalWithholdTax = wrapper.calculateTotalWithholdTaxWithdrawal(currency, transactions); + this.accountBalance = Money.of(currency, this.totalDeposits).plus(this.totalInterestPosted).minus(this.totalWithdrawals) .minus(this.totalWithdrawalFees).minus(this.totalAnnualFees).minus(this.totalFeeCharge).minus(this.totalPenaltyCharge) - .minus(totalOverdraftInterestDerived).getAmount(); + .minus(totalOverdraftInterestDerived).minus(totalWithholdTax).getAmount(); } public void updateFromInterestPeriodSummaries(final MonetaryCurrency currency, final List<PostingPeriod> allPostingPeriods) { @@ -122,4 +127,8 @@ public final class SavingsAccountSummary { return this.accountBalance; } + public BigDecimal getTotalInterestPosted() { + return this.totalInterestPosted; + } + } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/3015747f/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java index d09c667..a9cfc5d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java @@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.savings.domain; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -47,6 +48,7 @@ import org.apache.fineract.portfolio.savings.SavingsAccountTransactionType; import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionEnumData; import org.apache.fineract.portfolio.savings.domain.interest.EndOfDayBalance; import org.apache.fineract.portfolio.savings.service.SavingsEnumerations; +import org.apache.fineract.portfolio.tax.domain.TaxComponent; import org.apache.fineract.useradministration.domain.AppUser; import org.hibernate.annotations.LazyCollection; import org.hibernate.annotations.LazyCollectionOption; @@ -115,6 +117,11 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> { @JoinColumn(name = "appuser_id", nullable = true) private AppUser appUser; + @LazyCollection(LazyCollectionOption.FALSE) + @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) + @JoinColumn(name = "savings_transaction_id", referencedColumnName = "id", nullable = false) + private final List<SavingsAccountTransactionTaxDetails> taxDetails = new ArrayList<>(); + protected SavingsAccountTransaction() { this.dateOf = null; this.typeOf = null; @@ -142,14 +149,14 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> { amount, isReversed, null); } - public static SavingsAccountTransaction overdraftInterest(final SavingsAccount savingsAccount, final Office office, final LocalDate date, - final Money amount) { + public static SavingsAccountTransaction overdraftInterest(final SavingsAccount savingsAccount, final Office office, + final LocalDate date, final Money amount) { final boolean isReversed = false; return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.OVERDRAFT_INTEREST.getValue(), date, amount, isReversed, null); - } + } - public static SavingsAccountTransaction withdrawalFee(final SavingsAccount savingsAccount, final Office office, final LocalDate date, + public static SavingsAccountTransaction withdrawalFee(final SavingsAccount savingsAccount, final Office office, final LocalDate date, final Money amount, final AppUser appUser) { final boolean isReversed = false; return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.WITHDRAWAL_FEE.getValue(), date, amount, @@ -204,6 +211,23 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> { .getAccountBalance(), isReversed, appUser); } + public static SavingsAccountTransaction withHoldTax(final SavingsAccount savingsAccount, final Office office, final LocalDate date, + final Money amount, final Map<TaxComponent, BigDecimal> taxDetails) { + final boolean isReversed = false; + SavingsAccountTransaction accountTransaction = new SavingsAccountTransaction(savingsAccount, office, + SavingsAccountTransactionType.WITHHOLD_TAX.getValue(), date, amount, isReversed, null); + updateTaxDetails(taxDetails, accountTransaction); + return accountTransaction; + } + + public static void updateTaxDetails(final Map<TaxComponent, BigDecimal> taxDetails, final SavingsAccountTransaction accountTransaction) { + if (taxDetails != null) { + for (Map.Entry<TaxComponent, BigDecimal> mapEntry : taxDetails.entrySet()) { + accountTransaction.getTaxDetails().add(new SavingsAccountTransactionTaxDetails(mapEntry.getKey(), mapEntry.getValue())); + } + } + } + public static SavingsAccountTransaction copyTransaction(SavingsAccountTransaction accountTransaction) { return new SavingsAccountTransaction(accountTransaction.savingsAccount, accountTransaction.office, accountTransaction.paymentDetail, accountTransaction.typeOf, accountTransaction.transactionLocalDate(), @@ -405,6 +429,19 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> { thisTransactionData.put("savingsChargesPaid", savingsChargesPaidData); } + if (!this.taxDetails.isEmpty()) { + final List<Map<String, Object>> taxData = new ArrayList<>(); + for (final SavingsAccountTransactionTaxDetails taxDetails : this.taxDetails) { + final Map<String, Object> taxDetailsData = new HashMap<>(); + taxDetailsData.put("amount", taxDetails.getAmount()); + if (taxDetails.getTaxComponent().getCreditAcount() != null) { + taxDetailsData.put("creditAccountId", taxDetails.getTaxComponent().getCreditAcount().getId()); + } + taxData.add(taxDetailsData); + } + thisTransactionData.put("taxDetails", taxData); + } + return thisTransactionData; } @@ -525,18 +562,19 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> { } public boolean isDebit() { - return isWithdrawal() - || isWithdrawalFeeAndNotReversed() - || isAnnualFeeAndNotReversed() - || isPayCharge() - || isOverdraftInterestAndNotReversed(); + return isWithdrawal() || isWithdrawalFeeAndNotReversed() || isAnnualFeeAndNotReversed() || isPayCharge() + || isOverdraftInterestAndNotReversed() || isWithHoldTaxAndNotReversed(); + } + + public boolean isWithHoldTaxAndNotReversed() { + return SavingsAccountTransactionType.fromInt(this.typeOf).isWithHoldTax() && isNotReversed(); } public boolean isOverdraftInterestAndNotReversed() { - return SavingsAccountTransactionType.fromInt(this.typeOf).isIncomeFromInterest() && isNotReversed(); + return SavingsAccountTransactionType.fromInt(this.typeOf).isIncomeFromInterest() && isNotReversed(); } - public boolean isPayCharge() { + public boolean isPayCharge() { return SavingsAccountTransactionType.fromInt(this.typeOf).isPayCharge(); } @@ -637,4 +675,12 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> { return this.amount; } + public List<SavingsAccountTransactionTaxDetails> getTaxDetails() { + return this.taxDetails; + } + + public void updateAmount(final Money amount) { + this.amount = amount.getAmount(); + } + } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/3015747f/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionSummaryWrapper.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionSummaryWrapper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionSummaryWrapper.java index 0a367de..744180d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionSummaryWrapper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionSummaryWrapper.java @@ -122,8 +122,7 @@ public final class SavingsAccountTransactionSummaryWrapper { return total.getAmountDefaultedToNullIfZero(); } - public BigDecimal calculateTotalOverdraftInterest(MonetaryCurrency currency, - List<SavingsAccountTransaction> transactions) { + public BigDecimal calculateTotalOverdraftInterest(MonetaryCurrency currency, List<SavingsAccountTransaction> transactions) { Money total = Money.zero(currency); for (final SavingsAccountTransaction transaction : transactions) { if (transaction.isOverdraftInterestAndNotReversed()) { @@ -131,6 +130,16 @@ public final class SavingsAccountTransactionSummaryWrapper { } } return total.getAmountDefaultedToNullIfZero(); - } + } + + public BigDecimal calculateTotalWithholdTaxWithdrawal(MonetaryCurrency currency, List<SavingsAccountTransaction> transactions) { + Money total = Money.zero(currency); + for (final SavingsAccountTransaction transaction : transactions) { + if (transaction.isWithHoldTaxAndNotReversed()) { + total = total.plus(transaction.getAmount(currency)); + } + } + return total.getAmountDefaultedToNullIfZero(); + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/3015747f/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionTaxDetails.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionTaxDetails.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionTaxDetails.java new file mode 100644 index 0000000..4c13b67 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionTaxDetails.java @@ -0,0 +1,63 @@ +/** + * 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.savings.domain; + +import java.math.BigDecimal; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +import org.apache.fineract.organisation.monetary.domain.Money; +import org.apache.fineract.portfolio.tax.domain.TaxComponent; +import org.springframework.data.jpa.domain.AbstractPersistable; + +@Entity +@Table(name = "m_savings_account_transaction_tax_details") +public class SavingsAccountTransactionTaxDetails extends AbstractPersistable<Long> { + + @ManyToOne + @JoinColumn(name = "tax_component_id", nullable = false) + private TaxComponent taxComponent; + + @Column(name = "amount", scale = 6, precision = 19, nullable = false) + private BigDecimal amount; + + protected SavingsAccountTransactionTaxDetails() {} + + public SavingsAccountTransactionTaxDetails(final TaxComponent taxComponent, final BigDecimal amount) { + this.taxComponent = taxComponent; + this.amount = amount; + } + + public TaxComponent getTaxComponent() { + return this.taxComponent; + } + + public BigDecimal getAmount() { + return this.amount; + } + + public void updateAmount(Money amount) { + this.amount = amount.getAmount(); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/3015747f/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProduct.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProduct.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProduct.java index d5aaa5d..1b100a0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProduct.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProduct.java @@ -44,6 +44,8 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominalA import static org.apache.fineract.portfolio.savings.SavingsApiConstants.overdraftLimitParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.shortNameParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName; +import static org.apache.fineract.portfolio.savings.SavingsApiConstants.taxGroupIdParamName; +import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withHoldTaxParamName; import java.math.BigDecimal; import java.util.ArrayList; @@ -63,6 +65,7 @@ import javax.persistence.Inheritance; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; import javax.persistence.Table; import javax.persistence.UniqueConstraint; @@ -80,6 +83,7 @@ import org.apache.fineract.portfolio.savings.SavingsInterestCalculationDaysInYea import org.apache.fineract.portfolio.savings.SavingsInterestCalculationType; import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType; import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType; +import org.apache.fineract.portfolio.tax.domain.TaxGroup; import org.joda.time.LocalDate; import org.springframework.data.jpa.domain.AbstractPersistable; @@ -156,7 +160,7 @@ public class SavingsProduct extends AbstractPersistable<Long> { protected boolean withdrawalFeeApplicableForTransfer; @ManyToMany - @JoinTable(name = "m_savings_product_charge", joinColumns = @JoinColumn(name = "savings_product_id") , inverseJoinColumns = @JoinColumn(name = "charge_id") ) + @JoinTable(name = "m_savings_product_charge", joinColumns = @JoinColumn(name = "savings_product_id"), inverseJoinColumns = @JoinColumn(name = "charge_id")) protected Set<Charge> charges; @Column(name = "allow_overdraft") @@ -165,12 +169,12 @@ public class SavingsProduct extends AbstractPersistable<Long> { @Column(name = "overdraft_limit", scale = 6, precision = 19, nullable = true) private BigDecimal overdraftLimit; - @Column(name = "nominal_annual_interest_rate_overdraft", scale = 6, precision = 19, nullable = true) + @Column(name = "nominal_annual_interest_rate_overdraft", scale = 6, precision = 19, nullable = true) private BigDecimal nominalAnnualInterestRateOverdraft; @Column(name = "min_overdraft_for_interest_calculation", scale = 6, precision = 19, nullable = true) private BigDecimal minOverdraftForInterestCalculation; - + @Column(name = "enforce_min_required_balance") private boolean enforceMinRequiredBalance; @@ -180,6 +184,13 @@ public class SavingsProduct extends AbstractPersistable<Long> { @Column(name = "min_balance_for_interest_calculation", scale = 6, precision = 19, nullable = true) private BigDecimal minBalanceForInterestCalculation; + @Column(name = "withhold_tax", nullable = false) + private boolean withHoldTax; + + @ManyToOne + @JoinColumn(name = "tax_group_id") + private TaxGroup taxGroup; + public static SavingsProduct createNew(final String name, final String shortName, final String description, final MonetaryCurrency currency, final BigDecimal interestRate, final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType, @@ -189,13 +200,14 @@ public class SavingsProduct extends AbstractPersistable<Long> { final boolean withdrawalFeeApplicableForTransfer, final AccountingRuleType accountingRuleType, final Set<Charge> charges, final boolean allowOverdraft, final BigDecimal overdraftLimit, final boolean enforceMinRequiredBalance, final BigDecimal minRequiredBalance, final BigDecimal minBalanceForInterestCalculation, - final BigDecimal nominalAnnualInterestRateOverdraft, final BigDecimal minOverdraftForInterestCalculation) { + final BigDecimal nominalAnnualInterestRateOverdraft, final BigDecimal minOverdraftForInterestCalculation, + boolean withHoldTax, TaxGroup taxGroup) { return new SavingsProduct(name, shortName, description, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, accountingRuleType, charges, - allowOverdraft, overdraftLimit, enforceMinRequiredBalance, minRequiredBalance, minBalanceForInterestCalculation, - nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation); + allowOverdraft, overdraftLimit, enforceMinRequiredBalance, minRequiredBalance, minBalanceForInterestCalculation, + nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, taxGroup); } protected SavingsProduct() { @@ -209,11 +221,12 @@ public class SavingsProduct extends AbstractPersistable<Long> { final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType, final boolean withdrawalFeeApplicableForTransfer, final AccountingRuleType accountingRuleType, final Set<Charge> charges, - final boolean allowOverdraft, final BigDecimal overdraftLimit, BigDecimal minBalanceForInterestCalculation) { + final boolean allowOverdraft, final BigDecimal overdraftLimit, BigDecimal minBalanceForInterestCalculation, + boolean withHoldTax, TaxGroup taxGroup) { this(name, shortName, description, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, accountingRuleType, charges, allowOverdraft, overdraftLimit, - false, null, minBalanceForInterestCalculation, null, null); + false, null, minBalanceForInterestCalculation, null, null, withHoldTax, taxGroup); } protected SavingsProduct(final String name, final String shortName, final String description, final MonetaryCurrency currency, @@ -224,7 +237,8 @@ public class SavingsProduct extends AbstractPersistable<Long> { final boolean withdrawalFeeApplicableForTransfer, final AccountingRuleType accountingRuleType, final Set<Charge> charges, final boolean allowOverdraft, final BigDecimal overdraftLimit, final boolean enforceMinRequiredBalance, final BigDecimal minRequiredBalance, BigDecimal minBalanceForInterestCalculation, - final BigDecimal nominalAnnualInterestRateOverdraft, final BigDecimal minOverdraftForInterestCalculation) { + final BigDecimal nominalAnnualInterestRateOverdraft, final BigDecimal minOverdraftForInterestCalculation, + final boolean withHoldTax, final TaxGroup taxGroup) { this.name = name; this.shortName = shortName; @@ -267,6 +281,8 @@ public class SavingsProduct extends AbstractPersistable<Long> { this.enforceMinRequiredBalance = enforceMinRequiredBalance; this.minRequiredBalance = minRequiredBalance; this.minBalanceForInterestCalculation = minBalanceForInterestCalculation; + this.withHoldTax = withHoldTax; + this.taxGroup = taxGroup; } /** @@ -276,9 +292,11 @@ public class SavingsProduct extends AbstractPersistable<Long> { private void esnureOverdraftLimitsSetForOverdraftAccounts() { if (this.allowOverdraft) { - this.overdraftLimit = this.overdraftLimit == null? BigDecimal.ZERO : this.overdraftLimit; - this.nominalAnnualInterestRateOverdraft = this.nominalAnnualInterestRateOverdraft == null? BigDecimal.ZERO : this.nominalAnnualInterestRateOverdraft; - this.minOverdraftForInterestCalculation = this.minOverdraftForInterestCalculation == null? BigDecimal.ZERO : this.minOverdraftForInterestCalculation; + this.overdraftLimit = this.overdraftLimit == null ? BigDecimal.ZERO : this.overdraftLimit; + this.nominalAnnualInterestRateOverdraft = this.nominalAnnualInterestRateOverdraft == null ? BigDecimal.ZERO + : this.nominalAnnualInterestRateOverdraft; + this.minOverdraftForInterestCalculation = this.minOverdraftForInterestCalculation == null ? BigDecimal.ZERO + : this.minOverdraftForInterestCalculation; } } @@ -463,20 +481,24 @@ public class SavingsProduct extends AbstractPersistable<Long> { this.overdraftLimit = newValue; } - if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(nominalAnnualInterestRateOverdraftParamName, this.nominalAnnualInterestRateOverdraft)) { - final BigDecimal newValue = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(nominalAnnualInterestRateOverdraftParamName); + if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(nominalAnnualInterestRateOverdraftParamName, + this.nominalAnnualInterestRateOverdraft)) { + final BigDecimal newValue = command + .bigDecimalValueOfParameterNamedDefaultToNullIfZero(nominalAnnualInterestRateOverdraftParamName); actualChanges.put(nominalAnnualInterestRateOverdraftParamName, newValue); actualChanges.put(localeParamName, localeAsInput); this.nominalAnnualInterestRateOverdraft = newValue; } - - if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(minOverdraftForInterestCalculationParamName, this.minOverdraftForInterestCalculation)) { - final BigDecimal newValue = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(minOverdraftForInterestCalculationParamName); + + if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(minOverdraftForInterestCalculationParamName, + this.minOverdraftForInterestCalculation)) { + final BigDecimal newValue = command + .bigDecimalValueOfParameterNamedDefaultToNullIfZero(minOverdraftForInterestCalculationParamName); actualChanges.put(minOverdraftForInterestCalculationParamName, newValue); actualChanges.put(localeParamName, localeAsInput); this.minOverdraftForInterestCalculation = newValue; } - + if (!this.allowOverdraft) { this.overdraftLimit = null; this.nominalAnnualInterestRateOverdraft = null; @@ -505,6 +527,21 @@ public class SavingsProduct extends AbstractPersistable<Long> { this.minBalanceForInterestCalculation = newValue; } + if (command.isChangeInBooleanParameterNamed(withHoldTaxParamName, this.withHoldTax)) { + final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(withHoldTaxParamName); + actualChanges.put(withHoldTaxParamName, newValue); + this.withHoldTax = newValue; + } + + if (this.withHoldTax) { + if (this.taxGroup == null || command.isChangeInLongParameterNamed(taxGroupIdParamName, this.taxGroup.getId())) { + final Long newValue = command.longValueOfParameterNamed(taxGroupIdParamName); + actualChanges.put(taxGroupIdParamName, newValue); + } + } else { + this.taxGroup = null; + } + validateLockinDetails(); esnureOverdraftLimitsSetForOverdraftAccounts(); @@ -617,11 +654,26 @@ public class SavingsProduct extends AbstractPersistable<Long> { } public BigDecimal nominalAnnualInterestRateOverdraft() { - return this.nominalAnnualInterestRateOverdraft; - } + return this.nominalAnnualInterestRateOverdraft; + } + + public BigDecimal minOverdraftForInterestCalculation() { + return this.minOverdraftForInterestCalculation; + } + + + public TaxGroup getTaxGroup() { + return this.taxGroup; + } + + + public void setTaxGroup(TaxGroup taxGroup) { + this.taxGroup = taxGroup; + } - public BigDecimal minOverdraftForInterestCalculation() { - return this.minOverdraftForInterestCalculation; - } + + public boolean withHoldTax() { + return this.withHoldTax; + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/3015747f/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProductAssembler.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProductAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProductAssembler.java index 823a44f..dcbfe93 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProductAssembler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProductAssembler.java @@ -19,6 +19,7 @@ package org.apache.fineract.portfolio.savings.domain; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.allowOverdraftParamName; +import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withHoldTaxParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.chargesParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.currencyCodeParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.descriptionParamName; @@ -41,6 +42,7 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominalA import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.overdraftLimitParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.shortNameParamName; +import static org.apache.fineract.portfolio.savings.SavingsApiConstants.taxGroupIdParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName; import java.math.BigDecimal; @@ -59,6 +61,8 @@ import org.apache.fineract.portfolio.savings.SavingsInterestCalculationDaysInYea import org.apache.fineract.portfolio.savings.SavingsInterestCalculationType; import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType; import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType; +import org.apache.fineract.portfolio.tax.domain.TaxGroup; +import org.apache.fineract.portfolio.tax.domain.TaxGroupRepositoryWrapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -69,10 +73,12 @@ import com.google.gson.JsonObject; public class SavingsProductAssembler { private final ChargeRepositoryWrapper chargeRepository; + private final TaxGroupRepositoryWrapper taxGroupRepository; @Autowired - public SavingsProductAssembler(final ChargeRepositoryWrapper chargeRepository) { + public SavingsProductAssembler(final ChargeRepositoryWrapper chargeRepository, final TaxGroupRepositoryWrapper taxGroupRepository) { this.chargeRepository = chargeRepository; + this.taxGroupRepository = taxGroupRepository; } public SavingsProduct assemble(final JsonCommand command) { @@ -139,18 +145,18 @@ public class SavingsProductAssembler { } BigDecimal overdraftLimit = BigDecimal.ZERO; - if(command.parameterExists(overdraftLimitParamName)){ + if (command.parameterExists(overdraftLimitParamName)) { overdraftLimit = command.bigDecimalValueOfParameterNamed(overdraftLimitParamName); } BigDecimal nominalAnnualInterestRateOverdraft = BigDecimal.ZERO; - if(command.parameterExists(nominalAnnualInterestRateOverdraftParamName)){ - nominalAnnualInterestRateOverdraft = command.bigDecimalValueOfParameterNamed(nominalAnnualInterestRateOverdraftParamName); + if (command.parameterExists(nominalAnnualInterestRateOverdraftParamName)) { + nominalAnnualInterestRateOverdraft = command.bigDecimalValueOfParameterNamed(nominalAnnualInterestRateOverdraftParamName); } - + BigDecimal minOverdraftForInterestCalculation = BigDecimal.ZERO; - if(command.parameterExists(minOverdraftForInterestCalculationParamName)){ - minOverdraftForInterestCalculation = command.bigDecimalValueOfParameterNamed(minOverdraftForInterestCalculationParamName); + if (command.parameterExists(minOverdraftForInterestCalculationParamName)) { + minOverdraftForInterestCalculation = command.bigDecimalValueOfParameterNamed(minOverdraftForInterestCalculationParamName); } boolean enforceMinRequiredBalance = false; @@ -159,17 +165,20 @@ public class SavingsProductAssembler { } BigDecimal minRequiredBalance = BigDecimal.ZERO; - if(command.parameterExists(minRequiredBalanceParamName)){ + if (command.parameterExists(minRequiredBalanceParamName)) { minRequiredBalance = command.bigDecimalValueOfParameterNamed(minRequiredBalanceParamName); } final BigDecimal minBalanceForInterestCalculation = command .bigDecimalValueOfParameterNamedDefaultToNullIfZero(minBalanceForInterestCalculationParamName); + boolean withHoldTax = command.booleanPrimitiveValueOfParameterNamed(withHoldTaxParamName); + final TaxGroup taxGroup = assembleTaxGroup(command); + return SavingsProduct.createNew(name, shortName, description, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, iswithdrawalFeeApplicableForTransfer, accountingRuleType, charges, allowOverdraft, overdraftLimit, enforceMinRequiredBalance, minRequiredBalance, minBalanceForInterestCalculation, - nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation); + nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax, taxGroup); } public Set<Charge> assembleListOfSavingsProductCharges(final JsonCommand command, final String savingsProductCurrencyCode) { @@ -205,4 +214,13 @@ public class SavingsProductAssembler { return charges; } + + public TaxGroup assembleTaxGroup(final JsonCommand command) { + final Long taxGroupId = command.longValueOfParameterNamed(taxGroupIdParamName); + TaxGroup taxGroup = null; + if (taxGroupId != null) { + taxGroup = this.taxGroupRepository.findOneWithNotFoundDetection(taxGroupId); + } + return taxGroup; + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/3015747f/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/handler/UpdateWithHoldTaxSavingsAccountCommandHandler.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/handler/UpdateWithHoldTaxSavingsAccountCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/handler/UpdateWithHoldTaxSavingsAccountCommandHandler.java new file mode 100644 index 0000000..ce0f918 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/handler/UpdateWithHoldTaxSavingsAccountCommandHandler.java @@ -0,0 +1,46 @@ +/** + * 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.savings.handler; + +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.savings.service.SavingsAccountWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@CommandType(entity = "SAVINGSACCOUNT", action = "UPDATEWITHHOLDTAX") +public class UpdateWithHoldTaxSavingsAccountCommandHandler implements NewCommandSourceHandler { + + private final SavingsAccountWritePlatformService writePlatformService; + + @Autowired + public UpdateWithHoldTaxSavingsAccountCommandHandler(final SavingsAccountWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + return this.writePlatformService.modifyWithHoldTax(command.entityId(), command); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/3015747f/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java index 45de68c..5e0dab7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java @@ -83,6 +83,7 @@ import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData; import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionEnumData; import org.apache.fineract.portfolio.savings.domain.SavingsAccountStatusType; import org.apache.fineract.portfolio.savings.exception.DepositAccountNotFoundException; +import org.apache.fineract.portfolio.tax.data.TaxGroupData; import org.apache.fineract.useradministration.domain.AppUser; import org.joda.time.LocalDate; import org.joda.time.format.DateTimeFormat; @@ -580,8 +581,12 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead selectFieldsSqlBuilder.append("sa.account_balance_derived as accountBalance, "); selectFieldsSqlBuilder.append("sa.total_fees_charge_derived as totalFeeCharge, "); selectFieldsSqlBuilder.append("sa.total_penalty_charge_derived as totalPenaltyCharge, "); + selectFieldsSqlBuilder.append("sa.total_withhold_tax_derived as totalWithholdTax,"); selectFieldsSqlBuilder.append("sa.deposit_type_enum as depositTypeId, "); - selectFieldsSqlBuilder.append("sa.min_balance_for_interest_calculation as minBalanceForInterestCalculation "); + selectFieldsSqlBuilder.append("sa.min_balance_for_interest_calculation as minBalanceForInterestCalculation, "); + selectFieldsSqlBuilder.append("sa.withhold_tax as withHoldTax,"); + selectFieldsSqlBuilder.append("tg.id as taxGroupId, tg.name as taxGroupName "); + this.selectFieldsSql = selectFieldsSqlBuilder.toString(); @@ -599,6 +604,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead selectTablesSqlBuilder.append("left join m_appuser abu on abu.id = sa.approvedon_userid "); selectTablesSqlBuilder.append("left join m_appuser avbu on rbu.id = sa.activatedon_userid "); selectTablesSqlBuilder.append("left join m_appuser cbu on cbu.id = sa.closedon_userid "); + selectTablesSqlBuilder.append("left join m_tax_group tg on tg.id = sa.tax_group_id "); this.selectTablesSql = selectTablesSqlBuilder.toString(); } @@ -722,17 +728,26 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead final BigDecimal accountBalance = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "accountBalance"); final BigDecimal totalFeeCharge = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalFeeCharge"); final BigDecimal totalPenaltyCharge = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalPenaltyCharge"); + final BigDecimal totalWithholdTax = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalWithholdTax"); final BigDecimal totalOverdraftInterestDerived = null; + + final boolean withHoldTax = rs.getBoolean("withHoldTax"); + final Long taxGroupId = JdbcSupport.getLong(rs, "taxGroupId"); + final String taxGroupName = rs.getString("taxGroupName"); + TaxGroupData taxGroupData = null; + if (taxGroupId != null) { + taxGroupData = TaxGroupData.lookup(taxGroupId, taxGroupName); + } final SavingsAccountSummaryData summary = new SavingsAccountSummaryData(currency, totalDeposits, totalWithdrawals, totalWithdrawalFees, totalAnnualFees, totalInterestEarned, totalInterestPosted, accountBalance, totalFeeCharge, - totalPenaltyCharge, totalOverdraftInterestDerived); + totalPenaltyCharge, totalOverdraftInterestDerived, totalWithholdTax); return DepositAccountData.instance(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName, fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualInterestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary, depositType, - minBalanceForInterestCalculation); + minBalanceForInterestCalculation, withHoldTax, taxGroupData); } } @@ -1068,7 +1083,9 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead selectFieldsSqlBuilder.append("sa.lockin_period_frequency_enum as lockinPeriodFrequencyType, "); selectFieldsSqlBuilder.append("sa.withdrawal_fee_for_transfer as withdrawalFeeForTransfers, "); selectFieldsSqlBuilder.append("sa.deposit_type_enum as depositTypeId, "); - selectFieldsSqlBuilder.append("sa.min_balance_for_interest_calculation as minBalanceForInterestCalculation "); + selectFieldsSqlBuilder.append("sa.min_balance_for_interest_calculation as minBalanceForInterestCalculation, "); + selectFieldsSqlBuilder.append("sa.withhold_tax as withHoldTax,"); + selectFieldsSqlBuilder.append("tg.id as taxGroupId, tg.name as taxGroupName "); this.selectFieldsSql = selectFieldsSqlBuilder.toString(); @@ -1076,6 +1093,8 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead selectTablesSqlBuilder.append("from m_savings_product sa "); selectTablesSqlBuilder.append("left join m_deposit_product_term_and_preclosure dptp on sa.id = dptp.savings_product_id "); selectTablesSqlBuilder.append("join m_currency curr on curr.code = sa.currency_code "); + selectTablesSqlBuilder.append("left join m_tax_group tg on tg.id = sa.tax_group_id "); + this.selectTablesSql = selectTablesSqlBuilder.toString(); } @@ -1158,12 +1177,20 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead final SavingsAccountStatusEnumData status = null; final SavingsAccountSummaryData summary = null; final SavingsAccountApplicationTimelineData timeline = SavingsAccountApplicationTimelineData.templateDefault(); + + final boolean withHoldTax = rs.getBoolean("withHoldTax"); + final Long taxGroupId = JdbcSupport.getLong(rs, "taxGroupId"); + final String taxGroupName = rs.getString("taxGroupName"); + TaxGroupData taxGroupData = null; + if (taxGroupId != null) { + taxGroupData = TaxGroupData.lookup(taxGroupId, taxGroupName); + } return DepositAccountData.instance(null, null, null, groupId, groupName, clientId, clientName, productId, productName, fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualIterestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary, depositType, - minBalanceForInterestCalculation); + minBalanceForInterestCalculation, withHoldTax, taxGroupData); } } http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/3015747f/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositProductReadPlatformServiceImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositProductReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositProductReadPlatformServiceImpl.java index 70a65cf..3d39e87 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositProductReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositProductReadPlatformServiceImpl.java @@ -36,6 +36,7 @@ import org.apache.fineract.portfolio.savings.data.DepositProductData; import org.apache.fineract.portfolio.savings.data.FixedDepositProductData; import org.apache.fineract.portfolio.savings.data.RecurringDepositProductData; import org.apache.fineract.portfolio.savings.exception.FixedDepositProductNotFoundException; +import org.apache.fineract.portfolio.tax.data.TaxGroupData; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; @@ -144,7 +145,9 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead sqlBuilder.append("sp.lockin_period_frequency as lockinPeriodFrequency,"); sqlBuilder.append("sp.lockin_period_frequency_enum as lockinPeriodFrequencyType, "); sqlBuilder.append("sp.accounting_type as accountingType, "); - sqlBuilder.append("sp.min_balance_for_interest_calculation as minBalanceForInterestCalculation "); + sqlBuilder.append("sp.min_balance_for_interest_calculation as minBalanceForInterestCalculation, "); + sqlBuilder.append("sp.withhold_tax as withHoldTax,"); + sqlBuilder.append("tg.id as taxGroupId, tg.name as taxGroupName "); this.schemaSql = sqlBuilder.toString(); } @@ -197,9 +200,18 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead } final BigDecimal minBalanceForInterestCalculation = rs.getBigDecimal("minBalanceForInterestCalculation"); + final boolean withHoldTax = rs.getBoolean("withHoldTax"); + final Long taxGroupId = JdbcSupport.getLong(rs, "taxGroupId"); + final String taxGroupName = rs.getString("taxGroupName"); + TaxGroupData taxGroupData = null; + if (taxGroupId != null) { + taxGroupData = TaxGroupData.lookup(taxGroupId, taxGroupName); + } + return DepositProductData.instance(id, name, shortName, description, currency, nominalAnnualInterestRate, compoundingInterestPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, - lockinPeriodFrequency, lockinPeriodFrequencyType, accountingRuleType, minBalanceForInterestCalculation); + lockinPeriodFrequency, lockinPeriodFrequencyType, accountingRuleType, minBalanceForInterestCalculation, withHoldTax, + taxGroupData); } } @@ -224,6 +236,7 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead sqlBuilder.append("from m_savings_product sp "); sqlBuilder.append("left join m_deposit_product_term_and_preclosure dptp on sp.id=dptp.savings_product_id "); sqlBuilder.append("join m_currency curr on curr.code = sp.currency_code "); + sqlBuilder.append(" left join m_tax_group tg on tg.id = sp.tax_group_id "); this.schemaSql = sqlBuilder.toString(); } @@ -292,6 +305,7 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead sqlBuilder.append("left join m_deposit_product_term_and_preclosure dptp on sp.id=dptp.savings_product_id "); sqlBuilder.append("left join m_deposit_product_recurring_detail dprd on sp.id=dprd.savings_product_id "); sqlBuilder.append("join m_currency curr on curr.code = sp.currency_code "); + sqlBuilder.append(" left join m_tax_group tg on tg.id = sp.tax_group_id "); this.schemaSql = sqlBuilder.toString(); } http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/3015747f/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/FixedDepositProductWritePlatformServiceJpaRepositoryImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/FixedDepositProductWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/FixedDepositProductWritePlatformServiceJpaRepositoryImpl.java index 02c7db7..3da5ef8 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/FixedDepositProductWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/FixedDepositProductWritePlatformServiceJpaRepositoryImpl.java @@ -18,16 +18,23 @@ */ package org.apache.fineract.portfolio.savings.service; +import static org.apache.fineract.portfolio.savings.DepositsApiConstants.FIXED_DEPOSIT_PRODUCT_RESOURCE_NAME; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.accountingRuleParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.chargesParamName; +import static org.apache.fineract.portfolio.savings.SavingsApiConstants.taxGroupIdParamName; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Set; import org.apache.fineract.accounting.producttoaccountmapping.service.ProductToGLAccountMappingWritePlatformService; import org.apache.fineract.infrastructure.core.api.JsonCommand; +import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; +import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; +import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.portfolio.charge.domain.Charge; @@ -38,6 +45,7 @@ import org.apache.fineract.portfolio.savings.domain.DepositProductAssembler; import org.apache.fineract.portfolio.savings.domain.FixedDepositProduct; import org.apache.fineract.portfolio.savings.domain.FixedDepositProductRepository; import org.apache.fineract.portfolio.savings.exception.FixedDepositProductNotFoundException; +import org.apache.fineract.portfolio.tax.domain.TaxGroup; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -118,6 +126,19 @@ public class FixedDepositProductWritePlatformServiceJpaRepositoryImpl implements } } + if (changes.containsKey(taxGroupIdParamName)) { + final TaxGroup taxGroup = this.depositProductAssembler.assembleTaxGroup(command); + product.setTaxGroup(taxGroup); + if (product.withHoldTax() && product.getTaxGroup() == null) { + final List<ApiParameterError> dataValidationErrors = new ArrayList<>(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) + .resource(FIXED_DEPOSIT_PRODUCT_RESOURCE_NAME); + final Long taxGroupId = null; + baseDataValidator.reset().parameter(taxGroupIdParamName).value(taxGroupId).notBlank(); + throw new PlatformApiDataValidationException(dataValidationErrors); + } + } + // accounting related changes final boolean accountingTypeChanged = changes.containsKey(accountingRuleParamName); final Map<String, Object> accountingMappingChanges = this.accountMappingWritePlatformService http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/3015747f/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/RecurringDepositProductWritePlatformServiceJpaRepositoryImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/RecurringDepositProductWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/RecurringDepositProductWritePlatformServiceJpaRepositoryImpl.java index 2ec93c6..3309816 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/RecurringDepositProductWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/RecurringDepositProductWritePlatformServiceJpaRepositoryImpl.java @@ -18,16 +18,24 @@ */ package org.apache.fineract.portfolio.savings.service; +import static org.apache.fineract.portfolio.savings.DepositsApiConstants.RECURRING_DEPOSIT_PRODUCT_RESOURCE_NAME; +import static org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_PRODUCT_RESOURCE_NAME; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.accountingRuleParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.chargesParamName; +import static org.apache.fineract.portfolio.savings.SavingsApiConstants.taxGroupIdParamName; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Set; import org.apache.fineract.accounting.producttoaccountmapping.service.ProductToGLAccountMappingWritePlatformService; import org.apache.fineract.infrastructure.core.api.JsonCommand; +import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; +import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; +import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.portfolio.charge.domain.Charge; @@ -38,6 +46,7 @@ import org.apache.fineract.portfolio.savings.domain.DepositProductAssembler; import org.apache.fineract.portfolio.savings.domain.RecurringDepositProduct; import org.apache.fineract.portfolio.savings.domain.RecurringDepositProductRepository; import org.apache.fineract.portfolio.savings.exception.RecurringDepositProductNotFoundException; +import org.apache.fineract.portfolio.tax.domain.TaxGroup; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -118,6 +127,19 @@ public class RecurringDepositProductWritePlatformServiceJpaRepositoryImpl implem } } + if (changes.containsKey(taxGroupIdParamName)) { + final TaxGroup taxGroup = this.depositProductAssembler.assembleTaxGroup(command); + product.setTaxGroup(taxGroup); + if (product.withHoldTax() && product.getTaxGroup() == null) { + final List<ApiParameterError> dataValidationErrors = new ArrayList<>(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) + .resource(RECURRING_DEPOSIT_PRODUCT_RESOURCE_NAME); + final Long taxGroupId = null; + baseDataValidator.reset().parameter(taxGroupIdParamName).value(taxGroupId).notBlank(); + throw new PlatformApiDataValidationException(dataValidationErrors); + } + } + // accounting related changes final boolean accountingTypeChanged = changes.containsKey(accountingRuleParamName); final Map<String, Object> accountingMappingChanges = this.accountMappingWritePlatformService http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/3015747f/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountChargeReadPlatformServiceImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountChargeReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountChargeReadPlatformServiceImpl.java index baa3058..e2fa675 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountChargeReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountChargeReadPlatformServiceImpl.java @@ -40,6 +40,7 @@ import org.apache.fineract.portfolio.common.service.DropdownReadPlatformService; import org.apache.fineract.portfolio.savings.data.SavingsAccountAnnualFeeData; import org.apache.fineract.portfolio.savings.data.SavingsAccountChargeData; import org.apache.fineract.portfolio.savings.domain.SavingsAccountStatusType; +import org.apache.fineract.portfolio.tax.data.TaxGroupData; import org.joda.time.LocalDate; import org.joda.time.MonthDay; import org.springframework.beans.factory.annotation.Autowired; @@ -159,12 +160,14 @@ public class SavingsAccountChargeReadPlatformServiceImpl implements SavingsAccou final List<EnumOptionData> feeFrequencyOptions = this.dropdownReadPlatformService.retrievePeriodFrequencyTypeOptions(); // this field is applicable only for client charges final Map<String, List<GLAccountData>> incomeOrLiabilityAccountOptions = null; + + final Collection<TaxGroupData> taxGroupOptions = null; // TODO AA : revisit for merge conflict - Not sure method signature return ChargeData.template(null, allowedChargeCalculationTypeOptions, null, allowedChargeTimeOptions, null, loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions, savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions, clientChargeCalculationTypeOptions, clientChargeTimeTypeOptions, feeFrequencyOptions, - incomeOrLiabilityAccountOptions); + incomeOrLiabilityAccountOptions, taxGroupOptions); } @Override
