From 69861ba62444d7f19f0b9109803c3d9a039ae330 Mon Sep 17 00:00:00 2001 From: Pramod Nuthakki Date: Tue, 25 Feb 2014 13:50:04 +0530 Subject: [PATCH] MIFOSX-931 - added current account --- .../core_db/V148__overdraft_changes.sql | 14 ++ .../common/AccountingConstants.java | 9 +- .../data/SavingsTransactionDTO.java | 13 +- .../service/AccountingProcessorHelper.java | 3 +- ...ashBasedAccountingProcessorForSavings.java | 42 ++++- ...AccountMappingFromApiJsonDeserializer.java | 15 ++ ...AccountMappingReadPlatformServiceImpl.java | 6 + ...ccountMappingWritePlatformServiceImpl.java | 12 ++ ...avingsProductToGLAccountMappingHelper.java | 21 ++- .../charge/domain/ChargeTimeType.java | 16 +- ...ChargeDropdownReadPlatformServiceImpl.java | 3 +- .../charge/service/ChargeEnumerations.java | 3 + .../client/api/ClientApiConstants.java | 5 +- .../portfolio/client/data/ClientData.java | 34 ++-- .../client/data/ClientDataValidator.java | 10 ++ .../portfolio/client/domain/Client.java | 41 ++++- .../ClientActiveForUpdateException.java | 11 ++ .../InvalidClientSavingProductException.java | 21 +++ .../ClientReadPlatformServiceImpl.java | 34 +++- ...WritePlatformServiceJpaRepositoryImpl.java | 60 +++++++- .../SavingsAccountTransactionType.java | 18 ++- .../savings/SavingsApiConstants.java | 10 +- .../savings/data/SavingsAccountData.java | 26 +++- .../savings/data/SavingsAccountDataDTO.java | 52 +++++++ .../data/SavingsAccountDataValidator.java | 21 +++ .../SavingsAccountTransactionEnumData.java | 19 +++ .../savings/data/SavingsProductData.java | 29 +++- .../data/SavingsProductDataValidator.java | 56 ++++++- .../savings/domain/SavingsAccount.java | 145 ++++++++++++++++-- .../domain/SavingsAccountAssembler.java | 66 +++++++- .../savings/domain/SavingsAccountCharge.java | 4 + .../domain/SavingsAccountChargeAssembler.java | 26 ++++ .../domain/SavingsAccountTransaction.java | 21 +++ .../savings/domain/SavingsProduct.java | 60 +++++++- .../domain/SavingsProductAssembler.java | 14 +- ...SavingsAccountReadPlatformServiceImpl.java | 16 +- ...pplicationProcessWritePlatformService.java | 3 + ...WritePlatformServiceJpaRepositoryImpl.java | 21 +++ .../savings/service/SavingsEnumerations.java | 8 + .../SavingsProductReadPlatformService.java | 2 + ...SavingsProductReadPlatformServiceImpl.java | 15 +- 41 files changed, 921 insertions(+), 84 deletions(-) create mode 100755 mifosng-db/migrations/core_db/V148__overdraft_changes.sql create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/exception/ClientActiveForUpdateException.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/exception/InvalidClientSavingProductException.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataDTO.java diff --git a/mifosng-db/migrations/core_db/V148__overdraft_changes.sql b/mifosng-db/migrations/core_db/V148__overdraft_changes.sql new file mode 100755 index 000000000..c9649a162 --- /dev/null +++ b/mifosng-db/migrations/core_db/V148__overdraft_changes.sql @@ -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`); \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingConstants.java index eafd1c9fd..d2753cec2 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingConstants.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingConstants.java @@ -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; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/SavingsTransactionDTO.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/SavingsTransactionDTO.java index dc0f50683..ad0797010 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/SavingsTransactionDTO.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/SavingsTransactionDTO.java @@ -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 feePayments, final List penaltyPayments) { + final List feePayments, final List 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; + } + } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccountingProcessorHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccountingProcessorHelper.java index 4bf1e82ed..0b350d1ea 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccountingProcessorHelper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccountingProcessorHelper.java @@ -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 feePayments = new ArrayList(); final List penaltyPayments = new ArrayList(); @@ -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); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/CashBasedAccountingProcessorForSavings.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/CashBasedAccountingProcessorForSavings.java index 07991cbd4..ad50c3bf7 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/CashBasedAccountingProcessorForSavings.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/CashBasedAccountingProcessorForSavings.java @@ -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 feePayments = savingsTransactionDTO.getFeePayments(); final List 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); + } } } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/serialization/ProductToGLAccountMappingFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/serialization/ProductToGLAccountMappingFromApiJsonDeserializer.java index 7aa16db63..f99265379 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/serialization/ProductToGLAccountMappingFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/serialization/ProductToGLAccountMappingFromApiJsonDeserializer.java @@ -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); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java index 3ac53c404..4e7736e72 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java @@ -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); } } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java index 3b8643f53..5f78d16bd 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java @@ -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, diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/SavingsProductToGLAccountMappingHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/SavingsProductToGLAccountMappingHelper.java index 02b426f91..33f86a60e 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/SavingsProductToGLAccountMappingHelper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/SavingsProductToGLAccountMappingHelper.java @@ -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(), diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/domain/ChargeTimeType.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/domain/ChargeTimeType.java index 3f8d11749..793dec74f 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/domain/ChargeTimeType.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/domain/ChargeTimeType.java @@ -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()); + } + + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeDropdownReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeDropdownReadPlatformServiceImpl.java index d8bcd7ca6..6367220a3 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeDropdownReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeDropdownReadPlatformServiceImpl.java @@ -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)); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeEnumerations.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeEnumerations.java index c3a6daaaf..aaa72766a 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeEnumerations.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeEnumerations.java @@ -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; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientApiConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientApiConstants.java index c038651b9..401cd6eb9 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientApiConstants.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientApiConstants.java @@ -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 CLIENT_CREATE_REQUEST_DATA_PARAMETERS = new HashSet(Arrays.asList(localeParamName, dateFormatParamName, groupIdParamName, accountNoParamName, externalIdParamName, mobileNoParamName, firstnameParamName, middlenameParamName, lastnameParamName, fullnameParamName, officeIdParamName, activeParamName, activationDateParamName, - staffIdParamName,submittedOnDateParamName)); + staffIdParamName,submittedOnDateParamName,savingsProductIdParamName)); public static final Set CLIENT_UPDATE_REQUEST_DATA_PARAMETERS = new HashSet(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 diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientData.java index b7a64e82c..defa0b860 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientData.java @@ -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 { private final Long staffId; private final String staffName; private final ClientTimelineData timeline; + + private final Long savingsProductId; + private final String savingsProductName; // associations private final Collection groups; @@ -58,11 +62,13 @@ final public class ClientData implements Comparable { private final Collection staffOptions; @SuppressWarnings("unused") private final Collection closureReasons; + private final Collection savingProductOptions; public static ClientData template(final Long officeId, final LocalDate joinedDate, final Collection officeOptions, - final Collection staffOptions, final Collection closureReasons) { + final Collection staffOptions, final Collection closureReasons, + final Collection 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.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.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 { 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 allowedOffices, final Collection groups, - final Collection staffOptions, final Collection closureReasons,final ClientTimelineData timeline) { + final Collection staffOptions, final Collection closureReasons,final ClientTimelineData timeline, + final Collection 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 { this.closureReasons = closureReasons; this.timeline = timeline; + this.savingProductOptions = savingProductOptions; + this.savingsProductId = savingsProductId; + this.savingsProductName = savingsProductName; } public Long id() { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientDataValidator.java index 02fc6b67b..6d0d1b769 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientDataValidator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientDataValidator.java @@ -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; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/Client.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/Client.java index c4f7cc318..9e119c2e6 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/Client.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/Client.java @@ -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 { @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 { } 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 { 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 { } this.staff = staff; + this.savingsProduct = savingsProduct; deriveDisplayName(); validate(); @@ -394,6 +400,11 @@ public final class Client extends AbstractPersistable { 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 { } 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; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/exception/ClientActiveForUpdateException.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/exception/ClientActiveForUpdateException.java new file mode 100755 index 000000000..f78c38eda --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/exception/ClientActiveForUpdateException.java @@ -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); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/exception/InvalidClientSavingProductException.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/exception/InvalidClientSavingProductException.java new file mode 100755 index 000000000..f148f44f0 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/exception/InvalidClientSavingProductException.java @@ -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); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformServiceImpl.java index c09301880..07a4c847e 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformServiceImpl.java @@ -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 paginationHelper = new PaginationHelper(); 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 offices = this.officeReadPlatformService.retrieveAllOfficesForDropdown(); + + final Collection savingsProductDatas = this.savingsProductReadPlatformService.retrieveAllForLookupByType(true); + Collection 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 closureReasons = new ArrayList( this.codeValueReadPlatformService.retrieveCodeValuesByCode(clientClosureReason)); - return ClientData.template(null, null, null, null, closureReasons); + return ClientData.template(null, null, null, null, closureReasons,null); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java index ac800508c..d3a1b3306 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java @@ -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 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); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsAccountTransactionType.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsAccountTransactionType.java index 4cb3b6105..28b196dcb 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsAccountTransactionType.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsAccountTransactionType.java @@ -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(); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsApiConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsApiConstants.java index b74eaf285..b0a455e80 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsApiConstants.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsApiConstants.java @@ -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 diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountData.java index 39d0e179a..aa24cf3dc 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountData.java @@ -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 productOptions = null; final Collection 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 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 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 interestCalculationTypeOptions, final Collection interestCalculationDaysInYearTypeOptions, final Collection lockinPeriodFrequencyTypeOptions, final Collection withdrawalFeeTypeOptions, - final Collection charges, final Collection chargeOptions) { + final Collection charges, final Collection 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() { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataDTO.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataDTO.java new file mode 100755 index 000000000..9ac752af7 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataDTO.java @@ -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; + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataValidator.java index 561be8757..73e6e188d 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataValidator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataValidator.java @@ -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 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(); + } + + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountTransactionEnumData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountTransactionEnumData.java index 7b03124cf..90321ffe9 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountTransactionEnumData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountTransactionEnumData.java @@ -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; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsProductData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsProductData.java index 3704bf9b8..d40fb769b 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsProductData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsProductData.java @@ -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 charges = null; final Collection feeToIncomeAccountMappings = null; final Collection 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 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 accountingMappings = null; final Collection 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 accountingMappings = null; final Collection paymentChannelToFundSourceMappings = null; + final boolean allowOverdraft = false; + final BigDecimal overdraftLimit = null; final Collection currencyOptions = null; final Collection interestCompoundingPeriodTypeOptions = null; @@ -241,6 +249,8 @@ public class SavingsProductData { final Collection penaltyOptions = null; final Collection feeToIncomeAccountMappings = null; final Collection 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> accountingMappingOptions, final Collection charges, final Collection chargeOptions, final Collection penaltyOptions, final Collection feeToIncomeAccountMappings, - final Collection penaltyToIncomeAccountMappings) { + final Collection 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() { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsProductDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsProductDataValidator.java index 9668e94ed..7ca576e1c 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsProductDataValidator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsProductDataValidator.java @@ -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(); + } + + } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java index 34da5d819..0aabd02ab 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java @@ -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 { @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 { final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType, final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType, - final boolean withdrawalFeeApplicableForTransfer, final Set savingsAccountCharges) { + final boolean withdrawalFeeApplicableForTransfer, final Set 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 { final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType, final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType, - final boolean withdrawalFeeApplicableForTransfer, final Set savingsAccountCharges) { + final boolean withdrawalFeeApplicableForTransfer, final Set 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 { } this.summary = new SavingsAccountSummary(); + this.allowOverdraft = allowOverdraft; + this.overdraftLimit = overdraftLimit; } /** @@ -496,24 +509,57 @@ public class SavingsAccount extends AbstractPersistable { Money runningBalance = openingAccountBalance.copy(); - final List accountTransactionsSorted = retreiveListOfTransactions(); - + List 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 { 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 { final List dataValidationErrors = new ArrayList(); 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 { 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 { // 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 { //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 { public Set charges() { return (this.charges == null) ? new HashSet() : this.charges; } + + public void validateAccountValuesWithProduct() { + + final List dataValidationErrors = new ArrayList(); + 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);} + } + + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountAssembler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountAssembler.java index 52b285a1d..e1c1952d8 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountAssembler.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountAssembler.java @@ -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 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 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); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountCharge.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountCharge.java index 61d7cd9e4..ecd0c22f8 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountCharge.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountCharge.java @@ -614,6 +614,10 @@ public class SavingsAccountCharge extends AbstractPersistable { 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(); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountChargeAssembler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountChargeAssembler.java index 86e70f75f..7bc6976c7 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountChargeAssembler.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountChargeAssembler.java @@ -126,6 +126,32 @@ public class SavingsAccountChargeAssembler { return savingsAccountCharges; } + public Set fromSavingsProduct(final SavingsProduct savingsProduct) { + + final Set savingsAccountCharges = new HashSet(); + Set 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 charges, final String productCurrencyCode) { final List dataValidationErrors = new ArrayList(); final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountTransaction.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountTransaction.java index 8aab38eaf..1d88dd62a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountTransaction.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountTransaction.java @@ -89,6 +89,9 @@ public final class SavingsAccountTransaction extends AbstractPersistable { @LazyCollection(LazyCollectionOption.FALSE) @OneToMany(cascade = CascadeType.ALL, mappedBy = "savingsAccountTransaction", orphanRemoval = true) private final Set savingsAccountChargesPaid = new HashSet(); + + @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 { 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 { 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 { return this.savingsAccountChargesPaid; } + + public void updateOverdraftAmount(BigDecimal overdraftAmount) { + this.overdraftAmount = overdraftAmount; + } + + public Money getOverdraftAmount(final MonetaryCurrency currency) { + return Money.of(currency, this.overdraftAmount); + } + + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProduct.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProduct.java index 7657ded94..5ff37f00a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProduct.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProduct.java @@ -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 { @ManyToMany @JoinTable(name = "m_savings_product_charge", joinColumns = @JoinColumn(name = "savings_product_id"), inverseJoinColumns = @JoinColumn(name = "charge_id")) private Set 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 charges) { + final boolean withdrawalFeeApplicableForTransfer, final AccountingRuleType accountingRuleType, final Set 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 { 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 charges) { + final boolean withdrawalFeeApplicableForTransfer, final AccountingRuleType accountingRuleType, final Set charges, + final boolean allowOverdraft,final BigDecimal overdraftLimit) { this.name = name; this.shortName = shortName; @@ -192,6 +203,8 @@ public class SavingsProduct extends AbstractPersistable { validateLockinDetails(); //validateWithdrawalFeeDetails(); //validateAnnualFeeDetails(); + this.allowOverdraft = allowOverdraft; + this.overdraftLimit = overdraftLimit; } public MonetaryCurrency currency() { @@ -411,6 +424,23 @@ public class SavingsProduct extends AbstractPersistable { } } + 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 { } return updated; } + + + public BigDecimal overdraftLimit() { + return this.overdraftLimit; + } + + + public boolean isWithdrawalFeeApplicableForTransfer() { + return this.withdrawalFeeApplicableForTransfer; + } + + + public boolean isAllowOverdraft() { + return this.allowOverdraft; + } + + + public Set charges() { + return this.charges; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProductAssembler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProductAssembler.java index 7a724a642..3124326db 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProductAssembler.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProductAssembler.java @@ -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 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 assembleListOfSavingsProductCharges(final JsonCommand command, final String savingsProductCurrencyCode) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java index 8fba2e734..833a02288 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java @@ -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); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsApplicationProcessWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsApplicationProcessWritePlatformService.java index c68919cc5..2f1b4d7d4 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsApplicationProcessWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsApplicationProcessWritePlatformService.java @@ -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); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java index defc80366..5735aeb43 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java @@ -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(); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsEnumerations.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsEnumerations.java index 1f8e8945d..01435de7f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsEnumerations.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsEnumerations.java @@ -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; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsProductReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsProductReadPlatformService.java index 538c943e5..e770ab4dd 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsProductReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsProductReadPlatformService.java @@ -14,6 +14,8 @@ public interface SavingsProductReadPlatformService { Collection retrieveAll(); Collection retrieveAllForLookup(); + + Collection retrieveAllForLookupByType(boolean isOverdraftType); SavingsProductData retrieveOne(Long productId); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsProductReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsProductReadPlatformServiceImpl.java index d130ac5aa..1e8f2a06d 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsProductReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsProductReadPlatformServiceImpl.java @@ -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 retrieveAllForLookupByType(boolean isOverdraftType) { + final String sql = "select " + this.savingsProductLookupsRowMapper.schema() + " where sp.allow_overdraft=?"; + + return this.jdbcTemplate.query(sql, this.savingsProductLookupsRowMapper,isOverdraftType); + + } } \ No newline at end of file