add interest compounding frequency to deposit product along with externalId and unique constraints for name and externalId on product.

This commit is contained in:
Keith Woodlock
2012-08-14 23:54:33 +01:00
parent 6642aacff5
commit f30e8645a3
10 changed files with 391 additions and 77 deletions
@@ -0,0 +1,74 @@
DROP TABLE if exists `portfolio_deposit_account`;
DROP TABLE if exists `portfolio_product_deposit`;
CREATE TABLE `portfolio_product_deposit` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`is_deleted` tinyint(1) NOT NULL DEFAULT '0',
`external_id` varchar(100) DEFAULT NULL,
`description` varchar(500) DEFAULT NULL,
`currency_code` varchar(3) NOT NULL,
`currency_digits` smallint(5) NOT NULL,
`minimum_balance` decimal(19,6) DEFAULT NULL,
`maximum_balance` decimal(19,6) DEFAULT NULL,
`tenure_months` int(11) NOT NULL,
`interest_compounded_every` smallint(5) NOT NULL DEFAULT '1',
`interest_compounded_every_period_enum` smallint(5) NOT NULL DEFAULT '2',
`maturity_default_interest_rate` decimal(19,6) NOT NULL,
`maturity_min_interest_rate` decimal(19,6) NOT NULL,
`maturity_max_interest_rate` decimal(19,6) NOT NULL,
`is_renewal_allowed` tinyint(1) NOT NULL DEFAULT '0',
`is_preclosure_allowed` tinyint(1) NOT NULL DEFAULT '0',
`pre_closure_interest_rate` decimal(19,6) 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`),
UNIQUE KEY `name_deposit_product` (`name`),
UNIQUE KEY `externalid_deposit_product` (`external_id`),
KEY `FKJPW0000000000003` (`createdby_id`),
KEY `FKJPW0000000000004` (`lastmodifiedby_id`),
CONSTRAINT `FKJPX0000000000003` FOREIGN KEY (`createdby_id`) REFERENCES `admin_appuser` (`id`),
CONSTRAINT `FKJPX0000000000004` FOREIGN KEY (`lastmodifiedby_id`) REFERENCES `admin_appuser` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `portfolio_deposit_account` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`is_deleted` tinyint(1) NOT NULL DEFAULT '0',
`external_id` varchar(100) DEFAULT NULL,
`client_id` bigint(20) NOT NULL,
`product_id` bigint(20) NOT NULL,
`currency_code` varchar(3) NOT NULL,
`currency_digits` smallint(5) NOT NULL,
`deposit_amount` decimal(19,6) DEFAULT NULL,
`maturity_nominal_interest_rate` decimal(19,6) NOT NULL,
`tenure_months` int(11) NOT NULL,
`interest_compounded_every` smallint(5) NOT NULL DEFAULT '1',
`interest_compounded_every_period_enum` smallint(5) NOT NULL DEFAULT '2',
`projected_commencement_date` DATE NOT NULL,
`actual_commencement_date` DATE DEFAULT NULL,
`projected_maturity_date` DATE NOT NULL,
`actual_maturity_date` DATE DEFAULT NULL,
`projected_interest_accrued_on_maturity` decimal(19,6) NOT NULL,
`actual_interest_accrued` decimal(19,6) DEFAULT NULL,
`projected_total_maturity_amount` decimal(19,6) NOT NULL,
`actual_total_amount` decimal(19,6) DEFAULT NULL,
`is_renewal_allowed` tinyint(1) NOT NULL DEFAULT '0',
`renewed_account_id` bigint(20) DEFAULT NULL,
`is_preclosure_allowed` tinyint(1) NOT NULL DEFAULT '0',
`pre_closure_interest_rate` decimal(19,6) 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`),
UNIQUE KEY `deposit_acc_external_id` (`external_id`),
KEY `FKKW0000000000001` (`client_id`),
KEY `FKKW0000000000002` (`product_id`),
KEY `FKKW0000000000003` (`renewed_account_id`),
CONSTRAINT `FKKW0000000000001` FOREIGN KEY (`client_id`) REFERENCES `portfolio_client` (`id`),
CONSTRAINT `FKKW0000000000002` FOREIGN KEY (`product_id`) REFERENCES `portfolio_product_deposit` (`id`),
CONSTRAINT `FKKW0000000000003` FOREIGN KEY (`renewed_account_id`) REFERENCES `portfolio_deposit_account` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@@ -53,7 +53,6 @@ public class DepositProductsApiResource {
EntityIdentifier entityIdentifier=this.depositProductWritePlatformService.createDepositProduct(command);
return Response.ok().entity(entityIdentifier).build();
}
@PUT
@@ -84,9 +83,11 @@ public class DepositProductsApiResource {
public String retrieveAllDepositProducts(@Context final UriInfo uriInfo) {
Set<String> typicalResponseParameters = new HashSet<String>(
Arrays.asList("id", "name", "description", "createdOn", "lastModifedOn",
"currencyCode","digitsAfterDecimal","minimumBalance","maximumBalance","tenureInMonths","maturityDefaultInterestRate","maturityMinInterestRate",
"maturityMaxInterestRate","renewalAllowed","preClosureAllowed","preClosureInterestRate"));
Arrays.asList("id", "externalId", "name", "description", "createdOn", "lastModifedOn",
"currencyCode","digitsAfterDecimal","minimumBalance","maximumBalance","tenureInMonths",
"maturityDefaultInterestRate","maturityMinInterestRate","maturityMaxInterestRate",
"interestCompoundedEvery", "interestCompoundedEveryPeriodType",
"renewalAllowed","preClosureAllowed","preClosureInterestRate"));
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
if (responseParameters.isEmpty()) {
@@ -105,9 +106,11 @@ public class DepositProductsApiResource {
public String retrieveDepositProductDetails(@PathParam("productId") final Long productId, @Context final UriInfo uriInfo) {
Set<String> typicalResponseParameters = new HashSet<String>(
Arrays.asList("id", "name", "description", "createdOn", "lastModifedOn",
"currencyCode","digitsAfterDecimal","minimumBalance","maximumBalance","tenureInMonths","maturityDefaultInterestRate","maturityMinInterestRate",
"maturityMaxInterestRate","renewalAllowed","preClosureAllowed","preClosureInterestRate"));
Arrays.asList("id", "externalId", "name", "description", "createdOn", "lastModifedOn",
"currencyCode","digitsAfterDecimal","minimumBalance","maximumBalance","tenureInMonths",
"maturityDefaultInterestRate","maturityMinInterestRate","maturityMaxInterestRate",
"interestCompoundedEvery", "interestCompoundedEveryPeriodType",
"renewalAllowed","preClosureAllowed","preClosureInterestRate"));
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
if (responseParameters.isEmpty()) {
@@ -116,9 +119,11 @@ public class DepositProductsApiResource {
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
boolean template = ApiParameterHelper.template(uriInfo.getQueryParameters());
if (template) {
responseParameters.addAll(Arrays.asList("currencyOptions"));
responseParameters.addAll(Arrays.asList("currencyOptions", "interestCompoundedEveryPeriodTypeOptions"));
}
DepositProductData productData = this.depositProductReadPlatformService.retrieveDepositProductData(productId);
return this.apiDataConversionService.convertDepositProductDataToJson(prettyPrint, responseParameters, productData);
}
@@ -129,9 +134,12 @@ public class DepositProductsApiResource {
public String retrieveNewDepositProductDetails(@Context final UriInfo uriInfo) {
Set<String> typicalResponseParameters = new HashSet<String>(
Arrays.asList("currencyOptions", "id", "name", "description", "createdOn", "lastModifedOn",
"currencyCode","digitsAfterDecimal","minimumBalance","maximumBalance","tenureInMonths","maturityDefaultInterestRate","maturityMinInterestRate",
"maturityMaxInterestRate","renewalAllowed","preClosureAllowed","preClosureInterestRate"));
Arrays.asList("currencyOptions", "interestCompoundedEveryPeriodTypeOptions",
"id", "externalId", "name", "description", "createdOn", "lastModifedOn",
"currencyCode","digitsAfterDecimal","minimumBalance","maximumBalance","tenureInMonths",
"maturityDefaultInterestRate","maturityMinInterestRate","maturityMaxInterestRate",
"interestCompoundedEvery", "interestCompoundedEveryPeriodType",
"renewalAllowed","preClosureAllowed","preClosureInterestRate"));
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
if (responseParameters.isEmpty()) {
@@ -143,5 +151,4 @@ public class DepositProductsApiResource {
return this.apiDataConversionService.convertDepositProductDataToJson(prettyPrint, responseParameters, depositProduct);
}
}
}
@@ -6,6 +6,7 @@ import java.util.Set;
public class DepositProductCommand {
private final Long id;
private final String externalId;
private final String name;
private final String description;
@@ -19,6 +20,9 @@ public class DepositProductCommand {
private final BigDecimal maturityDefaultInterestRate;
private final BigDecimal maturityMinInterestRate;
private final BigDecimal maturityMaxInterestRate;
private final Integer interestCompoundedEvery;
private final Integer interestCompoundedEveryPeriodType;
private final boolean renewalAllowed;
private final boolean preClosureAllowed;
private final BigDecimal preClosureInterestRate;
@@ -26,13 +30,16 @@ public class DepositProductCommand {
private final Set<String> modifiedParameters;
public DepositProductCommand(final Set<String> modifiedParameters,
final Long id, final String name, final String description,
final Long id, final String externalId, final String name, final String description,
final String currencyCode, final Integer digitsAfterDecimal,
final BigDecimal minimumBalance, final BigDecimal maximumBalance,
final Integer tenureInMonths, final BigDecimal maturityDefaultInterestRate,
final BigDecimal maturityMinInterestRate, final BigDecimal maturityMaxInterestRate,
final Integer interestCompoundedEvery,
final Integer interestCompoundedEveryPeriodType,
final boolean renewalAllowed, final boolean preClosureAllowed, final BigDecimal preClosureInterestRate ) {
this.id = id;
this.externalId = externalId;
this.name = name;
this.description = description;
@@ -46,6 +53,8 @@ public class DepositProductCommand {
this.maturityDefaultInterestRate = maturityDefaultInterestRate;
this.maturityMinInterestRate = maturityMinInterestRate;
this.maturityMaxInterestRate = maturityMaxInterestRate;
this.interestCompoundedEvery = interestCompoundedEvery;
this.interestCompoundedEveryPeriodType = interestCompoundedEveryPeriodType;
this.preClosureInterestRate = preClosureInterestRate;
this.renewalAllowed = renewalAllowed;
@@ -58,6 +67,10 @@ public class DepositProductCommand {
public Long getId() {
return id;
}
public String getExternalId() {
return externalId;
}
public String getName() {
return name;
@@ -99,6 +112,14 @@ public class DepositProductCommand {
return maturityMaxInterestRate;
}
public Integer getInterestCompoundedEvery() {
return interestCompoundedEvery;
}
public Integer getInterestCompoundedEveryPeriodType() {
return interestCompoundedEveryPeriodType;
}
public boolean isRenewalAllowed() {
return renewalAllowed;
}
@@ -110,6 +131,10 @@ public class DepositProductCommand {
public BigDecimal getPreClosureInterestRate() {
return preClosureInterestRate;
}
public boolean isExternalIdChanged() {
return this.modifiedParameters.contains("externalId");
}
public boolean isNameChanged() {
return this.modifiedParameters.contains("name");
@@ -155,6 +180,14 @@ public class DepositProductCommand {
return this.modifiedParameters.contains("maturityMaxInterestRate");
}
public boolean isInterestCompoundedEveryChanged() {
return this.modifiedParameters.contains("interestCompoundedEvery");
}
public boolean isInterestCompoundedEveryPeriodTypeChanged() {
return this.modifiedParameters.contains("interestCompoundedEveryPeriodType");
}
public boolean isRenewalAllowedChanged() {
return this.modifiedParameters.contains("renewalAllowed");
}
@@ -12,6 +12,7 @@ import org.joda.time.DateTime;
public class DepositProductData {
private final Long id;
private final String externalId;
private final String name;
private final String description;
private final String currencyCode;
@@ -22,6 +23,9 @@ public class DepositProductData {
private final BigDecimal maturityDefaultInterestRate;
private final BigDecimal maturityMinInterestRate;
private final BigDecimal maturityMaxInterestRate;
private final Integer interestCompoundedEvery;
private final EnumOptionData interestCompoundedEveryPeriodType;
private final boolean renewalAllowed;
private final boolean preClosureAllowed;
private final BigDecimal preClosureInterestRate;
@@ -30,11 +34,13 @@ public class DepositProductData {
private final DateTime lastModifedOn;
private final List<CurrencyData> currencyOptions;
private final List<EnumOptionData> interestCompoundedEveryPeriodTypeOptions;
public DepositProductData(
final DateTime createdOn,
final DateTime lastModifedOn,
final Long id,
final String externalId,
final String name,
final String description,
final String currencyCode,
@@ -45,6 +51,8 @@ public class DepositProductData {
final BigDecimal maturityDefaultInterestRate,
final BigDecimal maturityMinInterestRate,
final BigDecimal maturityMaxInterestRate,
final Integer interestCompoundedEvery,
final EnumOptionData interestCompoundedEveryPeriodType,
final boolean renewalAllowed,
final boolean preClosureAllowed,
final BigDecimal preClosureInterestRate) {
@@ -52,6 +60,7 @@ public class DepositProductData {
this.createdOn=createdOn;
this.lastModifedOn=lastModifedOn;
this.id=id;
this.externalId = externalId;
this.name=name;
this.description=description;
this.currencyCode=currencyCode;
@@ -63,17 +72,24 @@ public class DepositProductData {
this.maturityDefaultInterestRate = maturityDefaultInterestRate;
this.maturityMinInterestRate=maturityMinInterestRate;
this.maturityMaxInterestRate=maturityMaxInterestRate;
this.interestCompoundedEvery = interestCompoundedEvery;
this.interestCompoundedEveryPeriodType = interestCompoundedEveryPeriodType;
this.renewalAllowed=renewalAllowed;
this.preClosureAllowed=preClosureAllowed;
this.preClosureInterestRate=preClosureInterestRate;
this.currencyOptions = new ArrayList<CurrencyData>();
this.interestCompoundedEveryPeriodTypeOptions = new ArrayList<EnumOptionData>();
}
public DepositProductData(final List<CurrencyData> currencyOptions) {
public DepositProductData(
final List<CurrencyData> currencyOptions,
final EnumOptionData defaultInterestCompoundedEveryPeriodType,
final List<EnumOptionData> interestCompoundedEveryPeriodTypeOptions) {
this.createdOn=null;
this.lastModifedOn=null;
this.id=null;
this.externalId = null;
this.name=null;
this.description=null;
this.currencyCode=null;
@@ -85,17 +101,25 @@ public class DepositProductData {
this.maturityDefaultInterestRate = null;
this.maturityMinInterestRate=BigDecimal.ZERO;
this.maturityMaxInterestRate=BigDecimal.ZERO;
this.interestCompoundedEvery = Integer.valueOf(1);
this.interestCompoundedEveryPeriodType = defaultInterestCompoundedEveryPeriodType;
this.renewalAllowed=true;
this.preClosureAllowed=true;
this.preClosureInterestRate=BigDecimal.ZERO;
this.currencyOptions = currencyOptions;
this.interestCompoundedEveryPeriodTypeOptions = interestCompoundedEveryPeriodTypeOptions;
}
public DepositProductData(final DepositProductData product, final List<CurrencyData> currencyOptions) {
public DepositProductData(
final DepositProductData product,
final List<CurrencyData> currencyOptions,
final List<EnumOptionData> interestCompoundedEveryPeriodTypeOptions) {
this.createdOn=product.getCreatedOn();
this.lastModifedOn=product.getLastModifedOn();
this.id=product.getId();
this.externalId = product.getExternalId();
this.name=product.getName();
this.description=product.getDescription();
this.currencyCode=product.getCurrencyCode();
@@ -107,16 +131,24 @@ public class DepositProductData {
this.maturityDefaultInterestRate = product.getMaturityDefaultInterestRate();
this.maturityMinInterestRate=product.getMaturityMinInterestRate();
this.maturityMaxInterestRate=product.getMaturityMaxInterestRate();
this.interestCompoundedEvery = product.getInterestCompoundedEvery();
this.interestCompoundedEveryPeriodType = product.getInterestCompoundedEveryPeriodType();
this.renewalAllowed=product.isRenewalAllowed();
this.preClosureAllowed=product.isPreClosureAllowed();
this.preClosureInterestRate=product.getPreClosureInterestRate();
this.currencyOptions = currencyOptions;
this.interestCompoundedEveryPeriodTypeOptions = interestCompoundedEveryPeriodTypeOptions;
}
public Long getId() {
return id;
}
public String getExternalId() {
return externalId;
}
public String getName() {
return name;
@@ -157,6 +189,14 @@ public class DepositProductData {
public BigDecimal getMaturityMaxInterestRate() {
return maturityMaxInterestRate;
}
public Integer getInterestCompoundedEvery() {
return interestCompoundedEvery;
}
public EnumOptionData getInterestCompoundedEveryPeriodType() {
return interestCompoundedEveryPeriodType;
}
public boolean isRenewalAllowed() {
return renewalAllowed;
@@ -181,4 +221,8 @@ public class DepositProductData {
public List<CurrencyData> getCurrencyOptions() {
return currencyOptions;
}
public List<EnumOptionData> getInterestCompoundedEveryPeriodTypeOptions() {
return interestCompoundedEveryPeriodTypeOptions;
}
}
@@ -1572,12 +1572,16 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
Map<String, String> requestMap = gsonConverter.fromJson(json, typeOfMap);
Set<String> supportedParams = new HashSet<String>(
Arrays.asList("name","description","currencyCode", "digitsAfterDecimal","locale","minimumBalance","maximumBalance","tenureInMonths",
"maturityDefaultInterestRate","maturityMinInterestRate","maturityMaxInterestRate","renewalAllowed","preClosureAllowed","preClosureInterestRate")
Arrays.asList("locale", "name", "externalId", "description","currencyCode", "digitsAfterDecimal","minimumBalance","maximumBalance","tenureInMonths",
"maturityDefaultInterestRate","maturityMinInterestRate","maturityMaxInterestRate",
"interestCompoundedEvery", "interestCompoundedEveryPeriodType",
"renewalAllowed","preClosureAllowed","preClosureInterestRate")
);
checkForUnsupportedParameters(requestMap, supportedParams);
Set<String> modifiedParameters = new HashSet<String>();
String name = extractStringParameter("name", requestMap,modifiedParameters);
String externalId = extractStringParameter("externalId", requestMap,modifiedParameters);
String description = extractStringParameter("description", requestMap,modifiedParameters);
String currencyCode=extractStringParameter("currencyCode", requestMap,modifiedParameters);
Integer digitsAfterDecimalValue = extractIntegerParameter("digitsAfterDecimal", requestMap, modifiedParameters);
@@ -1588,12 +1592,19 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
BigDecimal maturityDefaultInterestRate = extractBigDecimalParameter("maturityDefaultInterestRate", requestMap, modifiedParameters);
BigDecimal maturityMinInterestRate = extractBigDecimalParameter("maturityMinInterestRate", requestMap, modifiedParameters);
BigDecimal maturityMaxInterestRate = extractBigDecimalParameter("maturityMaxInterestRate", requestMap, modifiedParameters);
Integer interestCompoundedEvery = extractIntegerParameter("interestCompoundedEvery", requestMap, modifiedParameters);
Integer interestCompoundedEveryPeriodType = extractIntegerParameter("interestCompoundedEveryPeriodType", requestMap, modifiedParameters);
boolean canRenew = extractBooleanParameter("renewalAllowed", requestMap, modifiedParameters);
boolean canPreClose = extractBooleanParameter("preClosureAllowed", requestMap, modifiedParameters);
BigDecimal preClosureInterestRate = extractBigDecimalParameter("preClosureInterestRate", requestMap, modifiedParameters);
return new DepositProductCommand(modifiedParameters, resourceIdentifier, name, description, currencyCode, digitsAfterDecimalValue, minimumBalance,maximumBalance,
tenureMonths, maturityDefaultInterestRate, maturityMinInterestRate, maturityMaxInterestRate, canRenew, canPreClose, preClosureInterestRate);
return new DepositProductCommand(modifiedParameters, resourceIdentifier, externalId,
name, description, currencyCode, digitsAfterDecimalValue, minimumBalance,maximumBalance,
tenureMonths, maturityDefaultInterestRate, maturityMinInterestRate, maturityMaxInterestRate,
interestCompoundedEvery, interestCompoundedEveryPeriodType,
canRenew, canPreClose, preClosureInterestRate);
}
@Override
@@ -1601,9 +1612,11 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
Set<String> responseParameters, DepositProductData... products) {
Set<String> supportedParameters = new HashSet<String>(
Arrays.asList("id", "name", "description","createdOn", "lastModifedOn","currencyCode","digitsAfterDecimal",
"currencyOptions", "minimumBalance","maximumBalance","tenureInMonths","maturityDefaultInterestRate","maturityMinInterestRate",
"maturityMaxInterestRate","renewalAllowed","preClosureAllowed","preClosureInterestRate"));
Arrays.asList("currencyOptions", "interestCompoundedEveryPeriodTypeOptions",
"id", "externalId", "name", "description","createdOn", "lastModifedOn","currencyCode","digitsAfterDecimal",
"minimumBalance","maximumBalance","tenureInMonths","maturityDefaultInterestRate","maturityMinInterestRate",
"maturityMaxInterestRate", "interestCompoundedEvery", "interestCompoundedEveryPeriodType",
"renewalAllowed","preClosureAllowed","preClosureInterestRate"));
final Set<String> parameterNamesToSkip = new HashSet<String>();
@@ -6,21 +6,28 @@ import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import org.apache.commons.lang.StringUtils;
import org.mifosng.platform.api.commands.DepositProductCommand;
import org.mifosng.platform.currency.domain.MonetaryCurrency;
import org.mifosng.platform.exceptions.ValueOutsideRangeException;
import org.mifosng.platform.infrastructure.AbstractAuditableCustom;
import org.mifosng.platform.loan.domain.PeriodFrequencyType;
import org.mifosng.platform.user.domain.AppUser;
@Entity
@Table(name = "portfolio_product_deposit")
@Table(name = "portfolio_product_deposit", uniqueConstraints={
@UniqueConstraint(columnNames = {"name"}, name="name_deposit_product"),
@UniqueConstraint(columnNames = {"external_id"}, name="externalid_deposit_product")
})
public class DepositProduct extends AbstractAuditableCustom<AppUser, Long> {
@SuppressWarnings("unused")
@Column(name = "name", nullable = false)
private String name;
@Column(name = "external_id", length=100)
private String externalId;
@SuppressWarnings("unused")
@Column(name = "description")
@@ -39,8 +46,12 @@ public class DepositProduct extends AbstractAuditableCustom<AppUser, Long> {
private BigDecimal maximumBalance;
@SuppressWarnings("unused")
@Column(name = "tenure_months", nullable=false)
private Integer tenureInMonths;
@Column(name = "interest_compounded_every", nullable=false)
private Integer interestCompoundedEvery;
@SuppressWarnings("unused")
@Column(name = "interest_compounded_every_period_enum", nullable=false)
private PeriodFrequencyType interestCompoundedEveryPeriodType;
@SuppressWarnings("unused")
@Column(name = "maturity_default_interest_rate", scale = 6, precision = 19, nullable = false)
@@ -52,10 +63,14 @@ public class DepositProduct extends AbstractAuditableCustom<AppUser, Long> {
@Column(name = "maturity_max_interest_rate", scale = 6, precision = 19, nullable = false)
private BigDecimal maturityMaxInterestRate;
@Column(name = "can_renew", nullable=false)
@SuppressWarnings("unused")
@Column(name = "tenure_months", nullable=false)
private Integer tenureInMonths;
@Column(name = "is_renewal_allowed", nullable=false)
private boolean renewalAllowed = false;
@Column(name = "can_pre_close", nullable=false)
@Column(name = "is_preclosure_allowed", nullable=false)
private boolean preClosureAllowed = false;
@SuppressWarnings("unused")
@@ -66,19 +81,29 @@ public class DepositProduct extends AbstractAuditableCustom<AppUser, Long> {
//
}
public DepositProduct(final String name, final String description,
public DepositProduct(final String name, final String externalId,
final String description,
final MonetaryCurrency currency, final BigDecimal minimumBalance,
final BigDecimal maximumBalance, final Integer tenureMonths,
final BigDecimal maturityDefaultInterestRate,
final BigDecimal maturityMinInterestRate,
BigDecimal maturityMaxInterestRate, boolean canRenew,
boolean canPreClose, BigDecimal preClosureInterestRate) {
final BigDecimal maturityMaxInterestRate,
final Integer interestCompoundedEvery,
final PeriodFrequencyType interestCompoundedEveryPeriodType,
final boolean canRenew,
final boolean canPreClose,
final BigDecimal preClosureInterestRate) {
this.name = name.trim();
if (StringUtils.isNotBlank(description)) {
this.description = description.trim();
} else {
this.description = null;
}
if (StringUtils.isNotBlank(externalId)) {
this.externalId = externalId.trim();
} else {
this.externalId = null;
}
this.currency = currency;
this.minimumBalance = minimumBalance;
@@ -87,6 +112,8 @@ public class DepositProduct extends AbstractAuditableCustom<AppUser, Long> {
this.maturityDefaultInterestRate = maturityDefaultInterestRate;
this.maturityMinInterestRate = maturityMinInterestRate;
this.maturityMaxInterestRate = maturityMaxInterestRate;
this.interestCompoundedEvery = interestCompoundedEvery;
this.interestCompoundedEveryPeriodType = interestCompoundedEveryPeriodType;
this.renewalAllowed = canRenew;
this.preClosureAllowed = canPreClose;
this.preClosureInterestRate = preClosureInterestRate;
@@ -108,11 +135,22 @@ public class DepositProduct extends AbstractAuditableCustom<AppUser, Long> {
return deleted;
}
/**
* Delete is a <i>soft delete</i>. Updates flag on product so it wont appear in query/report results.
*
* Any fields with unique constraints and prepended with id of record.
*/
public void delete() {
this.deleted = true;
this.name = this.getId() + "_DELETED_" + this.name;
this.externalId = this.getId() + "_DELETED_" + this.externalId;
}
public void update(final DepositProductCommand command){
public void update(final DepositProductCommand command, final PeriodFrequencyType interestCompoundingFrequency){
if (command.isExternalIdChanged()) {
this.externalId = command.getExternalId();
}
if (command.isNameChanged()) {
this.name = command.getName();
@@ -160,6 +198,14 @@ public class DepositProduct extends AbstractAuditableCustom<AppUser, Long> {
this.maturityMinInterestRate=command.getMaturityMinInterestRate();
}
if (command.isInterestCompoundedEveryChanged()) {
this.interestCompoundedEvery = command.getInterestCompoundedEvery();
}
if (command.isInterestCompoundedEveryPeriodTypeChanged()) {
this.interestCompoundedEveryPeriodType = interestCompoundingFrequency;
}
if (command.isRenewalAllowedChanged()) {
this.renewalAllowed=command.isRenewalAllowed();
}
@@ -0,0 +1,31 @@
package org.mifosng.platform.deposit.domain;
import org.mifosng.platform.api.data.EnumOptionData;
import org.mifosng.platform.loan.domain.PeriodFrequencyType;
public class SavingsDepositEnumerations {
public static EnumOptionData interestCompoundingPeriodType(final int id) {
return interestCompoundingPeriodType(PeriodFrequencyType.fromInt(id));
}
public static EnumOptionData interestCompoundingPeriodType(final PeriodFrequencyType type) {
final String codePrefix = "deposit.interest.compounding.period.";
EnumOptionData optionData = null;
switch (type) {
case DAYS:
optionData = new EnumOptionData(PeriodFrequencyType.DAYS.getValue().longValue(), codePrefix + PeriodFrequencyType.DAYS.getCode(), "Days");
break;
case WEEKS:
optionData = new EnumOptionData(PeriodFrequencyType.WEEKS.getValue().longValue(), codePrefix + PeriodFrequencyType.WEEKS.getCode(), "Weeks");
break;
case MONTHS:
optionData = new EnumOptionData(PeriodFrequencyType.MONTHS.getValue().longValue(), codePrefix + PeriodFrequencyType.MONTHS.getCode(), "Months");
break;
default:
optionData = new EnumOptionData(PeriodFrequencyType.INVALID.getValue().longValue(), PeriodFrequencyType.INVALID.getCode(), "Invalid");
break;
}
return optionData;
}
}
@@ -21,6 +21,8 @@ public class DepositProductCommandValidator {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("deposit.product");
baseDataValidator.reset().parameter("externalId").value(command.getExternalId()).ignoreIfNull().notExceedingLengthOf(100);
baseDataValidator.reset().parameter("name").value(command.getName()).notBlank();
baseDataValidator.reset().parameter("description").value(command.getDescription()).notExceedingLengthOf(500);
baseDataValidator.reset().parameter("currencyCode").value(command.getCurrencyCode()).notBlank();
@@ -37,6 +39,9 @@ public class DepositProductCommandValidator {
baseDataValidator.reset().parameter("maturityDefaultInterestRate").comapareMinAndMaxOfTwoBigDecmimalNos(command.getMaturityDefaultInterestRate(), command.getMaturityMaxInterestRate());
baseDataValidator.reset().parameter("maturityMinInterestRate").comapareMinAndMaxOfTwoBigDecmimalNos(command.getMaturityMinInterestRate(), command.getMaturityDefaultInterestRate());
baseDataValidator.reset().parameter("interestCompoundedEvery").value(command.getInterestCompoundedEvery()).notNull().zeroOrPositiveAmount();
baseDataValidator.reset().parameter("interestCompoundedEveryPeriodType").value(command.getInterestCompoundedEveryPeriodType()).notNull().inMinMaxRange(1, 3);
baseDataValidator.reset().parameter("renewalAllowed").trueOrFalseRequired(command.isRenewalAllowedChanged());
baseDataValidator.reset().parameter("preClosureAllowed").trueOrFalseRequired(command.isPreClosureAllowedChanged());
@@ -54,6 +59,7 @@ public class DepositProductCommandValidator {
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("deposit.product");
baseDataValidator.reset().parameter("id").value(command.getId()).notNull();
baseDataValidator.reset().parameter("externalId").value(command.getExternalId()).ignoreIfNull().notExceedingLengthOf(100);
baseDataValidator.reset().parameter("name").value(command.getName()).ignoreIfNull().notBlank();
baseDataValidator.reset().parameter("description").value(command.getDescription()).ignoreIfNull().notExceedingLengthOf(500);
@@ -71,6 +77,9 @@ public class DepositProductCommandValidator {
baseDataValidator.reset().comapareMinAndMaxOfTwoBigDecmimalNos(command.getMaturityDefaultInterestRate(), command.getMaturityMaxInterestRate());
baseDataValidator.reset().comapareMinAndMaxOfTwoBigDecmimalNos(command.getMaturityMinInterestRate(), command.getMaturityDefaultInterestRate());
baseDataValidator.reset().parameter("interestCompoundedEvery").value(command.getInterestCompoundedEvery()).ignoreIfNull().zeroOrPositiveAmount();
baseDataValidator.reset().parameter("interestCompoundedEveryPeriodType").value(command.getInterestCompoundedEveryPeriodType()).ignoreIfNull().inMinMaxRange(1, 3);
baseDataValidator.reset().parameter("preClosureInterestRate").value(command.getPreClosureInterestRate()).ignoreIfNull().zeroOrPositiveAmount();
baseDataValidator.reset().comapareMinAndMaxOfTwoBigDecmimalNos(command.getPreClosureInterestRate(), command.getMaturityMinInterestRate());
@@ -3,6 +3,7 @@ package org.mifosng.platform.depositproduct.service;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@@ -10,9 +11,12 @@ import org.joda.time.DateTime;
import org.mifosng.platform.api.data.CurrencyData;
import org.mifosng.platform.api.data.DepositProductData;
import org.mifosng.platform.api.data.DepositProductLookup;
import org.mifosng.platform.api.data.EnumOptionData;
import org.mifosng.platform.currency.service.CurrencyReadPlatformService;
import org.mifosng.platform.deposit.domain.SavingsDepositEnumerations;
import org.mifosng.platform.infrastructure.JdbcSupport;
import org.mifosng.platform.infrastructure.TenantAwareRoutingDataSource;
import org.mifosng.platform.loan.domain.PeriodFrequencyType;
import org.mifosng.platform.security.PlatformSecurityContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -58,22 +62,30 @@ public class DepositProductReadPlatformServiceImpl implements
DepositProductData productData = this.jdbcTemplate.queryForObject(sql, depositProductMapper, new Object[]{productId});
List<CurrencyData> currencyOptions = currencyReadPlatformService.retrieveAllowedCurrencies();
return new DepositProductData(productData, currencyOptions);
EnumOptionData monthly = SavingsDepositEnumerations.interestCompoundingPeriodType(PeriodFrequencyType.MONTHS);
List<EnumOptionData> interestCompoundedEveryPeriodTypeOptions = Arrays.asList(monthly);
return new DepositProductData(productData, currencyOptions, interestCompoundedEveryPeriodTypeOptions);
}
@Override
public DepositProductData retrieveNewDepositProductDetails() {
List<CurrencyData> currencyOptions = currencyReadPlatformService.retrieveAllowedCurrencies();
return new DepositProductData(currencyOptions);
EnumOptionData monthly = SavingsDepositEnumerations.interestCompoundingPeriodType(PeriodFrequencyType.MONTHS);
List<EnumOptionData> interestCompoundedEveryPeriodTypeOptions = Arrays.asList(monthly);
return new DepositProductData(currencyOptions, monthly, interestCompoundedEveryPeriodTypeOptions);
}
private static final class DepositProductMapper implements RowMapper<DepositProductData>{
public String depositProductSchema(){
return "dp.id as id,dp.name as name, dp.description as description,dp.currency_code as currencyCode, dp.currency_digits as currencyDigits,dp.minimum_balance as minimumBalance,dp.maximum_balance as maximumBalance," +
"dp.created_date as createdon, dp.lastmodified_date as modifiedon,dp.tenure_months as tenureMonths, dp.maturity_default_interest_rate as maturityDefaultInterestRate, " +
"dp.maturity_min_interest_rate as maturityMinInterestRate, dp.maturity_max_interest_rate as maturityMaxInterestRate, dp.can_renew as canRenew, dp.can_pre_close as canPreClose, dp.pre_closure_interest_rate as preClosureInterestRate, " +
return " dp.id as id, dp.external_id as exernalId, dp.name as name, dp.description as description,dp.currency_code as currencyCode, dp.currency_digits as currencyDigits,dp.minimum_balance as minimumBalance,dp.maximum_balance as maximumBalance," +
"dp.created_date as createdon, dp.lastmodified_date as modifiedon,dp.tenure_months as tenureMonths, " +
"dp.interest_compounded_every as interestCompoundedEvery, dp.interest_compounded_every_period_enum as interestCompoundedEveryPeriodType, " +
"dp.maturity_default_interest_rate as maturityDefaultInterestRate, " +
"dp.maturity_min_interest_rate as maturityMinInterestRate, dp.maturity_max_interest_rate as maturityMaxInterestRate, dp.is_renewal_allowed as canRenew, dp.is_preclosure_allowed as canPreClose, dp.pre_closure_interest_rate as preClosureInterestRate, " +
"curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol " +
"from portfolio_product_deposit dp join ref_currency curr on curr.code = dp.currency_code ";
}
@@ -83,6 +95,7 @@ public class DepositProductReadPlatformServiceImpl implements
throws SQLException {
Long id = rs.getLong("id");
String exernalId = rs.getString("exernalId");
String name = rs.getString("name");
String description = rs.getString("description");
@@ -96,6 +109,10 @@ public class DepositProductReadPlatformServiceImpl implements
BigDecimal maximumBalance=rs.getBigDecimal("maximumBalance");
Integer tenureMonths = JdbcSupport.getInteger(rs, "tenureMonths");
Integer interestCompoundedEvery = JdbcSupport.getInteger(rs, "interestCompoundedEvery");
Integer interestCompoundedEveryPeriodTypeValue = JdbcSupport.getInteger(rs, "interestCompoundedEveryPeriodType");
EnumOptionData interestCompoundedEveryPeriodType = SavingsDepositEnumerations.interestCompoundingPeriodType(interestCompoundedEveryPeriodTypeValue);
BigDecimal maturityDefaultInterestRate=rs.getBigDecimal("maturityDefaultInterestRate");
BigDecimal maturityMinInterestRate= rs.getBigDecimal("maturityMinInterestRate");
BigDecimal maturityMaxInterestRate = rs.getBigDecimal("maturityMaxInterestRate");
@@ -105,8 +122,10 @@ public class DepositProductReadPlatformServiceImpl implements
BigDecimal preClosureInterestRate=rs.getBigDecimal("preClosureInterestRate");
return new DepositProductData(createdOn, lastModifedOn, id, name, description, currencyCode, currencyDigits, minimumBalance, maximumBalance,
tenureMonths, maturityDefaultInterestRate,maturityMinInterestRate,maturityMaxInterestRate,canRenew,canPreClose,preClosureInterestRate);
return new DepositProductData(createdOn, lastModifedOn, id, exernalId, name, description, currencyCode, currencyDigits, minimumBalance, maximumBalance,
tenureMonths, maturityDefaultInterestRate,maturityMinInterestRate,maturityMaxInterestRate,
interestCompoundedEvery, interestCompoundedEveryPeriodType,
canRenew,canPreClose,preClosureInterestRate);
}
}
@@ -6,65 +6,103 @@ import org.mifosng.platform.currency.domain.MonetaryCurrency;
import org.mifosng.platform.deposit.domain.DepositProduct;
import org.mifosng.platform.deposit.domain.DepositProductRepository;
import org.mifosng.platform.exceptions.DepositProductNotFoundException;
import org.mifosng.platform.exceptions.PlatformDataIntegrityException;
import org.mifosng.platform.loan.domain.PeriodFrequencyType;
import org.mifosng.platform.security.PlatformSecurityContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class DepositProductWritePlatformServiceJpaRepositoryImpl implements
DepositProductWritePlatformService {
public class DepositProductWritePlatformServiceJpaRepositoryImpl implements DepositProductWritePlatformService {
private final static Logger logger = LoggerFactory.getLogger(DepositProductWritePlatformServiceJpaRepositoryImpl.class);
private final PlatformSecurityContext context;
private final DepositProductRepository depositProductRepository;
@Autowired
public DepositProductWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final DepositProductRepository depositProductRepository){
this.context=context;
this.depositProductRepository=depositProductRepository;
}
@Transactional
@Override
public EntityIdentifier createDepositProduct(DepositProductCommand command) {
/*
* Guaranteed to throw an exception no matter what the data integrity issue is.
*/
private void handleDataIntegrityIssues(final DepositProductCommand command, final DataIntegrityViolationException dve) {
this.context.authenticatedUser();
DepositProductCommandValidator validator=new DepositProductCommandValidator(command);
validator.validateForCreate();
MonetaryCurrency currency = new MonetaryCurrency(command.getCurrencyCode(), command.getDigitsAfterDecimal());
DepositProduct product = new DepositProduct(command.getName(),command.getDescription(),currency,command.getMinimumBalance(),command.getMaximumBalance(),
command.getTenureInMonths(),command.getMaturityDefaultInterestRate(),command.getMaturityMinInterestRate(),command.getMaturityMaxInterestRate(),
command.isRenewalAllowed(), command.isPreClosureAllowed(),
command.getPreClosureInterestRate());
this.depositProductRepository.save(product);
return new EntityIdentifier(product.getId());
}
@Transactional
@Override
public EntityIdentifier updateDepositProduct(DepositProductCommand command) {
this.context.authenticatedUser();
DepositProductCommandValidator validator=new DepositProductCommandValidator(command);
validator.validateForUpdate();
DepositProduct product=this.depositProductRepository.findOne(command.getId());
if(product==null){
throw new DepositProductNotFoundException(command.getId());
Throwable realCause = dve.getMostSpecificCause();
if (realCause.getMessage().contains("name_deposit_product")) {
throw new PlatformDataIntegrityException("error.msg.desposit.product.duplicate.name", "Deposit product with name: " + command.getName() + " already exists", "name", command.getName());
}
if (realCause.getMessage().contains("externalid_deposit_product")) {
throw new PlatformDataIntegrityException("error.msg.desposit.product.duplicate.externalId", "Deposit product with externalId " + command.getExternalId() + " already exists", "externalId", command.getExternalId());
}
product.update(command);
this.depositProductRepository.save(product);
return new EntityIdentifier(Long.valueOf(product.getId()));
logger.error(dve.getMessage(), dve);
throw new PlatformDataIntegrityException("error.msg.deposit.product.unknown.data.integrity.issue", "Unknown data integrity issue with resource.");
}
@Transactional
@Override
public EntityIdentifier deleteDepositProduct(Long productId) {
public EntityIdentifier createDepositProduct(final DepositProductCommand command) {
try {
this.context.authenticatedUser();
DepositProductCommandValidator validator=new DepositProductCommandValidator(command);
validator.validateForCreate();
PeriodFrequencyType interestCompoundingPeriodType = PeriodFrequencyType.fromInt(command.getInterestCompoundedEveryPeriodType());
MonetaryCurrency currency = new MonetaryCurrency(command.getCurrencyCode(), command.getDigitsAfterDecimal());
DepositProduct product = new DepositProduct(command.getName(), command.getExternalId(), command.getDescription(),currency,command.getMinimumBalance(),command.getMaximumBalance(),
command.getTenureInMonths(),command.getMaturityDefaultInterestRate(),command.getMaturityMinInterestRate(),command.getMaturityMaxInterestRate(),
command.getInterestCompoundedEvery(), interestCompoundingPeriodType,
command.isRenewalAllowed(), command.isPreClosureAllowed(),
command.getPreClosureInterestRate());
this.depositProductRepository.save(product);
return new EntityIdentifier(product.getId());
} catch (DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve);
return new EntityIdentifier(Long.valueOf(-1));
}
}
@Transactional
@Override
public EntityIdentifier updateDepositProduct(final DepositProductCommand command) {
try {
this.context.authenticatedUser();
DepositProductCommandValidator validator=new DepositProductCommandValidator(command);
validator.validateForUpdate();
DepositProduct product=this.depositProductRepository.findOne(command.getId());
if(product==null){
throw new DepositProductNotFoundException(command.getId());
}
PeriodFrequencyType interestCompoundingFrequency = null;
if (command.isInterestCompoundedEveryPeriodTypeChanged()) {
interestCompoundingFrequency = PeriodFrequencyType.fromInt(command.getInterestCompoundedEveryPeriodType());
}
product.update(command, interestCompoundingFrequency);
this.depositProductRepository.save(product);
return new EntityIdentifier(Long.valueOf(product.getId()));
} catch (DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve);
return new EntityIdentifier(Long.valueOf(-1));
}
}
@Transactional
@Override
public EntityIdentifier deleteDepositProduct(final Long productId) {
this.context.authenticatedUser();
DepositProduct product=this.depositProductRepository.findOne(productId);