Merge pull request #773 from pramodn02/savings

MIFOSX-931 - added current account
This commit is contained in:
Vishwas Babu A J
2014-02-25 01:44:38 -08:00
41 changed files with 921 additions and 84 deletions
+14
View File
@@ -0,0 +1,14 @@
ALTER TABLE `m_savings_product`
ADD COLUMN `allow_overdraft` TINYINT(1) NOT NULL DEFAULT '0' AFTER `withdrawal_fee_for_transfer`,
ADD COLUMN `overdraft_limit` DECIMAL(19,6) NULL DEFAULT NULL AFTER `allow_overdraft`;
ALTER TABLE `m_savings_account`
ADD COLUMN `allow_overdraft` TINYINT(1) NOT NULL DEFAULT '0' AFTER `withdrawal_fee_for_transfer`,
ADD COLUMN `overdraft_limit` DECIMAL(19,6) NULL DEFAULT NULL AFTER `allow_overdraft`;
ALTER TABLE `m_savings_account_transaction`
ADD COLUMN `overdraft_amount_derived` DECIMAL(19,6) NULL DEFAULT NULL AFTER `amount`;
ALTER TABLE `m_client`
ADD COLUMN `default_savings_product` BIGINT(20) NULL DEFAULT NULL AFTER `closedon_userid`,
ADD CONSTRAINT `FK_m_client_m_savings_product` FOREIGN KEY (`default_savings_product`) REFERENCES `m_savings_product` (`id`);
@@ -133,7 +133,8 @@ public class AccountingConstants {
/*** Accounting placeholders for cash based accounting for savings products ***/
public static enum CASH_ACCOUNTS_FOR_SAVINGS {
SAVINGS_REFERENCE(1), SAVINGS_CONTROL(2), INTEREST_ON_SAVINGS(3), INCOME_FROM_FEES(4), INCOME_FROM_PENALTIES(5), TRANSFERS_SUSPENSE(
10);
10),OVERDRAFT_PORTFOLIO_CONTROL(11),INCOME_FROM_INTEREST(12),
LOSSES_WRITTEN_OFF(13);
private final Integer value;
@@ -173,7 +174,8 @@ public class AccountingConstants {
"interestOnSavingsAccountId"), PAYMENT_CHANNEL_FUND_SOURCE_MAPPING("paymentChannelToFundSourceMappings"), PAYMENT_TYPE(
"paymentTypeId"), FUND_SOURCE("fundSourceAccountId"), TRANSFERS_SUSPENSE("transfersInSuspenseAccountId"), FEE_INCOME_ACCOUNT_MAPPING(
"feeToIncomeAccountMappings"), PENALTY_INCOME_ACCOUNT_MAPPING("penaltyToIncomeAccountMappings"), CHARGE_ID("chargeId"), INCOME_ACCOUNT_ID(
"incomeAccountId");
"incomeAccountId"),OVERDRAFT_PORTFOLIO_CONTROL("overdraftPortfolioControlId"),INCOME_FROM_INTEREST("incomeFromInterestId"),
LOSSES_WRITTEN_OFF("writeOffAccountId");
private final String value;
@@ -196,7 +198,8 @@ public class AccountingConstants {
"incomeFromFeeAccount"), INCOME_FROM_PENALTIES("incomeFromPenaltyAccount"), INTEREST_ON_SAVINGS(
"interestOnSavingsAccount"), PAYMENT_TYPE("paymentType"), FUND_SOURCE("fundSourceAccount"),
TRANSFERS_SUSPENSE("transfersInSuspenseAccount"), PENALTY_INCOME_ACCOUNT_MAPPING("penaltyToIncomeAccountMappings"), CHARGE_ID("charge"), INCOME_ACCOUNT_ID(
"incomeAccount");
"incomeAccount"),OVERDRAFT_PORTFOLIO_CONTROL("overdraftPortfolioControl"),INCOME_FROM_INTEREST("incomeFromInterest"),
LOSSES_WRITTEN_OFF("writeOffAccount");
private final String value;
@@ -20,6 +20,7 @@ public class SavingsTransactionDTO {
private final SavingsAccountTransactionEnumData transactionType;
private final BigDecimal amount;
private final BigDecimal overdraftAmount;
/*** Boolean values determines if the transaction is reversed ***/
private final boolean reversed;
@@ -30,7 +31,7 @@ public class SavingsTransactionDTO {
public SavingsTransactionDTO(final Long officeId, final Long paymentTypeId, final String transactionId, final Date transactionDate,
final SavingsAccountTransactionEnumData transactionType, final BigDecimal amount, final boolean reversed,
final List<ChargePaymentDTO> feePayments, final List<ChargePaymentDTO> penaltyPayments) {
final List<ChargePaymentDTO> feePayments, final List<ChargePaymentDTO> penaltyPayments,final BigDecimal overdraftAmount) {
this.paymentTypeId = paymentTypeId;
this.transactionId = transactionId;
this.transactionDate = transactionDate;
@@ -40,6 +41,7 @@ public class SavingsTransactionDTO {
this.feePayments = feePayments;
this.penaltyPayments = penaltyPayments;
this.officeId = officeId;
this.overdraftAmount = overdraftAmount;
}
public Long getOfficeId() {
@@ -78,4 +80,13 @@ public class SavingsTransactionDTO {
return this.feePayments;
}
public BigDecimal getOverdraftAmount() {
return this.overdraftAmount;
}
public boolean isOverdraftTransaction(){
return this.overdraftAmount!=null && this.overdraftAmount.doubleValue() > 0;
}
}
@@ -150,6 +150,7 @@ public class AccountingProcessorHelper {
final BigDecimal amount = (BigDecimal) map.get("amount");
final boolean reversed = (Boolean) map.get("reversed");
final Long paymentTypeId = (Long) map.get("paymentTypeId");
final BigDecimal overdraftAmount = (BigDecimal) map.get("overdraftAmount");
final List<ChargePaymentDTO> feePayments = new ArrayList<ChargePaymentDTO>();
final List<ChargePaymentDTO> penaltyPayments = new ArrayList<ChargePaymentDTO>();
@@ -172,7 +173,7 @@ public class AccountingProcessorHelper {
}
final SavingsTransactionDTO transaction = new SavingsTransactionDTO(transactionOfficeId, paymentTypeId, transactionId,
transactionDate, transactionType, amount, reversed, feePayments, penaltyPayments);
transactionDate, transactionType, amount, reversed, feePayments, penaltyPayments,overdraftAmount);
newSavingsTransactions.add(transaction);
@@ -41,13 +41,35 @@ public class CashBasedAccountingProcessorForSavings implements AccountingProcess
final Long paymentTypeId = savingsTransactionDTO.getPaymentTypeId();
final boolean isReversal = savingsTransactionDTO.isReversed();
final BigDecimal amount = savingsTransactionDTO.getAmount();
final BigDecimal overdraftAmount = savingsTransactionDTO.getOverdraftAmount();
final List<ChargePaymentDTO> feePayments = savingsTransactionDTO.getFeePayments();
final List<ChargePaymentDTO> penaltyPayments = savingsTransactionDTO.getPenaltyPayments();
this.helper.checkForBranchClosures(latestGLClosure, transactionDate);
if (savingsTransactionDTO.getTransactionType().isWithdrawal() && savingsTransactionDTO.isOverdraftTransaction()) {
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE, savingsProductId,
paymentTypeId, savingsId, transactionId, transactionDate, overdraftAmount, isReversal);
if(amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) == 1){
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE, savingsProductId,
paymentTypeId, savingsId, transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal);
}
}
else if (savingsTransactionDTO.getTransactionType().isDeposit() && savingsTransactionDTO.isOverdraftTransaction()) {
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE, CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL, savingsProductId,
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
if(amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) == 1){
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL, savingsProductId,
paymentTypeId, savingsId, transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal);
}
}
/** Handle Deposits and reversals of deposits **/
if (savingsTransactionDTO.getTransactionType().isDeposit()) {
else if (savingsTransactionDTO.getTransactionType().isDeposit()) {
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL, savingsProductId,
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
@@ -98,7 +120,23 @@ public class CashBasedAccountingProcessorForSavings implements AccountingProcess
CASH_ACCOUNTS_FOR_SAVINGS.TRANSFERS_SUSPENSE, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL, savingsProductId,
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
}
/** overdraft **/
else if (savingsTransactionDTO.getTransactionType().isOverdraftInterest()) {
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE, CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_INTEREST, savingsProductId,
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
}
else if (savingsTransactionDTO.getTransactionType().isWrittenoff()) {
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
CASH_ACCOUNTS_FOR_SAVINGS.LOSSES_WRITTEN_OFF, CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL, savingsProductId,
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
}
else if (savingsTransactionDTO.getTransactionType().isOverdraftFee()) {
this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE, CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_FEES, savingsProductId,
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, feePayments);
}
}
}
}
@@ -186,6 +186,21 @@ public final class ProductToGLAccountMappingFromApiJsonDeserializer {
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue())
.value(incomeFromPenaltyId).notNull().integerGreaterThanZero();
final Long overdraftAccount = this.fromApiJsonHelper.extractLongNamed(
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), element);
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.OVERDRAFT_PORTFOLIO_CONTROL.getValue())
.value(overdraftAccount).notNull().integerGreaterThanZero();
final Long incomeFromInterest = this.fromApiJsonHelper.extractLongNamed(
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_INTEREST.getValue(), element);
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_INTEREST.getValue())
.value(incomeFromInterest).notNull().integerGreaterThanZero();
final Long writtenOff = this.fromApiJsonHelper.extractLongNamed(
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), element);
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue())
.value(writtenOff).notNull().integerGreaterThanZero();
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
@@ -204,6 +204,12 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_DATA_PARAMS.TRANSFERS_SUSPENSE.getValue(), gLAccountData);
} else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.INTEREST_ON_SAVINGS)) {
accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_DATA_PARAMS.INTEREST_ON_SAVINGS.getValue(), gLAccountData);
} else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL)) {
accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_DATA_PARAMS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), gLAccountData);
}else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.LOSSES_WRITTEN_OFF)) {
accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_DATA_PARAMS.LOSSES_WRITTEN_OFF.getValue(), gLAccountData);
}else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_INTEREST)) {
accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_DATA_PARAMS.INCOME_FROM_INTEREST.getValue(), gLAccountData);
}
}
}
@@ -158,6 +158,9 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
this.savingsProductToGLAccountMappingHelper.saveSavingsToAssetAccountMapping(element,
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue(), savingProductId,
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue());
this.savingsProductToGLAccountMappingHelper.saveSavingsToAssetAccountMapping(element,
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingProductId,
CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL.getValue());
// income
this.savingsProductToGLAccountMappingHelper.saveSavingsToIncomeAccountMapping(element,
@@ -167,11 +170,20 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
this.savingsProductToGLAccountMappingHelper.saveSavingsToIncomeAccountMapping(element,
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), savingProductId,
CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_PENALTIES.getValue());
this.savingsProductToGLAccountMappingHelper.saveSavingsToIncomeAccountMapping(element,
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_INTEREST.getValue(), savingProductId,
CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_INTEREST.getValue());
// expenses
this.savingsProductToGLAccountMappingHelper.saveSavingsToExpenseAccountMapping(element,
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), savingProductId,
CASH_ACCOUNTS_FOR_SAVINGS.INTEREST_ON_SAVINGS.getValue());
this.savingsProductToGLAccountMappingHelper.saveSavingsToExpenseAccountMapping(element,
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), savingProductId,
CASH_ACCOUNTS_FOR_SAVINGS.LOSSES_WRITTEN_OFF.getValue());
// liability
this.savingsProductToGLAccountMappingHelper.saveSavingsToLiabilityAccountMapping(element,
@@ -124,7 +124,12 @@ public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMa
element);
final Long transfersInSuspenseAccountId = this.fromApiJsonHelper.extractLongNamed(
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), element);
final Long overdraftControlId = this.fromApiJsonHelper.extractLongNamed(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
element);
final Long incomeFromInterest = this.fromApiJsonHelper.extractLongNamed(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_INTEREST.getValue(),
element);
final Long writeOffId = this.fromApiJsonHelper.extractLongNamed(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(),
element);
switch (accountingRuleType) {
case NONE:
break;
@@ -135,6 +140,9 @@ public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMa
changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), incomeFromFeesId);
changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), incomeFromPenaltiesId);
changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), transfersInSuspenseAccountId);
changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), overdraftControlId);
changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_INTEREST.getValue(), incomeFromInterest);
changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), writeOffId);
break;
case ACCRUAL_BASED:
break;
@@ -161,6 +169,10 @@ public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMa
mergeSavingsToAssetAccountMappingChanges(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue(),
savingsProductId, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue(),
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.toString(), changes);
mergeSavingsToAssetAccountMappingChanges(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
savingsProductId, CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL.toString(), changes);
// income
mergeSavingsToIncomeAccountMappingChanges(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(),
@@ -171,10 +183,17 @@ public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMa
savingsProductId, CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_PENALTIES.getValue(),
CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_PENALTIES.toString(), changes);
mergeSavingsToIncomeAccountMappingChanges(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_INTEREST.getValue(),
savingsProductId, CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_INTEREST.getValue(),
CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_INTEREST.toString(), changes);
// expenses
mergeSavingsToExpenseAccountMappingChanges(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(),
savingsProductId, CASH_ACCOUNTS_FOR_SAVINGS.INTEREST_ON_SAVINGS.getValue(),
CASH_ACCOUNTS_FOR_SAVINGS.INTEREST_ON_SAVINGS.toString(), changes);
mergeSavingsToExpenseAccountMappingChanges(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(),
savingsProductId, CASH_ACCOUNTS_FOR_SAVINGS.LOSSES_WRITTEN_OFF.getValue(),
CASH_ACCOUNTS_FOR_SAVINGS.LOSSES_WRITTEN_OFF.toString(), changes);
// liability
mergeSavingsToLiabilityAccountMappingChanges(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(),
@@ -18,7 +18,8 @@ public enum ChargeTimeType {
ANNUAL_FEE(6, "chargeTimeType.annualFee"), // only for savings
MONTHLY_FEE(7, "chargeTimeType.monthlyFee"), // only for savings
INSTALMENT_FEE(8, "chargeTimeType.instalmentFee"),// only for loan charges
OVERDUE_INSTALLMENT(9, "chargeTimeType.overdueInstallment"); // only for loan charges
OVERDUE_INSTALLMENT(9, "chargeTimeType.overdueInstallment"), // only for loan charges
OVERDRAFT_FEE(10,"chargeTimeType.overdraftFee");// only for savings
private final Integer value;
private final String code;
@@ -44,7 +45,7 @@ public enum ChargeTimeType {
public static Object[] validSavingsValues() {
return new Integer[] { ChargeTimeType.SPECIFIED_DUE_DATE.getValue(), ChargeTimeType.SAVINGS_ACTIVATION.getValue(),
ChargeTimeType.SAVINGS_CLOSURE.getValue(), ChargeTimeType.WITHDRAWAL_FEE.getValue(), ChargeTimeType.ANNUAL_FEE.getValue(),
ChargeTimeType.MONTHLY_FEE.getValue() };
ChargeTimeType.MONTHLY_FEE.getValue(),ChargeTimeType.OVERDRAFT_FEE.getValue() };
}
public static ChargeTimeType fromInt(final Integer chargeTime) {
@@ -78,6 +79,9 @@ public enum ChargeTimeType {
case 9:
chargeTimeType = OVERDUE_INSTALLMENT;
break;
case 10:
chargeTimeType = OVERDRAFT_FEE;
break;
default:
chargeTimeType = INVALID;
break;
@@ -128,6 +132,12 @@ public enum ChargeTimeType {
public boolean isAllowedSavingsChargeTime() {
return isOnSpecifiedDueDate() || isSavingsActivation() || isSavingsClosure() || isWithdrawalFee() || isAnnualFee()
|| isMonthlyFee();
|| isMonthlyFee() || isOverdraftFee();
}
public boolean isOverdraftFee() {
return this.value.equals(ChargeTimeType.OVERDRAFT_FEE.getValue());
}
}
@@ -81,6 +81,7 @@ public class ChargeDropdownReadPlatformServiceImpl implements ChargeDropdownRead
return Arrays.asList(chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE), chargeTimeType(ChargeTimeType.SAVINGS_ACTIVATION),
//chargeTimeType(ChargeTimeType.SAVINGS_CLOSURE),
chargeTimeType(ChargeTimeType.WITHDRAWAL_FEE),
chargeTimeType(ChargeTimeType.ANNUAL_FEE), chargeTimeType(ChargeTimeType.MONTHLY_FEE));
chargeTimeType(ChargeTimeType.ANNUAL_FEE), chargeTimeType(ChargeTimeType.MONTHLY_FEE),
chargeTimeType(ChargeTimeType.OVERDRAFT_FEE));
}
}
@@ -49,6 +49,9 @@ public class ChargeEnumerations {
case OVERDUE_INSTALLMENT:
optionData = new EnumOptionData(ChargeTimeType.OVERDUE_INSTALLMENT.getValue().longValue(),ChargeTimeType.OVERDUE_INSTALLMENT.getCode(),"overdue fees") ;
break;
case OVERDRAFT_FEE:
optionData = new EnumOptionData(ChargeTimeType.OVERDRAFT_FEE.getValue().longValue(), ChargeTimeType.OVERDRAFT_FEE.getCode(), "Overdraft Fee");
break;
default:
optionData = new EnumOptionData(ChargeTimeType.INVALID.getValue().longValue(), ChargeTimeType.INVALID.getCode(), "Invalid");
break;
@@ -38,6 +38,7 @@ public class ClientApiConstants {
public static final String closureDateParamName = "closureDate";
public static final String closureReasonIdParamName = "closureReasonId";
public static final String submittedOnDateParamName="submittedOnDate";
public static final String savingsProductIdParamName="savingsProductId";
// response parameters
public static final String statusParamName = "status";
public static final String hierarchyParamName = "hierarchy";
@@ -62,11 +63,11 @@ public class ClientApiConstants {
public static final Set<String> CLIENT_CREATE_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
dateFormatParamName, groupIdParamName, accountNoParamName, externalIdParamName, mobileNoParamName, firstnameParamName,
middlenameParamName, lastnameParamName, fullnameParamName, officeIdParamName, activeParamName, activationDateParamName,
staffIdParamName,submittedOnDateParamName));
staffIdParamName,submittedOnDateParamName,savingsProductIdParamName));
public static final Set<String> CLIENT_UPDATE_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
dateFormatParamName, accountNoParamName, externalIdParamName, mobileNoParamName, firstnameParamName, middlenameParamName,
lastnameParamName, fullnameParamName, activeParamName, activationDateParamName, staffIdParamName));
lastnameParamName, fullnameParamName, activeParamName, activationDateParamName, staffIdParamName,savingsProductIdParamName));
/**
* These parameters will match the class level parameters of
@@ -17,6 +17,7 @@ import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.organisation.office.data.OfficeData;
import org.mifosplatform.organisation.staff.data.StaffData;
import org.mifosplatform.portfolio.group.data.GroupGeneralData;
import org.mifosplatform.portfolio.savings.data.SavingsProductData;
/**
* Immutable data object representing client data.
@@ -49,6 +50,9 @@ final public class ClientData implements Comparable<ClientData> {
private final Long staffId;
private final String staffName;
private final ClientTimelineData timeline;
private final Long savingsProductId;
private final String savingsProductName;
// associations
private final Collection<GroupGeneralData> groups;
@@ -58,11 +62,13 @@ final public class ClientData implements Comparable<ClientData> {
private final Collection<StaffData> staffOptions;
@SuppressWarnings("unused")
private final Collection<CodeValueData> closureReasons;
private final Collection<SavingsProductData> savingProductOptions;
public static ClientData template(final Long officeId, final LocalDate joinedDate, final Collection<OfficeData> officeOptions,
final Collection<StaffData> staffOptions, final Collection<CodeValueData> closureReasons) {
final Collection<StaffData> staffOptions, final Collection<CodeValueData> closureReasons,
final Collection<SavingsProductData> savingProductOptions) {
return new ClientData(null, null, officeId, null, null, null, null, null, null, null, null, null, null, null, joinedDate, null,
null, null, officeOptions, null, staffOptions, closureReasons,null);
null, null, officeOptions, null, staffOptions, closureReasons,null, savingProductOptions,null,null);
}
@@ -72,7 +78,8 @@ final public class ClientData implements Comparable<ClientData> {
clientData.transferToOfficeId, clientData.transferToOfficeName, clientData.id, clientData.firstname, clientData.middlename,
clientData.lastname, clientData.fullname, clientData.displayName, clientData.externalId, clientData.mobileNo,
clientData.activationDate, clientData.imageId, clientData.staffId, clientData.staffName, templateData.officeOptions,
clientData.groups, templateData.staffOptions, null,null);
clientData.groups, templateData.staffOptions, null,null, templateData.savingProductOptions,
clientData.savingsProductId, clientData.savingsProductName);
}
@@ -81,7 +88,8 @@ final public class ClientData implements Comparable<ClientData> {
clientData.transferToOfficeId, clientData.transferToOfficeName, clientData.id, clientData.firstname, clientData.middlename,
clientData.lastname, clientData.fullname, clientData.displayName, clientData.externalId, clientData.mobileNo,
clientData.activationDate, clientData.imageId, clientData.staffId, clientData.staffName, clientData.officeOptions,
parentGroups, clientData.staffOptions, null,clientData.timeline);
parentGroups, clientData.staffOptions, null,clientData.timeline, clientData.savingProductOptions,
clientData.savingsProductId, clientData.savingsProductName);
}
@@ -90,31 +98,34 @@ final public class ClientData implements Comparable<ClientData> {
final String officeName) {
return new ClientData(accountNo, status, officeId, officeName, null, null, id, firstname, middlename, lastname, fullname,
displayName, null, null, null, null, null, null, null, null, null, null,null);
displayName, null, null, null, null, null, null, null, null, null, null,null, null,null,null);
}
public static ClientData lookup(final Long id, final String displayName, final Long officeId, final String officeName) {
return new ClientData(null, null, officeId, officeName, null, null, id, null, null, null, null, displayName, null, null, null,
null, null, null, null, null, null, null,null);
null, null, null, null, null, null, null,null, null,null,null);
}
public static ClientData instance(final String accountNo, final EnumOptionData status, final Long officeId, final String officeName,
final Long transferToOfficeId, final String transferToOfficeName, final Long id, final String firstname,
final String middlename, final String lastname, final String fullname, final String displayName, final String externalId,
final String mobileNo, final LocalDate activationDate, final Long imageId, final Long staffId, final String staffName,final ClientTimelineData timeline) {
final String mobileNo, final LocalDate activationDate, final Long imageId, final Long staffId, final String staffName,
final ClientTimelineData timeline,final Long savingsProductId,final String savingsProductName) {
return new ClientData(accountNo, status, officeId, officeName, transferToOfficeId, transferToOfficeName, id, firstname, middlename,
lastname, fullname, displayName, externalId, mobileNo, activationDate, imageId, staffId, staffName, null, null, null, null,timeline);
lastname, fullname, displayName, externalId, mobileNo, activationDate, imageId, staffId, staffName, null, null, null, null,
timeline, null,savingsProductId,savingsProductName);
}
private ClientData(final String accountNo, final EnumOptionData status, final Long officeId, final String officeName,
final Long transferToOfficeId, final String transferToOfficeName, final Long id, final String firstname,
final String middlename, final String lastname, final String fullname, final String displayName, final String externalId,
final String mobileNo, final LocalDate activationDate, final Long imageId, final Long staffId, final String staffName,
final Collection<OfficeData> allowedOffices, final Collection<GroupGeneralData> groups,
final Collection<StaffData> staffOptions, final Collection<CodeValueData> closureReasons,final ClientTimelineData timeline) {
final Collection<StaffData> staffOptions, final Collection<CodeValueData> closureReasons,final ClientTimelineData timeline,
final Collection<SavingsProductData> savingProductOptions,final Long savingsProductId, final String savingsProductName) {
this.accountNo = accountNo;
this.status = status;
if (status != null) {
@@ -153,6 +164,9 @@ final public class ClientData implements Comparable<ClientData> {
this.closureReasons = closureReasons;
this.timeline = timeline;
this.savingProductOptions = savingProductOptions;
this.savingsProductId = savingsProductId;
this.savingsProductName = savingsProductName;
}
public Long id() {
@@ -68,6 +68,11 @@ public final class ClientDataValidator {
final String accountNo = this.fromApiJsonHelper.extractStringNamed(ClientApiConstants.accountNoParamName, element);
baseDataValidator.reset().parameter(ClientApiConstants.accountNoParamName).value(accountNo).notBlank().notExceedingLengthOf(20);
}
if (this.fromApiJsonHelper.parameterExists(ClientApiConstants.savingsProductIdParamName, element)) {
final Long savingsProductId = this.fromApiJsonHelper.extractLongNamed(ClientApiConstants.savingsProductIdParamName, element);
baseDataValidator.reset().parameter(ClientApiConstants.savingsProductIdParamName).value(savingsProductId).ignoreIfNull().longGreaterThanZero();
}
if (isFullnameProvided(element) || isIndividualNameProvided(element)) {
@@ -305,6 +310,11 @@ public final class ClientDataValidator {
final Long staffId = this.fromApiJsonHelper.extractLongNamed(ClientApiConstants.staffIdParamName, element);
baseDataValidator.reset().parameter(ClientApiConstants.staffIdParamName).value(staffId).ignoreIfNull().longGreaterThanZero();
}
if (this.fromApiJsonHelper.parameterExists(ClientApiConstants.savingsProductIdParamName, element)) {
final Long savingsProductId = this.fromApiJsonHelper.extractLongNamed(ClientApiConstants.savingsProductIdParamName, element);
baseDataValidator.reset().parameter(ClientApiConstants.savingsProductIdParamName).value(savingsProductId).ignoreIfNull().longGreaterThanZero();
}
if (!atLeastOneParameterPassedForUpdate) {
final Object forceError = null;
@@ -45,6 +45,7 @@ import org.mifosplatform.organisation.office.domain.Office;
import org.mifosplatform.organisation.staff.domain.Staff;
import org.mifosplatform.portfolio.client.api.ClientApiConstants;
import org.mifosplatform.portfolio.group.domain.Group;
import org.mifosplatform.portfolio.savings.domain.SavingsProduct;
import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.data.jpa.domain.AbstractPersistable;
@@ -138,9 +139,13 @@ public final class Client extends AbstractPersistable<Long> {
@ManyToOne(optional = true)
@JoinColumn(name = "activatedon_userid", nullable = true)
private AppUser activatedBy;
@ManyToOne
@JoinColumn(name = "default_savings_product", nullable = true)
private SavingsProduct savingsProduct;
public static Client createNew(final AppUser currentUser, final Office clientOffice, final Group clientParentGroup, final Staff staff,
final JsonCommand command) {
final SavingsProduct savingsProduct, final JsonCommand command) {
final String accountNo = command.stringValueOfParameterNamed(ClientApiConstants.accountNoParamName);
final String externalId = command.stringValueOfParameterNamed(ClientApiConstants.externalIdParamName);
@@ -174,7 +179,7 @@ public final class Client extends AbstractPersistable<Long> {
}
return new Client(currentUser, status, clientOffice, clientParentGroup, accountNo, firstname, middlename, lastname, fullname,
activationDate, officeJoiningDate, externalId, mobileNo, staff, submittedOnDate);
activationDate, officeJoiningDate, externalId, mobileNo, staff, submittedOnDate,savingsProduct);
}
protected Client() {
@@ -184,7 +189,7 @@ public final class Client extends AbstractPersistable<Long> {
private Client(final AppUser currentUser, final ClientStatus status, final Office office, final Group clientParentGroup,
final String accountNo, final String firstname, final String middlename, final String lastname, final String fullname,
final LocalDate activationDate, final LocalDate officeJoiningDate, final String externalId, final String mobileNo,
final Staff staff, final LocalDate submittedOnDate) {
final Staff staff, final LocalDate submittedOnDate, final SavingsProduct savingsProduct) {
if (StringUtils.isBlank(accountNo)) {
this.accountNumber = new RandomPasswordGenerator(19).generate();
@@ -247,6 +252,7 @@ public final class Client extends AbstractPersistable<Long> {
}
this.staff = staff;
this.savingsProduct = savingsProduct;
deriveDisplayName();
validate();
@@ -394,6 +400,11 @@ public final class Client extends AbstractPersistable<Long> {
actualChanges.put(ClientApiConstants.staffIdParamName, newValue);
}
if (command.isChangeInLongParameterNamed(ClientApiConstants.savingsProductIdParamName, savingsProductId())) {
final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.savingsProductIdParamName);
actualChanges.put(ClientApiConstants.savingsProductIdParamName, newValue);
}
final String dateFormatAsInput = command.dateFormat();
final String localeAsInput = command.locale();
@@ -628,4 +639,28 @@ public final class Client extends AbstractPersistable<Long> {
}
return false;
}
private Long savingsProductId() {
Long savingsProductId = null;
if (this.savingsProduct != null) {
savingsProductId = this.savingsProduct.getId();
}
return savingsProductId;
}
public SavingsProduct SavingsProduct() {
return this.savingsProduct;
}
public void updateSavingsProduct(SavingsProduct savingsProduct) {
this.savingsProduct = savingsProduct;
}
public AppUser activatedBy() {
return this.activatedBy;
}
}
@@ -0,0 +1,11 @@
package org.mifosplatform.portfolio.client.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class ClientActiveForUpdateException extends AbstractPlatformDomainRuleException {
public ClientActiveForUpdateException(final Long clientId,final String parameterName) {
super("error.msg.client.active.for.update.parameter."+parameterName, "The Client with id `" + clientId + "` is active,can't update parameter "+parameterName, clientId,parameterName);
}
}
@@ -0,0 +1,21 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.client.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
/**
* {@link AbstractPlatformDomainRuleException} thrown an action to transition a
* loan from one state to another violates a domain rule.
*/
public class InvalidClientSavingProductException extends AbstractPlatformDomainRuleException {
public InvalidClientSavingProductException(final String action, final String postFix, final String defaultUserMessage,
final Object... defaultUserMessageArgs) {
super("error.msg.client." + action + "." + postFix, defaultUserMessage, defaultUserMessageArgs);
}
}
@@ -33,6 +33,8 @@ import org.mifosplatform.portfolio.client.domain.ClientStatus;
import org.mifosplatform.portfolio.client.exception.ClientNotFoundException;
import org.mifosplatform.portfolio.group.data.GroupGeneralData;
import org.mifosplatform.portfolio.group.service.SearchParameters;
import org.mifosplatform.portfolio.savings.data.SavingsProductData;
import org.mifosplatform.portfolio.savings.service.SavingsProductReadPlatformService;
import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
@@ -49,6 +51,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
private final OfficeReadPlatformService officeReadPlatformService;
private final StaffReadPlatformService staffReadPlatformService;
private final CodeValueReadPlatformService codeValueReadPlatformService;
private final SavingsProductReadPlatformService savingsProductReadPlatformService;
// data mappers
private final PaginationHelper<ClientData> paginationHelper = new PaginationHelper<ClientData>();
private final ClientMapper clientMapper = new ClientMapper();
@@ -59,12 +62,14 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
@Autowired
public ClientReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
final OfficeReadPlatformService officeReadPlatformService, final StaffReadPlatformService staffReadPlatformService,
final CodeValueReadPlatformService codeValueReadPlatformService) {
final CodeValueReadPlatformService codeValueReadPlatformService,
final SavingsProductReadPlatformService savingsProductReadPlatformService) {
this.context = context;
this.officeReadPlatformService = officeReadPlatformService;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.staffReadPlatformService = staffReadPlatformService;
this.codeValueReadPlatformService = codeValueReadPlatformService;
this.savingsProductReadPlatformService = savingsProductReadPlatformService;
}
@Override
@@ -74,6 +79,9 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final Long defaultOfficeId = defaultToUsersOfficeIfNull(officeId);
final Collection<OfficeData> offices = this.officeReadPlatformService.retrieveAllOfficesForDropdown();
final Collection<SavingsProductData> savingsProductDatas = this.savingsProductReadPlatformService.retrieveAllForLookupByType(true);
Collection<StaffData> staffOptions = null;
@@ -88,7 +96,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
staffOptions = null;
}
return ClientData.template(defaultOfficeId, new LocalDate(), offices, staffOptions, null);
return ClientData.template(defaultOfficeId, new LocalDate(), offices, staffOptions, null,savingsProductDatas);
}
@Override
@@ -265,6 +273,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
sqlBuilder.append("c.mobile_no as mobileNo, ");
sqlBuilder.append("c.activation_date as activationDate, c.image_id as imageId, ");
sqlBuilder.append("c.staff_id as staffId, s.display_name as staffName,");
sqlBuilder.append("c.default_savings_product as savingsProductId, sp.name as savingsProductName, ");
sqlBuilder.append("c.submittedon_date as submittedOnDate, ");
sqlBuilder.append("sbu.username as submittedByUsername, ");
@@ -284,6 +293,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
sqlBuilder.append("join m_office o on o.id = c.office_id ");
sqlBuilder.append("join m_group_client pgc on pgc.client_id = c.id ");
sqlBuilder.append("left join m_staff s on s.id = c.staff_id ");
sqlBuilder.append("left join m_savings_product sp on sp.id = c.default_savings_product ");
sqlBuilder.append("left join m_office transferToOffice on transferToOffice.id = c.transfer_to_office_id ");
sqlBuilder.append("left join m_appuser sbu on sbu.id = c.submittedon_userid ");
@@ -324,6 +334,10 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final Long imageId = JdbcSupport.getLong(rs, "imageId");
final Long staffId = JdbcSupport.getLong(rs, "staffId");
final String staffName = rs.getString("staffName");
final Long savingsProductId = JdbcSupport.getLong(rs, "savingsProductId");
final String savingsProductName = rs.getString("savingsProductName");
final LocalDate closedOnDate = JdbcSupport.getLocalDate(rs, "closedOnDate");
final String closedByUsername = rs.getString("closedByUsername");
@@ -345,7 +359,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
closedByFirstname, closedByLastname);
return ClientData.instance(accountNo, status, officeId, officeName, transferToOfficeId, transferToOfficeName, id, firstname,
middlename, lastname, fullname, displayName, externalId, mobileNo, activationDate, imageId, staffId, staffName,timeline);
middlename, lastname, fullname, displayName, externalId, mobileNo, activationDate, imageId, staffId, staffName,timeline,
savingsProductId, savingsProductName);
}
}
@@ -397,10 +412,12 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
builder.append("c.activation_date as activationDate, c.image_id as imageId, ");
builder.append("c.staff_id as staffId, s.display_name as staffName ");
builder.append("c.staff_id as staffId, s.display_name as staffName, ");
builder.append("c.default_savings_product as savingsProductId, sp.name as savingsProductName ");
builder.append("from m_client c ");
builder.append("join m_office o on o.id = c.office_id ");
builder.append("left join m_staff s on s.id = c.staff_id ");
builder.append("left join m_savings_product sp on sp.id = c.default_savings_product ");
builder.append("left join m_office transferToOffice on transferToOffice.id = c.transfer_to_office_id ");
builder.append("left join m_appuser sbu on sbu.id = c.submittedon_userid ");
builder.append("left join m_appuser acu on acu.id = c.activatedon_userid ");
@@ -440,6 +457,10 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final Long staffId = JdbcSupport.getLong(rs, "staffId");
final String staffName = rs.getString("staffName");
final Long savingsProductId = JdbcSupport.getLong(rs, "savingsProductId");
final String savingsProductName = rs.getString("savingsProductName");
final LocalDate closedOnDate = JdbcSupport.getLocalDate(rs, "closedOnDate");
final String closedByUsername = rs.getString("closedByUsername");
final String closedByFirstname = rs.getString("closedByFirstname");
@@ -459,7 +480,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
closedByFirstname, closedByLastname);
return ClientData.instance(accountNo, status, officeId, officeName, transferToOfficeId, transferToOfficeName, id, firstname,
middlename, lastname, fullname, displayName, externalId, mobileNo, activationDate, imageId, staffId, staffName,timeline);
middlename, lastname, fullname, displayName, externalId, mobileNo, activationDate, imageId, staffId, staffName,timeline,
savingsProductId, savingsProductName);
}
}
@@ -571,7 +593,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
public ClientData retrieveAllClosureReasons(final String clientClosureReason) {
final List<CodeValueData> closureReasons = new ArrayList<CodeValueData>(
this.codeValueReadPlatformService.retrieveCodeValuesByCode(clientClosureReason));
return ClientData.template(null, null, null, null, closureReasons);
return ClientData.template(null, null, null, null, closureReasons,null);
}
}
@@ -32,8 +32,10 @@ import org.mifosplatform.portfolio.client.domain.AccountNumberGeneratorFactory;
import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper;
import org.mifosplatform.portfolio.client.domain.ClientStatus;
import org.mifosplatform.portfolio.client.exception.ClientActiveForUpdateException;
import org.mifosplatform.portfolio.client.exception.ClientHasNoStaffException;
import org.mifosplatform.portfolio.client.exception.ClientMustBePendingToBeDeletedException;
import org.mifosplatform.portfolio.client.exception.InvalidClientSavingProductException;
import org.mifosplatform.portfolio.client.exception.InvalidClientStateTransitionException;
import org.mifosplatform.portfolio.group.domain.Group;
import org.mifosplatform.portfolio.group.domain.GroupRepository;
@@ -42,8 +44,13 @@ import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
import org.mifosplatform.portfolio.note.domain.Note;
import org.mifosplatform.portfolio.note.domain.NoteRepository;
import org.mifosplatform.portfolio.savings.data.SavingsAccountDataDTO;
import org.mifosplatform.portfolio.savings.domain.SavingsAccount;
import org.mifosplatform.portfolio.savings.domain.SavingsAccountRepository;
import org.mifosplatform.portfolio.savings.domain.SavingsProduct;
import org.mifosplatform.portfolio.savings.domain.SavingsProductRepository;
import org.mifosplatform.portfolio.savings.exception.SavingsProductNotFoundException;
import org.mifosplatform.portfolio.savings.service.SavingsApplicationProcessWritePlatformService;
import org.mifosplatform.useradministration.domain.AppUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -68,6 +75,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
private final CodeValueRepositoryWrapper codeValueRepository;
private final LoanRepository loanRepository;
private final SavingsAccountRepository savingsRepository;
private final SavingsProductRepository savingsProductRepository;
private final SavingsApplicationProcessWritePlatformService savingsApplicationProcessWritePlatformService;
@Autowired
public ClientWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -75,7 +84,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
final ClientDataValidator fromApiJsonDeserializer, final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory,
final GroupRepository groupRepository, final StaffRepositoryWrapper staffRepository,
final CodeValueRepositoryWrapper codeValueRepository, final LoanRepository loanRepository,
final SavingsAccountRepository savingsRepository) {
final SavingsAccountRepository savingsRepository,final SavingsProductRepository savingsProductRepository,
final SavingsApplicationProcessWritePlatformService savingsApplicationProcessWritePlatformService) {
this.context = context;
this.clientRepository = clientRepository;
this.officeRepository = officeRepository;
@@ -87,6 +97,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
this.codeValueRepository = codeValueRepository;
this.loanRepository = loanRepository;
this.savingsRepository = savingsRepository;
this.savingsProductRepository = savingsProductRepository;
this.savingsApplicationProcessWritePlatformService = savingsApplicationProcessWritePlatformService;
}
@Transactional
@@ -163,8 +175,16 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
if (staffId != null) {
staff = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(staffId, clientOffice.getHierarchy());
}
SavingsProduct savingsProduct = null;
final Long savingsProductId = command.longValueOfParameterNamed(ClientApiConstants.savingsProductIdParamName);
if(savingsProductId != null){
savingsProduct = this.savingsProductRepository.findOne(savingsProductId);
if (savingsProduct == null) { throw new SavingsProductNotFoundException(savingsProductId); }
final Client newClient = Client.createNew(currentUser,clientOffice, clientParentGroup, staff, command);
}
final Client newClient = Client.createNew(currentUser,clientOffice, clientParentGroup, staff, savingsProduct, command);
this.clientRepository.save(newClient);
@@ -174,6 +194,10 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
newClient.updateAccountNo(accountNoGenerator.generate());
this.clientRepository.save(newClient);
}
final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
Long savingsId = openOverdraftSavingsAccount(newClient, fmt);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
@@ -181,6 +205,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
.withClientId(newClient.getId()) //
.withGroupId(groupId) //
.withEntityId(newClient.getId()) //
.withSavingsId(savingsId)//
.build();
} catch (final DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve);
@@ -199,6 +224,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
final String clientHierarchy = clientForUpdate.getOffice().getHierarchy();
this.context.validateAccessRights(clientHierarchy);
final Map<String, Object> changes = clientForUpdate.update(command);
@@ -212,6 +238,20 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
}
clientForUpdate.updateStaff(newStaff);
}
if (changes.containsKey(ClientApiConstants.savingsProductIdParamName)) {
if(clientForUpdate.isActive()){
throw new ClientActiveForUpdateException(clientId, ClientApiConstants.savingsProductIdParamName);
}
SavingsProduct savingsProduct = null;
final Long savingsProductId = command.longValueOfParameterNamed(ClientApiConstants.savingsProductIdParamName);
if(savingsProductId != null){
savingsProduct = this.savingsProductRepository.findOne(savingsProductId);
if (savingsProduct == null) { throw new SavingsProductNotFoundException(savingsProductId); }
}
clientForUpdate.updateSavingsProduct(savingsProduct);
}
if (!changes.isEmpty()) {
this.clientRepository.saveAndFlush(clientForUpdate);
@@ -244,7 +284,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
final AppUser currentUser = this.context.authenticatedUser();
client.activate(currentUser, fmt, activationDate);
Long savingsId = openOverdraftSavingsAccount(client, fmt);
this.clientRepository.saveAndFlush(client);
return new CommandProcessingResultBuilder() //
@@ -252,6 +292,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
.withOfficeId(client.officeId()) //
.withClientId(clientId) //
.withEntityId(clientId) //
.withSavingsId(savingsId)//
.build();
} catch (final DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve);
@@ -259,6 +300,19 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
}
}
private Long openOverdraftSavingsAccount(final Client client, final DateTimeFormatter fmt) {
Long accountId = null;
if(client.isActive() && client.SavingsProduct() != null){
if(!client.SavingsProduct().isAllowOverdraft()){
String defaultUserMessage = "Client's saving account must be a overdraft account";
throw new InvalidClientSavingProductException("saving.product", "must.be.ovrdraft.account", defaultUserMessage, client.SavingsProduct().getId(),client.getId());
}
SavingsAccountDataDTO savingsAccountDataDTO = new SavingsAccountDataDTO(client, null, client.SavingsProduct(), client.getActivationLocalDate(), client.activatedBy(), fmt);
accountId = this.savingsApplicationProcessWritePlatformService.createActiveApplication(savingsAccountDataDTO);
}
return accountId;
}
private void logAsErrorUnexpectedDataIntegrityException(final DataIntegrityViolationException dve) {
logger.error(dve.getMessage(), dve);
}
@@ -24,7 +24,9 @@ public enum SavingsAccountTransactionType {
INITIATE_TRANSFER(12, "savingsAccountTransactionType.initiateTransfer"), //
APPROVE_TRANSFER(13, "savingsAccountTransactionType.approveTransfer"), //
WITHDRAW_TRANSFER(14, "savingsAccountTransactionType.withdrawTransfer"), //
REJECT_TRANSFER(15, "savingsAccountTransactionType.rejectTransfer");
REJECT_TRANSFER(15, "savingsAccountTransactionType.rejectTransfer"),
WRITTEN_OFF(16, "savingsAccountTransactionType.writtenoff"), //
OVERDRAFT_INTEREST(17, "savingsAccountTransactionType.overdraftInterest"); //
private final Integer value;
private final String code;
@@ -81,6 +83,12 @@ public enum SavingsAccountTransactionType {
case 15:
savingsAccountTransactionType = SavingsAccountTransactionType.REJECT_TRANSFER;
break;
case 18:
savingsAccountTransactionType = SavingsAccountTransactionType.WRITTEN_OFF;
break;
case 19:
savingsAccountTransactionType = SavingsAccountTransactionType.OVERDRAFT_INTEREST;
break;
}
return savingsAccountTransactionType;
}
@@ -132,6 +140,14 @@ public enum SavingsAccountTransactionType {
public boolean isTransferWithdrawal() {
return this.value.equals(SavingsAccountTransactionType.WITHDRAW_TRANSFER.getValue());
}
public boolean isWrittenoff(){
return this.value.equals(SavingsAccountTransactionType.WRITTEN_OFF.getValue());
}
public boolean isIncomeFromInterest(){
return this.value.equals(SavingsAccountTransactionType.OVERDRAFT_INTEREST.getValue());
}
public boolean isDebit() {
return isWithdrawal() || isWithdrawalFee() || isAnnualFee() || isPayCharge();
@@ -92,6 +92,8 @@ public class SavingsApiConstants {
public static final String routingCodeParamName = "routingCode";
public static final String receiptNumberParamName = "receiptNumber";
public static final String bankNumberParamName = "bankNumber";
public static final String allowOverdraftParamName = "allowOverdraft";
public static final String overdraftLimitParamName = "overdraftLimit";
// transaction parameters
public static final String transactionDateParamName = "transactionDate";
@@ -143,7 +145,11 @@ public class SavingsApiConstants {
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(), SAVINGS_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(),
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue(),
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.FEE_INCOME_ACCOUNT_MAPPING.getValue(),
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.PENALTY_INCOME_ACCOUNT_MAPPING.getValue()));
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.PENALTY_INCOME_ACCOUNT_MAPPING.getValue(),
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(),
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_INTEREST.getValue(),
allowOverdraftParamName,overdraftLimitParamName));
/**
* These parameters will match the class level parameters of
@@ -167,7 +173,7 @@ public class SavingsApiConstants {
lockinPeriodFrequencyTypeParamName,
//withdrawalFeeAmountParamName, withdrawalFeeTypeParamName,
withdrawalFeeForTransfersParamName,
feeAmountParamName, feeOnMonthDayParamName, chargesParamName));
feeAmountParamName, feeOnMonthDayParamName, chargesParamName,allowOverdraftParamName,overdraftLimitParamName));
/**
* These parameters will match the class level parameters of
@@ -44,6 +44,8 @@ public class SavingsAccountData {
private final Integer lockinPeriodFrequency;
private final EnumOptionData lockinPeriodFrequencyType;
private final boolean withdrawalFeeForTransfers;
private final boolean allowOverdraft;
private final BigDecimal overdraftLimit;
// associations
private final SavingsAccountSummaryData summary;
@@ -75,7 +77,8 @@ public class SavingsAccountData {
final EnumOptionData interestCompoundingPeriodType, final EnumOptionData interestPostingPeriodType,
final EnumOptionData interestCalculationType, final EnumOptionData interestCalculationDaysInYearType,
final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency,
final EnumOptionData lockinPeriodFrequencyType, final boolean withdrawalFeeForTransfers, final SavingsAccountSummaryData summary) {
final EnumOptionData lockinPeriodFrequencyType, final boolean withdrawalFeeForTransfers, final SavingsAccountSummaryData summary,
final boolean allowOverdraft,final BigDecimal overdraftLimit) {
final Collection<SavingsProductData> productOptions = null;
final Collection<StaffData> fieldOfficerOptions = null;
@@ -96,7 +99,7 @@ public class SavingsAccountData {
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary, transactions, productOptions,
fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
withdrawalFeeTypeOptions, charges, chargeOptions);
withdrawalFeeTypeOptions, charges, chargeOptions,allowOverdraft,overdraftLimit);
}
public static SavingsAccountData lookup(final Long accountId, final String accountNo) {
@@ -127,6 +130,8 @@ public class SavingsAccountData {
// final BigDecimal annualFeeAmount = null;
// final MonthDay annualFeeOnMonthDay = null;
// final LocalDate annualFeeNextDueDate = null;
final boolean allowOverdraft = false;
final BigDecimal overdraftLimit = null;
final SavingsAccountSummaryData summary = null;
final Collection<SavingsAccountTransactionData> transactions = null;
@@ -149,7 +154,7 @@ public class SavingsAccountData {
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary, transactions, productOptions,
fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
withdrawalFeeTypeOptions, charges, chargeOptions);
withdrawalFeeTypeOptions, charges, chargeOptions,allowOverdraft,overdraftLimit);
}
public static SavingsAccountData withTemplateOptions(final SavingsAccountData account, final SavingsAccountData template,
@@ -180,7 +185,8 @@ public class SavingsAccountData {
template.productOptions, template.fieldOfficerOptions, template.interestCompoundingPeriodTypeOptions,
template.interestPostingPeriodTypeOptions, template.interestCalculationTypeOptions,
template.interestCalculationDaysInYearTypeOptions, template.lockinPeriodFrequencyTypeOptions,
template.withdrawalFeeTypeOptions, charges, template.chargeOptions);
template.withdrawalFeeTypeOptions, charges, template.chargeOptions,account.allowOverdraft,
account.overdraftLimit);
}
public static SavingsAccountData withTemplateOptions(final SavingsAccountData account,
@@ -201,7 +207,7 @@ public class SavingsAccountData {
account.lockinPeriodFrequencyType, account.withdrawalFeeForTransfers, account.summary, transactions, productOptions,
fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
withdrawalFeeTypeOptions, charges, chargeOptions);
withdrawalFeeTypeOptions, charges, chargeOptions,account.allowOverdraft,account.overdraftLimit);
}
public static SavingsAccountData withClientTemplate(final Long clientId, final String clientName, final Long groupId,
@@ -231,6 +237,9 @@ public class SavingsAccountData {
// final BigDecimal annualFeeAmount = null;
// final MonthDay annualFeeOnMonthDay = null;
// final LocalDate annualFeeNextDueDate = null;
final boolean allowOverdraft = false;
final BigDecimal overdraftLimit = null;
final SavingsAccountSummaryData summary = null;
final Collection<SavingsAccountTransactionData> transactions = null;
@@ -253,7 +262,7 @@ public class SavingsAccountData {
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary, transactions, productOptions,
fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
withdrawalFeeTypeOptions, charges, chargeOptions);
withdrawalFeeTypeOptions, charges, chargeOptions,allowOverdraft,overdraftLimit);
}
private SavingsAccountData(final Long id, final String accountNo, final String externalId, final Long groupId, final String groupName,
@@ -270,7 +279,8 @@ public class SavingsAccountData {
final Collection<EnumOptionData> interestCalculationTypeOptions,
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
final Collection<SavingsAccountChargeData> charges, final Collection<ChargeData> chargeOptions) {
final Collection<SavingsAccountChargeData> charges, final Collection<ChargeData> chargeOptions,
final boolean allowOverdraft,final BigDecimal overdraftLimit) {
this.id = id;
this.accountNo = accountNo;
this.externalId = externalId;
@@ -319,6 +329,8 @@ public class SavingsAccountData {
this.withdrawalFee = getWithdrawalFee();
this.annualFee = getAnnualFee();
this.allowOverdraft = allowOverdraft;
this.overdraftLimit = overdraftLimit;
}
private SavingsAccountChargeData getWithdrawalFee() {
@@ -0,0 +1,52 @@
package org.mifosplatform.portfolio.savings.data;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.group.domain.Group;
import org.mifosplatform.portfolio.savings.domain.SavingsProduct;
import org.mifosplatform.useradministration.domain.AppUser;
public class SavingsAccountDataDTO {
private final Client client;
private final Group group;
private final SavingsProduct savingsProduct;
private final LocalDate applicationDate;
private final AppUser appliedBy;
private final DateTimeFormatter fmt;
public SavingsAccountDataDTO(final Client client, final Group group, final SavingsProduct savingsProduct,
final LocalDate applicationDate, final AppUser appliedBy, final DateTimeFormatter fmt) {
this.client = client;
this.group = group;
this.savingsProduct = savingsProduct;
this.applicationDate = applicationDate;
this.appliedBy = appliedBy;
this.fmt = fmt;
}
public Client getClient() {
return this.client;
}
public Group getGroup() {
return this.group;
}
public SavingsProduct getSavingsProduct() {
return this.savingsProduct;
}
public LocalDate getApplicationDate() {
return this.applicationDate;
}
public AppUser getAppliedBy() {
return this.appliedBy;
}
public DateTimeFormatter getFmt() {
return this.fmt;
}
}
@@ -6,6 +6,7 @@
package org.mifosplatform.portfolio.savings.data;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.accountNoParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.allowOverdraftParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.amountParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargeIdParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargesParamName;
@@ -23,6 +24,7 @@ import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeri
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequiredOpeningBalanceParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.overdraftLimitParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.productIdParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.submittedOnDateParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
@@ -188,6 +190,8 @@ public class SavingsAccountDataValidator {
validateSavingsCharges(element, baseDataValidator);
validateOverdraftParams(baseDataValidator, element);
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
@@ -359,10 +363,27 @@ public class SavingsAccountDataValidator {
.ignoreIfNull().validateForBooleanValue();
}
validateOverdraftParams(baseDataValidator, element);
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
private void validateOverdraftParams(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
if (this.fromApiJsonHelper.parameterExists(allowOverdraftParamName, element)) {
final Boolean allowOverdraft = this.fromApiJsonHelper.extractBooleanNamed(
allowOverdraftParamName, element);
baseDataValidator.reset().parameter(allowOverdraftParamName).value(allowOverdraft)
.ignoreIfNull().validateForBooleanValue();
}
if (this.fromApiJsonHelper.parameterExists(overdraftLimitParamName, element)) {
final BigDecimal overdraftLimit = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(
overdraftLimitParamName, element);
baseDataValidator.reset().parameter(overdraftLimitParamName).value(overdraftLimit).ignoreIfNull().zeroOrPositiveAmount();
}
}
}
@@ -25,6 +25,9 @@ public class SavingsAccountTransactionEnumData {
private final boolean approveTransfer;
private final boolean withdrawTransfer;
private final boolean rejectTransfer;
private final boolean overdraftInterest;
private final boolean writtenoff ;
private final boolean overdraftFee =true;
public SavingsAccountTransactionEnumData(final Long id, final String code, final String value) {
this.id = id;
@@ -40,6 +43,9 @@ public class SavingsAccountTransactionEnumData {
this.approveTransfer = Long.valueOf(SavingsAccountTransactionType.APPROVE_TRANSFER.getValue()).equals(this.id);
this.withdrawTransfer = Long.valueOf(SavingsAccountTransactionType.WITHDRAW_TRANSFER.getValue()).equals(this.id);
this.rejectTransfer = Long.valueOf(SavingsAccountTransactionType.REJECT_TRANSFER.getValue()).equals(this.id);
this.writtenoff = Long.valueOf(SavingsAccountTransactionType.WRITTEN_OFF.getValue()).equals(this.id);
this.overdraftInterest = Long.valueOf(SavingsAccountTransactionType.OVERDRAFT_INTEREST.getValue()).equals(this.id);
// this.overdraftFee = Long.valueOf(SavingsAccountTransactionType.OVERDRAFT_INTEREST.getValue()).equals(this.id);
}
public Long getId() {
@@ -89,5 +95,18 @@ public class SavingsAccountTransactionEnumData {
public boolean isRejectTransfer() {
return this.rejectTransfer;
}
public boolean isOverdraftInterest() {
return this.overdraftInterest;
}
public boolean isWrittenoff() {
return this.writtenoff;
}
public boolean isOverdraftFee() {
return this.overdraftFee;
}
}
@@ -38,6 +38,8 @@ public class SavingsProductData {
private final Integer lockinPeriodFrequency;
private final EnumOptionData lockinPeriodFrequencyType;
private final boolean withdrawalFeeForTransfers;
private final boolean allowOverdraft;
private final BigDecimal overdraftLimit;
// accounting
private final EnumOptionData accountingRule;
@@ -89,6 +91,9 @@ public class SavingsProductData {
final Collection<ChargeData> charges = null;
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings = null;
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings = null;
final boolean allowOverdraft = false;
final BigDecimal overdraftLimit = null;
return new SavingsProductData(id, name, shortName, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
@@ -97,7 +102,7 @@ public class SavingsProductData {
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions,
accountingMappingOptions, charges, chargeOptions, penaltyOptions, feeToIncomeAccountMappings,
penaltyToIncomeAccountMappings);
penaltyToIncomeAccountMappings,allowOverdraft,overdraftLimit);
}
public static SavingsProductData withCharges(final SavingsProductData product, final Collection<ChargeData> charges) {
@@ -110,7 +115,7 @@ public class SavingsProductData {
product.interestCalculationDaysInYearTypeOptions, product.lockinPeriodFrequencyTypeOptions,
product.withdrawalFeeTypeOptions, product.paymentTypeOptions, product.accountingRuleOptions,
product.accountingMappingOptions, charges, product.chargeOptions, product.penaltyOptions,
product.feeToIncomeAccountMappings, product.penaltyToIncomeAccountMappings);
product.feeToIncomeAccountMappings, product.penaltyToIncomeAccountMappings,product.allowOverdraft,product.overdraftLimit);
}
/**
@@ -137,7 +142,8 @@ public class SavingsProductData {
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions,
accountingMappingOptions, existingProduct.charges, chargeOptions, penaltyOptions,
existingProduct.feeToIncomeAccountMappings, existingProduct.penaltyToIncomeAccountMappings);
existingProduct.feeToIncomeAccountMappings, existingProduct.penaltyToIncomeAccountMappings,
existingProduct.allowOverdraft,existingProduct.overdraftLimit);
}
public static SavingsProductData withAccountingDetails(final SavingsProductData existingProduct,
@@ -169,7 +175,7 @@ public class SavingsProductData {
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions,
accountingMappingOptions, existingProduct.charges, chargeOptions, penaltyOptions, feeToIncomeAccountMappings,
penaltyToIncomeAccountMappings);
penaltyToIncomeAccountMappings,existingProduct.allowOverdraft,existingProduct.overdraftLimit);
}
public static SavingsProductData instance(final Long id, final String name, final String shortName, final String description,
@@ -177,7 +183,7 @@ public class SavingsProductData {
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final boolean withdrawalFeeForTransfers,
final EnumOptionData accountingType) {
final EnumOptionData accountingType,final boolean allowOverdraft,final BigDecimal overdraftLimit) {
final Map<String, Object> accountingMappings = null;
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
@@ -205,7 +211,7 @@ public class SavingsProductData {
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions,
accountingMappingOptions, charges, chargeOptions, penaltyOptions, feeToIncomeAccountMappings,
penaltyToIncomeAccountMappings);
penaltyToIncomeAccountMappings,allowOverdraft,overdraftLimit);
}
public static SavingsProductData lookup(final Long id, final String name) {
@@ -225,6 +231,8 @@ public class SavingsProductData {
final EnumOptionData accountingType = null;
final Map<String, Object> accountingMappings = null;
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
final boolean allowOverdraft = false;
final BigDecimal overdraftLimit = null;
final Collection<CurrencyData> currencyOptions = null;
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
@@ -241,6 +249,8 @@ public class SavingsProductData {
final Collection<ChargeData> penaltyOptions = null;
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings = null;
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings = null;
return new SavingsProductData(id, name, shortName, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
@@ -249,7 +259,7 @@ public class SavingsProductData {
currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions,
accountingRuleOptions, accountingMappingOptions, charges, chargeOptions, penaltyOptions, feeToIncomeAccountMappings,
penaltyToIncomeAccountMappings);
penaltyToIncomeAccountMappings,allowOverdraft,overdraftLimit);
}
private SavingsProductData(final Long id, final String name, final String shortName, final String description, final CurrencyData currency,
@@ -268,7 +278,8 @@ public class SavingsProductData {
final Map<String, List<GLAccountData>> accountingMappingOptions, final Collection<ChargeData> charges,
final Collection<ChargeData> chargeOptions, final Collection<ChargeData> penaltyOptions,
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings,
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings) {
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings,
final boolean allowOverdraft,final BigDecimal overdraftLimit) {
this.id = id;
this.name = name;
this.shortName = shortName;
@@ -311,6 +322,8 @@ public class SavingsProductData {
this.feeToIncomeAccountMappings = feeToIncomeAccountMappings;
this.penaltyToIncomeAccountMappings = penaltyToIncomeAccountMappings;
this.allowOverdraft = allowOverdraft;
this.overdraftLimit = overdraftLimit;
}
public boolean hasAccountingEnabled() {
@@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.savings.data;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_PRODUCT_RESOURCE_NAME;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.allowOverdraftParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.feeAmountParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.feeOnMonthDayParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.currencyCodeParamName;
@@ -22,6 +23,7 @@ import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeri
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequiredOpeningBalanceParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nameParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.overdraftLimitParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.shortNameParamName;
@@ -240,10 +242,28 @@ public class SavingsProductDataValidator {
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), element);
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue())
.value(incomeFromPenaltyId).notNull().integerGreaterThanZero();
final Long overdraftControlAccountId = this.fromApiJsonHelper.extractLongNamed(
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), element);
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.OVERDRAFT_PORTFOLIO_CONTROL.getValue())
.value(overdraftControlAccountId).notNull().integerGreaterThanZero();
final Long incomeFromInterest = this.fromApiJsonHelper.extractLongNamed(
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_INTEREST.getValue(), element);
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_INTEREST.getValue())
.value(incomeFromInterest).notNull().integerGreaterThanZero();
final Long writtenoff = this.fromApiJsonHelper.extractLongNamed(
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), element);
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue())
.value(writtenoff).notNull().integerGreaterThanZero();
validatePaymentChannelFundSourceMappings(baseDataValidator, element);
validateChargeToIncomeAccountMappings(baseDataValidator, element);
}
validateOverdraftParams(baseDataValidator, element);
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
@@ -383,10 +403,27 @@ public class SavingsProductDataValidator {
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), element);
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue()).value(incomeFromPenaltyId)
.ignoreIfNull().integerGreaterThanZero();
final Long overdraftAccountId = this.fromApiJsonHelper.extractLongNamed(
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), element);
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.OVERDRAFT_PORTFOLIO_CONTROL.getValue())
.value(overdraftAccountId).ignoreIfNull().integerGreaterThanZero();
final Long incomeFromInterest = this.fromApiJsonHelper.extractLongNamed(
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_INTEREST.getValue(), element);
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_INTEREST.getValue())
.value(incomeFromInterest).ignoreIfNull().integerGreaterThanZero();
final Long writtenoff = this.fromApiJsonHelper.extractLongNamed(
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), element);
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue())
.value(writtenoff).ignoreIfNull().integerGreaterThanZero();
validatePaymentChannelFundSourceMappings(baseDataValidator, element);
validateChargeToIncomeAccountMappings(baseDataValidator, element);
validateOverdraftParams(baseDataValidator, element);
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
@@ -467,4 +504,21 @@ public class SavingsProductDataValidator {
}
}
}
private void validateOverdraftParams(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
if (this.fromApiJsonHelper.parameterExists(allowOverdraftParamName, element)) {
final Boolean allowOverdraft = this.fromApiJsonHelper.extractBooleanNamed(
allowOverdraftParamName, element);
baseDataValidator.reset().parameter(allowOverdraftParamName).value(allowOverdraft)
.ignoreIfNull().validateForBooleanValue();
}
if (this.fromApiJsonHelper.parameterExists(overdraftLimitParamName, element)) {
final BigDecimal overdraftLimit = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(
overdraftLimitParamName, element);
baseDataValidator.reset().parameter(overdraftLimitParamName).value(overdraftLimit).ignoreIfNull().zeroOrPositiveAmount();
}
}
}
@@ -6,9 +6,12 @@
package org.mifosplatform.portfolio.savings.domain;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.allowOverdraftParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.localeParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.overdraftLimitParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
import java.math.BigDecimal;
@@ -218,6 +221,12 @@ public class SavingsAccount extends AbstractPersistable<Long> {
@Column(name = "withdrawal_fee_for_transfer", nullable = true)
private boolean withdrawalFeeApplicableForTransfer;
@Column(name = "allow_overdraft")
private boolean allowOverdraft;
@Column(name = "overdraft_limit", scale = 6, precision = 19, nullable = true)
private BigDecimal overdraftLimit;
@Embedded
private SavingsAccountSummary summary;
@@ -249,13 +258,14 @@ public class SavingsAccount extends AbstractPersistable<Long> {
final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
final boolean withdrawalFeeApplicableForTransfer, final Set<SavingsAccountCharge> savingsAccountCharges) {
final boolean withdrawalFeeApplicableForTransfer, final Set<SavingsAccountCharge> savingsAccountCharges,
final boolean allowOverdraft,final BigDecimal overdraftLimit) {
final SavingsAccountStatusType status = SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL;
return new SavingsAccount(client, group, product, fieldOfficer, accountNo, externalId, status, accountType, submittedOnDate, submittedBy,
interestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType,
interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType,
withdrawalFeeApplicableForTransfer, savingsAccountCharges);
withdrawalFeeApplicableForTransfer, savingsAccountCharges,allowOverdraft,overdraftLimit);
}
private SavingsAccount(final Client client, final Group group, final SavingsProduct product, final Staff fieldOfficer,
@@ -265,7 +275,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
final boolean withdrawalFeeApplicableForTransfer, final Set<SavingsAccountCharge> savingsAccountCharges) {
final boolean withdrawalFeeApplicableForTransfer, final Set<SavingsAccountCharge> savingsAccountCharges,
final boolean allowOverdraft,final BigDecimal overdraftLimit) {
this.client = client;
this.group = group;
this.product = product;
@@ -300,6 +311,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
}
this.summary = new SavingsAccountSummary();
this.allowOverdraft = allowOverdraft;
this.overdraftLimit = overdraftLimit;
}
/**
@@ -496,24 +509,57 @@ public class SavingsAccount extends AbstractPersistable<Long> {
Money runningBalance = openingAccountBalance.copy();
final List<SavingsAccountTransaction> accountTransactionsSorted = retreiveListOfTransactions();
List<SavingsAccountTransaction> accountTransactionsSorted = retreiveListOfTransactions();
boolean isTransactionsModified = false;
for (final SavingsAccountTransaction transaction : accountTransactionsSorted) {
if (transaction.isReversed()) {
transaction.zeroBalanceFields();
} else {
Money overdraftAmount = Money.zero(this.currency);
Money transactionAmount = Money.zero(this.currency);
if (transaction.isCredit()) {
if(runningBalance.isLessThanZero()){
Money diffAmount = transaction.getAmount(this.currency).plus(runningBalance);
if(diffAmount.isGreaterThanZero()){
overdraftAmount = transaction.getAmount(this.currency).minus(diffAmount);
}else{
overdraftAmount = transaction.getAmount(this.currency);
}
}
transactionAmount = transactionAmount.plus(transaction.getAmount(this.currency));
} else if (transaction.isDebit()) {
if(runningBalance.isLessThanZero()){
overdraftAmount = transaction.getAmount(this.currency);
}
transactionAmount = transactionAmount.minus(transaction.getAmount(this.currency));
}
runningBalance = runningBalance.plus(transactionAmount);
transaction.updateRunningBalance(runningBalance);
if(overdraftAmount.isZero() && runningBalance.isLessThanZero()){
overdraftAmount = overdraftAmount.plus(runningBalance.getAmount().negate());
}
if(transaction.getId() == null && overdraftAmount.isGreaterThanZero()){
transaction.updateOverdraftAmount(overdraftAmount.getAmount());
}else if(overdraftAmount.isNotEqualTo(transaction.getOverdraftAmount(getCurrency()))){
SavingsAccountTransaction accountTransaction = SavingsAccountTransaction.copyTransaction(transaction);
transaction.reverse();
if(overdraftAmount.isGreaterThanZero()){
accountTransaction.updateOverdraftAmount(overdraftAmount.getAmount());
}
accountTransaction.updateRunningBalance(runningBalance);
this.transactions.add(accountTransaction);
isTransactionsModified = true;
}
}
}
if(isTransactionsModified){
accountTransactionsSorted = retreiveListOfTransactions();
}
// loop over transactions in reverse
LocalDate endOfBalanceDate = DateUtils.getLocalDateOfTenant();
for (int i = accountTransactionsSorted.size() - 1; i >= 0; i--) {
@@ -687,10 +733,20 @@ public class SavingsAccount extends AbstractPersistable<Long> {
if (runningBalance.isLessThanZero()) {
//
final BigDecimal withdrawalFee = null;
throw new InsufficientAccountBalanceException("transactionAmount", getAccountBalance(), withdrawalFee, transactionAmount);
Money limit = runningBalance.zero();
if(this.allowOverdraft){
if(this.overdraftLimit != null){
limit = limit.plus(this.overdraftLimit);
}
}
if(limit.plus(runningBalance).isLessThanZero()){
throw new InsufficientAccountBalanceException("transactionAmount", getAccountBalance(), withdrawalFee, transactionAmount);
}
}
}
}
public void validateAccountBalanceDoesNotBecomeNegative(final String transactionAction) {
@@ -709,9 +765,18 @@ public class SavingsAccount extends AbstractPersistable<Long> {
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME + transactionAction);
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("results.in.balance.going.negative");
if(this.allowOverdraft){
Money limit = runningBalance.zero();
if(this.overdraftLimit != null){
limit = limit.plus(this.overdraftLimit);
}
if(limit.plus(runningBalance).isLessThanZero()){
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("results.in.balance.exceeding.overdraft.limit");
}
}else{
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("results.in.balance.going.negative");
}
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
}
@@ -878,6 +943,24 @@ public class SavingsAccount extends AbstractPersistable<Long> {
actualChanges.put(chargesParamName, command.jsonFragment(chargesParamName));
}
}
if (command.isChangeInBooleanParameterNamed(allowOverdraftParamName, this.allowOverdraft)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(allowOverdraftParamName);
actualChanges.put(allowOverdraftParamName, newValue);
this.allowOverdraft = newValue;
}
if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(overdraftLimitParamName,
this.overdraftLimit)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(overdraftLimitParamName);
actualChanges.put(overdraftLimitParamName, newValue);
actualChanges.put(localeParamName, localeAsInput);
this.overdraftLimit = newValue;
}
if(!this.allowOverdraft){
this.overdraftLimit = null;
}
validateLockinDetails();
@@ -1438,9 +1521,15 @@ public class SavingsAccount extends AbstractPersistable<Long> {
// auto enter deposit for minimum required opening balance when
// activating account.
processAccountUponActivation(fmt);
return actualChanges;
}
private void processAccountUponActivation(final DateTimeFormatter fmt) {
final Money minRequiredOpeningBalance = Money.of(this.currency, this.minRequiredOpeningBalance);
if (minRequiredOpeningBalance.isGreaterThanZero()) {
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, activationDate,
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, getActivationLocalDate(),
minRequiredOpeningBalance.getAmount(), null);
deposit(transactionDTO);
@@ -1463,8 +1552,22 @@ public class SavingsAccount extends AbstractPersistable<Long> {
//auto pay the activation time charges
this.payActivationCharges();
//TODO : AA add activation charges to actual changes list
return actualChanges;
}
public void approveAndActivateApplication(final Date appliedonDate,final AppUser appliedBy,final DateTimeFormatter fmt){
this.status = SavingsAccountStatusType.ACTIVE.getValue();
this.approvedOnDate = appliedonDate;
this.approvedBy = appliedBy;
this.rejectedOnDate = null;
this.rejectedBy = null;
this.withdrawnOnDate = null;
this.withdrawnBy = null;
this.closedOnDate = null;
this.closedBy = null;
this.activatedOnDate = appliedonDate;
this.activatedBy = appliedBy;
this.lockedInUntilDate = calculateDateAccountIsLockedUntil(getActivationLocalDate());
processAccountUponActivation(fmt);
}
private void payActivationCharges() {
@@ -1894,4 +1997,20 @@ public class SavingsAccount extends AbstractPersistable<Long> {
public Set<SavingsAccountCharge> charges() {
return (this.charges == null) ? new HashSet<SavingsAccountCharge>() : this.charges;
}
public void validateAccountValuesWithProduct() {
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
if(this.overdraftLimit != null && this.product.overdraftLimit() != null && this.overdraftLimit.compareTo(this.product.overdraftLimit()) == 1){
baseDataValidator.reset().parameter(SavingsApiConstants.overdraftLimitParamName).value(this.overdraftLimit)
.failWithCode("cannot.exceed.product.value");
}
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors);}
}
}
@@ -6,6 +6,7 @@
package org.mifosplatform.portfolio.savings.domain;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.accountNoParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.allowOverdraftParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.clientIdParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.externalIdParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.fieldOfficerIdParamName;
@@ -18,11 +19,13 @@ import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeri
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequiredOpeningBalanceParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.overdraftLimitParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.productIdParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.submittedOnDateParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Set;
import org.joda.time.LocalDate;
@@ -112,15 +115,15 @@ public class SavingsAccountAssembler {
if (groupId != null) {
group = this.groupRepository.findOneWithNotFoundDetection(groupId);
accountType = AccountType.GROUP;
if (group.isNotActive()) {
if (group.isCenter()) { throw new CenterNotActiveException(groupId); }
throw new GroupNotActiveException(groupId);
}
}
if (group != null && client != null) {
if (!group.hasClientAsMember(client)) { throw new ClientNotInGroupException(clientId, groupId); }
accountType = AccountType.JLG;
if (group.isNotActive()) {
if (group.isCenter()) { throw new CenterNotActiveException(groupId); }
throw new GroupNotActiveException(groupId);
}
}
final Long fieldOfficerId = this.fromApiJsonHelper.extractLongNamed(fieldOfficerIdParamName, element);
@@ -202,13 +205,23 @@ public class SavingsAccountAssembler {
final Set<SavingsAccountCharge> charges = this.savingsAccountChargeAssembler.fromParsedJson(element, product.currency().getCode());
boolean allowOverdraft = false;
if (command.parameterExists(allowOverdraftParamName)) {
allowOverdraft = command.booleanPrimitiveValueOfParameterNamed(allowOverdraftParamName);
}
final BigDecimal overdraftLimit = command
.bigDecimalValueOfParameterNamedDefaultToNullIfZero(overdraftLimitParamName);
final SavingsAccount account = SavingsAccount.createNewApplicationForSubmittal(client, group, product, fieldOfficer, accountNo,
externalId, accountType, submittedOnDate, submittedBy, interestRate, interestCompoundingPeriodType, interestPostingPeriodType,
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
lockinPeriodFrequencyType, iswithdrawalFeeApplicableForTransfer, charges);
lockinPeriodFrequencyType, iswithdrawalFeeApplicableForTransfer, charges,allowOverdraft,overdraftLimit);
account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper);
account.validateNewApplicationState(DateUtils.getLocalDateOfTenant());
account.validateAccountValuesWithProduct();
return account;
}
@@ -216,10 +229,53 @@ public class SavingsAccountAssembler {
public SavingsAccount assembleFrom(final Long savingsId) {
final SavingsAccount account = this.savingsAccountRepository.findOneWithNotFoundDetection(savingsId);
account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper);
return account;
}
/**
* Assembles a new {@link SavingsAccount} from JSON details passed in
* request inheriting details where relevant from chosen
* {@link SavingsProduct}.
*/
public SavingsAccount assembleFrom(final Client client ,final Group group, final SavingsProduct product,final LocalDate appliedonDate,final AppUser appliedBy) {
AccountType accountType = AccountType.INVALID;
if (client != null) {
accountType = AccountType.INDIVIDUAL;
if (client.isNotActive()) { throw new ClientNotActiveException(client.getId()); }
}
if (group != null) {
accountType = AccountType.GROUP;
if(group.isNotActive()){
if (group.isCenter()) { throw new CenterNotActiveException(group.getId()); }
throw new GroupNotActiveException(group.getId());
}
}
if (group != null && client != null) {
if (!group.hasClientAsMember(client)) { throw new ClientNotInGroupException(client.getId(), group.getId()); }
accountType = AccountType.JLG;
}
final Set<SavingsAccountCharge> charges = this.savingsAccountChargeAssembler.fromSavingsProduct(product);
final SavingsAccount account = SavingsAccount.createNewApplicationForSubmittal(client, group, product, null, null,
null, accountType, appliedonDate, appliedBy, product.nominalAnnualInterestRate(), product.interestCompoundingPeriodType(),
product.interestPostingPeriodType(),
product.interestCalculationType(), product.interestCalculationDaysInYearType(), product.minRequiredOpeningBalance(), product.lockinPeriodFrequency(),
product.lockinPeriodFrequencyType(), product.isWithdrawalFeeApplicableForTransfer(), charges ,product.isAllowOverdraft(),product.overdraftLimit());
account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper);
account.validateNewApplicationState(DateUtils.getLocalDateOfTenant());
account.validateAccountValuesWithProduct();
return account;
}
public void assignSavingAccountHelpers(final SavingsAccount savingsAccount) {
savingsAccount.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper);
}
@@ -614,6 +614,10 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
public boolean isWithdrawalFee() {
return ChargeTimeType.fromInt(this.chargeTime).isWithdrawalFee();
}
public boolean isOverdraftFee(){
return ChargeTimeType.fromInt(this.chargeTime).isOverdraftFee();
}
public boolean isAnnualFee() {
return ChargeTimeType.fromInt(this.chargeTime).isAnnualFee();
@@ -126,6 +126,32 @@ public class SavingsAccountChargeAssembler {
return savingsAccountCharges;
}
public Set<SavingsAccountCharge> fromSavingsProduct(final SavingsProduct savingsProduct) {
final Set<SavingsAccountCharge> savingsAccountCharges = new HashSet<SavingsAccountCharge>();
Set<Charge> productCharges = savingsProduct.charges();
for (Charge charge : productCharges) {
ChargeTimeType chargeTime = null;
if (charge.getChargeTime() != null) {
chargeTime = ChargeTimeType.fromInt(charge.getChargeTime());
}
if(chargeTime !=null && chargeTime.isOnSpecifiedDueDate()){
continue;
}
ChargeCalculationType chargeCalculation = null;
if (charge.getChargeCalculation() != null) {
chargeCalculation = ChargeCalculationType.fromInt(charge.getChargeCalculation());
}
final boolean status = true;
final SavingsAccountCharge savingsAccountCharge = SavingsAccountCharge.createNewWithoutSavingsAccount(
charge, charge.getAmount(),chargeTime ,chargeCalculation , null, status, charge.getFeeOnMonthDay(), charge.feeInterval());
savingsAccountCharges.add(savingsAccountCharge);
}
return savingsAccountCharges;
}
private void validateSavingsCharges(final Set<SavingsAccountCharge> charges, final String productCurrencyCode) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
@@ -89,6 +89,9 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
@LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "savingsAccountTransaction", orphanRemoval = true)
private final Set<SavingsAccountChargePaidBy> savingsAccountChargesPaid = new HashSet<SavingsAccountChargePaidBy>();
@Column(name = "overdraft_amount_derived", scale = 6, precision = 19, nullable = true)
private BigDecimal overdraftAmount;
protected SavingsAccountTransaction() {
this.dateOf = null;
@@ -167,6 +170,13 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
SavingsAccountTransactionType.WITHDRAW_TRANSFER.getValue(), date, savingsAccount.getSummary().getAccountBalance(),
isReversed);
}
public static SavingsAccountTransaction copyTransaction(SavingsAccountTransaction accountTransaction) {
return new SavingsAccountTransaction(accountTransaction.savingsAccount, accountTransaction.office, accountTransaction.paymentDetail,
accountTransaction.typeOf, accountTransaction.transactionLocalDate(), accountTransaction.amount,
accountTransaction.reversed);
}
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final Integer typeOf,
final LocalDate transactionLocalDate, final Money amount, final boolean isReversed) {
@@ -331,6 +341,7 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
thisTransactionData.put("date", getTransactionLocalDate());
thisTransactionData.put("currency", currencyData);
thisTransactionData.put("amount", this.amount);
thisTransactionData.put("overdraftAmount", this.overdraftAmount);
if (this.paymentDetail != null) {
thisTransactionData.put("paymentTypeId", this.paymentDetail.getPaymentType().getId());
@@ -535,4 +546,14 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
return this.savingsAccountChargesPaid;
}
public void updateOverdraftAmount(BigDecimal overdraftAmount) {
this.overdraftAmount = overdraftAmount;
}
public Money getOverdraftAmount(final MonetaryCurrency currency) {
return Money.of(currency, this.overdraftAmount);
}
}
@@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.savings.domain;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_PRODUCT_RESOURCE_NAME;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.accountingRuleParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.allowOverdraftParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargesParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.currencyCodeParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.descriptionParamName;
@@ -22,8 +23,9 @@ import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeri
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequiredOpeningBalanceParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nameParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.overdraftLimitParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.shortNameParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
import java.math.BigDecimal;
import java.util.ArrayList;
@@ -129,17 +131,25 @@ public class SavingsProduct extends AbstractPersistable<Long> {
@ManyToMany
@JoinTable(name = "m_savings_product_charge", joinColumns = @JoinColumn(name = "savings_product_id"), inverseJoinColumns = @JoinColumn(name = "charge_id"))
private Set<Charge> charges;
@Column(name = "allow_overdraft")
private boolean allowOverdraft;
@Column(name = "overdraft_limit", scale = 6, precision = 19, nullable = true)
private BigDecimal overdraftLimit;
public static SavingsProduct createNew(final String name, final String shortName, final String description, final MonetaryCurrency currency,
final BigDecimal interestRate, final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
final boolean withdrawalFeeApplicableForTransfer, final AccountingRuleType accountingRuleType, final Set<Charge> charges) {
final boolean withdrawalFeeApplicableForTransfer, final AccountingRuleType accountingRuleType, final Set<Charge> charges,
final boolean allowOverdraft,final BigDecimal overdraftLimit) {
return new SavingsProduct(name, shortName, description, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType,
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, accountingRuleType, charges);
lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, accountingRuleType, charges,
allowOverdraft,overdraftLimit);
}
protected SavingsProduct() {
@@ -152,7 +162,8 @@ public class SavingsProduct extends AbstractPersistable<Long> {
final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
final boolean withdrawalFeeApplicableForTransfer, final AccountingRuleType accountingRuleType, final Set<Charge> charges) {
final boolean withdrawalFeeApplicableForTransfer, final AccountingRuleType accountingRuleType, final Set<Charge> charges,
final boolean allowOverdraft,final BigDecimal overdraftLimit) {
this.name = name;
this.shortName = shortName;
@@ -192,6 +203,8 @@ public class SavingsProduct extends AbstractPersistable<Long> {
validateLockinDetails();
//validateWithdrawalFeeDetails();
//validateAnnualFeeDetails();
this.allowOverdraft = allowOverdraft;
this.overdraftLimit = overdraftLimit;
}
public MonetaryCurrency currency() {
@@ -411,6 +424,23 @@ public class SavingsProduct extends AbstractPersistable<Long> {
}
}
if (command.isChangeInBooleanParameterNamed(allowOverdraftParamName, this.allowOverdraft)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(allowOverdraftParamName);
actualChanges.put(allowOverdraftParamName, newValue);
this.allowOverdraft = newValue;
}
if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(overdraftLimitParamName,
this.overdraftLimit)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(overdraftLimitParamName);
actualChanges.put(overdraftLimitParamName, newValue);
actualChanges.put(localeParamName, localeAsInput);
this.overdraftLimit = newValue;
}
if(!this.allowOverdraft){
this.overdraftLimit = null;
}
validateLockinDetails();
//validateWithdrawalFeeDetails();
//validateAnnualFeeDetails();
@@ -517,4 +547,24 @@ public class SavingsProduct extends AbstractPersistable<Long> {
}
return updated;
}
public BigDecimal overdraftLimit() {
return this.overdraftLimit;
}
public boolean isWithdrawalFeeApplicableForTransfer() {
return this.withdrawalFeeApplicableForTransfer;
}
public boolean isAllowOverdraft() {
return this.allowOverdraft;
}
public Set<Charge> charges() {
return this.charges;
}
}
@@ -22,6 +22,9 @@ import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nameParamN
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.shortNameParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.allowOverdraftParamName;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.overdraftLimitParamName;
import java.math.BigDecimal;
import java.util.HashSet;
@@ -112,10 +115,19 @@ public class SavingsProductAssembler {
// Savings product charges
final Set<Charge> charges = assembleListOfSavingsProductCharges(command, currencyCode);
boolean allowOverdraft = false;
if (command.parameterExists(allowOverdraftParamName)) {
allowOverdraft = command.booleanPrimitiveValueOfParameterNamed(allowOverdraftParamName);
}
final BigDecimal overdraftLimit = command
.bigDecimalValueOfParameterNamedDefaultToNullIfZero(overdraftLimitParamName);
return SavingsProduct.createNew(name, shortName, description, currency, interestRate, interestCompoundingPeriodType,
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
lockinPeriodFrequency, lockinPeriodFrequencyType, iswithdrawalFeeApplicableForTransfer, accountingRuleType, charges);
lockinPeriodFrequency, lockinPeriodFrequencyType, iswithdrawalFeeApplicableForTransfer, accountingRuleType, charges,
allowOverdraft,overdraftLimit);
}
public Set<Charge> assembleListOfSavingsProductCharges(final JsonCommand command, final String savingsProductCurrencyCode) {
@@ -223,6 +223,8 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
// sqlBuilder.append("sa.withdrawal_fee_amount as withdrawalFeeAmount,");
// sqlBuilder.append("sa.withdrawal_fee_type_enum as withdrawalFeeTypeEnum, ");
sqlBuilder.append("sa.withdrawal_fee_for_transfer as withdrawalFeeForTransfers, ");
sqlBuilder.append("sa.allow_overdraft as allowOverdraft, ");
sqlBuilder.append("sa.overdraft_limit as overdraftLimit, ");
// sqlBuilder.append("sa.annual_fee_amount as annualFeeAmount,");
// sqlBuilder.append("sa.annual_fee_on_month as annualFeeOnMonth, ");
// sqlBuilder.append("sa.annual_fee_on_day as annualFeeOnDay, ");
@@ -358,6 +360,9 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
}*/
final boolean withdrawalFeeForTransfers = rs.getBoolean("withdrawalFeeForTransfers");
final boolean allowOverdraft = rs.getBoolean("allowOverdraft");
final BigDecimal overdraftLimit = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "overdraftLimit");
/*final BigDecimal annualFeeAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "annualFeeAmount");
@@ -388,7 +393,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
return SavingsAccountData.instance(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary);
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary,allowOverdraft,overdraftLimit);
}
}
@@ -731,7 +736,9 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
sqlBuilder.append("sp.lockin_period_frequency_enum as lockinPeriodFrequencyType, ");
// sqlBuilder.append("sp.withdrawal_fee_amount as withdrawalFeeAmount,");
// sqlBuilder.append("sp.withdrawal_fee_type_enum as withdrawalFeeTypeEnum, ");
sqlBuilder.append("sp.withdrawal_fee_for_transfer as withdrawalFeeForTransfers ");
sqlBuilder.append("sp.withdrawal_fee_for_transfer as withdrawalFeeForTransfers, ");
sqlBuilder.append("sp.allow_overdraft as allowOverdraft, ");
sqlBuilder.append("sp.overdraft_limit as overdraftLimit ");
// sqlBuilder.append("sp.annual_fee_amount as annualFeeAmount,");
// sqlBuilder.append("sp.annual_fee_on_month as annualFeeOnMonth, ");
// sqlBuilder.append("sp.annual_fee_on_day as annualFeeOnDay ");
@@ -795,6 +802,9 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
}
*/
final boolean withdrawalFeeForTransfers = rs.getBoolean("withdrawalFeeForTransfers");
final boolean allowOverdraft = rs.getBoolean("allowOverdraft");
final BigDecimal overdraftLimit = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "overdraftLimit");
//final BigDecimal annualFeeAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "annualFeeAmount");
@@ -830,7 +840,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
return SavingsAccountData.instance(null, null, null, groupId, groupName, clientId, clientName, productId, productName,
fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualIterestRate, interestCompoundingPeriodType,
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary);
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary,allowOverdraft,overdraftLimit);
}
}
@@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.savings.service;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.portfolio.savings.data.SavingsAccountDataDTO;
public interface SavingsApplicationProcessWritePlatformService {
@@ -23,4 +24,6 @@ public interface SavingsApplicationProcessWritePlatformService {
CommandProcessingResult rejectApplication(Long savingsId, JsonCommand command);
CommandProcessingResult applicantWithdrawsFromApplication(Long savingsId, JsonCommand command);
Long createActiveApplication(SavingsAccountDataDTO savingsAccountDataDTO);
}
@@ -8,12 +8,14 @@ package org.mifosplatform.portfolio.savings.service;
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
@@ -38,6 +40,7 @@ import org.mifosplatform.portfolio.group.exception.GroupNotFoundException;
import org.mifosplatform.portfolio.note.domain.Note;
import org.mifosplatform.portfolio.note.domain.NoteRepository;
import org.mifosplatform.portfolio.savings.SavingsApiConstants;
import org.mifosplatform.portfolio.savings.data.SavingsAccountDataDTO;
import org.mifosplatform.portfolio.savings.data.SavingsAccountDataValidator;
import org.mifosplatform.portfolio.savings.domain.SavingsAccount;
import org.mifosplatform.portfolio.savings.domain.SavingsAccountAssembler;
@@ -169,6 +172,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
checkClientOrGroupActive(account);
account.modifyApplication(command, changes);
account.validateNewApplicationState(DateUtils.getLocalDateOfTenant());
account.validateAccountValuesWithProduct();
if (!changes.isEmpty()) {
@@ -427,4 +431,21 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
}
}
}
@Override
public Long createActiveApplication(final SavingsAccountDataDTO savingsAccountDataDTO) {
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsAccountDataDTO.getClient(),savingsAccountDataDTO.getGroup(),
savingsAccountDataDTO.getSavingsProduct(),savingsAccountDataDTO.getApplicationDate(),savingsAccountDataDTO.getAppliedBy());
account.approveAndActivateApplication(savingsAccountDataDTO.getApplicationDate().toDate(), savingsAccountDataDTO.getAppliedBy(), savingsAccountDataDTO.getFmt());
this.savingAccountRepository.save(account);
if (account.isAccountNumberRequiresAutoGeneration()) {
final AccountNumberGenerator accountNoGenerator = this.accountIdentifierGeneratorFactory
.determineSavingsAccountNoGenerator(account.getId());
account.updateAccountNo(accountNoGenerator.generate());
this.savingAccountRepository.save(account);
}
return account.getId();
}
}
@@ -109,6 +109,14 @@ public class SavingsEnumerations {
optionData = new SavingsAccountTransactionEnumData(SavingsAccountTransactionType.WAIVE_CHARGES.getValue().longValue(),
SavingsAccountTransactionType.WAIVE_CHARGES.getCode(), "Waive Charge");
break;
case WRITTEN_OFF:
optionData = new SavingsAccountTransactionEnumData(SavingsAccountTransactionType.WRITTEN_OFF.getValue().longValue(),
SavingsAccountTransactionType.WRITTEN_OFF.getCode(), "writtenoff");
break;
case OVERDRAFT_INTEREST:
optionData = new SavingsAccountTransactionEnumData(SavingsAccountTransactionType.OVERDRAFT_INTEREST.getValue().longValue(),
SavingsAccountTransactionType.OVERDRAFT_INTEREST.getCode(), "Overdraft Interest");
break;
}
return optionData;
}
@@ -14,6 +14,8 @@ public interface SavingsProductReadPlatformService {
Collection<SavingsProductData> retrieveAll();
Collection<SavingsProductData> retrieveAllForLookup();
Collection<SavingsProductData> retrieveAllForLookupByType(boolean isOverdraftType);
SavingsProductData retrieveOne(Long productId);
@@ -88,6 +88,8 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
// sqlBuilder.append("sp.withdrawal_fee_amount as withdrawalFeeAmount,");
// sqlBuilder.append("sp.withdrawal_fee_type_enum as withdrawalFeeTypeEnum, ");
sqlBuilder.append("sp.withdrawal_fee_for_transfer as withdrawalFeeForTransfers, ");
sqlBuilder.append("sp.allow_overdraft as allowOverdraft, ");
sqlBuilder.append("sp.overdraft_limit as overdraftLimit, ");
// sqlBuilder.append("sp.annual_fee_amount as annualFeeAmount,");
// sqlBuilder.append("sp.annual_fee_on_month as annualFeeOnMonth, ");
// sqlBuilder.append("sp.annual_fee_on_day as annualFeeOnDay, ");
@@ -158,7 +160,8 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
}
*/
final boolean withdrawalFeeForTransfers = rs.getBoolean("withdrawalFeeForTransfers");
final boolean allowOverdraft = rs.getBoolean("allowOverdraft");
final BigDecimal overdraftLimit = rs.getBigDecimal("overdraftLimit");
/* final BigDecimal annualFeeAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "annualFeeAmount");
MonthDay annualFeeOnMonthDay = null;
@@ -170,7 +173,7 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
*/
return SavingsProductData.instance(id, name, shortName, description, currency, nominalAnnualInterestRate, compoundingInterestPeriodType,
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, accountingRuleType);
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, accountingRuleType,allowOverdraft,overdraftLimit);
}
}
@@ -189,4 +192,12 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
return SavingsProductData.lookup(id, name);
}
}
@Override
public Collection<SavingsProductData> retrieveAllForLookupByType(boolean isOverdraftType) {
final String sql = "select " + this.savingsProductLookupsRowMapper.schema() + " where sp.allow_overdraft=?";
return this.jdbcTemplate.query(sql, this.savingsProductLookupsRowMapper,isOverdraftType);
}
}