moving all bugf fixes and improvemnets from 1.10.3 to develop branch
This commit is contained in:
@@ -9159,8 +9159,8 @@ Request Body:
|
||||
"toDate": "25 October 2013",
|
||||
"repaymentsRescheduledTo": "26 October 2013",
|
||||
"offices": [
|
||||
"officeId":"1",
|
||||
"officeId":"2"
|
||||
{"officeId":"1"},
|
||||
{"officeId":"2"}
|
||||
]
|
||||
}
|
||||
</code>
|
||||
@@ -14345,8 +14345,10 @@ POST savingsaccounts/1/charges/2?command=paycharge
|
||||
Content-Type: application/json
|
||||
Request Body:
|
||||
{
|
||||
"dateFormat": "dd MMMM yyyy",
|
||||
"locale": "en",
|
||||
"amount": "60",
|
||||
"dueDate": "12 September 2013"
|
||||
}
|
||||
</code>
|
||||
<code class="method-response">
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
INSERT INTO `job` (`name`, `display_name`, `cron_expression`, `create_time`, `task_priority`, `group_name`, `previous_run_start_time`, `next_run_time`, `job_key`, `initializing_errorlog`, `is_active`, `currently_running`, `updates_allowed`, `scheduler_group`, `is_misfired`) VALUES ('Pay Due Savings Charges', 'Pay Due Savings Charges', '0 0 12 * * ?', '2013-09-23 00:00:00', 5, NULL, NULL, NULL, 'Pay Due Savings ChargesJobDetail1 _ DEFAULT', NULL, 1, 0, 1, 0, 0);
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
/***Set defaults for income from Penalties for existing Saving Products**/
|
||||
INSERT INTO `acc_product_mapping` (`gl_account_id`,`product_id`,`product_type`,`payment_type`,`charge_id`,`financial_account_type`)
|
||||
select mapping.gl_account_id,mapping.product_id,mapping.product_type,mapping.payment_type,mapping.charge_id, 5
|
||||
from acc_product_mapping mapping
|
||||
where mapping.financial_account_type = 4 and mapping.product_type=2;
|
||||
@@ -0,0 +1,25 @@
|
||||
ALTER TABLE `m_savings_account_charge`
|
||||
ADD COLUMN `is_active` TINYINT(1) NOT NULL DEFAULT '1' AFTER `waived`;
|
||||
|
||||
ALTER TABLE `m_savings_account`
|
||||
DROP COLUMN `withdrawal_fee_amount`,
|
||||
DROP COLUMN `withdrawal_fee_type_enum`;
|
||||
|
||||
ALTER TABLE `m_savings_account_charge`
|
||||
ADD COLUMN `fee_on_month` SMALLINT(5) NULL DEFAULT NULL AFTER `due_for_collection_as_of_date`,
|
||||
ADD COLUMN `fee_on_day` SMALLINT(5) NULL DEFAULT NULL AFTER `fee_on_month`;
|
||||
|
||||
ALTER TABLE `m_savings_account_charge`
|
||||
CHANGE COLUMN `due_for_collection_as_of_date` `charge_due_date` DATE NULL DEFAULT NULL AFTER `charge_time_enum`;
|
||||
|
||||
|
||||
ALTER TABLE `m_savings_account`
|
||||
DROP COLUMN `annual_fee_amount`,
|
||||
DROP COLUMN `annual_fee_on_month`,
|
||||
DROP COLUMN `annual_fee_on_day`,
|
||||
DROP COLUMN `annual_fee_next_due_date`;
|
||||
|
||||
ALTER TABLE `m_savings_product`
|
||||
DROP COLUMN `annual_fee_amount`,
|
||||
DROP COLUMN `annual_fee_on_month`,
|
||||
DROP COLUMN `annual_fee_on_day`;
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/***Set defaults for income from Penalties for existing Saving Products**/
|
||||
ALTER TABLE `m_loan_transaction`
|
||||
ADD COLUMN `overpayment_portion_derived` DECIMAL(19,6) NULL DEFAULT NULL AFTER `penalty_charges_portion_derived`;
|
||||
|
||||
/**Add dummy liability account if organization already has a loan product with accounting enabled**/
|
||||
INSERT INTO `acc_gl_account` (`name`, `hierarchy`, `gl_code`, `classification_enum`,`description`)
|
||||
select 'Loan Overpayments (Temp)', '.', '22000-Temp', 2,'Temporary account to track Loan overpayments Liabilities'
|
||||
FROM m_product_loan WHERE accounting_type != 1
|
||||
limit 1;
|
||||
|
||||
|
||||
/**Map a liability account for every loan which has accounting enabled**/
|
||||
INSERT INTO `acc_product_mapping` (`gl_account_id`,`product_id`,`product_type`,`financial_account_type`)
|
||||
select (select id from acc_gl_account where classification_enum=2 and account_usage=1 LIMIT 1), mapping.product_id, mapping.product_type, 11
|
||||
from acc_product_mapping mapping
|
||||
where mapping.financial_account_type = 2 and mapping.product_type=1;
|
||||
+15
-12
@@ -13,7 +13,7 @@ public class AccountingConstants {
|
||||
/*** Accounting placeholders for cash based accounting for loan products ***/
|
||||
public static enum CASH_ACCOUNTS_FOR_LOAN {
|
||||
FUND_SOURCE(1), LOAN_PORTFOLIO(2), INTEREST_ON_LOANS(3), INCOME_FROM_FEES(4), INCOME_FROM_PENALTIES(5), LOSSES_WRITTEN_OFF(6), TRANSFERS_SUSPENSE(
|
||||
10);
|
||||
10), OVERPAYMENT(11);
|
||||
|
||||
private final Integer value;
|
||||
|
||||
@@ -46,7 +46,7 @@ public class AccountingConstants {
|
||||
/*** Accounting placeholders for accrual based accounting for loan products ***/
|
||||
public static enum ACCRUAL_ACCOUNTS_FOR_LOAN {
|
||||
FUND_SOURCE(1), LOAN_PORTFOLIO(2), INTEREST_ON_LOANS(3), INCOME_FROM_FEES(4), INCOME_FROM_PENALTIES(5), LOSSES_WRITTEN_OFF(6), INTEREST_RECEIVABLE(
|
||||
7), FEES_RECEIVABLE(8), PENALTIES_RECEIVABLE(9), TRANSFERS_SUSPENSE(10);
|
||||
7), FEES_RECEIVABLE(8), PENALTIES_RECEIVABLE(9), TRANSFERS_SUSPENSE(10), OVERPAYMENT(11);
|
||||
|
||||
private final Integer value;
|
||||
|
||||
@@ -83,12 +83,12 @@ public class AccountingConstants {
|
||||
***/
|
||||
public static enum LOAN_PRODUCT_ACCOUNTING_PARAMS {
|
||||
FUND_SOURCE("fundSourceAccountId"), LOAN_PORTFOLIO("loanPortfolioAccountId"), INTEREST_ON_LOANS("interestOnLoanAccountId"), INCOME_FROM_FEES(
|
||||
"incomeFromFeeAccountId"), INCOME_FROM_PENALTIES("incomeFromPenaltyAccountId"), LOSSES_WRITTEN_OFF("writeOffAccountId"), INTEREST_RECEIVABLE(
|
||||
"receivableInterestAccountId"), FEES_RECEIVABLE("receivableFeeAccountId"), PENALTIES_RECEIVABLE(
|
||||
"receivablePenaltyAccountId"), TRANSFERS_SUSPENSE("transfersInSuspenseAccountId"), PAYMENT_CHANNEL_FUND_SOURCE_MAPPING(
|
||||
"paymentChannelToFundSourceMappings"), PAYMENT_TYPE("paymentTypeId"), FEE_INCOME_ACCOUNT_MAPPING(
|
||||
"feeToIncomeAccountMappings"), PENALTY_INCOME_ACCOUNT_MAPPING("penaltyToIncomeAccountMappings"), CHARGE_ID("chargeId"), INCOME_ACCOUNT_ID(
|
||||
"incomeAccountId");
|
||||
"incomeFromFeeAccountId"), INCOME_FROM_PENALTIES("incomeFromPenaltyAccountId"), LOSSES_WRITTEN_OFF("writeOffAccountId"), OVERPAYMENT(
|
||||
"overpaymentLiabilityAccountId"), INTEREST_RECEIVABLE("receivableInterestAccountId"), FEES_RECEIVABLE(
|
||||
"receivableFeeAccountId"), PENALTIES_RECEIVABLE("receivablePenaltyAccountId"), TRANSFERS_SUSPENSE(
|
||||
"transfersInSuspenseAccountId"), PAYMENT_CHANNEL_FUND_SOURCE_MAPPING("paymentChannelToFundSourceMappings"), PAYMENT_TYPE(
|
||||
"paymentTypeId"), FEE_INCOME_ACCOUNT_MAPPING("feeToIncomeAccountMappings"), PENALTY_INCOME_ACCOUNT_MAPPING(
|
||||
"penaltyToIncomeAccountMappings"), CHARGE_ID("chargeId"), INCOME_ACCOUNT_ID("incomeAccountId");
|
||||
|
||||
private final String value;
|
||||
|
||||
@@ -108,7 +108,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), TRANSFERS_SUSPENSE(10);
|
||||
SAVINGS_REFERENCE(1), SAVINGS_CONTROL(2), INTEREST_ON_SAVINGS(3), INCOME_FROM_FEES(4), INCOME_FROM_PENALTIES(5), TRANSFERS_SUSPENSE(
|
||||
10);
|
||||
|
||||
private final Integer value;
|
||||
|
||||
@@ -144,9 +145,11 @@ public class AccountingConstants {
|
||||
***/
|
||||
public static enum SAVINGS_PRODUCT_ACCOUNTING_PARAMS {
|
||||
SAVINGS_REFERENCE("savingsReferenceAccountId"), SAVINGS_CONTROL("savingsControlAccountId"), INCOME_FROM_FEES(
|
||||
"incomeFromFeeAccountId"), INTEREST_ON_SAVINGS("interestOnSavingsAccountId"), PAYMENT_CHANNEL_FUND_SOURCE_MAPPING(
|
||||
"paymentChannelToFundSourceMappings"), PAYMENT_TYPE("paymentTypeId"), FUND_SOURCE("fundSourceAccountId"), TRANSFERS_SUSPENSE(
|
||||
"transfersInSuspenseAccountId");
|
||||
"incomeFromFeeAccountId"), INCOME_FROM_PENALTIES("incomeFromPenaltyAccountId"), INTEREST_ON_SAVINGS(
|
||||
"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");
|
||||
|
||||
private final String value;
|
||||
|
||||
|
||||
+7
@@ -69,6 +69,13 @@ public class AccountingDropdownReadPlatformServiceImpl implements AccountingDrop
|
||||
expenseAccountOptions = null;
|
||||
}
|
||||
accountOptions.put("expenseAccountOptions", expenseAccountOptions);
|
||||
|
||||
List<GLAccountData> liabilityAccountOptions = this.accountReadPlatformService
|
||||
.retrieveAllEnabledDetailGLAccounts(GLAccountType.LIABILITY);
|
||||
if (liabilityAccountOptions.isEmpty()) {
|
||||
liabilityAccountOptions = null;
|
||||
}
|
||||
accountOptions.put("liabilityAccountOptions", liabilityAccountOptions);
|
||||
return accountOptions;
|
||||
}
|
||||
|
||||
|
||||
+8
-2
@@ -27,6 +27,7 @@ public class LoanTransactionDTO {
|
||||
private final BigDecimal interest;
|
||||
private final BigDecimal fees;
|
||||
private final BigDecimal penalties;
|
||||
private final BigDecimal overPayment;
|
||||
|
||||
/*** Boolean values determines if the transaction is reversed ***/
|
||||
private final boolean reversed;
|
||||
@@ -37,8 +38,8 @@ public class LoanTransactionDTO {
|
||||
|
||||
public LoanTransactionDTO(final Long officeId, final Long paymentTypeId, final String transactionId, final Date transactionDate,
|
||||
final LoanTransactionEnumData transactionType, final BigDecimal amount, final BigDecimal principal, final BigDecimal interest,
|
||||
final BigDecimal fees, final BigDecimal penalties, final boolean reversed, final List<ChargePaymentDTO> feePayments,
|
||||
final List<ChargePaymentDTO> penaltyPayments) {
|
||||
final BigDecimal fees, final BigDecimal penalties, final BigDecimal overPayment, final boolean reversed,
|
||||
final List<ChargePaymentDTO> feePayments, final List<ChargePaymentDTO> penaltyPayments) {
|
||||
this.paymentTypeId = paymentTypeId;
|
||||
this.transactionId = transactionId;
|
||||
this.transactionDate = transactionDate;
|
||||
@@ -51,6 +52,7 @@ public class LoanTransactionDTO {
|
||||
this.transactionType = transactionType;
|
||||
this.feePayments = feePayments;
|
||||
this.penaltyPayments = penaltyPayments;
|
||||
this.overPayment = overPayment;
|
||||
this.officeId = officeId;
|
||||
}
|
||||
|
||||
@@ -90,6 +92,10 @@ public class LoanTransactionDTO {
|
||||
return this.penalties;
|
||||
}
|
||||
|
||||
public BigDecimal getOverPayment() {
|
||||
return this.overPayment;
|
||||
}
|
||||
|
||||
public boolean isReversed() {
|
||||
return this.reversed;
|
||||
}
|
||||
|
||||
+17
-1
@@ -7,6 +7,7 @@ package org.mifosplatform.accounting.journalentry.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionEnumData;
|
||||
|
||||
@@ -23,14 +24,21 @@ public class SavingsTransactionDTO {
|
||||
/*** Boolean values determines if the transaction is reversed ***/
|
||||
private final boolean reversed;
|
||||
|
||||
/** Breakdowns of fees and penalties this Transaction pays **/
|
||||
private final List<ChargePaymentDTO> penaltyPayments;
|
||||
private final List<ChargePaymentDTO> feePayments;
|
||||
|
||||
public SavingsTransactionDTO(final Long officeId, final Long paymentTypeId, final String transactionId, final Date transactionDate,
|
||||
final SavingsAccountTransactionEnumData transactionType, final BigDecimal amount, final boolean reversed) {
|
||||
final SavingsAccountTransactionEnumData transactionType, final BigDecimal amount, final boolean reversed,
|
||||
final List<ChargePaymentDTO> feePayments, final List<ChargePaymentDTO> penaltyPayments) {
|
||||
this.paymentTypeId = paymentTypeId;
|
||||
this.transactionId = transactionId;
|
||||
this.transactionDate = transactionDate;
|
||||
this.amount = amount;
|
||||
this.reversed = reversed;
|
||||
this.transactionType = transactionType;
|
||||
this.feePayments = feePayments;
|
||||
this.penaltyPayments = penaltyPayments;
|
||||
this.officeId = officeId;
|
||||
}
|
||||
|
||||
@@ -62,4 +70,12 @@ public class SavingsTransactionDTO {
|
||||
return this.reversed;
|
||||
}
|
||||
|
||||
public List<ChargePaymentDTO> getPenaltyPayments() {
|
||||
return this.penaltyPayments;
|
||||
}
|
||||
|
||||
public List<ChargePaymentDTO> getFeePayments() {
|
||||
return this.feePayments;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+112
-8
@@ -32,6 +32,7 @@ import org.mifosplatform.accounting.journalentry.exception.JournalEntryInvalidEx
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.PortfolioProductType;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAccountMapping;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAccountMappingRepository;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.exception.ProductToGLAccountMappingNotFoundException;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.organisation.office.domain.Office;
|
||||
@@ -81,31 +82,33 @@ public class AccountingProcessorHelper {
|
||||
final BigDecimal interest = (BigDecimal) map.get("interestPortion");
|
||||
final BigDecimal fees = (BigDecimal) map.get("feeChargesPortion");
|
||||
final BigDecimal penalties = (BigDecimal) map.get("penaltyChargesPortion");
|
||||
final BigDecimal overPayments = (BigDecimal) map.get("overPaymentPortion");
|
||||
final boolean reversed = (Boolean) map.get("reversed");
|
||||
final Long paymentTypeId = (Long) map.get("paymentTypeId");
|
||||
|
||||
final List<ChargePaymentDTO> feePayments = new ArrayList<ChargePaymentDTO>();
|
||||
final List<ChargePaymentDTO> penaltyPayments = new ArrayList<ChargePaymentDTO>();
|
||||
final List<ChargePaymentDTO> feePaymentDetails = new ArrayList<ChargePaymentDTO>();
|
||||
final List<ChargePaymentDTO> penaltyPaymentDetails = new ArrayList<ChargePaymentDTO>();
|
||||
// extract charge payment details (if exists)
|
||||
if (map.containsKey("loanChargesPaid")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<Map<String, Object>> loanChargesPaidData = (List<Map<String, Object>>) map.get("loanChargesPaid");
|
||||
for (final Map<String, Object> loanChargePaid : loanChargesPaidData) {
|
||||
final Long chargeId = (Long) loanChargePaid.get("chargeId");
|
||||
final Long loanChargeId = (Long) loanChargePaid.get("chargeId");
|
||||
final Long loanChargeId = (Long) loanChargePaid.get("loanChargeId");
|
||||
final boolean isPenalty = (Boolean) loanChargePaid.get("isPenalty");
|
||||
final BigDecimal chargeAmountPaid = (BigDecimal) loanChargePaid.get("amount");
|
||||
final ChargePaymentDTO chargePaymentDTO = new ChargePaymentDTO(chargeId, loanChargeId, chargeAmountPaid);
|
||||
if (isPenalty) {
|
||||
penaltyPayments.add(chargePaymentDTO);
|
||||
penaltyPaymentDetails.add(chargePaymentDTO);
|
||||
} else {
|
||||
feePayments.add(chargePaymentDTO);
|
||||
feePaymentDetails.add(chargePaymentDTO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final LoanTransactionDTO transaction = new LoanTransactionDTO(transactionOfficeId, paymentTypeId, transactionId,
|
||||
transactionDate, transactionType, amount, principal, interest, fees, penalties, reversed, feePayments, penaltyPayments);
|
||||
transactionDate, transactionType, amount, principal, interest, fees, penalties, overPayments, reversed,
|
||||
feePaymentDetails, penaltyPaymentDetails);
|
||||
|
||||
newLoanTransactions.add(transaction);
|
||||
|
||||
@@ -135,8 +138,28 @@ public class AccountingProcessorHelper {
|
||||
final boolean reversed = (Boolean) map.get("reversed");
|
||||
final Long paymentTypeId = (Long) map.get("paymentTypeId");
|
||||
|
||||
final List<ChargePaymentDTO> feePayments = new ArrayList<ChargePaymentDTO>();
|
||||
final List<ChargePaymentDTO> penaltyPayments = new ArrayList<ChargePaymentDTO>();
|
||||
// extract charge payment details (if exists)
|
||||
if (map.containsKey("savingsChargesPaid")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<Map<String, Object>> savingsChargesPaidData = (List<Map<String, Object>>) map.get("savingsChargesPaid");
|
||||
for (final Map<String, Object> loanChargePaid : savingsChargesPaidData) {
|
||||
final Long chargeId = (Long) loanChargePaid.get("chargeId");
|
||||
final Long loanChargeId = (Long) loanChargePaid.get("savingsChargeId");
|
||||
final boolean isPenalty = (Boolean) loanChargePaid.get("isPenalty");
|
||||
final BigDecimal chargeAmountPaid = (BigDecimal) loanChargePaid.get("amount");
|
||||
final ChargePaymentDTO chargePaymentDTO = new ChargePaymentDTO(chargeId, loanChargeId, chargeAmountPaid);
|
||||
if (isPenalty) {
|
||||
penaltyPayments.add(chargePaymentDTO);
|
||||
} else {
|
||||
feePayments.add(chargePaymentDTO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final SavingsTransactionDTO transaction = new SavingsTransactionDTO(transactionOfficeId, paymentTypeId, transactionId,
|
||||
transactionDate, transactionType, amount, reversed);
|
||||
transactionDate, transactionType, amount, reversed, feePayments, penaltyPayments);
|
||||
|
||||
newSavingsTransactions.add(transaction);
|
||||
|
||||
@@ -378,6 +401,61 @@ public class AccountingProcessorHelper {
|
||||
totalCreditedAmount, totalAmount); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method that creates a pair of related Debits and Credits for
|
||||
* Cash Based accounting.
|
||||
*
|
||||
* The target accounts for debits and credits are switched in case of a
|
||||
* reversal
|
||||
*
|
||||
* @param office
|
||||
* @param accountTypeToBeDebited
|
||||
* Enum of the placeholder GLAccount to be debited
|
||||
* @param accountTypeToBeCredited
|
||||
* Enum of the placeholder of the GLAccount to be credited
|
||||
* @param savingsProductId
|
||||
* @param paymentTypeId
|
||||
* @param loanId
|
||||
* @param transactionId
|
||||
* @param transactionDate
|
||||
* @param amount
|
||||
* @param isReversal
|
||||
*/
|
||||
public void createCashBasedJournalEntriesAndReversalsForSavingsCharges(final Office office, final String currencyCode,
|
||||
final CASH_ACCOUNTS_FOR_SAVINGS accountTypeToBeDebited, final CASH_ACCOUNTS_FOR_SAVINGS accountTypeToBeCredited,
|
||||
final Long savingsProductId, final Long paymentTypeId, final Long loanId, final String transactionId,
|
||||
final Date transactionDate, final BigDecimal totalAmount, final Boolean isReversal,
|
||||
final List<ChargePaymentDTO> chargePaymentDTOs) {
|
||||
// TODO Vishwas: Remove this validation, as and when appropriate Junit
|
||||
// tests are written for accounting
|
||||
/**
|
||||
* Accounting module currently supports a single charge per transaction,
|
||||
* throw an error if this is not the case here so any developers
|
||||
* changing the expected portfolio behavior would also take care of
|
||||
* modifying the accounting code appropriately
|
||||
**/
|
||||
if (chargePaymentDTOs.size() != 1) { throw new PlatformDataIntegrityException(
|
||||
"Recent Portfolio changes w.r.t Charges for Savings have Broken the accounting code",
|
||||
"Recent Portfolio changes w.r.t Charges for Savings have Broken the accounting code"); }
|
||||
ChargePaymentDTO chargePaymentDTO = chargePaymentDTOs.get(0);
|
||||
|
||||
final GLAccount chargeSpecificAccount = getLinkedGLAccountForSavingsCharges(savingsProductId, accountTypeToBeCredited.getValue(),
|
||||
chargePaymentDTO.getChargeId());
|
||||
final GLAccount savingsControlAccount = getLinkedGLAccountForSavingsProduct(savingsProductId, accountTypeToBeDebited.getValue(),
|
||||
paymentTypeId);
|
||||
if (isReversal) {
|
||||
createDebitJournalEntryForSavings(office, currencyCode, chargeSpecificAccount, loanId, transactionId, transactionDate,
|
||||
totalAmount);
|
||||
createCreditJournalEntryForSavings(office, currencyCode, savingsControlAccount, loanId, transactionId, transactionDate,
|
||||
totalAmount);
|
||||
} else {
|
||||
createDebitJournalEntryForSavings(office, currencyCode, savingsControlAccount, loanId, transactionId, transactionDate,
|
||||
totalAmount);
|
||||
createCreditJournalEntryForSavings(office, currencyCode, chargeSpecificAccount, loanId, transactionId, transactionDate,
|
||||
totalAmount);
|
||||
}
|
||||
}
|
||||
|
||||
private void createCreditJournalEntryOrReversalForLoan(final Office office, final String currencyCode, final int accountMappingTypeId,
|
||||
final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate,
|
||||
final BigDecimal amount, final Boolean isReversal) {
|
||||
@@ -438,6 +516,9 @@ public class AccountingProcessorHelper {
|
||||
}
|
||||
}
|
||||
|
||||
if (accountMapping == null) { throw new ProductToGLAccountMappingNotFoundException(PortfolioProductType.LOAN, loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.OVERPAYMENT.toString()); }
|
||||
|
||||
return accountMapping.getGlAccount();
|
||||
}
|
||||
|
||||
@@ -464,6 +545,29 @@ public class AccountingProcessorHelper {
|
||||
return accountMapping.getGlAccount();
|
||||
}
|
||||
|
||||
private GLAccount getLinkedGLAccountForSavingsCharges(final Long savingsProductId, final int accountMappingTypeId, final Long chargeId) {
|
||||
ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(savingsProductId,
|
||||
PortfolioProductType.SAVING.getValue(), accountMappingTypeId);
|
||||
/*****
|
||||
* Get more specific mappings for Charges and penalties (based on the
|
||||
* actual charge /penalty coupled with the loan product). Note the
|
||||
* income from fees and income from penalties placeholder ID would be
|
||||
* the same for both cash and accrual based accounts
|
||||
*****/
|
||||
|
||||
// Vishwas TODO: remove this condition as it should always be true
|
||||
if (accountMappingTypeId == CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_FEES.getValue()
|
||||
|| accountMappingTypeId == CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue()) {
|
||||
final ProductToGLAccountMapping chargeSpecificIncomeAccountMapping = this.accountMappingRepository
|
||||
.findByProductIdAndProductTypeAndFinancialAccountTypeAndChargeId(savingsProductId,
|
||||
PortfolioProductType.SAVING.getValue(), accountMappingTypeId, chargeId);
|
||||
if (chargeSpecificIncomeAccountMapping != null) {
|
||||
accountMapping = chargeSpecificIncomeAccountMapping;
|
||||
}
|
||||
}
|
||||
return accountMapping.getGlAccount();
|
||||
}
|
||||
|
||||
private GLAccount getLinkedGLAccountForSavingsProduct(final Long savingsProductId, final int accountMappingTypeId,
|
||||
final Long paymentTypeId) {
|
||||
ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(savingsProductId,
|
||||
@@ -473,7 +577,7 @@ public class AccountingProcessorHelper {
|
||||
* channels). Note that fund source placeholder ID would be same for
|
||||
* both cash and accrual accounts
|
||||
***/
|
||||
if (accountMappingTypeId == CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue()) {
|
||||
if (accountMappingTypeId == CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue()) {
|
||||
final ProductToGLAccountMapping paymentChannelSpecificAccountMapping = this.accountMappingRepository
|
||||
.findByProductIdAndProductTypeAndFinancialAccountTypeAndPaymentTypeId(savingsProductId,
|
||||
PortfolioProductType.SAVING.getValue(), accountMappingTypeId, paymentTypeId);
|
||||
|
||||
+41
@@ -55,6 +55,11 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
|| loanTransactionDTO.getTransactionType().isChargePayment()) {
|
||||
createJournalEntriesForRepayments(loanDTO, loanTransactionDTO, office);
|
||||
}
|
||||
|
||||
/** Logic for Refunds of Overpayments **/
|
||||
else if (loanTransactionDTO.getTransactionType().isRefund()) {
|
||||
createJournalEntriesForRefund(loanDTO, loanTransactionDTO, office);
|
||||
}
|
||||
/***
|
||||
* Only principal write off affects cash based accounting (interest
|
||||
* and fee write off need not be considered). Debit losses written
|
||||
@@ -103,6 +108,35 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
isReversal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Debit loan Portfolio and credit Fund source for a Disbursement <br/>
|
||||
*
|
||||
* All debits are turned into credits and vice versa in case of disbursement
|
||||
* reversals
|
||||
*
|
||||
*
|
||||
* @param loanDTO
|
||||
* @param loanTransactionDTO
|
||||
* @param office
|
||||
*/
|
||||
private void createJournalEntriesForRefund(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO, final Office office) {
|
||||
// loan properties
|
||||
final Long loanProductId = loanDTO.getLoanProductId();
|
||||
final Long loanId = loanDTO.getLoanId();
|
||||
final String currencyCode = loanDTO.getCurrencyCode();
|
||||
|
||||
// transaction properties
|
||||
final String transactionId = loanTransactionDTO.getTransactionId();
|
||||
final Date transactionDate = loanTransactionDTO.getTransactionDate();
|
||||
final BigDecimal refundAmount = loanTransactionDTO.getAmount();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForLoan(office, currencyCode, CASH_ACCOUNTS_FOR_LOAN.OVERPAYMENT,
|
||||
CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId, paymentTypeId, loanId, transactionId, transactionDate, refundAmount,
|
||||
isReversal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a single Debit to fund source and multiple credits if applicable
|
||||
* (loan portfolio for principal repayments, Interest on loans for interest
|
||||
@@ -125,6 +159,7 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
final BigDecimal interestAmount = loanTransactionDTO.getInterest();
|
||||
final BigDecimal feesAmount = loanTransactionDTO.getFees();
|
||||
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
|
||||
final BigDecimal overPaymentAmount = loanTransactionDTO.getOverPayment();
|
||||
final boolean isReversal = loanTransactionDTO.isReversed();
|
||||
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
|
||||
|
||||
@@ -156,6 +191,12 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
||||
penaltiesAmount, isReversal, loanTransactionDTO.getPenaltyPayments());
|
||||
}
|
||||
|
||||
if (overPaymentAmount != null && !(overPaymentAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, CASH_ACCOUNTS_FOR_LOAN.OVERPAYMENT, loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, overPaymentAmount, isReversal);
|
||||
}
|
||||
|
||||
/*** create a single debit entry (or reversal) for the entire amount **/
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
|
||||
|
||||
+14
-3
@@ -7,9 +7,11 @@ package org.mifosplatform.accounting.journalentry.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.accounting.closure.domain.GLClosure;
|
||||
import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_SAVINGS;
|
||||
import org.mifosplatform.accounting.journalentry.data.ChargePaymentDTO;
|
||||
import org.mifosplatform.accounting.journalentry.data.SavingsDTO;
|
||||
import org.mifosplatform.accounting.journalentry.data.SavingsTransactionDTO;
|
||||
import org.mifosplatform.organisation.office.domain.Office;
|
||||
@@ -39,6 +41,8 @@ public class CashBasedAccountingProcessorForSavings implements AccountingProcess
|
||||
final Long paymentTypeId = savingsTransactionDTO.getPaymentTypeId();
|
||||
final boolean isReversal = savingsTransactionDTO.isReversed();
|
||||
final BigDecimal amount = savingsTransactionDTO.getAmount();
|
||||
final List<ChargePaymentDTO> feePayments = savingsTransactionDTO.getFeePayments();
|
||||
final List<ChargePaymentDTO> penaltyPayments = savingsTransactionDTO.getPenaltyPayments();
|
||||
|
||||
this.helper.checkForBranchClosures(latestGLClosure, transactionDate);
|
||||
|
||||
@@ -68,9 +72,16 @@ public class CashBasedAccountingProcessorForSavings implements AccountingProcess
|
||||
|
||||
/** Handle Fees Deductions and reversals of Fees Deductions **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isFeeDeduction()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL, CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_FEES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
// Is the Charge a penalty?
|
||||
if (penaltyPayments.size() > 0) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL, CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_PENALTIES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, penaltyPayments);
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL, CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_FEES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, feePayments);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Transfers proposal **/
|
||||
|
||||
+16
-8
@@ -11,7 +11,6 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.RandomStringUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.accounting.closure.domain.GLClosure;
|
||||
@@ -40,10 +39,12 @@ import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.organisation.office.domain.Office;
|
||||
import org.mifosplatform.organisation.office.domain.OfficeRepository;
|
||||
import org.mifosplatform.organisation.office.domain.OrganisationCurrencyRepositoryWrapper;
|
||||
import org.mifosplatform.organisation.office.exception.OfficeNotFoundException;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -67,6 +68,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
private final AccountingRuleRepository accountingRuleRepository;
|
||||
private final GLAccountReadPlatformService glAccountReadPlatformService;
|
||||
private final OrganisationCurrencyRepositoryWrapper organisationCurrencyRepository;
|
||||
private final PlatformSecurityContext context;
|
||||
|
||||
@Autowired
|
||||
public JournalEntryWritePlatformServiceJpaRepositoryImpl(final GLClosureRepository glClosureRepository,
|
||||
@@ -76,7 +78,8 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
final AccountingProcessorForLoanFactory accountingProcessorForLoanFactory,
|
||||
final AccountingProcessorForSavingsFactory accountingProcessorForSavingsFactory,
|
||||
final GLAccountReadPlatformService glAccountReadPlatformService,
|
||||
final OrganisationCurrencyRepositoryWrapper organisationCurrencyRepository) {
|
||||
final OrganisationCurrencyRepositoryWrapper organisationCurrencyRepository,
|
||||
final PlatformSecurityContext context) {
|
||||
this.glClosureRepository = glClosureRepository;
|
||||
this.officeRepository = officeRepository;
|
||||
this.glJournalEntryRepository = glJournalEntryRepository;
|
||||
@@ -88,6 +91,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
this.accountingRuleRepository = accountingRuleRepository;
|
||||
this.glAccountReadPlatformService = glAccountReadPlatformService;
|
||||
this.organisationCurrencyRepository = organisationCurrencyRepository;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -109,7 +113,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
|
||||
/** Set a transaction Id and save these Journal entries **/
|
||||
final Date transactionDate = command.DateValueOfParameterNamed(JournalEntryJsonInputParams.TRANSACTION_DATE.getValue());
|
||||
final String transactionId = generateTransactionId();
|
||||
final String transactionId = generateTransactionId(officeId);
|
||||
final String referenceNumber = command.stringValueOfParameterNamed(JournalEntryJsonInputParams.REFERENCE_NUMBER.getValue());
|
||||
|
||||
if (accountRuleId != null) {
|
||||
@@ -263,10 +267,10 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
.getTransactionId());
|
||||
|
||||
if (journalEntries.size() <= 1) { throw new JournalEntriesNotFoundException(command.getTransactionId()); }
|
||||
|
||||
final String reversalTransactionId = generateTransactionId();
|
||||
Long officeId = journalEntries.get(0).getOffice().getId();
|
||||
final String reversalTransactionId = generateTransactionId(officeId);
|
||||
final boolean manualEntry = true;
|
||||
|
||||
|
||||
for (final JournalEntry journalEntry : journalEntries) {
|
||||
JournalEntry reversalJournalEntry;
|
||||
final String reversalComment = "Reversal entry for Journal Entry with Entry Id :" + journalEntry.getId()
|
||||
@@ -377,8 +381,12 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
* TODO: Need a better implementation with guaranteed uniqueness (but not a
|
||||
* long UUID)...maybe something tied to system clock..
|
||||
*/
|
||||
private String generateTransactionId() {
|
||||
return RandomStringUtils.random(15, "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");
|
||||
private String generateTransactionId(Long officeId) {
|
||||
AppUser user = this.context.authenticatedUser();
|
||||
Long time = System.currentTimeMillis();
|
||||
String uniqueVal = String.valueOf(time) + user.getId() + officeId;
|
||||
String transactionId = Long.toHexString(Long.parseLong(uniqueVal));
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
private void handleJournalEntryDataIntegrityIssues(final DataIntegrityViolationException dve) {
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceN
|
||||
public class ProductToGLAccountMappingNotFoundException extends AbstractPlatformResourceNotFoundException {
|
||||
|
||||
public ProductToGLAccountMappingNotFoundException(final PortfolioProductType type, final Long productId, final String accountType) {
|
||||
super("error.msg.productTyAccountMapping.not.found", "Mapping for product of type" + type.toString() + " with Id " + productId
|
||||
super("error.msg.productToAccountMapping.not.found", "Mapping for product of type " + type.toString() + " with Id " + productId
|
||||
+ " does not exist for an account of type " + accountType, type.toString(), productId, accountType);
|
||||
}
|
||||
}
|
||||
+10
@@ -107,6 +107,11 @@ public final class ProductToGLAccountMappingFromApiJsonDeserializer {
|
||||
baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue()).value(writeOffAccountId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
final Long overpaymentAccountId = this.fromApiJsonHelper.extractLongNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(), element);
|
||||
baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue()).value(overpaymentAccountId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
final Long transfersInSuspenseAccountId = this.fromApiJsonHelper.extractLongNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue())
|
||||
@@ -176,6 +181,11 @@ public final class ProductToGLAccountMappingFromApiJsonDeserializer {
|
||||
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue()).value(incomeFromFeeId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromPenaltyId = this.fromApiJsonHelper.extractLongNamed(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue())
|
||||
.value(incomeFromPenaltyId).notNull().integerGreaterThanZero();
|
||||
|
||||
}
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
|
||||
+23
-8
@@ -52,6 +52,11 @@ public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappi
|
||||
saveProductToAccountMapping(element, paramName, productId, placeHolderTypeId, GLAccountType.EXPENSE, PortfolioProductType.LOAN);
|
||||
}
|
||||
|
||||
public void saveLoanToLiabilityAccountMapping(final JsonElement element, final String paramName, final Long productId,
|
||||
final int placeHolderTypeId) {
|
||||
saveProductToAccountMapping(element, paramName, productId, placeHolderTypeId, GLAccountType.LIABILITY, PortfolioProductType.LOAN);
|
||||
}
|
||||
|
||||
/*** Set of abstractions for merging Savings Products to GL Account Mappings ***/
|
||||
public void mergeLoanToAssetAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
|
||||
final int accountTypeId, final String accountTypeName, final Map<String, Object> changes) {
|
||||
@@ -71,6 +76,12 @@ public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappi
|
||||
PortfolioProductType.LOAN);
|
||||
}
|
||||
|
||||
public void mergeLoanToLiabilityAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
|
||||
final int accountTypeId, final String accountTypeName, final Map<String, Object> changes) {
|
||||
mergeProductToAccountMappingChanges(element, paramName, productId, accountTypeId, accountTypeName, changes,
|
||||
GLAccountType.LIABILITY, PortfolioProductType.LOAN);
|
||||
}
|
||||
|
||||
/*** Abstractions for payments channel related to loan products ***/
|
||||
|
||||
public void savePaymentChannelToFundSourceMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
@@ -112,6 +123,8 @@ public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappi
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), element);
|
||||
final Long writeOffAccountId = this.fromApiJsonHelper.extractLongNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), element);
|
||||
final Long overPaymentAccountId = this.fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(),
|
||||
element);
|
||||
final Long transfersInSuspenseAccountId = this.fromApiJsonHelper.extractLongNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), element);
|
||||
|
||||
@@ -132,19 +145,13 @@ public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappi
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), incomeFromFeeId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), incomeFromPenaltyId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), writeOffAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(), overPaymentAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), transfersInSuspenseAccountId);
|
||||
break;
|
||||
//$FALL-THROUGH$
|
||||
case ACCRUAL_BASED:
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), fundAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), loanPortfolioAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), incomeFromInterestId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), incomeFromFeeId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), incomeFromPenaltyId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), writeOffAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), receivableInterestAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), receivableFeeAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), receivablePenaltyAccountId);
|
||||
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), transfersInSuspenseAccountId);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -187,6 +194,10 @@ public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappi
|
||||
mergeLoanToExpenseAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(),
|
||||
loanProductId, CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue(),
|
||||
CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.toString(), changes);
|
||||
|
||||
// liabilities
|
||||
mergeLoanToLiabilityAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(), loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.OVERPAYMENT.getValue(), CASH_ACCOUNTS_FOR_LOAN.OVERPAYMENT.toString(), changes);
|
||||
break;
|
||||
case ACCRUAL_BASED:
|
||||
// assets (including receivables)
|
||||
@@ -221,6 +232,10 @@ public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappi
|
||||
mergeLoanToExpenseAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(),
|
||||
loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue(),
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.toString(), changes);
|
||||
|
||||
// liabilities
|
||||
mergeLoanToLiabilityAccountMappingChanges(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(), loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.OVERPAYMENT.getValue(), CASH_ACCOUNTS_FOR_LOAN.OVERPAYMENT.toString(), changes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -24,5 +24,9 @@ public interface ProductToGLAccountMappingReadPlatformService {
|
||||
public Map<String, Object> fetchAccountMappingDetailsForSavingsProduct(final Long savingsProductId, final Integer accountingType);
|
||||
|
||||
public List<PaymentTypeToGLAccountMapper> fetchPaymentTypeToFundSourceMappingsForSavingsProduct(final Long savingsProductId);
|
||||
|
||||
public List<ChargeToGLAccountMapper> fetchFeeToIncomeAccountMappingsForSavingsProduct(final Long savingsProductId);
|
||||
|
||||
public List<ChargeToGLAccountMapper> fetchPenaltyToIncomeAccountMappingsForSavingsProduct(final Long savingsProductId);
|
||||
|
||||
}
|
||||
+17
@@ -106,6 +106,8 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), glAccountId);
|
||||
} else if (glAccountForLoan.equals(CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF)) {
|
||||
accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), glAccountId);
|
||||
} else if (glAccountForLoan.equals(CASH_ACCOUNTS_FOR_LOAN.OVERPAYMENT)) {
|
||||
accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(), glAccountId);
|
||||
}
|
||||
}
|
||||
} else if (AccountingRuleType.ACCRUAL_BASED.getValue().equals(accountingType)) {
|
||||
@@ -126,6 +128,8 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), glAccountId);
|
||||
} else if (glAccountForLoan.equals(ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO)) {
|
||||
accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), glAccountId);
|
||||
} else if (glAccountForLoan.equals(ACCRUAL_ACCOUNTS_FOR_LOAN.OVERPAYMENT)) {
|
||||
accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(), glAccountId);
|
||||
} else if (glAccountForLoan.equals(ACCRUAL_ACCOUNTS_FOR_LOAN.TRANSFERS_SUSPENSE)) {
|
||||
accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), glAccountId);
|
||||
} else if (glAccountForLoan.equals(ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF)) {
|
||||
@@ -169,6 +173,8 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(), glAccountId);
|
||||
} else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_FEES)) {
|
||||
accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), glAccountId);
|
||||
} else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_PENALTIES)) {
|
||||
accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), glAccountId);
|
||||
} else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.TRANSFERS_SUSPENSE)) {
|
||||
accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), glAccountId);
|
||||
} else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.INTEREST_ON_SAVINGS)) {
|
||||
@@ -225,6 +231,16 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
return fetchChargeToIncomeAccountMappings(PortfolioProductType.LOAN, loanProductId, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ChargeToGLAccountMapper> fetchFeeToIncomeAccountMappingsForSavingsProduct(Long savingsProductId) {
|
||||
return fetchChargeToIncomeAccountMappings(PortfolioProductType.SAVING, savingsProductId, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ChargeToGLAccountMapper> fetchPenaltyToIncomeAccountMappingsForSavingsProduct(Long savingsProductId) {
|
||||
return fetchChargeToIncomeAccountMappings(PortfolioProductType.SAVING, savingsProductId, true);
|
||||
}
|
||||
|
||||
private List<ChargeToGLAccountMapper> fetchChargeToIncomeAccountMappings(final PortfolioProductType portfolioProductType,
|
||||
final Long loanProductId, final boolean penalty) {
|
||||
final ProductToGLAccountMappingMapper rm = new ProductToGLAccountMappingMapper();
|
||||
@@ -249,4 +265,5 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
}
|
||||
return chargeToGLAccountMappers;
|
||||
}
|
||||
|
||||
}
|
||||
+16
-3
@@ -79,9 +79,11 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
|
||||
CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue());
|
||||
|
||||
// expenses
|
||||
this.loanProductToGLAccountMappingHelper.saveLoanToExpenseAccountMapping(element,
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue());
|
||||
this.loanProductToGLAccountMappingHelper
|
||||
.saveLoanToLiabilityAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(), loanProductId,
|
||||
CASH_ACCOUNTS_FOR_LOAN.OVERPAYMENT.getValue());
|
||||
|
||||
// liabilities
|
||||
|
||||
// advanced accounting mappings
|
||||
this.loanProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, loanProductId, null);
|
||||
@@ -125,6 +127,11 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue());
|
||||
|
||||
// liabilities
|
||||
this.loanProductToGLAccountMappingHelper.saveLoanToLiabilityAccountMapping(element,
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(), loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.OVERPAYMENT.getValue());
|
||||
|
||||
// advanced accounting mappings
|
||||
this.loanProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, loanProductId, null);
|
||||
this.loanProductToGLAccountMappingHelper.saveChargesToIncomeAccountMappings(command, element, loanProductId, null);
|
||||
@@ -154,6 +161,10 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), savingProductId,
|
||||
CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_FEES.getValue());
|
||||
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToIncomeAccountMapping(element,
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), savingProductId,
|
||||
CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_PENALTIES.getValue());
|
||||
|
||||
// expenses
|
||||
this.savingsProductToGLAccountMappingHelper.saveSavingsToExpenseAccountMapping(element,
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), savingProductId,
|
||||
@@ -169,6 +180,7 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
|
||||
|
||||
// advanced accounting mappings
|
||||
this.savingsProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, savingProductId, null);
|
||||
this.savingsProductToGLAccountMappingHelper.saveChargesToIncomeAccountMappings(command, element, savingProductId, null);
|
||||
break;
|
||||
/*** Do not have accrual based accounting for now ***/
|
||||
case ACCRUAL_BASED:
|
||||
@@ -236,6 +248,7 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
|
||||
element, accountingRuleType);
|
||||
this.savingsProductToGLAccountMappingHelper.updatePaymentChannelToFundSourceMappings(command, element, savingsProductId,
|
||||
changes);
|
||||
this.savingsProductToGLAccountMappingHelper.updateChargesToIncomeAccountMappings(command, element, savingsProductId, changes);
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
+21
@@ -94,6 +94,20 @@ public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMa
|
||||
updatePaymentChannelToFundSourceMappings(command, element, productId, changes, PortfolioProductType.SAVING);
|
||||
}
|
||||
|
||||
public void saveChargesToIncomeAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
final Map<String, Object> changes) {
|
||||
// save both fee and penalty charges
|
||||
saveChargesToIncomeAccountMappings(command, element, productId, changes, PortfolioProductType.SAVING, true);
|
||||
saveChargesToIncomeAccountMappings(command, element, productId, changes, PortfolioProductType.SAVING, false);
|
||||
}
|
||||
|
||||
public void updateChargesToIncomeAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
final Map<String, Object> changes) {
|
||||
// update both fee and penalty charges
|
||||
updateChargeToIncomeAccountMappings(command, element, productId, changes, PortfolioProductType.SAVING, true);
|
||||
updateChargeToIncomeAccountMappings(command, element, productId, changes, PortfolioProductType.SAVING, false);
|
||||
}
|
||||
|
||||
public Map<String, Object> populateChangesForNewSavingsProductToGLAccountMappingCreation(final JsonElement element,
|
||||
final AccountingRuleType accountingRuleType) {
|
||||
final Map<String, Object> changes = new HashMap<String, Object>();
|
||||
@@ -102,6 +116,8 @@ public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMa
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue(), element);
|
||||
final Long incomeFromFeesId = this.fromApiJsonHelper.extractLongNamed(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), element);
|
||||
final Long incomeFromPenaltiesId = this.fromApiJsonHelper.extractLongNamed(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), element);
|
||||
final Long interestOnSavingsId = this.fromApiJsonHelper.extractLongNamed(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), element);
|
||||
final Long savingsControlId = this.fromApiJsonHelper.extractLongNamed(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(),
|
||||
@@ -117,6 +133,7 @@ public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMa
|
||||
changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue(), savingsReferenceId);
|
||||
changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), interestOnSavingsId);
|
||||
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);
|
||||
break;
|
||||
case ACCRUAL_BASED:
|
||||
@@ -150,6 +167,10 @@ public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMa
|
||||
savingsProductId, CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_FEES.getValue(),
|
||||
CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_FEES.toString(), changes);
|
||||
|
||||
mergeSavingsToIncomeAccountMappingChanges(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(),
|
||||
savingsProductId, CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_PENALTIES.getValue(),
|
||||
CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_PENALTIES.toString(), changes);
|
||||
|
||||
// expenses
|
||||
mergeSavingsToExpenseAccountMappingChanges(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(),
|
||||
savingsProductId, CASH_ACCOUNTS_FOR_SAVINGS.INTEREST_ON_SAVINGS.getValue(),
|
||||
|
||||
+2
-2
@@ -420,9 +420,9 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
handler = this.applicationContext.getBean("calculateInterestSavingsAccountCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isSavingsAccountInterestPosting()) {
|
||||
handler = this.applicationContext.getBean("postInterestSavingsAccountCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isSavingsAccountApplyAnnualFee()) {
|
||||
} /*else if (wrapper.isSavingsAccountApplyAnnualFee()) {
|
||||
handler = this.applicationContext.getBean("applyAnnualFeeSavingsAccountCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isSavingsAccountUndoTransaction()) {
|
||||
} */else if (wrapper.isSavingsAccountUndoTransaction()) {
|
||||
handler = this.applicationContext.getBean("undoTransactionSavingsAccountCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isAdjustSavingsAccountTransaction()) {
|
||||
handler = this.applicationContext.getBean("savingsTransactionAdjustmentCommandHandler", NewCommandSourceHandler.class);
|
||||
|
||||
+21
@@ -241,6 +241,27 @@ public class DataValidatorBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public DataValidatorBuilder isOneOfTheseStringValues(final Object... values) {
|
||||
if (this.value == null && this.ignoreNullValue) { return this; }
|
||||
|
||||
final List<Object> valuesList = Arrays.asList(values);
|
||||
final String valuesListStr = StringUtils.join(valuesList, ", ");
|
||||
|
||||
if (this.value == null || !valuesList.contains(this.value.toString().toLowerCase())) {
|
||||
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
|
||||
.append(this.parameter).append(".is.not.one.of.expected.enumerations");
|
||||
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
|
||||
.append(" must be one of [ ").append(valuesListStr).append(" ] ").append(".");
|
||||
|
||||
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
|
||||
defaultEnglishMessage.toString(), this.parameter, this.value, values);
|
||||
|
||||
this.dataValidationErrors.add(error);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public DataValidatorBuilder isNotOneOfTheseValues(final Object... values) {
|
||||
if (this.value == null && this.ignoreNullValue) { return this; }
|
||||
|
||||
|
||||
+4
-4
@@ -45,7 +45,7 @@ public class DatatableCommandFromApiJsonDeserializer {
|
||||
private final Set<String> supportedParametersForChangeColumns = new HashSet<String>(Arrays.asList("name", "newName", "length",
|
||||
"mandatory", "after", "code", "newCode"));
|
||||
private final Set<String> supportedParametersForDropColumns = new HashSet<String>(Arrays.asList("name"));
|
||||
private final Object[] supportedColumnTypes = { "String", "Number", "Decimal", "Date", "Text", "Dropdown" };
|
||||
private final Object[] supportedColumnTypes = { "string", "number", "decimal", "date", "text", "dropdown" };
|
||||
private final Object[] supportedApptableNames = { "m_loan", "m_savings_account", "m_client", "m_group", "m_center", "m_office",
|
||||
"m_savings_product", "m_product_loan" };
|
||||
|
||||
@@ -58,9 +58,9 @@ public class DatatableCommandFromApiJsonDeserializer {
|
||||
|
||||
private void validateType(final DataValidatorBuilder baseDataValidator, final JsonElement column) {
|
||||
final String type = this.fromApiJsonHelper.extractStringNamed("type", column);
|
||||
baseDataValidator.reset().parameter("type").value(type).notBlank().isOneOfTheseValues(this.supportedColumnTypes);
|
||||
baseDataValidator.reset().parameter("type").value(type).notBlank().isOneOfTheseStringValues(this.supportedColumnTypes);
|
||||
|
||||
if (type != null && type.equals("String")) {
|
||||
if (type != null && type.equalsIgnoreCase("String")) {
|
||||
if (this.fromApiJsonHelper.parameterExists("length", column)) {
|
||||
final String lengthStr = this.fromApiJsonHelper.extractStringNamed("length", column);
|
||||
if (lengthStr != null && !StringUtils.isWhitespace(lengthStr) && StringUtils.isNumeric(lengthStr)
|
||||
@@ -80,7 +80,7 @@ public class DatatableCommandFromApiJsonDeserializer {
|
||||
}
|
||||
|
||||
final String code = this.fromApiJsonHelper.extractStringNamed("code", column);
|
||||
if (type != null && type.equals("Dropdown")) {
|
||||
if (type != null && type.equalsIgnoreCase("Dropdown")) {
|
||||
if (code != null) {
|
||||
baseDataValidator.reset().parameter("code").value(code).notBlank().matchesRegularExpression(DATATABLE_NAME_REGEX_PATTERN);
|
||||
} else {
|
||||
|
||||
+9
@@ -149,6 +149,11 @@ public class FromJsonHelper {
|
||||
public MonthDay extractMonthDayNamed(final String parameterName, final JsonElement element) {
|
||||
return this.helperDelegator.extractMonthDayNamed(parameterName, element);
|
||||
}
|
||||
|
||||
public MonthDay extractMonthDayNamed(final String parameterName, final JsonObject object, final String dateFormat,
|
||||
final Locale clientApplicationLocale) {
|
||||
return this.helperDelegator.extractMonthDayNamed(parameterName, object, dateFormat, clientApplicationLocale);
|
||||
}
|
||||
|
||||
public LocalDate extractLocalDateNamed(final String parameterName, final JsonElement element) {
|
||||
return this.helperDelegator.extractLocalDateNamed(parameterName, element, new HashSet<String>());
|
||||
@@ -216,4 +221,8 @@ public class FromJsonHelper {
|
||||
public String extractDateFormatParameter(final JsonObject element) {
|
||||
return this.helperDelegator.extractDateFormatParameter(element);
|
||||
}
|
||||
|
||||
public String extractMonthDayFormatParameter(final JsonObject element) {
|
||||
return this.helperDelegator.extractMonthDayFormatParameter(element);
|
||||
}
|
||||
}
|
||||
+4
@@ -63,4 +63,8 @@ public class DateUtils {
|
||||
final String formattedSqlDate = df.format(date);
|
||||
return formattedSqlDate;
|
||||
}
|
||||
|
||||
public static boolean isDateInTheFuture(final LocalDate localDate){
|
||||
return localDate.isAfter(getLocalDateOfTenant());
|
||||
}
|
||||
}
|
||||
+28
-26
@@ -71,12 +71,12 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
private final static HashMap<String, String> apiTypeToMySQL = new HashMap<String, String>() {
|
||||
|
||||
{
|
||||
put("String", "VARCHAR");
|
||||
put("Number", "INT");
|
||||
put("Decimal", "DECIMAL");
|
||||
put("Date", "DATE");
|
||||
put("Text", "TEXT");
|
||||
put("Dropdown", "INT");
|
||||
put("string", "VARCHAR");
|
||||
put("number", "INT");
|
||||
put("decimal", "DECIMAL");
|
||||
put("date", "DATE");
|
||||
put("text", "TEXT");
|
||||
put("dropdown", "INT");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -265,15 +265,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
|
||||
final String deleteRegisteredDatatableSql = "delete from x_registered_table where registered_table_name = '" + datatable + "'";
|
||||
|
||||
String[] sqlArray = null;
|
||||
if (this.configurationDomainService.isConstraintApproachEnabledForDatatables()) {
|
||||
final String deleteColumnCodeSql = "delete from x_table_cloumn_code_mappings where column_alias_name like'"
|
||||
+ datatable.toLowerCase().replaceAll("\\s", "_") + "%'";
|
||||
sqlArray = new String[4];
|
||||
sqlArray[3] = deleteColumnCodeSql;
|
||||
} else {
|
||||
sqlArray = new String[3];
|
||||
}
|
||||
String[] sqlArray = new String[3];
|
||||
sqlArray[0] = deleteRolePermissionsSql;
|
||||
sqlArray[1] = deletePermissionsSql;
|
||||
sqlArray[2] = deleteRegisteredDatatableSql;
|
||||
@@ -362,7 +354,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
final boolean isConstraintApproach) {
|
||||
|
||||
String name = (column.has("name")) ? column.get("name").getAsString() : null;
|
||||
final String type = (column.has("type")) ? column.get("type").getAsString() : null;
|
||||
final String type = (column.has("type")) ? column.get("type").getAsString().toLowerCase() : null;
|
||||
final Integer length = (column.has("length")) ? column.get("length").getAsInt() : null;
|
||||
final Boolean mandatory = (column.has("mandatory")) ? column.get("mandatory").getAsBoolean() : false;
|
||||
final String code = (column.has("code")) ? column.get("code").getAsString() : null;
|
||||
@@ -381,11 +373,11 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
sqlBuilder = sqlBuilder.append("`" + name + "` " + mysqlType);
|
||||
|
||||
if (type != null) {
|
||||
if (type.equals("String")) {
|
||||
if (type.equalsIgnoreCase("String")) {
|
||||
sqlBuilder = sqlBuilder.append("(" + length + ")");
|
||||
} else if (type.equals("Decimal")) {
|
||||
} else if (type.equalsIgnoreCase("Decimal")) {
|
||||
sqlBuilder = sqlBuilder.append("(19,6)");
|
||||
} else if (type.equals("Dropdown")) {
|
||||
} else if (type.equalsIgnoreCase("Dropdown")) {
|
||||
sqlBuilder = sqlBuilder.append("(11)");
|
||||
}
|
||||
}
|
||||
@@ -526,14 +518,14 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
} else {
|
||||
if (code != null) {
|
||||
removeMappings.add(dataTableNameAlias + "_" + name);
|
||||
if (newCode == null) {
|
||||
if (newCode == null || !StringUtils.equalsIgnoreCase(name, newName)) {
|
||||
constrainBuilder.append(", DROP FOREIGN KEY `fk_").append(dataTableNameAlias).append("_").append(name)
|
||||
.append("` ");
|
||||
}
|
||||
}
|
||||
if (newCode != null) {
|
||||
codeMappings.put(dataTableNameAlias + "_" + newName, this.codeReadPlatformService.retriveCode(newCode).getCodeId());
|
||||
if (code == null) {
|
||||
if (code == null || !StringUtils.equalsIgnoreCase(name, newName)) {
|
||||
constrainBuilder.append(",ADD CONSTRAINT `fk_").append(dataTableNameAlias).append("_").append(newName)
|
||||
.append("` ").append("FOREIGN KEY (`" + newName + "`) ").append("REFERENCES `")
|
||||
.append(CODE_VALUES_TABLE).append("` (`id`)");
|
||||
@@ -596,7 +588,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
final StringBuilder constrainBuilder, final Map<String, Long> codeMappings, final boolean isConstraintApproach) {
|
||||
|
||||
String name = (column.has("name")) ? column.get("name").getAsString() : null;
|
||||
final String type = (column.has("type")) ? column.get("type").getAsString() : null;
|
||||
final String type = (column.has("type")) ? column.get("type").getAsString().toLowerCase() : null;
|
||||
final Integer length = (column.has("length")) ? column.get("length").getAsInt() : null;
|
||||
final Boolean mandatory = (column.has("mandatory")) ? column.get("mandatory").getAsBoolean() : false;
|
||||
final String after = (column.has("after")) ? column.get("after").getAsString() : null;
|
||||
@@ -616,11 +608,11 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
sqlBuilder = sqlBuilder.append(", ADD `" + name + "` " + mysqlType);
|
||||
|
||||
if (type != null) {
|
||||
if (type.equals("String") && length != null) {
|
||||
if (type.equalsIgnoreCase("String") && length != null) {
|
||||
sqlBuilder = sqlBuilder.append("(" + length + ")");
|
||||
} else if (type.equals("Decimal")) {
|
||||
} else if (type.equalsIgnoreCase("Decimal")) {
|
||||
sqlBuilder = sqlBuilder.append("(19,6)");
|
||||
} else if (type.equals("Dropdown")) {
|
||||
} else if (type.equalsIgnoreCase("Dropdown")) {
|
||||
sqlBuilder = sqlBuilder.append("(11)");
|
||||
}
|
||||
}
|
||||
@@ -828,8 +820,18 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
if (!isRegisteredDataTable(datatableName)) { throw new DatatableNotFoundException(datatableName); }
|
||||
validateDatatableName(datatableName);
|
||||
deregisterDatatable(datatableName);
|
||||
String[] sqlArray = null;
|
||||
if (this.configurationDomainService.isConstraintApproachEnabledForDatatables()) {
|
||||
final String deleteColumnCodeSql = "delete from x_table_cloumn_code_mappings where column_alias_name like'"
|
||||
+ datatableName.toLowerCase().replaceAll("\\s", "_") + "_%'";
|
||||
sqlArray = new String[2];
|
||||
sqlArray[1] = deleteColumnCodeSql;
|
||||
}else{
|
||||
sqlArray = new String[1];
|
||||
}
|
||||
final String sql = "DROP TABLE `" + datatableName + "`";
|
||||
this.jdbcTemplate.execute(sql);
|
||||
sqlArray[0] = sql;
|
||||
this.jdbcTemplate.batchUpdate(sqlArray);
|
||||
} catch (final SQLGrammarException e) {
|
||||
final Throwable realCause = e.getCause();
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
|
||||
+2
-1
@@ -5,7 +5,8 @@ public enum JobName {
|
||||
UPDATE_LOAN_SUMMARY("Update loan Summary"), UPDATE_LOAN_ARREARS_AGEING("Update Loan Arrears Ageing"), UPDATE_LOAN_PAID_IN_ADVANCE(
|
||||
"Update Loan Paid In Advance"), APPLY_ANNUAL_FEE_FOR_SAVINGS("Apply Annual Fee For Savings"), APPLY_HOLIDAYS_TO_LOANS(
|
||||
"Apply Holidays To Loans"), POST_INTEREST_FOR_SAVINGS("Post Interest For Savings"), TRANSFER_FEE_CHARGE_FOR_LOANS(
|
||||
"Transfer Fee For Loans From Savings"), ACCOUNTING_RUNNING_BALANCE_UPDATE("Update Accounting Running Balances");
|
||||
"Transfer Fee For Loans From Savings"), ACCOUNTING_RUNNING_BALANCE_UPDATE("Update Accounting Running Balances"), PAY_DUE_SAVINGS_CHARGES(
|
||||
"Pay Due Savings Charges");
|
||||
|
||||
private final String name;
|
||||
|
||||
|
||||
+5
@@ -1,9 +1,14 @@
|
||||
package org.mifosplatform.organisation.holiday.service;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
|
||||
public interface HolidayWritePlatformService {
|
||||
|
||||
CommandProcessingResult createHoliday(JsonCommand command);
|
||||
|
||||
boolean isHoliday(Long officeId, LocalDate transactionDate);
|
||||
|
||||
boolean isTransactionAllowedOnHoliday();
|
||||
}
|
||||
|
||||
+17
-2
@@ -1,9 +1,11 @@
|
||||
package org.mifosplatform.organisation.holiday.service;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
@@ -39,7 +41,7 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit
|
||||
private final HolidayDataValidator fromApiJsonDeserializer;
|
||||
private final HolidayRepository holidayRepository;
|
||||
private final WorkingDaysRepositoryWrapper daysRepositoryWrapper;
|
||||
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
private final PlatformSecurityContext context;
|
||||
private final OfficeRepository officeRepository;
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
@@ -47,13 +49,14 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit
|
||||
@Autowired
|
||||
public HolidayWritePlatformServiceJpaRepositoryImpl(final HolidayDataValidator fromApiJsonDeserializer,
|
||||
final HolidayRepository holidayRepository, final PlatformSecurityContext context, final OfficeRepository officeRepository,
|
||||
final FromJsonHelper fromApiJsonHelper, final WorkingDaysRepositoryWrapper daysRepositoryWrapper) {
|
||||
final FromJsonHelper fromApiJsonHelper, final WorkingDaysRepositoryWrapper daysRepositoryWrapper, final ConfigurationDomainService configurationDomainService) {
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
this.holidayRepository = holidayRepository;
|
||||
this.context = context;
|
||||
this.officeRepository = officeRepository;
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
this.daysRepositoryWrapper = daysRepositoryWrapper;
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -152,4 +155,16 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit
|
||||
toDate.toString(), repaymentsRescheduledTo.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHoliday(Long officeId, LocalDate transactionDate) {
|
||||
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(officeId, transactionDate.toDate());
|
||||
return HolidayUtil.isHoliday(transactionDate, holidays);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAllowedOnHoliday() {
|
||||
return this.configurationDomainService.allowTransactionsOnHolidayEnabled();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package org.mifosplatform.organisation.workingdays.service;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
public interface WorkingDaysWritePlatformService {
|
||||
|
||||
boolean isWorkingDay(LocalDate transactionDate);
|
||||
|
||||
boolean isTransactionAllowedOnNonWorkingDay();
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package org.mifosplatform.organisation.workingdays.service;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
|
||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class WorkingDaysWritePlatformServiceJpaRepositoryImpl implements WorkingDaysWritePlatformService {
|
||||
|
||||
private final WorkingDaysRepositoryWrapper daysRepositoryWrapper;
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
|
||||
@Autowired
|
||||
public WorkingDaysWritePlatformServiceJpaRepositoryImpl(final WorkingDaysRepositoryWrapper daysRepositoryWrapper,
|
||||
final ConfigurationDomainService configurationDomainService) {
|
||||
this.daysRepositoryWrapper = daysRepositoryWrapper;
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWorkingDay(LocalDate transactionDate) {
|
||||
final WorkingDays workingDays = this.daysRepositoryWrapper.findOne();
|
||||
return WorkingDaysUtil.isWorkingDay(workingDays, transactionDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAllowedOnNonWorkingDay() {
|
||||
return this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled();
|
||||
}
|
||||
|
||||
}
|
||||
+5
@@ -175,4 +175,9 @@ public class AccountTransfer extends AbstractPersistable<Long> {
|
||||
public SavingsAccount getFromAccount() {
|
||||
return this.fromAccount;
|
||||
}
|
||||
|
||||
|
||||
public void updateToLoanTransaction(LoanTransaction toLoanTransaction) {
|
||||
this.toLoanTransaction = toLoanTransaction;
|
||||
}
|
||||
}
|
||||
+3
@@ -19,4 +19,7 @@ public interface AccountTransferRepository extends JpaRepository<AccountTransfer
|
||||
|
||||
@Query("from AccountTransfer at where (at.fromLoanAccount.id= :accountNumber or at.toLoanAccount.id=:accountNumber) and at.reversed=false")
|
||||
List<AccountTransfer> findAllByLoanId(@Param("accountNumber") Long accountNumber);
|
||||
|
||||
@Query("from AccountTransfer at where at.toLoanTransaction.id= :loanTransactionId and at.reversed=false")
|
||||
AccountTransfer findByToLoanTransactionId(@Param("loanTransactionId") Long loanTransactionId);
|
||||
}
|
||||
+3
@@ -9,6 +9,7 @@ import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.portfolio.account.PortfolioAccountType;
|
||||
import org.mifosplatform.portfolio.account.data.AccountTransferDTO;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||
|
||||
public interface AccountTransfersWritePlatformService {
|
||||
|
||||
@@ -19,4 +20,6 @@ public interface AccountTransfersWritePlatformService {
|
||||
Long transferFunds(AccountTransferDTO accountTransferDTO);
|
||||
|
||||
void reverseAllTransactions(Long accountId, PortfolioAccountType accountTypeId);
|
||||
|
||||
void updateLoanTransaction(Long loanTransactionId, LoanTransaction newLoanTransaction);
|
||||
}
|
||||
+10
@@ -239,6 +239,16 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
||||
|
||||
return transferTransactionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void updateLoanTransaction(final Long loanTransactionId,final LoanTransaction newLoanTransaction){
|
||||
final AccountTransfer transferTransaction = this.accountTransferRepository.findByToLoanTransactionId(loanTransactionId);
|
||||
if(transferTransaction!=null){
|
||||
transferTransaction.updateToLoanTransaction(newLoanTransaction);
|
||||
this.accountTransferRepository.save(transferTransaction);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isLoanToSavingsAccountTransfer(final PortfolioAccountType fromAccountType, final PortfolioAccountType toAccountType) {
|
||||
return fromAccountType.isLoanAccount() && toAccountType.isSavingsAccount();
|
||||
|
||||
+2
-1
@@ -43,7 +43,8 @@ public class ChargesApiResource {
|
||||
|
||||
private final Set<String> CHARGES_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "name", "amount", "currency", "penalty",
|
||||
"active", "chargeAppliesTo", "chargeTimeType", "chargeCalculationType", "chargeCalculationTypeOptions",
|
||||
"chargeAppliesToOptions", "chargeTimeTypeOptions", "currencyOptions"));
|
||||
"chargeAppliesToOptions", "chargeTimeTypeOptions", "currencyOptions", "loanChargeCalculationTypeOptions",
|
||||
"loanChargeTimeTypeOptions", "savingsChargeCalculationTypeOptions", "savingsChargeTimeTypeOptions"));
|
||||
|
||||
private final String resourceNameForPermissions = "CHARGE";
|
||||
|
||||
|
||||
+48
-11
@@ -11,6 +11,7 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
|
||||
@@ -33,30 +34,53 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
||||
private final EnumOptionData chargePaymentMode;
|
||||
|
||||
private final Collection<CurrencyData> currencyOptions;
|
||||
private final List<EnumOptionData> chargeCalculationTypeOptions;
|
||||
private final List<EnumOptionData> chargeAppliesToOptions;
|
||||
private final List<EnumOptionData> chargeTimeTypeOptions;
|
||||
private final List<EnumOptionData> chargePaymetModeOptions;
|
||||
private final List<EnumOptionData> chargeCalculationTypeOptions;//
|
||||
private final List<EnumOptionData> chargeAppliesToOptions;//
|
||||
private final List<EnumOptionData> chargeTimeTypeOptions;//
|
||||
private final List<EnumOptionData> chargePaymetModeOptions;//
|
||||
|
||||
private final List<EnumOptionData> loanChargeCalculationTypeOptions;
|
||||
private final List<EnumOptionData> loanChargeTimeTypeOptions;
|
||||
private final List<EnumOptionData> savingsChargeCalculationTypeOptions;
|
||||
private final List<EnumOptionData> savingsChargeTimeTypeOptions;
|
||||
|
||||
public static ChargeData template(final Collection<CurrencyData> currencyOptions,
|
||||
final List<EnumOptionData> chargeCalculationTypeOptions, final List<EnumOptionData> chargeAppliesToOptions,
|
||||
final List<EnumOptionData> chargeTimeTypeOptions, final List<EnumOptionData> chargePaymentModeOptions) {
|
||||
final List<EnumOptionData> chargeTimeTypeOptions, final List<EnumOptionData> chargePaymentModeOptions,
|
||||
final List<EnumOptionData> loansChargeCalculationTypeOptions, final List<EnumOptionData> loansChargeTimeTypeOptions,
|
||||
final List<EnumOptionData> savingsChargeCalculationTypeOptions, final List<EnumOptionData> savingsChargeTimeTypeOptions) {
|
||||
|
||||
return new ChargeData(null, null, null, null, null, null, null, null, false, false, currencyOptions, chargeCalculationTypeOptions,
|
||||
chargeAppliesToOptions, chargeTimeTypeOptions, chargePaymentModeOptions);
|
||||
chargeAppliesToOptions, chargeTimeTypeOptions, chargePaymentModeOptions, loansChargeCalculationTypeOptions,
|
||||
loansChargeTimeTypeOptions, savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions);
|
||||
}
|
||||
|
||||
public static ChargeData withTemplate(final ChargeData charge, final ChargeData template) {
|
||||
return new ChargeData(charge.id, charge.name, charge.amount, charge.currency, charge.chargeTimeType, charge.chargeAppliesTo,
|
||||
charge.chargeCalculationType, charge.chargePaymentMode, charge.penalty, charge.active, template.currencyOptions,
|
||||
template.chargeCalculationTypeOptions, template.chargeAppliesToOptions, template.chargeTimeTypeOptions,
|
||||
template.chargePaymetModeOptions);
|
||||
template.chargePaymetModeOptions, template.loanChargeCalculationTypeOptions, template.loanChargeTimeTypeOptions,
|
||||
template.savingsChargeCalculationTypeOptions, template.savingsChargeTimeTypeOptions);
|
||||
}
|
||||
|
||||
public static ChargeData instance(final Long id, final String name, final BigDecimal amount, final CurrencyData currency,
|
||||
final EnumOptionData chargeTimeType, final EnumOptionData chargeAppliesTo, final EnumOptionData chargeCalculationType,
|
||||
final EnumOptionData chargePaymentMode, final boolean penalty, final boolean active) {
|
||||
|
||||
final Collection<CurrencyData> currencyOptions = null;
|
||||
final List<EnumOptionData> chargeCalculationTypeOptions = null;
|
||||
final List<EnumOptionData> chargeAppliesToOptions = null;
|
||||
final List<EnumOptionData> chargeTimeTypeOptions = null;
|
||||
final List<EnumOptionData> chargePaymentModeOptions = null;
|
||||
final List<EnumOptionData> loansChargeCalculationTypeOptions = null;
|
||||
final List<EnumOptionData> loansChargeTimeTypeOptions = null;
|
||||
final List<EnumOptionData> savingsChargeCalculationTypeOptions = null;
|
||||
final List<EnumOptionData> savingsChargeTimeTypeOptions = null;
|
||||
|
||||
return new ChargeData(id, name, amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType, chargePaymentMode,
|
||||
penalty, active, null, null, null, null, null);
|
||||
penalty, active, currencyOptions, chargeCalculationTypeOptions, chargeAppliesToOptions, chargeTimeTypeOptions,
|
||||
chargePaymentModeOptions, loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions,
|
||||
savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions);
|
||||
}
|
||||
|
||||
public static ChargeData lookup(final Long id, final String name, final boolean isPenalty) {
|
||||
@@ -73,9 +97,15 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
||||
final List<EnumOptionData> chargeAppliesToOptions = null;
|
||||
final List<EnumOptionData> chargeTimeTypeOptions = null;
|
||||
final List<EnumOptionData> chargePaymentModeOptions = null;
|
||||
final List<EnumOptionData> loansChargeCalculationTypeOptions = null;
|
||||
final List<EnumOptionData> loansChargeTimeTypeOptions = null;
|
||||
final List<EnumOptionData> savingsChargeCalculationTypeOptions = null;
|
||||
final List<EnumOptionData> savingsChargeTimeTypeOptions = null;
|
||||
|
||||
return new ChargeData(id, name, amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType, chargePaymentMode,
|
||||
penalty, active, currencyOptions, chargeCalculationTypeOptions, chargeAppliesToOptions, chargeTimeTypeOptions,
|
||||
chargePaymentModeOptions);
|
||||
chargePaymentModeOptions, loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions,
|
||||
savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions);
|
||||
}
|
||||
|
||||
private ChargeData(final Long id, final String name, final BigDecimal amount, final CurrencyData currency,
|
||||
@@ -83,7 +113,9 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
||||
final EnumOptionData chargePaymentMode, final boolean penalty, final boolean active,
|
||||
final Collection<CurrencyData> currencyOptions, final List<EnumOptionData> chargeCalculationTypeOptions,
|
||||
final List<EnumOptionData> chargeAppliesToOptions, final List<EnumOptionData> chargeTimeTypeOptions,
|
||||
final List<EnumOptionData> chargePaymentModeOptions) {
|
||||
final List<EnumOptionData> chargePaymentModeOptions, final List<EnumOptionData> loansChargeCalculationTypeOptions,
|
||||
final List<EnumOptionData> loansChargeTimeTypeOptions, final List<EnumOptionData> savingsChargeCalculationTypeOptions,
|
||||
final List<EnumOptionData> savingsChargeTimeTypeOptions) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.amount = amount;
|
||||
@@ -99,6 +131,10 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
||||
this.chargeAppliesToOptions = chargeAppliesToOptions;
|
||||
this.chargeTimeTypeOptions = chargeTimeTypeOptions;
|
||||
this.chargePaymetModeOptions = chargePaymentModeOptions;
|
||||
this.savingsChargeCalculationTypeOptions = savingsChargeCalculationTypeOptions;
|
||||
this.savingsChargeTimeTypeOptions = savingsChargeTimeTypeOptions;
|
||||
this.loanChargeCalculationTypeOptions = loansChargeCalculationTypeOptions;
|
||||
this.loanChargeTimeTypeOptions = loansChargeTimeTypeOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -141,9 +177,10 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
||||
final BigDecimal amountPercentageAppliedTo = BigDecimal.ZERO;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
final LocalDate dueAsOfDate = null;
|
||||
final MonthDay feeOnMonthDay = null;
|
||||
|
||||
return SavingsAccountChargeData.instance(savingsChargeId, this.id, this.name, this.currency, this.amount, amountPaid, amountWaived,
|
||||
amountWrittenOff, amountOutstanding, this.chargeTimeType, dueAsOfDate, this.chargeCalculationType, percentage,
|
||||
amountPercentageAppliedTo, chargeOptions, this.penalty);
|
||||
amountPercentageAppliedTo, chargeOptions, this.penalty, feeOnMonthDay);
|
||||
}
|
||||
}
|
||||
@@ -114,6 +114,11 @@ public class Charge extends AbstractPersistable<Long> {
|
||||
baseDataValidator.reset().parameter("chargeCalculationType").value(this.chargeCalculation)
|
||||
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.calculation.type.for.savings");
|
||||
}
|
||||
|
||||
if (!ChargeTimeType.fromInt(getChargeTime()).isWithdrawalFee() && ChargeCalculationType.fromInt(getChargeCalculation()).isPercentageOfAmount()) {
|
||||
baseDataValidator.reset().parameter("chargeCalculationType").value(this.chargeCalculation)
|
||||
.failWithCodeNoParameterAddedToErrorCode("charge.calculation.type.percentage.allowed.only.for.withdrawal");
|
||||
}
|
||||
|
||||
} else if (isLoanCharge()) {
|
||||
|
||||
@@ -277,6 +282,11 @@ public class Charge extends AbstractPersistable<Long> {
|
||||
baseDataValidator.reset().parameter("chargeCalculationType").value(this.chargeCalculation)
|
||||
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.calculation.type.for.savings");
|
||||
}
|
||||
|
||||
if (!ChargeTimeType.fromInt(getChargeTime()).isWithdrawalFee() && ChargeCalculationType.fromInt(getChargeCalculation()).isPercentageOfAmount()) {
|
||||
baseDataValidator.reset().parameter("chargeCalculationType").value(this.chargeCalculation)
|
||||
.failWithCodeNoParameterAddedToErrorCode("charge.calculation.type.percentage.allowed.only.for.withdrawal");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -57,6 +57,6 @@ public enum ChargeCalculationType {
|
||||
}
|
||||
|
||||
public boolean isAllowedSavingsChargeCalculationType() {
|
||||
return isFlat();
|
||||
return isFlat() || isPercentageOfAmount();
|
||||
}
|
||||
}
|
||||
+32
-10
@@ -8,8 +8,12 @@ package org.mifosplatform.portfolio.charge.domain;
|
||||
public enum ChargeTimeType {
|
||||
|
||||
INVALID(0, "chargeTimeType.invalid"), //
|
||||
DISBURSEMENT(1, "chargeTimeType.disbursement"), //
|
||||
SPECIFIED_DUE_DATE(2, "chargeTimeType.specifiedDueDate"), MONTHLY(3, "chargeTimeType.monthly"), YEARLY(4, "chargeTimeType.yearly");
|
||||
DISBURSEMENT(1, "chargeTimeType.disbursement"), //only for loan charges
|
||||
SPECIFIED_DUE_DATE(2, "chargeTimeType.specifiedDueDate"), // for loan and savings charges
|
||||
SAVINGS_ACTIVATION(3, "chargeTimeType.savingsActivation"), // only for savings
|
||||
SAVINGS_CLOSURE(4, "chargeTimeType.savingsClosure"), // only for savings
|
||||
WITHDRAWAL_FEE(5, "chargeTimeType.withdrawalFee"), // only for savings
|
||||
ANNUAL_FEE(6, "chargeTimeType.annualFee"); // only for savings
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
@@ -32,7 +36,11 @@ public enum ChargeTimeType {
|
||||
}
|
||||
|
||||
public static int maxValue() {
|
||||
return 4;
|
||||
int max = 1;// Default it to one (1)
|
||||
for (ChargeTimeType chargeTimeType : ChargeTimeType.values()) {
|
||||
max = (chargeTimeType.getValue() > max) ? chargeTimeType.getValue() : max;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
public static ChargeTimeType fromInt(final Integer chargeTime) {
|
||||
@@ -45,10 +53,16 @@ public enum ChargeTimeType {
|
||||
chargeTimeType = SPECIFIED_DUE_DATE;
|
||||
break;
|
||||
case 3:
|
||||
chargeTimeType = MONTHLY;
|
||||
chargeTimeType = SAVINGS_ACTIVATION;
|
||||
break;
|
||||
case 4:
|
||||
chargeTimeType = YEARLY;
|
||||
chargeTimeType = SAVINGS_CLOSURE;
|
||||
break;
|
||||
case 5:
|
||||
chargeTimeType = WITHDRAWAL_FEE;
|
||||
break;
|
||||
case 6:
|
||||
chargeTimeType = ANNUAL_FEE;
|
||||
break;
|
||||
default:
|
||||
chargeTimeType = INVALID;
|
||||
@@ -65,12 +79,20 @@ public enum ChargeTimeType {
|
||||
return this.value.equals(ChargeTimeType.SPECIFIED_DUE_DATE.getValue());
|
||||
}
|
||||
|
||||
public boolean isMonthly() {
|
||||
return this.value.equals(ChargeTimeType.MONTHLY.getValue());
|
||||
public boolean isSavingsActivation() {
|
||||
return this.value.equals(ChargeTimeType.SAVINGS_ACTIVATION.getValue());
|
||||
}
|
||||
|
||||
public boolean isYearly() {
|
||||
return this.value.equals(ChargeTimeType.YEARLY.getValue());
|
||||
public boolean isSavingsClosure() {
|
||||
return this.value.equals(ChargeTimeType.SAVINGS_CLOSURE.getValue());
|
||||
}
|
||||
|
||||
public boolean isWithdrawalFee() {
|
||||
return this.value.equals(ChargeTimeType.WITHDRAWAL_FEE.getValue());
|
||||
}
|
||||
|
||||
public boolean isAnnualFee() {
|
||||
return this.value.equals(ChargeTimeType.ANNUAL_FEE.getValue());
|
||||
}
|
||||
|
||||
public boolean isAllowedLoanChargeTime() {
|
||||
@@ -78,6 +100,6 @@ public enum ChargeTimeType {
|
||||
}
|
||||
|
||||
public boolean isAllowedSavingsChargeTime() {
|
||||
return isOnSpecifiedDueDate() || isMonthly() || isYearly();
|
||||
return isOnSpecifiedDueDate() || isSavingsActivation() || isSavingsClosure() || isWithdrawalFee() || isAnnualFee();
|
||||
}
|
||||
}
|
||||
+9
@@ -18,4 +18,13 @@ public interface ChargeDropdownReadPlatformService {
|
||||
List<EnumOptionData> retrieveCollectionTimeTypes();
|
||||
|
||||
List<EnumOptionData> retrivePaymentModes();
|
||||
|
||||
List<EnumOptionData> retrieveLoanCalculationTypes();
|
||||
|
||||
List<EnumOptionData> retrieveLoanCollectionTimeTypes();
|
||||
|
||||
List<EnumOptionData> retrieveSavingsCalculationTypes();
|
||||
|
||||
List<EnumOptionData> retrieveSavingsCollectionTimeTypes();
|
||||
|
||||
}
|
||||
|
||||
+25
-9
@@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.charge.service;
|
||||
|
||||
import static org.mifosplatform.portfolio.charge.service.ChargeEnumerations.chargeCalculationType;
|
||||
import static org.mifosplatform.portfolio.charge.service.ChargeEnumerations.chargePaymentMode;
|
||||
import static org.mifosplatform.portfolio.charge.service.ChargeEnumerations.chargeTimeType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -48,15 +49,7 @@ public class ChargeDropdownReadPlatformServiceImpl implements ChargeDropdownRead
|
||||
public List<EnumOptionData> retrieveCollectionTimeTypes() {
|
||||
final List<EnumOptionData> chargeTimeTypes = new ArrayList<EnumOptionData>();
|
||||
for (final ChargeTimeType chargeTimeType : ChargeTimeType.values()) {
|
||||
if (ChargeTimeType.INVALID.equals(chargeTimeType) || ChargeTimeType.MONTHLY.equals(chargeTimeType) // To
|
||||
// be
|
||||
// implemented
|
||||
// for
|
||||
// Savings
|
||||
|| ChargeTimeType.YEARLY.equals(chargeTimeType)) {
|
||||
// implemented
|
||||
// for
|
||||
// Savings
|
||||
if (ChargeTimeType.INVALID.equals(chargeTimeType)) {
|
||||
continue;
|
||||
}
|
||||
chargeTimeTypes.add(ChargeEnumerations.chargeTimeType(chargeTimeType));
|
||||
@@ -68,4 +61,27 @@ public class ChargeDropdownReadPlatformServiceImpl implements ChargeDropdownRead
|
||||
public List<EnumOptionData> retrivePaymentModes() {
|
||||
return Arrays.asList(chargePaymentMode(ChargePaymentMode.REGULAR), chargePaymentMode(ChargePaymentMode.ACCOUNT_TRANSFER));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveLoanCalculationTypes() {
|
||||
return Arrays.asList(chargeCalculationType(ChargeCalculationType.FLAT), chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveLoanCollectionTimeTypes() {
|
||||
return Arrays.asList(chargeTimeType(ChargeTimeType.DISBURSEMENT), chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveSavingsCalculationTypes() {
|
||||
return Arrays.asList(chargeCalculationType(ChargeCalculationType.FLAT),
|
||||
chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveSavingsCollectionTimeTypes() {
|
||||
return Arrays.asList(chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE), chargeTimeType(ChargeTimeType.SAVINGS_ACTIVATION),
|
||||
chargeTimeType(ChargeTimeType.SAVINGS_CLOSURE), chargeTimeType(ChargeTimeType.WITHDRAWAL_FEE),
|
||||
chargeTimeType(ChargeTimeType.ANNUAL_FEE));
|
||||
}
|
||||
}
|
||||
+10
-4
@@ -28,11 +28,17 @@ public class ChargeEnumerations {
|
||||
optionData = new EnumOptionData(ChargeTimeType.SPECIFIED_DUE_DATE.getValue().longValue(),
|
||||
ChargeTimeType.SPECIFIED_DUE_DATE.getCode(), "Specified due date");
|
||||
break;
|
||||
case MONTHLY:
|
||||
optionData = new EnumOptionData(ChargeTimeType.MONTHLY.getValue().longValue(), ChargeTimeType.MONTHLY.getCode(), "Monthly");
|
||||
case SAVINGS_ACTIVATION:
|
||||
optionData = new EnumOptionData(ChargeTimeType.SAVINGS_ACTIVATION.getValue().longValue(), ChargeTimeType.SAVINGS_ACTIVATION.getCode(), "Savings Activation");
|
||||
break;
|
||||
case YEARLY:
|
||||
optionData = new EnumOptionData(ChargeTimeType.YEARLY.getValue().longValue(), ChargeTimeType.YEARLY.getCode(), "Yearly");
|
||||
case SAVINGS_CLOSURE:
|
||||
optionData = new EnumOptionData(ChargeTimeType.SAVINGS_CLOSURE.getValue().longValue(), ChargeTimeType.SAVINGS_CLOSURE.getCode(), "Savings Closure");
|
||||
break;
|
||||
case WITHDRAWAL_FEE:
|
||||
optionData = new EnumOptionData(ChargeTimeType.WITHDRAWAL_FEE.getValue().longValue(), ChargeTimeType.WITHDRAWAL_FEE.getCode(), "Withdrawal Fee");
|
||||
break;
|
||||
case ANNUAL_FEE:
|
||||
optionData = new EnumOptionData(ChargeTimeType.ANNUAL_FEE.getValue().longValue(), ChargeTimeType.ANNUAL_FEE.getCode(), "Annual Fee");
|
||||
break;
|
||||
default:
|
||||
optionData = new EnumOptionData(ChargeTimeType.INVALID.getValue().longValue(), ChargeTimeType.INVALID.getCode(), "Invalid");
|
||||
|
||||
+9
-1
@@ -82,9 +82,17 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
|
||||
final List<EnumOptionData> allowedChargeAppliesToOptions = this.chargeDropdownReadPlatformService.retrieveApplicableToTypes();
|
||||
final List<EnumOptionData> allowedChargeTimeOptions = this.chargeDropdownReadPlatformService.retrieveCollectionTimeTypes();
|
||||
final List<EnumOptionData> chargePaymentOptions = this.chargeDropdownReadPlatformService.retrivePaymentModes();
|
||||
final List<EnumOptionData> loansChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService
|
||||
.retrieveLoanCalculationTypes();
|
||||
final List<EnumOptionData> loansChargeTimeTypeOptions = this.chargeDropdownReadPlatformService.retrieveLoanCollectionTimeTypes();
|
||||
final List<EnumOptionData> savingsChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService
|
||||
.retrieveSavingsCalculationTypes();
|
||||
final List<EnumOptionData> savingsChargeTimeTypeOptions = this.chargeDropdownReadPlatformService
|
||||
.retrieveSavingsCollectionTimeTypes();
|
||||
|
||||
return ChargeData.template(currencyOptions, allowedChargeCalculationTypeOptions, allowedChargeAppliesToOptions,
|
||||
allowedChargeTimeOptions, chargePaymentOptions);
|
||||
allowedChargeTimeOptions, chargePaymentOptions, loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions,
|
||||
savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+14
-11
@@ -35,6 +35,7 @@ public class LoanTransactionData {
|
||||
private final BigDecimal interestPortion;
|
||||
private final BigDecimal feeChargesPortion;
|
||||
private final BigDecimal penaltyChargesPortion;
|
||||
private final BigDecimal overpaymentPortion;
|
||||
private final String externalId;
|
||||
private final AccountTransferData transfer;
|
||||
|
||||
@@ -46,23 +47,24 @@ public class LoanTransactionData {
|
||||
return new LoanTransactionData(loanTransactionData.id, loanTransactionData.officeId, loanTransactionData.officeName,
|
||||
loanTransactionData.type, loanTransactionData.paymentDetailData, loanTransactionData.currency, loanTransactionData.date,
|
||||
loanTransactionData.amount, loanTransactionData.principalPortion, loanTransactionData.interestPortion,
|
||||
loanTransactionData.feeChargesPortion, loanTransactionData.penaltyChargesPortion, paymentTypeOptions,
|
||||
loanTransactionData.externalId, loanTransactionData.transfer);
|
||||
loanTransactionData.feeChargesPortion, loanTransactionData.penaltyChargesPortion, loanTransactionData.overpaymentPortion,
|
||||
paymentTypeOptions, loanTransactionData.externalId, loanTransactionData.transfer);
|
||||
}
|
||||
|
||||
public LoanTransactionData(final Long id, final Long officeId, final String officeName, final LoanTransactionEnumData transactionType,
|
||||
final PaymentDetailData paymentDetailData, final CurrencyData currency, final LocalDate date, final BigDecimal amount,
|
||||
final BigDecimal principalPortion, final BigDecimal interestPortion, final BigDecimal feeChargesPortion,
|
||||
final BigDecimal penaltyChargesPortion, final String externalId, final AccountTransferData transfer) {
|
||||
this(id, officeId, officeName, transactionType, paymentDetailData, currency, date, amount, principalPortion, interestPortion,
|
||||
feeChargesPortion, penaltyChargesPortion, null, externalId, transfer);
|
||||
}
|
||||
|
||||
public LoanTransactionData(final Long id, final Long officeId, final String officeName, final LoanTransactionEnumData transactionType,
|
||||
final PaymentDetailData paymentDetailData, final CurrencyData currency, final LocalDate date, final BigDecimal amount,
|
||||
final BigDecimal principalPortion, final BigDecimal interestPortion, final BigDecimal feeChargesPortion,
|
||||
final BigDecimal penaltyChargesPortion, final Collection<CodeValueData> paymentTypeOptions, final String externalId,
|
||||
final BigDecimal penaltyChargesPortion, final BigDecimal overpaymentPortion, final String externalId,
|
||||
final AccountTransferData transfer) {
|
||||
this(id, officeId, officeName, transactionType, paymentDetailData, currency, date, amount, principalPortion, interestPortion,
|
||||
feeChargesPortion, penaltyChargesPortion, overpaymentPortion, null, externalId, transfer);
|
||||
}
|
||||
|
||||
public LoanTransactionData(final Long id, final Long officeId, final String officeName, final LoanTransactionEnumData transactionType,
|
||||
final PaymentDetailData paymentDetailData, final CurrencyData currency, final LocalDate date, final BigDecimal amount,
|
||||
final BigDecimal principalPortion, final BigDecimal interestPortion, final BigDecimal feeChargesPortion,
|
||||
final BigDecimal penaltyChargesPortion, final BigDecimal overpaymentPortion,
|
||||
final Collection<CodeValueData> paymentTypeOptions, final String externalId, final AccountTransferData transfer) {
|
||||
this.id = id;
|
||||
this.officeId = officeId;
|
||||
this.officeName = officeName;
|
||||
@@ -78,6 +80,7 @@ public class LoanTransactionData {
|
||||
this.paymentTypeOptions = paymentTypeOptions;
|
||||
this.externalId = externalId;
|
||||
this.transfer = transfer;
|
||||
this.overpaymentPortion = overpaymentPortion;
|
||||
}
|
||||
|
||||
public LocalDate dateOf() {
|
||||
|
||||
+5
-11
@@ -5,8 +5,8 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.loanaccount.domain;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Stores details of {@link LoanTransaction}'s that were reversed or newly
|
||||
@@ -16,16 +16,10 @@ import java.util.List;
|
||||
*/
|
||||
public class ChangedTransactionDetail {
|
||||
|
||||
private final List<LoanTransaction> newTransactions = new ArrayList<LoanTransaction>();
|
||||
private final Map<Long,LoanTransaction> newTransactionMappings = new HashMap<Long, LoanTransaction>();
|
||||
|
||||
private final List<LoanTransaction> reversedTransactions = new ArrayList<LoanTransaction>();
|
||||
|
||||
public List<LoanTransaction> getNewTransactions() {
|
||||
return this.newTransactions;
|
||||
}
|
||||
|
||||
public List<LoanTransaction> getReversedTransactions() {
|
||||
return this.reversedTransactions;
|
||||
public Map<Long, LoanTransaction> getNewTransactionMappings() {
|
||||
return this.newTransactionMappings;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
-7
@@ -444,10 +444,10 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
||||
allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges());
|
||||
for (final LoanTransaction transaction : changedTransactionDetail.getNewTransactions()) {
|
||||
transaction.updateLoan(this);
|
||||
for(Map.Entry<Long,LoanTransaction> mapEntry:changedTransactionDetail.getNewTransactionMappings().entrySet()){
|
||||
mapEntry.getValue().updateLoan(this);
|
||||
}
|
||||
this.loanTransactions.addAll(changedTransactionDetail.getNewTransactions());
|
||||
this.loanTransactions.addAll(changedTransactionDetail.getNewTransactionMappings().values());
|
||||
} else {
|
||||
// just reprocess the loan schedule only for now.
|
||||
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
|
||||
@@ -1493,7 +1493,10 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
return disbursementTransaction;
|
||||
}
|
||||
|
||||
public LoanTransaction handlePayDisbursementTransaction(final Long chargeId, final LoanTransaction chargesPayment) {
|
||||
public LoanTransaction handlePayDisbursementTransaction(final Long chargeId, final LoanTransaction chargesPayment,
|
||||
final List<Long> existingTransactionIds,final List<Long> existingReversedTransactionIds) {
|
||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||
LoanCharge charge = null;
|
||||
for (final LoanCharge loanCharge : this.charges) {
|
||||
if (chargeId.equals(loanCharge.getId())) {
|
||||
@@ -1710,10 +1713,10 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
||||
allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, setOfLoanCharges());
|
||||
for (final LoanTransaction newLoanTransaction : changedTransactionDetail.getNewTransactions()) {
|
||||
newLoanTransaction.updateLoan(this);
|
||||
for(Map.Entry<Long,LoanTransaction> mapEntry:changedTransactionDetail.getNewTransactionMappings().entrySet()){
|
||||
mapEntry.getValue().updateLoan(this);
|
||||
}
|
||||
this.loanTransactions.addAll(changedTransactionDetail.getNewTransactions());
|
||||
this.loanTransactions.addAll(changedTransactionDetail.getNewTransactionMappings().values());
|
||||
}
|
||||
|
||||
updateLoanSummaryDerivedFields();
|
||||
|
||||
+21
-4
@@ -24,6 +24,8 @@ import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
|
||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.account.domain.AccountTransfer;
|
||||
import org.mifosplatform.portfolio.account.domain.AccountTransferRepository;
|
||||
import org.mifosplatform.portfolio.client.domain.Client;
|
||||
import org.mifosplatform.portfolio.client.exception.ClientNotActiveException;
|
||||
import org.mifosplatform.portfolio.group.domain.Group;
|
||||
@@ -49,6 +51,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper;
|
||||
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
|
||||
private final NoteRepository noteRepository;
|
||||
private final AccountTransferRepository accountTransferRepository;
|
||||
|
||||
@Autowired
|
||||
public LoanAccountDomainServiceJpa(final LoanAssembler loanAccountAssembler, final LoanRepository loanRepository,
|
||||
@@ -56,7 +59,8 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
final ConfigurationDomainService configurationDomainService, final HolidayRepository holidayRepository,
|
||||
final WorkingDaysRepositoryWrapper workingDaysRepository,
|
||||
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper,
|
||||
final JournalEntryWritePlatformService journalEntryWritePlatformService) {
|
||||
final JournalEntryWritePlatformService journalEntryWritePlatformService,
|
||||
final AccountTransferRepository accountTransferRepository) {
|
||||
this.loanAccountAssembler = loanAccountAssembler;
|
||||
this.loanRepository = loanRepository;
|
||||
this.loanTransactionRepository = loanTransactionRepository;
|
||||
@@ -66,6 +70,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
this.workingDaysRepository = workingDaysRepository;
|
||||
this.applicationCurrencyRepositoryWrapper = applicationCurrencyRepositoryWrapper;
|
||||
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
|
||||
this.accountTransferRepository = accountTransferRepository;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -115,8 +120,9 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
* recorded against the loan)
|
||||
***/
|
||||
if (changedTransactionDetail != null) {
|
||||
for (final LoanTransaction loanTransaction : changedTransactionDetail.getNewTransactions()) {
|
||||
this.loanTransactionRepository.save(loanTransaction);
|
||||
for(Map.Entry<Long,LoanTransaction> mapEntry:changedTransactionDetail.getNewTransactionMappings().entrySet()){
|
||||
this.loanTransactionRepository.save(mapEntry.getValue());
|
||||
updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
||||
}
|
||||
}
|
||||
this.loanRepository.save(loan);
|
||||
@@ -125,6 +131,8 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
final Note note = Note.loanTransactionNote(loan, newRepaymentTransaction, noteText);
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
|
||||
|
||||
|
||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
@@ -158,7 +166,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
final WorkingDays workingDays = this.workingDaysRepository.findOne();
|
||||
final boolean allowTransactionsOnNonWorkingDay = this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled();
|
||||
if (loanTransactionType.isRepaymentAtDisbursement()) {
|
||||
loan.handlePayDisbursementTransaction(chargeId, newPaymentTransaction);
|
||||
loan.handlePayDisbursementTransaction(chargeId, newPaymentTransaction, existingTransactionIds, existingReversedTransactionIds);
|
||||
} else {
|
||||
loan.makeChargePayment(chargeId, defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds,
|
||||
allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay, newPaymentTransaction);
|
||||
@@ -247,4 +255,13 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
loanTransaction.reverse();
|
||||
this.loanTransactionRepository.save(loanTransaction);
|
||||
}
|
||||
|
||||
private void updateLoanTransaction(final Long loanTransactionId,final LoanTransaction newLoanTransaction){
|
||||
final AccountTransfer transferTransaction = this.accountTransferRepository.findByToLoanTransactionId(loanTransactionId);
|
||||
if(transferTransaction!=null){
|
||||
transferTransaction.updateToLoanTransaction(newLoanTransaction);
|
||||
this.accountTransferRepository.save(transferTransaction);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+24
-8
@@ -82,6 +82,9 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
@Column(name = "penalty_charges_portion_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal penaltyChargesPortion;
|
||||
|
||||
@Column(name = "overpayment_portion_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal overPaymentPortion;
|
||||
|
||||
@Column(name = "is_reversed", nullable = false)
|
||||
private boolean reversed;
|
||||
|
||||
@@ -133,21 +136,21 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
return new LoanTransaction(loan, office, LoanTransactionType.INITIATE_TRANSFER.getValue(), transferDate.toDateMidnight().toDate(),
|
||||
loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(), loan.getSummary()
|
||||
.getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(), loan.getSummary()
|
||||
.getTotalPenaltyChargesOutstanding(), false, null);
|
||||
.getTotalPenaltyChargesOutstanding(), null, false, null);
|
||||
}
|
||||
|
||||
public static LoanTransaction approveTransfer(final Office office, final Loan loan, final LocalDate transferDate) {
|
||||
return new LoanTransaction(loan, office, LoanTransactionType.APPROVE_TRANSFER.getValue(), transferDate.toDateMidnight().toDate(),
|
||||
loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(), loan.getSummary()
|
||||
.getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(), loan.getSummary()
|
||||
.getTotalPenaltyChargesOutstanding(), false, null);
|
||||
.getTotalPenaltyChargesOutstanding(), null, false, null);
|
||||
}
|
||||
|
||||
public static LoanTransaction withdrawTransfer(final Office office, final Loan loan, final LocalDate transferDate) {
|
||||
return new LoanTransaction(loan, office, LoanTransactionType.WITHDRAW_TRANSFER.getValue(), transferDate.toDateMidnight().toDate(),
|
||||
loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(), loan.getSummary()
|
||||
.getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(), loan.getSummary()
|
||||
.getTotalPenaltyChargesOutstanding(), false, null);
|
||||
.getTotalPenaltyChargesOutstanding(), null, false, null);
|
||||
}
|
||||
|
||||
public static LoanTransaction refund(final Office office, final Money amount, final PaymentDetail paymentDetail,
|
||||
@@ -158,8 +161,8 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
public static LoanTransaction copyTransactionProperties(final LoanTransaction loanTransaction) {
|
||||
return new LoanTransaction(loanTransaction.loan, loanTransaction.office, loanTransaction.typeOf, loanTransaction.dateOf,
|
||||
loanTransaction.amount, loanTransaction.principalPortion, loanTransaction.interestPortion,
|
||||
loanTransaction.feeChargesPortion, loanTransaction.penaltyChargesPortion, loanTransaction.reversed,
|
||||
loanTransaction.paymentDetail);
|
||||
loanTransaction.feeChargesPortion, loanTransaction.penaltyChargesPortion, loanTransaction.overPaymentPortion,
|
||||
loanTransaction.reversed, loanTransaction.paymentDetail);
|
||||
}
|
||||
|
||||
public static LoanTransaction applyLoanCharge(final Loan loan, final Office office, final Money amount, final LocalDate applyDate,
|
||||
@@ -176,13 +179,15 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
&& (loanTransaction.getPrincipalPortion(currency).isEqualTo(newLoanTransaction.getPrincipalPortion(currency)))
|
||||
&& (loanTransaction.getInterestPortion(currency).isEqualTo(newLoanTransaction.getInterestPortion(currency)))
|
||||
&& (loanTransaction.getFeeChargesPortion(currency).isEqualTo(newLoanTransaction.getFeeChargesPortion(currency)))
|
||||
&& (loanTransaction.getPenaltyChargesPortion(currency).isEqualTo(newLoanTransaction.getPenaltyChargesPortion(currency)))) { return true; }
|
||||
&& (loanTransaction.getPenaltyChargesPortion(currency).isEqualTo(newLoanTransaction.getPenaltyChargesPortion(currency)))
|
||||
&& (loanTransaction.getOverPaymentPortion(currency).isEqualTo(newLoanTransaction.getOverPaymentPortion(currency)))) { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
private LoanTransaction(final Loan loan, final Office office, final Integer typeOf, final Date dateOf, final BigDecimal amount,
|
||||
final BigDecimal principalPortion, final BigDecimal interestPortion, final BigDecimal feeChargesPortion,
|
||||
final BigDecimal penaltyChargesPortion, final boolean reversed, final PaymentDetail paymentDetail) {
|
||||
final BigDecimal penaltyChargesPortion, final BigDecimal overPaymentPortion, final boolean reversed,
|
||||
final PaymentDetail paymentDetail) {
|
||||
super();
|
||||
this.loan = loan;
|
||||
this.typeOf = typeOf;
|
||||
@@ -192,6 +197,7 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
this.interestPortion = interestPortion;
|
||||
this.feeChargesPortion = feeChargesPortion;
|
||||
this.penaltyChargesPortion = penaltyChargesPortion;
|
||||
this.overPaymentPortion = overPaymentPortion;
|
||||
this.reversed = reversed;
|
||||
this.paymentDetail = paymentDetail;
|
||||
this.office = office;
|
||||
@@ -274,6 +280,11 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
.plus(getPenaltyChargesPortion(currency)).getAmount();
|
||||
}
|
||||
|
||||
public void updateOverPayments(final Money overPayment) {
|
||||
final MonetaryCurrency currency = overPayment.getCurrency();
|
||||
this.overPaymentPortion = defaultToNullIfZero(getOverPaymentPortion(currency).plus(overPayment).getAmount());
|
||||
}
|
||||
|
||||
public Money getPrincipalPortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.principalPortion);
|
||||
}
|
||||
@@ -294,6 +305,10 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
return Money.of(currency, this.penaltyChargesPortion);
|
||||
}
|
||||
|
||||
public Money getOverPaymentPortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.overPaymentPortion);
|
||||
}
|
||||
|
||||
public Money getAmount(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amount);
|
||||
}
|
||||
@@ -425,7 +440,7 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
}
|
||||
return new LoanTransactionData(getId(), this.office.getId(), this.office.getName(), transactionType, paymentDetailData,
|
||||
currencyData, getTransactionDate(), this.amount, this.principalPortion, this.interestPortion, this.feeChargesPortion,
|
||||
this.penaltyChargesPortion, this.externalId, transfer);
|
||||
this.penaltyChargesPortion, this.overPaymentPortion, this.externalId, transfer);
|
||||
}
|
||||
|
||||
public Map<String, Object> toMapData(final CurrencyData currencyData) {
|
||||
@@ -444,6 +459,7 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
thisTransactionData.put("interestPortion", this.interestPortion);
|
||||
thisTransactionData.put("feeChargesPortion", this.feeChargesPortion);
|
||||
thisTransactionData.put("penaltyChargesPortion", this.penaltyChargesPortion);
|
||||
thisTransactionData.put("overPaymentPortion", this.overPaymentPortion);
|
||||
|
||||
if (this.paymentDetail != null) {
|
||||
thisTransactionData.put("paymentTypeId", this.paymentDetail.getPaymentType().getId());
|
||||
|
||||
+2
-2
@@ -118,8 +118,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
**/
|
||||
if (!LoanTransaction.transactionAmountsMatch(currency, loanTransaction, newLoanTransaction)) {
|
||||
loanTransaction.reverse();
|
||||
changedTransactionDetail.getReversedTransactions().add(loanTransaction);
|
||||
changedTransactionDetail.getNewTransactions().add(newLoanTransaction);
|
||||
changedTransactionDetail.getNewTransactionMappings().put(loanTransaction.getId(), newLoanTransaction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,6 +186,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
|
||||
if (transactionAmountUnprocessed.isGreaterThanZero()) {
|
||||
onLoanOverpayment(loanTransaction, transactionAmountUnprocessed);
|
||||
loanTransaction.updateOverPayments(transactionAmountUnprocessed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -542,7 +542,7 @@ public final class LoanApplicationTerms {
|
||||
switch (this.interestCalculationPeriodMethod) {
|
||||
case DAILY:
|
||||
final BigDecimal dailyInterestRate = this.annualNominalInterestRate.divide(BigDecimal.valueOf(Long.valueOf(365)), mc)
|
||||
.divide(BigDecimal.valueOf(Double.valueOf("100.0")), mc).multiply(BigDecimal.valueOf(this.repaymentEvery));
|
||||
.divide(BigDecimal.valueOf(Double.valueOf("100.0")), mc);
|
||||
|
||||
final BigDecimal equivalentInterestRateForPeriod = dailyInterestRate
|
||||
.multiply(BigDecimal.valueOf(Long.valueOf(daysInPeriod)));
|
||||
|
||||
+11
-2
@@ -115,8 +115,17 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
|
||||
|
||||
final List<EnumOptionData> allowedChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService.retrieveCalculationTypes();
|
||||
final List<EnumOptionData> allowedChargeTimeOptions = this.chargeDropdownReadPlatformService.retrieveCollectionTimeTypes();
|
||||
|
||||
return ChargeData.template(null, allowedChargeCalculationTypeOptions, null, allowedChargeTimeOptions, null);
|
||||
final List<EnumOptionData> loansChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService
|
||||
.retrieveLoanCalculationTypes();
|
||||
final List<EnumOptionData> loansChargeTimeTypeOptions = this.chargeDropdownReadPlatformService.retrieveLoanCollectionTimeTypes();
|
||||
final List<EnumOptionData> savingsChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService
|
||||
.retrieveSavingsCalculationTypes();
|
||||
final List<EnumOptionData> savingsChargeTimeTypeOptions = this.chargeDropdownReadPlatformService
|
||||
.retrieveSavingsCollectionTimeTypes();
|
||||
|
||||
return ChargeData.template(null, allowedChargeCalculationTypeOptions, null, allowedChargeTimeOptions, null,
|
||||
loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions, savingsChargeCalculationTypeOptions,
|
||||
savingsChargeTimeTypeOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+7
-5
@@ -330,7 +330,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
final Collection<CodeValueData> paymentOptions = this.codeValueReadPlatformService
|
||||
.retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName);
|
||||
return new LoanTransactionData(null, null, null, transactionType, null, currencyData, earliestUnpaidInstallmentDate,
|
||||
possibleNextRepaymentAmount.getAmount(), null, null, null, null, paymentOptions, null, null);
|
||||
possibleNextRepaymentAmount.getAmount(), null, null, null, null, null, paymentOptions, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -354,7 +354,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
|
||||
final BigDecimal amount = waiveOfInterest.getAmount(currency).getAmount();
|
||||
return new LoanTransactionData(null, null, null, transactionType, null, currencyData, waiveOfInterest.getTransactionDate(), amount,
|
||||
null, null, null, null, null, null);
|
||||
null, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -364,7 +364,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
|
||||
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.WRITEOFF);
|
||||
return new LoanTransactionData(null, null, null, transactionType, null, null, DateUtils.getLocalDateOfTenant(), null, null, null,
|
||||
null, null, null, null);
|
||||
null, null, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -375,7 +375,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
final Collection<CodeValueData> paymentOptions = this.codeValueReadPlatformService
|
||||
.retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName);
|
||||
return new LoanTransactionData(null, null, null, transactionType, null, null, loan.getExpectedDisbursedOnLocalDate(), null, null,
|
||||
null, null, null, paymentOptions, null, null);
|
||||
null, null, null, null, paymentOptions, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -861,6 +861,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
return " tr.id as id, tr.transaction_type_enum as transactionType, tr.transaction_date as `date`, tr.amount as total, "
|
||||
+ " tr.principal_portion_derived as principal, tr.interest_portion_derived as interest, "
|
||||
+ " tr.fee_charges_portion_derived as fees, tr.penalty_charges_portion_derived as penalties, "
|
||||
+ " tr.overpayment_portion_derived as overpayment, "
|
||||
+ " pd.payment_type_cv_id as paymentType,pd.account_number as accountNumber,pd.check_number as checkNumber, "
|
||||
+ " pd.receipt_number as receiptNumber, pd.bank_number as bankNumber,pd.routing_code as routingCode, "
|
||||
+ " l.currency_code as currencyCode, l.currency_digits as currencyDigits, l.currency_multiplesof as inMultiplesOf, rc.`name` as currencyName, "
|
||||
@@ -920,6 +921,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
final BigDecimal interestPortion = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "interest");
|
||||
final BigDecimal feeChargesPortion = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "fees");
|
||||
final BigDecimal penaltyChargesPortion = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "penalties");
|
||||
final BigDecimal overPaymentPortion = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "overpayment");
|
||||
final String externalId = rs.getString("externalId");
|
||||
|
||||
AccountTransferData transfer = null;
|
||||
@@ -944,7 +946,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
}
|
||||
|
||||
return new LoanTransactionData(id, officeId, officeName, transactionType, paymentDetailData, currencyData, date, totalAmount,
|
||||
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion, externalId, transfer);
|
||||
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion, overPaymentPortion, externalId, transfer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-6
@@ -523,8 +523,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
* payment recorded against the loan)
|
||||
***/
|
||||
if (changedTransactionDetail != null) {
|
||||
for (final LoanTransaction loanTransaction : changedTransactionDetail.getNewTransactions()) {
|
||||
this.loanTransactionRepository.save(loanTransaction);
|
||||
for(Map.Entry<Long,LoanTransaction> mapEntry:changedTransactionDetail.getNewTransactionMappings().entrySet()){
|
||||
this.loanTransactionRepository.save(mapEntry.getValue());
|
||||
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,8 +599,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
* recorded against the loan)
|
||||
***/
|
||||
if (changedTransactionDetail != null) {
|
||||
for (final LoanTransaction loanTransaction : changedTransactionDetail.getNewTransactions()) {
|
||||
this.loanTransactionRepository.save(loanTransaction);
|
||||
for(Map.Entry<Long,LoanTransaction> mapEntry:changedTransactionDetail.getNewTransactionMappings().entrySet()){
|
||||
this.loanTransactionRepository.save(mapEntry.getValue());
|
||||
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -819,8 +821,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
* latest payment recorded against the loan)
|
||||
***/
|
||||
if (changedTransactionDetail != null) {
|
||||
for (final LoanTransaction loanTransaction : changedTransactionDetail.getNewTransactions()) {
|
||||
this.loanTransactionRepository.save(loanTransaction);
|
||||
for(Map.Entry<Long,LoanTransaction> mapEntry:changedTransactionDetail.getNewTransactionMappings().entrySet()){
|
||||
this.loanTransactionRepository.save(mapEntry.getValue());
|
||||
this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-2
@@ -48,8 +48,8 @@ public final class LoanProductDataValidator {
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.FEE_INCOME_ACCOUNT_MAPPING.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTY_INCOME_ACCOUNT_MAPPING.getValue()));
|
||||
@@ -282,6 +282,11 @@ public final class LoanProductDataValidator {
|
||||
baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue()).value(writeOffAccountId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
final Long overpaymentAccountId = this.fromApiJsonHelper.extractLongNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(), element);
|
||||
baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue()).value(overpaymentAccountId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
validatePaymentChannelFundSourceMappings(baseDataValidator, element);
|
||||
validateChargeToIncomeAccountMappings(baseDataValidator, element);
|
||||
|
||||
@@ -520,6 +525,11 @@ public final class LoanProductDataValidator {
|
||||
baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue()).value(writeOffAccountId)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
final Long overpaymentAccountId = this.fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(),
|
||||
element);
|
||||
baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue()).value(overpaymentAccountId)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
final Long receivableInterestAccountId = this.fromApiJsonHelper.extractLongNamed(
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), element);
|
||||
baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue())
|
||||
|
||||
+7
-3
@@ -19,7 +19,7 @@ public enum SavingsAccountTransactionType {
|
||||
INTEREST_POSTING(3, "savingsAccountTransactionType.interestPosting"), //
|
||||
WITHDRAWAL_FEE(4, "savingsAccountTransactionType.withdrawalFee"), //
|
||||
ANNUAL_FEE(5, "savingsAccountTransactionType.annualFee"), //
|
||||
WAIVE_CHARGES(6, "savingsAccountTransactionType.waiveCharges"), //
|
||||
WAIVE_CHARGES(6, "savingsAccountTransactionType.waiveCharge"), //
|
||||
PAY_CHARGE(7, "savingsAccountTransactionType.payCharge"), //
|
||||
INITIATE_TRANSFER(12, "savingsAccountTransactionType.initiateTransfer"), //
|
||||
APPROVE_TRANSFER(13, "savingsAccountTransactionType.approveTransfer"), //
|
||||
@@ -105,9 +105,13 @@ public enum SavingsAccountTransactionType {
|
||||
return this.value.equals(SavingsAccountTransactionType.ANNUAL_FEE.getValue());
|
||||
}
|
||||
|
||||
public boolean isCharge() {
|
||||
public boolean isPayCharge() {
|
||||
return this.value.equals(SavingsAccountTransactionType.PAY_CHARGE.getValue());
|
||||
}
|
||||
|
||||
public boolean isChargeTransaction(){
|
||||
return isPayCharge() || isWithdrawalFee() || isAnnualFee();
|
||||
}
|
||||
|
||||
public boolean isWaiveCharge() {
|
||||
return this.value.equals(SavingsAccountTransactionType.WAIVE_CHARGES.getValue());
|
||||
@@ -130,7 +134,7 @@ public enum SavingsAccountTransactionType {
|
||||
}
|
||||
|
||||
public boolean isDebit() {
|
||||
return isWithdrawal() || isWithdrawalFee() || isAnnualFee() || isCharge();
|
||||
return isWithdrawal() || isWithdrawalFee() || isAnnualFee() || isPayCharge();
|
||||
}
|
||||
|
||||
public boolean isCredit() {
|
||||
|
||||
+27
-12
@@ -34,6 +34,7 @@ public class SavingsApiConstants {
|
||||
public static String adjustTransactionAction = ".adjusttransaction";
|
||||
public static String closeAction = ".close";
|
||||
public static String payChargeTransactionAction = ".paycharge";
|
||||
public static String waiveChargeTransactionAction = ".waivecharge";
|
||||
|
||||
// command
|
||||
public static String COMMAND_UNDO_TRANSACTION = "undo";
|
||||
@@ -80,8 +81,8 @@ public class SavingsApiConstants {
|
||||
public static final String withdrawalFeeAmountParamName = "withdrawalFeeAmount";
|
||||
public static final String withdrawalFeeTypeParamName = "withdrawalFeeType";
|
||||
public static final String withdrawalFeeForTransfersParamName = "withdrawalFeeForTransfers";
|
||||
public static final String annualFeeAmountParamName = "annualFeeAmount";
|
||||
public static final String annualFeeOnMonthDayParamName = "annualFeeOnMonthDay";
|
||||
public static final String feeAmountParamName = "feeAmount";//to be deleted
|
||||
public static final String feeOnMonthDayParamName = "feeOnMonthDay";
|
||||
public static final String accountingRuleParamName = "accountingRule";
|
||||
public static final String paymentTypeIdParamName = "paymentTypeId";
|
||||
public static final String transactionAccountNumberParamName = "accountNumber";
|
||||
@@ -117,21 +118,30 @@ public class SavingsApiConstants {
|
||||
public static final String amountParamName = "amount";
|
||||
public static final String amountPaidParamName = "amountPaid";
|
||||
public static final String chargeOptionsParamName = "chargeOptions";
|
||||
public static final String chargePaymentModeParamName = "chargePaymentMode";
|
||||
|
||||
public static final String noteParamName = "note";
|
||||
|
||||
//Savings account associations
|
||||
public static final String transactions = "transactions";
|
||||
public static final String charges = "charges";
|
||||
|
||||
|
||||
public static final Set<String> SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
|
||||
monthDayFormatParamName, nameParamName, descriptionParamName, currencyCodeParamName, digitsAfterDecimalParamName,
|
||||
inMultiplesOfParamName, nominalAnnualInterestRateParamName, interestCompoundingPeriodTypeParamName,
|
||||
interestPostingPeriodTypeParamName, interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName,
|
||||
minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName,
|
||||
withdrawalFeeAmountParamName, withdrawalFeeTypeParamName, withdrawalFeeForTransfersParamName, annualFeeAmountParamName,
|
||||
annualFeeOnMonthDayParamName, accountingRuleParamName, chargesParamName,
|
||||
withdrawalFeeAmountParamName, withdrawalFeeTypeParamName, withdrawalFeeForTransfersParamName, feeAmountParamName,
|
||||
feeOnMonthDayParamName, accountingRuleParamName, chargesParamName,
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(),
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(),
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(),
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(),
|
||||
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.SAVINGS_REFERENCE.getValue(),
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.FEE_INCOME_ACCOUNT_MAPPING.getValue(),
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.PENALTY_INCOME_ACCOUNT_MAPPING.getValue()));
|
||||
|
||||
/**
|
||||
* These parameters will match the class level parameters of
|
||||
@@ -143,7 +153,7 @@ public class SavingsApiConstants {
|
||||
nominalAnnualInterestRateParamName, interestCompoundingPeriodTypeParamName, interestPostingPeriodTypeParamName,
|
||||
interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName, minRequiredOpeningBalanceParamName,
|
||||
lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName, withdrawalFeeAmountParamName, withdrawalFeeTypeParamName,
|
||||
withdrawalFeeForTransfersParamName, annualFeeAmountParamName, annualFeeOnMonthDayParamName, "currencyOptions",
|
||||
withdrawalFeeForTransfersParamName, feeAmountParamName, feeOnMonthDayParamName, "currencyOptions",
|
||||
"interestCompoundingPeriodTypeOptions", "interestPostingPeriodTypeOptions", "interestCalculationTypeOptions",
|
||||
"interestCalculationDaysInYearTypeOptions", "lockinPeriodFrequencyTypeOptions", "withdrawalFeeTypeOptions"));
|
||||
|
||||
@@ -152,8 +162,10 @@ public class SavingsApiConstants {
|
||||
productIdParamName, fieldOfficerIdParamName, submittedOnDateParamName, nominalAnnualInterestRateParamName,
|
||||
interestCompoundingPeriodTypeParamName, interestPostingPeriodTypeParamName, interestCalculationTypeParamName,
|
||||
interestCalculationDaysInYearTypeParamName, minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName,
|
||||
lockinPeriodFrequencyTypeParamName, withdrawalFeeAmountParamName, withdrawalFeeTypeParamName,
|
||||
withdrawalFeeForTransfersParamName, annualFeeAmountParamName, annualFeeOnMonthDayParamName, chargesParamName));
|
||||
lockinPeriodFrequencyTypeParamName,
|
||||
//withdrawalFeeAmountParamName, withdrawalFeeTypeParamName,
|
||||
//withdrawalFeeForTransfersParamName,
|
||||
feeAmountParamName, feeOnMonthDayParamName, chargesParamName));
|
||||
|
||||
/**
|
||||
* These parameters will match the class level parameters of
|
||||
@@ -165,10 +177,10 @@ public class SavingsApiConstants {
|
||||
groupIdParamName, "groupName", "savingsProductId", "savingsProductName", "currency", nominalAnnualInterestRateParamName,
|
||||
interestCompoundingPeriodTypeParamName, interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName,
|
||||
minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName,
|
||||
withdrawalFeeAmountParamName, withdrawalFeeTypeParamName, withdrawalFeeForTransfersParamName, annualFeeAmountParamName,
|
||||
annualFeeOnMonthDayParamName, "summary", "transactions", "productOptions", "interestCompoundingPeriodTypeOptions",
|
||||
withdrawalFeeAmountParamName, withdrawalFeeTypeParamName, withdrawalFeeForTransfersParamName, feeAmountParamName,
|
||||
feeOnMonthDayParamName, "summary", "transactions", "productOptions", "interestCompoundingPeriodTypeOptions",
|
||||
"interestPostingPeriodTypeOptions", "interestCalculationTypeOptions", "interestCalculationDaysInYearTypeOptions",
|
||||
"lockinPeriodFrequencyTypeOptions", "withdrawalFeeTypeOptions"));
|
||||
"lockinPeriodFrequencyTypeOptions", "withdrawalFeeTypeOptions", "withdrawalFee", "annualFee"));
|
||||
|
||||
public static final Set<String> SAVINGS_ACCOUNT_TRANSACTION_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(
|
||||
localeParamName, dateFormatParamName, transactionDateParamName, transactionAmountParamName, paymentTypeIdParamName,
|
||||
@@ -191,5 +203,8 @@ public class SavingsApiConstants {
|
||||
amountPaidParamName, chargeOptionsParamName));
|
||||
|
||||
public static final Set<String> SAVINGS_ACCOUNT_CHARGES_ADD_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(
|
||||
chargeIdParamName, amountParamName, dueAsOfDateParamName, dateFormatParamName, localeParamName));
|
||||
chargeIdParamName, amountParamName, dueAsOfDateParamName, dateFormatParamName, localeParamName, feeOnMonthDayParamName, monthDayFormatParamName));
|
||||
|
||||
public static final Set<String> SAVINGS_ACCOUNT_CHARGES_PAY_CHARGE_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(
|
||||
amountParamName, dueAsOfDateParamName, dateFormatParamName, localeParamName));
|
||||
}
|
||||
+1
-1
@@ -155,7 +155,7 @@ public class SavingsAccountChargesApiResource {
|
||||
@Path("{savingsAccountChargeId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String waiveSavingsAccountCharge(@PathParam("savingsAccountId") final Long savingsAccountId,
|
||||
public String payOrWaiveSavingsAccountCharge(@PathParam("savingsAccountId") final Long savingsAccountId,
|
||||
@PathParam("savingsAccountChargeId") final Long savingsAccountChargeId, @QueryParam("command") final String commandParam,
|
||||
final String apiRequestBodyAsJson) {
|
||||
|
||||
|
||||
+5
-5
@@ -154,11 +154,11 @@ public class SavingsAccountsApiResource {
|
||||
if (!associationParameters.isEmpty()) {
|
||||
|
||||
if (associationParameters.contains("all")) {
|
||||
associationParameters.addAll(Arrays.asList("transactions", "charges"));
|
||||
associationParameters.addAll(Arrays.asList(SavingsApiConstants.transactions, SavingsApiConstants.charges));
|
||||
}
|
||||
|
||||
if (associationParameters.contains("transactions")) {
|
||||
mandatoryResponseParameters.add("transactions");
|
||||
if (associationParameters.contains(SavingsApiConstants.transactions)) {
|
||||
mandatoryResponseParameters.add(SavingsApiConstants.transactions);
|
||||
final Collection<SavingsAccountTransactionData> currentTransactions = this.savingsAccountReadPlatformService
|
||||
.retrieveAllTransactions(accountId);
|
||||
if (!CollectionUtils.isEmpty(currentTransactions)) {
|
||||
@@ -166,8 +166,8 @@ public class SavingsAccountsApiResource {
|
||||
}
|
||||
}
|
||||
|
||||
if (associationParameters.contains("charges")) {
|
||||
mandatoryResponseParameters.add("charges");
|
||||
if (associationParameters.contains(SavingsApiConstants.charges)) {
|
||||
mandatoryResponseParameters.add(SavingsApiConstants.charges);
|
||||
final Collection<SavingsAccountChargeData> currentCharges = this.savingsAccountChargeReadPlatformService
|
||||
.retrieveSavingsAccountCharges(accountId);
|
||||
if (!CollectionUtils.isEmpty(currentCharges)) {
|
||||
|
||||
+6
-1
@@ -26,6 +26,7 @@ import org.mifosplatform.accounting.common.AccountingDropdownReadPlatformService
|
||||
import org.mifosplatform.accounting.common.AccountingEnumerations;
|
||||
import org.mifosplatform.accounting.common.AccountingRuleType;
|
||||
import org.mifosplatform.accounting.glaccount.data.GLAccountData;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.service.ProductToGLAccountMappingReadPlatformService;
|
||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||
@@ -159,8 +160,12 @@ public class SavingsProductsApiResource {
|
||||
.fetchAccountMappingDetailsForSavingsProduct(productId, savingProductData.accountingRuleTypeId());
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = this.accountMappingReadPlatformService
|
||||
.fetchPaymentTypeToFundSourceMappingsForSavingsProduct(productId);
|
||||
Collection<ChargeToGLAccountMapper> feeToGLAccountMappings = this.accountMappingReadPlatformService
|
||||
.fetchFeeToIncomeAccountMappingsForSavingsProduct(productId);
|
||||
Collection<ChargeToGLAccountMapper> penaltyToGLAccountMappings = this.accountMappingReadPlatformService
|
||||
.fetchPenaltyToIncomeAccountMappingsForSavingsProduct(productId);
|
||||
savingProductData = SavingsProductData.withAccountingDetails(savingProductData, accountingMappings,
|
||||
paymentChannelToFundSourceMappings);
|
||||
paymentChannelToFundSourceMappings, feeToGLAccountMappings, penaltyToGLAccountMappings);
|
||||
}
|
||||
|
||||
if (settings.isTemplate()) {
|
||||
|
||||
+19
-5
@@ -9,9 +9,11 @@ import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
||||
import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
|
||||
|
||||
/**
|
||||
* Immutable data object for Savings Account charge data.
|
||||
@@ -27,12 +29,14 @@ public class SavingsAccountChargeData {
|
||||
@SuppressWarnings("unused")
|
||||
private final String name;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final EnumOptionData chargeTimeType;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final LocalDate dueDate;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final MonthDay feeOnMonthDay;
|
||||
|
||||
private final EnumOptionData chargeCalculationType;
|
||||
|
||||
private final BigDecimal percentage;
|
||||
@@ -82,28 +86,30 @@ public class SavingsAccountChargeData {
|
||||
final BigDecimal percentage = BigDecimal.ZERO;
|
||||
final boolean penalty = false;
|
||||
final LocalDate dueAsOfDate = null;
|
||||
final MonthDay feeOnMonthDay = null;
|
||||
|
||||
|
||||
return new SavingsAccountChargeData(id, chargeId, name, chargeTimeType, dueAsOfDate, chargeCalculationType, percentage,
|
||||
amountPercentageAppliedTo, currency, amount, amountPaid, amountWaived, amountWrittenOff, amountOutstanding, chargeOptions,
|
||||
penalty);
|
||||
penalty, feeOnMonthDay);
|
||||
}
|
||||
|
||||
public static SavingsAccountChargeData instance(final Long id, final Long chargeId, final String name, final CurrencyData currency,
|
||||
final BigDecimal amount, final BigDecimal amountPaid, final BigDecimal amountWaived, final BigDecimal amountWrittenOff,
|
||||
final BigDecimal amountOutstanding, final EnumOptionData chargeTimeType, final LocalDate dueAsOfDate,
|
||||
final EnumOptionData chargeCalculationType, final BigDecimal percentage, final BigDecimal amountPercentageAppliedTo,
|
||||
final Collection<ChargeData> chargeOptions, final boolean penalty) {
|
||||
final Collection<ChargeData> chargeOptions, final boolean penalty, final MonthDay feeOnMonthDay) {
|
||||
|
||||
return new SavingsAccountChargeData(id, chargeId, name, chargeTimeType, dueAsOfDate, chargeCalculationType, percentage,
|
||||
amountPercentageAppliedTo, currency, amount, amountPaid, amountWaived, amountWrittenOff, amountOutstanding, chargeOptions,
|
||||
penalty);
|
||||
penalty, feeOnMonthDay);
|
||||
}
|
||||
|
||||
private SavingsAccountChargeData(final Long id, final Long chargeId, final String name, final EnumOptionData chargeTimeType,
|
||||
final LocalDate dueAsOfDate, final EnumOptionData chargeCalculationType, final BigDecimal percentage,
|
||||
final BigDecimal amountPercentageAppliedTo, final CurrencyData currency, final BigDecimal amount, final BigDecimal amountPaid,
|
||||
final BigDecimal amountWaived, final BigDecimal amountWrittenOff, final BigDecimal amountOutstanding,
|
||||
final Collection<ChargeData> chargeOptions, final boolean penalty) {
|
||||
final Collection<ChargeData> chargeOptions, final boolean penalty, final MonthDay feeOnMonthDay) {
|
||||
this.id = id;
|
||||
this.chargeId = chargeId;
|
||||
this.name = name;
|
||||
@@ -121,10 +127,18 @@ public class SavingsAccountChargeData {
|
||||
this.amountOrPercentage = getAmountOrPercentage();
|
||||
this.chargeOptions = chargeOptions;
|
||||
this.penalty = penalty;
|
||||
this.feeOnMonthDay = feeOnMonthDay;
|
||||
}
|
||||
|
||||
private BigDecimal getAmountOrPercentage() {
|
||||
return (this.chargeCalculationType != null) && (this.chargeCalculationType.getId().intValue() > 1) ? this.percentage : this.amount;
|
||||
}
|
||||
|
||||
public boolean isWithdrawalFee(){
|
||||
return ChargeTimeType.fromInt(this.chargeTimeType.getId().intValue()).isWithdrawalFee();
|
||||
}
|
||||
|
||||
public boolean isAnnualFee(){
|
||||
return ChargeTimeType.fromInt(this.chargeTimeType.getId().intValue()).isAnnualFee();
|
||||
}
|
||||
}
|
||||
+35
-3
@@ -6,10 +6,12 @@
|
||||
package org.mifosplatform.portfolio.savings.data;
|
||||
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_CHARGES_ADD_REQUEST_DATA_PARAMETERS;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_CHARGES_PAY_CHARGE_REQUEST_DATA_PARAMETERS;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_CHARGE_RESOURCE_NAME;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.amountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargeIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.feeOnMonthDayParamName;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
@@ -18,6 +20,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
||||
@@ -57,9 +61,15 @@ public class SavingsAccountChargeDataValidator {
|
||||
baseDataValidator.reset().parameter(amountParamName).value(amount).notNull().positiveAmount();
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(dueAsOfDateParamName, element)) {
|
||||
this.fromApiJsonHelper.extractLocalDateNamed(dueAsOfDateParamName, element);
|
||||
final LocalDate transactionDate = this.fromApiJsonHelper.extractLocalDateNamed(dueAsOfDateParamName, element);
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(transactionDate).notNull();
|
||||
}
|
||||
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(feeOnMonthDayParamName, element)) {
|
||||
final MonthDay monthDay = this.fromApiJsonHelper.extractMonthDayNamed(feeOnMonthDayParamName, element);
|
||||
baseDataValidator.reset().parameter(feeOnMonthDayParamName).value(monthDay).notNull();
|
||||
}
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
@@ -79,12 +89,34 @@ public class SavingsAccountChargeDataValidator {
|
||||
baseDataValidator.reset().parameter(amountParamName).value(amount).notNull().positiveAmount();
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(dueAsOfDateParamName, element)) {
|
||||
this.fromApiJsonHelper.extractLocalDateNamed(dueAsOfDateParamName, element);
|
||||
final LocalDate transactionDate = this.fromApiJsonHelper.extractLocalDateNamed(dueAsOfDateParamName, element);
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(transactionDate).notNull();
|
||||
}
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
public void validatePayCharge(final String json) {
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SAVINGS_ACCOUNT_CHARGES_PAY_CHARGE_REQUEST_DATA_PARAMETERS);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_CHARGE_RESOURCE_NAME);
|
||||
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
|
||||
final BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(amountParamName, element);
|
||||
baseDataValidator.reset().parameter(amountParamName).value(amount).notNull().positiveAmount();
|
||||
|
||||
final LocalDate transactionDate = this.fromApiJsonHelper.extractLocalDateNamed(dueAsOfDateParamName, element);
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(transactionDate).notNull();
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
+95
-50
@@ -7,11 +7,10 @@ package org.mifosplatform.portfolio.savings.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.organisation.staff.data.StaffData;
|
||||
@@ -44,18 +43,13 @@ public class SavingsAccountData {
|
||||
private final BigDecimal minRequiredOpeningBalance;
|
||||
private final Integer lockinPeriodFrequency;
|
||||
private final EnumOptionData lockinPeriodFrequencyType;
|
||||
private final BigDecimal withdrawalFeeAmount;
|
||||
private final EnumOptionData withdrawalFeeType;
|
||||
private final boolean withdrawalFeeForTransfers;
|
||||
private final BigDecimal annualFeeAmount;
|
||||
private final MonthDay annualFeeOnMonthDay;
|
||||
private final LocalDate annualFeeNextDueDate;
|
||||
|
||||
// associations
|
||||
private final SavingsAccountSummaryData summary;
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<SavingsAccountTransactionData> transactions;
|
||||
@SuppressWarnings("unused")
|
||||
|
||||
private final Collection<SavingsAccountChargeData> charges;
|
||||
|
||||
// template
|
||||
@@ -69,6 +63,11 @@ public class SavingsAccountData {
|
||||
private final Collection<EnumOptionData> withdrawalFeeTypeOptions;
|
||||
private final Collection<ChargeData> chargeOptions;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final SavingsAccountChargeData withdrawalFee;
|
||||
@SuppressWarnings("unused")
|
||||
private final SavingsAccountChargeData annualFee;
|
||||
|
||||
public static SavingsAccountData instance(final Long id, final String accountNo, final String externalId, final Long groupId,
|
||||
final String groupName, final Long clientId, final String clientName, final Long productId, final String productName,
|
||||
final Long fieldOfficerId, final String fieldOfficerName, final SavingsAccountStatusEnumData status,
|
||||
@@ -76,9 +75,7 @@ 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 BigDecimal withdrawalFeeAmount, final EnumOptionData withdrawalFeeType,
|
||||
final boolean withdrawalFeeForTransfers, final BigDecimal annualFeeAmount, final MonthDay annualFeeOnMonthDay,
|
||||
final LocalDate annualFeeNextDueDate, final SavingsAccountSummaryData summary) {
|
||||
final EnumOptionData lockinPeriodFrequencyType, final boolean withdrawalFeeForTransfers, final SavingsAccountSummaryData summary) {
|
||||
|
||||
final Collection<SavingsProductData> productOptions = null;
|
||||
final Collection<StaffData> fieldOfficerOptions = null;
|
||||
@@ -96,15 +93,44 @@ public class SavingsAccountData {
|
||||
return new SavingsAccountData(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
|
||||
fieldOfficerId, fieldOfficerName, status, timeline, currency, interestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, withdrawalFeeForTransfers,
|
||||
annualFeeAmount, annualFeeOnMonthDay, annualFeeNextDueDate, summary, transactions, productOptions, fieldOfficerOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, charges,
|
||||
chargeOptions);
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary, transactions, productOptions,
|
||||
fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, charges, chargeOptions);
|
||||
}
|
||||
|
||||
public static SavingsAccountData lookup(final Long accountId, final String accountNo) {
|
||||
|
||||
final String externalId = null;
|
||||
final Long productId = null;
|
||||
final Long groupId = null;
|
||||
final Long clientId = null;
|
||||
final String clientName = null;
|
||||
final String groupName = null;
|
||||
final String productName = null;
|
||||
final Long fieldOfficerId = null;
|
||||
final String fieldOfficerName = null;
|
||||
final SavingsAccountStatusEnumData status = null;
|
||||
final SavingsAccountApplicationTimelineData timeline = null;
|
||||
final CurrencyData currency = null;
|
||||
final BigDecimal nominalAnnualInterestRate = null;
|
||||
final EnumOptionData interestPeriodType = null;
|
||||
final EnumOptionData interestPostingPeriodType = null;
|
||||
final EnumOptionData interestCalculationType = null;
|
||||
final EnumOptionData interestCalculationDaysInYearType = null;
|
||||
final BigDecimal minRequiredOpeningBalance = null;
|
||||
final Integer lockinPeriodFrequency = null;
|
||||
final EnumOptionData lockinPeriodFrequencyType = null;
|
||||
// final BigDecimal withdrawalFeeAmount = null;
|
||||
// final EnumOptionData withdrawalFeeType = null;
|
||||
final boolean withdrawalFeeForTransfers = false;
|
||||
// final BigDecimal annualFeeAmount = null;
|
||||
// final MonthDay annualFeeOnMonthDay = null;
|
||||
// final LocalDate annualFeeNextDueDate = null;
|
||||
|
||||
final SavingsAccountSummaryData summary = null;
|
||||
final Collection<SavingsAccountTransactionData> transactions = null;
|
||||
|
||||
final Collection<SavingsProductData> productOptions = null;
|
||||
final Collection<StaffData> fieldOfficerOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
@@ -114,12 +140,13 @@ public class SavingsAccountData {
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
|
||||
final Collection<SavingsAccountTransactionData> transactions = null;
|
||||
final Collection<SavingsAccountChargeData> charges = null;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
|
||||
return new SavingsAccountData(accountId, accountNo, null, null, null, null, null, null, null, null, null, null, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null, false, null, null, null, null, transactions, productOptions,
|
||||
return new SavingsAccountData(accountId, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
|
||||
fieldOfficerId , fieldOfficerName, status, timeline, currency, nominalAnnualInterestRate, interestPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary, transactions, productOptions,
|
||||
fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, charges, chargeOptions);
|
||||
@@ -149,12 +176,11 @@ public class SavingsAccountData {
|
||||
account.fieldOfficerName, account.status, account.timeline, account.currency, account.nominalAnnualInterestRate,
|
||||
account.interestCompoundingPeriodType, account.interestPostingPeriodType, account.interestCalculationType,
|
||||
account.interestCalculationDaysInYearType, account.minRequiredOpeningBalance, account.lockinPeriodFrequency,
|
||||
account.lockinPeriodFrequencyType, account.withdrawalFeeAmount, account.withdrawalFeeType,
|
||||
account.withdrawalFeeForTransfers, account.annualFeeAmount, account.annualFeeOnMonthDay, account.annualFeeNextDueDate,
|
||||
account.summary, transactions, template.productOptions, template.fieldOfficerOptions,
|
||||
template.interestCompoundingPeriodTypeOptions, template.interestPostingPeriodTypeOptions,
|
||||
template.interestCalculationTypeOptions, template.interestCalculationDaysInYearTypeOptions,
|
||||
template.lockinPeriodFrequencyTypeOptions, template.withdrawalFeeTypeOptions, charges, template.chargeOptions);
|
||||
account.lockinPeriodFrequencyType, account.withdrawalFeeForTransfers, account.summary, transactions,
|
||||
template.productOptions, template.fieldOfficerOptions, template.interestCompoundingPeriodTypeOptions,
|
||||
template.interestPostingPeriodTypeOptions, template.interestCalculationTypeOptions,
|
||||
template.interestCalculationDaysInYearTypeOptions, template.lockinPeriodFrequencyTypeOptions,
|
||||
template.withdrawalFeeTypeOptions, charges, template.chargeOptions);
|
||||
}
|
||||
|
||||
public static SavingsAccountData withTemplateOptions(final SavingsAccountData account,
|
||||
@@ -172,11 +198,10 @@ public class SavingsAccountData {
|
||||
account.fieldOfficerName, account.status, account.timeline, account.currency, account.nominalAnnualInterestRate,
|
||||
account.interestCompoundingPeriodType, account.interestPostingPeriodType, account.interestCalculationType,
|
||||
account.interestCalculationDaysInYearType, account.minRequiredOpeningBalance, account.lockinPeriodFrequency,
|
||||
account.lockinPeriodFrequencyType, account.withdrawalFeeAmount, account.withdrawalFeeType,
|
||||
account.withdrawalFeeForTransfers, account.annualFeeAmount, account.annualFeeOnMonthDay, account.annualFeeNextDueDate,
|
||||
account.summary, transactions, productOptions, fieldOfficerOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, charges, chargeOptions);
|
||||
account.lockinPeriodFrequencyType, account.withdrawalFeeForTransfers, account.summary, transactions, productOptions,
|
||||
fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, charges, chargeOptions);
|
||||
}
|
||||
|
||||
public static SavingsAccountData withClientTemplate(final Long clientId, final String clientName, final Long groupId,
|
||||
@@ -200,12 +225,12 @@ public class SavingsAccountData {
|
||||
final BigDecimal minRequiredOpeningBalance = null;
|
||||
final Integer lockinPeriodFrequency = null;
|
||||
final EnumOptionData lockinPeriodFrequencyType = null;
|
||||
final BigDecimal withdrawalFeeAmount = null;
|
||||
final EnumOptionData withdrawalFeeType = null;
|
||||
// final BigDecimal withdrawalFeeAmount = null;
|
||||
// final EnumOptionData withdrawalFeeType = null;
|
||||
final boolean withdrawalFeeForTransfers = false;
|
||||
final BigDecimal annualFeeAmount = null;
|
||||
final MonthDay annualFeeOnMonthDay = null;
|
||||
final LocalDate annualFeeNextDueDate = null;
|
||||
// final BigDecimal annualFeeAmount = null;
|
||||
// final MonthDay annualFeeOnMonthDay = null;
|
||||
// final LocalDate annualFeeNextDueDate = null;
|
||||
|
||||
final SavingsAccountSummaryData summary = null;
|
||||
final Collection<SavingsAccountTransactionData> transactions = null;
|
||||
@@ -225,11 +250,10 @@ public class SavingsAccountData {
|
||||
return new SavingsAccountData(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
|
||||
fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualInterestRate, interestPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, withdrawalFeeForTransfers,
|
||||
annualFeeAmount, annualFeeOnMonthDay, annualFeeNextDueDate, summary, transactions, productOptions, fieldOfficerOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, charges,
|
||||
chargeOptions);
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary, transactions, productOptions,
|
||||
fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, charges, chargeOptions);
|
||||
}
|
||||
|
||||
private SavingsAccountData(final Long id, final String accountNo, final String externalId, final Long groupId, final String groupName,
|
||||
@@ -238,11 +262,10 @@ public class SavingsAccountData {
|
||||
final CurrencyData currency, final BigDecimal nominalAnnualInterestRate, final EnumOptionData interestPeriodType,
|
||||
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
|
||||
final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final BigDecimal withdrawalFeeAmount,
|
||||
final EnumOptionData withdrawalFeeType, final boolean withdrawalFeeForTransfers, final BigDecimal annualFeeAmount,
|
||||
final MonthDay annualFeeOnMonthDay, final LocalDate annualFeeNextDueDate, final SavingsAccountSummaryData summary,
|
||||
final Collection<SavingsAccountTransactionData> transactions, final Collection<SavingsProductData> productOptions,
|
||||
final Collection<StaffData> fieldOfficerOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final boolean withdrawalFeeForTransfers,
|
||||
final SavingsAccountSummaryData summary, final Collection<SavingsAccountTransactionData> transactions,
|
||||
final Collection<SavingsProductData> productOptions, final Collection<StaffData> fieldOfficerOptions,
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
@@ -270,12 +293,12 @@ public class SavingsAccountData {
|
||||
this.minRequiredOpeningBalance = minRequiredOpeningBalance;
|
||||
this.lockinPeriodFrequency = lockinPeriodFrequency;
|
||||
this.lockinPeriodFrequencyType = lockinPeriodFrequencyType;
|
||||
this.withdrawalFeeAmount = withdrawalFeeAmount;
|
||||
this.withdrawalFeeType = withdrawalFeeType;
|
||||
// this.withdrawalFeeAmount = withdrawalFeeAmount;
|
||||
// this.withdrawalFeeType = withdrawalFeeType;
|
||||
this.withdrawalFeeForTransfers = withdrawalFeeForTransfers;
|
||||
this.annualFeeAmount = annualFeeAmount;
|
||||
this.annualFeeOnMonthDay = annualFeeOnMonthDay;
|
||||
this.annualFeeNextDueDate = annualFeeNextDueDate;
|
||||
// this.annualFeeAmount = annualFeeAmount;
|
||||
// this.annualFeeOnMonthDay = annualFeeOnMonthDay;
|
||||
// this.annualFeeNextDueDate = annualFeeNextDueDate;
|
||||
|
||||
this.summary = summary;
|
||||
this.transactions = transactions;
|
||||
@@ -292,8 +315,26 @@ public class SavingsAccountData {
|
||||
this.charges = charges;// charges associated with Savings account
|
||||
// charges available for adding to Savings account
|
||||
this.chargeOptions = chargeOptions;
|
||||
|
||||
this.withdrawalFee = getWithdrawalFee();
|
||||
|
||||
this.annualFee = getAnnualFee();
|
||||
}
|
||||
|
||||
private SavingsAccountChargeData getWithdrawalFee() {
|
||||
for (SavingsAccountChargeData charge : this.charges()) {
|
||||
if (charge.isWithdrawalFee()) return charge;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private SavingsAccountChargeData getAnnualFee() {
|
||||
for (SavingsAccountChargeData charge : this.charges()) {
|
||||
if (charge.isAnnualFee()) return charge;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Long id() {
|
||||
return this.id;
|
||||
}
|
||||
@@ -328,4 +369,8 @@ public class SavingsAccountData {
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37).append(this.id).append(this.accountNo).toHashCode();
|
||||
}
|
||||
|
||||
public Collection<SavingsAccountChargeData> charges() {
|
||||
return (this.charges == null) ? new HashSet<SavingsAccountChargeData>() : this.charges;
|
||||
}
|
||||
}
|
||||
+39
-70
@@ -6,10 +6,13 @@
|
||||
package org.mifosplatform.portfolio.savings.data;
|
||||
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.accountNoParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeOnMonthDayParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.amountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargeIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargesParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.clientIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.externalIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.feeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.feeOnMonthDayParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.fieldOfficerIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.groupIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestCalculationDaysInYearTypeParamName;
|
||||
@@ -22,14 +25,13 @@ import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequire
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.productIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.submittedOnDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeTypeParamName;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
@@ -45,11 +47,12 @@ import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationDaysInYearType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsWithdrawalFeesType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
@Component
|
||||
@@ -176,32 +179,6 @@ public class SavingsAccountDataValidator {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeAmountParamName, element)) {
|
||||
|
||||
final BigDecimal withdrawalFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(withdrawalFeeAmountParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(withdrawalFeeAmount).zeroOrPositiveAmount();
|
||||
|
||||
if (withdrawalFeeAmount != null) {
|
||||
final Integer withdrawalFeeType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(withdrawalFeeTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(withdrawalFeeType)
|
||||
.isOneOfTheseValues(SavingsWithdrawalFeesType.integerValues());
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeTypeParamName, element)) {
|
||||
final Integer withdrawalFeeType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(withdrawalFeeTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(withdrawalFeeType).ignoreIfNull()
|
||||
.isOneOfTheseValues(1, 2);
|
||||
|
||||
if (withdrawalFeeType != null) {
|
||||
final BigDecimal withdrawalFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(
|
||||
withdrawalFeeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(withdrawalFeeAmount).notNull()
|
||||
.zeroOrPositiveAmount();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeForTransfersParamName, element)) {
|
||||
final Boolean isWithdrawalFeeApplicableForTransfers = this.fromApiJsonHelper.extractBooleanNamed(
|
||||
withdrawalFeeForTransfersParamName, element);
|
||||
@@ -209,29 +186,34 @@ public class SavingsAccountDataValidator {
|
||||
.ignoreIfNull().validateForBooleanValue();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(annualFeeAmountParamName, element)) {
|
||||
final BigDecimal annualFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(annualFeeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(annualFeeAmount).zeroOrPositiveAmount();
|
||||
|
||||
if (annualFeeAmount != null) {
|
||||
final MonthDay monthDayOfAnnualFee = this.fromApiJsonHelper.extractMonthDayNamed(annualFeeOnMonthDayParamName, element);
|
||||
baseDataValidator.reset().parameter(annualFeeOnMonthDayParamName).value(monthDayOfAnnualFee).notNull();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(annualFeeOnMonthDayParamName, element)) {
|
||||
|
||||
final MonthDay monthDayOfAnnualFee = this.fromApiJsonHelper.extractMonthDayNamed(annualFeeOnMonthDayParamName, element);
|
||||
if (monthDayOfAnnualFee != null) {
|
||||
final BigDecimal annualFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(annualFeeAmountParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(annualFeeAmount).notNull().zeroOrPositiveAmount();
|
||||
}
|
||||
}
|
||||
|
||||
validateSavingsCharges(element, baseDataValidator);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
private void validateSavingsCharges(final JsonElement element, final DataValidatorBuilder baseDataValidator) {
|
||||
|
||||
if (element.isJsonObject()) {
|
||||
final JsonObject topLevelJsonElement = element.getAsJsonObject();
|
||||
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
|
||||
if (topLevelJsonElement.has(chargesParamName) && topLevelJsonElement.get(chargesParamName).isJsonArray()) {
|
||||
final JsonArray array = topLevelJsonElement.get(chargesParamName).getAsJsonArray();
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
|
||||
final JsonObject savingsChargeElement = array.get(i).getAsJsonObject();
|
||||
|
||||
//final Long id = this.fromApiJsonHelper.extractLongNamed(idParamName, savingsChargeElement);
|
||||
|
||||
final Long chargeId = this.fromApiJsonHelper.extractLongNamed(chargeIdParamName, savingsChargeElement);
|
||||
baseDataValidator.reset().parameter(chargeIdParamName).value(chargeId).longGreaterThanZero();
|
||||
|
||||
final BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalNamed(amountParamName, savingsChargeElement, locale);
|
||||
baseDataValidator.reset().parameter(amountParamName).value(amount).notNull().positiveAmount();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void validateForUpdate(final String json) {
|
||||
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
@@ -359,19 +341,6 @@ public class SavingsAccountDataValidator {
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).inMinMaxRange(0, 3);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeAmountParamName, element)) {
|
||||
final BigDecimal withdrawalFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(withdrawalFeeAmountParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(withdrawalFeeAmount).ignoreIfNull()
|
||||
.zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeTypeParamName, element)) {
|
||||
final Integer withdrawalFeeType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(withdrawalFeeTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(withdrawalFeeType).ignoreIfNull()
|
||||
.isOneOfTheseValues(SavingsWithdrawalFeesType.integerValues());
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeForTransfersParamName, element)) {
|
||||
final Boolean isWithdrawalFeeApplicableForTransfers = this.fromApiJsonHelper.extractBooleanNamed(
|
||||
withdrawalFeeForTransfersParamName, element);
|
||||
@@ -379,14 +348,14 @@ public class SavingsAccountDataValidator {
|
||||
.ignoreIfNull().validateForBooleanValue();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(annualFeeAmountParamName, element)) {
|
||||
final BigDecimal annualFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(annualFeeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(annualFeeAmount).ignoreIfNull().zeroOrPositiveAmount();
|
||||
if (this.fromApiJsonHelper.parameterExists(feeAmountParamName, element)) {
|
||||
final BigDecimal annualFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(feeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(feeAmountParamName).value(annualFeeAmount).ignoreIfNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(annualFeeOnMonthDayParamName, element)) {
|
||||
final MonthDay monthDayOfAnnualFee = this.fromApiJsonHelper.extractMonthDayNamed(annualFeeOnMonthDayParamName, element);
|
||||
baseDataValidator.reset().parameter(annualFeeOnMonthDayParamName).value(monthDayOfAnnualFee).ignoreIfNull();
|
||||
if (this.fromApiJsonHelper.parameterExists(feeOnMonthDayParamName, element)) {
|
||||
final MonthDay monthDayOfAnnualFee = this.fromApiJsonHelper.extractMonthDayNamed(feeOnMonthDayParamName, element);
|
||||
baseDataValidator.reset().parameter(feeOnMonthDayParamName).value(monthDayOfAnnualFee).ignoreIfNull();
|
||||
}
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
|
||||
+1
-15
@@ -1,7 +1,6 @@
|
||||
package org.mifosplatform.portfolio.savings.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
@@ -12,18 +11,13 @@ public class SavingsAccountTransactionDTO {
|
||||
private final DateTimeFormatter formatter;
|
||||
private final LocalDate transactionDate;
|
||||
private final BigDecimal transactionAmount;
|
||||
private final List<Long> existingTransactionIds;
|
||||
private final List<Long> existingReversedTransactionIds;
|
||||
private final PaymentDetail paymentDetail;
|
||||
|
||||
public SavingsAccountTransactionDTO(final DateTimeFormatter formatter, final LocalDate transactionDate,
|
||||
final BigDecimal transactionAmount, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
|
||||
final PaymentDetail paymentDetail) {
|
||||
final BigDecimal transactionAmount, final PaymentDetail paymentDetail) {
|
||||
this.formatter = formatter;
|
||||
this.transactionDate = transactionDate;
|
||||
this.transactionAmount = transactionAmount;
|
||||
this.existingTransactionIds = existingTransactionIds;
|
||||
this.existingReversedTransactionIds = existingReversedTransactionIds;
|
||||
this.paymentDetail = paymentDetail;
|
||||
}
|
||||
|
||||
@@ -39,14 +33,6 @@ public class SavingsAccountTransactionDTO {
|
||||
return this.transactionAmount;
|
||||
}
|
||||
|
||||
public List<Long> getExistingTransactionIds() {
|
||||
return this.existingTransactionIds;
|
||||
}
|
||||
|
||||
public List<Long> getExistingReversedTransactionIds() {
|
||||
return this.existingReversedTransactionIds;
|
||||
}
|
||||
|
||||
public PaymentDetail getPaymentDetail() {
|
||||
return this.paymentDetail;
|
||||
}
|
||||
|
||||
+54
-53
@@ -10,9 +10,9 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.accounting.common.AccountingRuleType;
|
||||
import org.mifosplatform.accounting.glaccount.data.GLAccountData;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper;
|
||||
import org.mifosplatform.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper;
|
||||
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
@@ -36,16 +36,14 @@ public class SavingsProductData {
|
||||
private final BigDecimal minRequiredOpeningBalance;
|
||||
private final Integer lockinPeriodFrequency;
|
||||
private final EnumOptionData lockinPeriodFrequencyType;
|
||||
private final BigDecimal withdrawalFeeAmount;
|
||||
private final EnumOptionData withdrawalFeeType;
|
||||
private final boolean withdrawalFeeForTransfers;
|
||||
private final BigDecimal annualFeeAmount;
|
||||
private final MonthDay annualFeeOnMonthDay;
|
||||
|
||||
// accounting
|
||||
private final EnumOptionData accountingRule;
|
||||
private final Map<String, Object> accountingMappings;
|
||||
private final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings;
|
||||
private final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings;
|
||||
private final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings;
|
||||
|
||||
// charges
|
||||
private final Collection<ChargeData> charges;
|
||||
@@ -83,35 +81,34 @@ public class SavingsProductData {
|
||||
final BigDecimal minRequiredOpeningBalance = null;
|
||||
final Integer lockinPeriodFrequency = null;
|
||||
final EnumOptionData lockinPeriodFrequencyType = null;
|
||||
final BigDecimal withdrawalFeeAmount = null;
|
||||
final EnumOptionData withdrawalFeeType = null;
|
||||
final boolean withdrawalFeeForTransfers = false;
|
||||
final BigDecimal annualFeeAmount = null;
|
||||
final MonthDay annualFeeMonthDay = null;
|
||||
final Map<String, Object> accountingMappings = null;
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
|
||||
final Collection<ChargeData> charges = null;
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings = null;
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings = null;
|
||||
|
||||
return new SavingsProductData(id, name, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, withdrawalFeeForTransfers,
|
||||
accountingRule, annualFeeAmount, annualFeeMonthDay, accountingMappings, paymentChannelToFundSourceMappings,
|
||||
currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions,
|
||||
accountingRuleOptions, accountingMappingOptions, charges, chargeOptions, penaltyOptions);
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, accountingRule, accountingMappings,
|
||||
paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions,
|
||||
accountingMappingOptions, charges, chargeOptions, penaltyOptions, feeToIncomeAccountMappings,
|
||||
penaltyToIncomeAccountMappings);
|
||||
}
|
||||
|
||||
public static SavingsProductData withCharges(final SavingsProductData product, final Collection<ChargeData> charges) {
|
||||
return new SavingsProductData(product.id, product.name, product.description, product.currency, product.nominalAnnualInterestRate,
|
||||
product.interestCompoundingPeriodType, product.interestPostingPeriodType, product.interestCalculationType,
|
||||
product.interestCalculationDaysInYearType, product.minRequiredOpeningBalance, product.lockinPeriodFrequency,
|
||||
product.lockinPeriodFrequencyType, product.withdrawalFeeAmount, product.withdrawalFeeType,
|
||||
product.withdrawalFeeForTransfers, product.accountingRule, product.annualFeeAmount, product.annualFeeOnMonthDay,
|
||||
product.accountingMappings, product.paymentChannelToFundSourceMappings, product.currencyOptions,
|
||||
product.interestCompoundingPeriodTypeOptions, product.interestPostingPeriodTypeOptions,
|
||||
product.interestCalculationTypeOptions, product.interestCalculationDaysInYearTypeOptions,
|
||||
product.lockinPeriodFrequencyTypeOptions, product.withdrawalFeeTypeOptions, product.paymentTypeOptions,
|
||||
product.accountingRuleOptions, product.accountingMappingOptions, charges, product.chargeOptions, product.penaltyOptions);
|
||||
product.lockinPeriodFrequencyType, product.withdrawalFeeForTransfers, product.accountingRule, product.accountingMappings,
|
||||
product.paymentChannelToFundSourceMappings, product.currencyOptions, product.interestCompoundingPeriodTypeOptions,
|
||||
product.interestPostingPeriodTypeOptions, product.interestCalculationTypeOptions,
|
||||
product.interestCalculationDaysInYearTypeOptions, product.lockinPeriodFrequencyTypeOptions,
|
||||
product.withdrawalFeeTypeOptions, product.paymentTypeOptions, product.accountingRuleOptions,
|
||||
product.accountingMappingOptions, charges, product.chargeOptions, product.penaltyOptions,
|
||||
product.feeToIncomeAccountMappings, product.penaltyToIncomeAccountMappings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,17 +129,20 @@ public class SavingsProductData {
|
||||
existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType,
|
||||
existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
existingProduct.interestCalculationDaysInYearType, existingProduct.minRequiredOpeningBalance,
|
||||
existingProduct.lockinPeriodFrequency, existingProduct.lockinPeriodFrequencyType, existingProduct.withdrawalFeeAmount,
|
||||
existingProduct.withdrawalFeeType, existingProduct.withdrawalFeeForTransfers, existingProduct.accountingRule,
|
||||
existingProduct.annualFeeAmount, existingProduct.annualFeeOnMonthDay, existingProduct.accountingMappings,
|
||||
existingProduct.lockinPeriodFrequency, existingProduct.lockinPeriodFrequencyType,
|
||||
existingProduct.withdrawalFeeForTransfers, existingProduct.accountingRule, existingProduct.accountingMappings,
|
||||
existingProduct.paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions,
|
||||
accountingMappingOptions, existingProduct.charges, chargeOptions, penaltyOptions);
|
||||
accountingMappingOptions, existingProduct.charges, chargeOptions, penaltyOptions,
|
||||
existingProduct.feeToIncomeAccountMappings, existingProduct.penaltyToIncomeAccountMappings);
|
||||
}
|
||||
|
||||
public static SavingsProductData withAccountingDetails(final SavingsProductData existingProduct,
|
||||
final Map<String, Object> accountingMappings, final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings) {
|
||||
final Map<String, Object> accountingMappings,
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings,
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings,
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings) {
|
||||
|
||||
final Collection<CurrencyData> currencyOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
@@ -161,22 +161,21 @@ public class SavingsProductData {
|
||||
existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType,
|
||||
existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
|
||||
existingProduct.interestCalculationDaysInYearType, existingProduct.minRequiredOpeningBalance,
|
||||
existingProduct.lockinPeriodFrequency, existingProduct.lockinPeriodFrequencyType, existingProduct.withdrawalFeeAmount,
|
||||
existingProduct.withdrawalFeeType, existingProduct.withdrawalFeeForTransfers, existingProduct.accountingRule,
|
||||
existingProduct.annualFeeAmount, existingProduct.annualFeeOnMonthDay, accountingMappings,
|
||||
existingProduct.lockinPeriodFrequency, existingProduct.lockinPeriodFrequencyType,
|
||||
existingProduct.withdrawalFeeForTransfers, existingProduct.accountingRule, accountingMappings,
|
||||
paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions,
|
||||
accountingMappingOptions, existingProduct.charges, chargeOptions, penaltyOptions);
|
||||
accountingMappingOptions, existingProduct.charges, chargeOptions, penaltyOptions, feeToIncomeAccountMappings,
|
||||
penaltyToIncomeAccountMappings);
|
||||
}
|
||||
|
||||
public static SavingsProductData instance(final Long id, final String name, final String description, final CurrencyData currency,
|
||||
final BigDecimal nominalAnnualInterestRate, final EnumOptionData interestCompoundingPeriodType,
|
||||
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
|
||||
final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final BigDecimal withdrawalFeeAmount,
|
||||
final EnumOptionData withdrawalFeeType, final boolean withdrawalFeeForTransfers, final BigDecimal annualFeeAmount,
|
||||
final MonthDay annualFeeOnMonthDay, final EnumOptionData accountingType) {
|
||||
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final boolean withdrawalFeeForTransfers,
|
||||
final EnumOptionData accountingType) {
|
||||
|
||||
final Map<String, Object> accountingMappings = null;
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
|
||||
@@ -194,14 +193,17 @@ public class SavingsProductData {
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
final Collection<ChargeData> penaltyOptions = null;
|
||||
final Collection<ChargeData> charges = null;
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings = null;
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings = null;
|
||||
|
||||
return new SavingsProductData(id, name, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, withdrawalFeeForTransfers,
|
||||
accountingType, annualFeeAmount, annualFeeOnMonthDay, accountingMappings, paymentChannelToFundSourceMappings,
|
||||
currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions,
|
||||
accountingRuleOptions, accountingMappingOptions, charges, chargeOptions, penaltyOptions);
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, accountingType, accountingMappings,
|
||||
paymentChannelToFundSourceMappings, currencyOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions,
|
||||
accountingMappingOptions, charges, chargeOptions, penaltyOptions, feeToIncomeAccountMappings,
|
||||
penaltyToIncomeAccountMappings);
|
||||
}
|
||||
|
||||
public static SavingsProductData lookup(final Long id, final String name) {
|
||||
@@ -216,12 +218,8 @@ public class SavingsProductData {
|
||||
final BigDecimal minRequiredOpeningBalance = null;
|
||||
final Integer lockinPeriodFrequency = null;
|
||||
final EnumOptionData lockinPeriodFrequencyType = null;
|
||||
final BigDecimal withdrawalFeeAmount = null;
|
||||
final EnumOptionData withdrawalFeeType = null;
|
||||
final boolean withdrawalFeeForTransfers = false;
|
||||
final EnumOptionData accountingType = null;
|
||||
final BigDecimal annualFeeAmount = null;
|
||||
final MonthDay annualFeeMonthDay = null;
|
||||
final Map<String, Object> accountingMappings = null;
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
|
||||
|
||||
@@ -238,23 +236,25 @@ public class SavingsProductData {
|
||||
final Collection<ChargeData> charges = null;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
final Collection<ChargeData> penaltyOptions = null;
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings = null;
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings = null;
|
||||
|
||||
return new SavingsProductData(id, name, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, withdrawalFeeForTransfers,
|
||||
accountingType, annualFeeAmount, annualFeeMonthDay, accountingMappings, paymentChannelToFundSourceMappings,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers,
|
||||
accountingType, accountingMappings, paymentChannelToFundSourceMappings,
|
||||
currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions,
|
||||
accountingRuleOptions, accountingMappingOptions, charges, chargeOptions, penaltyOptions);
|
||||
accountingRuleOptions, accountingMappingOptions, charges, chargeOptions, penaltyOptions, feeToIncomeAccountMappings,
|
||||
penaltyToIncomeAccountMappings);
|
||||
}
|
||||
|
||||
private SavingsProductData(final Long id, final String name, final String description, final CurrencyData currency,
|
||||
final BigDecimal nominalAnnualInterestRate, final EnumOptionData interestCompoundingPeriodType,
|
||||
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
|
||||
final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final BigDecimal withdrawalFeeAmount,
|
||||
final EnumOptionData withdrawalFeeType, final boolean withdrawalFeeForTransfers, final EnumOptionData accountingType,
|
||||
final BigDecimal annualFeeAmount, final MonthDay annualFeeOnMonthDay, final Map<String, Object> accountingMappings,
|
||||
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final boolean withdrawalFeeForTransfers,
|
||||
final EnumOptionData accountingType, final Map<String, Object> accountingMappings,
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings,
|
||||
final Collection<CurrencyData> currencyOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
@@ -263,7 +263,9 @@ public class SavingsProductData {
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<CodeValueData> paymentTypeOptions, final Collection<EnumOptionData> accountingRuleOptions,
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions, final Collection<ChargeData> charges,
|
||||
final Collection<ChargeData> chargeOptions, final Collection<ChargeData> penaltyOptions) {
|
||||
final Collection<ChargeData> chargeOptions, final Collection<ChargeData> penaltyOptions,
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings,
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
@@ -277,11 +279,7 @@ public class SavingsProductData {
|
||||
this.minRequiredOpeningBalance = minRequiredOpeningBalance;
|
||||
this.lockinPeriodFrequency = lockinPeriodFrequency;
|
||||
this.lockinPeriodFrequencyType = lockinPeriodFrequencyType;
|
||||
this.withdrawalFeeAmount = withdrawalFeeAmount;
|
||||
this.withdrawalFeeType = withdrawalFeeType;
|
||||
this.withdrawalFeeForTransfers = withdrawalFeeForTransfers;
|
||||
this.annualFeeAmount = annualFeeAmount;
|
||||
this.annualFeeOnMonthDay = annualFeeOnMonthDay;
|
||||
|
||||
this.currencyOptions = currencyOptions;
|
||||
this.interestCompoundingPeriodTypeOptions = interestCompoundingPeriodTypeOptions;
|
||||
@@ -306,6 +304,9 @@ public class SavingsProductData {
|
||||
// Savings product
|
||||
this.penaltyOptions = penaltyOptions;// penalties available for adding
|
||||
// to Savings product
|
||||
|
||||
this.feeToIncomeAccountMappings = feeToIncomeAccountMappings;
|
||||
this.penaltyToIncomeAccountMappings = penaltyToIncomeAccountMappings;
|
||||
}
|
||||
|
||||
public boolean hasAccountingEnabled() {
|
||||
|
||||
+68
-35
@@ -7,8 +7,8 @@ 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.annualFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeOnMonthDayParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.feeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.feeOnMonthDayParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.currencyCodeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.descriptionParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.digitsAfterDecimalParamName;
|
||||
@@ -22,9 +22,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.withdrawalFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeTypeParamName;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
@@ -46,7 +44,6 @@ import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationDaysInYearType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsWithdrawalFeesType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -151,7 +148,7 @@ public class SavingsProductDataValidator {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeAmountParamName, element)) {
|
||||
/*if (this.fromApiJsonHelper.parameterExists(withdrawalFeeAmountParamName, element)) {
|
||||
|
||||
final BigDecimal withdrawalFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(withdrawalFeeAmountParamName,
|
||||
element);
|
||||
@@ -176,7 +173,7 @@ public class SavingsProductDataValidator {
|
||||
.zeroOrPositiveAmount();
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeForTransfersParamName, element)) {
|
||||
final Boolean isWithdrawalFeeApplicableForTransfers = this.fromApiJsonHelper.extractBooleanNamed(
|
||||
withdrawalFeeForTransfersParamName, element);
|
||||
@@ -184,23 +181,23 @@ public class SavingsProductDataValidator {
|
||||
.ignoreIfNull().validateForBooleanValue();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(annualFeeAmountParamName, element)) {
|
||||
final BigDecimal annualFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(annualFeeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(annualFeeAmount).zeroOrPositiveAmount();
|
||||
if (this.fromApiJsonHelper.parameterExists(feeAmountParamName, element)) {
|
||||
final BigDecimal annualFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(feeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(feeAmountParamName).value(annualFeeAmount).zeroOrPositiveAmount();
|
||||
|
||||
if (annualFeeAmount != null) {
|
||||
final MonthDay monthDayOfAnnualFee = this.fromApiJsonHelper.extractMonthDayNamed(annualFeeOnMonthDayParamName, element);
|
||||
baseDataValidator.reset().parameter(annualFeeOnMonthDayParamName).value(monthDayOfAnnualFee).notNull();
|
||||
final MonthDay monthDayOfAnnualFee = this.fromApiJsonHelper.extractMonthDayNamed(feeOnMonthDayParamName, element);
|
||||
baseDataValidator.reset().parameter(feeOnMonthDayParamName).value(monthDayOfAnnualFee).notNull();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(annualFeeOnMonthDayParamName, element)) {
|
||||
if (this.fromApiJsonHelper.parameterExists(feeOnMonthDayParamName, element)) {
|
||||
|
||||
final MonthDay monthDayOfAnnualFee = this.fromApiJsonHelper.extractMonthDayNamed(annualFeeOnMonthDayParamName, element);
|
||||
final MonthDay monthDayOfAnnualFee = this.fromApiJsonHelper.extractMonthDayNamed(feeOnMonthDayParamName, element);
|
||||
if (monthDayOfAnnualFee != null) {
|
||||
final BigDecimal annualFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(annualFeeAmountParamName,
|
||||
final BigDecimal annualFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(feeAmountParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(annualFeeAmount).notNull().zeroOrPositiveAmount();
|
||||
baseDataValidator.reset().parameter(feeAmountParamName).value(annualFeeAmount).notNull().zeroOrPositiveAmount();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +232,13 @@ public class SavingsProductDataValidator {
|
||||
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue()).value(incomeFromFeeId)
|
||||
.notNull().integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromPenaltyId = this.fromApiJsonHelper.extractLongNamed(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue())
|
||||
.value(incomeFromPenaltyId).notNull().integerGreaterThanZero();
|
||||
|
||||
validatePaymentChannelFundSourceMappings(baseDataValidator, element);
|
||||
validateChargeToIncomeAccountMappings(baseDataValidator, element);
|
||||
}
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
@@ -325,19 +328,6 @@ public class SavingsProductDataValidator {
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).inMinMaxRange(0, 3);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeAmountParamName, element)) {
|
||||
final BigDecimal withdrawalFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(withdrawalFeeAmountParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(withdrawalFeeAmount).ignoreIfNull()
|
||||
.zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeTypeParamName, element)) {
|
||||
final Integer withdrawalFeeType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(withdrawalFeeTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(withdrawalFeeType).ignoreIfNull()
|
||||
.isOneOfTheseValues(1, 2);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeForTransfersParamName, element)) {
|
||||
final Boolean isWithdrawalFeeApplicableForTransfers = this.fromApiJsonHelper.extractBooleanNamed(
|
||||
withdrawalFeeForTransfersParamName, element);
|
||||
@@ -345,14 +335,14 @@ public class SavingsProductDataValidator {
|
||||
.ignoreIfNull().validateForBooleanValue();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(annualFeeAmountParamName, element)) {
|
||||
final BigDecimal annualFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(annualFeeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(annualFeeAmount).ignoreIfNull().zeroOrPositiveAmount();
|
||||
if (this.fromApiJsonHelper.parameterExists(feeAmountParamName, element)) {
|
||||
final BigDecimal annualFeeAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(feeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(feeAmountParamName).value(annualFeeAmount).ignoreIfNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(annualFeeOnMonthDayParamName, element)) {
|
||||
final MonthDay monthDayOfAnnualFee = this.fromApiJsonHelper.extractMonthDayNamed(annualFeeOnMonthDayParamName, element);
|
||||
baseDataValidator.reset().parameter(annualFeeOnMonthDayParamName).value(monthDayOfAnnualFee).ignoreIfNull();
|
||||
if (this.fromApiJsonHelper.parameterExists(feeOnMonthDayParamName, element)) {
|
||||
final MonthDay monthDayOfAnnualFee = this.fromApiJsonHelper.extractMonthDayNamed(feeOnMonthDayParamName, element);
|
||||
baseDataValidator.reset().parameter(feeOnMonthDayParamName).value(monthDayOfAnnualFee).ignoreIfNull();
|
||||
}
|
||||
|
||||
final Long savingsControlAccountId = this.fromApiJsonHelper.extractLongNamed(
|
||||
@@ -380,7 +370,13 @@ public class SavingsProductDataValidator {
|
||||
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue()).value(incomeFromFeeId)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
final Long incomeFromPenaltyId = this.fromApiJsonHelper.extractLongNamed(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), element);
|
||||
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue()).value(incomeFromPenaltyId)
|
||||
.ignoreIfNull().integerGreaterThanZero();
|
||||
|
||||
validatePaymentChannelFundSourceMappings(baseDataValidator, element);
|
||||
validateChargeToIncomeAccountMappings(baseDataValidator, element);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
@@ -425,4 +421,41 @@ public class SavingsProductDataValidator {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateChargeToIncomeAccountMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
|
||||
// validate for both fee and penalty charges
|
||||
validateChargeToIncomeAccountMappings(baseDataValidator, element, true);
|
||||
validateChargeToIncomeAccountMappings(baseDataValidator, element, true);
|
||||
}
|
||||
|
||||
private void validateChargeToIncomeAccountMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element,
|
||||
final boolean isPenalty) {
|
||||
String parameterName;
|
||||
if (isPenalty) {
|
||||
parameterName = SAVINGS_PRODUCT_ACCOUNTING_PARAMS.PENALTY_INCOME_ACCOUNT_MAPPING.getValue();
|
||||
} else {
|
||||
parameterName = SAVINGS_PRODUCT_ACCOUNTING_PARAMS.FEE_INCOME_ACCOUNT_MAPPING.getValue();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(parameterName, element)) {
|
||||
final JsonArray chargeToIncomeAccountMappingArray = this.fromApiJsonHelper.extractJsonArrayNamed(parameterName, element);
|
||||
if (chargeToIncomeAccountMappingArray != null && chargeToIncomeAccountMappingArray.size() > 0) {
|
||||
int i = 0;
|
||||
do {
|
||||
final JsonObject jsonObject = chargeToIncomeAccountMappingArray.get(i).getAsJsonObject();
|
||||
final Long chargeId = this.fromApiJsonHelper.extractLongNamed(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.CHARGE_ID.getValue(),
|
||||
jsonObject);
|
||||
final Long incomeAccountId = this.fromApiJsonHelper.extractLongNamed(
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_ACCOUNT_ID.getValue(), jsonObject);
|
||||
baseDataValidator.reset()
|
||||
.parameter(parameterName + "[" + i + "]." + SAVINGS_PRODUCT_ACCOUNTING_PARAMS.CHARGE_ID.getValue())
|
||||
.value(chargeId).notNull().integerGreaterThanZero();
|
||||
baseDataValidator.reset()
|
||||
.parameter(parameterName + "[" + i + "]." + SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_ACCOUNT_ID.getValue())
|
||||
.value(incomeAccountId).notNull().integerGreaterThanZero();
|
||||
i++;
|
||||
} while (i < chargeToIncomeAccountMappingArray.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+216
-396
@@ -6,14 +6,10 @@
|
||||
package org.mifosplatform.portfolio.savings.domain;
|
||||
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeOnMonthDayParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.localeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeTypeParamName;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
@@ -48,7 +44,6 @@ import org.apache.commons.lang.StringUtils;
|
||||
import org.hibernate.annotations.LazyCollection;
|
||||
import org.hibernate.annotations.LazyCollectionOption;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.MonthDay;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
@@ -75,7 +70,6 @@ import org.mifosplatform.portfolio.savings.SavingsInterestCalculationDaysInYearT
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPeriodFrequencyType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsWithdrawalFeesType;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionDTO;
|
||||
import org.mifosplatform.portfolio.savings.domain.interest.PostingPeriod;
|
||||
import org.mifosplatform.portfolio.savings.exception.InsufficientAccountBalanceException;
|
||||
@@ -222,28 +216,9 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
@Column(name = "lockedin_until_date_derived", nullable = true)
|
||||
private Date lockedInUntilDate;
|
||||
|
||||
@Column(name = "withdrawal_fee_amount", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal withdrawalFeeAmount;
|
||||
|
||||
@Column(name = "withdrawal_fee_type_enum", nullable = true)
|
||||
private Integer withdrawalFeeType;
|
||||
|
||||
@Column(name = "withdrawal_fee_for_transfer", nullable = true)
|
||||
private boolean withdrawalFeeApplicableForTransfer;
|
||||
|
||||
@Column(name = "annual_fee_amount", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal annualFeeAmount;
|
||||
|
||||
@Column(name = "annual_fee_on_month", nullable = true)
|
||||
private Integer annualFeeOnMonth;
|
||||
|
||||
@Column(name = "annual_fee_on_day", nullable = true)
|
||||
private Integer annualFeeOnDay;
|
||||
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "annual_fee_next_due_date", nullable = true)
|
||||
private Date annualFeeNextDueDate;
|
||||
|
||||
@Embedded
|
||||
private SavingsAccountSummary summary;
|
||||
|
||||
@@ -274,16 +249,13 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
|
||||
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
|
||||
final BigDecimal withdrawalFeeAmount, final SavingsWithdrawalFeesType withdrawalFeeType,
|
||||
final boolean withdrawalFeeApplicableForTransfer, final BigDecimal annualFeeAmount, final MonthDay annualFeeOnMonthDay,
|
||||
final Set<SavingsAccountCharge> savingsAccountCharges) {
|
||||
final boolean withdrawalFeeApplicableForTransfer, final Set<SavingsAccountCharge> savingsAccountCharges) {
|
||||
|
||||
final SavingsAccountStatusType status = SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL;
|
||||
return new SavingsAccount(client, group, product, fieldOfficer, accountNo, externalId, status, accountType, submittedOnDate,
|
||||
interestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType,
|
||||
interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType,
|
||||
withdrawalFeeAmount, withdrawalFeeType, withdrawalFeeApplicableForTransfer, annualFeeAmount, annualFeeOnMonthDay,
|
||||
savingsAccountCharges);
|
||||
withdrawalFeeApplicableForTransfer, savingsAccountCharges);
|
||||
}
|
||||
|
||||
private SavingsAccount(final Client client, final Group group, final SavingsProduct product, final Staff fieldOfficer,
|
||||
@@ -293,9 +265,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
|
||||
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
|
||||
final BigDecimal withdrawalFeeAmount, final SavingsWithdrawalFeesType withdrawalFeeType,
|
||||
final boolean withdrawalFeeApplicableForTransfer, final BigDecimal annualFeeAmount, final MonthDay annualFeeOnMonthDay,
|
||||
final Set<SavingsAccountCharge> savingsAccountCharges) {
|
||||
final boolean withdrawalFeeApplicableForTransfer, final Set<SavingsAccountCharge> savingsAccountCharges) {
|
||||
this.client = client;
|
||||
this.group = group;
|
||||
this.product = product;
|
||||
@@ -321,23 +291,10 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
if (lockinPeriodFrequencyType != null) {
|
||||
this.lockinPeriodFrequencyType = lockinPeriodFrequencyType.getValue();
|
||||
}
|
||||
this.withdrawalFeeAmount = withdrawalFeeAmount;
|
||||
if (withdrawalFeeType != null) {
|
||||
this.withdrawalFeeType = withdrawalFeeType.getValue();
|
||||
}
|
||||
this.withdrawalFeeApplicableForTransfer = withdrawalFeeApplicableForTransfer;
|
||||
|
||||
this.annualFeeAmount = annualFeeAmount;
|
||||
if (annualFeeOnMonthDay != null) {
|
||||
this.annualFeeOnMonth = annualFeeOnMonthDay.getMonthOfYear();
|
||||
this.annualFeeOnDay = annualFeeOnMonthDay.getDayOfMonth();
|
||||
}
|
||||
|
||||
if (!CollectionUtils.isEmpty(savingsAccountCharges)) {
|
||||
this.charges = associateChargesWithThisSavingsAccount(savingsAccountCharges);
|
||||
// TODO:Add charges details to savings summary
|
||||
// this.summary =
|
||||
// updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
|
||||
}
|
||||
|
||||
this.summary = new SavingsAccountSummary();
|
||||
@@ -378,16 +335,13 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
return SavingsAccountStatusType.fromInt(this.status).isClosed();
|
||||
}
|
||||
|
||||
public void postInterest(final MathContext mc, final LocalDate interestPostingUpToDate, final List<Long> existingTransactionIds,
|
||||
final List<Long> existingReversedTransactionIds) {
|
||||
public void postInterest(final MathContext mc, final LocalDate interestPostingUpToDate) {
|
||||
|
||||
final List<PostingPeriod> postingPeriods = calculateInterestUsing(mc, interestPostingUpToDate);
|
||||
|
||||
Money interestPostedToDate = Money.zero(this.currency);
|
||||
|
||||
boolean recalucateDailyBalanceDetails = false;
|
||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||
|
||||
for (final PostingPeriod interestPostingPeriod : postingPeriods) {
|
||||
|
||||
@@ -610,9 +564,6 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
}
|
||||
validateActivityNotBeforeClientOrGroupTransferDate(SavingsEvent.SAVINGS_DEPOSIT, transactionDTO.getTransactionDate());
|
||||
|
||||
transactionDTO.getExistingTransactionIds().addAll(findExistingTransactionIds());
|
||||
transactionDTO.getExistingReversedTransactionIds().addAll(findExistingReversedTransactionIds());
|
||||
|
||||
final Money amount = Money.of(this.currency, transactionDTO.getTransactionAmount());
|
||||
|
||||
final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(this, office(), transactionDTO.getPaymentDetail(),
|
||||
@@ -624,7 +575,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
private LocalDate getActivationLocalDate() {
|
||||
public LocalDate getActivationLocalDate() {
|
||||
LocalDate activationLocalDate = null;
|
||||
if (this.activatedOnDate != null) {
|
||||
activationLocalDate = new LocalDate(this.activatedOnDate);
|
||||
@@ -685,41 +636,25 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
}
|
||||
validateActivityNotBeforeClientOrGroupTransferDate(SavingsEvent.SAVINGS_WITHDRAWAL, transactionDTO.getTransactionDate());
|
||||
|
||||
transactionDTO.getExistingTransactionIds().addAll(findExistingTransactionIds());
|
||||
transactionDTO.getExistingReversedTransactionIds().addAll(findExistingReversedTransactionIds());
|
||||
|
||||
final Money transactionAmountMoney = Money.of(this.currency, transactionDTO.getTransactionAmount());
|
||||
final SavingsAccountTransaction transaction = SavingsAccountTransaction.withdrawal(this, office(),
|
||||
transactionDTO.getPaymentDetail(), transactionDTO.getTransactionDate(), transactionAmountMoney);
|
||||
this.transactions.add(transaction);
|
||||
|
||||
if (applyWithdrawFee && isAutomaticWithdrawalFee()) {
|
||||
|
||||
SavingsAccountTransaction withdrawalFeeTransaction = null;
|
||||
Money feeAmount = Money.zero(this.currency);
|
||||
switch (SavingsWithdrawalFeesType.fromInt(this.withdrawalFeeType)) {
|
||||
case INVALID:
|
||||
break;
|
||||
case FLAT:
|
||||
feeAmount = Money.of(this.currency, this.withdrawalFeeAmount);
|
||||
withdrawalFeeTransaction = SavingsAccountTransaction
|
||||
.fee(this, office(), transactionDTO.getTransactionDate(), feeAmount);
|
||||
this.transactions.add(withdrawalFeeTransaction);
|
||||
break;
|
||||
case PERCENT_OF_AMOUNT:
|
||||
final BigDecimal feeAmountDecimal = transactionDTO.getTransactionAmount().multiply(this.withdrawalFeeAmount)
|
||||
.divide(BigDecimal.valueOf(100l));
|
||||
feeAmount = Money.of(this.currency, feeAmountDecimal);
|
||||
withdrawalFeeTransaction = SavingsAccountTransaction
|
||||
.fee(this, office(), transactionDTO.getTransactionDate(), feeAmount);
|
||||
this.transactions.add(withdrawalFeeTransaction);
|
||||
break;
|
||||
if (applyWithdrawFee){
|
||||
//auto pay withdrawal fee
|
||||
payWithdrawalFee(transactionDTO.getTransactionAmount(), transactionDTO.getTransactionDate());
|
||||
}
|
||||
return transaction;
|
||||
}
|
||||
|
||||
private void payWithdrawalFee(final BigDecimal transactionAmoount, final LocalDate transactionDate){
|
||||
for (SavingsAccountCharge charge : this.charges()) {
|
||||
if (charge.isWithdrawalFee()){
|
||||
charge.updateWithdralFeeAmount(transactionAmoount);
|
||||
this.payCharge(charge, charge.getAmountOutstanding(this.getCurrency()), transactionDate);
|
||||
}
|
||||
}
|
||||
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
public boolean isBeforeLastPostingPeriod(final LocalDate transactionDate) {
|
||||
@@ -779,132 +714,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SavingsAccountTransaction addAnnualFee(final MathContext mc, final DateTimeFormatter formatter,
|
||||
final LocalDate annualFeeTransactionDate, final LocalDate today, final List<Long> existingTransactionIds,
|
||||
final List<Long> existingReversedTransactionIds) {
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME + SavingsApiConstants.applyAnnualFeeTransactionAction);
|
||||
|
||||
if (isNotActive()) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.not.active");
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
final LocalDate nextAnnualFeeDueDate = getNextAnnualFeeDueDate();
|
||||
if (nextAnnualFeeDueDate == null || annualFeeSettingsNotSet()) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("no.annualfee.settings");
|
||||
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
if (nextAnnualFeeDueDate.isBefore(getActivationLocalDate())) {
|
||||
|
||||
baseDataValidator.reset().parameter("annualFeeTransactionDate").value(getActivationLocalDate().toString(formatter))
|
||||
.failWithCodeNoParameterAddedToErrorCode("before.activationDate");
|
||||
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
if (isDateInTheFuture(annualFeeTransactionDate)) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.in.the.future");
|
||||
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
if (isNotValidAnnualFeeTransactionDate(annualFeeTransactionDate, today)) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("invalid.date");
|
||||
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
Date currentAnnualFeeNextDueDate = findLatestAnnualFeeTransactionDueDate();
|
||||
if (currentAnnualFeeNextDueDate != null && new LocalDate(currentAnnualFeeNextDueDate).isEqual(annualFeeTransactionDate)) {
|
||||
baseDataValidator.reset().parameter("annualFeeTransactionDate").value(annualFeeTransactionDate.toString(formatter))
|
||||
.failWithCodeNoParameterAddedToErrorCode("transaction.exists.on.date");
|
||||
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
validateActivityNotBeforeClientOrGroupTransferDate(SavingsEvent.SAVINGS_PAY_CHARGE, annualFeeTransactionDate);
|
||||
|
||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||
|
||||
final Money annualFee = Money.of(this.currency, this.annualFeeAmount);
|
||||
final SavingsAccountTransaction annualFeeTransaction = SavingsAccountTransaction.annualFee(this, office(),
|
||||
annualFeeTransactionDate, annualFee);
|
||||
this.transactions.add(annualFeeTransaction);
|
||||
|
||||
validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.applyAnnualFeeTransactionAction);
|
||||
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
|
||||
calculateInterestUsing(mc, today);
|
||||
|
||||
currentAnnualFeeNextDueDate = findLatestAnnualFeeTransactionDueDate();
|
||||
if (currentAnnualFeeNextDueDate != null) {
|
||||
final LocalDate newAnnualFeeNextDueDate = new LocalDate(currentAnnualFeeNextDueDate).withMonthOfYear(this.annualFeeOnMonth)
|
||||
.withDayOfMonth(this.annualFeeOnDay).plusYears(1);
|
||||
this.annualFeeNextDueDate = newAnnualFeeNextDueDate.toDate();
|
||||
} else {
|
||||
updateToNextAnnualFeeDueDateFrom(getActivationLocalDate());
|
||||
}
|
||||
|
||||
return annualFeeTransaction;
|
||||
}
|
||||
|
||||
private boolean isNotValidAnnualFeeTransactionDate(final LocalDate annualFeeTransactionDate, final LocalDate today) {
|
||||
return !isValidAnnualFeeTransactionDate(annualFeeTransactionDate, today);
|
||||
}
|
||||
|
||||
private boolean isValidAnnualFeeTransactionDate(final LocalDate annualFeeTransactionDate, final LocalDate today) {
|
||||
|
||||
LocalDate startingDate = getActivationLocalDate();
|
||||
boolean isValid = false;
|
||||
while (!startingDate.isAfter(today) && !isValid) {
|
||||
LocalDate nextDueLocalDate = startingDate.withMonthOfYear(this.annualFeeOnMonth).withDayOfMonth(this.annualFeeOnDay);
|
||||
if (startingDate.isAfter(nextDueLocalDate)) {
|
||||
nextDueLocalDate = nextDueLocalDate.plusYears(1);
|
||||
}
|
||||
isValid = nextDueLocalDate.isEqual(annualFeeTransactionDate);
|
||||
|
||||
startingDate = nextDueLocalDate.plusYears(1);
|
||||
}
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
private void updateToNextAnnualFeeDueDateFrom(final LocalDate startingDate) {
|
||||
LocalDate nextDueLocalDate = startingDate.withMonthOfYear(this.annualFeeOnMonth).withDayOfMonth(this.annualFeeOnDay);
|
||||
if (startingDate.isAfter(nextDueLocalDate)) {
|
||||
nextDueLocalDate = nextDueLocalDate.plusYears(1);
|
||||
}
|
||||
this.annualFeeNextDueDate = nextDueLocalDate.toDate();
|
||||
}
|
||||
|
||||
private LocalDate getNextAnnualFeeDueDate() {
|
||||
LocalDate nextAnnualFeeDueDate = null;
|
||||
if (this.annualFeeNextDueDate != null) {
|
||||
nextAnnualFeeDueDate = new LocalDate(this.annualFeeNextDueDate);
|
||||
}
|
||||
return nextAnnualFeeDueDate;
|
||||
}
|
||||
|
||||
private boolean annualFeeSettingsNotSet() {
|
||||
return !annualFeeSettingsSet();
|
||||
}
|
||||
|
||||
private boolean annualFeeSettingsSet() {
|
||||
return this.annualFeeOnDay != null && this.annualFeeOnMonth != null;
|
||||
}
|
||||
|
||||
private boolean isAutomaticWithdrawalFee() {
|
||||
return this.withdrawalFeeType != null;
|
||||
}
|
||||
|
||||
|
||||
private boolean isAccountLocked(final LocalDate transactionDate) {
|
||||
boolean isLocked = false;
|
||||
final boolean accountHasLockedInSetting = this.lockedInUntilDate != null;
|
||||
@@ -1052,55 +862,12 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
this.lockinPeriodFrequencyType = null;
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(withdrawalFeeAmountParamName, this.withdrawalFeeAmount)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(withdrawalFeeAmountParamName);
|
||||
actualChanges.put(withdrawalFeeAmountParamName, newValue);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.withdrawalFeeAmount = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamedDefaultingZeroToNull(withdrawalFeeTypeParamName, this.withdrawalFeeType)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamedDefaultToNullIfZero(withdrawalFeeTypeParamName);
|
||||
actualChanges.put(withdrawalFeeTypeParamName, newValue);
|
||||
this.withdrawalFeeType = newValue != null ? SavingsWithdrawalFeesType.fromInt(newValue).getValue() : newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInBooleanParameterNamed(withdrawalFeeForTransfersParamName, this.withdrawalFeeApplicableForTransfer)) {
|
||||
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(withdrawalFeeForTransfersParamName);
|
||||
actualChanges.put(withdrawalFeeForTransfersParamName, newValue);
|
||||
this.withdrawalFeeApplicableForTransfer = newValue;
|
||||
}
|
||||
|
||||
// set period type to null if frequency is null
|
||||
if (this.withdrawalFeeAmount == null) {
|
||||
this.withdrawalFeeType = null;
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(annualFeeAmountParamName, this.annualFeeAmount)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(annualFeeAmountParamName);
|
||||
actualChanges.put(annualFeeAmountParamName, newValue);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.annualFeeAmount = newValue;
|
||||
}
|
||||
|
||||
if (command.hasParameter(annualFeeOnMonthDayParamName)) {
|
||||
final MonthDay monthDay = command.extractMonthDayNamed(annualFeeOnMonthDayParamName);
|
||||
final String actualValueEntered = command.stringValueOfParameterNamed(annualFeeOnMonthDayParamName);
|
||||
final Integer dayOfMonthValue = monthDay.getDayOfMonth();
|
||||
if (this.annualFeeOnDay != dayOfMonthValue) {
|
||||
actualChanges.put(annualFeeOnMonthDayParamName, actualValueEntered);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.annualFeeOnDay = dayOfMonthValue;
|
||||
}
|
||||
|
||||
final Integer monthOfYear = monthDay.getMonthOfYear();
|
||||
if (this.annualFeeOnMonth != monthOfYear) {
|
||||
actualChanges.put(annualFeeOnMonthDayParamName, actualValueEntered);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.annualFeeOnMonth = monthOfYear;
|
||||
}
|
||||
}
|
||||
|
||||
// charges
|
||||
final String chargesParamName = "charges";
|
||||
if (command.hasParameter(chargesParamName)) {
|
||||
@@ -1110,60 +877,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
}
|
||||
}
|
||||
|
||||
// set period type to null if frequency is null
|
||||
if (this.annualFeeAmount == null) {
|
||||
this.annualFeeOnDay = null;
|
||||
this.annualFeeOnMonth = null;
|
||||
}
|
||||
|
||||
validateLockinDetails();
|
||||
validateWithdrawalFeeDetails();
|
||||
validateAnnualFeeDetails();
|
||||
}
|
||||
|
||||
private void validateAnnualFeeDetails() {
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
if (this.annualFeeAmount == null) {
|
||||
|
||||
if (this.annualFeeOnMonth != null || this.annualFeeOnDay != null) {
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(this.annualFeeAmount).notNull();
|
||||
}
|
||||
} else {
|
||||
|
||||
if (this.annualFeeOnMonth == null || this.annualFeeOnDay == null) {
|
||||
baseDataValidator.reset().parameter(annualFeeOnMonthDayParamName).value(this.annualFeeOnMonth).notNull();
|
||||
}
|
||||
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(this.annualFeeAmount).zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
private void validateWithdrawalFeeDetails() {
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
if (this.withdrawalFeeAmount == null) {
|
||||
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(this.withdrawalFeeType).ignoreIfNull()
|
||||
.isOneOfTheseValues(1, 2);
|
||||
|
||||
if (this.withdrawalFeeType != null) {
|
||||
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(this.withdrawalFeeAmount).notNull();
|
||||
}
|
||||
} else {
|
||||
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(this.withdrawalFeeAmount).zeroOrPositiveAmount();
|
||||
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(this.withdrawalFeeType).notNull()
|
||||
.isOneOfTheseValues(1, 2);
|
||||
}
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
|
||||
}
|
||||
|
||||
private void validateLockinDetails() {
|
||||
@@ -1190,8 +905,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
public Map<String, Object> deriveAccountingBridgeData(final CurrencyData currencyData, final List<Long> existingTransactionIds,
|
||||
final List<Long> existingReversedTransactionIds) {
|
||||
public Map<String, Object> deriveAccountingBridgeData(final CurrencyData currencyData, final Set<Long> existingTransactionIds,
|
||||
final Set<Long> existingReversedTransactionIds) {
|
||||
|
||||
final Map<String, Object> accountingBridgeData = new LinkedHashMap<String, Object>();
|
||||
accountingBridgeData.put("savingsId", getId());
|
||||
@@ -1326,8 +1041,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
public void validateNewApplicationState(final LocalDate todayDateOfTenant) {
|
||||
|
||||
validateLockinDetails();
|
||||
validateWithdrawalFeeDetails();
|
||||
validateAnnualFeeDetails();
|
||||
//validateWithdrawalFeeDetails();
|
||||
//validateAnnualFeeDetails();
|
||||
|
||||
final LocalDate submittedOn = getSubmittedOnLocalDate();
|
||||
|
||||
@@ -1468,7 +1183,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
public void undoTransaction(final Long transactionId, final List<Long> reversedTransactionIds) {
|
||||
public void undoTransaction(final Long transactionId) {
|
||||
|
||||
SavingsAccountTransaction transactionToUndo = null;
|
||||
for (final SavingsAccountTransaction transaction : this.transactions) {
|
||||
@@ -1485,26 +1200,21 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
validateActivityNotBeforeClientOrGroupTransferDate(SavingsEvent.SAVINGS_UNDO_TRANSACTION,
|
||||
transactionToUndo.transactionLocalDate());
|
||||
transactionToUndo.reverse();
|
||||
reversedTransactionIds.add(transactionId);
|
||||
|
||||
if (transactionToUndo.isAnnualFee()) {
|
||||
this.annualFeeNextDueDate = findLatestAnnualFeeTransactionDueDate();
|
||||
if (this.annualFeeNextDueDate == null) {
|
||||
updateToNextAnnualFeeDueDateFrom(getActivationLocalDate());
|
||||
} else {
|
||||
final LocalDate newAnnualFeeNextDueDate = new LocalDate(this.annualFeeNextDueDate)
|
||||
.withMonthOfYear(this.annualFeeOnMonth).withDayOfMonth(this.annualFeeOnDay).plusYears(1);
|
||||
this.annualFeeNextDueDate = newAnnualFeeNextDueDate.toDate();
|
||||
}
|
||||
} else if (transactionToUndo.isCharge()) {
|
||||
if (transactionToUndo.isChargeTransaction() || transactionToUndo.isWaiveCharge()) {
|
||||
// undo charge
|
||||
final Set<SavingsAccountChargePaidBy> chargesPaidBy = transactionToUndo.getSavingsAccountChargesPaid();
|
||||
for (final SavingsAccountChargePaidBy savingsAccountChargePaidBy : chargesPaidBy) {
|
||||
final SavingsAccountCharge chargeToUndo = savingsAccountChargePaidBy.getSavingsAccountCharge();
|
||||
chargeToUndo.resetPaidAmount(this.currency);
|
||||
if (transactionToUndo.isChargeTransaction()) {
|
||||
chargeToUndo.undoPayment(this.getCurrency(), transactionToUndo.getAmount(this.getCurrency()));
|
||||
if(chargeToUndo.isAnnualFee()){
|
||||
chargeToUndo.updateToPreviousAnnualFeeDueDate();
|
||||
}
|
||||
} else if (transactionToUndo.isWaiveCharge()) {
|
||||
chargeToUndo.undoWaiver(this.getCurrency(), transactionToUndo.getAmount(this.getCurrency()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1649,8 +1359,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
public Map<String, Object> activate(final AppUser currentUser, final JsonCommand command, final LocalDate tenantsTodayDate,
|
||||
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) {
|
||||
public Map<String, Object> activate(final AppUser currentUser, final JsonCommand command, final LocalDate tenantsTodayDate) {
|
||||
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
||||
|
||||
@@ -1687,10 +1396,10 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
this.activatedBy = currentUser;
|
||||
this.lockedInUntilDate = calculateDateAccountIsLockedUntil(getActivationLocalDate());
|
||||
|
||||
if (annualFeeSettingsSet()) {
|
||||
/*if (annualFeeSettingsSet()) {
|
||||
updateToNextAnnualFeeDueDateFrom(getActivationLocalDate());
|
||||
}
|
||||
|
||||
*/
|
||||
if (this.client != null && this.client.isActivatedAfter(activationDate)) {
|
||||
final DateTimeFormatter formatter = DateTimeFormat.forPattern(command.dateFormat()).withLocale(command.extractLocale());
|
||||
final String dateAsString = formatter.print(this.client.getActivationLocalDate());
|
||||
@@ -1733,7 +1442,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
final Money minRequiredOpeningBalance = Money.of(this.currency, this.minRequiredOpeningBalance);
|
||||
if (minRequiredOpeningBalance.isGreaterThanZero()) {
|
||||
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, activationDate,
|
||||
minRequiredOpeningBalance.getAmount(), existingTransactionIds, existingReversedTransactionIds, null);
|
||||
minRequiredOpeningBalance.getAmount(), null);
|
||||
deposit(transactionDTO);
|
||||
|
||||
// no openingBalance concept supported yet but probably will to
|
||||
@@ -1745,9 +1454,27 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
// correct.
|
||||
recalculateDailyBalances(openingAccountBalance);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//update annual fee due date
|
||||
for (SavingsAccountCharge charge : this.charges()) {
|
||||
charge.updateToNextAnnualFeeDueDateFrom(getActivationLocalDate());
|
||||
}
|
||||
|
||||
//auto pay the activation time charges
|
||||
this.payActivationCharges();
|
||||
//TODO : AA add activation charges to actual changes list
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
private void payActivationCharges() {
|
||||
for (SavingsAccountCharge savingsAccountCharge : this.charges()) {
|
||||
if (savingsAccountCharge.isSavingsActivation()) {
|
||||
payCharge(savingsAccountCharge, savingsAccountCharge.getAmountOutstanding(getCurrency()), getActivationLocalDate());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Object> close(final AppUser currentUser, final JsonCommand command, final LocalDate tenantsTodayDate) {
|
||||
|
||||
@@ -1893,21 +1620,33 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public boolean hasCurrencyCodeOf(final String matchingCurrencyCode) {
|
||||
// TODO AA: revisit
|
||||
if (this.currency == null) { return false; }
|
||||
return this.currency.getCode().equalsIgnoreCase(matchingCurrencyCode);
|
||||
}
|
||||
|
||||
public void removeCharge(final SavingsAccountCharge charge) {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
if (isClosed()) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("delete.transaction.invalid.account.is.closed");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
if (isActive() || isApproved()) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("delete.transaction.invalid.account.is.active");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
this.charges.remove(charge);
|
||||
}
|
||||
|
||||
public void waiveCharge(final Long savingsAccountChargeId, final List<Long> existingTransactionIds,
|
||||
final List<Long> existingReversedTransactionIds) {
|
||||
public void waiveCharge(final Long savingsAccountChargeId) {
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME + "dueDate");
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
if (isClosed()) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.closed");
|
||||
@@ -1921,6 +1660,11 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
|
||||
final SavingsAccountCharge savingsAccountCharge = getCharge(savingsAccountChargeId);
|
||||
|
||||
if (savingsAccountCharge.isWithdrawalFee()){
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.waiver.of.withdrawal.fee.not.supported");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
// validate charge is not already paid or waived
|
||||
if (savingsAccountCharge.isWaived()) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.charge.is.already.waived");
|
||||
@@ -1930,46 +1674,23 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||
|
||||
// waive charge
|
||||
final Money amountWaived = savingsAccountCharge.waive(getCurrency());
|
||||
// TODO : AA revisit the code
|
||||
/*
|
||||
* Money feeChargesWaived = amountWaived; Money penaltyChargesWaived =
|
||||
* Money.zero(this.getCurrency()); if
|
||||
* (savingsAccountCharge.isPenaltyCharge()) { penaltyChargesWaived =
|
||||
* amountWaived; feeChargesWaived = Money.zero(this.getCurrency()); }
|
||||
*/
|
||||
|
||||
// persist an entry in transaction details
|
||||
final SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.charge(this, office(),
|
||||
savingsAccountCharge.getDueLocalDate(), amountWaived);
|
||||
|
||||
this.transactions.add(chargeTransaction);
|
||||
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
calculateInterestUsing(mc, savingsAccountCharge.getDueLocalDate());
|
||||
handleWaiverChargeTransactions(savingsAccountCharge, amountWaived);
|
||||
}
|
||||
|
||||
public void addCharge(final DateTimeFormatter formatter, final SavingsAccountCharge savingsAccountCharge, final Charge chargeDefinition) {
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME + "dueDate");
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
if (isClosed()) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.closed");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
if (isNotActive()) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.not.active");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
if (!hasCurrencyCodeOf(chargeDefinition.getCurrencyCode())) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
|
||||
"transaction.invalid.account.currency.and.charge.currency.not.same");
|
||||
@@ -1978,25 +1699,72 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
|
||||
final LocalDate chargeDueDate = savingsAccountCharge.getDueLocalDate();
|
||||
|
||||
if (chargeDueDate != null && chargeDueDate.isBefore(getActivationLocalDate())) {
|
||||
baseDataValidator.reset().parameter("dueDate").value(getActivationLocalDate().toString(formatter))
|
||||
.failWithCodeNoParameterAddedToErrorCode("before.activationDate");
|
||||
if (savingsAccountCharge.isOnSpecifiedDueDate()) {
|
||||
if (getActivationLocalDate() != null && chargeDueDate.isBefore(getActivationLocalDate())) {
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(getActivationLocalDate().toString(formatter))
|
||||
.failWithCodeNoParameterAddedToErrorCode("before.activationDate");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
} else if (getSubmittedOnLocalDate() != null && chargeDueDate.isBefore(getSubmittedOnLocalDate())) {
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(getSubmittedOnLocalDate().toString(formatter))
|
||||
.failWithCodeNoParameterAddedToErrorCode("before.submittedOnDate");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
if (savingsAccountCharge.isSavingsActivation() && !(isSubmittedAndPendingApproval() || (isApproved() && isNotActive()))) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
|
||||
"not.valid.account.status.cannot.add.activation.time.charge");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
validateActivityNotBeforeClientOrGroupTransferDate(SavingsEvent.SAVINGS_APPLY_CHARGE, chargeDueDate);
|
||||
|
||||
//Only one withdrawal fee is supported per account
|
||||
if(savingsAccountCharge.isWithdrawalFee()){
|
||||
if(this.isWithDrawalFeeExists()){
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
|
||||
"multiple.withdrawal.fee.per.account.not.supported");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
//Only one annual fee is supported per account
|
||||
if(savingsAccountCharge.isAnnualFee()){
|
||||
if(this.isAnnualFeeExists()){
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
|
||||
"multiple.annual.fee.per.account.not.supported");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
//activation charge and withdrawal charges not required this validation
|
||||
if(savingsAccountCharge.isOnSpecifiedDueDate()){
|
||||
validateActivityNotBeforeClientOrGroupTransferDate(SavingsEvent.SAVINGS_APPLY_CHARGE, chargeDueDate);
|
||||
}
|
||||
|
||||
// add new charge to savings account
|
||||
getCharges().add(savingsAccountCharge);
|
||||
charges().add(savingsAccountCharge);
|
||||
|
||||
}
|
||||
|
||||
public void payCharge(final Long savingsAccountChargeId, final BigDecimal amountPaid, final List<Long> existingTransactionIds,
|
||||
final List<Long> existingReversedTransactionIds) {
|
||||
private boolean isWithDrawalFeeExists() {
|
||||
for (SavingsAccountCharge charge : this.charges()) {
|
||||
if(charge.isWithdrawalFee()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isAnnualFeeExists() {
|
||||
for (SavingsAccountCharge charge : this.charges()) {
|
||||
if(charge.isAnnualFee()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void payCharge(final SavingsAccountCharge savingsAccountCharge, final BigDecimal amountPaid, final LocalDate transactionDate,
|
||||
final DateTimeFormatter formatter) {
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME + "dueDate");
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
if (isClosed()) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.closed");
|
||||
@@ -2008,8 +1776,45 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
final SavingsAccountCharge savingsAccountCharge = getCharge(savingsAccountChargeId);
|
||||
if (getActivationLocalDate() != null && transactionDate.isBefore(getActivationLocalDate())) {
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(getActivationLocalDate().toString(formatter))
|
||||
.failWithCodeNoParameterAddedToErrorCode("transaction.before.activationDate");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
if (DateUtils.isDateInTheFuture(transactionDate)) {
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(getSubmittedOnLocalDate().toString(formatter))
|
||||
.failWithCodeNoParameterAddedToErrorCode("transaction.is.futureDate");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
if (savingsAccountCharge.isSavingsActivation()) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
|
||||
"transaction.not.valid.cannot.pay.activation.time.charge.is.automated");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
if (savingsAccountCharge.isAnnualFee()){
|
||||
final LocalDate annualFeeDueDate = savingsAccountCharge.getDueLocalDate();
|
||||
if (annualFeeDueDate == null) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("no.annualfee.settings");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
if (!annualFeeDueDate.equals(transactionDate)) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("invalid.date");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
Date currentAnnualFeeNextDueDate = findLatestAnnualFeeTransactionDueDate();
|
||||
if (currentAnnualFeeNextDueDate != null && new LocalDate(currentAnnualFeeNextDueDate).isEqual(transactionDate)) {
|
||||
baseDataValidator.reset().parameter("dueDate").value(transactionDate.toString(formatter))
|
||||
.failWithCodeNoParameterAddedToErrorCode("transaction.exists.on.date");
|
||||
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
// validate charge is not already paid or waived
|
||||
if (savingsAccountCharge.isWaived()) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.charge.is.already.waived");
|
||||
@@ -2019,36 +1824,51 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||
|
||||
final Money chargePaid = savingsAccountCharge.pay(getCurrency(), amountPaid);
|
||||
|
||||
// If null reset to current date
|
||||
final LocalDate transactionDate = (savingsAccountCharge.getDueLocalDate() == null) ? DateUtils.getLocalDateOfTenant()
|
||||
: savingsAccountCharge.getDueLocalDate();
|
||||
|
||||
// persist an entry in transaction details
|
||||
final SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.charge(this, office(), transactionDate, chargePaid);
|
||||
|
||||
final SavingsAccountChargePaidBy chargePaidBy = SavingsAccountChargePaidBy.instance(chargeTransaction, savingsAccountCharge,
|
||||
amountPaid);
|
||||
chargeTransaction.getSavingsAccountChargesPaid().add(chargePaidBy);
|
||||
this.transactions.add(chargeTransaction);
|
||||
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
postInterest(mc, today, existingTransactionIds, existingReversedTransactionIds);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
calculateInterestUsing(mc, today);
|
||||
final Money chargePaid = Money.of(currency, amountPaid);
|
||||
if (!savingsAccountCharge.getAmountOutstanding(getCurrency()).isGreaterThanOrEqualTo(chargePaid)) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.charge.amount.paid.in.access");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
this.payCharge(savingsAccountCharge, chargePaid, transactionDate);
|
||||
|
||||
//update next annual fee due date
|
||||
savingsAccountCharge.updateToNextAnnualFeeDueDate();
|
||||
}
|
||||
|
||||
validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.payChargeTransactionAction);
|
||||
public void payCharge(final SavingsAccountCharge savingsAccountCharge, final Money amountPaid, final LocalDate transactionDate) {
|
||||
savingsAccountCharge.pay(getCurrency(), amountPaid);
|
||||
handlePayChargeTransactions(savingsAccountCharge, amountPaid, transactionDate);
|
||||
}
|
||||
|
||||
private void handlePayChargeTransactions(SavingsAccountCharge savingsAccountCharge, Money transactionAmount,
|
||||
final LocalDate transactionDate) {
|
||||
SavingsAccountTransaction chargeTransaction = null;
|
||||
|
||||
if (savingsAccountCharge.isWithdrawalFee()){
|
||||
chargeTransaction = SavingsAccountTransaction.withdrawalFee(this, office(), transactionDate, transactionAmount);
|
||||
}else if (savingsAccountCharge.isAnnualFee()){
|
||||
chargeTransaction = SavingsAccountTransaction.annualFee(this, office(), transactionDate, transactionAmount);
|
||||
}else {
|
||||
chargeTransaction = SavingsAccountTransaction.charge(this, office(), transactionDate, transactionAmount);
|
||||
}
|
||||
|
||||
handleChargeTransactions(savingsAccountCharge, chargeTransaction);
|
||||
}
|
||||
|
||||
private void handleWaiverChargeTransactions(SavingsAccountCharge savingsAccountCharge, Money transactionAmount) {
|
||||
final SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.waiver(this, office(),
|
||||
DateUtils.getLocalDateOfTenant(), transactionAmount);
|
||||
handleChargeTransactions(savingsAccountCharge, chargeTransaction);
|
||||
}
|
||||
|
||||
private void handleChargeTransactions(final SavingsAccountCharge savingsAccountCharge, final SavingsAccountTransaction transaction) {
|
||||
// Provide a link between transaction and savings charge for which
|
||||
// amount is waived.
|
||||
final SavingsAccountChargePaidBy chargePaidBy = SavingsAccountChargePaidBy.instance(transaction, savingsAccountCharge, transaction
|
||||
.getAmount(this.getCurrency()).getAmount());
|
||||
transaction.getSavingsAccountChargesPaid().add(chargePaidBy);
|
||||
this.getTransactions().add(transaction);
|
||||
}
|
||||
|
||||
private SavingsAccountCharge getCharge(final Long savingsAccountChargeId) {
|
||||
@@ -2065,7 +1885,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
return charge;
|
||||
}
|
||||
|
||||
private Set<SavingsAccountCharge> getCharges() {
|
||||
public Set<SavingsAccountCharge> charges() {
|
||||
return (this.charges == null) ? new HashSet<SavingsAccountCharge>() : this.charges;
|
||||
}
|
||||
}
|
||||
+2
-40
@@ -6,8 +6,6 @@
|
||||
package org.mifosplatform.portfolio.savings.domain;
|
||||
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.accountNoParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeOnMonthDayParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.clientIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.externalIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.fieldOfficerIdParamName;
|
||||
@@ -22,15 +20,12 @@ import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequire
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.productIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.submittedOnDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeTypeParamName;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Set;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
@@ -50,7 +45,6 @@ import org.mifosplatform.portfolio.savings.SavingsInterestCalculationDaysInYearT
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPeriodFrequencyType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsWithdrawalFeesType;
|
||||
import org.mifosplatform.portfolio.savings.exception.SavingsProductNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -199,50 +193,18 @@ public class SavingsAccountAssembler {
|
||||
} else {
|
||||
lockinPeriodFrequencyType = product.lockinPeriodFrequencyType();
|
||||
}
|
||||
|
||||
BigDecimal withdrawalFeeAmount = null;
|
||||
if (command.parameterExists(withdrawalFeeAmountParamName)) {
|
||||
withdrawalFeeAmount = command.bigDecimalValueOfParameterNamed(withdrawalFeeAmountParamName);
|
||||
} else {
|
||||
withdrawalFeeAmount = product.withdrawalFeeAmount();
|
||||
}
|
||||
|
||||
SavingsWithdrawalFeesType withdrawalFeeType = null;
|
||||
if (command.parameterExists(withdrawalFeeAmountParamName)) {
|
||||
final Integer withdrawalFeeTypeValue = command.integerValueOfParameterNamed(withdrawalFeeTypeParamName);
|
||||
if (withdrawalFeeTypeValue != null) {
|
||||
withdrawalFeeType = SavingsWithdrawalFeesType.fromInt(withdrawalFeeTypeValue);
|
||||
}
|
||||
} else {
|
||||
withdrawalFeeType = product.withdrawalFeeType();
|
||||
}
|
||||
|
||||
boolean iswithdrawalFeeApplicableForTransfer = false;
|
||||
if (command.parameterExists(withdrawalFeeForTransfersParamName)) {
|
||||
iswithdrawalFeeApplicableForTransfer = command.booleanPrimitiveValueOfParameterNamed(withdrawalFeeForTransfersParamName);
|
||||
}
|
||||
|
||||
BigDecimal annualFeeAmount = null;
|
||||
if (command.parameterExists(annualFeeAmountParamName)) {
|
||||
annualFeeAmount = command.bigDecimalValueOfParameterNamed(annualFeeAmountParamName);
|
||||
} else {
|
||||
annualFeeAmount = product.annualFeeAmount();
|
||||
}
|
||||
|
||||
MonthDay monthDayOfAnnualFee = null;
|
||||
if (command.parameterExists(annualFeeOnMonthDayParamName)) {
|
||||
monthDayOfAnnualFee = command.extractMonthDayNamed(annualFeeOnMonthDayParamName);
|
||||
} else {
|
||||
monthDayOfAnnualFee = product.monthDayOfAnnualFee();
|
||||
}
|
||||
|
||||
final Set<SavingsAccountCharge> charges = this.savingsAccountChargeAssembler.fromParsedJson(element);
|
||||
final Set<SavingsAccountCharge> charges = this.savingsAccountChargeAssembler.fromParsedJson(element, product.currency().getCode());
|
||||
|
||||
final SavingsAccount account = SavingsAccount.createNewApplicationForSubmittal(client, group, product, fieldOfficer, accountNo,
|
||||
externalId, accountType, submittedOnDate, interestRate, interestCompoundingPeriodType, interestPostingPeriodType,
|
||||
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, iswithdrawalFeeApplicableForTransfer, annualFeeAmount,
|
||||
monthDayOfAnnualFee, charges);
|
||||
lockinPeriodFrequencyType, iswithdrawalFeeApplicableForTransfer, charges);
|
||||
account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper);
|
||||
|
||||
account.validateNewApplicationState(DateUtils.getLocalDateOfTenant());
|
||||
|
||||
+165
-29
@@ -9,6 +9,7 @@ import static org.mifosplatform.portfolio.savings.SavingsApiConstants.amountPara
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.dateFormatParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.localeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.feeOnMonthDayParamName;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
@@ -28,6 +29,7 @@ import javax.persistence.TemporalType;
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
@@ -53,15 +55,22 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
||||
private Integer chargeTime;
|
||||
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "due_for_collection_as_of_date")
|
||||
@Column(name = "charge_due_date")
|
||||
private Date dueDate;
|
||||
|
||||
@Column(name = "fee_on_month", nullable = true)
|
||||
private Integer feeOnMonth;
|
||||
|
||||
@Column(name = "fee_on_day", nullable = true)
|
||||
private Integer feeOnDay;
|
||||
|
||||
@Column(name = "charge_calculation_enum")
|
||||
private Integer chargeCalculation;
|
||||
|
||||
@Column(name = "calculation_percentage", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal percentage;
|
||||
|
||||
// TODO AA: This field may not require for savings charges
|
||||
@Column(name = "calculation_on_amount", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal amountPercentageAppliedTo;
|
||||
|
||||
@@ -89,29 +98,38 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
||||
@Column(name = "waived", nullable = false)
|
||||
private boolean waived = false;
|
||||
|
||||
@Column(name = "is_active", nullable = false)
|
||||
private boolean status = true;
|
||||
|
||||
public static SavingsAccountCharge createNewFromJson(final SavingsAccount savingsAccount, final Charge chargeDefinition,
|
||||
final JsonCommand command) {
|
||||
|
||||
final BigDecimal amount = command.bigDecimalValueOfParameterNamed(amountParamName);
|
||||
final LocalDate dueDate = command.localDateValueOfParameterNamed(dueAsOfDateParamName);
|
||||
final MonthDay feeOnMonthDay = command.extractMonthDayNamed(feeOnMonthDayParamName);
|
||||
final ChargeTimeType chargeTime = null;
|
||||
final ChargeCalculationType chargeCalculation = null;
|
||||
final boolean status = true;
|
||||
|
||||
return new SavingsAccountCharge(savingsAccount, chargeDefinition, amount, chargeTime, chargeCalculation, dueDate);
|
||||
return new SavingsAccountCharge(savingsAccount, chargeDefinition, amount, chargeTime, chargeCalculation, dueDate, status,
|
||||
feeOnMonthDay);
|
||||
}
|
||||
|
||||
// TODO AA: refactor method signature
|
||||
public static SavingsAccountCharge createNewWithoutSavingsAccount(final Charge chargeDefinition, final BigDecimal amount,
|
||||
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculation, final LocalDate dueDate) {
|
||||
return new SavingsAccountCharge(null, chargeDefinition, amount, chargeTime, chargeCalculation, dueDate);
|
||||
public static SavingsAccountCharge createNewWithoutSavingsAccount(final Charge chargeDefinition, final BigDecimal amountPayable,
|
||||
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculation, final LocalDate dueDate, final boolean status,
|
||||
final MonthDay feeOnMonthDay) {
|
||||
return new SavingsAccountCharge(null, chargeDefinition, amountPayable, chargeTime, chargeCalculation, dueDate, status,
|
||||
feeOnMonthDay);
|
||||
}
|
||||
|
||||
protected SavingsAccountCharge() {
|
||||
//
|
||||
}
|
||||
|
||||
public SavingsAccountCharge(final SavingsAccount savingsAccount, final Charge chargeDefinition, final BigDecimal amount,
|
||||
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculation, final LocalDate dueDate) {
|
||||
private SavingsAccountCharge(final SavingsAccount savingsAccount, final Charge chargeDefinition, final BigDecimal amount,
|
||||
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculation, final LocalDate dueDate, final boolean status,
|
||||
final MonthDay feeOnMonthDay) {
|
||||
|
||||
this.savingsAccount = savingsAccount;
|
||||
this.charge = chargeDefinition;
|
||||
@@ -127,6 +145,16 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
||||
|
||||
}
|
||||
|
||||
if (isAnnualFee()) {
|
||||
if (feeOnMonthDay == null) {
|
||||
final String defaultUserMessage = "Savings Account charge is missing due date.";
|
||||
throw new SavingsAccountChargeWithoutMandatoryFieldException("savingsaccount.charge", dueAsOfDateParamName,
|
||||
defaultUserMessage, chargeDefinition.getId(), chargeDefinition.getName());
|
||||
}
|
||||
this.feeOnMonth = feeOnMonthDay.getMonthOfYear();
|
||||
this.feeOnDay = feeOnMonthDay.getDayOfMonth();
|
||||
}
|
||||
|
||||
this.dueDate = (dueDate == null) ? null : dueDate.toDate();
|
||||
|
||||
this.chargeCalculation = chargeDefinition.getChargeCalculation();
|
||||
@@ -139,13 +167,18 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
||||
chargeAmount = amount;
|
||||
}
|
||||
|
||||
final BigDecimal transactionAmount = new BigDecimal(0);// percentage
|
||||
// based fee is
|
||||
// not yet
|
||||
// supported for
|
||||
// savings
|
||||
final BigDecimal transactionAmount = new BigDecimal(0);
|
||||
|
||||
populateDerivedFields(transactionAmount, chargeAmount);
|
||||
resetOutstandingAmount();// reset only if it's withdrawal or annual fee
|
||||
this.paid = determineIfFullyPaid();
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
private void resetOutstandingAmount() {
|
||||
if (this.isWithdrawalFee()) {
|
||||
this.amountOutstanding = BigDecimal.ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
private void populateDerivedFields(final BigDecimal transactionAmount, final BigDecimal chargeAmount) {
|
||||
@@ -214,31 +247,42 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
||||
this.waived = false;
|
||||
}
|
||||
|
||||
public void resetPaidAmount(final MonetaryCurrency currency) {
|
||||
this.amountPaid = BigDecimal.ZERO;
|
||||
public void undoPayment(final MonetaryCurrency currency, final Money transactionAmount) {
|
||||
Money amountPaid = getAmountPaid(currency);
|
||||
amountPaid = amountPaid.minus(transactionAmount);
|
||||
this.amountPaid = amountPaid.getAmount();
|
||||
this.amountOutstanding = calculateAmountOutstanding(currency);
|
||||
if (this.isWithdrawalFee()) {
|
||||
this.amountOutstanding = BigDecimal.ZERO;
|
||||
}
|
||||
this.paid = false;
|
||||
}
|
||||
|
||||
public Money waive(final MonetaryCurrency currency) {
|
||||
this.amountWaived = this.amountOutstanding;
|
||||
this.amountOutstanding = BigDecimal.ZERO;
|
||||
this.paid = false;
|
||||
this.waived = true;
|
||||
return getAmountWaived(currency);
|
||||
}
|
||||
|
||||
public Money pay(final MonetaryCurrency currency, final BigDecimal chargePaid) {
|
||||
public void undoWaiver(final MonetaryCurrency currency, final Money transactionAmount) {
|
||||
Money amountWaived = getAmountWaived(currency);
|
||||
amountWaived = amountWaived.minus(transactionAmount);
|
||||
this.amountWaived = amountWaived.getAmount();
|
||||
this.amountOutstanding = calculateAmountOutstanding(currency);
|
||||
this.waived = false;
|
||||
}
|
||||
|
||||
public Money pay(final MonetaryCurrency currency, final Money amountPaid) {
|
||||
|
||||
Money amountPaidToDate = Money.of(currency, this.amountPaid);
|
||||
final Money amountPaid = Money.of(currency, chargePaid);
|
||||
Money amountOutstanding = Money.of(currency, this.amountOutstanding);
|
||||
amountPaidToDate = amountPaidToDate.plus(amountPaid);
|
||||
amountOutstanding = amountOutstanding.minus(chargePaid);
|
||||
amountOutstanding = amountOutstanding.minus(amountPaid);
|
||||
this.amountPaid = amountPaidToDate.getAmount();
|
||||
this.amountOutstanding = amountOutstanding.getAmount();
|
||||
this.paid = determineIfFullyPaid();
|
||||
return amountPaid;
|
||||
return amountOutstanding;
|
||||
}
|
||||
|
||||
private BigDecimal calculateAmountOutstanding(final MonetaryCurrency currency) {
|
||||
@@ -249,16 +293,17 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
||||
this.savingsAccount = savingsAccount;
|
||||
}
|
||||
|
||||
public void update(final BigDecimal amount, final LocalDate dueDate) {
|
||||
final BigDecimal transactionAmount = BigDecimal.ZERO;// percentage based
|
||||
// fee calculation
|
||||
// is not yet
|
||||
// supported for
|
||||
// Savings
|
||||
public void update(final BigDecimal amount, final LocalDate dueDate, final MonthDay feeOnMonthDay) {
|
||||
final BigDecimal transactionAmount = BigDecimal.ZERO;
|
||||
if (dueDate != null) {
|
||||
this.dueDate = dueDate.toDate();
|
||||
}
|
||||
|
||||
if (feeOnMonthDay != null) {
|
||||
this.feeOnMonth = feeOnMonthDay.getMonthOfYear();
|
||||
this.feeOnDay = feeOnMonthDay.getDayOfMonth();
|
||||
}
|
||||
|
||||
if (amount != null) {
|
||||
switch (ChargeCalculationType.fromInt(this.chargeCalculation)) {
|
||||
case INVALID:
|
||||
@@ -305,6 +350,24 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
||||
this.dueDate = newValue.toDate();
|
||||
}
|
||||
|
||||
if (command.hasParameter(feeOnMonthDayParamName)) {
|
||||
final MonthDay monthDay = command.extractMonthDayNamed(feeOnMonthDayParamName);
|
||||
final String actualValueEntered = command.stringValueOfParameterNamed(feeOnMonthDayParamName);
|
||||
final Integer dayOfMonthValue = monthDay.getDayOfMonth();
|
||||
if (this.feeOnDay != dayOfMonthValue) {
|
||||
actualChanges.put(feeOnMonthDayParamName, actualValueEntered);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.feeOnDay = dayOfMonthValue;
|
||||
}
|
||||
|
||||
final Integer monthOfYear = monthDay.getMonthOfYear();
|
||||
if (this.feeOnMonth != monthOfYear) {
|
||||
actualChanges.put(feeOnMonthDayParamName, actualValueEntered);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.feeOnMonth = monthOfYear;
|
||||
}
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamed(amountParamName, this.amount)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(amountParamName);
|
||||
actualChanges.put(amountParamName, newValue);
|
||||
@@ -314,6 +377,7 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
||||
break;
|
||||
case FLAT:
|
||||
this.amount = newValue;
|
||||
this.amountOutstanding = calculateOutstanding();
|
||||
break;
|
||||
case PERCENT_OF_AMOUNT:
|
||||
this.percentage = newValue;
|
||||
@@ -339,10 +403,6 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
public boolean isSpecifiedDueDate() {
|
||||
return ChargeTimeType.fromInt(this.chargeTime).equals(ChargeTimeType.SPECIFIED_DUE_DATE);
|
||||
}
|
||||
|
||||
private boolean isGreaterThanZero(final BigDecimal value) {
|
||||
return value.compareTo(BigDecimal.ZERO) == 1;
|
||||
}
|
||||
@@ -398,6 +458,10 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public BigDecimal amoutOutstanding() {
|
||||
return this.amountOutstanding;
|
||||
}
|
||||
|
||||
public boolean isFeeCharge() {
|
||||
return !this.penaltyCharge;
|
||||
}
|
||||
@@ -440,6 +504,10 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
||||
return Money.of(currency, this.amountWrittenOff);
|
||||
}
|
||||
|
||||
public Money getAmountOutstanding(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amountOutstanding);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param incrementBy
|
||||
* Amount used to pay off this charge
|
||||
@@ -482,10 +550,35 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
||||
return this.charge;
|
||||
}
|
||||
|
||||
public SavingsAccount savingsAccount() {
|
||||
return this.savingsAccount;
|
||||
}
|
||||
|
||||
public boolean isOnSpecifiedDueDate() {
|
||||
return ChargeTimeType.fromInt(this.chargeTime).isOnSpecifiedDueDate();
|
||||
}
|
||||
|
||||
public boolean isSavingsActivation() {
|
||||
return ChargeTimeType.fromInt(this.chargeTime).isSavingsActivation();
|
||||
}
|
||||
|
||||
public boolean isSavingsClosure() {
|
||||
return ChargeTimeType.fromInt(this.chargeTime).isSavingsClosure();
|
||||
}
|
||||
|
||||
public boolean isWithdrawalFee() {
|
||||
return ChargeTimeType.fromInt(this.chargeTime).isWithdrawalFee();
|
||||
}
|
||||
|
||||
public boolean isAnnualFee() {
|
||||
return ChargeTimeType.fromInt(this.chargeTime).isAnnualFee();
|
||||
}
|
||||
|
||||
public boolean hasCurrencyCodeOf(final String matchingCurrencyCode) {
|
||||
if (this.currencyCode() == null || matchingCurrencyCode == null) { return false; }
|
||||
return this.currencyCode().equalsIgnoreCase(matchingCurrencyCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == null) { return false; }
|
||||
@@ -508,4 +601,47 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
||||
.append(this.amount).append(getDueLocalDate()) //
|
||||
.toHashCode();
|
||||
}
|
||||
|
||||
public BigDecimal updateWithdralFeeAmount(final BigDecimal transactionAmount) {
|
||||
BigDecimal amountPaybale = BigDecimal.ZERO;
|
||||
if (ChargeCalculationType.fromInt(this.chargeCalculation).isFlat()) {
|
||||
amountPaybale = this.amount;
|
||||
} else if (ChargeCalculationType.fromInt(this.chargeCalculation).isPercentageOfAmount()) {
|
||||
amountPaybale = transactionAmount.multiply(this.percentage).divide(BigDecimal.valueOf(100l));
|
||||
}
|
||||
this.amountOutstanding = amountPaybale;
|
||||
return amountPaybale;
|
||||
}
|
||||
|
||||
public void updateToNextAnnualFeeDueDateFrom(final LocalDate startingDate) {
|
||||
if (isAnnualFee()) {
|
||||
LocalDate nextDueLocalDate = startingDate.withMonthOfYear(this.feeOnMonth).withDayOfMonth(this.feeOnDay);
|
||||
if (startingDate.isAfter(nextDueLocalDate)) {
|
||||
nextDueLocalDate = nextDueLocalDate.plusYears(1);
|
||||
}
|
||||
this.dueDate = nextDueLocalDate.toDate();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateToNextAnnualFeeDueDate() {
|
||||
if (isAnnualFee()) {
|
||||
LocalDate nextDueLocalDate = new LocalDate(dueDate);
|
||||
this.dueDate = nextDueLocalDate.withMonthOfYear(this.feeOnMonth).withDayOfMonth(this.feeOnDay).plusYears(1).toDate();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateToPreviousAnnualFeeDueDate() {
|
||||
if (isAnnualFee()) {
|
||||
LocalDate previousDueLocalDate = new LocalDate(dueDate);
|
||||
this.dueDate = previousDueLocalDate.withMonthOfYear(this.feeOnMonth).withDayOfMonth(this.feeOnDay).minusYears(1).toDate();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean feeSettingsNotSet() {
|
||||
return !feeSettingsSet();
|
||||
}
|
||||
|
||||
public boolean feeSettingsSet() {
|
||||
return this.feeOnDay != null && this.feeOnMonth != null;
|
||||
}
|
||||
}
|
||||
+46
-3
@@ -5,20 +5,28 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.savings.domain;
|
||||
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.amountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargeCalculationTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargeIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargeTimeTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargesParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.feeOnMonthDayParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.idParamName;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.portfolio.charge.domain.Charge;
|
||||
import org.mifosplatform.portfolio.charge.domain.ChargeCalculationType;
|
||||
@@ -48,13 +56,14 @@ public class SavingsAccountChargeAssembler {
|
||||
this.savingsAccountChargeRepository = savingsAccountChargeRepository;
|
||||
}
|
||||
|
||||
public Set<SavingsAccountCharge> fromParsedJson(final JsonElement element) {
|
||||
public Set<SavingsAccountCharge> fromParsedJson(final JsonElement element, final String productCurrencyCode) {
|
||||
|
||||
final Set<SavingsAccountCharge> savingsAccountCharges = new HashSet<SavingsAccountCharge>();
|
||||
|
||||
if (element.isJsonObject()) {
|
||||
final JsonObject topLevelJsonElement = element.getAsJsonObject();
|
||||
final String dateFormat = this.fromApiJsonHelper.extractDateFormatParameter(topLevelJsonElement);
|
||||
final String monthDayFormat = this.fromApiJsonHelper.extractMonthDayFormatParameter(topLevelJsonElement);
|
||||
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
|
||||
if (topLevelJsonElement.has(chargesParamName) && topLevelJsonElement.get(chargesParamName).isJsonArray()) {
|
||||
final JsonArray array = topLevelJsonElement.get(chargesParamName).getAsJsonArray();
|
||||
@@ -72,6 +81,8 @@ public class SavingsAccountChargeAssembler {
|
||||
final LocalDate dueDate = this.fromApiJsonHelper.extractLocalDateNamed(dueAsOfDateParamName, savingsChargeElement,
|
||||
dateFormat, locale);
|
||||
|
||||
final MonthDay feeOnMonthDay = this.fromApiJsonHelper.extractMonthDayNamed(feeOnMonthDayParamName, savingsChargeElement, monthDayFormat, locale);
|
||||
|
||||
if (id == null) {
|
||||
final Charge chargeDefinition = this.chargeRepository.findOneWithNotFoundDetection(chargeId);
|
||||
|
||||
@@ -89,8 +100,10 @@ public class SavingsAccountChargeAssembler {
|
||||
if (chargeCalculationType != null) {
|
||||
ChargeCalculationType.fromInt(chargeCalculationType);
|
||||
}
|
||||
|
||||
final boolean status = true;
|
||||
final SavingsAccountCharge savingsAccountCharge = SavingsAccountCharge.createNewWithoutSavingsAccount(
|
||||
chargeDefinition, amount, chargeTime, chargeCalculation, dueDate);
|
||||
chargeDefinition, amount, chargeTime, chargeCalculation, dueDate, status, feeOnMonthDay);
|
||||
savingsAccountCharges.add(savingsAccountCharge);
|
||||
} else {
|
||||
final Long savingsAccountChargeId = id;
|
||||
@@ -98,7 +111,7 @@ public class SavingsAccountChargeAssembler {
|
||||
.findOne(savingsAccountChargeId);
|
||||
if (savingsAccountCharge == null) { throw new SavingsAccountChargeNotFoundException(savingsAccountChargeId); }
|
||||
|
||||
savingsAccountCharge.update(amount, dueDate);
|
||||
savingsAccountCharge.update(amount, dueDate, feeOnMonthDay);
|
||||
|
||||
savingsAccountCharges.add(savingsAccountCharge);
|
||||
}
|
||||
@@ -106,6 +119,36 @@ public class SavingsAccountChargeAssembler {
|
||||
}
|
||||
}
|
||||
|
||||
this.validateSavingsCharges(savingsAccountCharges, productCurrencyCode);
|
||||
return savingsAccountCharges;
|
||||
}
|
||||
|
||||
private void validateSavingsCharges(final Set<SavingsAccountCharge> charges, final String productCurrencyCode) {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
boolean isOneWithdrawalPresent = false;
|
||||
boolean isOneAnnualPresent = false;
|
||||
for (SavingsAccountCharge charge : charges) {
|
||||
if(!charge.hasCurrencyCodeOf(productCurrencyCode)){
|
||||
baseDataValidator.reset().parameter("currency").value(charge.getCharge().getId())
|
||||
.failWithCodeNoParameterAddedToErrorCode("currency.and.charge.currency.not.same");
|
||||
}
|
||||
|
||||
if (charge.isWithdrawalFee()) {
|
||||
if (isOneWithdrawalPresent) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("multiple.withdrawal.fee.per.account.not.supported");
|
||||
}
|
||||
isOneWithdrawalPresent = true;
|
||||
}
|
||||
|
||||
if (charge.isAnnualFee()) {
|
||||
if (isOneAnnualPresent) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("multiple.annual.fee.per.account.not.supported");
|
||||
}
|
||||
isOneAnnualPresent = true;
|
||||
}
|
||||
}
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
}
|
||||
+8
@@ -5,11 +5,19 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.savings.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface SavingsAccountChargeRepository extends JpaRepository<SavingsAccountCharge, Long>,
|
||||
JpaSpecificationExecutor<SavingsAccountCharge> {
|
||||
|
||||
SavingsAccountCharge findByIdAndSavingsAccountId(Long id, Long savingsAccountId);
|
||||
|
||||
@Query("from SavingsAccountCharge sac where sac.dueDate <=:transactionDate and sac.waived = 0 and sac.paid=0 order by sac.dueDate")
|
||||
List<SavingsAccountCharge> findPendingCharges(@Param("transactionDate") Date transactionDate);
|
||||
}
|
||||
|
||||
+11
@@ -5,6 +5,9 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.savings.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.portfolio.charge.exception.SavingsAccountChargeNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -36,11 +39,19 @@ public class SavingsAccountChargeRepositoryWrapper {
|
||||
if (savingsAccountCharge == null) { throw new SavingsAccountChargeNotFoundException(id); }
|
||||
return savingsAccountCharge;
|
||||
}
|
||||
|
||||
public List<SavingsAccountCharge> findPendingCharges(final Date transactionDate){
|
||||
return this.repository.findPendingCharges(transactionDate);
|
||||
}
|
||||
|
||||
public void save(final SavingsAccountCharge savingsAccountCharge) {
|
||||
this.repository.save(savingsAccountCharge);
|
||||
}
|
||||
|
||||
public void save(final Iterable<SavingsAccountCharge> savingsAccountCharges){
|
||||
this.repository.save(savingsAccountCharges);
|
||||
}
|
||||
|
||||
public void saveAndFlush(final SavingsAccountCharge savingsAccountCharge) {
|
||||
this.repository.saveAndFlush(savingsAccountCharge);
|
||||
}
|
||||
|
||||
+20
-12
@@ -7,9 +7,9 @@ package org.mifosplatform.portfolio.savings.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
@@ -49,16 +49,17 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail,
|
||||
final boolean applyWithdrawFee) {
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
final Set<Long> existingTransactionIds = new HashSet<Long>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
|
||||
existingTransactionIds, existingReversedTransactionIds, paymentDetail);
|
||||
paymentDetail);
|
||||
final SavingsAccountTransaction withdrawal = account.withdraw(transactionDTO, applyWithdrawFee);
|
||||
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.postInterest(mc, today, existingTransactionIds, existingReversedTransactionIds);
|
||||
account.postInterest(mc, today);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today);
|
||||
@@ -77,16 +78,17 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
public SavingsAccountTransaction handleDeposit(final SavingsAccount account, final DateTimeFormatter fmt,
|
||||
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail) {
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
final Set<Long> existingTransactionIds = new HashSet<Long>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
|
||||
existingTransactionIds, existingReversedTransactionIds, paymentDetail);
|
||||
paymentDetail);
|
||||
final SavingsAccountTransaction deposit = account.deposit(transactionDTO);
|
||||
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.postInterest(mc, today, existingTransactionIds, existingReversedTransactionIds);
|
||||
account.postInterest(mc, today);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today);
|
||||
@@ -106,8 +108,14 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
|
||||
return transaction.getId();
|
||||
}
|
||||
|
||||
private void postJournalEntries(final SavingsAccount savingsAccount, final List<Long> existingTransactionIds,
|
||||
final List<Long> existingReversedTransactionIds) {
|
||||
private void updateExistingTransactionsDetails(SavingsAccount account, Set<Long> existingTransactionIds,
|
||||
Set<Long> existingReversedTransactionIds) {
|
||||
existingTransactionIds.addAll(account.findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(account.findExistingReversedTransactionIds());
|
||||
}
|
||||
|
||||
private void postJournalEntries(final SavingsAccount savingsAccount, final Set<Long> existingTransactionIds,
|
||||
final Set<Long> existingReversedTransactionIds) {
|
||||
|
||||
final MonetaryCurrency currency = savingsAccount.getCurrency();
|
||||
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency);
|
||||
|
||||
+10
@@ -10,6 +10,7 @@ import java.util.List;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
@@ -49,6 +50,13 @@ public final class SavingsAccountSummary {
|
||||
@Column(name = "account_balance_derived", scale = 6, precision = 19)
|
||||
private BigDecimal accountBalance = BigDecimal.ZERO;
|
||||
|
||||
//TODO: AA do we need this data to be persisted.
|
||||
@Transient
|
||||
private BigDecimal totalFeeChargesWaived = BigDecimal.ZERO;
|
||||
|
||||
@Transient
|
||||
private BigDecimal totalPenaltyChargesWaived = BigDecimal.ZERO;
|
||||
|
||||
protected SavingsAccountSummary() {
|
||||
//
|
||||
}
|
||||
@@ -63,6 +71,8 @@ public final class SavingsAccountSummary {
|
||||
this.totalAnnualFees = wrapper.calculateTotalAnnualFees(currency, transactions);
|
||||
this.totalFeeCharge = wrapper.calculateTotalFeesCharge(currency, transactions);
|
||||
this.totalPenaltyCharge = wrapper.calculateTotalPenaltyCharge(currency, transactions);
|
||||
this.totalFeeChargesWaived = wrapper.calculateTotalFeesChargeWaived(currency, transactions);
|
||||
this.totalPenaltyChargesWaived = wrapper.calculateTotalPenaltyChargeWaived(currency, transactions);
|
||||
|
||||
this.accountBalance = Money.of(currency, this.totalDeposits).plus(this.totalInterestPosted).minus(this.totalWithdrawals)
|
||||
.minus(this.totalWithdrawalFees).minus(this.totalAnnualFees).minus(this.totalFeeCharge).minus(this.totalPenaltyCharge)
|
||||
|
||||
+61
-6
@@ -6,9 +6,11 @@
|
||||
package org.mifosplatform.portfolio.savings.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -114,7 +116,7 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
amount, isReversed);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction fee(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
public static SavingsAccountTransaction withdrawalFee(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
final Money amount) {
|
||||
final boolean isReversed = false;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.WITHDRAWAL_FEE.getValue(), date, amount,
|
||||
@@ -208,6 +210,10 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isWithdrawal();
|
||||
}
|
||||
|
||||
public boolean isPostInterestCalculationRequired(){
|
||||
return this.isDeposit() || this.isWithdrawal() || this.isPayCharge();
|
||||
}
|
||||
|
||||
public boolean isInterestPostingAndNotReversed() {
|
||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isInterestPosting() && isNotReversed();
|
||||
}
|
||||
@@ -215,6 +221,10 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
public boolean isWithdrawalFeeAndNotReversed() {
|
||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isWithdrawalFee() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isWithdrawalFee() {
|
||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isWithdrawalFee();
|
||||
}
|
||||
|
||||
public boolean isAnnualFeeAndNotReversed() {
|
||||
return isAnnualFee() && isNotReversed();
|
||||
@@ -315,6 +325,25 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
thisTransactionData.put("paymentTypeId", this.paymentDetail.getPaymentType().getId());
|
||||
}
|
||||
|
||||
/***
|
||||
* Sending data in a map, though in savings we currently expect a transaction to
|
||||
* always repay a single charge (or may repay a part of a single charge
|
||||
* too)
|
||||
***/
|
||||
if (!this.savingsAccountChargesPaid.isEmpty()) {
|
||||
final List<Map<String, Object>> savingsChargesPaidData = new ArrayList<Map<String, Object>>();
|
||||
for (final SavingsAccountChargePaidBy chargePaidBy : this.savingsAccountChargesPaid) {
|
||||
final Map<String, Object> savingChargePaidData = new LinkedHashMap<String, Object>();
|
||||
savingChargePaidData.put("chargeId", chargePaidBy.getSavingsAccountCharge().getCharge().getId());
|
||||
savingChargePaidData.put("isPenalty", chargePaidBy.getSavingsAccountCharge().getCharge().isPenalty());
|
||||
savingChargePaidData.put("savingsChargeId", chargePaidBy.getSavingsAccountCharge().getId());
|
||||
savingChargePaidData.put("amount", chargePaidBy.getAmount());
|
||||
|
||||
savingsChargesPaidData.add(savingChargePaidData);
|
||||
}
|
||||
thisTransactionData.put("savingsChargesPaid", savingsChargesPaidData);
|
||||
}
|
||||
|
||||
return thisTransactionData;
|
||||
}
|
||||
|
||||
@@ -431,21 +460,29 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public boolean isDebit() {
|
||||
return isWithdrawal() || isWithdrawalFeeAndNotReversed() || isAnnualFeeAndNotReversed() || isCharge();
|
||||
return isWithdrawal() || isWithdrawalFeeAndNotReversed() || isAnnualFeeAndNotReversed() || isPayCharge();
|
||||
}
|
||||
|
||||
public boolean isCharge() {
|
||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isCharge();
|
||||
public boolean isPayCharge() {
|
||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isPayCharge();
|
||||
}
|
||||
|
||||
public boolean isChargeTransaction(){
|
||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isChargeTransaction();
|
||||
}
|
||||
|
||||
public boolean isWaiveCharge(){
|
||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isWaiveCharge();
|
||||
}
|
||||
|
||||
public boolean isFeeCharge() {
|
||||
final SavingsAccountChargePaidBy chargePaidBy = getSavingsAccountChargePaidBy();
|
||||
return (isCharge() && chargePaidBy != null) ? chargePaidBy.isFeeCharge() : false;
|
||||
return (isPayCharge() && chargePaidBy != null) ? chargePaidBy.isFeeCharge() : false;
|
||||
}
|
||||
|
||||
public boolean isPenaltyCharge() {
|
||||
final SavingsAccountChargePaidBy chargePaidBy = getSavingsAccountChargePaidBy();
|
||||
return (isCharge() && chargePaidBy != null) ? chargePaidBy.isPenaltyCharge() : false;
|
||||
return (isPayCharge() && chargePaidBy != null) ? chargePaidBy.isPenaltyCharge() : false;
|
||||
}
|
||||
|
||||
public boolean isFeeChargeAndNotReversed() {
|
||||
@@ -456,6 +493,24 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
return isPenaltyCharge() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isWaiveFeeCharge() {
|
||||
final SavingsAccountChargePaidBy chargePaidBy = getSavingsAccountChargePaidBy();
|
||||
return (isWaiveCharge() && chargePaidBy != null) ? chargePaidBy.isFeeCharge() : false;
|
||||
}
|
||||
|
||||
public boolean isWaivePenaltyCharge() {
|
||||
final SavingsAccountChargePaidBy chargePaidBy = getSavingsAccountChargePaidBy();
|
||||
return (isWaiveCharge() && chargePaidBy != null) ? chargePaidBy.isPenaltyCharge() : false;
|
||||
}
|
||||
|
||||
public boolean isWaiveFeeChargeAndNotReversed() {
|
||||
return isWaiveFeeCharge() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isWaivePenaltyChargeAndNotReversed() {
|
||||
return isWaivePenaltyCharge() && isNotReversed();
|
||||
}
|
||||
|
||||
private SavingsAccountChargePaidBy getSavingsAccountChargePaidBy() {
|
||||
if (!CollectionUtils.isEmpty(this.savingsAccountChargesPaid)) { return this.savingsAccountChargesPaid.iterator().next(); }
|
||||
return null;
|
||||
|
||||
+22
-2
@@ -72,17 +72,37 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
public BigDecimal calculateTotalFeesCharge(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
if (transaction.isFeeChargeAndNotReversed() && transaction.isNotReversed()) {
|
||||
if (transaction.isFeeChargeAndNotReversed()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
return total.getAmountDefaultedToNullIfZero();
|
||||
}
|
||||
|
||||
public BigDecimal calculateTotalFeesChargeWaived(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
if (transaction.isWaiveFeeChargeAndNotReversed()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
return total.getAmountDefaultedToNullIfZero();
|
||||
}
|
||||
|
||||
public BigDecimal calculateTotalPenaltyCharge(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
if (transaction.isPenaltyChargeAndNotReversed() && transaction.isNotReversed()) {
|
||||
if (transaction.isPenaltyChargeAndNotReversed()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
return total.getAmountDefaultedToNullIfZero();
|
||||
}
|
||||
|
||||
public BigDecimal calculateTotalPenaltyChargeWaived(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
if (transaction.isWaivePenaltyChargeAndNotReversed()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
|
||||
+39
-93
@@ -7,8 +7,6 @@ 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.annualFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeOnMonthDayParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargesParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.currencyCodeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.descriptionParamName;
|
||||
@@ -24,9 +22,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.withdrawalFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeTypeParamName;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
@@ -44,7 +40,6 @@ import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.accounting.common.AccountingRuleType;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
@@ -58,7 +53,6 @@ import org.mifosplatform.portfolio.savings.SavingsInterestCalculationDaysInYearT
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPeriodFrequencyType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsWithdrawalFeesType;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
@@ -123,24 +117,9 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
@Column(name = "accounting_type", nullable = false)
|
||||
private Integer accountingRule;
|
||||
|
||||
@Column(name = "withdrawal_fee_amount", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal withdrawalFeeAmount;
|
||||
|
||||
@Column(name = "withdrawal_fee_type_enum", nullable = true)
|
||||
private Integer withdrawalFeeType;
|
||||
|
||||
@Column(name = "withdrawal_fee_for_transfer")
|
||||
private boolean withdrawalFeeApplicableForTransfer;
|
||||
|
||||
@Column(name = "annual_fee_amount", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal annualFeeAmount;
|
||||
|
||||
@Column(name = "annual_fee_on_month", nullable = true)
|
||||
private Integer annualFeeOnMonth;
|
||||
|
||||
@Column(name = "annual_fee_on_day", nullable = true)
|
||||
private Integer annualFeeOnDay;
|
||||
|
||||
@ManyToMany
|
||||
@JoinTable(name = "m_savings_product_charge", joinColumns = @JoinColumn(name = "savings_product_id"), inverseJoinColumns = @JoinColumn(name = "charge_id"))
|
||||
private Set<Charge> charges;
|
||||
@@ -150,14 +129,11 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
|
||||
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
|
||||
final BigDecimal withdrawalFeeAmount, final SavingsWithdrawalFeesType withdrawalFeeType,
|
||||
final boolean withdrawalFeeApplicableForTransfer, final BigDecimal annualFeeAmount, final MonthDay annualFeeOnMonthDay,
|
||||
final AccountingRuleType accountingRuleType, final Set<Charge> charges) {
|
||||
final boolean withdrawalFeeApplicableForTransfer, final AccountingRuleType accountingRuleType, final Set<Charge> charges) {
|
||||
|
||||
return new SavingsProduct(name, description, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType,
|
||||
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, withdrawalFeeApplicableForTransfer, annualFeeAmount,
|
||||
annualFeeOnMonthDay, accountingRuleType, charges);
|
||||
lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, accountingRuleType, charges);
|
||||
}
|
||||
|
||||
protected SavingsProduct() {
|
||||
@@ -170,9 +146,7 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
|
||||
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
|
||||
final BigDecimal withdrawalFeeAmount, final SavingsWithdrawalFeesType withdrawalFeeType,
|
||||
final boolean withdrawalFeeApplicableForTransfer, final BigDecimal annualFeeAmount, final MonthDay annualFeeOnMonthDay,
|
||||
final AccountingRuleType accountingRuleType, final Set<Charge> charges) {
|
||||
final boolean withdrawalFeeApplicableForTransfer, final AccountingRuleType accountingRuleType, final Set<Charge> charges) {
|
||||
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
@@ -192,17 +166,13 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
if (lockinPeriodFrequency != null && lockinPeriodFrequencyType != null) {
|
||||
this.lockinPeriodFrequencyType = lockinPeriodFrequencyType.getValue();
|
||||
}
|
||||
|
||||
this.withdrawalFeeAmount = withdrawalFeeAmount;
|
||||
if (withdrawalFeeAmount != null && withdrawalFeeType != null) {
|
||||
this.withdrawalFeeType = withdrawalFeeType.getValue();
|
||||
}
|
||||
|
||||
this.withdrawalFeeApplicableForTransfer = withdrawalFeeApplicableForTransfer;
|
||||
this.annualFeeAmount = annualFeeAmount;
|
||||
/* this.annualFeeAmount = annualFeeAmount;
|
||||
if (annualFeeAmount != null && annualFeeOnMonthDay != null) {
|
||||
this.annualFeeOnMonth = annualFeeOnMonthDay.getMonthOfYear();
|
||||
this.annualFeeOnDay = annualFeeOnMonthDay.getDayOfMonth();
|
||||
}
|
||||
}*/
|
||||
|
||||
if (accountingRuleType != null) {
|
||||
this.accountingRule = accountingRuleType.getValue();
|
||||
@@ -213,8 +183,8 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
validateLockinDetails();
|
||||
validateWithdrawalFeeDetails();
|
||||
validateAnnualFeeDetails();
|
||||
//validateWithdrawalFeeDetails();
|
||||
//validateAnnualFeeDetails();
|
||||
}
|
||||
|
||||
public MonetaryCurrency currency() {
|
||||
@@ -257,30 +227,6 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
return type;
|
||||
}
|
||||
|
||||
public BigDecimal withdrawalFeeAmount() {
|
||||
return this.withdrawalFeeAmount;
|
||||
}
|
||||
|
||||
public SavingsWithdrawalFeesType withdrawalFeeType() {
|
||||
SavingsWithdrawalFeesType type = null;
|
||||
if (this.withdrawalFeeType != null) {
|
||||
type = SavingsWithdrawalFeesType.fromInt(this.withdrawalFeeType);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
public BigDecimal annualFeeAmount() {
|
||||
return this.annualFeeAmount;
|
||||
}
|
||||
|
||||
public MonthDay monthDayOfAnnualFee() {
|
||||
MonthDay monthDay = null;
|
||||
if (this.annualFeeOnMonth != null && this.annualFeeOnDay != null) {
|
||||
monthDay = new MonthDay(this.annualFeeOnMonth, this.annualFeeOnDay);
|
||||
}
|
||||
return monthDay;
|
||||
}
|
||||
|
||||
public Map<String, Object> update(final JsonCommand command) {
|
||||
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(10);
|
||||
@@ -382,7 +328,7 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
if (this.lockinPeriodFrequency == null) {
|
||||
this.lockinPeriodFrequencyType = null;
|
||||
}
|
||||
|
||||
/*
|
||||
if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(withdrawalFeeAmountParamName, this.withdrawalFeeAmount)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(withdrawalFeeAmountParamName);
|
||||
actualChanges.put(withdrawalFeeAmountParamName, newValue);
|
||||
@@ -395,7 +341,7 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
actualChanges.put(withdrawalFeeTypeParamName, newValue);
|
||||
this.withdrawalFeeType = newValue != null ? SavingsWithdrawalFeesType.fromInt(newValue).getValue() : newValue;
|
||||
}
|
||||
|
||||
*/
|
||||
if (command.isChangeInBooleanParameterNamed(withdrawalFeeForTransfersParamName, this.withdrawalFeeApplicableForTransfer)) {
|
||||
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(withdrawalFeeForTransfersParamName);
|
||||
actualChanges.put(withdrawalFeeForTransfersParamName, newValue);
|
||||
@@ -403,40 +349,40 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
// set period type to null if frequency is null
|
||||
if (this.withdrawalFeeAmount == null) {
|
||||
this.withdrawalFeeType = null;
|
||||
}
|
||||
// if (this.withdrawalFeeAmount == null) {
|
||||
// this.withdrawalFeeType = null;
|
||||
// }
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(annualFeeAmountParamName, this.annualFeeAmount)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(annualFeeAmountParamName);
|
||||
actualChanges.put(annualFeeAmountParamName, newValue);
|
||||
/* if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(feeAmountParamName, this.annualFeeAmount)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(feeAmountParamName);
|
||||
actualChanges.put(feeAmountParamName, newValue);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.annualFeeAmount = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamedDefaultingZeroToNull(annualFeeOnMonthDayParamName, this.annualFeeOnDay)) {
|
||||
final MonthDay monthDay = command.extractMonthDayNamed(annualFeeOnMonthDayParamName);
|
||||
final String actualValueEntered = command.stringValueOfParameterNamed(annualFeeOnMonthDayParamName);
|
||||
if (command.isChangeInIntegerParameterNamedDefaultingZeroToNull(feeOnMonthDayParamName, this.annualFeeOnDay)) {
|
||||
final MonthDay monthDay = command.extractMonthDayNamed(feeOnMonthDayParamName);
|
||||
final String actualValueEntered = command.stringValueOfParameterNamed(feeOnMonthDayParamName);
|
||||
final Integer newValue = monthDay != null ? monthDay.getDayOfMonth() : null;
|
||||
actualChanges.put(annualFeeOnMonthDayParamName, actualValueEntered);
|
||||
actualChanges.put(feeOnMonthDayParamName, actualValueEntered);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.annualFeeOnDay = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamedDefaultingZeroToNull(annualFeeOnMonthDayParamName, this.annualFeeOnMonth)) {
|
||||
final MonthDay monthDay = command.extractMonthDayNamed(annualFeeOnMonthDayParamName);
|
||||
final String actualValueEntered = command.stringValueOfParameterNamed(annualFeeOnMonthDayParamName);
|
||||
if (command.isChangeInIntegerParameterNamedDefaultingZeroToNull(feeOnMonthDayParamName, this.annualFeeOnMonth)) {
|
||||
final MonthDay monthDay = command.extractMonthDayNamed(feeOnMonthDayParamName);
|
||||
final String actualValueEntered = command.stringValueOfParameterNamed(feeOnMonthDayParamName);
|
||||
final Integer newValue = monthDay != null ? monthDay.getMonthOfYear() : null;
|
||||
actualChanges.put(annualFeeOnMonthDayParamName, actualValueEntered);
|
||||
actualChanges.put(feeOnMonthDayParamName, actualValueEntered);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.annualFeeOnMonth = newValue;
|
||||
}
|
||||
}*/
|
||||
|
||||
// set period type to null if frequency is null
|
||||
if (this.annualFeeAmount == null) {
|
||||
this.annualFeeOnDay = null;
|
||||
this.annualFeeOnMonth = null;
|
||||
}
|
||||
// // set period type to null if frequency is null
|
||||
// if (this.annualFeeAmount == null) {
|
||||
// this.annualFeeOnDay = null;
|
||||
// this.annualFeeOnMonth = null;
|
||||
// }
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(accountingRuleParamName, this.accountingRule)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(accountingRuleParamName);
|
||||
@@ -453,13 +399,13 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
validateLockinDetails();
|
||||
validateWithdrawalFeeDetails();
|
||||
validateAnnualFeeDetails();
|
||||
//validateWithdrawalFeeDetails();
|
||||
//validateAnnualFeeDetails();
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
private void validateAnnualFeeDetails() {
|
||||
/* private void validateAnnualFeeDetails() {
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
@@ -468,21 +414,21 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
if (this.annualFeeAmount == null) {
|
||||
|
||||
if (this.annualFeeOnMonth != null || this.annualFeeOnDay != null) {
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(this.annualFeeAmount).notNull();
|
||||
baseDataValidator.reset().parameter(feeAmountParamName).value(this.annualFeeAmount).notNull();
|
||||
}
|
||||
} else {
|
||||
|
||||
if (this.annualFeeOnMonth == null || this.annualFeeOnDay == null) {
|
||||
baseDataValidator.reset().parameter(annualFeeOnMonthDayParamName).value(this.annualFeeOnMonth).notNull();
|
||||
baseDataValidator.reset().parameter(feeOnMonthDayParamName).value(this.annualFeeOnMonth).notNull();
|
||||
}
|
||||
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(this.annualFeeAmount).zeroOrPositiveAmount();
|
||||
baseDataValidator.reset().parameter(feeAmountParamName).value(this.annualFeeAmount).zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
private void validateWithdrawalFeeDetails() {
|
||||
*/
|
||||
/* private void validateWithdrawalFeeDetails() {
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
@@ -503,7 +449,7 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
*/
|
||||
private void validateLockinDetails() {
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
|
||||
+1
-17
@@ -5,8 +5,6 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.savings.domain;
|
||||
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeOnMonthDayParamName;
|
||||
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,15 +20,12 @@ 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.withdrawalFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeTypeParamName;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.accounting.common.AccountingRuleType;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
@@ -43,7 +38,6 @@ import org.mifosplatform.portfolio.savings.SavingsInterestCalculationDaysInYearT
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPeriodFrequencyType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsWithdrawalFeesType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -107,20 +101,11 @@ public class SavingsProductAssembler {
|
||||
lockinPeriodFrequencyType = SavingsPeriodFrequencyType.fromInt(lockinPeriodFrequencyTypeValue);
|
||||
}
|
||||
|
||||
final BigDecimal withdrawalFeeAmount = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(withdrawalFeeAmountParamName);
|
||||
SavingsWithdrawalFeesType withdrawalFeeType = null;
|
||||
final Integer withdrawalFeeTypeValue = command.integerValueOfParameterNamed(withdrawalFeeTypeParamName);
|
||||
if (withdrawalFeeTypeValue != null) {
|
||||
withdrawalFeeType = SavingsWithdrawalFeesType.fromInt(withdrawalFeeTypeValue);
|
||||
}
|
||||
|
||||
boolean iswithdrawalFeeApplicableForTransfer = false;
|
||||
if (command.parameterExists(withdrawalFeeForTransfersParamName)) {
|
||||
iswithdrawalFeeApplicableForTransfer = command.booleanPrimitiveValueOfParameterNamed(withdrawalFeeForTransfersParamName);
|
||||
}
|
||||
|
||||
final BigDecimal annualFeeAmount = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(annualFeeAmountParamName);
|
||||
final MonthDay monthDayOfAnnualFee = command.extractMonthDayNamed(annualFeeOnMonthDayParamName);
|
||||
final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(command.integerValueOfParameterNamed("accountingRule"));
|
||||
|
||||
// Savings product charges
|
||||
@@ -128,8 +113,7 @@ public class SavingsProductAssembler {
|
||||
|
||||
return SavingsProduct.createNew(name, description, currency, interestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType,
|
||||
iswithdrawalFeeApplicableForTransfer, annualFeeAmount, monthDayOfAnnualFee, accountingRuleType, charges);
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, iswithdrawalFeeApplicableForTransfer, accountingRuleType, charges);
|
||||
}
|
||||
|
||||
public Set<Charge> assembleListOfSavingsProductCharges(final JsonCommand command, final String savingsProductCurrencyCode) {
|
||||
|
||||
+6
-3
@@ -11,6 +11,7 @@ import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargeIdPa
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargeTimeTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargesParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.feeOnMonthDayParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.idParamName;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@@ -19,6 +20,7 @@ import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.portfolio.charge.domain.Charge;
|
||||
import org.mifosplatform.portfolio.charge.domain.ChargeCalculationType;
|
||||
@@ -70,7 +72,8 @@ public class SavingsProductChargeAssembler {
|
||||
savingsChargeElement, locale);
|
||||
final LocalDate dueDate = this.fromApiJsonHelper.extractLocalDateNamed(dueAsOfDateParamName, savingsChargeElement,
|
||||
dateFormat, locale);
|
||||
|
||||
final MonthDay feeOnMonthDay = this.fromApiJsonHelper.extractMonthDayNamed(feeOnMonthDayParamName, savingsChargeElement);
|
||||
|
||||
if (id == null) {
|
||||
final Charge chargeDefinition = this.chargeRepository.findOneWithNotFoundDetection(chargeId);
|
||||
final ChargeTimeType chargeTime = null;
|
||||
@@ -82,7 +85,7 @@ public class SavingsProductChargeAssembler {
|
||||
ChargeCalculationType.fromInt(chargeCalculationType);
|
||||
}
|
||||
final SavingsAccountCharge savingsAccountCharge = SavingsAccountCharge.createNewWithoutSavingsAccount(
|
||||
chargeDefinition, amount, chargeTime, chargeCalculation, dueDate);
|
||||
chargeDefinition, amount, chargeTime, chargeCalculation, dueDate, true, feeOnMonthDay);
|
||||
savingsAccountCharges.add(savingsAccountCharge);
|
||||
} else {
|
||||
final Long savingsAccountChargeId = id;
|
||||
@@ -90,7 +93,7 @@ public class SavingsProductChargeAssembler {
|
||||
.findOne(savingsAccountChargeId);
|
||||
if (savingsAccountCharge == null) { throw new SavingsAccountChargeNotFoundException(savingsAccountChargeId); }
|
||||
|
||||
savingsAccountCharge.update(amount, dueDate);
|
||||
savingsAccountCharge.update(amount, dueDate, null);
|
||||
|
||||
savingsAccountCharges.add(savingsAccountCharge);
|
||||
}
|
||||
|
||||
+4
-1
@@ -17,6 +17,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
@Service
|
||||
public class ApplyAnnualFeeSavingsAccountCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final SavingsAccountWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
@@ -28,8 +29,10 @@ public class ApplyAnnualFeeSavingsAccountCommandHandler implements NewCommandSou
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
final LocalDate annualFeeTransactionDate = command.localDateValueOfParameterNamed("annualFeeTransactionDate");
|
||||
|
||||
return this.writePlatformService.applyAnnualFee(command.getSavingsId(), annualFeeTransactionDate);
|
||||
//return this.writePlatformService.applyAnnualFee(command.getSavingsId(), annualFeeTransactionDate);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -27,6 +27,6 @@ public class WaiveSavingsAccountChargeCommandHandler implements NewCommandSource
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.writePlatformService.waiveCharge(command.getSavingsId(), command.entityId(), command);
|
||||
return this.writePlatformService.waiveCharge(command.getSavingsId(), command.entityId());
|
||||
}
|
||||
}
|
||||
+23
-5
@@ -12,6 +12,7 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||
@@ -55,7 +56,9 @@ public class SavingsAccountChargeReadPlatformServiceImpl implements SavingsAccou
|
||||
+ "sc.calculation_percentage as percentageOf, sc.calculation_on_amount as amountPercentageAppliedTo, "
|
||||
+ "sc.charge_time_enum as chargeTime, "
|
||||
+ "sc.is_penalty as penalty, "
|
||||
+ "sc.due_for_collection_as_of_date as dueAsOfDate, "
|
||||
+ "sc.charge_due_date as dueAsOfDate, "
|
||||
+ "sc.fee_on_month as feeOnMonth, "
|
||||
+ "sc.fee_on_day as feeOnDay, "
|
||||
+ "sc.charge_calculation_enum as chargeCalculation, "
|
||||
+ "c.currency_code as currencyCode, oc.name as currencyName, "
|
||||
+ "oc.decimal_places as currencyDecimalPlaces, oc.currency_multiplesof as inMultiplesOf, oc.display_symbol as currencyDisplaySymbol, "
|
||||
@@ -93,7 +96,13 @@ public class SavingsAccountChargeReadPlatformServiceImpl implements SavingsAccou
|
||||
final EnumOptionData chargeTimeType = ChargeEnumerations.chargeTimeType(chargeTime);
|
||||
|
||||
final LocalDate dueAsOfDate = JdbcSupport.getLocalDate(rs, "dueAsOfDate");
|
||||
|
||||
MonthDay feeOnMonthDay = null;
|
||||
final Integer feeOnMonth = JdbcSupport.getInteger(rs, "feeOnMonth");
|
||||
final Integer feeOnDay = JdbcSupport.getInteger(rs, "feeOnDay");
|
||||
if (feeOnDay != null) {
|
||||
feeOnMonthDay = new MonthDay(feeOnMonth, feeOnDay);
|
||||
}
|
||||
|
||||
final int chargeCalculation = rs.getInt("chargeCalculation");
|
||||
final EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(chargeCalculation);
|
||||
final boolean penalty = rs.getBoolean("penalty");
|
||||
@@ -102,7 +111,7 @@ public class SavingsAccountChargeReadPlatformServiceImpl implements SavingsAccou
|
||||
|
||||
return SavingsAccountChargeData.instance(id, chargeId, name, currency, amount, amountPaid, amountWaived, amountWrittenOff,
|
||||
amountOutstanding, chargeTimeType, dueAsOfDate, chargeCalculationType, percentageOf, amountPercentageAppliedTo,
|
||||
chargeOptions, penalty);
|
||||
chargeOptions, penalty, feeOnMonthDay);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,9 +121,18 @@ public class SavingsAccountChargeReadPlatformServiceImpl implements SavingsAccou
|
||||
|
||||
final List<EnumOptionData> allowedChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService.retrieveCalculationTypes();
|
||||
final List<EnumOptionData> allowedChargeTimeOptions = this.chargeDropdownReadPlatformService.retrieveCollectionTimeTypes();
|
||||
final List<EnumOptionData> loansChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService
|
||||
.retrieveLoanCalculationTypes();
|
||||
final List<EnumOptionData> loansChargeTimeTypeOptions = this.chargeDropdownReadPlatformService.retrieveLoanCollectionTimeTypes();
|
||||
final List<EnumOptionData> savingsChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService
|
||||
.retrieveSavingsCalculationTypes();
|
||||
final List<EnumOptionData> savingsChargeTimeTypeOptions = this.chargeDropdownReadPlatformService
|
||||
.retrieveSavingsCollectionTimeTypes();
|
||||
|
||||
// TODO AA : revisit for merge conflict - Not sure method signature
|
||||
return ChargeData.template(null, allowedChargeCalculationTypeOptions, null, allowedChargeTimeOptions, null);
|
||||
return ChargeData.template(null, allowedChargeCalculationTypeOptions, null, allowedChargeTimeOptions, null,
|
||||
loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions, savingsChargeCalculationTypeOptions,
|
||||
savingsChargeTimeTypeOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -139,7 +157,7 @@ public class SavingsAccountChargeReadPlatformServiceImpl implements SavingsAccou
|
||||
final SavingsAccountChargeMapper rm = new SavingsAccountChargeMapper();
|
||||
|
||||
final String sql = "select " + rm.schema() + " where sc.savings_account_id=? "
|
||||
+ " order by sc.charge_time_enum ASC, sc.due_for_collection_as_of_date ASC, sc.is_penalty ASC";
|
||||
+ " order by sc.charge_time_enum ASC, sc.charge_due_date ASC, sc.is_penalty ASC";
|
||||
|
||||
return this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
|
||||
}
|
||||
|
||||
+1
-2
@@ -9,7 +9,6 @@ import java.util.Collection;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.service.Page;
|
||||
import org.mifosplatform.portfolio.group.service.SearchParameters;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountAnnualFeeData;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountData;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionData;
|
||||
|
||||
@@ -27,7 +26,7 @@ public interface SavingsAccountReadPlatformService {
|
||||
|
||||
Collection<SavingsAccountTransactionData> retrieveAllTransactions(Long savingsId);
|
||||
|
||||
Collection<SavingsAccountAnnualFeeData> retrieveAccountsWithAnnualFeeDue();
|
||||
//Collection<SavingsAccountAnnualFeeData> retrieveAccountsWithAnnualFeeDue();
|
||||
|
||||
SavingsAccountTransactionData retrieveSavingsTransaction(Long savingsId, Long transactionId);
|
||||
}
|
||||
+31
-35
@@ -14,7 +14,6 @@ import java.util.Collection;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||
@@ -40,7 +39,6 @@ import org.mifosplatform.portfolio.savings.SavingsInterestCalculationDaysInYearT
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPeriodFrequencyType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountAnnualFeeData;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountApplicationTimelineData;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountChargeData;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountData;
|
||||
@@ -74,7 +72,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
private final SavingsAccountTransactionTemplateMapper transactionTemplateMapper;
|
||||
private final SavingsAccountTransactionsMapper transactionsMapper;
|
||||
private final SavingAccountMapper savingAccountMapper;
|
||||
private final SavingsAccountAnnualFeeMapper annualFeeMapper;
|
||||
//private final SavingsAccountAnnualFeeMapper annualFeeMapper;
|
||||
|
||||
// pagination
|
||||
private final PaginationHelper<SavingsAccountData> paginationHelper = new PaginationHelper<SavingsAccountData>();
|
||||
@@ -95,7 +93,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
this.transactionTemplateMapper = new SavingsAccountTransactionTemplateMapper();
|
||||
this.transactionsMapper = new SavingsAccountTransactionsMapper();
|
||||
this.savingAccountMapper = new SavingAccountMapper();
|
||||
this.annualFeeMapper = new SavingsAccountAnnualFeeMapper();
|
||||
//this.annualFeeMapper = new SavingsAccountAnnualFeeMapper();
|
||||
this.chargeReadPlatformService = chargeReadPlatformService;
|
||||
}
|
||||
|
||||
@@ -222,13 +220,13 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
sqlBuilder.append("sa.min_required_opening_balance as minRequiredOpeningBalance, ");
|
||||
sqlBuilder.append("sa.lockin_period_frequency as lockinPeriodFrequency,");
|
||||
sqlBuilder.append("sa.lockin_period_frequency_enum as lockinPeriodFrequencyType, ");
|
||||
sqlBuilder.append("sa.withdrawal_fee_amount as withdrawalFeeAmount,");
|
||||
sqlBuilder.append("sa.withdrawal_fee_type_enum as withdrawalFeeTypeEnum, ");
|
||||
// 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.annual_fee_amount as annualFeeAmount,");
|
||||
sqlBuilder.append("sa.annual_fee_on_month as annualFeeOnMonth, ");
|
||||
sqlBuilder.append("sa.annual_fee_on_day as annualFeeOnDay, ");
|
||||
sqlBuilder.append("sa.annual_fee_next_due_date as annualFeeNextDueDate, ");
|
||||
// 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, ");
|
||||
// sqlBuilder.append("sa.annual_fee_next_due_date as annualFeeNextDueDate, ");
|
||||
sqlBuilder.append("sa.total_deposits_derived as totalDeposits, ");
|
||||
sqlBuilder.append("sa.total_withdrawals_derived as totalWithdrawals, ");
|
||||
sqlBuilder.append("sa.total_withdrawal_fees_derived as totalWithdrawalFees, ");
|
||||
@@ -351,17 +349,17 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
lockinPeriodFrequencyType = SavingsEnumerations.lockinPeriodFrequencyType(lockinPeriodType);
|
||||
}
|
||||
|
||||
final BigDecimal withdrawalFeeAmount = rs.getBigDecimal("withdrawalFeeAmount");
|
||||
/*final BigDecimal withdrawalFeeAmount = rs.getBigDecimal("withdrawalFeeAmount");
|
||||
|
||||
EnumOptionData withdrawalFeeType = null;
|
||||
final Integer withdrawalFeeTypeValue = JdbcSupport.getInteger(rs, "withdrawalFeeTypeEnum");
|
||||
if (withdrawalFeeTypeValue != null) {
|
||||
withdrawalFeeType = SavingsEnumerations.withdrawalFeeType(withdrawalFeeTypeValue);
|
||||
}
|
||||
}*/
|
||||
|
||||
final boolean withdrawalFeeForTransfers = rs.getBoolean("withdrawalFeeForTransfers");
|
||||
|
||||
final BigDecimal annualFeeAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "annualFeeAmount");
|
||||
/*final BigDecimal annualFeeAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "annualFeeAmount");
|
||||
|
||||
MonthDay annualFeeOnMonthDay = null;
|
||||
final Integer annualFeeOnMonth = JdbcSupport.getInteger(rs, "annualFeeOnMonth");
|
||||
@@ -371,7 +369,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
}
|
||||
|
||||
final LocalDate annualFeeNextDueDate = JdbcSupport.getLocalDate(rs, "annualFeeNextDueDate");
|
||||
|
||||
*/
|
||||
final BigDecimal totalDeposits = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalDeposits");
|
||||
final BigDecimal totalWithdrawals = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalWithdrawals");
|
||||
final BigDecimal totalWithdrawalFees = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalWithdrawalFees");
|
||||
@@ -390,8 +388,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, withdrawalFeeAmount, withdrawalFeeType, withdrawalFeeForTransfers,
|
||||
annualFeeAmount, annualFeeOnMonthDay, annualFeeNextDueDate, summary);
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,13 +551,13 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
return this.jdbcTemplate.queryForObject(sql, this.transactionsMapper, new Object[] { savingsId, transactionId });
|
||||
}
|
||||
|
||||
@Override
|
||||
/*@Override
|
||||
public Collection<SavingsAccountAnnualFeeData> retrieveAccountsWithAnnualFeeDue() {
|
||||
final String sql = "select " + this.annualFeeMapper.schema()
|
||||
+ " where sa.annual_fee_next_due_date is not null and sa.annual_fee_next_due_date <= NOW()";
|
||||
|
||||
return this.jdbcTemplate.query(sql, this.annualFeeMapper, new Object[] {});
|
||||
}
|
||||
}*/
|
||||
|
||||
private static final class SavingsAccountTransactionsMapper implements RowMapper<SavingsAccountTransactionData> {
|
||||
|
||||
@@ -732,12 +729,12 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
sqlBuilder.append("sp.min_required_opening_balance as minRequiredOpeningBalance, ");
|
||||
sqlBuilder.append("sp.lockin_period_frequency as lockinPeriodFrequency,");
|
||||
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.annual_fee_amount as annualFeeAmount,");
|
||||
sqlBuilder.append("sp.annual_fee_on_month as annualFeeOnMonth, ");
|
||||
sqlBuilder.append("sp.annual_fee_on_day as annualFeeOnDay ");
|
||||
// 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.annual_fee_amount as annualFeeAmount,");
|
||||
// sqlBuilder.append("sp.annual_fee_on_month as annualFeeOnMonth, ");
|
||||
// sqlBuilder.append("sp.annual_fee_on_day as annualFeeOnDay ");
|
||||
sqlBuilder.append("from m_savings_product sp ");
|
||||
sqlBuilder.append("join m_currency curr on curr.code = sp.currency_code ");
|
||||
|
||||
@@ -789,24 +786,24 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
lockinPeriodFrequencyType = SavingsEnumerations.lockinPeriodFrequencyType(lockinPeriodType);
|
||||
}
|
||||
|
||||
final BigDecimal withdrawalFeeAmount = rs.getBigDecimal("withdrawalFeeAmount");
|
||||
// final BigDecimal withdrawalFeeAmount = rs.getBigDecimal("withdrawalFeeAmount");
|
||||
|
||||
EnumOptionData withdrawalFeeType = null;
|
||||
/* EnumOptionData withdrawalFeeType = null;
|
||||
final Integer withdrawalFeeTypeValue = JdbcSupport.getInteger(rs, "withdrawalFeeTypeEnum");
|
||||
if (withdrawalFeeTypeValue != null) {
|
||||
withdrawalFeeType = SavingsEnumerations.withdrawalFeeType(withdrawalFeeTypeValue);
|
||||
}
|
||||
|
||||
*/
|
||||
final boolean withdrawalFeeForTransfers = rs.getBoolean("withdrawalFeeForTransfers");
|
||||
|
||||
final BigDecimal annualFeeAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "annualFeeAmount");
|
||||
//final BigDecimal annualFeeAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "annualFeeAmount");
|
||||
|
||||
MonthDay annualFeeOnMonthDay = null;
|
||||
/*MonthDay annualFeeOnMonthDay = null;
|
||||
final Integer annualFeeOnMonth = JdbcSupport.getInteger(rs, "annualFeeOnMonth");
|
||||
final Integer annualFeeOnDay = JdbcSupport.getInteger(rs, "annualFeeOnDay");
|
||||
if (annualFeeAmount != null && annualFeeOnDay != null) {
|
||||
annualFeeOnMonthDay = new MonthDay(annualFeeOnMonth, annualFeeOnDay);
|
||||
}
|
||||
}*/
|
||||
|
||||
Long clientId = null;
|
||||
String clientName = null;
|
||||
@@ -825,7 +822,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
final Long fieldOfficerId = null;
|
||||
final String fieldOfficerName = null;
|
||||
final SavingsAccountStatusEnumData status = null;
|
||||
final LocalDate annualFeeNextDueDate = null;
|
||||
// final LocalDate annualFeeNextDueDate = null;
|
||||
final SavingsAccountSummaryData summary = null;
|
||||
|
||||
final SavingsAccountApplicationTimelineData timeline = SavingsAccountApplicationTimelineData.templateDefault();
|
||||
@@ -833,12 +830,11 @@ 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, withdrawalFeeAmount, withdrawalFeeType, withdrawalFeeForTransfers,
|
||||
annualFeeAmount, annualFeeOnMonthDay, annualFeeNextDueDate, summary);
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class SavingsAccountAnnualFeeMapper implements RowMapper<SavingsAccountAnnualFeeData> {
|
||||
/*private static final class SavingsAccountAnnualFeeMapper implements RowMapper<SavingsAccountAnnualFeeData> {
|
||||
|
||||
private final String schemaSql;
|
||||
|
||||
@@ -864,5 +860,5 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
|
||||
return SavingsAccountAnnualFeeData.instance(id, accountNo, annualFeeNextDueDate);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
+4
-2
@@ -20,7 +20,7 @@ public interface SavingsAccountWritePlatformService {
|
||||
|
||||
CommandProcessingResult withdrawal(Long savingsId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult applyAnnualFee(Long savingsId, LocalDate annualFeeTransactionDate);
|
||||
/*CommandProcessingResult applyAnnualFee(Long savingsId, LocalDate annualFeeTransactionDate);*/
|
||||
|
||||
CommandProcessingResult calculateInterest(Long savingsId);
|
||||
|
||||
@@ -48,7 +48,9 @@ public interface SavingsAccountWritePlatformService {
|
||||
|
||||
CommandProcessingResult deleteSavingsAccountCharge(Long savingsAccountId, Long savingsAccountChargeId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult waiveCharge(Long savingsAccountId, Long savingsAccountChargeId, JsonCommand command);
|
||||
CommandProcessingResult waiveCharge(Long savingsAccountId, Long savingsAccountChargeId);
|
||||
|
||||
CommandProcessingResult payCharge(Long savingsAccountId, Long savingsAccountChargeId, JsonCommand command);
|
||||
|
||||
void processDueCharges();
|
||||
}
|
||||
+250
-93
@@ -8,15 +8,18 @@ package org.mifosplatform.portfolio.savings.service;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.amountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargeIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
@@ -34,11 +37,13 @@ import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.infrastructure.jobs.annotation.CronTarget;
|
||||
import org.mifosplatform.infrastructure.jobs.service.JobName;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.organisation.holiday.service.HolidayWritePlatformService;
|
||||
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.office.domain.Office;
|
||||
import org.mifosplatform.organisation.staff.domain.Staff;
|
||||
import org.mifosplatform.organisation.workingdays.service.WorkingDaysWritePlatformService;
|
||||
import org.mifosplatform.portfolio.account.PortfolioAccountType;
|
||||
import org.mifosplatform.portfolio.account.service.AccountAssociationsReadPlatformService;
|
||||
import org.mifosplatform.portfolio.account.service.AccountTransfersReadPlatformService;
|
||||
@@ -52,6 +57,7 @@ import org.mifosplatform.portfolio.note.domain.Note;
|
||||
import org.mifosplatform.portfolio.note.domain.NoteRepository;
|
||||
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.mifosplatform.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
|
||||
import org.mifosplatform.portfolio.savings.SavingsAccountTransactionType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsApiConstants;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountChargeDataValidator;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionDTO;
|
||||
@@ -91,6 +97,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
private final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService;
|
||||
private final ChargeRepositoryWrapper chargeRepository;
|
||||
private final SavingsAccountChargeRepositoryWrapper savingsAccountChargeRepository;
|
||||
private final HolidayWritePlatformService holidayWritePlatformService;
|
||||
private final WorkingDaysWritePlatformService workingDaysWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||
@@ -105,7 +113,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final SavingsAccountDomainService savingsAccountDomainService, final NoteRepository noteRepository,
|
||||
final AccountTransfersReadPlatformService accountTransfersReadPlatformService,
|
||||
final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService,
|
||||
final ChargeRepositoryWrapper chargeRepository, final SavingsAccountChargeRepositoryWrapper savingsAccountChargeRepository) {
|
||||
final ChargeRepositoryWrapper chargeRepository, final SavingsAccountChargeRepositoryWrapper savingsAccountChargeRepository,
|
||||
final HolidayWritePlatformService holidayWritePlatformService,
|
||||
final WorkingDaysWritePlatformService workingDaysWritePlatformService) {
|
||||
this.context = context;
|
||||
this.savingAccountRepository = savingAccountRepository;
|
||||
this.savingsAccountTransactionRepository = savingsAccountTransactionRepository;
|
||||
@@ -121,6 +131,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
this.accountAssociationsReadPlatformService = accountAssociationsReadPlatformService;
|
||||
this.chargeRepository = chargeRepository;
|
||||
this.savingsAccountChargeRepository = savingsAccountChargeRepository;
|
||||
this.holidayWritePlatformService = holidayWritePlatformService;
|
||||
this.workingDaysWritePlatformService = workingDaysWritePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -134,12 +146,24 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
checkClientOrGroupActive(account);
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
final Set<Long> existingTransactionIds = new HashSet<Long>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
final Map<String, Object> changes = account.activate(user, command, DateUtils.getLocalDateOfTenant(),
|
||||
existingReversedTransactionIds, existingReversedTransactionIds);
|
||||
final Map<String, Object> changes = account.activate(user, command, DateUtils.getLocalDateOfTenant());
|
||||
if (!changes.isEmpty()) {
|
||||
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (account.isBeforeLastPostingPeriod(account.getActivationLocalDate())) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.postInterest(mc, today);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today);
|
||||
}
|
||||
|
||||
account.validateAccountBalanceDoesNotBecomeNegative(SavingsAccountTransactionType.PAY_CHARGE.name());
|
||||
|
||||
this.savingAccountRepository.save(account);
|
||||
}
|
||||
|
||||
@@ -224,7 +248,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
.build();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
/*@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult applyAnnualFee(final Long savingsId, final LocalDate annualFeeTransactionDate) {
|
||||
|
||||
@@ -233,14 +257,14 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern("dd MM yyyy");
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
final Set<Long> existingTransactionIds = new HashSet<Long>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
|
||||
final SavingsAccountTransaction annualFee = account.addAnnualFee(mc, fmt, annualFeeTransactionDate, today, existingTransactionIds,
|
||||
existingReversedTransactionIds);
|
||||
final SavingsAccountTransaction annualFee = account.addAnnualFee(mc, fmt, annualFeeTransactionDate, today);
|
||||
final Long transactionId = saveTransactionToGenerateTransactionId(annualFee);
|
||||
this.savingAccountRepository.save(account);
|
||||
|
||||
@@ -253,7 +277,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
.withGroupId(account.groupId()) //
|
||||
.withSavingsId(savingsId) //
|
||||
.build();
|
||||
}
|
||||
}*/
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
@@ -296,12 +320,13 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
@Transactional
|
||||
private void postInterest(final SavingsAccount account) {
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
final Set<Long> existingTransactionIds = new HashSet<Long>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
|
||||
|
||||
account.postInterest(mc, today, existingTransactionIds, existingReversedTransactionIds);
|
||||
account.postInterest(mc, today);
|
||||
this.savingAccountRepository.save(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
@@ -322,8 +347,10 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
public CommandProcessingResult undoTransaction(final Long savingsId, final Long transactionId,
|
||||
final boolean allowAccountTransferModification) {
|
||||
|
||||
final List<Long> newTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> reversedTransactionIds = new ArrayList<Long>();
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
final Set<Long> existingTransactionIds = new HashSet<Long>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
final SavingsAccountTransaction savingsAccountTransaction = this.savingsAccountTransactionRepository
|
||||
.findOneByIdAndSavingsAccountId(transactionId, savingsId);
|
||||
@@ -337,21 +364,31 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
final MathContext mc = new MathContext(15, RoundingMode.HALF_EVEN);
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
if (account.isNotActive()) {
|
||||
throwValidationForActiveStatus(SavingsApiConstants.undoTransactionAction);
|
||||
}
|
||||
account.undoTransaction(transactionId, reversedTransactionIds);
|
||||
account.undoTransaction(transactionId);
|
||||
|
||||
// undoing transaction is withdrawal then undo withdrawal fee
|
||||
// transaction if any
|
||||
if (savingsAccountTransaction.isWithdrawal()) {
|
||||
final SavingsAccountTransaction nextSavingsAccountTransaction = this.savingsAccountTransactionRepository
|
||||
.findOneByIdAndSavingsAccountId(transactionId + 1, savingsId);
|
||||
if (nextSavingsAccountTransaction != null && nextSavingsAccountTransaction.isWithdrawalFeeAndNotReversed()) {
|
||||
account.undoTransaction(transactionId + 1);
|
||||
}
|
||||
}
|
||||
|
||||
checkClientOrGroupActive(account);
|
||||
if ((savingsAccountTransaction.isDeposit() || savingsAccountTransaction.isWithdrawal())
|
||||
if (savingsAccountTransaction.isPostInterestCalculationRequired()
|
||||
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) {
|
||||
account.postInterest(mc, today, newTransactionIds, reversedTransactionIds);
|
||||
account.postInterest(mc, today);
|
||||
} else {
|
||||
account.calculateInterestUsing(mc, today);
|
||||
}
|
||||
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.undoTransactionAction);
|
||||
account.activateAccountBasedOnBalance();
|
||||
postJournalEntries(account, newTransactionIds, reversedTransactionIds);
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(savingsId) //
|
||||
@@ -384,41 +421,42 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
if (account.isNotActive()) {
|
||||
throwValidationForActiveStatus(SavingsApiConstants.adjustTransactionAction);
|
||||
}
|
||||
final Set<Long> existingTransactionIds = new HashSet<Long>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed(SavingsApiConstants.transactionDateParamName);
|
||||
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed(SavingsApiConstants.transactionAmountParamName);
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
|
||||
final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes);
|
||||
|
||||
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
|
||||
account.undoTransaction(transactionId, existingReversedTransactionIds);
|
||||
account.undoTransaction(transactionId);
|
||||
|
||||
// for undo withdrawal fee
|
||||
final SavingsAccountTransaction nextSavingsAccountTransaction = this.savingsAccountTransactionRepository
|
||||
.findOneByIdAndSavingsAccountId(transactionId + 1, savingsId);
|
||||
if (nextSavingsAccountTransaction != null && nextSavingsAccountTransaction.isWithdrawalFeeAndNotReversed()) {
|
||||
account.undoTransaction(transactionId + 1, existingReversedTransactionIds);
|
||||
account.undoTransaction(transactionId + 1);
|
||||
}
|
||||
|
||||
SavingsAccountTransaction transaction = null;
|
||||
if (savingsAccountTransaction.isDeposit()) {
|
||||
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
|
||||
existingTransactionIds, existingReversedTransactionIds, paymentDetail);
|
||||
paymentDetail);
|
||||
transaction = account.deposit(transactionDTO);
|
||||
} else {
|
||||
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
|
||||
existingTransactionIds, existingReversedTransactionIds, paymentDetail);
|
||||
paymentDetail);
|
||||
transaction = account.withdraw(transactionDTO, true);
|
||||
}
|
||||
final Long newtransactionId = saveTransactionToGenerateTransactionId(transaction);
|
||||
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate)
|
||||
|| account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate())) {
|
||||
account.postInterest(mc, today, existingTransactionIds, existingReversedTransactionIds);
|
||||
account.postInterest(mc, today);
|
||||
} else {
|
||||
account.calculateInterestUsing(mc, today);
|
||||
}
|
||||
@@ -446,17 +484,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
private void postJournalEntries(final SavingsAccount savingsAccount, final List<Long> existingTransactionIds,
|
||||
final List<Long> existingReversedTransactionIds) {
|
||||
|
||||
final MonetaryCurrency currency = savingsAccount.getCurrency();
|
||||
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency);
|
||||
|
||||
final Map<String, Object> accountingBridgeData = savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(),
|
||||
existingTransactionIds, existingReversedTransactionIds);
|
||||
this.journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData);
|
||||
}
|
||||
|
||||
private void checkClientOrGroupActive(final SavingsAccount account) {
|
||||
final Client client = account.getClient();
|
||||
if (client != null) {
|
||||
@@ -507,8 +534,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
public SavingsAccountTransaction initiateSavingsTransfer(final Long accountId, final LocalDate transferDate) {
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(accountId);
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>(savingsAccount.findExistingTransactionIds());
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>(savingsAccount.findExistingReversedTransactionIds());
|
||||
final Set<Long> existingTransactionIds = new HashSet<Long>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
|
||||
updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
final SavingsAccountTransaction newTransferTransaction = SavingsAccountTransaction.initiateTransfer(savingsAccount,
|
||||
savingsAccount.office(), transferDate);
|
||||
@@ -529,8 +557,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
public SavingsAccountTransaction withdrawSavingsTransfer(final Long accountId, final LocalDate transferDate) {
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(accountId);
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>(savingsAccount.findExistingTransactionIds());
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>(savingsAccount.findExistingReversedTransactionIds());
|
||||
final Set<Long> existingTransactionIds = new HashSet<Long>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
|
||||
updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
final SavingsAccountTransaction withdrawtransferTransaction = SavingsAccountTransaction.withdrawTransfer(savingsAccount,
|
||||
savingsAccount.office(), transferDate);
|
||||
@@ -559,8 +588,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final Office acceptedInOffice, final Staff fieldOfficer) {
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(accountId);
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>(savingsAccount.findExistingTransactionIds());
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>(savingsAccount.findExistingReversedTransactionIds());
|
||||
final Set<Long> existingTransactionIds = new HashSet<Long>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
|
||||
updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
final SavingsAccountTransaction acceptTransferTransaction = SavingsAccountTransaction.approveTransfer(savingsAccount,
|
||||
acceptedInOffice, transferDate);
|
||||
@@ -569,7 +599,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
if (fieldOfficer != null) {
|
||||
savingsAccount.update(fieldOfficer);
|
||||
}
|
||||
|
||||
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
savingsAccount.calculateInterestUsing(mc, transferDate);
|
||||
|
||||
@@ -586,39 +616,65 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
public CommandProcessingResult addSavingsAccountCharge(final JsonCommand command) {
|
||||
|
||||
this.context.authenticatedUser();
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
final Long savingsAccountId = command.getSavingsId();
|
||||
this.savingsAccountChargeDataValidator.validateAdd(command.json());
|
||||
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsAccountId);
|
||||
checkClientOrGroupActive(savingsAccount);
|
||||
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern("dd MM yyyy");
|
||||
final Locale locale = command.extractLocale();
|
||||
final String format = command.dateFormat();
|
||||
final DateTimeFormatter fmt = StringUtils.isNotBlank(format) ? DateTimeFormat.forPattern(format).withLocale(locale) : DateTimeFormat.forPattern("dd MM yyyy");
|
||||
|
||||
final Long chargeDefinitionId = command.longValueOfParameterNamed(chargeIdParamName);
|
||||
final Charge chargeDefinition = this.chargeRepository.findOneWithNotFoundDetection(chargeDefinitionId);
|
||||
|
||||
final SavingsAccountCharge savingsAccountCharge = SavingsAccountCharge.createNewFromJson(savingsAccount, chargeDefinition, command);
|
||||
|
||||
if (savingsAccountCharge.getDueLocalDate() != null) {
|
||||
// transaction date should not be on a holiday or non working day
|
||||
if (!this.holidayWritePlatformService.isTransactionAllowedOnHoliday()
|
||||
&& this.holidayWritePlatformService.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueLocalDate())) {
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().toString(fmt))
|
||||
.failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.on.holiday");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
if (!this.workingDaysWritePlatformService.isTransactionAllowedOnNonWorkingDay()
|
||||
&& !this.workingDaysWritePlatformService.isWorkingDay(savingsAccountCharge.getDueLocalDate())) {
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().toString(fmt))
|
||||
.failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.a.nonworking.day");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
}
|
||||
|
||||
savingsAccount.addCharge(fmt, savingsAccountCharge, chargeDefinition);
|
||||
|
||||
this.savingAccountRepository.saveAndFlush(savingsAccount);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(savingsAccountCharge.getId()) //
|
||||
.withOfficeId(savingsAccount.officeId()) //
|
||||
.withClientId(savingsAccount.clientId()) //
|
||||
.withGroupId(savingsAccount.groupId()) //
|
||||
.withLoanId(savingsAccountId) //
|
||||
.withSavingsId(savingsAccountId) //
|
||||
.build();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult updateSavingsAccountCharge(final JsonCommand command) {
|
||||
this.context.authenticatedUser();
|
||||
|
||||
this.context.authenticatedUser();
|
||||
this.savingsAccountChargeDataValidator.validateUpdate(command.json());
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
final Long savingsAccountId = command.getSavingsId();
|
||||
// SavingsAccount Charge entity
|
||||
final Long savingsChargeId = command.entityId();
|
||||
@@ -630,51 +686,78 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
savingsAccountId);
|
||||
|
||||
final Map<String, Object> changes = savingsAccountCharge.update(command);
|
||||
|
||||
if (savingsAccountCharge.getDueLocalDate() != null) {
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
|
||||
// transaction date should not be on a holiday or non working day
|
||||
if (!this.holidayWritePlatformService.isTransactionAllowedOnHoliday()
|
||||
&& this.holidayWritePlatformService.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueLocalDate())) {
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().toString(fmt))
|
||||
.failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.on.holiday");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
if (!this.workingDaysWritePlatformService.isTransactionAllowedOnNonWorkingDay()
|
||||
&& !this.workingDaysWritePlatformService.isWorkingDay(savingsAccountCharge.getDueLocalDate())) {
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().toString(fmt))
|
||||
.failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.a.nonworking.day");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
}
|
||||
|
||||
this.savingsAccountChargeRepository.saveAndFlush(savingsAccountCharge);
|
||||
// TODO AA: revisit the code
|
||||
/*
|
||||
* // Charges may be edited only when the loan associated with them are
|
||||
* // yet to be approved (are in submitted and pending status) if
|
||||
* (!loan.status().isSubmittedAndPendingApproval()) { throw new
|
||||
* LoanChargeCannotBeUpdatedException(
|
||||
* LOAN_CHARGE_CANNOT_BE_UPDATED_REASON
|
||||
* .LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE,
|
||||
* loanCharge.getId()); }
|
||||
*/
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(savingsChargeId) //
|
||||
// .withOfficeId(savings) //
|
||||
// .withClientId(loan.getClientId()) //
|
||||
// .withGroupId(loan.getGroupId()) //
|
||||
// .withLoanId(savingsAccountId) //
|
||||
.withEntityId(savingsAccountCharge.getId()) //
|
||||
.withOfficeId(savingsAccountCharge.savingsAccount().officeId()) //
|
||||
.withClientId(savingsAccountCharge.savingsAccount().clientId()) //
|
||||
.withGroupId(savingsAccountCharge.savingsAccount().groupId()) //
|
||||
.withSavingsId(savingsAccountCharge.savingsAccount().getId()) //
|
||||
.with(changes) //
|
||||
.build();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult waiveCharge(final Long savingsAccountId, final Long savingsAccountChargeId, final JsonCommand command) {
|
||||
public CommandProcessingResult waiveCharge(final Long savingsAccountId, final Long savingsAccountChargeId) {
|
||||
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection(
|
||||
savingsAccountChargeId, savingsAccountId);
|
||||
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsAccountId);
|
||||
checkClientOrGroupActive(savingsAccount);
|
||||
// Get Savings account from savings charge
|
||||
final SavingsAccount account = savingsAccountCharge.savingsAccount();
|
||||
this.savingAccountAssembler.assignSavingAccountHelpers(account);
|
||||
|
||||
savingsAccount.waiveCharge(savingsAccountChargeId, existingTransactionIds, existingReversedTransactionIds);
|
||||
final Set<Long> existingTransactionIds = new HashSet<Long>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
this.savingAccountRepository.saveAndFlush(savingsAccount);
|
||||
account.waiveCharge(savingsAccountChargeId);
|
||||
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.postInterest(mc, today);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today);
|
||||
}
|
||||
|
||||
account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.waiveChargeTransactionAction);
|
||||
|
||||
this.savingAccountRepository.saveAndFlush(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(savingsAccountChargeId) //
|
||||
.withOfficeId(savingsAccount.officeId()) //
|
||||
.withClientId(savingsAccount.clientId()) //
|
||||
.withGroupId(savingsAccount.groupId()) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
.withClientId(account.clientId()) //
|
||||
.withGroupId(account.groupId()) //
|
||||
.withSavingsId(savingsAccountId) //
|
||||
.build();
|
||||
}
|
||||
@@ -690,8 +773,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection(
|
||||
savingsAccountChargeId, savingsAccountId);
|
||||
|
||||
// TODO AA: validate before deleting a charge
|
||||
|
||||
savingsAccount.removeCharge(savingsAccountCharge);
|
||||
this.savingAccountRepository.saveAndFlush(savingsAccount);
|
||||
|
||||
@@ -704,31 +785,107 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
.build();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult payCharge(final Long savingsAccountId, final Long savingsAccountChargeId, final JsonCommand command) {
|
||||
|
||||
this.context.authenticatedUser();
|
||||
this.savingsAccountChargeDataValidator.validatePayCharge(command.json());
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
final BigDecimal amountPaid = command.bigDecimalValueOfParameterNamed(amountParamName);
|
||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed(dueAsOfDateParamName);
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection(
|
||||
savingsAccountChargeId, savingsAccountId);
|
||||
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsAccountId);
|
||||
checkClientOrGroupActive(savingsAccount);
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
final BigDecimal chargeAmount = command.bigDecimalValueOfParameterNamed(amountParamName);
|
||||
savingsAccount.payCharge(savingsAccountChargeId, chargeAmount, existingTransactionIds, existingReversedTransactionIds);
|
||||
// transaction date should not be on a holiday or non working day
|
||||
if (!this.holidayWritePlatformService.isTransactionAllowedOnHoliday()
|
||||
&& this.holidayWritePlatformService.isHoliday(savingsAccountCharge.savingsAccount().officeId(), transactionDate)) {
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(transactionDate.toString(fmt))
|
||||
.failWithCodeNoParameterAddedToErrorCode("transaction.not.allowed.transaction.date.is.on.holiday");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
this.savingAccountRepository.saveAndFlush(savingsAccount);
|
||||
if (!this.workingDaysWritePlatformService.isTransactionAllowedOnNonWorkingDay()
|
||||
&& !this.workingDaysWritePlatformService.isWorkingDay(transactionDate)) {
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(transactionDate.toString(fmt))
|
||||
.failWithCodeNoParameterAddedToErrorCode("transaction.not.allowed.transaction.date.is.a.nonworking.day");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
this.payCharge(savingsAccountCharge, transactionDate, amountPaid, fmt);
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(savingsAccountChargeId) //
|
||||
.withOfficeId(savingsAccount.officeId()) //
|
||||
.withClientId(savingsAccount.clientId()) //
|
||||
.withGroupId(savingsAccount.groupId()) //
|
||||
.withSavingsId(savingsAccountId) //
|
||||
.withEntityId(savingsAccountCharge.getId()) //
|
||||
.withOfficeId(savingsAccountCharge.savingsAccount().officeId()) //
|
||||
.withClientId(savingsAccountCharge.savingsAccount().clientId()) //
|
||||
.withGroupId(savingsAccountCharge.savingsAccount().groupId()) //
|
||||
.withSavingsId(savingsAccountCharge.savingsAccount().getId()) //
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@CronTarget(jobName = JobName.PAY_DUE_SAVINGS_CHARGES)
|
||||
public void processDueCharges() {
|
||||
// always use current date as transaction date for batch job
|
||||
final LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
|
||||
final List<SavingsAccountCharge> pendingCharges = this.savingsAccountChargeRepository.findPendingCharges(transactionDate.toDate());
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern("dd MM yyyy");
|
||||
for (SavingsAccountCharge savingsAccountCharge : pendingCharges) {
|
||||
try {
|
||||
payCharge(savingsAccountCharge, transactionDate, savingsAccountCharge.amoutOutstanding(), fmt);
|
||||
} catch (Exception exception) {
|
||||
// TODO: AA - provide a meaningful error with failed
|
||||
// transactions list
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
private void payCharge(final SavingsAccountCharge savingsAccountCharge, final LocalDate transactionDate, final BigDecimal amountPaid,
|
||||
final DateTimeFormatter formatter) {
|
||||
// Get Savings account from savings charge
|
||||
final SavingsAccount account = savingsAccountCharge.savingsAccount();
|
||||
this.savingAccountAssembler.assignSavingAccountHelpers(account);
|
||||
final Set<Long> existingTransactionIds = new HashSet<Long>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter);
|
||||
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.postInterest(mc, today);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(mc, today);
|
||||
}
|
||||
|
||||
account.validateAccountBalanceDoesNotBecomeNegative(SavingsAccountTransactionType.PAY_CHARGE.name());
|
||||
|
||||
this.savingAccountRepository.save(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
}
|
||||
|
||||
private void updateExistingTransactionsDetails(SavingsAccount account, Set<Long> existingTransactionIds,
|
||||
Set<Long> existingReversedTransactionIds) {
|
||||
existingTransactionIds.addAll(account.findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(account.findExistingReversedTransactionIds());
|
||||
}
|
||||
|
||||
private void postJournalEntries(final SavingsAccount savingsAccount, final Set<Long> existingTransactionIds,
|
||||
final Set<Long> existingReversedTransactionIds) {
|
||||
|
||||
final MonetaryCurrency currency = savingsAccount.getCurrency();
|
||||
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency);
|
||||
|
||||
final Map<String, Object> accountingBridgeData = savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(),
|
||||
existingTransactionIds, existingReversedTransactionIds);
|
||||
this.journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData);
|
||||
}
|
||||
}
|
||||
+2
-29
@@ -14,7 +14,6 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.mifosplatform.accounting.journalentry.service.JournalEntryWritePlatformService;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
@@ -24,9 +23,6 @@ import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidation
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.staff.domain.Staff;
|
||||
import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.client.domain.AccountNumberGenerator;
|
||||
@@ -75,8 +71,6 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
private final NoteRepository noteRepository;
|
||||
private final StaffRepositoryWrapper staffRepository;
|
||||
private final SavingsAccountApplicationTransitionApiJsonValidator savingsAccountApplicationTransitionApiJsonValidator;
|
||||
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper;
|
||||
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
|
||||
private final SavingsAccountChargeAssembler savingsAccountChargeAssembler;
|
||||
|
||||
@Autowired
|
||||
@@ -87,8 +81,6 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
final GroupRepository groupRepository, final SavingsProductRepository savingsProductRepository,
|
||||
final NoteRepository noteRepository, final StaffRepositoryWrapper staffRepository,
|
||||
final SavingsAccountApplicationTransitionApiJsonValidator savingsAccountApplicationTransitionApiJsonValidator,
|
||||
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper,
|
||||
final JournalEntryWritePlatformService journalEntryWritePlatformService,
|
||||
final SavingsAccountChargeAssembler savingsAccountChargeAssembler) {
|
||||
this.context = context;
|
||||
this.savingAccountRepository = savingAccountRepository;
|
||||
@@ -101,8 +93,6 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
this.noteRepository = noteRepository;
|
||||
this.staffRepository = staffRepository;
|
||||
this.savingsAccountApplicationTransitionApiJsonValidator = savingsAccountApplicationTransitionApiJsonValidator;
|
||||
this.applicationCurrencyRepositoryWrapper = applicationCurrencyRepositoryWrapper;
|
||||
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
|
||||
this.savingsAccountChargeAssembler = savingsAccountChargeAssembler;
|
||||
}
|
||||
|
||||
@@ -140,8 +130,6 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
try {
|
||||
this.savingsAccountDataValidator.validateForSubmit(command.json());
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(command);
|
||||
this.savingAccountRepository.save(account);
|
||||
|
||||
@@ -153,8 +141,6 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
this.savingAccountRepository.save(account);
|
||||
}
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
final Long savingsId = account.getId();
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
@@ -233,10 +219,8 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
}
|
||||
|
||||
if (changes.containsKey("charges")) {
|
||||
// final Set<Charge> savingsProductCharges =
|
||||
// this.savi.assembleListOfSavingsProductCharges(command,
|
||||
// product.currency().getCode());
|
||||
final Set<SavingsAccountCharge> charges = this.savingsAccountChargeAssembler.fromParsedJson(command.parsedJson());
|
||||
final Set<SavingsAccountCharge> charges = this.savingsAccountChargeAssembler.fromParsedJson(command.parsedJson(),
|
||||
account.getCurrency().getCode());
|
||||
final boolean updated = account.update(charges);
|
||||
if (!updated) {
|
||||
changes.remove("charges");
|
||||
@@ -429,17 +413,6 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
.build();
|
||||
}
|
||||
|
||||
private void postJournalEntries(final SavingsAccount savingsAccount, final List<Long> existingTransactionIds,
|
||||
final List<Long> existingReversedTransactionIds) {
|
||||
|
||||
final MonetaryCurrency currency = savingsAccount.getCurrency();
|
||||
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency);
|
||||
|
||||
final Map<String, Object> accountingBridgeData = savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(),
|
||||
existingTransactionIds, existingReversedTransactionIds);
|
||||
this.journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData);
|
||||
}
|
||||
|
||||
private void checkClientOrGroupActive(final SavingsAccount account) {
|
||||
final Client client = account.getClient();
|
||||
if (client != null) {
|
||||
|
||||
+10
-12
@@ -10,7 +10,6 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.accounting.common.AccountingEnumerations;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||
@@ -87,12 +86,12 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
|
||||
sqlBuilder.append("sp.min_required_opening_balance as minRequiredOpeningBalance, ");
|
||||
sqlBuilder.append("sp.lockin_period_frequency as lockinPeriodFrequency,");
|
||||
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_amount as withdrawalFeeAmount,");
|
||||
// sqlBuilder.append("sp.withdrawal_fee_type_enum as withdrawalFeeTypeEnum, ");
|
||||
sqlBuilder.append("sp.withdrawal_fee_for_transfer as withdrawalFeeForTransfers, ");
|
||||
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, ");
|
||||
// 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, ");
|
||||
sqlBuilder.append("sp.accounting_type as accountingType ");
|
||||
sqlBuilder.append("from m_savings_product sp ");
|
||||
sqlBuilder.append("join m_currency curr on curr.code = sp.currency_code ");
|
||||
@@ -150,17 +149,17 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
|
||||
lockinPeriodFrequencyType = SavingsEnumerations.lockinPeriodFrequencyType(lockinPeriodFrequencyTypeValue);
|
||||
}
|
||||
|
||||
final BigDecimal withdrawalFeeAmount = rs.getBigDecimal("withdrawalFeeAmount");
|
||||
/*final BigDecimal withdrawalFeeAmount = rs.getBigDecimal("withdrawalFeeAmount");
|
||||
|
||||
EnumOptionData withdrawalFeeType = null;
|
||||
final Integer withdrawalFeeTypeValue = JdbcSupport.getInteger(rs, "withdrawalFeeTypeEnum");
|
||||
if (withdrawalFeeTypeValue != null) {
|
||||
withdrawalFeeType = SavingsEnumerations.withdrawalFeeType(withdrawalFeeTypeValue);
|
||||
}
|
||||
|
||||
*/
|
||||
final boolean withdrawalFeeForTransfers = rs.getBoolean("withdrawalFeeForTransfers");
|
||||
|
||||
final BigDecimal annualFeeAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "annualFeeAmount");
|
||||
/* final BigDecimal annualFeeAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "annualFeeAmount");
|
||||
|
||||
MonthDay annualFeeOnMonthDay = null;
|
||||
final Integer annualFeeOnMonth = JdbcSupport.getInteger(rs, "annualFeeOnMonth");
|
||||
@@ -168,11 +167,10 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
|
||||
if (annualFeeAmount != null && annualFeeOnDay != null) {
|
||||
annualFeeOnMonthDay = new MonthDay(annualFeeOnMonth, annualFeeOnDay);
|
||||
}
|
||||
|
||||
*/
|
||||
return SavingsProductData.instance(id, name, description, currency, nominalAnnualInterestRate, compoundingInterestPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, withdrawalFeeForTransfers,
|
||||
annualFeeAmount, annualFeeOnMonthDay, accountingRuleType);
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, accountingRuleType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-8
@@ -5,16 +5,10 @@
|
||||
*/
|
||||
package org.mifosplatform.scheduledjobs.service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSourceServiceFactory;
|
||||
import org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.mifosplatform.infrastructure.jobs.annotation.CronTarget;
|
||||
import org.mifosplatform.infrastructure.jobs.service.JobName;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountAnnualFeeData;
|
||||
import org.mifosplatform.portfolio.savings.service.SavingsAccountReadPlatformService;
|
||||
import org.mifosplatform.portfolio.savings.service.SavingsAccountWritePlatformService;
|
||||
import org.slf4j.Logger;
|
||||
@@ -30,7 +24,9 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
|
||||
private final static Logger logger = LoggerFactory.getLogger(ScheduledJobRunnerServiceImpl.class);
|
||||
|
||||
private final RoutingDataSourceServiceFactory dataSourceServiceFactory;
|
||||
@SuppressWarnings("unused")
|
||||
private final SavingsAccountWritePlatformService savingsAccountWritePlatformService;
|
||||
@SuppressWarnings("unused")
|
||||
private final SavingsAccountReadPlatformService savingsAccountReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
@@ -203,7 +199,7 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
|
||||
@CronTarget(jobName = JobName.APPLY_ANNUAL_FEE_FOR_SAVINGS)
|
||||
public void applyAnnualFeeForSavings() {
|
||||
|
||||
final Collection<SavingsAccountAnnualFeeData> annualFeeData = this.savingsAccountReadPlatformService
|
||||
/*final Collection<SavingsAccountAnnualFeeData> annualFeeData = this.savingsAccountReadPlatformService
|
||||
.retrieveAccountsWithAnnualFeeDue();
|
||||
|
||||
for (final SavingsAccountAnnualFeeData savingsAccountReference : annualFeeData) {
|
||||
@@ -219,6 +215,6 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(ThreadLocalContextUtil.getTenant().getName() + ": Savings accounts affected by update: " + annualFeeData.size());
|
||||
logger.info(ThreadLocalContextUtil.getTenant().getName() + ": Savings accounts affected by update: " + annualFeeData.size());*/
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user