interest payouts patch3

This commit is contained in:
Madhukar
2012-09-21 20:53:48 +05:30
parent 4ac094fc78
commit 1f8b325258
19 changed files with 265 additions and 69 deletions
@@ -0,0 +1,13 @@
ALTER TABLE `m_deposit_account_transaction`
ADD COLUMN `interest` decimal(19,6) NOT NULL AFTER `amount`,
ADD COLUMN `total` decimal(19,6) NOT NULL AFTER `interest`;
ALTER TABLE `m_deposit_account`
ADD COLUMN `interest_paid` decimal(19,6) NOT NULL DEFAULT 0 AFTER `actual_total_amount`,
ADD COLUMN `is_interest_withdrawable` tinyint(1) NOT NULL DEFAULT '0' AFTER `interest_paid`;
ALTER TABLE `m_product_deposit`
ADD COLUMN `is_compounding_interest_allowed` tinyint(1) NOT NULL DEFAULT '0' AFTER `maturity_max_interest_rate`;
ALTER TABLE `m_deposit_account`
ADD COLUMN `is_compounding_interest_allowed` tinyint(1) NOT NULL DEFAULT '0' AFTER `actual_total_amount`;
@@ -68,10 +68,10 @@ public class DepositAccountsApiResource {
Arrays.asList("id", "externalId", "clientId", "clientName",
"productId", "productName", "status", "currency",
"deposit", "maturityInterestRate", "tenureInMonths",
"interestCompoundedEvery",
"interestCompoundedEvery","interestCompoundingAllowed",
"interestCompoundedEveryPeriodType", "renewalAllowed",
"preClosureAllowed", "preClosureInterestRate",
"withdrawnonDate","rejectedonDate","closedonDate","transactions"));
"withdrawnonDate","rejectedonDate","closedonDate","transactions","interestPaid","isInterestWithdrawable"));
@POST
@@ -100,7 +100,7 @@ public class DepositProductsApiResource {
"currencyCode","digitsAfterDecimal","minimumBalance","maximumBalance","tenureInMonths",
"maturityDefaultInterestRate","maturityMinInterestRate","maturityMaxInterestRate",
"interestCompoundedEvery", "interestCompoundedEveryPeriodType",
"renewalAllowed","preClosureAllowed","preClosureInterestRate"));
"renewalAllowed","preClosureAllowed","preClosureInterestRate","interestCompoundingAllowed"));
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
if (responseParameters.isEmpty()) {
@@ -123,7 +123,7 @@ public class DepositProductsApiResource {
"currencyCode","digitsAfterDecimal","minimumBalance","maximumBalance","tenureInMonths",
"maturityDefaultInterestRate","maturityMinInterestRate","maturityMaxInterestRate",
"interestCompoundedEvery", "interestCompoundedEveryPeriodType",
"renewalAllowed","preClosureAllowed","preClosureInterestRate"));
"renewalAllowed","preClosureAllowed","preClosureInterestRate","interestCompoundingAllowed"));
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
if (responseParameters.isEmpty()) {
@@ -26,6 +26,8 @@ public class DepositAccountCommand {
private final boolean renewalAllowed;
private final boolean preClosureAllowed;
private final boolean isInterestWithdrawable;
private final boolean interestCompoundingAllowed;
private final Set<String> modifiedParameters;
@@ -37,7 +39,7 @@ public class DepositAccountCommand {
final BigDecimal depositAmount,
final BigDecimal interestRate, final BigDecimal preClosureInterestRate,
final Integer tenureInMonths, final Integer compoundingInterestFrequency, final Integer compoundingInterestFrequencyType, final LocalDate commencementDate,
final boolean renewalAllowed, final boolean preClosureAllowed) {
final boolean renewalAllowed, final boolean preClosureAllowed,final boolean isInterstWithdrawable, final boolean interestCompoundingAllowed) {
this.id = id;
this.clientId = clientId;
this.productId = productId;
@@ -54,6 +56,8 @@ public class DepositAccountCommand {
this.commencementDate = commencementDate;
this.renewalAllowed = renewalAllowed;
this.preClosureAllowed = preClosureAllowed;
this.isInterestWithdrawable = isInterstWithdrawable;
this.interestCompoundingAllowed = interestCompoundingAllowed;
}
public Long getId() {
@@ -100,6 +104,10 @@ public class DepositAccountCommand {
return commencementDate;
}
public boolean isInterestWithdrawable() {
return isInterestWithdrawable;
}
public boolean isRenewalAllowed() {
return renewalAllowed;
}
@@ -108,6 +116,10 @@ public class DepositAccountCommand {
return preClosureAllowed;
}
public boolean isInterestCompoundingAllowed() {
return interestCompoundingAllowed;
}
public boolean isNoFieldChanged() {
return this.modifiedParameters.isEmpty();
}
@@ -131,4 +143,12 @@ public class DepositAccountCommand {
public boolean isPreClosureAllowedChanged() {
return this.modifiedParameters.contains("preClosureAllowed");
}
public boolean isInterestWithdrawableChanged(){
return this.modifiedParameters.contains("isInterestWithdrawable");
}
public boolean isInterestCompoundingAllowedChanged(){
return this.modifiedParameters.contains("interestCompoundingAllowed");
}
}
@@ -26,6 +26,8 @@ public class DepositProductCommand {
private final boolean renewalAllowed;
private final boolean preClosureAllowed;
private final BigDecimal preClosureInterestRate;
private final boolean interestCompoundingAllowed;
private final Set<String> modifiedParameters;
@@ -37,7 +39,8 @@ public class DepositProductCommand {
final BigDecimal maturityMinInterestRate, final BigDecimal maturityMaxInterestRate,
final Integer interestCompoundedEvery,
final Integer interestCompoundedEveryPeriodType,
final boolean renewalAllowed, final boolean preClosureAllowed, final BigDecimal preClosureInterestRate ) {
final boolean renewalAllowed, final boolean preClosureAllowed,
final BigDecimal preClosureInterestRate, final boolean interestCompoundingAllowed ) {
this.id = id;
this.externalId = externalId;
this.name = name;
@@ -59,7 +62,7 @@ public class DepositProductCommand {
this.renewalAllowed = renewalAllowed;
this.preClosureAllowed = preClosureAllowed;
this.interestCompoundingAllowed = interestCompoundingAllowed;
this.modifiedParameters = modifiedParameters;
}
@@ -132,6 +135,10 @@ public class DepositProductCommand {
return preClosureInterestRate;
}
public boolean isInterestCompoundingAllowed() {
return interestCompoundingAllowed;
}
public boolean isExternalIdChanged() {
return this.modifiedParameters.contains("externalId");
}
@@ -203,4 +210,8 @@ public class DepositProductCommand {
public boolean isNoFieldChanged() {
return this.modifiedParameters.isEmpty();
}
public boolean interestCompoundingAllowedChanged(){
return this.modifiedParameters.contains("interestCompoundingAllowed");
}
}
@@ -42,6 +42,10 @@ public class DepositAccountData {
private final boolean preClosureAllowed;
private final BigDecimal preClosureInterestRate;
private final boolean isInterestWithdrawable;
private final BigDecimal interestPaid;
private final boolean interestCompoundingAllowed;
private final List<EnumOptionData> interestCompoundedEveryPeriodTypeOptions;
private final List<DepositProductLookup> productOptions;
@@ -91,6 +95,10 @@ public class DepositAccountData {
this.transactions=null;
this.permissions=null;
this.interestPaid=null;
this.isInterestWithdrawable=false;
this.interestCompoundingAllowed = true;
}
public DepositAccountData(
@@ -130,6 +138,9 @@ public class DepositAccountData {
this.transactions=account.getTransactions();
this.permissions=account.getPermissions();
this.interestPaid=account.getInterestPaid();
this.isInterestWithdrawable=account.isInterestWithdrawable();
this.interestCompoundingAllowed=account.isInterestCompoundingAllowed();
}
public DepositAccountData(final DepositAccountData account, final DepositPermissionData permissions, final Collection<DepositAccountTransactionData> transactions) {
@@ -166,6 +177,9 @@ public class DepositAccountData {
this.transactions=transactions;
this.permissions=permissions;
this.interestPaid=account.getInterestPaid();
this.isInterestWithdrawable=account.isInterestWithdrawable();
this.interestCompoundingAllowed = account.isInterestCompoundingAllowed();
}
public DepositAccountData(
@@ -193,7 +207,10 @@ public class DepositAccountData {
final BigDecimal preClosureInterestRate,
final LocalDate withdrawnonDate,
final LocalDate rejectedonDate,
final LocalDate closedonDate) {
final LocalDate closedonDate,
final boolean isInterestWithdrawable,
final BigDecimal interestPaid,
final boolean interestCompoundingAllowed) {
this.id=id;
this.externalId = externalId;
this.status = status;
@@ -227,6 +244,10 @@ public class DepositAccountData {
this.transactions = null;
this.permissions = null;
this.interestPaid =interestPaid;
this.isInterestWithdrawable=isInterestWithdrawable;
this.interestCompoundingAllowed = interestCompoundingAllowed;
}
public DepositAccountData(
@@ -275,6 +296,9 @@ public class DepositAccountData {
this.transactions = null;
this.permissions = null;
this.interestPaid=null;
this.isInterestWithdrawable=false;
this.interestCompoundingAllowed=true;
}
public Long getId() {
@@ -396,4 +420,17 @@ public class DepositAccountData {
public DepositPermissionData getPermissions() {
return permissions;
}
public boolean isInterestWithdrawable() {
return isInterestWithdrawable;
}
public BigDecimal getInterestPaid() {
return interestPaid;
}
public boolean isInterestCompoundingAllowed() {
return interestCompoundingAllowed;
}
}
@@ -29,6 +29,7 @@ public class DepositProductData {
private final boolean renewalAllowed;
private final boolean preClosureAllowed;
private final BigDecimal preClosureInterestRate;
private final boolean interestCompoundingAllowed;
private final DateTime createdOn;
private final DateTime lastModifedOn;
@@ -55,7 +56,8 @@ public class DepositProductData {
final EnumOptionData interestCompoundedEveryPeriodType,
final boolean renewalAllowed,
final boolean preClosureAllowed,
final BigDecimal preClosureInterestRate) {
final BigDecimal preClosureInterestRate,
final boolean interestCompoundingAllowed) {
this.createdOn=createdOn;
this.lastModifedOn=lastModifedOn;
@@ -77,6 +79,7 @@ public class DepositProductData {
this.renewalAllowed=renewalAllowed;
this.preClosureAllowed=preClosureAllowed;
this.preClosureInterestRate=preClosureInterestRate;
this.interestCompoundingAllowed=interestCompoundingAllowed;
this.currencyOptions = new ArrayList<CurrencyData>();
this.interestCompoundedEveryPeriodTypeOptions = new ArrayList<EnumOptionData>();
@@ -107,6 +110,7 @@ public class DepositProductData {
this.renewalAllowed=true;
this.preClosureAllowed=true;
this.preClosureInterestRate=BigDecimal.ZERO;
this.interestCompoundingAllowed=true;
this.currencyOptions = currencyOptions;
this.interestCompoundedEveryPeriodTypeOptions = interestCompoundedEveryPeriodTypeOptions;
@@ -137,6 +141,7 @@ public class DepositProductData {
this.renewalAllowed=product.isRenewalAllowed();
this.preClosureAllowed=product.isPreClosureAllowed();
this.preClosureInterestRate=product.getPreClosureInterestRate();
this.interestCompoundingAllowed=product.isInterestCompoundingAllowed();
this.currencyOptions = currencyOptions;
this.interestCompoundedEveryPeriodTypeOptions = interestCompoundedEveryPeriodTypeOptions;
@@ -225,4 +230,8 @@ public class DepositProductData {
public List<EnumOptionData> getInterestCompoundedEveryPeriodTypeOptions() {
return interestCompoundedEveryPeriodTypeOptions;
}
public boolean isInterestCompoundingAllowed() {
return interestCompoundingAllowed;
}
}
@@ -1042,8 +1042,8 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
Set<String> supportedParams = new HashSet<String>(
Arrays.asList("clientId", "productId", "externalId", "deposit", "maturityInterestRate", "preClosureInterestRate",
"tenureInMonths", "interestCompoundedEvery", "interestCompoundedEveryPeriodType", "commencementDate",
"renewalAllowed", "preClosureAllowed",
"locale", "dateFormat")
"renewalAllowed", "preClosureAllowed","interestCompoundingAllowed",
"locale", "dateFormat","isInterestWithdrawable")
);
checkForUnsupportedParameters(requestMap, supportedParams);
Set<String> modifiedParameters = new HashSet<String>();
@@ -1062,10 +1062,13 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
boolean renewalAllowed = extractBooleanParameter("renewalAllowed", requestMap, modifiedParameters);
boolean preClosureAllowed = extractBooleanParameter("preClosureAllowed", requestMap, modifiedParameters);
boolean isInterestWithdrawable = extractBooleanParameter("isInterestWithdrawable", requestMap, modifiedParameters);
boolean interestCompoundingAllowed = extractBooleanParameter("interestCompoundingAllowed", requestMap, modifiedParameters);
return new DepositAccountCommand(modifiedParameters, resourceIdentifier, clientId, productId,
externalId, deposit, interestRate, preClosureInterestRate, tenureInMonths,
interestCompoundedEvery, interestCompoundedEveryPeriodType, commencementDate, renewalAllowed, preClosureAllowed);
interestCompoundedEvery, interestCompoundedEveryPeriodType, commencementDate, renewalAllowed,
preClosureAllowed, isInterestWithdrawable, interestCompoundingAllowed);
}
@Override
@@ -1082,7 +1085,7 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
Arrays.asList("locale", "name", "externalId", "description","currencyCode", "digitsAfterDecimal","minimumBalance","maximumBalance","tenureInMonths",
"maturityDefaultInterestRate","maturityMinInterestRate","maturityMaxInterestRate",
"interestCompoundedEvery", "interestCompoundedEveryPeriodType",
"renewalAllowed","preClosureAllowed","preClosureInterestRate")
"renewalAllowed","preClosureAllowed","preClosureInterestRate","interestCompoundingAllowed")
);
checkForUnsupportedParameters(requestMap, supportedParams);
Set<String> modifiedParameters = new HashSet<String>();
@@ -1103,6 +1106,8 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
Integer interestCompoundedEvery = extractIntegerParameter("interestCompoundedEvery", requestMap, modifiedParameters);
Integer interestCompoundedEveryPeriodType = extractIntegerParameter("interestCompoundedEveryPeriodType", requestMap, modifiedParameters);
boolean interestCompoundingAllowed = extractBooleanParameter("interestCompoundingAllowed", requestMap, modifiedParameters);
boolean canRenew = extractBooleanParameter("renewalAllowed", requestMap, modifiedParameters);
boolean canPreClose = extractBooleanParameter("preClosureAllowed", requestMap, modifiedParameters);
BigDecimal preClosureInterestRate = extractBigDecimalParameter("preClosureInterestRate", requestMap, modifiedParameters);
@@ -1111,7 +1116,7 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
name, description, currencyCode, digitsAfterDecimalValue, minimumBalance,maximumBalance,
tenureMonths, maturityDefaultInterestRate, maturityMinInterestRate, maturityMaxInterestRate,
interestCompoundedEvery, interestCompoundedEveryPeriodType,
canRenew, canPreClose, preClosureInterestRate);
canRenew, canPreClose, preClosureInterestRate, interestCompoundingAllowed);
}
@Override
@@ -99,7 +99,7 @@ public class GoogleGsonApiJsonSerializerService implements ApiJsonSerializerServ
"maturityDefaultInterestRate", "maturityMinInterestRate",
"maturityMaxInterestRate", "interestCompoundedEvery",
"interestCompoundedEveryPeriodType", "renewalAllowed",
"preClosureAllowed", "preClosureInterestRate"));
"preClosureAllowed", "preClosureInterestRate", "interestCompoundingAllowed"));
private static final Set<String> SAVINGS_DEPOSIT_ACCOUNT_DATA_PARAMETERS = new HashSet<String>(
Arrays.asList("productOptions", "interestCompoundedEveryPeriodTypeOptions",
@@ -107,7 +107,8 @@ public class GoogleGsonApiJsonSerializerService implements ApiJsonSerializerServ
"currency", "deposit", "maturityInterestRate", "tenureInMonths",
"interestCompoundedEvery", "interestCompoundedEveryPeriodType",
"renewalAllowed","preClosureAllowed","preClosureInterestRate",
"withdrawnonDate","rejectedonDate","closedonDate","transactions","permissions"
"withdrawnonDate","rejectedonDate","closedonDate","transactions",
"permissions","isInterestWithdrawable","interestPaid","interestCompoundingAllowed"
)
);
@@ -124,6 +124,14 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
@Column(name = "withdrawnon_date")
private Date withdrawnOnDate;
@Column(name = "interest_paid", scale = 6, precision = 19, nullable = false)
private BigDecimal interstPaid;
@Column(name = "is_interest_withdrawable", nullable = false)
private boolean isInterestWithdrawable = false;
@Column(name = "is_compounding_interest_allowed", nullable = false)
private boolean interestCompoundingAllowed = false;
// see
// http://stackoverflow.com/questions/4334970/hibernate-cannot-simultaneously-fetch-multiple-bags
@@ -146,11 +154,18 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
final boolean renewalAllowed,
final boolean preClosureAllowed,
final FixedTermDepositInterestCalculator fixedTermDepositInterestCalculator,
final DepositLifecycleStateMachine depositLifecycleStateMachine) {
final DepositLifecycleStateMachine depositLifecycleStateMachine,
final boolean isInterstWithdrawable,final boolean interestCompoundingAllowed) {
Money futureValueOnMaturity = fixedTermDepositInterestCalculator.calculateInterestOnMaturityFor(deposit, tenureInMonths,
Money futureValueOnMaturity =null;
if(interestCompoundingAllowed){
futureValueOnMaturity = fixedTermDepositInterestCalculator.calculateInterestOnMaturityFor(deposit, tenureInMonths,
maturityInterestRate, interestCompoundedEvery, interestCompoundedFrequencyPeriodType);
}else if(!interestCompoundingAllowed){
futureValueOnMaturity = fixedTermDepositInterestCalculator.calculateInterestOnMaturityForSimpleInterest(deposit, tenureInMonths,
maturityInterestRate, interestCompoundedEvery, interestCompoundedFrequencyPeriodType);
}
DepositAccountStatus from = null;
if (depositStatus != null) {
@@ -161,7 +176,8 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
depositStatus = statusEnum.getValue();
return new DepositAccount(client, product, externalId, deposit, maturityInterestRate, preClosureInterestRate, tenureInMonths,
interestCompoundedEvery, interestCompoundedFrequencyPeriodType, commencementDate, renewalAllowed, preClosureAllowed, futureValueOnMaturity,depositStatus);
interestCompoundedEvery, interestCompoundedFrequencyPeriodType, commencementDate, renewalAllowed, preClosureAllowed,
futureValueOnMaturity,depositStatus,isInterstWithdrawable, interestCompoundingAllowed);
}
public DepositAccount() {
@@ -177,7 +193,9 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
final boolean renewalAllowed,
final boolean preClosureAllowed,
final Money futureValueOnMaturity,
final Integer depositStatus) {
final Integer depositStatus,
final boolean isInterestWithdrawable,
final boolean interestCompoundingAllowed) {
this.client = client;
this.product = product;
setExternalId(externalId);
@@ -200,11 +218,14 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
this.preClosureAllowed = preClosureAllowed;
this.preClosureInterestRate = preClosureInterestRate;
this.isInterestWithdrawable = isInterestWithdrawable;
this.interestCompoundingAllowed = interestCompoundingAllowed;
// derived fields
this.projectedInterestAccruedOnMaturity = futureValueOnMaturity.minus(deposit).getAmount();
this.projectedTotalOnMaturity = futureValueOnMaturity.getAmount();
this.depositStatus=depositStatus;
this.interstPaid = new BigDecimal(0);
}
private void setExternalId(final String externalId) {
@@ -253,19 +274,21 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
this.actualCommencementDate = actualCommencementDate.toDate();
this.maturesOnDate = getActualCommencementDate().plusMonths(this.tenureInMonths).toDate();
Money futureValueOnMaturity = calculator.calculateInterestOnMaturityFor(getDeposit(), this.tenureInMonths,
this.interestRate, this.interestCompoundedEvery, getInterestCompoundedFrequencyType());
Money futureValueOnMaturity =null;
if(this.interestCompoundingAllowed){
futureValueOnMaturity = calculator.calculateInterestOnMaturityFor(getDeposit(), this.tenureInMonths,
this.interestRate, this.interestCompoundedEvery, getInterestCompoundedFrequencyType());
} else if(!this.interestCompoundingAllowed){
futureValueOnMaturity = calculator.calculateInterestOnMaturityForSimpleInterest(getDeposit(), this.tenureInMonths,
this.interestRate, this.interestCompoundedEvery, getInterestCompoundedFrequencyType());
}
this.interestAccrued = futureValueOnMaturity.minus(getDeposit()).getAmount();
this.total = futureValueOnMaturity.getAmount();
this.total = this.interestCompoundingAllowed?futureValueOnMaturity.getAmount():getDeposit().getAmount();
DepositAccountTransaction depositaccountTransaction = DepositAccountTransaction.deposit(getDeposit(), getActualCommencementDate(),getAccuredInterest());
depositaccountTransaction.updateAccount(this);
this.depositaccountTransactions.add(depositaccountTransaction);/*
depositaccountTransaction = DepositAccountTransaction.deposit(getAccuredInterest(), getActualCommencementDate(), getAccuredInterest());
depositaccountTransaction.updateAccount(this);
this.depositaccountTransactions.add(depositaccountTransaction);*/
this.depositaccountTransactions.add(depositaccountTransaction);
LocalDate submittalDate = new LocalDate(this.projectedCommencementDate);
if (actualCommencementDate.isBefore(submittalDate)) {
@@ -315,6 +338,10 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
return total;
}
public boolean isInterestCompoundingAllowed() {
return interestCompoundingAllowed;
}
public void reject(final LocalDate rejectedOn,
final DepositLifecycleStateMachine depositLifecycleStateMachine) {
@@ -415,6 +442,14 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
return this.renewalAllowed;
}
public BigDecimal getInterstPaid() {
return this.interstPaid;
}
public boolean isInterestWithdrawable() {
return isInterestWithdrawable;
}
public Integer getTenureInMonths() {
return tenureInMonths;
}
@@ -503,11 +538,7 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
DepositAccountTransaction depositaccountTransaction = DepositAccountTransaction.withdraw(getDeposit(), new LocalDate(),getAccuredInterest());
depositaccountTransaction.updateAccount(this);
this.depositaccountTransactions.add(depositaccountTransaction);/*
depositaccountTransaction = DepositAccountTransaction.withdraw(getAccuredInterest(), new LocalDate(),getAccuredInterest());
depositaccountTransaction.updateAccount(this);
this.depositaccountTransactions.add(depositaccountTransaction);*/
this.depositaccountTransactions.add(depositaccountTransaction);
DepositAccountStatus statusEnumForClose = depositLifecycleStateMachine.transition(DepositAccountEvent.DEPOSIT_CLOSED, DepositAccountStatus.fromInt(this.depositStatus));
this.depositStatus = statusEnumForClose.getValue();
@@ -523,11 +554,7 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
DepositAccountTransaction depositaccountTransaction = DepositAccountTransaction.withdraw(getDeposit(), new LocalDate(),getAccuredInterest());
depositaccountTransaction.updateAccount(this);
this.depositaccountTransactions.add(depositaccountTransaction);/*
depositaccountTransaction = DepositAccountTransaction.withdraw(getAccuredInterest(), new LocalDate(),getAccuredInterest());
depositaccountTransaction.updateAccount(this);
this.depositaccountTransactions.add(depositaccountTransaction);*/
this.depositaccountTransactions.add(depositaccountTransaction);
this.closedOnDate = new LocalDate().toDate();
this.withdrawnOnDate = null;
@@ -544,10 +571,13 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
Integer tenure = Months.monthsBetween(commnencementDate, preClosedDate).getMonths();
Money deposit = Money.of(account.getDeposit().getCurrency(), account.getDeposit().getAmount());
Money accuredtotalAmount = fixedTermDepositInterestCalculator.calculateInterestOnMaturityFor(deposit, tenure,
preClosureInterestRate, interestCompoundedEvery, this.product.getInterestCompoundedEveryPeriodType());
this.total = accuredtotalAmount.getAmount();
Money accuredtotalAmount = null;
if(account.isInterestCompoundingAllowed()){
accuredtotalAmount = fixedTermDepositInterestCalculator.calculateInterestOnMaturityFor(deposit, tenure, preClosureInterestRate, interestCompoundedEvery, this.product.getInterestCompoundedEveryPeriodType());
}else if(!account.isInterestCompoundingAllowed()){
accuredtotalAmount = fixedTermDepositInterestCalculator.calculateInterestOnMaturityForSimpleInterest(deposit, tenure, preClosureInterestRate, interestCompoundedEvery, this.product.getInterestCompoundedEveryPeriodType());
}
this.total = account.isInterestCompoundingAllowed()?accuredtotalAmount.getAmount():getDeposit().getAmount();
this.interestAccrued = accuredtotalAmount.minus(deposit).getAmount();
}
@@ -558,6 +588,7 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
DepositAccountTransaction depositAccountTransaction = DepositAccountTransaction.withdraw(null, new LocalDate(), interest);
depositAccountTransaction.updateAccount(this);
this.depositaccountTransactions.add(depositAccountTransaction);
this.interstPaid = this.interstPaid.add(interest.getAmount());
}
}
@@ -65,7 +65,7 @@ public class DepositAccountTransaction extends AbstractPersistable<Long> {
this.amount = amount;
this.dateOf = date.toDateMidnight().toDate();
this.interest = interest;
this.total = amount.equals(0)?new BigDecimal(0):amount.add(interest);
this.total = amount.doubleValue()==0?new BigDecimal(0):amount.add(interest);
}
public Date getDateOf() {
@@ -63,4 +63,23 @@ public class FixedTermDepositInterestCalculator {
}
return retval;
}
public Money calculateInterestOnMaturityForSimpleInterest(Money deposit,
Integer tenureInMonths, BigDecimal maturityInterestRate,
Integer interestCompoundedEvery,
PeriodFrequencyType interestCompoundedFrequencyPeriodType) {
MathContext mc = new MathContext(8, RoundingMode.HALF_EVEN);
Integer monthsInYear = 12;
BigDecimal interestRateAsFraction = maturityInterestRate.divide(BigDecimal.valueOf(100), mc);
BigDecimal interestRateForOneMonth = interestRateAsFraction.divide(BigDecimal.valueOf(monthsInYear.doubleValue()), mc);
BigDecimal ratePerCompoundingPeriod = interestRateForOneMonth.multiply(BigDecimal.valueOf(interestCompoundedEvery.doubleValue()), mc);
Integer numberOfPeriods = tenureInMonths / interestCompoundedEvery;
BigDecimal interest = ratePerCompoundingPeriod.multiply(deposit.getAmount()).multiply(BigDecimal.valueOf(new Double(numberOfPeriods)));
BigDecimal totalAmount =deposit.getAmount().add(interest);
return Money.of(deposit.getCurrency(), totalAmount);
}
}
@@ -52,6 +52,8 @@ public class DepositAccountAssembler {
throw new DepositProductNotFoundException(command.getProductId());
}
boolean isInterestWithdrawable = command.isInterestWithdrawable();
// details inherited from product setting (unless allowed to be overridden through account creation api
Money deposit = Money.of(product.getCurrency(), command.getDepositAmount());
@@ -93,6 +95,11 @@ public class DepositAccountAssembler {
if (command.isPreClosureAllowedChanged()) {
preClosureAllowed = command.isPreClosureAllowed();
}
boolean interestCompoundingAllowed= product.isInterestCompoundingAllowed();
if(command.isInterestCompoundingAllowedChanged()){
interestCompoundingAllowed = command.isInterestCompoundingAllowed();
}
// end of details allowed to be overriden from product
DepositAccount account =new DepositAccount().openNew(client, product, command.getExternalId(),
@@ -100,7 +107,8 @@ public class DepositAccountAssembler {
maturityInterestRate, preClosureInterestRate,
tenureInMonths, compoundingInterestEvery, compoundingInterestFrequency,
command.getCommencementDate(),
renewalAllowed, preClosureAllowed, this.fixedTermDepositInterestCalculator, defaultDepositLifecycleStateMachine());
renewalAllowed, preClosureAllowed, this.fixedTermDepositInterestCalculator,
defaultDepositLifecycleStateMachine(),isInterestWithdrawable,interestCompoundingAllowed);
return account;
}
@@ -141,7 +149,8 @@ public class DepositAccountAssembler {
maturityInterestRate, preClosureInterestRate,
tenureInMonths, compoundingInterestEvery, compoundingInterestFrequency,
account.maturesOnDate(),
renewalAllowed, preClosureAllowed, this.fixedTermDepositInterestCalculator, defaultDepositLifecycleStateMachine());
renewalAllowed, preClosureAllowed, this.fixedTermDepositInterestCalculator, defaultDepositLifecycleStateMachine(),
account.isInterestWithdrawable(),product.isInterestCompoundingAllowed());
newAccount.updateAccount(account);
@@ -155,7 +155,8 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
+ " da.projected_total_maturity_amount as projectedMaturityAmount, da.actual_total_amount as actualMaturityAmount, "
+ " da.interest_compounded_every as interestCompoundedEvery, da.interest_compounded_every_period_enum as interestCompoundedEveryPeriodType, "
+ " da.is_renewal_allowed as renewalAllowed, da.is_preclosure_allowed as preClosureAllowed, da.pre_closure_interest_rate as preClosureInterestRate, "
+ " da.withdrawnon_date as withdrawnonDate, da.rejectedon_date as rejectedonDate, da.closedon_date as closedonDate, "
+ " da.withdrawnon_date as withdrawnonDate, da.rejectedon_date as rejectedonDate, da.closedon_date as closedonDate, "
+ " da.interest_paid as interestPaid, da.is_interest_withdrawable as isInterestWithdrawable, da.is_compounding_interest_allowed as interestCompoundingAllowed, "
+ " c.firstname as firstname, c.lastname as lastname, pd.name as productName,"
+ " curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol "
+ " from m_deposit_account da "
@@ -205,6 +206,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
boolean renewalAllowed = rs.getBoolean("renewalAllowed");
boolean preClosureAllowed = rs.getBoolean("preClosureAllowed");
boolean interestCompoundingAllowed = rs.getBoolean("interestCompoundingAllowed");
BigDecimal preClosureInterestRate = rs.getBigDecimal("preClosureInterestRate");
@@ -212,12 +214,15 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
LocalDate rejectedonDate = JdbcSupport.getLocalDate(rs, "rejectedonDate");
LocalDate closedonDate = JdbcSupport.getLocalDate(rs, "closedonDate");
boolean isInterestWithdrawable = rs.getBoolean("isInterestWithdrawable");
BigDecimal interestPaid = rs.getBigDecimal("interestPaid");
return new DepositAccountData(id, externalId, status, clientId, clientName, productId, productName, currencyData, depositAmount,
interestRate, termInMonths, projectedCommencementDate, actualCommencementDate, maturedOn,
projectedInterestAccrued, actualInterestAccrued, projectedMaturityAmount, actualMaturityAmount,
interestCompoundedEvery, interestCompoundedEveryPeriodType,
renewalAllowed, preClosureAllowed, preClosureInterestRate,
withdrawnonDate,rejectedonDate,closedonDate);
withdrawnonDate,rejectedonDate,closedonDate,isInterestWithdrawable,interestPaid,interestCompoundingAllowed);
}
}
@@ -336,25 +336,40 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
if (account == null || account.isDeleted()) {
throw new DepositAccountNotFoundException(command.getAccountId());
}
BigDecimal interstGettingForPeriod = BigDecimal.valueOf(account.getAccuredInterest().getAmount().doubleValue()/new Double(account.getTenureInMonths()));
LocalDate lastInterestTakenDate = getLastTxnDate(account);
Integer noOfMonthsforInterestCal = Months.monthsBetween(lastInterestTakenDate, new LocalDate()).getMonths();
Integer noOfPeriods = noOfMonthsforInterestCal / account.getInterestCompoundedEvery();
BigDecimal availableInterestAmountForWithDrawal = interstGettingForPeriod.multiply(new BigDecimal(noOfPeriods));
BigDecimal cmdInterest = command.getWithdrawInterest();
Integer iswithdrawable = availableInterestAmountForWithDrawal.compareTo(command.getWithdrawInterest());
if(noOfPeriods > 0 ){
if(iswithdrawable >= 0){
account.withdrawInterest(Money.of(account.getDeposit().getCurrency(), cmdInterest));
this.depositAccountRepository.save(account);
if(account.isInterestWithdrawable()){
/*BigDecimal interstGettingForPeriod = BigDecimal.valueOf(account.getAccuredInterest().getAmount().doubleValue()/new Double(account.getTenureInMonths()));
LocalDate lastInterestTakenDate = getLastTxnDate(account);
Integer noOfMonthsforInterestCal = Months.monthsBetween(lastInterestTakenDate, new LocalDate()).getMonths();
Integer noOfPeriods = noOfMonthsforInterestCal / account.getInterestCompoundedEvery();
BigDecimal availableInterestAmountForWithDrawal = interstGettingForPeriod.multiply(new BigDecimal(noOfPeriods));
Integer iswithdrawable = availableInterestAmountForWithDrawal.compareTo(command.getWithdrawInterest());*/
BigDecimal totalAvailableInterestForWithdrawal = getTotalWithdrawableInterestAvailable(account);
BigDecimal interestPaid = account.getInterstPaid();
BigDecimal remainInterestForWithdrawal = totalAvailableInterestForWithdrawal.subtract(interestPaid);
if(remainInterestForWithdrawal.doubleValue() > 0){
if(remainInterestForWithdrawal.doubleValue() > command.getWithdrawInterest().doubleValue()){
account.withdrawInterest(Money.of(account.getDeposit().getCurrency(), command.getWithdrawInterest()));
this.depositAccountRepository.save(account);
}else {
throw new RuntimeException("You can Withdraw "+remainInterestForWithdrawal+" only, \n please enter a valid amount for withdrawal");
}
}
}else if(noOfPeriods <= 0){
if(iswithdrawable==-1){
/*if(noOfPeriods > 0 ){
if(iswithdrawable >= 0){
account.withdrawInterest(Money.of(account.getDeposit().getCurrency(), command.getWithdrawInterest()));
this.depositAccountRepository.save(account);
}else if(iswithdrawable == -1){
throw new RuntimeException();
}
}else if(noOfPeriods <= 0){
throw new RuntimeException();
}*/
}else{
throw new RuntimeException("You can not withdraw interst for this account");
}
return new EntityIdentifier(account.getId());
}
@@ -375,4 +390,11 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
lastTransactionDate = account.getActualCommencementDate();
return lastTransactionDate;
}
private BigDecimal getTotalWithdrawableInterestAvailable(DepositAccount account){
BigDecimal interstGettingForPeriod = BigDecimal.valueOf(account.getAccuredInterest().getAmount().doubleValue()/new Double(account.getTenureInMonths()));
Integer noOfMonthsforInterestCal = Months.monthsBetween(account.getActualCommencementDate(), new LocalDate()).getMonths();
Integer noOfPeriods = noOfMonthsforInterestCal / account.getInterestCompoundedEvery();
return interstGettingForPeriod.multiply(new BigDecimal(noOfPeriods));
}
}
@@ -69,6 +69,9 @@ public class DepositProduct extends AbstractAuditableCustom<AppUser, Long> {
@Column(name = "is_preclosure_allowed", nullable=false)
private boolean preClosureAllowed = false;
@Column(name = "is_compounding_interest_allowed", nullable=false)
private boolean interestCompoundingAllowed = false;
@Column(name = "pre_closure_interest_rate", scale = 6, precision = 19, nullable = false)
private BigDecimal preClosureInterestRate;
@@ -87,7 +90,8 @@ public class DepositProduct extends AbstractAuditableCustom<AppUser, Long> {
final PeriodFrequencyType interestCompoundedEveryPeriodType,
final boolean canRenew,
final boolean canPreClose,
final BigDecimal preClosureInterestRate) {
final BigDecimal preClosureInterestRate,
final boolean isInterestCompoundingAllowed) {
this.name = name.trim();
if (StringUtils.isNotBlank(description)) {
this.description = description.trim();
@@ -112,6 +116,7 @@ public class DepositProduct extends AbstractAuditableCustom<AppUser, Long> {
this.renewalAllowed = canRenew;
this.preClosureAllowed = canPreClose;
this.preClosureInterestRate = preClosureInterestRate;
this.interestCompoundingAllowed = isInterestCompoundingAllowed;
}
public MonetaryCurrency getCurrency() {
@@ -150,6 +155,10 @@ public class DepositProduct extends AbstractAuditableCustom<AppUser, Long> {
return this.preClosureAllowed;
}
public boolean isInterestCompoundingAllowed() {
return interestCompoundingAllowed;
}
public boolean isDeleted() {
return deleted;
}
@@ -236,6 +245,10 @@ public class DepositProduct extends AbstractAuditableCustom<AppUser, Long> {
if (command.isPreClosureInterestRateChanged()) {
this.preClosureInterestRate=command.getPreClosureInterestRate();
}
if(command.interestCompoundingAllowedChanged()){
this.interestCompoundingAllowed = command.isInterestCompoundingAllowed();
}
}
public void validateInterestRateInRange(final BigDecimal interestRate) {
@@ -44,6 +44,7 @@ public class DepositProductCommandValidator {
baseDataValidator.reset().parameter("renewalAllowed").trueOrFalseRequired(command.isRenewalAllowedChanged());
baseDataValidator.reset().parameter("preClosureAllowed").trueOrFalseRequired(command.isPreClosureAllowedChanged());
baseDataValidator.reset().parameter("interestCompoundingAllowed").trueOrFalseRequired(command.interestCompoundingAllowedChanged());
baseDataValidator.reset().parameter("preClosureInterestRate").value(command.getPreClosureInterestRate()).notNull().zeroOrPositiveAmount();
baseDataValidator.reset().parameter("preClosureInterestRate").comapareMinAndMaxOfTwoBigDecmimalNos(command.getPreClosureInterestRate(), command.getMaturityMinInterestRate());
@@ -79,7 +80,6 @@ public class DepositProductCommandValidator {
baseDataValidator.reset().parameter("interestCompoundedEvery").value(command.getInterestCompoundedEvery()).ignoreIfNull().zeroOrPositiveAmount();
baseDataValidator.reset().parameter("interestCompoundedEveryPeriodType").value(command.getInterestCompoundedEveryPeriodType()).ignoreIfNull().inMinMaxRange(1, 3);
baseDataValidator.reset().parameter("preClosureInterestRate").value(command.getPreClosureInterestRate()).ignoreIfNull().zeroOrPositiveAmount();
baseDataValidator.reset().comapareMinAndMaxOfTwoBigDecmimalNos(command.getPreClosureInterestRate(), command.getMaturityMinInterestRate());
@@ -72,7 +72,7 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead
return " dp.id as id, dp.external_id as exernalId, dp.name as name, dp.description as description,dp.currency_code as currencyCode, dp.currency_digits as currencyDigits,dp.minimum_balance as minimumBalance,dp.maximum_balance as maximumBalance," +
"dp.created_date as createdon, dp.lastmodified_date as modifiedon,dp.tenure_months as tenureMonths, " +
"dp.interest_compounded_every as interestCompoundedEvery, dp.interest_compounded_every_period_enum as interestCompoundedEveryPeriodType, " +
"dp.maturity_default_interest_rate as maturityDefaultInterestRate, " +
"dp.maturity_default_interest_rate as maturityDefaultInterestRate, dp.is_compounding_interest_allowed as interestCompoundingAllowed, " +
"dp.maturity_min_interest_rate as maturityMinInterestRate, dp.maturity_max_interest_rate as maturityMaxInterestRate, dp.is_renewal_allowed as canRenew, dp.is_preclosure_allowed as canPreClose, dp.pre_closure_interest_rate as preClosureInterestRate, " +
"curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol " +
"from m_product_deposit dp join m_currency curr on curr.code = dp.currency_code ";
@@ -107,13 +107,14 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead
Boolean canRenew = rs.getBoolean("canRenew");
Boolean canPreClose=rs.getBoolean("canPreClose");
Boolean interestCompoundingAllowed= rs.getBoolean("interestCompoundingAllowed");
BigDecimal preClosureInterestRate=rs.getBigDecimal("preClosureInterestRate");
return new DepositProductData(createdOn, lastModifedOn, id, exernalId, name, description, currencyCode, currencyDigits, minimumBalance, maximumBalance,
tenureMonths, maturityDefaultInterestRate,maturityMinInterestRate,maturityMaxInterestRate,
interestCompoundedEvery, interestCompoundedEveryPeriodType,
canRenew,canPreClose,preClosureInterestRate);
canRenew,canPreClose,preClosureInterestRate,interestCompoundingAllowed);
}
}
@@ -62,7 +62,7 @@ public class DepositProductWritePlatformServiceJpaRepositoryImpl implements Depo
command.getTenureInMonths(),command.getMaturityDefaultInterestRate(),command.getMaturityMinInterestRate(),command.getMaturityMaxInterestRate(),
command.getInterestCompoundedEvery(), interestCompoundingPeriodType,
command.isRenewalAllowed(), command.isPreClosureAllowed(),
command.getPreClosureInterestRate());
command.getPreClosureInterestRate(),command.isInterestCompoundingAllowed());
this.depositProductRepository.save(product);
return new EntityIdentifier(product.getId());