Madhukars interest posting for fixed deposit and recurrint deposit work.

This commit is contained in:
Madhukar
2012-12-04 15:10:44 +00:00
committed by Keith Woodlock
parent 2dd5c5a7cd
commit d1a1ed60ab
30 changed files with 1683 additions and 845 deletions
+3
View File
@@ -123,6 +123,9 @@ function getBaseURL(docURL)
<tr><td></td><td>offices/{officeId}</td><td></td><td><a href="#offices_retrieve">Retrieve an Office</a></td><td><a href="#offices_update">Update an Office</a></td><td></td></tr> <tr><td></td><td>offices/{officeId}</td><td></td><td><a href="#offices_retrieve">Retrieve an Office</a></td><td><a href="#offices_update">Update an Office</a></td><td></td></tr>
<tr class="alt"><td><a href="#loanproducts">LOAN PRODUCT</a></td><td>loanproducts</td><td><a href="#loanproducts_create">Create a Loan Product</a></td><td><a href="#loanproducts_list">List Loan Products</a></td><td></td><td></td></tr> <tr class="alt"><td><a href="#loanproducts">LOAN PRODUCT</a></td><td>loanproducts</td><td><a href="#loanproducts_create">Create a Loan Product</a></td><td><a href="#loanproducts_list">List Loan Products</a></td><td></td><td></td></tr>
<tr><td></td><td>loanproducts/{productId}</td><td></td><td><a href="#loanproducts_retrieve">Retrieve a Loan Product</a></td><td><a href="#loanproducts_update">Update a Loan Product</a></td><td></td></tr> <tr><td></td><td>loanproducts/{productId}</td><td></td><td><a href="#loanproducts_retrieve">Retrieve a Loan Product</a></td><td><a href="#loanproducts_update">Update a Loan Product</a></td><td></td></tr>
<tr></tr>
<tr class="alt"><td><a href="#loans">FIXED DEPOSITS</a></td><td>depositaccounts</td><td><a href="#loans_create">Create a New Deposit Application</a></td><td><a href="#loans_create">List Deposit Applications</a></td><td></td><td></td></tr>
<tr><td></td><td>depositaccounts/{accountId}</td><td><a href="#loans_approve_etc">Approve, Undo Approve, Interest withdraw, Reject a Deposit Application or Withdraw a Deposit Application</a></td><td><a href="#loans_retrieve">Retrieve a Deposit Application</a></td><td> <a href="#loans_delete">Update a Deposit Application</a></td><td><a href="#loans_delete">Delete a Deposit Application</a></td></tr>
</table> </table>
</div> </div>
</div> </div>
@@ -0,0 +1,18 @@
DROP TABLE IF EXISTS `m_saving_schedule`
CREATE TABLE `m_saving_schedule` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`saving_account_id` bigint(20) NOT NULL,
`duedate` date NOT NULL,
`installment` smallint(5) NOT NULL,
`deposit` decimal(21,4) NOT NULL,
`payment_date` date DEFAULT NULL,
`deposit_paid` decimal(21,4) DEFAULT NULL,
`completed_derived` bit(1) NOT NULL,
`createdby_id` bigint(20) DEFAULT NULL,
`created_date` datetime DEFAULT NULL,
`lastmodified_date` datetime DEFAULT NULL,
`lastmodifiedby_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FKSS00000000001` (`saving_account_id`),
CONSTRAINT `FKSS00000000001` FOREIGN KEY (`saving_account_id`) REFERENCES `m_saving_account` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@@ -31,6 +31,7 @@ import org.mifosplatform.portfolio.loanaccount.gaurantor.data.GuarantorData;
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData; import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData; import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountData; import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData;
import org.mifosplatform.portfolio.savingsaccountproduct.data.SavingProductData; import org.mifosplatform.portfolio.savingsaccountproduct.data.SavingProductData;
import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositAccountData; import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositAccountData;
import org.mifosplatform.portfolio.savingsdepositproduct.data.DepositProductData; import org.mifosplatform.portfolio.savingsdepositproduct.data.DepositProductData;
@@ -167,6 +168,9 @@ public class GoogleGsonPortfolioApiJsonSerializerService implements PortfolioApi
"firstname", "lastname", "addressLine1", "addressLine2", "city", "state", "zip", "country", "mobileNumber", "housePhoneNumber", "firstname", "lastname", "addressLine1", "addressLine2", "city", "state", "zip", "country", "mobileNumber", "housePhoneNumber",
"comment", "dob")); "comment", "dob"));
private static final Set<String> SAVING_SCHEDULE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("periods",
"cumulativeDepositDue"));
private final GoogleGsonSerializerHelper helper; private final GoogleGsonSerializerHelper helper;
@Autowired @Autowired
@@ -555,4 +559,11 @@ public class GoogleGsonPortfolioApiJsonSerializerService implements PortfolioApi
prettyPrint, responseParameters); prettyPrint, responseParameters);
return helper.serializedJsonFrom(gsonDeserializer, guarantorData); return helper.serializedJsonFrom(gsonDeserializer, guarantorData);
} }
@Override
public String serializeSavingScheduleDataToJson(boolean prettyPrint, Set<String> responseParameters, SavingScheduleData savingScheduleData) {
final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(SAVING_SCHEDULE_DATA_PARAMETERS,
prettyPrint, responseParameters);
return helper.serializedJsonFrom(gsonDeserializer, savingScheduleData);
}
} }
@@ -1528,7 +1528,7 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo
"digitsAfterDecimal", "savingsDepositAmountPerPeriod", "recurringInterestRate", "savingInterestRate", "tenure", "digitsAfterDecimal", "savingsDepositAmountPerPeriod", "recurringInterestRate", "savingInterestRate", "tenure",
"commencementDate", "locale", "dateFormat", "isLockinPeriodAllowed", "lockinPeriod", "lockinPeriodType", "commencementDate", "locale", "dateFormat", "isLockinPeriodAllowed", "lockinPeriod", "lockinPeriodType",
"savingProductType", "tenureType", "frequency", "interestType", "interestCalculationMethod", "minimumBalanceForWithdrawal", "savingProductType", "tenureType", "frequency", "interestType", "interestCalculationMethod", "minimumBalanceForWithdrawal",
"isPartialDepositAllowed")); "isPartialDepositAllowed","payEvery"));
checkForUnsupportedParameters(requestMap, supportedParams); checkForUnsupportedParameters(requestMap, supportedParams);
Set<String> modifiedParameters = new HashSet<String>(); Set<String> modifiedParameters = new HashSet<String>();
@@ -1554,11 +1554,12 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo
Integer interestCalculationMethod = extractIntegerParameter("interestCalculationMethod", requestMap, modifiedParameters); Integer interestCalculationMethod = extractIntegerParameter("interestCalculationMethod", requestMap, modifiedParameters);
BigDecimal minimumBalanceForWithdrawal = extractBigDecimalParameter("minimumBalanceForWithdrawal", requestMap, modifiedParameters); BigDecimal minimumBalanceForWithdrawal = extractBigDecimalParameter("minimumBalanceForWithdrawal", requestMap, modifiedParameters);
boolean isPartialDepositAllowed = extractBooleanParameter("isPartialDepositAllowed", requestMap, modifiedParameters); boolean isPartialDepositAllowed = extractBooleanParameter("isPartialDepositAllowed", requestMap, modifiedParameters);
Integer payEvery = extractIntegerParameter("payEvery", requestMap, modifiedParameters);
return new SavingAccountCommand(modifiedParameters, resourceIdentifier, clientId, productId, externalId, currencyCode, return new SavingAccountCommand(modifiedParameters, resourceIdentifier, clientId, productId, externalId, currencyCode,
digitsAfterDecimalValue, savingsDepositAmount, recurringInterestRate, savingInterestRate, tenure, commencementDate, digitsAfterDecimalValue, savingsDepositAmount, recurringInterestRate, savingInterestRate, tenure, commencementDate,
savingProductType, tenureType, frequency, interestType, minimumBalanceForWithdrawal, interestCalculationMethod, savingProductType, tenureType, frequency, interestType, minimumBalanceForWithdrawal, interestCalculationMethod,
isLockinPeriodAllowed, isPartialDepositAllowed, lockinPeriod, lockinPeriodType); isLockinPeriodAllowed, isPartialDepositAllowed, lockinPeriod, lockinPeriodType,payEvery);
} }
@Override @Override
@@ -5,6 +5,7 @@ import java.util.Set;
import org.mifosplatform.commands.data.CommandSourceData; import org.mifosplatform.commands.data.CommandSourceData;
import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
import org.mifosplatform.infrastructure.dataqueries.data.DatatableData; import org.mifosplatform.infrastructure.dataqueries.data.DatatableData;
import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData; import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData;
import org.mifosplatform.infrastructure.documentmanagement.data.DocumentData; import org.mifosplatform.infrastructure.documentmanagement.data.DocumentData;
@@ -28,6 +29,7 @@ import org.mifosplatform.portfolio.loanaccount.gaurantor.data.GuarantorData;
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData; import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData; import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountData; import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData;
import org.mifosplatform.portfolio.savingsaccountproduct.data.SavingProductData; import org.mifosplatform.portfolio.savingsaccountproduct.data.SavingProductData;
import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositAccountData; import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositAccountData;
import org.mifosplatform.portfolio.savingsdepositproduct.data.DepositProductData; import org.mifosplatform.portfolio.savingsdepositproduct.data.DepositProductData;
@@ -153,4 +155,6 @@ public interface PortfolioApiJsonSerializerService {
String serializeGuarantorDataToJson(boolean prettyPrint, Set<String> responseParameters, GuarantorData guarantorData); String serializeGuarantorDataToJson(boolean prettyPrint, Set<String> responseParameters, GuarantorData guarantorData);
String serializeSavingScheduleDataToJson(boolean prettyPrint, Set<String> responseParameters, SavingScheduleData savingScheduleData);
} }
@@ -18,13 +18,17 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.infrastructure.core.api.ApiParameterHelper; import org.mifosplatform.infrastructure.core.api.ApiParameterHelper;
import org.mifosplatform.infrastructure.core.api.PortfolioApiDataConversionService; import org.mifosplatform.infrastructure.core.api.PortfolioApiDataConversionService;
import org.mifosplatform.infrastructure.core.api.PortfolioApiJsonSerializerService; import org.mifosplatform.infrastructure.core.api.PortfolioApiJsonSerializerService;
import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.portfolio.savingsaccount.command.CalculateSavingScheduleCommand;
import org.mifosplatform.portfolio.savingsaccount.command.SavingAccountCommand; import org.mifosplatform.portfolio.savingsaccount.command.SavingAccountCommand;
import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountData; import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData;
import org.mifosplatform.portfolio.savingsaccount.service.CalculateSavingSchedule;
import org.mifosplatform.portfolio.savingsaccount.service.SavingAccountReadPlatformService; import org.mifosplatform.portfolio.savingsaccount.service.SavingAccountReadPlatformService;
import org.mifosplatform.portfolio.savingsaccount.service.SavingAccountWritePlatformService; import org.mifosplatform.portfolio.savingsaccount.service.SavingAccountWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -36,113 +40,135 @@ import org.springframework.stereotype.Component;
@Scope("singleton") @Scope("singleton")
public class SavingsAccountApiResource { public class SavingsAccountApiResource {
@Autowired @Autowired
private SavingAccountWritePlatformService savingAccountWritePlatformService; private SavingAccountWritePlatformService savingAccountWritePlatformService;
@Autowired @Autowired
private SavingAccountReadPlatformService savingAccountReadPlatformService; private SavingAccountReadPlatformService savingAccountReadPlatformService;
@Autowired @Autowired
private PortfolioApiDataConversionService apiDataConversionService; private PortfolioApiDataConversionService apiDataConversionService;
@Autowired @Autowired
private PortfolioApiJsonSerializerService apiJsonSerializerService; private PortfolioApiJsonSerializerService apiJsonSerializerService;
private final String entityType = "SAVINGSACCOUNT"; private final String entityType = "SAVINGSACCOUNT";
@Autowired
private PlatformSecurityContext context;
private static final Set<String> typicalResponseParameters = new HashSet<String>(Arrays.asList("id", "status", "externalId", @Autowired
"clientId", "clientName", "productId", "productName", "productType", "currencyData", "savingsDepostiAmountPerPeriod", private PlatformSecurityContext context;
"savingsFrequencyType", "totalDepositAmount", "reccuringInterestRate", "savingInterestRate", "interestType",
"interestCalculationMethod", "tenure", "tenureType", "projectedCommencementDate", "actualCommencementDate", "maturesOnDate",
"projectedInterestAccuredOnMaturity", "actualInterestAccured", "projectedMaturityAmount", "actualMaturityAmount",
"preClosureAllowed", "preClosureInterestRate", "withdrawnonDate", "rejectedonDate", "closedonDate", "isLockinPeriodAllowed",
"lockinPeriod", "lockinPeriodType"));
@POST @Autowired
@Consumes({ MediaType.APPLICATION_JSON }) private CalculateSavingSchedule calculateSavingSchedule;
@Produces({ MediaType.APPLICATION_JSON })
public Response createSavingAccount(final String jsonRequestBody) {
final SavingAccountCommand command = this.apiDataConversionService.convertJsonToSavingAccountCommand(null, jsonRequestBody); private static final Set<String> typicalResponseParameters = new HashSet<String>(
Arrays.asList("id", "status", "externalId", "clientId", "clientName", "productId", "productName", "productType", "currencyData", "savingsDepostiAmountPerPeriod", "savingsFrequencyType",
"totalDepositAmount", "reccuringInterestRate", "savingInterestRate", "interestType", "interestCalculationMethod", "tenure", "tenureType", "projectedCommencementDate",
"actualCommencementDate", "maturesOnDate", "projectedInterestAccuredOnMaturity", "actualInterestAccured", "projectedMaturityAmount", "actualMaturityAmount", "preClosureAllowed",
"preClosureInterestRate", "withdrawnonDate", "rejectedonDate", "closedonDate", "isLockinPeriodAllowed", "lockinPeriod", "lockinPeriodType"));
EntityIdentifier entityIdentifier = this.savingAccountWritePlatformService.createSavingAccount(command); @POST
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public String createSavingAccount(@QueryParam("command") final String commandParam,
@Context final UriInfo uriInfo,final String jsonRequestBody){
return Response.ok().entity(entityIdentifier).build(); final SavingAccountCommand command = this.apiDataConversionService.convertJsonToSavingAccountCommand(null, jsonRequestBody);
}
@PUT if (is(commandParam, "calculateSavingSchedule")) {
@Path("{accountId}") CalculateSavingScheduleCommand calculateSavingScheduleCommand = command.toCalculateSavingScheduleCommand();
@Consumes({ MediaType.APPLICATION_JSON }) return calculateSavingSchedule(uriInfo,calculateSavingScheduleCommand);
@Produces({ MediaType.APPLICATION_JSON })
public Response updateSavingAccount(@PathParam("accountId") final Long accountId, final String jsonRequestBody) {
final SavingAccountCommand command = this.apiDataConversionService.convertJsonToSavingAccountCommand(accountId, jsonRequestBody);
EntityIdentifier entityIdentifier = this.savingAccountWritePlatformService.updateSavingAccount(command);
return Response.ok().entity(entityIdentifier).build();
}
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveAllDepositAccounts(@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(entityType);
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
if (responseParameters.isEmpty()) {
responseParameters.addAll(typicalResponseParameters);
} }
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
Collection<SavingAccountData> accounts = this.savingAccountReadPlatformService.retrieveAllSavingsAccounts(); EntityIdentifier entityIdentifier = this.savingAccountWritePlatformService.createSavingAccount(command);
return this.apiJsonSerializerService.serializeSavingAccountsDataToJson(prettyPrint, responseParameters, accounts); return this.apiJsonSerializerService.serializeEntityIdentifier(entityIdentifier);
} }
@GET private String calculateSavingSchedule(final UriInfo uriInfo, final CalculateSavingScheduleCommand command) {
@Path("{accountId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveDepositAccount(@PathParam("accountId") final Long accountId, @Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(entityType); SavingScheduleData savingScheduleData = this.calculateSavingSchedule.calculateSavingSchedule(command);
final Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); return this.apiJsonSerializerService.serializeSavingScheduleDataToJson(prettyPrint, responseParameters, savingScheduleData);
}
if (responseParameters.isEmpty()) { @PUT
responseParameters.addAll(typicalResponseParameters); @Path("{accountId}")
} @Consumes({MediaType.APPLICATION_JSON})
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); @Produces({MediaType.APPLICATION_JSON})
public Response updateSavingAccount(@PathParam("accountId") final Long accountId,final String jsonRequestBody){
SavingAccountData account = this.savingAccountReadPlatformService.retrieveSavingsAccount(accountId); final SavingAccountCommand command = this.apiDataConversionService.convertJsonToSavingAccountCommand(accountId, jsonRequestBody);
return this.apiJsonSerializerService.serializeSavingAccountsDataToJson(prettyPrint, responseParameters, account); EntityIdentifier entityIdentifier = this.savingAccountWritePlatformService.updateSavingAccount(command);
}
@SuppressWarnings("unused") return Response.ok().entity(entityIdentifier).build();
@GET }
@Path("template")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveNewDepositAccountDetails(@QueryParam("clientId") final Long clientId,
@QueryParam("productId") final Long productId, @Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(entityType); @GET
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public String retrieveAllDepositAccounts(@Context final UriInfo uriInfo) {
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); context.authenticatedUser().validateHasReadPermission(entityType);
if (responseParameters.isEmpty()) {
responseParameters.addAll(typicalResponseParameters);
}
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
SavingAccountData account = null; Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
// this.savingAccountReadPlatformService.retrieveNewSavingsAccountDetails(clientId, if (responseParameters.isEmpty()) {
// productId); responseParameters.addAll(typicalResponseParameters);
}
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
return this.apiJsonSerializerService.serializeSavingAccountsDataToJson(prettyPrint, responseParameters, account); Collection<SavingAccountData> accounts = this.savingAccountReadPlatformService.retrieveAllSavingsAccounts();
return this.apiJsonSerializerService.serializeSavingAccountsDataToJson(prettyPrint, responseParameters, accounts);
}
@GET
@Path("{accountId}")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public String retrieveDepositAccount(@PathParam("accountId") final Long accountId, @Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(entityType);
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
if (responseParameters.isEmpty()) {
responseParameters.addAll(typicalResponseParameters);
}
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
SavingAccountData account = this.savingAccountReadPlatformService.retrieveSavingsAccount(accountId);
return this.apiJsonSerializerService.serializeSavingAccountsDataToJson(prettyPrint, responseParameters, account);
}
@SuppressWarnings("unused")
@GET
@Path("template")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public String retrieveNewDepositAccountDetails(
@QueryParam("clientId") final Long clientId,
@QueryParam("productId") final Long productId,
@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(entityType);
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
if (responseParameters.isEmpty()) {
responseParameters.addAll(typicalResponseParameters);
}
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
SavingAccountData account = null;
// this.savingAccountReadPlatformService.retrieveNewSavingsAccountDetails(clientId, productId);
return this.apiJsonSerializerService.serializeSavingAccountsDataToJson(prettyPrint, responseParameters, account);
}
private boolean is(final String commandParam, final String commandValue) {
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
} }
} }
@@ -0,0 +1,63 @@
package org.mifosplatform.portfolio.savingsaccount.command;
import java.math.BigDecimal;
import org.joda.time.LocalDate;
public class CalculateSavingScheduleCommand {
private final Long productId;
private final BigDecimal deposit;
private final Integer payEvery;
private final Integer paymentFrequencyType;
private final BigDecimal interestRate;
private final LocalDate paymentsStartingFromDate;
private final Integer tenure;
public CalculateSavingScheduleCommand(final Long productId,
final BigDecimal deposit,
final Integer payEvery,
final Integer paymentFrequencyType,
final BigDecimal interestRate,
final LocalDate paymentsStartingFromDate,
final Integer tenure) {
this.productId = productId;
this.deposit = deposit;
this.payEvery = payEvery;
this.paymentFrequencyType=paymentFrequencyType;
this.interestRate= interestRate;
this.paymentsStartingFromDate=paymentsStartingFromDate;
this.tenure = tenure;
}
public Long getProductId() {
return this.productId;
}
public BigDecimal getDeposit() {
return this.deposit;
}
public Integer getPayEvery() {
return this.payEvery;
}
public Integer getPaymentFrequencyType() {
return this.paymentFrequencyType;
}
public BigDecimal getInterestRate() {
return this.interestRate;
}
public LocalDate getPaymentsStartingFromDate() {
return this.paymentsStartingFromDate;
}
public Integer getTenure() {
return this.tenure;
}
}
@@ -7,223 +7,244 @@ import org.joda.time.LocalDate;
public class SavingAccountCommand { public class SavingAccountCommand {
private final Long id;
private final Long clientId;
private final Long productId;
private final String externalId;
private final String currencyCode; private final Long id;
private final Integer digitsAfterDecimal; private final Long clientId;
private final BigDecimal savingsDepositAmount; private final Long productId;
private final BigDecimal recurringInterestRate; private final String externalId;
private final BigDecimal savingInterestRate;
private final Integer tenure;
private final boolean isLockinPeriodAllowed; private final String currencyCode;
private final Integer lockinPeriod; private final Integer digitsAfterDecimal;
private final Integer lockinPeriodType; private final BigDecimal savingsDepositAmount;
private final BigDecimal recurringInterestRate;
private final BigDecimal savingInterestRate;
private final Integer tenure;
private final LocalDate commencementDate; private final boolean isLockinPeriodAllowed;
private final Integer savingProductType; private final Integer lockinPeriod;
private final Integer tenureType; private final Integer lockinPeriodType;
private final Integer frequency;
private final Integer interestType;
private final Integer interestCalculationMethod; private final LocalDate commencementDate;
private final BigDecimal minimumBalanceForWithdrawal; private final Integer savingProductType;
private final boolean isPartialDepositAllowed; private final Integer tenureType;
private final Integer frequency;
private final Integer interestType;
private final Set<String> modifiedParameters; private final Integer interestCalculationMethod;
private final BigDecimal minimumBalanceForWithdrawal;
private final boolean isPartialDepositAllowed;
private final Integer payEvery;
public SavingAccountCommand(final Set<String> modifiedParameters, final Long id, final Long clientId, final Long productId, private final Set<String> modifiedParameters;
final String externalId, final String currencyCode, final Integer digitsAfterDecimal, final BigDecimal savingsDepositAmount,
final BigDecimal recurringInterestRate, final BigDecimal savingInterestRate, final Integer tenure,
final LocalDate commencementDate, final Integer savingProductType, final Integer tenureType, final Integer frequency,
final Integer interestType, final BigDecimal minimumBalanceForWithdrawal, final Integer interestCalculationMethod,
final boolean isLockinPeriodAllowed, final boolean isPartialDepositAllowed, final Integer lockInPeriod,
final Integer lockinPeriodType) {
this.id = id;
this.clientId = clientId;
this.productId = productId;
this.externalId = externalId;
this.currencyCode = currencyCode; public SavingAccountCommand(final Set<String> modifiedParameters,
this.digitsAfterDecimal = digitsAfterDecimal; final Long id,
this.savingsDepositAmount = savingsDepositAmount; final Long clientId,
this.recurringInterestRate = recurringInterestRate; final Long productId,
this.savingInterestRate = savingInterestRate; final String externalId,final String currencyCode, final Integer digitsAfterDecimal,
this.tenure = tenure; final BigDecimal savingsDepositAmount,
final BigDecimal recurringInterestRate, final BigDecimal savingInterestRate,
final Integer tenure, final LocalDate commencementDate,
final Integer savingProductType, final Integer tenureType, final Integer frequency, final Integer interestType,
final BigDecimal minimumBalanceForWithdrawal, final Integer interestCalculationMethod,
final boolean isLockinPeriodAllowed, final boolean isPartialDepositAllowed, final Integer lockInPeriod, final Integer lockinPeriodType,
final Integer payEvery) {
this.id = id;
this.clientId = clientId;
this.productId = productId;
this.externalId = externalId;
this.modifiedParameters = modifiedParameters; this.currencyCode = currencyCode;
this.commencementDate = commencementDate; this.digitsAfterDecimal = digitsAfterDecimal;
this.savingsDepositAmount = savingsDepositAmount;
this.recurringInterestRate = recurringInterestRate;
this.savingInterestRate = savingInterestRate;
this.tenure = tenure;
this.savingProductType = savingProductType; this.modifiedParameters = modifiedParameters;
this.tenureType = tenureType; this.commencementDate = commencementDate;
this.frequency = frequency;
this.interestType = interestType;
this.isPartialDepositAllowed = isPartialDepositAllowed;
this.isLockinPeriodAllowed = isLockinPeriodAllowed; this.savingProductType=savingProductType;
this.lockinPeriod = lockInPeriod; this.tenureType=tenureType;
this.lockinPeriodType = lockinPeriodType; this.frequency=frequency;
this.minimumBalanceForWithdrawal = minimumBalanceForWithdrawal; this.interestType=interestType;
this.interestCalculationMethod = interestCalculationMethod; this.isPartialDepositAllowed=isPartialDepositAllowed;
}
public Long getId() {
return id;
}
public Long getClientId() { this.isLockinPeriodAllowed = isLockinPeriodAllowed;
return clientId; this.lockinPeriod = lockInPeriod;
} this.lockinPeriodType = lockinPeriodType;
this.minimumBalanceForWithdrawal=minimumBalanceForWithdrawal;
this.interestCalculationMethod=interestCalculationMethod;
this.payEvery = payEvery;
}
public Long getProductId() { public Long getId() {
return productId; return id;
} }
public String getExternalId() { public Long getClientId() {
return externalId; return clientId;
} }
public String getCurrencyCode() { public Long getProductId() {
return currencyCode; return productId;
} }
public Integer getDigitsAfterDecimal() { public String getExternalId() {
return digitsAfterDecimal; return externalId;
} }
public BigDecimal getSavingsDepositAmount() { public String getCurrencyCode() {
return savingsDepositAmount; return currencyCode;
} }
public BigDecimal getRecurringInterestRate() { public Integer getDigitsAfterDecimal() {
return recurringInterestRate; return digitsAfterDecimal;
} }
public BigDecimal getSavingInterestRate() { public BigDecimal getSavingsDepositAmount() {
return savingInterestRate; return savingsDepositAmount;
} }
public Integer getTenure() { public BigDecimal getRecurringInterestRate() {
return tenure; return recurringInterestRate;
} }
public boolean isLockinPeriodAllowed() { public BigDecimal getSavingInterestRate() {
return isLockinPeriodAllowed; return savingInterestRate;
} }
public Integer getLockinPeriod() { public Integer getTenure() {
return lockinPeriod; return tenure;
} }
public Integer getLockinPeriodType() { public boolean isLockinPeriodAllowed() {
return lockinPeriodType; return isLockinPeriodAllowed;
} }
public LocalDate getCommencementDate() { public Integer getLockinPeriod() {
return commencementDate; return lockinPeriod;
} }
public Integer getSavingProductType() { public Integer getLockinPeriodType() {
return savingProductType; return lockinPeriodType;
} }
public Integer getTenureType() { public LocalDate getCommencementDate() {
return tenureType; return commencementDate;
} }
public Integer getFrequency() { public Integer getSavingProductType() {
return frequency; return savingProductType;
} }
public Integer getInterestType() { public Integer getTenureType() {
return interestType; return tenureType;
} }
public Integer getInterestCalculationMethod() { public Integer getFrequency() {
return interestCalculationMethod; return frequency;
} }
public BigDecimal getMinimumBalanceForWithdrawal() { public Integer getInterestType() {
return minimumBalanceForWithdrawal; return interestType;
} }
public boolean isPartialDepositAllowed() { public Integer getInterestCalculationMethod() {
return isPartialDepositAllowed; return interestCalculationMethod;
} }
public boolean isNoFieldChanged() { public BigDecimal getMinimumBalanceForWithdrawal() {
return this.modifiedParameters.isEmpty(); return minimumBalanceForWithdrawal;
} }
public boolean isProductIdChanged() { public boolean isPartialDepositAllowed() {
return this.modifiedParameters.contains("productId"); return isPartialDepositAllowed;
} }
public boolean isExternalIdChanged() { public Integer getPayEvery() {
return this.modifiedParameters.contains("externalId"); return this.payEvery;
} }
public boolean isDepositAmountChanged() { public boolean isNoFieldChanged() {
return this.modifiedParameters.contains("deposit"); return this.modifiedParameters.isEmpty();
} }
public boolean isTenureInMonthsChanged() { public boolean isProductIdChanged(){
return this.modifiedParameters.contains("tenureInMonths"); return this.modifiedParameters.contains("productId");
} }
public boolean isLockinPeriodChanged() { public boolean isExternalIdChanged(){
return this.modifiedParameters.contains("lockinPeriod"); return this.modifiedParameters.contains("externalId");
} }
public boolean isPreClosureInterestRateChanged() { public boolean isDepositAmountChanged(){
return this.modifiedParameters.contains("preClosureInterestRate"); return this.modifiedParameters.contains("deposit");
} }
public boolean isPreClosureAllowedChanged() { public boolean isTenureInMonthsChanged() {
return this.modifiedParameters.contains("preClosureAllowed"); return this.modifiedParameters.contains("tenureInMonths");
} }
public boolean isCommencementDateChanged() { public boolean isLockinPeriodChanged() {
return this.modifiedParameters.contains("commencementDate"); return this.modifiedParameters.contains("lockinPeriod");
} }
public boolean isTenureTypeEnumChanged() { public boolean isPreClosureInterestRateChanged(){
return this.modifiedParameters.contains("tenureType"); return this.modifiedParameters.contains("preClosureInterestRate");
} }
public boolean isSavingProductTypeChanged() { public boolean isPreClosureAllowedChanged() {
return this.modifiedParameters.contains("savingProductType"); return this.modifiedParameters.contains("preClosureAllowed");
} }
public boolean isSavingFrequencyTypeChanged() { public boolean isCommencementDateChanged() {
return this.modifiedParameters.contains("frequency"); return this.modifiedParameters.contains("commencementDate");
} }
public boolean isSavingInterestCalculationMethodChanged() { public boolean isTenureTypeEnumChanged() {
return this.modifiedParameters.contains("interestCalculationMethod"); return this.modifiedParameters.contains("tenureType");
} }
public boolean isReccuringInterestRateChanged() { public boolean isSavingProductTypeChanged() {
return this.modifiedParameters.contains("recurringInterestRate"); return this.modifiedParameters.contains("savingProductType");
} }
public boolean isSavingInterestRateChanged() { public boolean isSavingFrequencyTypeChanged() {
return this.modifiedParameters.contains("savingInterestRate"); return this.modifiedParameters.contains("frequency");
} }
public boolean isLockinPeriodAllowedChanged() { public boolean isSavingInterestCalculationMethodChanged() {
return this.modifiedParameters.contains("isLockinPeriodAllowed"); return this.modifiedParameters.contains("interestCalculationMethod");
} }
public boolean isLockinPeriodTypeChanged() { public boolean isReccuringInterestRateChanged() {
return this.modifiedParameters.contains("lockinPeriodType"); return this.modifiedParameters.contains("recurringInterestRate");
} }
public boolean isPartialDepositAllowedChanged() { public boolean isSavingInterestRateChanged() {
return this.modifiedParameters.contains("isPartialDepositAllowed"); return this.modifiedParameters.contains("savingInterestRate");
} }
public boolean isLockinPeriodAllowedChanged() {
return this.modifiedParameters.contains("isLockinPeriodAllowed");
}
public boolean isLockinPeriodTypeChanged() {
return this.modifiedParameters.contains("lockinPeriodType");
}
public boolean isPartialDepositAllowedChanged() {
return this.modifiedParameters.contains("isPartialDepositAllowed");
}
public boolean isPayEveryChanged(){
return this.modifiedParameters.contains("payEvery");
}
public CalculateSavingScheduleCommand toCalculateSavingScheduleCommand() {
return new CalculateSavingScheduleCommand(productId, savingsDepositAmount, payEvery, frequency, recurringInterestRate, commencementDate,tenure);
}
} }
@@ -0,0 +1,34 @@
package org.mifosplatform.portfolio.savingsaccount.data;
import java.math.BigDecimal;
import java.util.Collection;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
public class SavingScheduleData {
private final CurrencyData currency;
private final BigDecimal cumulativeDepositDue;
private final Collection<SavingSchedulePeriodData> periods;
public SavingScheduleData(final CurrencyData currency, final BigDecimal cumulativeDepositDue,
final Collection<SavingSchedulePeriodData> periods) {
this.currency = currency;
this.cumulativeDepositDue= cumulativeDepositDue;
this.periods= periods;
}
public CurrencyData getCurrency() {
return this.currency;
}
public BigDecimal getCumulativeDepositDue() {
return this.cumulativeDepositDue;
}
public Collection<SavingSchedulePeriodData> getPeriods() {
return this.periods;
}
}
@@ -0,0 +1,41 @@
package org.mifosplatform.portfolio.savingsaccount.data;
import java.math.BigDecimal;
import org.joda.time.LocalDate;
public class SavingSchedulePeriodData {
private final Integer period;
private final LocalDate dueDate;
private final BigDecimal depositDue;
private final BigDecimal depositPaid;
public SavingSchedulePeriodData(final Integer period, final LocalDate dueDate, final BigDecimal depositDue, final BigDecimal depositPaid) {
this.period = period;
this.dueDate = dueDate;
this.depositDue= depositDue;
this.depositPaid= depositPaid;
}
public static SavingSchedulePeriodData addScheduleInformation(int periodNumber, LocalDate scheduleDate, BigDecimal depositAmountPerPeriod){
return new SavingSchedulePeriodData(periodNumber, scheduleDate, depositAmountPerPeriod, BigDecimal.ZERO);
}
public Integer getPeriod() {
return this.period;
}
public LocalDate getDueDate() {
return this.dueDate;
}
public BigDecimal getDepositDue() {
return this.depositDue;
}
public BigDecimal getDepositPaid() {
return this.depositPaid;
}
}
@@ -0,0 +1,12 @@
package org.mifosplatform.portfolio.savingsaccount.domain;
import java.util.List;
import org.joda.time.LocalDate;
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
public interface DepositScheduleDateGenerator {
List<LocalDate> generate(LocalDate startDate, Integer paymentPeriods, Integer depositFrequency, PeriodFrequencyType depositFrequencyType);
}
@@ -1,18 +1,24 @@
package org.mifosplatform.portfolio.savingsaccount.domain; package org.mifosplatform.portfolio.savingsaccount.domain;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Embedded; import javax.persistence.Embedded;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.Temporal; import javax.persistence.Temporal;
import javax.persistence.TemporalType; import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom; import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
@@ -31,307 +37,345 @@ import org.mifosplatform.portfolio.savingsdepositproduct.domain.TenureTypeEnum;
import org.mifosplatform.useradministration.domain.AppUser; import org.mifosplatform.useradministration.domain.AppUser;
@Entity @Entity
@Table(name = "m_saving_account", uniqueConstraints = @UniqueConstraint(name = "saving_acc_external_id", columnNames = { "external_id" })) @Table(name = "m_saving_account", uniqueConstraints = @UniqueConstraint(name="saving_acc_external_id", columnNames = { "external_id" }))
public class SavingAccount extends AbstractAuditableCustom<AppUser, Long> { public class SavingAccount extends AbstractAuditableCustom<AppUser, Long> {
@ManyToOne @ManyToOne
@JoinColumn(name = "client_id", nullable = false) @JoinColumn(name = "client_id", nullable = false)
private Client client; private Client client;
@ManyToOne @ManyToOne
@JoinColumn(name = "product_id") @JoinColumn(name = "product_id")
private SavingProduct product; private SavingProduct product;
// FIXME - MADHUKAR - Do not use the actual enum type here but instead use // FIXME - MADHUKAR - Do not use the actual enum type here but instead use Integer e.g. private Integer savingProductType;
// Integer e.g. private Integer savingProductType; @Column(name = "savings_product_type", nullable=false)
@Column(name = "savings_product_type", nullable = false) private SavingProductType savingProductType;
private SavingProductType savingProductType;
@Column(name = "external_id") @Column(name = "external_id")
private String externalId; private String externalId;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Embedded @Embedded
private MonetaryCurrency currency; private MonetaryCurrency currency;
@Column(name = "deposit_amount_per_period", scale = 6, precision = 19, nullable = false) @Column(name = "deposit_amount_per_period", scale = 6, precision = 19, nullable = false)
private BigDecimal savingsDepositAmountPerPeriod; private BigDecimal savingsDepositAmountPerPeriod;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Column(name = "total_deposit_amount", scale = 6, precision = 19, nullable = false) @Column(name = "total_deposit_amount", scale = 6, precision = 19, nullable = false)
private BigDecimal totalSavingsAmount; private BigDecimal totalSavingsAmount;
@Column(name = "reccuring_nominal_interest_rate", scale = 6, precision = 19, nullable = false) @Column(name = "reccuring_nominal_interest_rate", scale = 6, precision = 19, nullable = false)
private BigDecimal reccuringInterestRate; private BigDecimal reccuringInterestRate;
@Column(name = "regular_saving_nominal_interest_rate", scale = 6, precision = 19, nullable = false) @Column(name = "regular_saving_nominal_interest_rate", scale = 6, precision = 19, nullable = false)
private BigDecimal savingInterestRate; private BigDecimal savingInterestRate;
@Column(name = "tenure", nullable = false) @Column(name = "tenure", nullable=false)
private Integer tenure; private Integer tenure;
@Column(name = "tenure_type", nullable = false) @Column(name = "tenure_type", nullable=false)
private TenureTypeEnum tenureType; private TenureTypeEnum tenureType;
// FIXME - MADHUKAR - Do not use the actual enum type here but instead use // FIXME - MADHUKAR - Do not use the actual enum type here but instead use Integer e.g. private Integer savingProductType;
// Integer e.g. private Integer savingProductType; @Column(name = "frequency", nullable=false)
@Column(name = "frequency", nullable = false) private SavingFrequencyType frequency;
private SavingFrequencyType frequency;
// FIXME - MADHUKAR - Do not use the actual enum type here but instead use // FIXME - MADHUKAR - Do not use the actual enum type here but instead use Integer e.g. private Integer savingProductType;
// Integer e.g. private Integer savingProductType; @Column(name = "interest_type", nullable=false)
@Column(name = "interest_type", nullable = false) private SavingsInterestType interestType;
private SavingsInterestType interestType;
// FIXME - MADHUKAR - Do not use the actual enum type here but instead use // FIXME - MADHUKAR - Do not use the actual enum type here but instead use Integer e.g. private Integer savingProductType;
// Integer e.g. private Integer savingProductType; @Column(name = "interest_calculation_method")
@Column(name = "interest_calculation_method") private SavingInterestCalculationMethod interestCalculationMethod;
private SavingInterestCalculationMethod interestCalculationMethod;
@Temporal(TemporalType.DATE) @Temporal(TemporalType.DATE)
@Column(name = "projected_commencement_date") @Column(name = "projected_commencement_date")
private Date projectedCommencementDate; private Date projectedCommencementDate;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Temporal(TemporalType.DATE) @Temporal(TemporalType.DATE)
@Column(name = "actual_commencement_date") @Column(name = "actual_commencement_date")
private Date actualCommencementDate; private Date actualCommencementDate;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Temporal(TemporalType.DATE) @Temporal(TemporalType.DATE)
@Column(name = "matures_on_date") @Column(name = "matures_on_date")
private Date maturesOnDate; private Date maturesOnDate;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Column(name = "projected_interest_accrued_on_maturity", scale = 6, precision = 19, nullable = false) @Column(name = "projected_interest_accrued_on_maturity", scale = 6, precision = 19, nullable = false)
private BigDecimal projectedInterestAccruedOnMaturity; private BigDecimal projectedInterestAccruedOnMaturity;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Column(name = "actual_interest_accrued", scale = 6, precision = 19, nullable = false) @Column(name = "actual_interest_accrued", scale = 6, precision = 19, nullable = false)
private BigDecimal interestAccrued; private BigDecimal interestAccrued;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Column(name = "projected_total_maturity_amount", scale = 6, precision = 19, nullable = false) @Column(name = "projected_total_maturity_amount", scale = 6, precision = 19, nullable = false)
private BigDecimal projectedTotalOnMaturity; private BigDecimal projectedTotalOnMaturity;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Column(name = "actual_total_amount", scale = 6, precision = 19, nullable = false) @Column(name = "actual_total_amount", scale = 6, precision = 19, nullable = false)
private BigDecimal total; private BigDecimal total;
@Column(name = "pre_closure_interest_rate", scale = 6, precision = 19, nullable = false) @Column(name = "pre_closure_interest_rate", scale = 6, precision = 19, nullable = false)
private BigDecimal preClosureInterestRate; private BigDecimal preClosureInterestRate;
@Column(name = "is_preclosure_allowed", nullable = false) @Column(name = "is_preclosure_allowed", nullable = false)
private boolean preClosureAllowed = false; private boolean preClosureAllowed = false;
@Column(name = "is_deleted", nullable = false) @Column(name = "is_deleted", nullable=false)
private boolean deleted = false; private boolean deleted = false;
@Column(name = "status_enum", nullable = false) @Column(name = "status_enum", nullable = false)
private Integer accountStatus; private Integer accountStatus;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Temporal(TemporalType.DATE) @Temporal(TemporalType.DATE)
@Column(name = "closedon_date") @Column(name = "closedon_date")
private Date closedOnDate; private Date closedOnDate;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Temporal(TemporalType.DATE) @Temporal(TemporalType.DATE)
@Column(name = "rejectedon_date") @Column(name = "rejectedon_date")
private Date rejectedOnDate; private Date rejectedOnDate;
@Temporal(TemporalType.DATE) @Temporal(TemporalType.DATE)
@Column(name = "withdrawnon_date") @Column(name = "withdrawnon_date")
private Date withdrawnOnDate; private Date withdrawnOnDate;
@Column(name = "is_lock_in_period_allowed", nullable = false) @Column(name = "is_lock_in_period_allowed", nullable=false)
private boolean isLockinPeriodAllowed = false; private boolean isLockinPeriodAllowed = false;
@Column(name = "lock_in_period", nullable = false) @Column(name = "lock_in_period", nullable=false)
private Integer lockinPeriod; private Integer lockinPeriod;
@Column(name = "lock_in_period_type", nullable = false) @Column(name = "lock_in_period_type", nullable=false)
private PeriodFrequencyType lockinPeriodType; private PeriodFrequencyType lockinPeriodType;
public static SavingAccount openNew(Client client, SavingProduct product, String externalId, Money savingsDeposit, // see
BigDecimal reccuringInterestRate, BigDecimal savingInterestRate, Integer tenure, LocalDate commencementDate, // http://stackoverflow.com/questions/4334970/hibernate-cannot-simultaneously-fetch-multiple-bags
TenureTypeEnum tenureTypeEnum, SavingProductType savingProductType, SavingFrequencyType savingFrequencyType, @LazyCollection(LazyCollectionOption.FALSE)
SavingsInterestType interestType, SavingInterestCalculationMethod savingInterestCalculationMethod, @OneToMany(cascade = CascadeType.ALL, mappedBy = "savingAccount", orphanRemoval = true)
boolean isLockinPeriodAllowed, Integer lockinPeriod, PeriodFrequencyType lockinPeriodType, private final List<SavingScheduleInstallments> savingScheduleInstallments = new ArrayList<SavingScheduleInstallments>();
ReccuringDepositInterestCalculator reccuringDepositInterestCalculator, final DepositLifecycleStateMachine lifecycleStateMachine) {
Money futureValueOnMaturity = null;
if (savingProductType.isReccuring()) {
futureValueOnMaturity = reccuringDepositInterestCalculator.calculateInterestOnMaturityFor(savingsDeposit, tenure,
reccuringInterestRate, commencementDate, tenureTypeEnum, savingFrequencyType, savingInterestCalculationMethod);
} else if (savingProductType.isRegular()) {
futureValueOnMaturity = reccuringDepositInterestCalculator.calculateInterestOnMaturityFor(savingsDeposit, tenure,
savingInterestRate, commencementDate, tenureTypeEnum, savingFrequencyType, savingInterestCalculationMethod);
}
return new SavingAccount(client, externalId, product, savingsDeposit, reccuringInterestRate, savingInterestRate, tenure, public static SavingAccount openNew(
commencementDate, tenureTypeEnum, savingProductType, savingFrequencyType, interestType, savingInterestCalculationMethod, Client client,
isLockinPeriodAllowed, lockinPeriod, lockinPeriodType, futureValueOnMaturity, lifecycleStateMachine); SavingProduct product,
} String externalId,
Money savingsDeposit,
BigDecimal reccuringInterestRate,
BigDecimal savingInterestRate,
Integer tenure,
LocalDate commencementDate,
TenureTypeEnum tenureTypeEnum,
SavingProductType savingProductType,
SavingFrequencyType savingFrequencyType,
SavingsInterestType interestType,
SavingInterestCalculationMethod savingInterestCalculationMethod,
boolean isLockinPeriodAllowed,
Integer lockinPeriod,
PeriodFrequencyType lockinPeriodType,
ReccuringDepositInterestCalculator reccuringDepositInterestCalculator,
final DepositLifecycleStateMachine lifecycleStateMachine) {
public SavingAccount(Client client, String externalId, SavingProduct product, Money savingsDeposit, BigDecimal reccuringInterestRate, Money futureValueOnMaturity = null;
BigDecimal savingInterestRate, Integer tenure, LocalDate commencementDate, TenureTypeEnum tenureTypeEnum, if(savingProductType.isReccuring()){
SavingProductType savingProductType, SavingFrequencyType savingFrequencyType, SavingsInterestType interestType, futureValueOnMaturity = reccuringDepositInterestCalculator.calculateInterestOnMaturityFor(savingsDeposit, tenure, reccuringInterestRate,
SavingInterestCalculationMethod savingInterestCalculationMethod, boolean isLockinPeriodAllowed, Integer lockinPeriod, commencementDate, tenureTypeEnum, savingFrequencyType, savingInterestCalculationMethod);
PeriodFrequencyType lockinPeriodType, Money futureValueOnMaturity, final DepositLifecycleStateMachine lifecycleStateMachine) { } else if(savingProductType.isRegular()){
futureValueOnMaturity = reccuringDepositInterestCalculator.calculateInterestOnMaturityFor(savingsDeposit, tenure, savingInterestRate,
commencementDate, tenureTypeEnum, savingFrequencyType, savingInterestCalculationMethod);
}
DepositAccountStatus from = null; return new SavingAccount(client, externalId, product, savingsDeposit, reccuringInterestRate, savingInterestRate, tenure,
if (accountStatus != null) { commencementDate, tenureTypeEnum, savingProductType, savingFrequencyType, interestType, savingInterestCalculationMethod,
from = DepositAccountStatus.fromInt(accountStatus); isLockinPeriodAllowed, lockinPeriod, lockinPeriodType, futureValueOnMaturity, lifecycleStateMachine);
} }
DepositAccountStatus statusEnum = lifecycleStateMachine.transition(DepositAccountEvent.DEPOSIT_CREATED, from); public SavingAccount(Client client, String externalId,
accountStatus = statusEnum.getValue(); SavingProduct product, Money savingsDeposit,
BigDecimal reccuringInterestRate, BigDecimal savingInterestRate,
Integer tenure, LocalDate commencementDate,
TenureTypeEnum tenureTypeEnum,
SavingProductType savingProductType,
SavingFrequencyType savingFrequencyType, SavingsInterestType interestType,
SavingInterestCalculationMethod savingInterestCalculationMethod,
boolean isLockinPeriodAllowed, Integer lockinPeriod,
PeriodFrequencyType lockinPeriodType, Money futureValueOnMaturity,
final DepositLifecycleStateMachine lifecycleStateMachine) {
this.total = BigDecimal.ZERO; DepositAccountStatus from = null;
this.preClosureInterestRate = BigDecimal.ZERO; if (accountStatus != null) {
this.totalSavingsAmount = BigDecimal.ZERO; from = DepositAccountStatus.fromInt(accountStatus);
this.interestAccrued = BigDecimal.ZERO; }
this.client = client; DepositAccountStatus statusEnum = lifecycleStateMachine.transition(DepositAccountEvent.DEPOSIT_CREATED, from);
this.externalId = externalId; accountStatus = statusEnum.getValue();
this.product = product;
this.savingsDepositAmountPerPeriod = savingsDeposit.getAmount();
this.currency = savingsDeposit.getCurrency();
this.reccuringInterestRate = reccuringInterestRate;
this.savingInterestRate = savingInterestRate;
this.tenure = tenure;
this.projectedCommencementDate = commencementDate.toDate();
this.tenureType = tenureTypeEnum;
this.savingProductType = savingProductType;
this.frequency = savingFrequencyType;
this.interestType = interestType;
this.interestCalculationMethod = savingInterestCalculationMethod;
this.isLockinPeriodAllowed = isLockinPeriodAllowed;
this.lockinPeriod = lockinPeriod;
this.lockinPeriodType = lockinPeriodType;
this.projectedTotalOnMaturity = futureValueOnMaturity.getAmount();
this.projectedInterestAccruedOnMaturity = futureValueOnMaturity.getAmount().subtract(
BigDecimal.valueOf(savingsDeposit.getAmount().doubleValue() * tenure.doubleValue()));
}
public void modifyAccount(SavingProduct product, String externalId, Money savingsDeposit, BigDecimal reccuringInterestRate, this.total=BigDecimal.ZERO;
BigDecimal savingInterestRate, Integer tenure, LocalDate commencementDate, TenureTypeEnum tenureTypeEnum, this.preClosureInterestRate=BigDecimal.ZERO;
SavingProductType savingProductType, SavingFrequencyType savingFrequencyType, this.totalSavingsAmount = BigDecimal.ZERO;
SavingInterestCalculationMethod savingInterestCalculationMethod, boolean isLockinPeriodAllowed, Integer lockinPeriod, this.interestAccrued = BigDecimal.ZERO;
PeriodFrequencyType lockinPeriodType, ReccuringDepositInterestCalculator reccuringDepositInterestCalculator) {
Money futureValueOnMaturity = null; this.client = client;
if (savingProductType.isReccuring()) { this.externalId = externalId;
futureValueOnMaturity = reccuringDepositInterestCalculator.calculateInterestOnMaturityFor(savingsDeposit, tenure, this.product = product;
reccuringInterestRate, commencementDate, tenureTypeEnum, savingFrequencyType, savingInterestCalculationMethod); this.savingsDepositAmountPerPeriod = savingsDeposit.getAmount();
} else if (savingProductType.isRegular()) { this.currency = savingsDeposit.getCurrency();
futureValueOnMaturity = reccuringDepositInterestCalculator.calculateInterestOnMaturityFor(savingsDeposit, tenure, this.reccuringInterestRate = reccuringInterestRate;
savingInterestRate, commencementDate, tenureTypeEnum, savingFrequencyType, savingInterestCalculationMethod); this.savingInterestRate = savingInterestRate;
} this.tenure =tenure;
this.projectedCommencementDate=commencementDate.toDate();
this.tenureType = tenureTypeEnum;
this.savingProductType = savingProductType;
this.frequency = savingFrequencyType;
this.interestType = interestType;
this.interestCalculationMethod= savingInterestCalculationMethod;
this.isLockinPeriodAllowed = isLockinPeriodAllowed;
this.lockinPeriod = lockinPeriod;
this.lockinPeriodType = lockinPeriodType;
this.projectedTotalOnMaturity = futureValueOnMaturity.getAmount();
this.projectedInterestAccruedOnMaturity =futureValueOnMaturity.getAmount().subtract(BigDecimal.valueOf(savingsDeposit.getAmount().doubleValue()*tenure.doubleValue()));
}
this.product = product; public void modifyAccount(
this.externalId = externalId; SavingProduct product,
this.savingsDepositAmountPerPeriod = savingsDeposit.getAmount(); String externalId,
this.reccuringInterestRate = reccuringInterestRate; Money savingsDeposit,
this.savingInterestRate = savingInterestRate; BigDecimal reccuringInterestRate,
this.tenure = tenure; BigDecimal savingInterestRate,
this.projectedCommencementDate = commencementDate.toDate(); Integer tenure,
this.tenureType = tenureTypeEnum; LocalDate commencementDate,
this.savingProductType = savingProductType; TenureTypeEnum tenureTypeEnum,
this.frequency = savingFrequencyType; SavingProductType savingProductType,
this.interestCalculationMethod = savingInterestCalculationMethod; SavingFrequencyType savingFrequencyType,
this.isLockinPeriodAllowed = isLockinPeriodAllowed; SavingInterestCalculationMethod savingInterestCalculationMethod,
this.lockinPeriod = lockinPeriod; boolean isLockinPeriodAllowed,
this.lockinPeriodType = lockinPeriodType; Integer lockinPeriod,
PeriodFrequencyType lockinPeriodType,
ReccuringDepositInterestCalculator reccuringDepositInterestCalculator) {
// FIXME - MADHUKAR - futureValueOnMaturity is possibly null
this.projectedTotalOnMaturity = futureValueOnMaturity.getAmount();
this.projectedInterestAccruedOnMaturity = futureValueOnMaturity.getAmount().subtract(
BigDecimal.valueOf(savingsDeposit.getAmount().doubleValue() * tenure.doubleValue()));
}
public boolean isDeleted() { Money futureValueOnMaturity = null;
return this.deleted; if(savingProductType.isReccuring()){
} futureValueOnMaturity = reccuringDepositInterestCalculator.calculateInterestOnMaturityFor(savingsDeposit, tenure, reccuringInterestRate,
commencementDate, tenureTypeEnum, savingFrequencyType, savingInterestCalculationMethod);
} else if(savingProductType.isRegular()){
futureValueOnMaturity = reccuringDepositInterestCalculator.calculateInterestOnMaturityFor(savingsDeposit, tenure, savingInterestRate,
commencementDate, tenureTypeEnum, savingFrequencyType, savingInterestCalculationMethod);
}
public boolean isPendingApproval() { this.product = product;
return this.accountStatus.equals(100); this.externalId=externalId;
} this.savingsDepositAmountPerPeriod=savingsDeposit.getAmount();
this.reccuringInterestRate=reccuringInterestRate;
this.savingInterestRate = savingInterestRate;
this.tenure = tenure;
this.projectedCommencementDate = commencementDate.toDate();
this.tenureType = tenureTypeEnum;
this.savingProductType = savingProductType;
this.frequency =savingFrequencyType;
this.interestCalculationMethod = savingInterestCalculationMethod;
this.isLockinPeriodAllowed = isLockinPeriodAllowed;
this.lockinPeriod = lockinPeriod;
this.lockinPeriodType = lockinPeriodType;
public Client getClient() { // FIXME - MADHUKAR - futureValueOnMaturity is possibly null
return client; this.projectedTotalOnMaturity = futureValueOnMaturity.getAmount();
} this.projectedInterestAccruedOnMaturity =futureValueOnMaturity.getAmount().subtract(BigDecimal.valueOf(savingsDeposit.getAmount().doubleValue()*tenure.doubleValue()));
}
public SavingProduct getProduct() { public boolean isDeleted() {
return product; return this.deleted;
} }
public SavingProductType getSavingProductType() { public boolean isPendingApproval() {
return savingProductType; return this.accountStatus.equals(100);
} }
public String getExternalId() { public Client getClient() {
return externalId; return client;
} }
public BigDecimal getSavingsDepositAmountPerPeriod() { public SavingProduct getProduct() {
return savingsDepositAmountPerPeriod; return product;
} }
public BigDecimal getReccuringInterestRate() { public SavingProductType getSavingProductType() {
return reccuringInterestRate; return savingProductType;
} }
public BigDecimal getSavingInterestRate() { public String getExternalId() {
return savingInterestRate; return externalId;
} }
public Integer getTenure() { public BigDecimal getSavingsDepositAmountPerPeriod() {
return tenure; return savingsDepositAmountPerPeriod;
} }
public TenureTypeEnum getTenureType() { public BigDecimal getReccuringInterestRate() {
return tenureType; return reccuringInterestRate;
} }
public SavingFrequencyType getFrequency() { public BigDecimal getSavingInterestRate() {
return frequency; return savingInterestRate;
} }
public SavingsInterestType getInterestType() { public Integer getTenure() {
return interestType; return tenure;
} }
public SavingInterestCalculationMethod getInterestCalculationMethod() { public TenureTypeEnum getTenureType() {
return interestCalculationMethod; return tenureType;
} }
public Date getProjectedCommencementDate() { public SavingFrequencyType getFrequency() {
return projectedCommencementDate; return frequency;
} }
public BigDecimal getPreClosureInterestRate() { public SavingsInterestType getInterestType() {
return preClosureInterestRate; return interestType;
} }
public boolean isPreClosureAllowed() { public SavingInterestCalculationMethod getInterestCalculationMethod() {
return preClosureAllowed; return interestCalculationMethod;
} }
public Date getWithdrawnOnDate() { public Date getProjectedCommencementDate() {
return withdrawnOnDate; return projectedCommencementDate;
} }
public boolean isLockinPeriodAllowed() { public BigDecimal getPreClosureInterestRate() {
return isLockinPeriodAllowed; return preClosureInterestRate;
} }
public Integer getLockinPeriod() { public boolean isPreClosureAllowed() {
return lockinPeriod; return preClosureAllowed;
} }
public Date getWithdrawnOnDate() {
return withdrawnOnDate;
}
public boolean isLockinPeriodAllowed() {
return isLockinPeriodAllowed;
}
public Integer getLockinPeriod() {
return lockinPeriod;
}
public PeriodFrequencyType getLockinPeriodType() {
return lockinPeriodType;
}
public void addSavingScheduleInstallment(final SavingScheduleInstallments installment) {
installment.updateAccount(this);
this.savingScheduleInstallments.add(installment);
}
public PeriodFrequencyType getLockinPeriodType() {
return lockinPeriodType;
}
} }
@@ -0,0 +1,60 @@
package org.mifosplatform.portfolio.savingsaccount.domain;
import java.math.BigDecimal;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom;
import org.mifosplatform.useradministration.domain.AppUser;
@Entity
@Table(name="m_saving_schedule")
public class SavingScheduleInstallments extends AbstractAuditableCustom<AppUser, Long> {
@ManyToOne(optional = false)
@JoinColumn(name = "saving_account_id", nullable=false)
private SavingAccount savingAccount;
@Temporal(TemporalType.DATE)
@Column(name = "duedate", nullable=false)
private final Date dueDate;
@Column(name = "installment", nullable=false)
private final Integer installmentNumber;
@Column(name = "deposit", scale=6, precision=19, nullable=false)
private BigDecimal deposit;
@Temporal(TemporalType.DATE)
@Column(name = "payment_date", nullable=true)
private final Date paymentDate;
@Column(name = "deposit_paid", scale=6, precision=19, nullable=true)
private BigDecimal depositPaid;
@Column(name="completed_derived", nullable=false)
private boolean completed;
public SavingScheduleInstallments(SavingAccount account, Date dueDate,
Integer installmentNumber, BigDecimal deposit) {
this.savingAccount = account;
this.dueDate = dueDate;
this.installmentNumber = installmentNumber;
this.deposit = deposit;
this.paymentDate = null;
this.depositPaid = BigDecimal.ZERO;
this.completed = false;
}
public void updateAccount(SavingAccount account){
this.savingAccount = account;
}
}
@@ -0,0 +1,10 @@
package org.mifosplatform.portfolio.savingsaccount.service;
import org.mifosplatform.portfolio.savingsaccount.command.CalculateSavingScheduleCommand;
import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData;
public interface CalculateSavingSchedule {
SavingScheduleData calculateSavingSchedule(CalculateSavingScheduleCommand command);
}
@@ -0,0 +1,62 @@
package org.mifosplatform.portfolio.savingsaccount.service;
import java.math.BigDecimal;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepository;
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.savingsaccount.command.CalculateSavingScheduleCommand;
import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProduct;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProductRepository;
import org.mifosplatform.portfolio.savingsaccountproduct.exception.SavingProductNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CalculateSavingScheduleImpl implements CalculateSavingSchedule {
private final PlatformSecurityContext context;
private final SavingProductRepository savingProductRepository;
private final SavingScheduleGenerator savingScheduleGenerator;
private final ApplicationCurrencyRepository applicationCurrencyRepository;
@Autowired
public CalculateSavingScheduleImpl(
final PlatformSecurityContext context,
final SavingProductRepository savingProductRepository,
final ApplicationCurrencyRepository applicationCurrencyRepository) {
this.context = context;
this.savingProductRepository = savingProductRepository;
this.savingScheduleGenerator = new SavingScheduleGenerator();
this.applicationCurrencyRepository = applicationCurrencyRepository;
}
@Override
public SavingScheduleData calculateSavingSchedule(CalculateSavingScheduleCommand command) {
context.authenticatedUser();
// FIXME Validations should write here
final SavingProduct savingProduct = this.savingProductRepository.findOne(command.getProductId());
if (savingProduct == null)
throw new SavingProductNotFoundException(command.getProductId());
final Integer depositFrequency = command.getPayEvery();
final PeriodFrequencyType depositFrequencyType = PeriodFrequencyType.fromInt(command.getPaymentFrequencyType());
final LocalDate scheduleStartDate = command.getPaymentsStartingFromDate();
@SuppressWarnings("unused")
final BigDecimal interestRate = command.getInterestRate();
final BigDecimal depositAmountPerPeriod = command.getDeposit();
final Integer tenure = command.getTenure();
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneByCode(savingProduct.getCurrency().getCode());
SavingScheduleData savingScheduleData = savingScheduleGenerator.generate(scheduleStartDate,depositAmountPerPeriod,
depositFrequency,depositFrequencyType,savingProduct,tenure,applicationCurrency);
return savingScheduleData;
}
}
@@ -0,0 +1,47 @@
package org.mifosplatform.portfolio.savingsaccount.service;
import java.util.ArrayList;
import java.util.List;
import org.joda.time.LocalDate;
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.savingsaccount.domain.DepositScheduleDateGenerator;
public class DefaultDepositScheduleDateGenerator implements DepositScheduleDateGenerator {
@Override
public List<LocalDate> generate(LocalDate scheuleStartDate, Integer paymentPeriods, Integer depositFrequency, PeriodFrequencyType depositFrequencyType) {
List<LocalDate> duePaymentPeriodDates = new ArrayList<LocalDate>(depositFrequency);
LocalDate startDate = scheuleStartDate;
for (int period=1; period <= paymentPeriods; period++){
LocalDate duePaymentPeriodDate = startDate;
if (period == 1) {
duePaymentPeriodDate = startDate;
} else {
switch (depositFrequencyType) {
case DAYS:
duePaymentPeriodDate = startDate.plusDays(depositFrequency);
break;
case WEEKS:
duePaymentPeriodDate = startDate.plusWeeks(depositFrequency);
break;
case MONTHS:
duePaymentPeriodDate = startDate.plusMonths(depositFrequency);
break;
case YEARS:
duePaymentPeriodDate = startDate.plusYears(depositFrequency);
break;
case INVALID:
break;
}
}
duePaymentPeriodDates.add(duePaymentPeriodDate);
startDate = duePaymentPeriodDate;
}
return duePaymentPeriodDates;
}
}
@@ -12,15 +12,18 @@ import org.mifosplatform.portfolio.client.domain.ClientRepository;
import org.mifosplatform.portfolio.client.exception.ClientNotFoundException; import org.mifosplatform.portfolio.client.exception.ClientNotFoundException;
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType; import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.savingsaccount.command.SavingAccountCommand; import org.mifosplatform.portfolio.savingsaccount.command.SavingAccountCommand;
import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingSchedulePeriodData;
import org.mifosplatform.portfolio.savingsaccount.domain.ReccuringDepositInterestCalculator; import org.mifosplatform.portfolio.savingsaccount.domain.ReccuringDepositInterestCalculator;
import org.mifosplatform.portfolio.savingsaccount.domain.SavingAccount; import org.mifosplatform.portfolio.savingsaccount.domain.SavingAccount;
import org.mifosplatform.portfolio.savingsaccount.domain.SavingScheduleInstallments;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingFrequencyType; import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingFrequencyType;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingInterestCalculationMethod; import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingInterestCalculationMethod;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProduct; import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProduct;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProductRepository; import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProductRepository;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProductType; import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProductType;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingsInterestType; import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingsInterestType;
import org.mifosplatform.portfolio.savingsaccountproduct.exception.SavingsProductNotFoundException; import org.mifosplatform.portfolio.savingsaccountproduct.exception.SavingProductNotFoundException;
import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositAccountStatus; import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositAccountStatus;
import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositLifecycleStateMachine; import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositLifecycleStateMachine;
import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositLifecycleStateMachineImpl; import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositLifecycleStateMachineImpl;
@@ -31,173 +34,190 @@ import org.springframework.stereotype.Service;
@Service @Service
public class SavingAccountAssembler { public class SavingAccountAssembler {
private final ClientRepository clientRepository; private final ClientRepository clientRepository;
private final SavingProductRepository savingProductRepository; private final SavingProductRepository savingProductRepository;
private final ReccuringDepositInterestCalculator reccuringDepositInterestCalculator; private final ReccuringDepositInterestCalculator reccuringDepositInterestCalculator;
private final CalculateSavingSchedule calculateSavingSchedule;
@Autowired @Autowired
public SavingAccountAssembler(final ClientRepository clientRepository, final SavingProductRepository savingProductRepository, public SavingAccountAssembler(final ClientRepository clientRepository,final SavingProductRepository savingProductRepository,
final ReccuringDepositInterestCalculator reccuringDepositInterestCalculator) { final ReccuringDepositInterestCalculator reccuringDepositInterestCalculator,final CalculateSavingSchedule calculateSavingSchedule) {
this.clientRepository = clientRepository; this.clientRepository=clientRepository;
this.savingProductRepository = savingProductRepository; this.savingProductRepository=savingProductRepository;
this.reccuringDepositInterestCalculator = reccuringDepositInterestCalculator; this.reccuringDepositInterestCalculator=reccuringDepositInterestCalculator;
} this.calculateSavingSchedule = calculateSavingSchedule;
}
//minimumBalanceForWithdrawal,isPartialDepositAllowed
public SavingAccount assembleFrom(SavingAccountCommand command){
// minimumBalanceForWithdrawal,isPartialDepositAllowed Client client = this.clientRepository.findOne(command.getClientId());
public SavingAccount assembleFrom(SavingAccountCommand command) { if (client == null || client.isDeleted()) {
throw new ClientNotFoundException(command.getClientId());
}
Client client = this.clientRepository.findOne(command.getClientId()); SavingProduct product=this.savingProductRepository.findOne(command.getProductId());
if (client == null || client.isDeleted()) { throw new ClientNotFoundException(command.getClientId()); } if(product == null || product.isDeleted()){
throw new SavingProductNotFoundException(command.getProductId());
}
SavingProduct product = this.savingProductRepository.findOne(command.getProductId()); MonetaryCurrency currency = product.getCurrency();
if (product == null || product.isDeleted()) { throw new SavingsProductNotFoundException(command.getProductId()); } if(command.getCurrencyCode() != null && command.getDigitsAfterDecimal() != null){
currency = new MonetaryCurrency(command.getCurrencyCode(), command.getDigitsAfterDecimal());
}
MonetaryCurrency currency = product.getCurrency(); Money savingsDeposit = Money.of(currency, command.getSavingsDepositAmount());
if (command.getCurrencyCode() != null && command.getDigitsAfterDecimal() != null) {
currency = new MonetaryCurrency(command.getCurrencyCode(), command.getDigitsAfterDecimal());
}
Money savingsDeposit = Money.of(currency, command.getSavingsDepositAmount()); Integer tenure = product.getSavingProductRelatedDetail().getTenure();
if(command.getTenure() != null){
tenure=command.getTenure();
}
Integer tenure = product.getSavingProductRelatedDetail().getTenure(); TenureTypeEnum tenureTypeEnum=product.getSavingProductRelatedDetail().getTenureType();
if (command.getTenure() != null) { if (command.getTenureType() != null) {
tenure = command.getTenure(); tenureTypeEnum = TenureTypeEnum.fromInt(command.getTenureType());
} }
TenureTypeEnum tenureTypeEnum = product.getSavingProductRelatedDetail().getTenureType(); SavingProductType savingProductType= product.getSavingProductRelatedDetail().getSavingProductType();
if (command.getTenureType() != null) { if(command.getSavingProductType() != null){
tenureTypeEnum = TenureTypeEnum.fromInt(command.getTenureType()); savingProductType = SavingProductType.fromInt(command.getSavingProductType());
} }
SavingProductType savingProductType = product.getSavingProductRelatedDetail().getSavingProductType(); SavingFrequencyType savingFrequencyType = product.getSavingProductRelatedDetail().getFrequency();
if (command.getSavingProductType() != null) { if (command.getFrequency() != null) {
savingProductType = SavingProductType.fromInt(command.getSavingProductType()); savingFrequencyType = SavingFrequencyType.fromInt(command.getFrequency());
} }
SavingFrequencyType savingFrequencyType = product.getSavingProductRelatedDetail().getFrequency(); SavingInterestCalculationMethod savingInterestCalculationMethod = product.getSavingProductRelatedDetail().getInterestCalculationMethod();
if (command.getFrequency() != null) { if (command.getInterestCalculationMethod() != null) {
savingFrequencyType = SavingFrequencyType.fromInt(command.getFrequency()); savingInterestCalculationMethod = SavingInterestCalculationMethod.fromInt(command.getInterestCalculationMethod());
} }
SavingInterestCalculationMethod savingInterestCalculationMethod = product.getSavingProductRelatedDetail() SavingsInterestType interestType = product.getSavingProductRelatedDetail().getInterestType();
.getInterestCalculationMethod(); if (command.getInterestType() != null) {
if (command.getInterestCalculationMethod() != null) { interestType = SavingsInterestType.fromInt(command.getInterestType());
savingInterestCalculationMethod = SavingInterestCalculationMethod.fromInt(command.getInterestCalculationMethod()); }
}
SavingsInterestType interestType = product.getSavingProductRelatedDetail().getInterestType(); BigDecimal reccuringInterestRate = command.getRecurringInterestRate();
if (command.getInterestType() != null) { BigDecimal savingInterestRate = product.getInterestRate();
interestType = SavingsInterestType.fromInt(command.getInterestType()); if(command.getSavingInterestRate() != null)
} savingInterestRate = command.getSavingInterestRate();
BigDecimal reccuringInterestRate = command.getRecurringInterestRate(); boolean isLockinPeriodAllowed = product.getSavingProductRelatedDetail().isLockinPeriodAllowed();
BigDecimal savingInterestRate = product.getInterestRate(); if(command.isLockinPeriodChanged()){
if (command.getSavingInterestRate() != null) savingInterestRate = command.getSavingInterestRate(); isLockinPeriodAllowed = command.isLockinPeriodAllowed();
}
boolean isLockinPeriodAllowed = product.getSavingProductRelatedDetail().isLockinPeriodAllowed(); Integer lockinPeriod = product.getSavingProductRelatedDetail().getLockinPeriod();
if (command.isLockinPeriodChanged()) { if(command.getLockinPeriod() != null){
isLockinPeriodAllowed = command.isLockinPeriodAllowed(); lockinPeriod = command.getLockinPeriod();
} }
Integer lockinPeriod = product.getSavingProductRelatedDetail().getLockinPeriod(); PeriodFrequencyType lockinPeriodType = product.getSavingProductRelatedDetail().getLockinPeriodType();
if (command.getLockinPeriod() != null) { if(command.getLockinPeriodType() != null){
lockinPeriod = command.getLockinPeriod(); lockinPeriodType = PeriodFrequencyType.fromInt(command.getLockinPeriodType());
} }
PeriodFrequencyType lockinPeriodType = product.getSavingProductRelatedDetail().getLockinPeriodType(); SavingAccount account = SavingAccount.openNew(client, product, command.getExternalId(),savingsDeposit,
if (command.getLockinPeriodType() != null) { reccuringInterestRate,savingInterestRate,tenure,command.getCommencementDate(),tenureTypeEnum, savingProductType,
lockinPeriodType = PeriodFrequencyType.fromInt(command.getLockinPeriodType()); savingFrequencyType, interestType, savingInterestCalculationMethod, isLockinPeriodAllowed,lockinPeriod, lockinPeriodType,
} this.reccuringDepositInterestCalculator, defaultDepositLifecycleStateMachine());
SavingAccount account = SavingAccount.openNew(client, product, command.getExternalId(), savingsDeposit, reccuringInterestRate, SavingScheduleData savingScheduleData = this.calculateSavingSchedule.calculateSavingSchedule(command.toCalculateSavingScheduleCommand());
savingInterestRate, tenure, command.getCommencementDate(), tenureTypeEnum, savingProductType, savingFrequencyType, for(SavingSchedulePeriodData savingSchedulePeriodData : savingScheduleData.getPeriods()){
interestType, savingInterestCalculationMethod, isLockinPeriodAllowed, lockinPeriod, lockinPeriodType,
this.reccuringDepositInterestCalculator, defaultDepositLifecycleStateMachine());
return account; final SavingScheduleInstallments installment = new SavingScheduleInstallments(
} account,
savingSchedulePeriodData.getDueDate().toDate(),
savingSchedulePeriodData.getPeriod(),
savingSchedulePeriodData.getDepositDue());
account.addSavingScheduleInstallment(installment);
}
public void assembleFrom(SavingAccountCommand command, SavingAccount account) { return account;
}
SavingProduct product = account.getProduct(); public void assembleFrom(SavingAccountCommand command, SavingAccount account) {
if (command.isProductIdChanged()) {
if (product.getId() != command.getProductId()) {
product = this.savingProductRepository.findOne(command.getProductId());
if (product == null || product.isDeleted()) throw new SavingsProductNotFoundException(command.getProductId());
}
}
String externalId = account.getExternalId(); SavingProduct product=account.getProduct();
if (command.isExternalIdChanged()) { if(command.isProductIdChanged()){
externalId = command.getExternalId(); if(product.getId() != command.getProductId()){
} product = this.savingProductRepository.findOne(command.getProductId());
if(product == null || product.isDeleted())
throw new SavingProductNotFoundException(command.getProductId());
}
}
Money savingsDeposit = Money.of(product.getCurrency(), account.getSavingsDepositAmountPerPeriod()); String externalId = account.getExternalId();
if (command.isDepositAmountChanged()) { if(command.isExternalIdChanged()){
savingsDeposit = Money.of(product.getCurrency(), command.getSavingsDepositAmount()); externalId = command.getExternalId();
} }
Integer tenure = account.getTenure();
if (command.isTenureInMonthsChanged()) {
tenure = command.getTenure();
}
LocalDate commencementDate = new LocalDate(account.getProjectedCommencementDate()); Money savingsDeposit = Money.of(product.getCurrency(), account.getSavingsDepositAmountPerPeriod());
if (command.isCommencementDateChanged()) { if(command.isDepositAmountChanged()){
commencementDate = command.getCommencementDate(); savingsDeposit = Money.of(product.getCurrency(), command.getSavingsDepositAmount());
} }
Integer tenure = account.getTenure();
if(command.isTenureInMonthsChanged()){
tenure = command.getTenure();
}
TenureTypeEnum tenureTypeEnum = account.getTenureType(); LocalDate commencementDate = new LocalDate(account.getProjectedCommencementDate());
if (command.isTenureTypeEnumChanged()) { if (command.isCommencementDateChanged()) {
tenureTypeEnum = TenureTypeEnum.fromInt(command.getTenureType()); commencementDate = command.getCommencementDate();
} }
SavingProductType savingProductType = account.getSavingProductType(); TenureTypeEnum tenureTypeEnum=account.getTenureType();
if (command.isSavingProductTypeChanged()) { if(command.isTenureTypeEnumChanged()){
savingProductType = SavingProductType.fromInt(command.getSavingProductType()); tenureTypeEnum = TenureTypeEnum.fromInt(command.getTenureType());
} }
SavingFrequencyType savingFrequencyType = account.getFrequency(); SavingProductType savingProductType= account.getSavingProductType();
if (command.isSavingFrequencyTypeChanged()) { if (command.isSavingProductTypeChanged()) {
savingFrequencyType = SavingFrequencyType.fromInt(command.getFrequency()); savingProductType = SavingProductType.fromInt(command.getSavingProductType());
} }
SavingInterestCalculationMethod savingInterestCalculationMethod = account.getInterestCalculationMethod(); SavingFrequencyType savingFrequencyType = account.getFrequency();
if (command.isSavingInterestCalculationMethodChanged()) { if (command.isSavingFrequencyTypeChanged()) {
savingInterestCalculationMethod = SavingInterestCalculationMethod.fromInt(command.getInterestCalculationMethod()); savingFrequencyType = SavingFrequencyType.fromInt(command.getFrequency());
} }
BigDecimal reccuringInterestRate = account.getReccuringInterestRate(); SavingInterestCalculationMethod savingInterestCalculationMethod =account.getInterestCalculationMethod();
if (command.isReccuringInterestRateChanged()) { if (command.isSavingInterestCalculationMethodChanged()) {
reccuringInterestRate = command.getRecurringInterestRate(); savingInterestCalculationMethod = SavingInterestCalculationMethod.fromInt(command.getInterestCalculationMethod());
} }
BigDecimal savingInterestRate = account.getSavingInterestRate(); BigDecimal reccuringInterestRate = account.getReccuringInterestRate();
if (command.isSavingInterestRateChanged()) { if (command.isReccuringInterestRateChanged()) {
savingInterestRate = command.getSavingInterestRate(); reccuringInterestRate = command.getRecurringInterestRate();
} }
boolean isLockinPeriodAllowed = account.isLockinPeriodAllowed(); BigDecimal savingInterestRate = account.getSavingInterestRate();
if (command.isLockinPeriodAllowedChanged()) { if (command.isSavingInterestRateChanged()) {
isLockinPeriodAllowed = command.isLockinPeriodAllowed(); savingInterestRate = command.getSavingInterestRate();
} }
Integer lockinPeriod = account.getLockinPeriod(); boolean isLockinPeriodAllowed = account.isLockinPeriodAllowed();
if (command.isLockinPeriodChanged()) { if (command.isLockinPeriodAllowedChanged()) {
lockinPeriod = command.getLockinPeriod(); isLockinPeriodAllowed = command.isLockinPeriodAllowed();
} }
PeriodFrequencyType lockinPeriodType = account.getLockinPeriodType(); Integer lockinPeriod =account.getLockinPeriod();
if (command.isLockinPeriodTypeChanged()) { if (command.isLockinPeriodChanged()) {
lockinPeriodType = PeriodFrequencyType.fromInt(command.getLockinPeriodType()); lockinPeriod = command.getLockinPeriod();
} }
account.modifyAccount(product, externalId, savingsDeposit, reccuringInterestRate, savingInterestRate, tenure, commencementDate,
tenureTypeEnum, savingProductType, savingFrequencyType, savingInterestCalculationMethod, isLockinPeriodAllowed,
lockinPeriod, lockinPeriodType, this.reccuringDepositInterestCalculator);
} PeriodFrequencyType lockinPeriodType = account.getLockinPeriodType();
if (command.isLockinPeriodTypeChanged()) {
lockinPeriodType = PeriodFrequencyType.fromInt(command.getLockinPeriodType());
}
account.modifyAccount(product, externalId, savingsDeposit, reccuringInterestRate, savingInterestRate, tenure,
commencementDate, tenureTypeEnum, savingProductType, savingFrequencyType, savingInterestCalculationMethod,
isLockinPeriodAllowed, lockinPeriod, lockinPeriodType, this.reccuringDepositInterestCalculator);
private DepositLifecycleStateMachine defaultDepositLifecycleStateMachine() { }
List<DepositAccountStatus> allowedDepositStatuses = Arrays.asList(DepositAccountStatus.values());
return new DepositLifecycleStateMachineImpl(allowedDepositStatuses); private DepositLifecycleStateMachine defaultDepositLifecycleStateMachine() {
} List<DepositAccountStatus> allowedDepositStatuses = Arrays.asList(DepositAccountStatus.values());
return new DepositLifecycleStateMachineImpl(allowedDepositStatuses);
}
} }
@@ -0,0 +1,44 @@
package org.mifosplatform.portfolio.savingsaccount.service;
import java.math.BigDecimal;
import org.joda.time.LocalDate;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.portfolio.savingsaccount.command.CalculateSavingScheduleCommand;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProduct;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProductRelatedDetail;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProductRepository;
import org.mifosplatform.portfolio.savingsaccountproduct.exception.SavingProductNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class SavingProductRelatedDetailAssembler {
private final SavingProductRepository savingProductRepository;
@Autowired
public SavingProductRelatedDetailAssembler(final SavingProductRepository savingProductRepository) {
this.savingProductRepository = savingProductRepository;
}
public SavingProductRelatedDetail assembleFrom(CalculateSavingScheduleCommand command) {
final BigDecimal depositAmountForPeriod = command.getDeposit();
final BigDecimal depositInterestRate = command.getInterestRate();
final LocalDate installmentDate = command.getPaymentsStartingFromDate();
final Integer payEvery = command.getPayEvery();
final Integer paymentFrequencyType = command.getPaymentFrequencyType();
final SavingProduct savingProduct = this.savingProductRepository.findOne(command.getProductId());
if (savingProduct == null) {
throw new SavingProductNotFoundException(command.getProductId());
}
final MonetaryCurrency currency = savingProduct.getCurrency();
return null;
}
}
@@ -0,0 +1,58 @@
package org.mifosplatform.portfolio.savingsaccount.service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.joda.time.LocalDate;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingSchedulePeriodData;
import org.mifosplatform.portfolio.savingsaccount.domain.DepositScheduleDateGenerator;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProduct;
public class SavingScheduleGenerator {
private final DepositScheduleDateGenerator scheduledDateGenerator = new DefaultDepositScheduleDateGenerator();
public SavingScheduleData generate(
final LocalDate scheduleStartDate,
final BigDecimal depositAmountPerPeriod,
final Integer depositFrequency,
final PeriodFrequencyType depositFrequencyType,
final SavingProduct savingProduct,
final Integer tenure,
final ApplicationCurrency applicationCurrency) {
LocalDate startDate = scheduleStartDate;
int periodNumber = 1;
Integer paymentPeriods = tenure/depositFrequency;
final Collection<SavingSchedulePeriodData> periods = new ArrayList<SavingSchedulePeriodData>();
final List<LocalDate> scheduledDates = this.scheduledDateGenerator.generate(startDate,paymentPeriods,depositFrequency,depositFrequencyType);
final MonetaryCurrency currency = savingProduct.getCurrency();
final Money depositAmount = Money.of(currency, depositAmountPerPeriod);
Money totalDeposit = Money.zero(currency);
for(LocalDate scheduleDate : scheduledDates){
totalDeposit = totalDeposit.plus(depositAmount);
SavingSchedulePeriodData installment = SavingSchedulePeriodData.addScheduleInformation(periodNumber, scheduleDate, depositAmount.getAmount());
periods.add(installment);
periodNumber++;
}
CurrencyData currencyData = new CurrencyData(
applicationCurrency.getCode(),
applicationCurrency.getName(),
currency.getDigitsAfterDecimal(),
applicationCurrency.getDisplaySymbol(),
applicationCurrency.getNameCode());
return new SavingScheduleData(currencyData, totalDeposit.getAmount(), periods);
}
}
@@ -37,6 +37,7 @@ import org.mifosplatform.portfolio.savingsdepositaccount.command.DepositAccountW
import org.mifosplatform.portfolio.savingsdepositaccount.command.DepositStateTransitionApprovalCommand; import org.mifosplatform.portfolio.savingsdepositaccount.command.DepositStateTransitionApprovalCommand;
import org.mifosplatform.portfolio.savingsdepositaccount.command.DepositStateTransitionCommand; import org.mifosplatform.portfolio.savingsdepositaccount.command.DepositStateTransitionCommand;
import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositAccountData; import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositAccountData;
import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositAccountsForLookup;
import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositPermissionData; import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositPermissionData;
import org.mifosplatform.portfolio.savingsdepositaccount.service.DepositAccountReadPlatformService; import org.mifosplatform.portfolio.savingsdepositaccount.service.DepositAccountReadPlatformService;
import org.mifosplatform.portfolio.savingsdepositaccount.service.DepositAccountWritePlatformService; import org.mifosplatform.portfolio.savingsdepositaccount.service.DepositAccountWritePlatformService;
@@ -257,5 +258,16 @@ public class DepositAccountsApiResource {
private boolean is(final String commandParam, final String commandValue) { private boolean is(final String commandParam, final String commandValue) {
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue); return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
}
@POST
@Path("postinterest")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response postInterest(){
Collection<DepositAccountsForLookup> accounts = this.depositAccountReadPlatformService.retrieveDepositAccountForLookup();
@SuppressWarnings("unused")
EntityIdentifier entityIdentifier = this.depositAccountWritePlatformService.postInterestToDepositAccount(accounts);
return Response.ok().entity(entityIdentifier).build();
} }
} }
@@ -66,6 +66,11 @@ public class DepositAccountData {
private final Integer lockinPeriod; private final Integer lockinPeriod;
private final EnumOptionData lockinPeriodType; private final EnumOptionData lockinPeriodType;
private final BigDecimal availableInterest;
private final BigDecimal interestPostedAmount;
private final LocalDate lastInterestPostedDate;
private final LocalDate nextInterestPostedDate;
/* /*
* used when returning account template data but only a clientId is passed, * used when returning account template data but only a clientId is passed,
* no selected product. * no selected product.
@@ -119,6 +124,11 @@ public class DepositAccountData {
this.isLockinPeriodAllowed = true; this.isLockinPeriodAllowed = true;
this.lockinPeriod = null; this.lockinPeriod = null;
this.lockinPeriodType = null; this.lockinPeriodType = null;
this.availableInterest = BigDecimal.ZERO;
this.interestPostedAmount = BigDecimal.ZERO;
this.lastInterestPostedDate = null;
this.nextInterestPostedDate = null;
} }
public DepositAccountData(final DepositAccountData account, final List<EnumOptionData> interestCompoundedEveryPeriodTypeOptions, public DepositAccountData(final DepositAccountData account, final List<EnumOptionData> interestCompoundedEveryPeriodTypeOptions,
@@ -166,6 +176,11 @@ public class DepositAccountData {
this.lockinPeriod = account.getLockinPeriod(); this.lockinPeriod = account.getLockinPeriod();
this.lockinPeriodType = account.getLockinPeriodType(); this.lockinPeriodType = account.getLockinPeriodType();
this.isLockinPeriodAllowed = account.isLockinPeriodAllowed(); this.isLockinPeriodAllowed = account.isLockinPeriodAllowed();
this.availableInterest = account.getAvailableInterest();
this.interestPostedAmount = account.getInterestPostedAmount();
this.lastInterestPostedDate = account.getLastInterestPostedDate();
this.nextInterestPostedDate = account.getNextInterestPostedDate();
} }
public DepositAccountData(final DepositAccountData account, final DepositPermissionData permissions, public DepositAccountData(final DepositAccountData account, final DepositPermissionData permissions,
@@ -213,6 +228,11 @@ public class DepositAccountData {
this.lockinPeriod = account.getLockinPeriod(); this.lockinPeriod = account.getLockinPeriod();
this.lockinPeriodType = account.getLockinPeriodType(); this.lockinPeriodType = account.getLockinPeriodType();
this.isLockinPeriodAllowed = account.isLockinPeriodAllowed(); this.isLockinPeriodAllowed = account.isLockinPeriodAllowed();
this.availableInterest = account.getAvailableInterest();
this.interestPostedAmount = account.getInterestPostedAmount();
this.lastInterestPostedDate = account.getLastInterestPostedDate();
this.nextInterestPostedDate = account.getNextInterestPostedDate();
} }
public DepositAccountData(final Long id, final String externalId, final EnumOptionData status, final Long clientId, public DepositAccountData(final Long id, final String externalId, final EnumOptionData status, final Long clientId,
@@ -224,7 +244,8 @@ public class DepositAccountData {
final boolean preClosureAllowed, final BigDecimal preClosureInterestRate, final LocalDate withdrawnonDate, final boolean preClosureAllowed, final BigDecimal preClosureInterestRate, final LocalDate withdrawnonDate,
final LocalDate rejectedonDate, final LocalDate closedonDate, final boolean isInterestWithdrawable, final LocalDate rejectedonDate, final LocalDate closedonDate, final boolean isInterestWithdrawable,
final BigDecimal interestPaid, final boolean interestCompoundingAllowed, final boolean isLockinPeriodAllowed, final BigDecimal interestPaid, final boolean interestCompoundingAllowed, final boolean isLockinPeriodAllowed,
final Integer lockinPeriod, final EnumOptionData lockinPeriodType) { final Integer lockinPeriod, final EnumOptionData lockinPeriodType,final BigDecimal availableInterest,
final BigDecimal interestPostedAmount, final LocalDate lastInterestPostedDate, final LocalDate nextInterestPostedDate) {
this.id = id; this.id = id;
this.externalId = externalId; this.externalId = externalId;
this.status = status; this.status = status;
@@ -269,6 +290,11 @@ public class DepositAccountData {
this.isLockinPeriodAllowed = isLockinPeriodAllowed; this.isLockinPeriodAllowed = isLockinPeriodAllowed;
this.lockinPeriod = lockinPeriod; this.lockinPeriod = lockinPeriod;
this.lockinPeriodType = lockinPeriodType; this.lockinPeriodType = lockinPeriodType;
this.availableInterest = availableInterest;
this.interestPostedAmount = interestPostedAmount;
this.lastInterestPostedDate = lastInterestPostedDate;
this.nextInterestPostedDate = nextInterestPostedDate;
} }
public DepositAccountData(final Long clientId, final String clientName, final Long productId, final String productName, public DepositAccountData(final Long clientId, final String clientName, final Long productId, final String productName,
@@ -319,6 +345,11 @@ public class DepositAccountData {
this.lockinPeriod = Integer.valueOf(0); this.lockinPeriod = Integer.valueOf(0);
this.isLockinPeriodAllowed = true; this.isLockinPeriodAllowed = true;
this.lockinPeriodType = interestCompoundedEveryPeriodType; this.lockinPeriodType = interestCompoundedEveryPeriodType;
this.availableInterest = BigDecimal.ZERO;
this.interestPostedAmount = BigDecimal.ZERO;
this.lastInterestPostedDate = null;
this.nextInterestPostedDate = null;
} }
public Long getId() { public Long getId() {
@@ -477,68 +508,67 @@ public class DepositAccountData {
return lockinPeriodType; return lockinPeriodType;
} }
private BigDecimal determineAvailableInterestForWithdrawal(final DepositAccountData account) { public BigDecimal getAvailableInterest() {
BigDecimal availableInterestForWithdrawal = BigDecimal.ZERO; return this.availableInterest;
}
if (this.status != null) { public BigDecimal getInterestPostedAmount() {
if (account.getStatus().getId() == 300) { return this.interestPostedAmount;
BigDecimal interestGettingForPeriod = BigDecimal.valueOf(account.getActualInterestAccrued().doubleValue() }
/ new Double(account.getTenureInMonths()));
LocalDate interestWithdrawingDate = new LocalDate().isBefore(getMaturedOn()) ? new LocalDate() : getMaturedOn().plusDays(1);
Integer noOfMonthsforInterestCal = Months.monthsBetween(account.getActualCommencementDate(), interestWithdrawingDate)
.getMonths();
Integer noOfPeriods = noOfMonthsforInterestCal / account.getInterestCompoundedEvery();
availableInterestForWithdrawal = BigDecimal.valueOf(interestGettingForPeriod.multiply(new BigDecimal(noOfPeriods)) public LocalDate getLastInterestPostedDate() {
.doubleValue() - account.getInterestPaid().doubleValue()); return this.lastInterestPostedDate;
} else { }
return BigDecimal.ZERO;
}
} else
return BigDecimal.ZERO;
return availableInterestForWithdrawal; public LocalDate getNextInterestPostedDate() {
} return this.nextInterestPostedDate;
}
private BigDecimal determineAvailableInterestForWithdrawal(final DepositAccountData account) {
BigDecimal availableInterestForWithdrawal = BigDecimal.ZERO;
private BigDecimal determineAvalableWithdrawalAmount(final DepositAccountData account) { if(this.status!=null){
if (account.getStatus().getId() == 300) {
BigDecimal interestGettingForPeriod = BigDecimal.valueOf(account.getActualInterestAccrued().doubleValue()/ new Double(account.getTenureInMonths()));
LocalDate interestWithdrawingDate= new LocalDate().isBefore(getMaturedOn())?new LocalDate():getMaturedOn().plusDays(1);
Integer noOfMonthsforInterestCal = Months.monthsBetween(account.getActualCommencementDate(), interestWithdrawingDate).getMonths();
Integer noOfPeriods = noOfMonthsforInterestCal/ account.getInterestCompoundedEvery();
BigDecimal avalablePreclosureWithdrawalAmount = BigDecimal.ZERO; availableInterestForWithdrawal = BigDecimal.valueOf(interestGettingForPeriod.multiply(new BigDecimal(noOfPeriods)).doubleValue()- account.getInterestPaid().doubleValue());
if (this.status != null) { }else {
if (account.getStatus().getId() == 300) { return BigDecimal.ZERO;
if (new LocalDate().isBefore(account.getMaturedOn()) || new LocalDate().isEqual(account.getMaturedOn())) { }
MathContext mc = new MathContext(8, RoundingMode.HALF_EVEN); }else return BigDecimal.ZERO;
Integer monthsInYear = 12;
BigDecimal interestRateAsFraction = account.getPreClosureInterestRate().divide(BigDecimal.valueOf(100), mc);
BigDecimal interestRateForOneMonth = interestRateAsFraction.divide(BigDecimal.valueOf(monthsInYear.doubleValue()), mc);
Integer noOfMonthsforInterestCal = Months.monthsBetween(account.getActualCommencementDate(), new LocalDate())
.getMonths();
Integer days = Days.daysBetween(account.getActualCommencementDate().plusMonths(noOfMonthsforInterestCal),
new LocalDate()).getDays();
BigDecimal interest = BigDecimal.valueOf(account.getDeposit().doubleValue() * new Double(noOfMonthsforInterestCal)
* interestRateForOneMonth.doubleValue());
avalablePreclosureWithdrawalAmount = interest.add(account.getDeposit()).subtract(account.getInterestPaid())
.add(determineRemainInerestAmount(account.getDeposit(), account.getPreClosureInterestRate(), days));
} else if (new LocalDate().isAfter(account.getMaturedOn())) {
Integer days = Days.daysBetween(account.getMaturedOn(), new LocalDate()).getDays();
avalablePreclosureWithdrawalAmount = determineAvailableInterestForWithdrawal(account).add(account.getDeposit()).add(
determineRemainInerestAmount(account.getDeposit(), account.getPreClosureInterestRate(), days));
}
} else {
avalablePreclosureWithdrawalAmount = account.getDeposit();
}
}
return avalablePreclosureWithdrawalAmount;
}
private BigDecimal determineRemainInerestAmount(final BigDecimal depsoitAmount, final BigDecimal interstRateApplicable, return availableInterestForWithdrawal;
final Integer days) { }
MathContext mc = new MathContext(8, RoundingMode.HALF_EVEN); private BigDecimal determineAvalableWithdrawalAmount(final DepositAccountData account) {
Integer daysInYear = 365;
BigDecimal interestRateAsFraction = interstRateApplicable.divide(BigDecimal.valueOf(100), mc);
BigDecimal interestRateForOneDay = interestRateAsFraction.divide(BigDecimal.valueOf(daysInYear.doubleValue()), mc);
return BigDecimal.valueOf(depsoitAmount.doubleValue() * days.doubleValue() * interestRateForOneDay.doubleValue());
} BigDecimal avalablePreclosureWithdrawalAmount = BigDecimal.ZERO;
if(this.status != null){
if (account.getStatus().getId() == 300) {
// if(new LocalDate().isBefore(account.getMaturedOn()) || new LocalDate().isEqual(account.getMaturedOn())){
Integer days = Days.daysBetween(account.getLastInterestPostedDate(), new LocalDate()).getDays();
avalablePreclosureWithdrawalAmount=account.getAvailableInterest().add(account.getDeposit()).add(determineRemainInerestAmount(account.getDeposit(), account.getPreClosureInterestRate(), days));
// }else if(new LocalDate().isAfter(account.getMaturedOn())){
// Integer days = Days.daysBetween(account.getLastInterestPostedDate(), new LocalDate()).getDays();
// avalablePreclosureWithdrawalAmount=account.getAvailableInterest().add(account.getDeposit()).add(determineRemainInerestAmount(account.getDeposit(), account.getPreClosureInterestRate(), days));
// }
}else{
avalablePreclosureWithdrawalAmount=account.getDeposit();
}
}
return avalablePreclosureWithdrawalAmount;
}
private BigDecimal determineRemainInerestAmount(final BigDecimal depsoitAmount, final BigDecimal interstRateApplicable, final Integer days){
MathContext mc = new MathContext(8, RoundingMode.HALF_EVEN);
Integer daysInYear = 365;
BigDecimal interestRateAsFraction = interstRateApplicable.divide(BigDecimal.valueOf(100), mc);
BigDecimal interestRateForOneDay = interestRateAsFraction.divide(BigDecimal.valueOf(daysInYear.doubleValue()), mc);
return BigDecimal.valueOf(depsoitAmount.doubleValue()*days.doubleValue()*interestRateForOneDay.doubleValue());
}
} }
@@ -0,0 +1,15 @@
package org.mifosplatform.portfolio.savingsdepositaccount.data;
public class DepositAccountsForLookup {
private final Long id;
public DepositAccountsForLookup(final Long id) {
this.id = id;
}
public Long getId() {
return id;
}
}
@@ -152,6 +152,21 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
@Column(name = "lock_in_period_type", nullable=false) @Column(name = "lock_in_period_type", nullable=false)
private PeriodFrequencyType lockinPeriodType; private PeriodFrequencyType lockinPeriodType;
//for interest posting
@Column(name = "available_interest", scale = 6, precision = 19)
private BigDecimal availableInterest;
@Column(name = "interest_posted_amount", scale = 6, precision = 19)
private BigDecimal interestPostedAmount;
@Temporal(TemporalType.DATE)
@Column(name = "last_interest_posted_date")
private Date lastInterestPostedDate;
@Temporal(TemporalType.DATE)
@Column(name = "next_interest_posting_date")
private Date nextInterestPostingDate;
public DepositAccount openNew( public DepositAccount openNew(
final Client client, final DepositProduct product, final Client client, final DepositProduct product,
@@ -325,6 +340,12 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
depositaccountTransaction.updateAccount(this); depositaccountTransaction.updateAccount(this);
this.depositaccountTransactions.add(depositaccountTransaction); this.depositaccountTransactions.add(depositaccountTransaction);
//for interest posting initializing
this.lastInterestPostedDate = this.actualCommencementDate;
this.nextInterestPostingDate = new LocalDate(this.lastInterestPostedDate).plusMonths(this.interestCompoundedEvery).toDate();
this.availableInterest = BigDecimal.ZERO;
this.interestPostedAmount = BigDecimal.ZERO;
LocalDate submittalDate = new LocalDate(this.projectedCommencementDate); LocalDate submittalDate = new LocalDate(this.projectedCommencementDate);
if (actualCommencementDate.isBefore(submittalDate)) { if (actualCommencementDate.isBefore(submittalDate)) {
final String errorMessage = "The date on which a deposit is approved cannot be before its submittal date: " + submittalDate.toString(); final String errorMessage = "The date on which a deposit is approved cannot be before its submittal date: " + submittalDate.toString();
@@ -545,46 +566,44 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
public void withdrawDepositAccountMoney(DepositLifecycleStateMachine depositLifecycleStateMachine, FixedTermDepositInterestCalculator fixedTermDepositInterestCalculator,LocalDate eventDate) { public void withdrawDepositAccountMoney(DepositLifecycleStateMachine depositLifecycleStateMachine, FixedTermDepositInterestCalculator fixedTermDepositInterestCalculator,LocalDate eventDate) {
if (eventDate.isBefore(getLastInterestPostedDate())) {
final String errorMessage = "Deposit Account Preclosed date \"" +eventDate+ "\"cannot before last interest posted date \"" + getLastInterestPostedDate()+"\"";
throw new InvalidDepositStateTransitionException("withdraw", "event.date.cannot.before.last.interest.posted.date",errorMessage, getLastInterestPostedDate(), eventDate);
}
if (eventDate.isAfter(maturesOnDate()) || eventDate.equals(maturesOnDate())) { if (eventDate.isAfter(maturesOnDate()) || eventDate.equals(maturesOnDate())) {
DepositAccountStatus statusEnum = depositLifecycleStateMachine.transition(DepositAccountEvent.DEPOSIT_CLOSED, DepositAccountStatus.fromInt(this.depositStatus)); DepositAccountStatus statusEnum = depositLifecycleStateMachine.transition(DepositAccountEvent.DEPOSIT_CLOSED, DepositAccountStatus.fromInt(this.depositStatus));
this.depositStatus = statusEnum.getValue(); this.depositStatus = statusEnum.getValue();
} else if(eventDate.isBefore(maturesOnDate())){
Integer days = Days.daysBetween(maturesOnDate(), eventDate).getDays();
Money accuredInterestAfterMaturityToTillDate = fixedTermDepositInterestCalculator.calculateRemainInterest(getDeposit(), days, preClosureInterestRate);
this.interestAccrued = this.interestAccrued.add(accuredInterestAfterMaturityToTillDate.getAmount());
DepositAccountTransaction depositaccountTransaction = DepositAccountTransaction.withdraw(getDeposit(), eventDate,getAccuredInterest());
depositaccountTransaction.updateAccount(this);
this.depositaccountTransactions.add(depositaccountTransaction);
this.closedOnDate = eventDate.toDate();
this.withdrawnOnDate = null;
this.rejectedOnDate = null;
}else if(new LocalDate().isBefore(maturesOnDate())){
DepositAccountStatus statusEnum = depositLifecycleStateMachine.transition(DepositAccountEvent.DEPOSIT_PRECLOSED, DepositAccountStatus.fromInt(this.depositStatus)); DepositAccountStatus statusEnum = depositLifecycleStateMachine.transition(DepositAccountEvent.DEPOSIT_PRECLOSED, DepositAccountStatus.fromInt(this.depositStatus));
this.depositStatus = statusEnum.getValue(); this.depositStatus = statusEnum.getValue();
DepositAccountTransaction depositaccountTransaction = DepositAccountTransaction.withdraw(getDeposit(), eventDate, getAccuredInterest());
depositaccountTransaction.updateAccount(this);
this.depositaccountTransactions.add(depositaccountTransaction);
this.closedOnDate = eventDate.toDate();
this.withdrawnOnDate = null;
this.rejectedOnDate = null;
} }
Integer days = Days.daysBetween(getLastInterestPostedDate(), eventDate).getDays();
Money accuredInterestAfterMaturityToTillDate = fixedTermDepositInterestCalculator.calculateRemainInterest(getDeposit(), days, preClosureInterestRate);
this.interestAccrued = this.interestAccrued.add(accuredInterestAfterMaturityToTillDate.getAmount());
DepositAccountTransaction depositaccountTransaction = DepositAccountTransaction.withdraw(getDeposit(), eventDate,getAccuredInterest());
depositaccountTransaction.updateAccount(this);
this.depositaccountTransactions.add(depositaccountTransaction);
this.closedOnDate = eventDate.toDate();
this.withdrawnOnDate = null;
this.rejectedOnDate = null;
} }
public void adjustTotalAmountForPreclosureInterest(DepositAccount account, FixedTermDepositInterestCalculator fixedTermDepositInterestCalculator,LocalDate eventDate) { /*public void adjustTotalAmountForPreclosureInterest(DepositAccount account, FixedTermDepositInterestCalculator fixedTermDepositInterestCalculator,LocalDate eventDate) {
LocalDate commnencementDate = getActualCommencementDate(); LocalDate commnencementDate = getActualCommencementDate();
LocalDate lastInterestPosedDate = getLastInterestPostedDate();
LocalDate preClosedDate = eventDate; LocalDate preClosedDate = eventDate;
Integer tenure = Months.monthsBetween(commnencementDate, preClosedDate).getMonths(); if (preClosedDate.isBefore(lastInterestPosedDate)) {
LocalDate actualPrecloseCalculationDate = commnencementDate.plusMonths(tenure); throw new DepositAccountTransactionsException("deposit.account.preclosed.date.should.be.after.last.interest.posted.date", null);
}
Integer tenure = Months.monthsBetween(lastInterestPosedDate, preClosedDate).getMonths();
LocalDate actualPrecloseCalculationDate = lastInterestPosedDate.plusMonths(tenure);
Integer missedDays = Days.daysBetween(actualPrecloseCalculationDate, preClosedDate).getDays(); Integer missedDays = Days.daysBetween(actualPrecloseCalculationDate, preClosedDate).getDays();
Money deposit = Money.of(account.getDeposit().getCurrency(), account.getDeposit().getAmount()); Money deposit = Money.of(account.getDeposit().getCurrency(), account.getDeposit().getAmount());
@@ -607,15 +626,17 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
this.total = account.isInterestCompoundingAllowed()?accuredtotalAmount.getAmount():BigDecimal.valueOf(accuredtotalAmount.getAmount().doubleValue()-this.interstPaid.doubleValue()); this.total = account.isInterestCompoundingAllowed()?accuredtotalAmount.getAmount():BigDecimal.valueOf(accuredtotalAmount.getAmount().doubleValue()-this.interstPaid.doubleValue());
this.interestAccrued = accuredtotalAmount.minus(deposit).getAmount(); this.interestAccrued = accuredtotalAmount.minus(deposit).getAmount();
} }*/
public void withdrawInterest(Money interest) { public void withdrawInterest(Money interest) {
@SuppressWarnings("unused")
if(this.depositStatus == 300 ){ boolean statustest = isActive();
if(isActive()){
DepositAccountTransaction depositAccountTransaction = DepositAccountTransaction.withdraw(null, new LocalDate(), interest); DepositAccountTransaction depositAccountTransaction = DepositAccountTransaction.withdraw(null, new LocalDate(), interest);
depositAccountTransaction.updateAccount(this); depositAccountTransaction.updateAccount(this);
this.depositaccountTransactions.add(depositAccountTransaction); this.depositaccountTransactions.add(depositAccountTransaction);
this.interstPaid = this.interstPaid.add(interest.getAmount()); this.interstPaid = this.interstPaid.add(interest.getAmount());
this.availableInterest = this.availableInterest.subtract(interest.getAmount());
this.total = this.total.subtract(interest.getAmount()); this.total = this.total.subtract(interest.getAmount());
} }
@@ -639,7 +660,6 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
final boolean renewalAllowed, final boolean preClosureAllowed, final boolean renewalAllowed, final boolean preClosureAllowed,
final boolean isInterestWithdrawable, final boolean isInterestCompoundingAllowed, final boolean isInterestWithdrawable, final boolean isInterestCompoundingAllowed,
final FixedTermDepositInterestCalculator fixedTermDepositInterestCalculator, final FixedTermDepositInterestCalculator fixedTermDepositInterestCalculator,
@SuppressWarnings("unused") final DepositLifecycleStateMachine depositLifecycleStateMachine,
final boolean isLockinPeriodAllowed, final boolean isLockinPeriodAllowed,
final Integer lockinPeriod, final Integer lockinPeriod,
final PeriodFrequencyType lockinPeriodType) { final PeriodFrequencyType lockinPeriodType) {
@@ -695,4 +715,120 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
public boolean isActive() { public boolean isActive() {
return DepositAccountStatus.fromInt(this.depositStatus).isActive(); return DepositAccountStatus.fromInt(this.depositStatus).isActive();
} }
public void postInterestForDepositAccount(DepositAccount account, FixedTermDepositInterestCalculator fixedTermDepositInterestCalculator) {
LocalDate lastInterestPostedDate = getLastInterestPostedDate();
LocalDate nextInterestPostingDate = getNextInterestPostedDate();
Integer monthsForInterestCalculation = Months.monthsBetween(lastInterestPostedDate, new LocalDate()).getMonths();
Integer postInterestItereations = monthsForInterestCalculation/this.interestCompoundedEvery;
Money deposit = Money.of(this.currency, this.depositAmount);
while (postInterestItereations > 0) {
lastInterestPostedDate = getLastInterestPostedDate();
nextInterestPostingDate = getNextInterestPostedDate();
if (lastInterestPostedDate.isBefore(getMaturityDate())){
if (nextInterestPostingDate.isAfter(getMaturityDate())){
Integer noofRemainMonthsAfterMaturity = Months.monthsBetween(getMaturityDate(), nextInterestPostingDate).getMonths();
Integer noOfMonthsBeforeMaturity = Months.monthsBetween(lastInterestPostedDate, getMaturityDate()).getMonths();
Money futureValueOnMaturity =null;
if (noOfMonthsBeforeMaturity >0) {
if (this.interestCompoundingAllowed) {
futureValueOnMaturity = fixedTermDepositInterestCalculator.calculateInterestOnMaturityFor(deposit, noOfMonthsBeforeMaturity,this.interestRate, this.interestCompoundedEvery, getInterestCompoundedFrequencyType());
} else {
futureValueOnMaturity = fixedTermDepositInterestCalculator.calculateInterestOnMaturityForSimpleInterest(deposit, noOfMonthsBeforeMaturity, this.interestRate, this.interestCompoundedEvery, getInterestCompoundedFrequencyType());
}
this.interestPostedAmount = this.interestPostedAmount.add(futureValueOnMaturity.minus(deposit).getAmount());
this.availableInterest = this.availableInterest.add(futureValueOnMaturity.minus(deposit).getAmount());
this.lastInterestPostedDate = nextInterestPostingDate.toDate();
this.nextInterestPostingDate = nextInterestPostingDate.plusMonths(this.interestCompoundedEvery).toDate();
}
if (noofRemainMonthsAfterMaturity >0){
if (this.interestCompoundingAllowed) {
futureValueOnMaturity = fixedTermDepositInterestCalculator.calculateInterestOnMaturityFor(deposit, noofRemainMonthsAfterMaturity, this.preClosureInterestRate, this.interestCompoundedEvery, getInterestCompoundedFrequencyType());
} else {
futureValueOnMaturity = fixedTermDepositInterestCalculator.calculateInterestOnMaturityForSimpleInterest(deposit, noofRemainMonthsAfterMaturity, this.preClosureInterestRate, this.interestCompoundedEvery, getInterestCompoundedFrequencyType());
}
this.interestPostedAmount = this.interestPostedAmount.add(futureValueOnMaturity.minus(deposit).getAmount());
this.availableInterest = this.availableInterest.add(futureValueOnMaturity.minus(deposit).getAmount());
this.lastInterestPostedDate = nextInterestPostingDate.toDate();
this.nextInterestPostingDate = nextInterestPostingDate.plusMonths(this.interestCompoundedEvery).toDate();
}
// add transaction entry for each interest posting
DepositAccountTransaction depositaccountTransaction = DepositAccountTransaction.postInterest(null, nextInterestPostingDate,futureValueOnMaturity.minus(deposit));
depositaccountTransaction.updateAccount(this);
this.depositaccountTransactions.add(depositaccountTransaction);
} else {
Money futureValueOnMaturity =null;
if (this.interestCompoundingAllowed) {
futureValueOnMaturity = fixedTermDepositInterestCalculator.calculateInterestOnMaturityFor(deposit, this.interestCompoundedEvery, this.interestRate, this.interestCompoundedEvery, getInterestCompoundedFrequencyType());
} else {
futureValueOnMaturity = fixedTermDepositInterestCalculator.calculateInterestOnMaturityForSimpleInterest(deposit, this.interestCompoundedEvery, this.interestRate, this.interestCompoundedEvery, getInterestCompoundedFrequencyType());
}
this.interestPostedAmount = this.interestPostedAmount.add(futureValueOnMaturity.minus(deposit).getAmount());
this.availableInterest = this.availableInterest.add(futureValueOnMaturity.minus(deposit).getAmount());
this.lastInterestPostedDate = nextInterestPostingDate.toDate();
this.nextInterestPostingDate = nextInterestPostingDate.plusMonths(this.interestCompoundedEvery).toDate();
// add transaction entry for each interest posting
DepositAccountTransaction depositaccountTransaction = DepositAccountTransaction.postInterest(null, nextInterestPostingDate,futureValueOnMaturity.minus(deposit));
depositaccountTransaction.updateAccount(this);
this.depositaccountTransactions.add(depositaccountTransaction);
}
} else{
Money futureValueOnMaturity =null;
if (this.interestCompoundingAllowed) {
futureValueOnMaturity = fixedTermDepositInterestCalculator.calculateInterestOnMaturityFor(deposit, this.interestCompoundedEvery, this.preClosureInterestRate, this.interestCompoundedEvery, getInterestCompoundedFrequencyType());
} else {
futureValueOnMaturity = fixedTermDepositInterestCalculator.calculateInterestOnMaturityForSimpleInterest(deposit, this.interestCompoundedEvery, this.preClosureInterestRate, this.interestCompoundedEvery, getInterestCompoundedFrequencyType());
}
this.interestPostedAmount = this.interestPostedAmount.add(futureValueOnMaturity.minus(deposit).getAmount());
this.availableInterest = this.availableInterest.add(futureValueOnMaturity.minus(deposit).getAmount());
this.lastInterestPostedDate = nextInterestPostingDate.toDate();
this.nextInterestPostingDate = nextInterestPostingDate.plusMonths(this.interestCompoundedEvery).toDate();
// add transaction entry for each interest posting
DepositAccountTransaction depositaccountTransaction = DepositAccountTransaction.postInterest(null, nextInterestPostingDate,futureValueOnMaturity.minus(deposit));
depositaccountTransaction.updateAccount(this);
this.depositaccountTransactions.add(depositaccountTransaction);
}
postInterestItereations--;
}
}
private final LocalDate getLastInterestPostedDate() {
LocalDate lastInterestPostedDate;
if (this.lastInterestPostedDate == null){
lastInterestPostedDate = new LocalDate(this.actualCommencementDate);
} else {
lastInterestPostedDate = new LocalDate(this.lastInterestPostedDate);
}
return lastInterestPostedDate;
}
private final LocalDate getNextInterestPostedDate() {
LocalDate nextInterestPostingDate;
if (this.nextInterestPostingDate == null){
nextInterestPostingDate = new LocalDate(this.nextInterestPostingDate).plusMonths(this.interestCompoundedEvery);
} else {
nextInterestPostingDate = new LocalDate(this.nextInterestPostingDate);
}
return nextInterestPostingDate;
}
public BigDecimal getAvailableInterest() {
return availableInterest;
}
public BigDecimal getInterestPostedAmount() {
return interestPostedAmount;
}
} }
@@ -102,6 +102,10 @@ public class DepositAccountTransaction extends AbstractPersistable<Long> {
return new DepositAccountTransaction(DepositAccountTransactionType.WITHDRAW, amount == null ? new BigDecimal(0) : amount.getAmount(), paymentDate, interest==null ? new BigDecimal(0) : interest.getAmount()); return new DepositAccountTransaction(DepositAccountTransactionType.WITHDRAW, amount == null ? new BigDecimal(0) : amount.getAmount(), paymentDate, interest==null ? new BigDecimal(0) : interest.getAmount());
} }
public static DepositAccountTransaction postInterest(Money depositAmount, LocalDate paymentDate, Money interest) {
return new DepositAccountTransaction(DepositAccountTransactionType.INTEREST_POSTING, depositAmount == null ? new BigDecimal(0) : depositAmount.getAmount(), paymentDate, interest==null ? new BigDecimal(0) : interest.getAmount());
}
public void updateAccount(DepositAccount depositAccount) { public void updateAccount(DepositAccount depositAccount) {
this.depositAccount=depositAccount; this.depositAccount=depositAccount;
} }
@@ -5,7 +5,8 @@ public enum DepositAccountTransactionType {
INVALID(0, "depositTransactionType.invalid"), // INVALID(0, "depositTransactionType.invalid"), //
DEPOSIT(1, "depositTransactionType.deposit"), // DEPOSIT(1, "depositTransactionType.deposit"), //
WITHDRAW(2, "depositTransactionType.withdraw"), // WITHDRAW(2, "depositTransactionType.withdraw"), //
REVERSAL(3, "depositTransactionType.reversal"); REVERSAL(3, "depositTransactionType.reversal"),
INTEREST_POSTING(4,"depositTransactionType.interestPosting");
private final Integer value; private final Integer value;
private final String code; private final String code;
@@ -43,6 +44,10 @@ public enum DepositAccountTransactionType {
depositTransactionType=DepositAccountTransactionType.REVERSAL; depositTransactionType=DepositAccountTransactionType.REVERSAL;
break; break;
case 4:
depositTransactionType=DepositAccountTransactionType.INTEREST_POSTING;
break;
default : default :
depositTransactionType=DepositAccountTransactionType.INVALID; depositTransactionType=DepositAccountTransactionType.INVALID;
break; break;
@@ -230,9 +230,9 @@ public class DepositAccountAssembler {
return newAccount; return newAccount;
} }
public void adjustTotalAmountForPreclosureInterest(DepositAccount account,LocalDate eventDate) { /*public void adjustTotalAmountForPreclosureInterest(DepositAccount account,LocalDate eventDate) {
account.adjustTotalAmountForPreclosureInterest(account,this.fixedTermDepositInterestCalculator,eventDate); account.adjustTotalAmountForPreclosureInterest(account,this.fixedTermDepositInterestCalculator,eventDate);
} }*/
public void assembleUpdatedDepositAccount(DepositAccount account,DepositAccountCommand command) { public void assembleUpdatedDepositAccount(DepositAccount account,DepositAccountCommand command) {
@@ -323,7 +323,7 @@ public class DepositAccountAssembler {
lockinPeriodType = PeriodFrequencyType.fromInt(command.getLockinPeriodType()); lockinPeriodType = PeriodFrequencyType.fromInt(command.getLockinPeriodType());
} }
account.update(product,externalId,commencementDate,deposit,tenureInMonths,maturityInterestRate,preClosureInterestRate,compoundingInterestEvery,compoundingInterestFrequency,renewalAllowed, account.update(product,externalId,commencementDate,deposit,tenureInMonths,maturityInterestRate,preClosureInterestRate,compoundingInterestEvery,compoundingInterestFrequency,renewalAllowed,
preClosureAllowed,isInterestWithdrawable,isInterestCompoundingAllowed,this.fixedTermDepositInterestCalculator,defaultDepositLifecycleStateMachine(),isLockinPeriodAllowed,lockinPeriod,lockinPeriodType); preClosureAllowed,isInterestWithdrawable,isInterestCompoundingAllowed,this.fixedTermDepositInterestCalculator,isLockinPeriodAllowed,lockinPeriod,lockinPeriodType);
} }
public void updateApprovedDepositAccount(DepositAccount account, DepositAccountCommand command) { public void updateApprovedDepositAccount(DepositAccount account, DepositAccountCommand command) {
@@ -340,4 +340,8 @@ public class DepositAccountAssembler {
account.update(renewalAllowed,isInterestWithdrawable); account.update(renewalAllowed,isInterestWithdrawable);
} }
public void postInterest(DepositAccount account) {
account.postInterestForDepositAccount(account,this.fixedTermDepositInterestCalculator);
}
} }
@@ -4,6 +4,7 @@ import java.math.BigDecimal;
import java.util.Collection; import java.util.Collection;
import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositAccountData; import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositAccountData;
import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositAccountsForLookup;
import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositPermissionData; import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositPermissionData;
public interface DepositAccountReadPlatformService { public interface DepositAccountReadPlatformService {
@@ -17,4 +18,6 @@ public interface DepositAccountReadPlatformService {
DepositPermissionData retrieveDepositAccountsPermissions(DepositAccountData depositAccountData); DepositPermissionData retrieveDepositAccountsPermissions(DepositAccountData depositAccountData);
BigDecimal retrieveAvailableInterestForWithdrawal(DepositAccountData account); BigDecimal retrieveAvailableInterestForWithdrawal(DepositAccountData account);
Collection<DepositAccountsForLookup> retrieveDepositAccountForLookup();
} }
@@ -18,6 +18,7 @@ import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundExce
import org.mifosplatform.portfolio.savingsaccountproduct.service.SavingsDepositEnumerations; import org.mifosplatform.portfolio.savingsaccountproduct.service.SavingsDepositEnumerations;
import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositAccountData; import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositAccountData;
import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositAccountTransactionData; import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositAccountTransactionData;
import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositAccountsForLookup;
import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositPermissionData; import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositPermissionData;
import org.mifosplatform.portfolio.savingsdepositproduct.data.DepositProductData; import org.mifosplatform.portfolio.savingsdepositproduct.data.DepositProductData;
import org.mifosplatform.portfolio.savingsdepositproduct.data.DepositProductLookup; import org.mifosplatform.portfolio.savingsdepositproduct.data.DepositProductLookup;
@@ -143,6 +144,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
+ " 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, " + " da.interest_paid as interestPaid, da.is_interest_withdrawable as isInterestWithdrawable, da.is_compounding_interest_allowed as interestCompoundingAllowed, "
+ " da.is_lock_in_period_allowed as isLockinPeriodAllowed, da.lock_in_period as lockinPeriod, da.lock_in_period_type lockinPeriodType, " + " da.is_lock_in_period_allowed as isLockinPeriodAllowed, da.lock_in_period as lockinPeriod, da.lock_in_period_type lockinPeriodType, "
+ " da.available_interest as availableInterest, da.interest_posted_amount as interestPostedAmount, da.last_interest_posted_date as lastInterestPostedDate, da.next_interest_posting_date as nextInterestPostedDate,"
+ " c.firstname as firstname, c.lastname as lastname, pd.name as productName," + " 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 " + " curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol "
+ " from m_deposit_account da " + " join m_currency curr on curr.code = da.currency_code " + " from m_deposit_account da " + " join m_currency curr on curr.code = da.currency_code "
@@ -207,12 +209,17 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
Integer lockinPeriodTypeValue = JdbcSupport.getInteger(rs, "lockinPeriodType"); Integer lockinPeriodTypeValue = JdbcSupport.getInteger(rs, "lockinPeriodType");
EnumOptionData lockinPeriodType = SavingsDepositEnumerations.interestCompoundingPeriodType(lockinPeriodTypeValue); EnumOptionData lockinPeriodType = SavingsDepositEnumerations.interestCompoundingPeriodType(lockinPeriodTypeValue);
BigDecimal availableInterest = rs.getBigDecimal("availableInterest");
BigDecimal interestPostedAmount = rs.getBigDecimal("interestPostedAmount");
LocalDate lastInterestPostedDate = JdbcSupport.getLocalDate(rs, "lastInterestPostedDate");
LocalDate nextInterestPostedDate = JdbcSupport.getLocalDate(rs, "nextInterestPostedDate");
return new DepositAccountData(id, externalId, status, clientId, clientName, productId, productName, currencyData, return new DepositAccountData(id, externalId, status, clientId, clientName, productId, productName, currencyData,
depositAmount, interestRate, termInMonths, projectedCommencementDate, actualCommencementDate, maturedOn, depositAmount, interestRate, termInMonths, projectedCommencementDate, actualCommencementDate, maturedOn,
projectedInterestAccrued, actualInterestAccrued, projectedMaturityAmount, actualMaturityAmount, projectedInterestAccrued, actualInterestAccrued, projectedMaturityAmount, actualMaturityAmount,
interestCompoundedEvery, interestCompoundedEveryPeriodType, renewalAllowed, preClosureAllowed, preClosureInterestRate, interestCompoundedEvery, interestCompoundedEveryPeriodType, renewalAllowed, preClosureAllowed, preClosureInterestRate,
withdrawnonDate, rejectedonDate, closedonDate, isInterestWithdrawable, interestPaid, interestCompoundingAllowed, withdrawnonDate, rejectedonDate, closedonDate, isInterestWithdrawable, interestPaid, interestCompoundingAllowed,
isLockinPeriodAllowed, lockinPeriod, lockinPeriodType); isLockinPeriodAllowed, lockinPeriod, lockinPeriodType, availableInterest, interestPostedAmount, lastInterestPostedDate, nextInterestPostedDate);
} }
} }
@@ -247,18 +254,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
boolean undoApprovalAllowed = (depositAccountData.getStatus().getId().equals(300L)); boolean undoApprovalAllowed = (depositAccountData.getStatus().getId().equals(300L));
boolean renewelAllowed = false; boolean renewelAllowed = false;
if (depositAccountData.getMaturedOn() != null) { if (depositAccountData.getMaturedOn() != null) {
if (new LocalDate().isAfter(depositAccountData.getMaturedOn())/* if (new LocalDate().isAfter(depositAccountData.getMaturedOn())/* || depositAccountData.getMaturedOn().isEqual(new LocalDate()) */) {
* ||
* depositAccountData
* .
* getMaturedOn
* ().
* isEqual
* (
* new
* LocalDate
* ())
*/) {
renewelAllowed = depositAccountData.isRenewalAllowed(); renewelAllowed = depositAccountData.isRenewalAllowed();
} }
} }
@@ -280,4 +276,28 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
return BigDecimal.valueOf(interstGettingForPeriod.multiply(new BigDecimal(noOfPeriods)).doubleValue() return BigDecimal.valueOf(interstGettingForPeriod.multiply(new BigDecimal(noOfPeriods)).doubleValue()
- account.getInterestPaid().doubleValue()); - account.getInterestPaid().doubleValue());
} }
@Override
public Collection<DepositAccountsForLookup> retrieveDepositAccountForLookup() {
this.context.authenticatedUser();
DepositAccountLookupMapper mapper = new DepositAccountLookupMapper();
String sql = "select "+mapper.depositAccountLookupSchema();
return this.jdbcTemplate.query(sql, mapper, new Object[]{});
}
private static final class DepositAccountLookupMapper implements RowMapper<DepositAccountsForLookup> {
public String depositAccountLookupSchema(){
return " da.id as id from m_deposit_account da where da.status_enum=300 and da.is_deleted=0";
}
@Override
public DepositAccountsForLookup mapRow(ResultSet rs, int rowNum) throws SQLException {
Long id = rs.getLong("id");
return new DepositAccountsForLookup(id);
}
}
} }
@@ -1,5 +1,7 @@
package org.mifosplatform.portfolio.savingsdepositaccount.service; package org.mifosplatform.portfolio.savingsdepositaccount.service;
import java.util.Collection;
import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
import org.mifosplatform.portfolio.loanaccount.command.UndoStateTransitionCommand; import org.mifosplatform.portfolio.loanaccount.command.UndoStateTransitionCommand;
import org.mifosplatform.portfolio.savingsdepositaccount.command.DepositAccountCommand; import org.mifosplatform.portfolio.savingsdepositaccount.command.DepositAccountCommand;
@@ -7,6 +9,7 @@ import org.mifosplatform.portfolio.savingsdepositaccount.command.DepositAccountW
import org.mifosplatform.portfolio.savingsdepositaccount.command.DepositAccountWithdrawalCommand; import org.mifosplatform.portfolio.savingsdepositaccount.command.DepositAccountWithdrawalCommand;
import org.mifosplatform.portfolio.savingsdepositaccount.command.DepositStateTransitionApprovalCommand; import org.mifosplatform.portfolio.savingsdepositaccount.command.DepositStateTransitionApprovalCommand;
import org.mifosplatform.portfolio.savingsdepositaccount.command.DepositStateTransitionCommand; import org.mifosplatform.portfolio.savingsdepositaccount.command.DepositStateTransitionCommand;
import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositAccountsForLookup;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
public interface DepositAccountWritePlatformService { public interface DepositAccountWritePlatformService {
@@ -49,4 +52,7 @@ public interface DepositAccountWritePlatformService {
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'ORGANISATION_ADMINISTRATION_SUPER_USER', 'RENEW_DEPOSITACCOUNT')") @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'ORGANISATION_ADMINISTRATION_SUPER_USER', 'RENEW_DEPOSITACCOUNT')")
EntityIdentifier renewDepositAccount(DepositAccountCommand command); EntityIdentifier renewDepositAccount(DepositAccountCommand command);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER')")
EntityIdentifier postInterestToDepositAccount(Collection<DepositAccountsForLookup> accounts);
} }
@@ -2,6 +2,7 @@ package org.mifosplatform.portfolio.savingsdepositaccount.service;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.List; import java.util.List;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
@@ -24,6 +25,7 @@ import org.mifosplatform.portfolio.savingsdepositaccount.command.DepositStateTra
import org.mifosplatform.portfolio.savingsdepositaccount.command.DepositStateTransitionApprovalCommandValidator; import org.mifosplatform.portfolio.savingsdepositaccount.command.DepositStateTransitionApprovalCommandValidator;
import org.mifosplatform.portfolio.savingsdepositaccount.command.DepositStateTransitionCommand; import org.mifosplatform.portfolio.savingsdepositaccount.command.DepositStateTransitionCommand;
import org.mifosplatform.portfolio.savingsdepositaccount.command.WithDrawDepositAccountInterestCommandValidator; import org.mifosplatform.portfolio.savingsdepositaccount.command.WithDrawDepositAccountInterestCommandValidator;
import org.mifosplatform.portfolio.savingsdepositaccount.data.DepositAccountsForLookup;
import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositAccount; import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositAccount;
import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositAccountRepository; import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositAccountRepository;
import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositAccountStatus; import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositAccountStatus;
@@ -303,9 +305,9 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
"deposit.transaction.canot.withdraw.before.lockinperiod.reached", "deposit.transaction.canot.withdraw.before.lockinperiod.reached",
"You can not withdraw your application before maturity date reached"); } "You can not withdraw your application before maturity date reached"); }
} }
if (eventDate.isBefore(account.maturesOnDate())) { // if (eventDate.isBefore(account.maturesOnDate())) {
this.depositAccountAssembler.adjustTotalAmountForPreclosureInterest(account, eventDate); // this.depositAccountAssembler.adjustTotalAmountForPreclosureInterest(account, eventDate);
} // }
account.withdrawDepositAccountMoney(defaultDepositLifecycleStateMachine(), fixedTermDepositInterestCalculator, eventDate); account.withdrawDepositAccountMoney(defaultDepositLifecycleStateMachine(), fixedTermDepositInterestCalculator, eventDate);
this.depositAccountRepository.save(account); this.depositAccountRepository.save(account);
String noteText = command.getNote(); String noteText = command.getNote();
@@ -419,4 +421,26 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
return new EntityIdentifier(Long.valueOf(-1)); return new EntityIdentifier(Long.valueOf(-1));
} }
} }
@Transactional
@Override
public EntityIdentifier postInterestToDepositAccount(Collection<DepositAccountsForLookup> accounts) {
try {
for (DepositAccountsForLookup accountData : accounts)
{
DepositAccount account = this.depositAccountRepository.findOne(accountData.getId());
if (account == null || account.isDeleted()) {
throw new DepositAccountNotFoundException(accountData.getId());
}
this.depositAccountAssembler.postInterest(account);
this.depositAccountRepository.save(account);
}
return new EntityIdentifier(new Long(accounts.size()));
} catch (Exception e) {
return new EntityIdentifier(Long.valueOf(-1));
}
}
} }