user configurable payment types and related accounting changes

This commit is contained in:
Vishwas Babu AJ
2013-05-14 12:08:17 +05:30
parent 86a123b702
commit dd5a1cf995
33 changed files with 698 additions and 414 deletions
@@ -0,0 +1,17 @@
INSERT INTO `m_code` (`code_name`, `is_system_defined`) VALUES
('PaymentType',1);
/*Update payment detail to add foreign key relationship to user defined Code Value*/
update m_loan_transaction set payment_detail_id=null;
ALTER TABLE `m_payment_detail`
ALTER `payment_type_enum` DROP DEFAULT;
ALTER TABLE `m_payment_detail`
CHANGE COLUMN `payment_type_enum` `payment_type_cv_id` INT(11) NULL AFTER `id`;
delete from m_payment_detail;
ALTER TABLE `m_payment_detail`
ADD CONSTRAINT `FK_m_payment_detail_m_code_value` FOREIGN KEY (`payment_type_cv_id`) REFERENCES `m_code_value` (`id`);
/*Map Different Payment Channels to payment Types*/
ALTER TABLE `acc_product_mapping`
ADD COLUMN `payment_type` INT(11) NULL DEFAULT NULL AFTER `product_type`,
ADD CONSTRAINT `FK_acc_product_mapping_m_code_value` FOREIGN KEY (`payment_type`) REFERENCES `m_code_value` (`id`);
@@ -84,7 +84,8 @@ public class AccountingConstants {
FUND_SOURCE("fundSourceAccountId"), LOAN_PORTFOLIO("loanPortfolioAccountId"), INTEREST_ON_LOANS("interestOnLoanAccountId"), INCOME_FROM_FEES( FUND_SOURCE("fundSourceAccountId"), LOAN_PORTFOLIO("loanPortfolioAccountId"), INTEREST_ON_LOANS("interestOnLoanAccountId"), INCOME_FROM_FEES(
"incomeFromFeeAccountId"), INCOME_FROM_PENALTIES("incomeFromPenaltyAccountId"), LOSSES_WRITTEN_OFF("writeOffAccountId"), INTEREST_RECEIVABLE( "incomeFromFeeAccountId"), INCOME_FROM_PENALTIES("incomeFromPenaltyAccountId"), LOSSES_WRITTEN_OFF("writeOffAccountId"), INTEREST_RECEIVABLE(
"receivableInterestAccountId"), FEES_RECEIVABLE("receivableFeeAccountId"), PENALTIES_RECEIVABLE( "receivableInterestAccountId"), FEES_RECEIVABLE("receivableFeeAccountId"), PENALTIES_RECEIVABLE(
"receivablePenaltyAccountId"); "receivablePenaltyAccountId"), PAYMENT_CHANNEL_FUND_SOURCE_MAPPING("paymentChannelFundSourceMappings"), PAYMENT_TYPE(
"paymentTypeId");
private final String value; private final String value;
@@ -27,8 +27,7 @@ public class JournalEntryCommand {
private final SingleDebitOrCreditEntryCommand[] debits; private final SingleDebitOrCreditEntryCommand[] debits;
public JournalEntryCommand(final Long officeId, final LocalDate transactionDate, final String comments, public JournalEntryCommand(final Long officeId, final LocalDate transactionDate, final String comments,
final SingleDebitOrCreditEntryCommand[] credits, final SingleDebitOrCreditEntryCommand[] debits, final SingleDebitOrCreditEntryCommand[] credits, final SingleDebitOrCreditEntryCommand[] debits, final String referenceNumber) {
final String referenceNumber) {
this.officeId = officeId; this.officeId = officeId;
this.transactionDate = transactionDate; this.transactionDate = transactionDate;
this.comments = comments; this.comments = comments;
@@ -118,8 +117,8 @@ public class JournalEntryCommand {
return this.debits; return this.debits;
} }
public String getReferenceNumber() { public String getReferenceNumber() {
return this.referenceNumber; return this.referenceNumber;
} }
} }
@@ -14,6 +14,7 @@ public class LoanTransactionDTO {
private final String transactionId; private final String transactionId;
private final Date transactionDate; private final Date transactionDate;
private final Long paymentTypeId;
private final LoanTransactionEnumData transactionType; private final LoanTransactionEnumData transactionType;
private final BigDecimal amount; private final BigDecimal amount;
@@ -27,9 +28,10 @@ public class LoanTransactionDTO {
/*** Boolean values determines if the transaction is reversed ***/ /*** Boolean values determines if the transaction is reversed ***/
private final boolean reversed; private final boolean reversed;
public LoanTransactionDTO(final String transactionId, final Date transactionDate, final LoanTransactionEnumData transactionType, public LoanTransactionDTO(final Long paymentTypeId, final String transactionId, final Date transactionDate,
final BigDecimal amount, final BigDecimal principal, final BigDecimal interest, final BigDecimal fees, final LoanTransactionEnumData transactionType, final BigDecimal amount, final BigDecimal principal, final BigDecimal interest,
final BigDecimal penalties, final boolean reversed) { final BigDecimal fees, final BigDecimal penalties, final boolean reversed) {
this.paymentTypeId = paymentTypeId;
this.transactionId = transactionId; this.transactionId = transactionId;
this.transactionDate = transactionDate; this.transactionDate = transactionDate;
this.amount = amount; this.amount = amount;
@@ -77,4 +79,8 @@ public class LoanTransactionDTO {
return this.reversed; return this.reversed;
} }
public Long getPaymentTypeId() {
return this.paymentTypeId;
}
} }
@@ -71,9 +71,10 @@ public class AccountingProcessorHelper {
final BigDecimal fees = (BigDecimal) map.get("feeChargesPortion"); final BigDecimal fees = (BigDecimal) map.get("feeChargesPortion");
final BigDecimal penalties = (BigDecimal) map.get("penaltyChargesPortion"); final BigDecimal penalties = (BigDecimal) map.get("penaltyChargesPortion");
final boolean reversed = (Boolean) map.get("reversed"); final boolean reversed = (Boolean) map.get("reversed");
final Long paymentTypeId = (Long) map.get("paymentTypeId");
final LoanTransactionDTO transaction = new LoanTransactionDTO(transactionId, transactionDate, transactionType, amount, final LoanTransactionDTO transaction = new LoanTransactionDTO(paymentTypeId, transactionId, transactionDate, transactionType,
principal, interest, fees, penalties, reversed); amount, principal, interest, fees, penalties, reversed);
newLoanTransactions.add(transaction); newLoanTransactions.add(transaction);
@@ -95,6 +96,7 @@ public class AccountingProcessorHelper {
* @param accountTypeToBeCredited * @param accountTypeToBeCredited
* Enum of the placeholder of the GLAccount to be credited * Enum of the placeholder of the GLAccount to be credited
* @param loanProductId * @param loanProductId
* @param paymentTypeId
* @param loanId * @param loanId
* @param transactionId * @param transactionId
* @param transactionDate * @param transactionDate
@@ -103,8 +105,8 @@ public class AccountingProcessorHelper {
*/ */
public void createAccrualBasedJournalEntriesAndReversalsForLoan(final Office office, public void createAccrualBasedJournalEntriesAndReversalsForLoan(final Office office,
final ACCRUAL_ACCOUNTS_FOR_LOAN accountTypeToBeDebited, final ACCRUAL_ACCOUNTS_FOR_LOAN accountTypeToBeCredited, final ACCRUAL_ACCOUNTS_FOR_LOAN accountTypeToBeDebited, final ACCRUAL_ACCOUNTS_FOR_LOAN accountTypeToBeCredited,
final Long loanProductId, final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount, final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate,
final Boolean isReversal) { final BigDecimal amount, final Boolean isReversal) {
int accountTypeToDebitId = accountTypeToBeDebited.getValue(); int accountTypeToDebitId = accountTypeToBeDebited.getValue();
int accountTypeToCreditId = accountTypeToBeCredited.getValue(); int accountTypeToCreditId = accountTypeToBeCredited.getValue();
// reverse debits and credits for reversals // reverse debits and credits for reversals
@@ -112,8 +114,8 @@ public class AccountingProcessorHelper {
accountTypeToDebitId = accountTypeToBeCredited.getValue(); accountTypeToDebitId = accountTypeToBeCredited.getValue();
accountTypeToCreditId = accountTypeToBeDebited.getValue(); accountTypeToCreditId = accountTypeToBeDebited.getValue();
} }
createJournalEntriesForLoan(office, accountTypeToDebitId, accountTypeToCreditId, loanProductId, loanId, transactionId, createJournalEntriesForLoan(office, accountTypeToDebitId, accountTypeToCreditId, loanProductId, paymentTypeId, loanId,
transactionDate, amount); transactionId, transactionDate, amount);
} }
/** /**
@@ -129,6 +131,7 @@ public class AccountingProcessorHelper {
* @param accountTypeToBeCredited * @param accountTypeToBeCredited
* Enum of the placeholder of the GLAccount to be credited * Enum of the placeholder of the GLAccount to be credited
* @param loanProductId * @param loanProductId
* @param paymentTypeId
* @param loanId * @param loanId
* @param transactionId * @param transactionId
* @param transactionDate * @param transactionDate
@@ -136,8 +139,8 @@ public class AccountingProcessorHelper {
* @param isReversal * @param isReversal
*/ */
public void createCashBasedJournalEntriesAndReversalsForLoan(final Office office, final CASH_ACCOUNTS_FOR_LOAN accountTypeToBeDebited, public void createCashBasedJournalEntriesAndReversalsForLoan(final Office office, final CASH_ACCOUNTS_FOR_LOAN accountTypeToBeDebited,
final CASH_ACCOUNTS_FOR_LOAN accountTypeToBeCredited, final Long loanProductId, final Long loanId, final String transactionId, final CASH_ACCOUNTS_FOR_LOAN accountTypeToBeCredited, final Long loanProductId, final Long paymentTypeId, final Long loanId,
final Date transactionDate, final BigDecimal amount, final Boolean isReversal) { final String transactionId, final Date transactionDate, final BigDecimal amount, final Boolean isReversal) {
int accountTypeToDebitId = accountTypeToBeDebited.getValue(); int accountTypeToDebitId = accountTypeToBeDebited.getValue();
int accountTypeToCreditId = accountTypeToBeCredited.getValue(); int accountTypeToCreditId = accountTypeToBeCredited.getValue();
// reverse debits and credits for reversals // reverse debits and credits for reversals
@@ -145,40 +148,40 @@ public class AccountingProcessorHelper {
accountTypeToDebitId = accountTypeToBeCredited.getValue(); accountTypeToDebitId = accountTypeToBeCredited.getValue();
accountTypeToCreditId = accountTypeToBeDebited.getValue(); accountTypeToCreditId = accountTypeToBeDebited.getValue();
} }
createJournalEntriesForLoan(office, accountTypeToDebitId, accountTypeToCreditId, loanProductId, loanId, transactionId, createJournalEntriesForLoan(office, accountTypeToDebitId, accountTypeToCreditId, loanProductId, paymentTypeId, loanId,
transactionDate, amount); transactionId, transactionDate, amount);
} }
public void createCreditJournalEntryOrReversalForLoan(final Office office, final CASH_ACCOUNTS_FOR_LOAN accountMappingType, public void createCreditJournalEntryOrReversalForLoan(final Office office, final CASH_ACCOUNTS_FOR_LOAN accountMappingType,
final Long loanProductId, final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount, final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate,
final Boolean isReversal) { final BigDecimal amount, final Boolean isReversal) {
int accountMappingTypeId = accountMappingType.getValue(); int accountMappingTypeId = accountMappingType.getValue();
createCreditJournalEntryOrReversalForLoan(office, accountMappingTypeId, loanProductId, loanId, transactionId, transactionDate, createCreditJournalEntryOrReversalForLoan(office, accountMappingTypeId, loanProductId, paymentTypeId, loanId, transactionId,
amount, isReversal); transactionDate, amount, isReversal);
} }
public void createCreditJournalEntryOrReversalForLoan(final Office office, final ACCRUAL_ACCOUNTS_FOR_LOAN accountMappingType, public void createCreditJournalEntryOrReversalForLoan(final Office office, final ACCRUAL_ACCOUNTS_FOR_LOAN accountMappingType,
final Long loanProductId, final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount, final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate,
final Boolean isReversal) { final BigDecimal amount, final Boolean isReversal) {
int accountMappingTypeId = accountMappingType.getValue(); int accountMappingTypeId = accountMappingType.getValue();
createCreditJournalEntryOrReversalForLoan(office, accountMappingTypeId, loanProductId, loanId, transactionId, transactionDate, createCreditJournalEntryOrReversalForLoan(office, accountMappingTypeId, loanProductId, paymentTypeId, loanId, transactionId,
amount, isReversal); transactionDate, amount, isReversal);
} }
public void createDebitJournalEntryOrReversalForLoan(final Office office, final CASH_ACCOUNTS_FOR_LOAN accountMappingType, public void createDebitJournalEntryOrReversalForLoan(final Office office, final CASH_ACCOUNTS_FOR_LOAN accountMappingType,
final Long loanProductId, final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount, final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate,
final Boolean isReversal) { final BigDecimal amount, final Boolean isReversal) {
int accountMappingTypeId = accountMappingType.getValue(); int accountMappingTypeId = accountMappingType.getValue();
createDebitJournalEntryOrReversalForLoan(office, accountMappingTypeId, loanProductId, loanId, transactionId, transactionDate, createDebitJournalEntryOrReversalForLoan(office, accountMappingTypeId, loanProductId, paymentTypeId, loanId, transactionId,
amount, isReversal); transactionDate, amount, isReversal);
} }
public void createDebitJournalEntryOrReversalForLoan(final Office office, final ACCRUAL_ACCOUNTS_FOR_LOAN accountMappingType, public void createDebitJournalEntryOrReversalForLoan(final Office office, final ACCRUAL_ACCOUNTS_FOR_LOAN accountMappingType,
final Long loanProductId, final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount, final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate,
final Boolean isReversal) { final BigDecimal amount, final Boolean isReversal) {
int accountMappingTypeId = accountMappingType.getValue(); int accountMappingTypeId = accountMappingType.getValue();
createDebitJournalEntryOrReversalForLoan(office, accountMappingTypeId, loanProductId, loanId, transactionId, transactionDate, createDebitJournalEntryOrReversalForLoan(office, accountMappingTypeId, loanProductId, paymentTypeId, loanId, transactionId,
amount, isReversal); transactionDate, amount, isReversal);
} }
/** /**
@@ -205,16 +208,18 @@ public class AccountingProcessorHelper {
} }
private void createJournalEntriesForLoan(final Office office, final int accountTypeToDebitId, final int accountTypeToCreditId, private void createJournalEntriesForLoan(final Office office, final int accountTypeToDebitId, final int accountTypeToCreditId,
final Long loanProductId, final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount) { final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate,
GLAccount debitAccount = getLinkedGLAccountForLoanProduct(loanProductId, accountTypeToDebitId); final BigDecimal amount) {
GLAccount creditAccount = getLinkedGLAccountForLoanProduct(loanProductId, accountTypeToCreditId); GLAccount debitAccount = getLinkedGLAccountForLoanProduct(loanProductId, accountTypeToDebitId, paymentTypeId);
GLAccount creditAccount = getLinkedGLAccountForLoanProduct(loanProductId, accountTypeToCreditId, paymentTypeId);
createDebitJournalEntryForLoan(office, debitAccount, loanId, transactionId, transactionDate, amount); createDebitJournalEntryForLoan(office, debitAccount, loanId, transactionId, transactionDate, amount);
createCreditJournalEntryForLoan(office, creditAccount, loanId, transactionId, transactionDate, amount); createCreditJournalEntryForLoan(office, creditAccount, loanId, transactionId, transactionDate, amount);
} }
private void createDebitJournalEntryOrReversalForLoan(final Office office, final int accountMappingTypeId, final Long loanProductId, private void createDebitJournalEntryOrReversalForLoan(final Office office, final int accountMappingTypeId, final Long loanProductId,
final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount, final Boolean isReversal) { final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount,
GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, accountMappingTypeId); final Boolean isReversal) {
GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, accountMappingTypeId, paymentTypeId);
if (isReversal) { if (isReversal) {
createCreditJournalEntryForLoan(office, account, loanId, transactionId, transactionDate, amount); createCreditJournalEntryForLoan(office, account, loanId, transactionId, transactionDate, amount);
} else { } else {
@@ -223,8 +228,9 @@ public class AccountingProcessorHelper {
} }
private void createCreditJournalEntryOrReversalForLoan(final Office office, final int accountMappingTypeId, final Long loanProductId, private void createCreditJournalEntryOrReversalForLoan(final Office office, final int accountMappingTypeId, final Long loanProductId,
final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount, final Boolean isReversal) { final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount,
GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, accountMappingTypeId); final Boolean isReversal) {
GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, accountMappingTypeId, paymentTypeId);
if (isReversal) { if (isReversal) {
createDebitJournalEntryForLoan(office, account, loanId, transactionId, transactionDate, amount); createDebitJournalEntryForLoan(office, account, loanId, transactionId, transactionDate, amount);
} else { } else {
@@ -248,11 +254,22 @@ public class AccountingProcessorHelper {
this.glJournalEntryRepository.saveAndFlush(journalEntry); this.glJournalEntryRepository.saveAndFlush(journalEntry);
} }
private GLAccount getLinkedGLAccountForLoanProduct(final Long loanProductId, final int accountMappingTypeId) { private GLAccount getLinkedGLAccountForLoanProduct(final Long loanProductId, final int accountMappingTypeId, final Long paymentTypeId) {
final ProductToGLAccountMapping accountMapping = this.accountMappingRepository ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(loanProductId,
.findByProductIdAndProductTypeAndFinancialAccountType(loanProductId, PortfolioProductType.LOAN.getValue(), PortfolioProductType.LOAN.getValue(), accountMappingTypeId);
accountMappingTypeId); /****
* Get more specific mapping for FUND source accounts (based on payment
* 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()) {
ProductToGLAccountMapping paymentChannelSpecificAccountMapping = this.accountMappingRepository
.findByProductIdAndProductTypeAndFinancialAccountTypeAndPaymentType(loanProductId,
PortfolioProductType.LOAN.getValue(), accountMappingTypeId, paymentTypeId);
if (paymentChannelSpecificAccountMapping != null) {
accountMapping = paymentChannelSpecificAccountMapping;
}
}
return accountMapping.getGlAccount(); return accountMapping.getGlAccount();
} }
} }
@@ -86,11 +86,13 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
final Date transactionDate = loanTransactionDTO.getTransactionDate(); final Date transactionDate = loanTransactionDTO.getTransactionDate();
final BigDecimal disbursalAmount = loanTransactionDTO.getAmount(); final BigDecimal disbursalAmount = loanTransactionDTO.getAmount();
final boolean isReversed = loanTransactionDTO.isReversed(); final boolean isReversed = loanTransactionDTO.isReversed();
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
// create journal entries for the disbursement (or disbursement // create journal entries for the disbursement (or disbursement
// reversal) // reversal)
helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO,
ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId, loanId, transactionId, transactionDate, disbursalAmount, isReversed); ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
disbursalAmount, isReversed);
} }
@@ -114,11 +116,13 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
final Date transactionDate = loanTransactionDTO.getTransactionDate(); final Date transactionDate = loanTransactionDTO.getTransactionDate();
final BigDecimal amount = loanTransactionDTO.getAmount(); final BigDecimal amount = loanTransactionDTO.getAmount();
final boolean isReversed = loanTransactionDTO.isReversed(); final boolean isReversed = loanTransactionDTO.isReversed();
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
// create journal entries for recognising interest (or reversal) // create journal entries for recognising interest (or reversal)
if (amount != null && !(amount.compareTo(BigDecimal.ZERO) == 0)) { if (amount != null && !(amount.compareTo(BigDecimal.ZERO) == 0)) {
helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE, helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE,
ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS, loanProductId, loanId, transactionId, transactionDate, amount, isReversed); ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS, loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
amount, isReversed);
} }
} }
@@ -176,6 +180,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
final BigDecimal interestAmount = loanTransactionDTO.getInterest(); final BigDecimal interestAmount = loanTransactionDTO.getInterest();
final BigDecimal feesAmount = loanTransactionDTO.getFees(); final BigDecimal feesAmount = loanTransactionDTO.getFees();
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties(); final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
final boolean isReversal = loanTransactionDTO.isReversed(); final boolean isReversal = loanTransactionDTO.isReversed();
BigDecimal totalDebitAmount = new BigDecimal(0); BigDecimal totalDebitAmount = new BigDecimal(0);
@@ -183,15 +188,15 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
// handle principal payment or writeOff (and reversals) // handle principal payment or writeOff (and reversals)
if (principalAmount != null && !(principalAmount.compareTo(BigDecimal.ZERO) == 0)) { if (principalAmount != null && !(principalAmount.compareTo(BigDecimal.ZERO) == 0)) {
totalDebitAmount = totalDebitAmount.add(principalAmount); totalDebitAmount = totalDebitAmount.add(principalAmount);
helper.createCreditJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, loanProductId, loanId, helper.createCreditJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, loanProductId,
transactionId, transactionDate, principalAmount, isReversal); paymentTypeId, loanId, transactionId, transactionDate, principalAmount, isReversal);
} }
// handle interest payment of writeOff (and reversals) // handle interest payment of writeOff (and reversals)
if (interestAmount != null && !(interestAmount.compareTo(BigDecimal.ZERO) == 0)) { if (interestAmount != null && !(interestAmount.compareTo(BigDecimal.ZERO) == 0)) {
totalDebitAmount = totalDebitAmount.add(interestAmount); totalDebitAmount = totalDebitAmount.add(interestAmount);
helper.createCreditJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE, loanProductId, loanId, helper.createCreditJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE, loanProductId,
transactionId, transactionDate, interestAmount, isReversal); paymentTypeId, loanId, transactionId, transactionDate, interestAmount, isReversal);
} }
// handle fees payment of writeOff (and reversals) // handle fees payment of writeOff (and reversals)
@@ -204,15 +209,15 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
feeAccountToCredit = ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES; feeAccountToCredit = ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES;
} }
helper.createCreditJournalEntryOrReversalForLoan(office, feeAccountToCredit, loanProductId, loanId, transactionId, helper.createCreditJournalEntryOrReversalForLoan(office, feeAccountToCredit, loanProductId, paymentTypeId, loanId,
transactionDate, feesAmount, isReversal); transactionId, transactionDate, feesAmount, isReversal);
} }
// handle penalties payment of writeOff (and reversals) // handle penalties payment of writeOff (and reversals)
if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) { if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
totalDebitAmount = totalDebitAmount.add(penaltiesAmount); totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
helper.createCreditJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE, loanProductId, loanId, helper.createCreditJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE, loanProductId,
transactionId, transactionDate, penaltiesAmount, isReversal); paymentTypeId, loanId, transactionId, transactionDate, penaltiesAmount, isReversal);
} }
/** /**
@@ -220,11 +225,11 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
* reversals) * reversals)
***/ ***/
if (writeOff) { if (writeOff) {
helper.createDebitJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF, loanProductId, loanId, helper.createDebitJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF, loanProductId,
transactionId, transactionDate, totalDebitAmount, isReversal); paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
} else { } else {
helper.createDebitJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId, loanId, helper.createDebitJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId, paymentTypeId,
transactionId, transactionDate, totalDebitAmount, isReversal); loanId, transactionId, transactionDate, totalDebitAmount, isReversal);
} }
} }
@@ -256,19 +261,19 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
final BigDecimal feesAmount = loanTransactionDTO.getFees(); final BigDecimal feesAmount = loanTransactionDTO.getFees();
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties(); final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
final boolean isReversed = loanTransactionDTO.isReversed(); final boolean isReversed = loanTransactionDTO.isReversed();
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
// create journal entries for the fees application (or reversal) // create journal entries for the fees application (or reversal)
if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 0)) { if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 0)) {
helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE, helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE,
ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES, loanProductId, loanId, transactionId, transactionDate, feesAmount, ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES, loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
isReversed); feesAmount, isReversed);
} }
// create journal entries for the penalties application (or reversal) // create journal entries for the penalties application (or reversal)
else if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) { else if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE, helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE,
ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES, loanProductId, loanId, transactionId, transactionDate, ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES, loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
penaltiesAmount, isReversed); penaltiesAmount, isReversed);
} }
} }
} }
@@ -34,6 +34,7 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
for (final LoanTransactionDTO loanTransactionDTO : loanDTO.getNewLoanTransactions()) { for (final LoanTransactionDTO loanTransactionDTO : loanDTO.getNewLoanTransactions()) {
final Date transactionDate = loanTransactionDTO.getTransactionDate(); final Date transactionDate = loanTransactionDTO.getTransactionDate();
final String transactionId = loanTransactionDTO.getTransactionId(); final String transactionId = loanTransactionDTO.getTransactionId();
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
final Long loanId = loanDTO.getLoanId(); final Long loanId = loanDTO.getLoanId();
helper.checkForBranchClosures(latestGLClosure, transactionDate); helper.checkForBranchClosures(latestGLClosure, transactionDate);
@@ -58,8 +59,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
else if (loanTransactionDTO.getTransactionType().isWriteOff() && !loanTransactionDTO.isReversed()) { else if (loanTransactionDTO.getTransactionType().isWriteOff() && !loanTransactionDTO.isReversed()) {
final BigDecimal principalAmount = loanTransactionDTO.getPrincipal(); final BigDecimal principalAmount = loanTransactionDTO.getPrincipal();
helper.createCashBasedJournalEntriesAndReversalsForLoan(office, CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF, helper.createCashBasedJournalEntriesAndReversalsForLoan(office, CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF,
CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, loanProductId, loanId, transactionId, transactionDate, principalAmount, CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, loanProductId, paymentTypeId, loanId, transactionId, transactionDate,
false); principalAmount, false);
} }
} }
} }
@@ -86,9 +87,11 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
final Date transactionDate = loanTransactionDTO.getTransactionDate(); final Date transactionDate = loanTransactionDTO.getTransactionDate();
final BigDecimal disbursalAmount = loanTransactionDTO.getAmount(); final BigDecimal disbursalAmount = loanTransactionDTO.getAmount();
final boolean isReversal = loanTransactionDTO.isReversed(); final boolean isReversal = loanTransactionDTO.isReversed();
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
helper.createCashBasedJournalEntriesAndReversalsForLoan(office, CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, helper.createCashBasedJournalEntriesAndReversalsForLoan(office, CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO,
CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId, loanId, transactionId, transactionDate, disbursalAmount, isReversal); CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId, paymentTypeId, loanId, transactionId, transactionDate, disbursalAmount,
isReversal);
} }
/** /**
@@ -113,35 +116,36 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
final BigDecimal feesAmount = loanTransactionDTO.getFees(); final BigDecimal feesAmount = loanTransactionDTO.getFees();
final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties(); final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties();
final boolean isReversal = loanTransactionDTO.isReversed(); final boolean isReversal = loanTransactionDTO.isReversed();
final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId();
BigDecimal totalDebitAmount = new BigDecimal(0); BigDecimal totalDebitAmount = new BigDecimal(0);
if (principalAmount != null && !(principalAmount.compareTo(BigDecimal.ZERO) == 0)) { if (principalAmount != null && !(principalAmount.compareTo(BigDecimal.ZERO) == 0)) {
totalDebitAmount = totalDebitAmount.add(principalAmount); totalDebitAmount = totalDebitAmount.add(principalAmount);
helper.createCreditJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, loanProductId, loanId, helper.createCreditJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, loanProductId, paymentTypeId,
transactionId, transactionDate, principalAmount, isReversal); loanId, transactionId, transactionDate, principalAmount, isReversal);
} }
if (interestAmount != null && !(interestAmount.compareTo(BigDecimal.ZERO) == 0)) { if (interestAmount != null && !(interestAmount.compareTo(BigDecimal.ZERO) == 0)) {
totalDebitAmount = totalDebitAmount.add(interestAmount); totalDebitAmount = totalDebitAmount.add(interestAmount);
helper.createCreditJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS, loanProductId, loanId, helper.createCreditJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS, loanProductId,
transactionId, transactionDate, interestAmount, isReversal); paymentTypeId, loanId, transactionId, transactionDate, interestAmount, isReversal);
} }
if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 0)) { if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 0)) {
totalDebitAmount = totalDebitAmount.add(feesAmount); totalDebitAmount = totalDebitAmount.add(feesAmount);
helper.createCreditJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES, loanProductId, loanId, helper.createCreditJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES, loanProductId, paymentTypeId,
transactionId, transactionDate, feesAmount, isReversal); loanId, transactionId, transactionDate, feesAmount, isReversal);
} }
if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) { if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
totalDebitAmount = totalDebitAmount.add(penaltiesAmount); totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
helper.createCreditJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES, loanProductId, loanId, helper.createCreditJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES, loanProductId,
transactionId, transactionDate, penaltiesAmount, isReversal); paymentTypeId, loanId, transactionId, transactionDate, penaltiesAmount, isReversal);
} }
/*** create a single debit entry (or reversal) for the entire amount **/ /*** create a single debit entry (or reversal) for the entire amount **/
helper.createDebitJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId, loanId, transactionId, helper.createDebitJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId, paymentTypeId, loanId,
transactionDate, totalDebitAmount, isReversal); transactionId, transactionDate, totalDebitAmount, isReversal);
} }
} }
@@ -14,11 +14,12 @@ import javax.persistence.Table;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
import org.mifosplatform.accounting.glaccount.domain.GLAccount; import org.mifosplatform.accounting.glaccount.domain.GLAccount;
import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity @Entity
@Table(name = "acc_product_mapping", uniqueConstraints = { @UniqueConstraint(columnNames = { "product_id", "product_type", @Table(name = "acc_product_mapping", uniqueConstraints = { @UniqueConstraint(columnNames = { "product_id", "product_type",
"financial_account_type" }, name = "financial_action") }) "financial_account_type", "payment_type" }, name = "financial_action") })
public class ProductToGLAccountMapping extends AbstractPersistable<Long> { public class ProductToGLAccountMapping extends AbstractPersistable<Long> {
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY)
@@ -28,6 +29,10 @@ public class ProductToGLAccountMapping extends AbstractPersistable<Long> {
@Column(name = "product_id", nullable = false) @Column(name = "product_id", nullable = false)
private Long productId; private Long productId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "payment_type", nullable = true)
private CodeValue paymentType;
@Column(name = "product_type", nullable = false) @Column(name = "product_type", nullable = false)
private int productType; private int productType;
@@ -44,10 +49,16 @@ public class ProductToGLAccountMapping extends AbstractPersistable<Long> {
} }
public ProductToGLAccountMapping(final GLAccount glAccount, final Long productId, final int productType, final int financialAccountType) { public ProductToGLAccountMapping(final GLAccount glAccount, final Long productId, final int productType, final int financialAccountType) {
this(glAccount, productId, productType, financialAccountType, null);
}
public ProductToGLAccountMapping(final GLAccount glAccount, final Long productId, final int productType,
final int financialAccountType, final CodeValue paymentType) {
this.glAccount = glAccount; this.glAccount = glAccount;
this.productId = productId; this.productId = productId;
this.productType = productType; this.productType = productType;
this.financialAccountType = financialAccountType; this.financialAccountType = financialAccountType;
this.paymentType = paymentType;
} }
public GLAccount getGlAccount() { public GLAccount getGlAccount() {
@@ -82,4 +93,12 @@ public class ProductToGLAccountMapping extends AbstractPersistable<Long> {
this.financialAccountType = financialAccountType; this.financialAccountType = financialAccountType;
} }
public CodeValue getPaymentType() {
return this.paymentType;
}
public void setPaymentType(CodeValue paymentType) {
this.paymentType = paymentType;
}
} }
@@ -9,11 +9,23 @@ import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface ProductToGLAccountMappingRepository extends JpaRepository<ProductToGLAccountMapping, Long>, public interface ProductToGLAccountMappingRepository extends JpaRepository<ProductToGLAccountMapping, Long>,
JpaSpecificationExecutor<ProductToGLAccountMapping> { JpaSpecificationExecutor<ProductToGLAccountMapping> {
ProductToGLAccountMapping findByProductIdAndProductTypeAndFinancialAccountType(Long productId, int productType, int financialAccountType); ProductToGLAccountMapping findByProductIdAndProductTypeAndFinancialAccountTypeAndPaymentType(Long productId, int productType,
int financialAccountType, Long paymentType);
@Query("from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.financialAccountType=:financialAccountType and mapping.paymentType is NULL")
ProductToGLAccountMapping findCoreProductToFinAccountMapping(@Param("productId") Long productId, @Param("productType") int productType,
@Param("financialAccountType") int financialAccountType);
/*** The financial Account Type for a fund source will always be an asset (1) ***/
@Query("from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.financialAccountType=1 and mapping.paymentType is not NULL")
List<ProductToGLAccountMapping> findAllPaymentTypeToFundSourceMappings(@Param("productId") Long productId,
@Param("productType") int productType);
List<ProductToGLAccountMapping> findByProductIdAndProductType(Long productId, int productType); List<ProductToGLAccountMapping> findByProductIdAndProductType(Long productId, int productType);
} }
@@ -10,4 +10,6 @@ import java.util.Map;
public interface ProductToGLAccountMappingReadPlatformService { public interface ProductToGLAccountMappingReadPlatformService {
Map<String, Object> fetchAccountMappingDetailsForLoanProduct(final Long loanProductId, final Integer accountingType); Map<String, Object> fetchAccountMappingDetailsForLoanProduct(final Long loanProductId, final Integer accountingType);
Map<Long, Long> fetchPaymentTypeToFundSourceMappingsForLoanProduct(final Long loanProductId);
} }
@@ -34,8 +34,8 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
private static final class LoanProductToGLAccountMappingMapper implements RowMapper<Map<String, Object>> { private static final class LoanProductToGLAccountMappingMapper implements RowMapper<Map<String, Object>> {
public String schema() { public String schema() {
return " id as id, gl_account_id as glAccountId,product_id as productId,product_type as productType,financial_account_type as financialAccountType" return " id as id, gl_account_id as glAccountId,product_id as productId,product_type as productType,financial_account_type as financialAccountType,"
+ " from acc_product_mapping " + " where product_type=1 "; + " payment_type as paymentTypeId from acc_product_mapping " + " where product_type=1 ";
} }
@Override @Override
@@ -44,6 +44,7 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
final Long id = rs.getLong("id"); final Long id = rs.getLong("id");
final Long glAccountId = rs.getLong("glAccountId"); final Long glAccountId = rs.getLong("glAccountId");
final Long productId = rs.getLong("productId"); final Long productId = rs.getLong("productId");
final Long paymentTypeId = rs.getLong("paymentTypeId");
final Integer productType = rs.getInt("productType"); final Integer productType = rs.getInt("productType");
final Integer financialAccountType = rs.getInt("financialAccountType"); final Integer financialAccountType = rs.getInt("financialAccountType");
@@ -53,6 +54,7 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
loanProductToGLAccountMap.put("productId", productId); loanProductToGLAccountMap.put("productId", productId);
loanProductToGLAccountMap.put("productType", productType); loanProductToGLAccountMap.put("productType", productType);
loanProductToGLAccountMap.put("financialAccountType", financialAccountType); loanProductToGLAccountMap.put("financialAccountType", financialAccountType);
loanProductToGLAccountMap.put("paymentTypeId", paymentTypeId);
return loanProductToGLAccountMap; return loanProductToGLAccountMap;
} }
@@ -124,4 +126,25 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
return accountMappingDetails; return accountMappingDetails;
} }
@Override
public Map<Long, Long> fetchPaymentTypeToFundSourceMappingsForLoanProduct(Long loanProductId) {
Map<Long, Long> paymentTypeToFundSourceMappingDetails = null;
final LoanProductToGLAccountMappingMapper rm = new LoanProductToGLAccountMappingMapper();
final String sql = "select " + rm.schema() + " and product_id = ? and payment_type is not null";
final List<Map<String, Object>> paymentTypeToFundSourceMappingsList = this.jdbcTemplate.query(sql, rm,
new Object[] { loanProductId });
for (final Map<String, Object> productToGLAccountMap : paymentTypeToFundSourceMappingsList) {
if (paymentTypeToFundSourceMappingDetails == null) {
paymentTypeToFundSourceMappingDetails = new LinkedHashMap<Long, Long>();
}
final Long glAccountId = (Long) productToGLAccountMap.get("glAccountId");
final Long paymentTypeId = (Long) productToGLAccountMap.get("paymentTypeId");
paymentTypeToFundSourceMappingDetails.put(paymentTypeId, glAccountId);
}
return paymentTypeToFundSourceMappingDetails;
}
} }
@@ -6,9 +6,11 @@
package org.mifosplatform.accounting.producttoaccountmapping.service; package org.mifosplatform.accounting.producttoaccountmapping.service;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.mifosplatform.accounting.common.AccountingConstants.ACCRUAL_ACCOUNTS_FOR_LOAN; import org.mifosplatform.accounting.common.AccountingConstants.ACCRUAL_ACCOUNTS_FOR_LOAN;
import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_LOAN; import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_LOAN;
@@ -23,14 +25,19 @@ import org.mifosplatform.accounting.producttoaccountmapping.domain.ProductToGLAc
import org.mifosplatform.accounting.producttoaccountmapping.exception.ProductToGLAccountMappingInvalidException; import org.mifosplatform.accounting.producttoaccountmapping.exception.ProductToGLAccountMappingInvalidException;
import org.mifosplatform.accounting.producttoaccountmapping.exception.ProductToGLAccountMappingNotFoundException; import org.mifosplatform.accounting.producttoaccountmapping.exception.ProductToGLAccountMappingNotFoundException;
import org.mifosplatform.accounting.producttoaccountmapping.serialization.ProductToGLAccountMappingFromApiJsonDeserializer; import org.mifosplatform.accounting.producttoaccountmapping.serialization.ProductToGLAccountMappingFromApiJsonDeserializer;
import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.mifosplatform.infrastructure.codes.domain.CodeValueRepositoryWrapper;
import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType; import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType;
import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@Service @Service
public class ProductToGLAccountMappingWritePlatformServiceImpl implements ProductToGLAccountMappingWritePlatformService { public class ProductToGLAccountMappingWritePlatformServiceImpl implements ProductToGLAccountMappingWritePlatformService {
@@ -39,15 +46,17 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
private final ProductToGLAccountMappingRepository accountMappingRepository; private final ProductToGLAccountMappingRepository accountMappingRepository;
private final FromJsonHelper fromApiJsonHelper; private final FromJsonHelper fromApiJsonHelper;
private final ProductToGLAccountMappingFromApiJsonDeserializer deserializer; private final ProductToGLAccountMappingFromApiJsonDeserializer deserializer;
private final CodeValueRepositoryWrapper codeValueRepositoryWrapper;
@Autowired @Autowired
public ProductToGLAccountMappingWritePlatformServiceImpl(final GLAccountRepository glAccountRepository, public ProductToGLAccountMappingWritePlatformServiceImpl(final GLAccountRepository glAccountRepository,
final ProductToGLAccountMappingRepository glAccountMappingRepository, final FromJsonHelper fromApiJsonHelper, final ProductToGLAccountMappingRepository glAccountMappingRepository, final FromJsonHelper fromApiJsonHelper,
final ProductToGLAccountMappingFromApiJsonDeserializer deserializer) { final ProductToGLAccountMappingFromApiJsonDeserializer deserializer, final CodeValueRepositoryWrapper codeValueRepositoryWrapper) {
this.accountRepository = glAccountRepository; this.accountRepository = glAccountRepository;
this.accountMappingRepository = glAccountMappingRepository; this.accountMappingRepository = glAccountMappingRepository;
this.fromApiJsonHelper = fromApiJsonHelper; this.fromApiJsonHelper = fromApiJsonHelper;
this.deserializer = deserializer; this.deserializer = deserializer;
this.codeValueRepositoryWrapper = codeValueRepositoryWrapper;
} }
@Override @Override
@@ -78,6 +87,9 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
// expenses // expenses
saveLoanToExpenseAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), loanProductId, saveLoanToExpenseAccountMapping(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.getValue());
// advanced accounting mappings
savePaymentChannelToFundSourceMappings(command, element, loanProductId, null);
break; break;
case ACCRUAL_BASED: case ACCRUAL_BASED:
@@ -104,6 +116,9 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
// expenses // expenses
saveLoanToExpenseAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), loanProductId, saveLoanToExpenseAccountMapping(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.getValue());
// advanced accounting mappings
savePaymentChannelToFundSourceMappings(command, element, loanProductId, null);
break; break;
} }
} }
@@ -127,9 +142,11 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
if (accountingRuleChanged) { if (accountingRuleChanged) {
this.deserializer.validateForCreate(command.json()); this.deserializer.validateForCreate(command.json());
handleChangesToAccountingRuleType(loanProductId, command, changes, element, accountingRuleType); handleChangesToAccountingRuleType(loanProductId, command, changes, element, accountingRuleType);
savePaymentChannelToFundSourceMappings(command, element, loanProductId, changes);
}/*** else examine and update individual changes ***/ }/*** else examine and update individual changes ***/
else { else {
handleChangesToLoanProductToGLAccountMappings(loanProductId, changes, element, accountingRuleType); handleChangesToLoanProductToGLAccountMappings(loanProductId, changes, element, accountingRuleType);
updatePaymentChannelToFundSourceMappings(command, element, loanProductId, changes);
} }
return changes; return changes;
} }
@@ -143,6 +160,129 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
} }
} }
/**
* Saves payment type to Fund source mappings (also populates the changes
* array if passed in)
*
* @param command
* @param element
* @param productId
* @param changes
*/
private void savePaymentChannelToFundSourceMappings(final JsonCommand command, final JsonElement element, final Long productId,
Map<String, Object> changes) {
JsonArray paymentChannelMappingArray = fromApiJsonHelper.extractJsonArrayNamed(
LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element);
if (paymentChannelMappingArray != null) {
if (changes != null) {
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(),
command.jsonFragment(LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue()));
}
for (int i = 0; i < paymentChannelMappingArray.size(); i++) {
final JsonObject jsonObject = paymentChannelMappingArray.get(i).getAsJsonObject();
final Long paymentTypeId = jsonObject.get(LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_TYPE.getValue()).getAsLong();
final Long paymentSpecificFundAccountId = jsonObject.get(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue()).getAsLong();
savePaymentChannelToFundSourceMapping(productId, paymentTypeId, paymentSpecificFundAccountId);
}
}
}
/**
* Finds
*
* @param command
* @param element
* @param productId
* @param changes
*/
private void updatePaymentChannelToFundSourceMappings(final JsonCommand command, final JsonElement element, final Long productId,
Map<String, Object> changes) {
// find all existing payment Channel to Fund source Mappings
List<ProductToGLAccountMapping> existingPaymentChannelToFundSourceMappings = accountMappingRepository
.findAllPaymentTypeToFundSourceMappings(productId, PortfolioProductType.LOAN.getValue());
JsonArray paymentChannelMappingArray = fromApiJsonHelper.extractJsonArrayNamed(
LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element);
/**
* Variable stores a map representation of Payment channels (key) and
* their fund sources (value) extracted from the passed in Jsoncommand
**/
Map<Long, Long> inputPaymentChannelFundSourceMap = new HashMap<Long, Long>();
/***
* Variable stores all payment types which hae already been mapped to
* Fund Sources in the system
**/
Set<Long> existingPaymentTypes = new HashSet<Long>();
if (paymentChannelMappingArray != null) {
if (changes != null) {
changes.put(LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(),
command.jsonFragment(LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue()));
}
for (int i = 0; i < paymentChannelMappingArray.size(); i++) {
final JsonObject jsonObject = paymentChannelMappingArray.get(i).getAsJsonObject();
final Long paymentTypeId = jsonObject.get(LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_TYPE.getValue()).getAsLong();
final Long paymentSpecificFundAccountId = jsonObject.get(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue()).getAsLong();
inputPaymentChannelFundSourceMap.put(paymentTypeId, paymentSpecificFundAccountId);
}
// If input map is empty, delete all existing mappings
if (inputPaymentChannelFundSourceMap.size() == 0) {
accountMappingRepository.deleteInBatch(existingPaymentChannelToFundSourceMappings);
}/**
* Else, <br/>
* update existing mappings OR <br/>
* delete old mappings (which re already present, but not passed in
* as a part of Jsoncommand)<br/>
* Create new mappings for payment types that are passed in as a
* part of the Jsoncommand but not already present
*
**/
else {
for (ProductToGLAccountMapping existingPaymentChannelToFundSourceMapping : existingPaymentChannelToFundSourceMappings) {
Long currentPaymentChannelId = existingPaymentChannelToFundSourceMapping.getId();
existingPaymentTypes.add(currentPaymentChannelId);
// update existing mappings (if required)
if (inputPaymentChannelFundSourceMap.containsKey(existingPaymentChannelToFundSourceMapping.getId())) {
Long newGLAccountId = inputPaymentChannelFundSourceMap.get(existingPaymentChannelToFundSourceMapping.getId());
if (newGLAccountId != existingPaymentChannelToFundSourceMapping.getGlAccount().getId()) {
final GLAccount glAccount = getAccountByIdAndType(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(),
GLAccountType.ASSET, newGLAccountId);
existingPaymentChannelToFundSourceMapping.setGlAccount(glAccount);
accountMappingRepository.save(existingPaymentChannelToFundSourceMapping);
}
}// deleted payment type
else {
accountMappingRepository.delete(existingPaymentChannelToFundSourceMapping);
}
}
// create new mappings
Set<Long> incomingPaymentTypes = inputPaymentChannelFundSourceMap.keySet();
boolean newPaymentTypesAdded = incomingPaymentTypes.removeAll(existingPaymentTypes);
if (newPaymentTypesAdded) {
for (Long newPaymentType : incomingPaymentTypes) {
Long newGLAccountId = inputPaymentChannelFundSourceMap.get(newPaymentType);
savePaymentChannelToFundSourceMapping(productId, newPaymentType, newGLAccountId);
}
}
}
}
}
/**
* @param productId
* @param jsonObject
*/
private void savePaymentChannelToFundSourceMapping(final Long productId, final Long paymentTypeId,
final Long paymentTypeSpecificFundAccountId) {
CodeValue paymentType = codeValueRepositoryWrapper.findOneByCodeNameAndIdWithNotFoundDetection(
PaymentDetailConstants.paymentTypeCodeName, paymentTypeId);
final GLAccount glAccount = getAccountByIdAndType(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), GLAccountType.ASSET,
paymentTypeSpecificFundAccountId);
final ProductToGLAccountMapping accountMapping = new ProductToGLAccountMapping(glAccount, productId,
PortfolioProductType.LOAN.getValue(), CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), paymentType);
this.accountMappingRepository.save(accountMapping);
}
/** /**
* Examines and updates each account mapping for given loan product with * Examines and updates each account mapping for given loan product with
* changes passed in from the Json element * changes passed in from the Json element
@@ -396,8 +536,8 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
// get the existing product // get the existing product
if (accountId != null) { if (accountId != null) {
final ProductToGLAccountMapping accountMapping = this.accountMappingRepository final ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(productId,
.findByProductIdAndProductTypeAndFinancialAccountType(productId, PortfolioProductType.LOAN.getValue(), accountTypeId); PortfolioProductType.LOAN.getValue(), accountTypeId);
if (accountMapping == null) { throw new ProductToGLAccountMappingNotFoundException(PortfolioProductType.LOAN, productId, if (accountMapping == null) { throw new ProductToGLAccountMappingNotFoundException(PortfolioProductType.LOAN, productId,
accountTypeName); } accountTypeName); }
if (accountMapping.getGlAccount().getId() != accountId) { if (accountMapping.getGlAccount().getId() != accountId) {
@@ -411,7 +551,7 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
/** /**
* Fetches account with a particular Id and throws and Exception it is not * Fetches account with a particular Id and throws and Exception it is not
* of the expected Account Category ('DEBIT','CREDIT' etc) * of the expected Account Category ('ASSET','liability' etc)
* *
* @param paramName * @param paramName
* @param expectedAccountType * @param expectedAccountType
@@ -6,8 +6,8 @@
package org.mifosplatform.portfolio.loanaccount.api; package org.mifosplatform.portfolio.loanaccount.api;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
@@ -25,17 +25,17 @@ import org.apache.commons.lang.StringUtils;
import org.mifosplatform.commands.domain.CommandWrapper; import org.mifosplatform.commands.domain.CommandWrapper;
import org.mifosplatform.commands.service.CommandWrapperBuilder; import org.mifosplatform.commands.service.CommandWrapperBuilder;
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService; import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
import org.mifosplatform.infrastructure.codes.service.CodeValueReadPlatformService;
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper; import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamException; import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamException;
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer; import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData; import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData;
import org.mifosplatform.portfolio.loanaccount.domain.PaymentType;
import org.mifosplatform.portfolio.loanaccount.service.LoanReadPlatformService; import org.mifosplatform.portfolio.loanaccount.service.LoanReadPlatformService;
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations; import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -54,17 +54,20 @@ public class LoanTransactionsApiResource {
private final ApiRequestParameterHelper apiRequestParameterHelper; private final ApiRequestParameterHelper apiRequestParameterHelper;
private final DefaultToApiJsonSerializer<LoanTransactionData> toApiJsonSerializer; private final DefaultToApiJsonSerializer<LoanTransactionData> toApiJsonSerializer;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final CodeValueReadPlatformService codeValueReadPlatformService;
@Autowired @Autowired
public LoanTransactionsApiResource(final PlatformSecurityContext context, final LoanReadPlatformService loanReadPlatformService, public LoanTransactionsApiResource(final PlatformSecurityContext context, final LoanReadPlatformService loanReadPlatformService,
final ApiRequestParameterHelper apiRequestParameterHelper, final ApiRequestParameterHelper apiRequestParameterHelper,
final DefaultToApiJsonSerializer<LoanTransactionData> toApiJsonSerializer, final DefaultToApiJsonSerializer<LoanTransactionData> toApiJsonSerializer,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
final CodeValueReadPlatformService codeValueReadPlatformService) {
this.context = context; this.context = context;
this.loanReadPlatformService = loanReadPlatformService; this.loanReadPlatformService = loanReadPlatformService;
this.apiRequestParameterHelper = apiRequestParameterHelper; this.apiRequestParameterHelper = apiRequestParameterHelper;
this.toApiJsonSerializer = toApiJsonSerializer; this.toApiJsonSerializer = toApiJsonSerializer;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
this.codeValueReadPlatformService = codeValueReadPlatformService;
} }
private boolean is(final String commandParam, final String commandValue) { private boolean is(final String commandParam, final String commandValue) {
@@ -113,7 +116,8 @@ public class LoanTransactionsApiResource {
LoanTransactionData transactionData = this.loanReadPlatformService.retrieveLoanTransaction(loanId, transactionId); LoanTransactionData transactionData = this.loanReadPlatformService.retrieveLoanTransaction(loanId, transactionId);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
if (settings.isTemplate()) { if (settings.isTemplate()) {
final List<EnumOptionData> paymentTypeOptions = LoanEnumerations.paymentTypes(PaymentType.values()); final Collection<CodeValueData> paymentTypeOptions = codeValueReadPlatformService
.retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName);
transactionData = LoanTransactionData.templateOnTop(transactionData, paymentTypeOptions); transactionData = LoanTransactionData.templateOnTop(transactionData, paymentTypeOptions);
} }
@@ -6,11 +6,12 @@
package org.mifosplatform.portfolio.loanaccount.data; package org.mifosplatform.portfolio.loanaccount.data;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List; import java.util.Collection;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.codes.data.CodeValueData;
import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.portfolio.paymentdetail.data.PaymentDetailData;
/** /**
* Immutable data object representing a loan transaction. * Immutable data object representing a loan transaction.
@@ -33,9 +34,9 @@ public class LoanTransactionData {
private final BigDecimal penaltyChargesPortion; private final BigDecimal penaltyChargesPortion;
// templates // templates
final List<EnumOptionData> paymentTypeOptions; final Collection<CodeValueData> paymentTypeOptions;
public static LoanTransactionData templateOnTop(LoanTransactionData loanTransactionData, List<EnumOptionData> paymentTypeOptions) { public static LoanTransactionData templateOnTop(LoanTransactionData loanTransactionData, Collection<CodeValueData> paymentTypeOptions) {
return new LoanTransactionData(loanTransactionData.id, loanTransactionData.type, loanTransactionData.paymentDetailData, return new LoanTransactionData(loanTransactionData.id, loanTransactionData.type, loanTransactionData.paymentDetailData,
loanTransactionData.currency, loanTransactionData.date, loanTransactionData.amount, loanTransactionData.principalPortion, loanTransactionData.currency, loanTransactionData.date, loanTransactionData.amount, loanTransactionData.principalPortion,
loanTransactionData.interestPortion, loanTransactionData.feeChargesPortion, loanTransactionData.penaltyChargesPortion, loanTransactionData.interestPortion, loanTransactionData.feeChargesPortion, loanTransactionData.penaltyChargesPortion,
@@ -52,7 +53,7 @@ public class LoanTransactionData {
public LoanTransactionData(final Long id, final LoanTransactionEnumData transactionType, final PaymentDetailData paymentDetailData, public LoanTransactionData(final Long id, final LoanTransactionEnumData transactionType, final PaymentDetailData paymentDetailData,
final CurrencyData currency, final LocalDate date, final BigDecimal amount, final BigDecimal principalPortion, final CurrencyData currency, final LocalDate date, final BigDecimal amount, final BigDecimal principalPortion,
final BigDecimal interestPortion, final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion, final BigDecimal interestPortion, final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion,
final List<EnumOptionData> paymentTypeOptions) { final Collection<CodeValueData> paymentTypeOptions) {
this.id = id; this.id = id;
this.type = transactionType; this.type = transactionType;
this.paymentDetailData = paymentDetailData; this.paymentDetailData = paymentDetailData;
@@ -75,6 +75,7 @@ import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy; import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType; import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations; import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
import org.mifosplatform.useradministration.domain.AppUser; import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.springframework.data.jpa.domain.AbstractPersistable;
@@ -24,8 +24,9 @@ import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money; import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData; import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData;
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData; import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
import org.mifosplatform.portfolio.loanaccount.data.PaymentDetailData;
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations; import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
import org.mifosplatform.portfolio.paymentdetail.data.PaymentDetailData;
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.springframework.data.jpa.domain.AbstractPersistable;
/** /**
@@ -353,6 +354,10 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
thisTransactionData.put("feeChargesPortion", this.feeChargesPortion); thisTransactionData.put("feeChargesPortion", this.feeChargesPortion);
thisTransactionData.put("penaltyChargesPortion", this.penaltyChargesPortion); thisTransactionData.put("penaltyChargesPortion", this.penaltyChargesPortion);
if (this.paymentDetail != null) {
thisTransactionData.put("paymentTypeId", this.paymentDetail.getPaymentType().getId());
}
return thisTransactionData; return thisTransactionData;
} }
@@ -1,128 +0,0 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.loanaccount.domain;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.portfolio.loanaccount.data.PaymentDetailData;
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity
@Table(name = "m_payment_detail")
public final class PaymentDetail extends AbstractPersistable<Long> {
@Column(name = "payment_type_enum", nullable = false)
private Integer paymentType;
@Column(name = "account_number", length = 50)
private String accountNumber;
@Column(name = "check_number", length = 50)
private String checkNumber;
@Column(name = "routing_code", length = 50)
private String routingCode;
@Column(name = "receipt_number", length = 50)
private String receiptNumber;
@Column(name = "bank_number", length = 50)
private String bankNumber;
protected PaymentDetail() {
}
public static PaymentDetail generatePaymentDetail(final JsonCommand command, final Map<String, Object> changes) {
// create a payment detail
final Integer paymentTypeId = command.integerValueSansLocaleOfParameterNamed("paymentTypeId");
if (paymentTypeId == null) { return null; }
changes.put("paymentTypeId", paymentTypeId);
final String accountNumber = command.stringValueOfParameterNamed("accountNumber");
final String checkNumber = command.stringValueOfParameterNamed("checkNumber");
final String routingCode = command.stringValueOfParameterNamed("routingCode");
final String receiptNumber = command.stringValueOfParameterNamed("receiptNumber");
final String bankNumber = command.stringValueOfParameterNamed("bankNumber");
final PaymentType paymentType = PaymentType.fromInt(paymentTypeId);
PaymentDetail paymentDetail = null;
if (paymentType.isCheckPayment()) {
paymentDetail = PaymentDetail.checkPaymentDetail(accountNumber, checkNumber, routingCode);
if (StringUtils.isNotBlank(accountNumber)) {
changes.put("accountNumber", accountNumber);
}
if (StringUtils.isNotBlank(checkNumber)) {
changes.put("checkNumber", checkNumber);
}
if (StringUtils.isNotBlank(routingCode)) {
changes.put("routingCode", routingCode);
}
} else if (paymentType.isEFTPayment()) {
paymentDetail = PaymentDetail.eftPaymentDetail(accountNumber, routingCode);
if (StringUtils.isNotBlank(accountNumber)) {
changes.put("accountNumber", accountNumber);
}
if (StringUtils.isNotBlank(routingCode)) {
changes.put("routingCode", routingCode);
}
} else if (paymentType.isReceiptPayment()) {
paymentDetail = PaymentDetail.receiptPaymentDetail(receiptNumber, bankNumber);
if (StringUtils.isNotBlank(receiptNumber)) {
changes.put("receiptNumber", receiptNumber);
}
if (StringUtils.isNotBlank(bankNumber)) {
changes.put("bankNumber", bankNumber);
}
} else {
paymentDetail = PaymentDetail.cashPaymentDetail();
}
return paymentDetail;
}
public static PaymentDetail cashPaymentDetail() {
return new PaymentDetail(PaymentType.CASH, null, null, null, null, null);
}
public static PaymentDetail checkPaymentDetail(final String accountNumber, final String checkNumber, final String routingCode) {
return new PaymentDetail(PaymentType.CHECK, accountNumber, checkNumber, routingCode, null, null);
}
public static PaymentDetail receiptPaymentDetail(final String receiptNumber, final String bankNumber) {
return new PaymentDetail(PaymentType.RECEIPT, null, null, null, receiptNumber, bankNumber);
}
public static PaymentDetail eftPaymentDetail(final String accountNumber, final String routingCode) {
return new PaymentDetail(PaymentType.ELECTRONIC_FUND_TRANSFER, accountNumber, null, routingCode, null, null);
}
private PaymentDetail(final PaymentType paymentType, final String accountNumber, final String checkNumber, final String routingCode,
final String receiptNumber, final String bankNumber) {
this.paymentType = paymentType.getValue();
this.accountNumber = accountNumber;
this.checkNumber = checkNumber;
this.routingCode = routingCode;
this.receiptNumber = receiptNumber;
this.bankNumber = bankNumber;
}
public PaymentDetailData toData() {
final EnumOptionData paymentTypeData = LoanEnumerations.paymentType(this.paymentType);
final PaymentDetailData paymentDetailData = new PaymentDetailData(getId(), paymentTypeData, this.accountNumber, this.checkNumber,
this.routingCode, this.receiptNumber, this.bankNumber);
return paymentDetailData;
}
}
@@ -1,86 +0,0 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.loanaccount.domain;
import java.util.HashMap;
import java.util.Map;
public enum PaymentType {
CASH(1, "paymentType.cash"), CHECK(2, "paymentType.check"), RECEIPT(3, "paymentType.receipt"), //
ELECTRONIC_FUND_TRANSFER(4, "paymentType.eft");// Electronic Funds Transfer
private final Integer value;
private final String code;
private PaymentType(final Integer value, final String code) {
this.value = value;
this.code = code;
}
public Integer getValue() {
return this.value;
}
public String getCode() {
return this.code;
}
private static final Map<Integer, PaymentType> intToEnumMap = new HashMap<Integer, PaymentType>();
private static int minValue;
private static int maxValue;
static {
int i = 0;
for (final PaymentType type : PaymentType.values()) {
if (i == 0) {
minValue = type.value;
}
intToEnumMap.put(type.value, type);
if (minValue >= type.value) {
minValue = type.value;
}
if (maxValue < type.value) {
maxValue = type.value;
}
i = i + 1;
}
}
public static PaymentType fromInt(final int i) {
final PaymentType type = intToEnumMap.get(Integer.valueOf(i));
return type;
}
public static int getMinValue() {
return minValue;
}
public static int getMaxValue() {
return maxValue;
}
@Override
public String toString() {
return name().toString().replaceAll("_", " ");
}
public boolean isCashPayment() {
return this.value.equals(PaymentType.CASH.value);
}
public boolean isCheckPayment() {
return this.value.equals(PaymentType.CHECK.value);
}
public boolean isReceiptPayment() {
return this.value.equals(PaymentType.RECEIPT.value);
}
public boolean isEFTPayment() {
return this.value.equals(PaymentType.ELECTRONIC_FUND_TRANSFER.value);
}
}
@@ -21,7 +21,6 @@ import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.portfolio.loanaccount.domain.PaymentType;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -102,8 +101,7 @@ public final class LoanEventApiJsonValidator {
private void validatePaymentDetails(final DataValidatorBuilder baseDataValidator, final JsonElement element) { private void validatePaymentDetails(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
// Validate all string payment detail fields for max length // Validate all string payment detail fields for max length
final Integer paymentTypeId = fromApiJsonHelper.extractIntegerWithLocaleNamed("paymentTypeId", element); final Integer paymentTypeId = fromApiJsonHelper.extractIntegerWithLocaleNamed("paymentTypeId", element);
baseDataValidator.reset().parameter("paymentTypeId").value(paymentTypeId) baseDataValidator.reset().parameter("paymentTypeId").value(paymentTypeId).ignoreIfNull().integerGreaterThanZero();
.inMinMaxRange(PaymentType.getMinValue(), PaymentType.getMaxValue());
final Set<String> paymentDetailParameters = new HashSet<String>(Arrays.asList("accountNumber", "checkNumber", "routingCode", final Set<String> paymentDetailParameters = new HashSet<String>(Arrays.asList("accountNumber", "checkNumber", "routingCode",
"receiptNumber", "bankNumber")); "receiptNumber", "bankNumber"));
for (String paymentDetailParameterName : paymentDetailParameters) { for (String paymentDetailParameterName : paymentDetailParameters) {
@@ -11,7 +11,6 @@ import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.joda.time.Days; import org.joda.time.Days;
@@ -50,7 +49,6 @@ import org.mifosplatform.portfolio.loanaccount.data.LoanStatusEnumData;
import org.mifosplatform.portfolio.loanaccount.data.LoanSummaryData; import org.mifosplatform.portfolio.loanaccount.data.LoanSummaryData;
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData; import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData;
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData; import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
import org.mifosplatform.portfolio.loanaccount.data.PaymentDetailData;
import org.mifosplatform.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData; import org.mifosplatform.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
import org.mifosplatform.portfolio.loanaccount.domain.Loan; import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository; import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
@@ -66,6 +64,8 @@ import org.mifosplatform.portfolio.loanproduct.data.TransactionProcessingStrateg
import org.mifosplatform.portfolio.loanproduct.service.LoanDropdownReadPlatformService; import org.mifosplatform.portfolio.loanproduct.service.LoanDropdownReadPlatformService;
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations; import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
import org.mifosplatform.portfolio.loanproduct.service.LoanProductReadPlatformService; import org.mifosplatform.portfolio.loanproduct.service.LoanProductReadPlatformService;
import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants;
import org.mifosplatform.portfolio.paymentdetail.data.PaymentDetailData;
import org.mifosplatform.useradministration.domain.AppUser; import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
@@ -92,10 +92,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
private final ChargeReadPlatformService chargeReadPlatformService; private final ChargeReadPlatformService chargeReadPlatformService;
private final CodeValueReadPlatformService codeValueReadPlatformService; private final CodeValueReadPlatformService codeValueReadPlatformService;
private final CalendarReadPlatformService calendarReadPlatformService; private final CalendarReadPlatformService calendarReadPlatformService;
private final PaginationHelper<LoanAccountData> paginationHelper = new PaginationHelper<LoanAccountData>(); private final PaginationHelper<LoanAccountData> paginationHelper = new PaginationHelper<LoanAccountData>();
private final LoanMapper loaanLoanMapper = new LoanMapper(); private final LoanMapper loaanLoanMapper = new LoanMapper();
@Autowired @Autowired
public LoanReadPlatformServiceImpl(final PlatformSecurityContext context, final LoanRepository loanRepository, public LoanReadPlatformServiceImpl(final PlatformSecurityContext context, final LoanRepository loanRepository,
final LoanTransactionRepository loanTransactionRepository, final LoanTransactionRepository loanTransactionRepository,
@@ -313,7 +313,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final Money possibleNextRepaymentAmount = loan.possibleNextRepaymentAmount(); final Money possibleNextRepaymentAmount = loan.possibleNextRepaymentAmount();
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.REPAYMENT); final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.REPAYMENT);
final List<EnumOptionData> paymentOptions = loanDropdownReadPlatformService.retrievePaymentTypeOptions(); final Collection<CodeValueData> paymentOptions = codeValueReadPlatformService
.retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName);
return new LoanTransactionData(null, transactionType, null, currencyData, earliestUnpaidInstallmentDate, return new LoanTransactionData(null, transactionType, null, currencyData, earliestUnpaidInstallmentDate,
possibleNextRepaymentAmount.getAmount(), null, null, null, null, paymentOptions); possibleNextRepaymentAmount.getAmount(), null, null, null, null, paymentOptions);
} }
@@ -356,7 +357,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final Loan loan = this.loanRepository.findOne(loanId); final Loan loan = this.loanRepository.findOne(loanId);
if (loan == null) { throw new LoanNotFoundException(loanId); } if (loan == null) { throw new LoanNotFoundException(loanId); }
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.DISBURSEMENT); final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.DISBURSEMENT);
final List<EnumOptionData> paymentOptions = loanDropdownReadPlatformService.retrievePaymentTypeOptions(); final Collection<CodeValueData> paymentOptions = codeValueReadPlatformService
.retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName);
return new LoanTransactionData(null, transactionType, null, null, loan.getExpectedDisbursedOnLocalDate(), null, null, null, null, return new LoanTransactionData(null, transactionType, null, null, loan.getExpectedDisbursedOnLocalDate(), null, null, null, null,
null, paymentOptions); null, paymentOptions);
} }
@@ -806,13 +808,14 @@ 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, " 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.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.fee_charges_portion_derived as fees, tr.penalty_charges_portion_derived as penalties, "
+ " pd.payment_type_enum as paymentType,pd.account_number as accountNumber,pd.check_number as checkNumber, " + " 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, " + " 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, rc.`name` as currencyName, " + " l.currency_code as currencyCode, l.currency_digits as currencyDigits, rc.`name` as currencyName, "
+ " rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode " + " rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, "
+ " from m_loan l join m_loan_transaction tr on tr.loan_id = l.id" + " cv.code_value as paymentTypeName " + " from m_loan l join m_loan_transaction tr on tr.loan_id = l.id"
+ " join m_currency rc on rc.`code` = l.currency_code " + " join m_currency rc on rc.`code` = l.currency_code "
+ " left JOIN m_payment_detail pd ON tr.payment_detail_id = pd.id"; + " left JOIN m_payment_detail pd ON tr.payment_detail_id = pd.id"
+ " left join m_code_value cv on pd.payment_type_cv_id = cv.id";
} }
@Override @Override
@@ -833,9 +836,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
PaymentDetailData paymentDetailData = null; PaymentDetailData paymentDetailData = null;
if (transactionType.isPaymentOrReceipt()) { if (transactionType.isPaymentOrReceipt()) {
final Integer paymentTypeId = JdbcSupport.getInteger(rs, "paymentType"); final Long paymentTypeId = JdbcSupport.getLong(rs, "paymentType");
if (paymentTypeId != null) { if (paymentTypeId != null) {
EnumOptionData paymentType = LoanEnumerations.paymentType(paymentTypeId); final String typeName = rs.getString("paymentTypeName");
CodeValueData paymentType = CodeValueData.instance(paymentTypeId, typeName);
final String accountNumber = rs.getString("accountNumber"); final String accountNumber = rs.getString("accountNumber");
final String checkNumber = rs.getString("checkNumber"); final String checkNumber = rs.getString("checkNumber");
final String routingCode = rs.getString("routingCode"); final String routingCode = rs.getString("routingCode");
@@ -860,6 +864,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
@Override @Override
public LoanAccountData retrieveLoanProductDetailsTemplate(final Long productId) { public LoanAccountData retrieveLoanProductDetailsTemplate(final Long productId) {
context.authenticatedUser(); context.authenticatedUser();
final LoanProductData loanProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId); final LoanProductData loanProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId);
@@ -57,8 +57,6 @@ import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
import org.mifosplatform.portfolio.loanaccount.domain.LoanSummaryWrapper; import org.mifosplatform.portfolio.loanaccount.domain.LoanSummaryWrapper;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction; import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionRepository; import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionRepository;
import org.mifosplatform.portfolio.loanaccount.domain.PaymentDetail;
import org.mifosplatform.portfolio.loanaccount.domain.PaymentDetailRepository;
import org.mifosplatform.portfolio.loanaccount.exception.LoanApplicationDateException; import org.mifosplatform.portfolio.loanaccount.exception.LoanApplicationDateException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanNotFoundException; import org.mifosplatform.portfolio.loanaccount.exception.LoanNotFoundException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerAssignmentException; import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerAssignmentException;
@@ -69,6 +67,8 @@ import org.mifosplatform.portfolio.loanaccount.serialization.LoanUpdateCommandFr
import org.mifosplatform.portfolio.loanproduct.exception.InvalidCurrencyException; import org.mifosplatform.portfolio.loanproduct.exception.InvalidCurrencyException;
import org.mifosplatform.portfolio.note.domain.Note; import org.mifosplatform.portfolio.note.domain.Note;
import org.mifosplatform.portfolio.note.domain.NoteRepository; import org.mifosplatform.portfolio.note.domain.NoteRepository;
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
import org.mifosplatform.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
import org.mifosplatform.useradministration.domain.AppUser; import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -91,8 +91,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final JournalEntryWritePlatformService journalEntryWritePlatformService; private final JournalEntryWritePlatformService journalEntryWritePlatformService;
private final LoanSummaryWrapper loanSummaryWrapper; private final LoanSummaryWrapper loanSummaryWrapper;
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory; private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
private final PaymentDetailRepository paymentDetailRepository;
private final CalendarInstanceRepository calendarInstanceRepository; private final CalendarInstanceRepository calendarInstanceRepository;
private final PaymentDetailWritePlatformService paymentDetailWritePlatformService;
@Autowired @Autowired
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -103,7 +103,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LoanChargeRepository loanChargeRepository, final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository, final LoanChargeRepository loanChargeRepository, final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
final JournalEntryWritePlatformService journalEntryWritePlatformService, final LoanSummaryWrapper loanSummaryWrapper, final JournalEntryWritePlatformService journalEntryWritePlatformService, final LoanSummaryWrapper loanSummaryWrapper,
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory, final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
final PaymentDetailRepository paymentDetailRepository, final CalendarInstanceRepository calendarInstanceRepository) { final CalendarInstanceRepository calendarInstanceRepository,
final PaymentDetailWritePlatformService paymentDetailWritePlatformService) {
this.context = context; this.context = context;
this.loanEventApiJsonValidator = loanEventApiJsonValidator; this.loanEventApiJsonValidator = loanEventApiJsonValidator;
this.loanAssembler = loanAssembler; this.loanAssembler = loanAssembler;
@@ -117,8 +118,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.loanUpdateCommandFromApiJsonDeserializer = loanUpdateCommandFromApiJsonDeserializer; this.loanUpdateCommandFromApiJsonDeserializer = loanUpdateCommandFromApiJsonDeserializer;
this.loanSummaryWrapper = loanSummaryWrapper; this.loanSummaryWrapper = loanSummaryWrapper;
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory; this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
this.paymentDetailRepository = paymentDetailRepository;
this.calendarInstanceRepository = calendarInstanceRepository; this.calendarInstanceRepository = calendarInstanceRepository;
this.paymentDetailWritePlatformService = paymentDetailWritePlatformService;
} }
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() { private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
@@ -136,8 +137,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final Loan loan = retrieveLoanBy(loanId); final Loan loan = retrieveLoanBy(loanId);
//validate actual disbursement date against meeting date // validate actual disbursement date against meeting date
Collection<CalendarInstance> calendarInstances = this.calendarInstanceRepository.findByEntityIdAndEntityTypeId(loan.getId(), CalendarEntityType.LOANS.getValue()); Collection<CalendarInstance> calendarInstances = this.calendarInstanceRepository.findByEntityIdAndEntityTypeId(loan.getId(),
CalendarEntityType.LOANS.getValue());
validateDisbursementDate(command.localDateValueOfParameterNamed("actualDisbursementDate"), calendarInstances); validateDisbursementDate(command.localDateValueOfParameterNamed("actualDisbursementDate"), calendarInstances);
final MonetaryCurrency currency = loan.getCurrency(); final MonetaryCurrency currency = loan.getCurrency();
@@ -147,10 +149,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final List<Long> existingReversedTransactionIds = new ArrayList<Long>(); final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
final Map<String, Object> changes = new LinkedHashMap<String, Object>(); final Map<String, Object> changes = new LinkedHashMap<String, Object>();
PaymentDetail paymentDetail = PaymentDetail.generatePaymentDetail(command, changes);
if (paymentDetail != null) { PaymentDetail paymentDetail = paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes);
paymentDetailRepository.save(paymentDetail);
}
loan.disburse(currentUser, command, applicationCurrency, existingTransactionIds, existingReversedTransactionIds, changes, loan.disburse(currentUser, command, applicationCurrency, existingTransactionIds, existingReversedTransactionIds, changes,
paymentDetail); paymentDetail);
@@ -192,13 +192,14 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (disbursementDate.isBefore(calendar.getStartDateLocalDate())) { if (disbursementDate.isBefore(calendar.getStartDateLocalDate())) {
final String errorMessage = "Actual disbursement date '" + disbursementDate.toString() final String errorMessage = "Actual disbursement date '" + disbursementDate.toString()
+ "' cannot be before meeting start date '" + calendar.getStartDate().toString() + "' "; + "' cannot be before meeting start date '" + calendar.getStartDate().toString() + "' ";
throw new LoanApplicationDateException("actual.disbursement.date.cannot.be.before.meeting.start.date", errorMessage, disbursementDate.toString(), throw new LoanApplicationDateException("actual.disbursement.date.cannot.be.before.meeting.start.date", errorMessage,
calendar.getStartDate()); disbursementDate.toString(), calendar.getStartDate());
} }
// Disbursement date should fall on a meeting date // Disbursement date should fall on a meeting date
if (!CalendarHelper.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), disbursementDate)) { if (!CalendarHelper.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), disbursementDate)) {
final String errorMessage = "Expected disbursement date '" + disbursementDate.toString() + "' does not fall on a meeting date."; final String errorMessage = "Expected disbursement date '" + disbursementDate.toString()
+ "' does not fall on a meeting date.";
throw new NotValidRecurringDateException("loan.actual.disbursement.date", errorMessage, disbursementDate.toString(), throw new NotValidRecurringDateException("loan.actual.disbursement.date", errorMessage, disbursementDate.toString(),
calendar.getTitle()); calendar.getTitle());
} }
@@ -231,10 +232,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final List<Long> existingTransactionIds = new ArrayList<Long>(); final List<Long> existingTransactionIds = new ArrayList<Long>();
final List<Long> existingReversedTransactionIds = new ArrayList<Long>(); final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
PaymentDetail paymentDetail = PaymentDetail.generatePaymentDetail(command, changes); PaymentDetail paymentDetail = paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes);
if (paymentDetail != null) {
paymentDetailRepository.save(paymentDetail);
}
loan.disburse(currentUser, command, applicationCurrency, existingTransactionIds, existingReversedTransactionIds, changes, loan.disburse(currentUser, command, applicationCurrency, existingTransactionIds, existingReversedTransactionIds, changes,
paymentDetail); paymentDetail);
@@ -314,10 +312,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
changes.put("note", noteText); changes.put("note", noteText);
} }
PaymentDetail paymentDetail = PaymentDetail.generatePaymentDetail(command, changes); PaymentDetail paymentDetail = paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes);
if (paymentDetail != null) {
paymentDetailRepository.save(paymentDetail);
}
CommandProcessingResultBuilder commandProcessingResultBuilder = saveLoanRepayment(loanId, paymentDetail, transactionAmount, CommandProcessingResultBuilder commandProcessingResultBuilder = saveLoanRepayment(loanId, paymentDetail, transactionAmount,
transactionDate, noteText); transactionDate, noteText);
@@ -418,7 +414,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final List<Long> existingReversedTransactionIds = new ArrayList<Long>(); final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
final Money transactionAmountAsMoney = Money.of(loan.getCurrency(), transactionAmount); final Money transactionAmountAsMoney = Money.of(loan.getCurrency(), transactionAmount);
PaymentDetail paymentDetail = PaymentDetail.generatePaymentDetail(command, changes); PaymentDetail paymentDetail = paymentDetailWritePlatformService.createPaymentDetail(command, changes);
LoanTransaction newTransactionDetail = LoanTransaction.repayment(transactionAmountAsMoney, paymentDetail, transactionDate); LoanTransaction newTransactionDetail = LoanTransaction.repayment(transactionAmountAsMoney, paymentDetail, transactionDate);
if (transactionToAdjust.isInterestWaiver()) { if (transactionToAdjust.isInterestWaiver()) {
newTransactionDetail = LoanTransaction.waiver(loan, transactionAmountAsMoney, transactionDate); newTransactionDetail = LoanTransaction.waiver(loan, transactionAmountAsMoney, transactionDate);
@@ -429,7 +425,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (newTransactionDetail.isGreaterThanZero(loan.getPrincpal().getCurrency())) { if (newTransactionDetail.isGreaterThanZero(loan.getPrincpal().getCurrency())) {
if (paymentDetail != null) { if (paymentDetail != null) {
paymentDetailRepository.save(paymentDetail); paymentDetailWritePlatformService.persistPaymentDetail(paymentDetail);
} }
this.loanTransactionRepository.save(newTransactionDetail); this.loanTransactionRepository.save(newTransactionDetail);
} }
@@ -31,6 +31,8 @@ import org.mifosplatform.accounting.producttoaccountmapping.service.ProductToGLA
import org.mifosplatform.commands.domain.CommandWrapper; import org.mifosplatform.commands.domain.CommandWrapper;
import org.mifosplatform.commands.service.CommandWrapperBuilder; import org.mifosplatform.commands.service.CommandWrapperBuilder;
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService; import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
import org.mifosplatform.infrastructure.codes.service.CodeValueReadPlatformService;
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper; import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.data.EnumOptionData;
@@ -47,6 +49,7 @@ import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
import org.mifosplatform.portfolio.loanproduct.data.TransactionProcessingStrategyData; import org.mifosplatform.portfolio.loanproduct.data.TransactionProcessingStrategyData;
import org.mifosplatform.portfolio.loanproduct.service.LoanDropdownReadPlatformService; import org.mifosplatform.portfolio.loanproduct.service.LoanDropdownReadPlatformService;
import org.mifosplatform.portfolio.loanproduct.service.LoanProductReadPlatformService; import org.mifosplatform.portfolio.loanproduct.service.LoanProductReadPlatformService;
import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -61,10 +64,10 @@ public class LoanProductsApiResource {
"maxNumberOfRepayments", "repaymentEvery", "repaymentFrequencyType", "interestRatePerPeriod", "minInterestRatePerPeriod", "maxNumberOfRepayments", "repaymentEvery", "repaymentFrequencyType", "interestRatePerPeriod", "minInterestRatePerPeriod",
"maxInterestRatePerPeriod", "interestRateFrequencyType", "annualInterestRate", "amortizationType", "interestType", "maxInterestRatePerPeriod", "interestRateFrequencyType", "annualInterestRate", "amortizationType", "interestType",
"interestCalculationPeriodType", "inArrearsTolerance", "transactionProcessingStrategyId", "transactionProcessingStrategyName", "interestCalculationPeriodType", "inArrearsTolerance", "transactionProcessingStrategyId", "transactionProcessingStrategyName",
"charges", "accountingRule", "accountingMappings", "fundOptions", "currencyOptions", "repaymentFrequencyTypeOptions", "charges", "accountingRule", "accountingMappings", "paymentChannelToFundSourceMappings", "fundOptions", "paymentTypeOptions",
"interestRateFrequencyTypeOptions", "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", "currencyOptions", "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "amortizationTypeOptions",
"transactionProcessingStrategyOptions", "chargeOptions", "accountingOptions", "accountingRuleOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", "transactionProcessingStrategyOptions", "chargeOptions",
"accountingMappingOptions")); "accountingOptions", "accountingRuleOptions", "accountingMappingOptions"));
private final String resourceNameForPermissions = "LOANPRODUCT"; private final String resourceNameForPermissions = "LOANPRODUCT";
@@ -79,6 +82,7 @@ public class LoanProductsApiResource {
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final GLAccountReadPlatformService accountReadPlatformService; private final GLAccountReadPlatformService accountReadPlatformService;
private final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService; private final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService;
private final CodeValueReadPlatformService codeValueReadPlatformService;
@Autowired @Autowired
public LoanProductsApiResource(final PlatformSecurityContext context, final LoanProductReadPlatformService readPlatformService, public LoanProductsApiResource(final PlatformSecurityContext context, final LoanProductReadPlatformService readPlatformService,
@@ -88,7 +92,8 @@ public class LoanProductsApiResource {
final ApiRequestParameterHelper apiRequestParameterHelper, final ApiRequestParameterHelper apiRequestParameterHelper,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService, final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
final GLAccountReadPlatformService accountReadPlatformService, final GLAccountReadPlatformService accountReadPlatformService,
final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService) { final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService,
final CodeValueReadPlatformService codeValueReadPlatformService) {
this.context = context; this.context = context;
this.loanProductReadPlatformService = readPlatformService; this.loanProductReadPlatformService = readPlatformService;
this.chargeReadPlatformService = chargeReadPlatformService; this.chargeReadPlatformService = chargeReadPlatformService;
@@ -100,6 +105,7 @@ public class LoanProductsApiResource {
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
this.accountReadPlatformService = accountReadPlatformService; this.accountReadPlatformService = accountReadPlatformService;
this.accountMappingReadPlatformService = accountMappingReadPlatformService; this.accountMappingReadPlatformService = accountMappingReadPlatformService;
this.codeValueReadPlatformService = codeValueReadPlatformService;
} }
@POST @POST
@@ -136,7 +142,7 @@ public class LoanProductsApiResource {
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions); context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
LoanProductData loanProduct = this.loanProductReadPlatformService.retrieveNewLoanProductDetails(); LoanProductData loanProduct = this.loanProductReadPlatformService.retrieveNewLoanProductDetails();
loanProduct = handleTemplate(loanProduct, new HashMap<String, Object>()); loanProduct = handleTemplate(loanProduct, new HashMap<String, Object>(), null);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, loanProduct, LOAN_PRODUCT_DATA_PARAMETERS); return this.toApiJsonSerializer.serialize(settings, loanProduct, LOAN_PRODUCT_DATA_PARAMETERS);
@@ -155,14 +161,17 @@ public class LoanProductsApiResource {
LoanProductData loanProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId); LoanProductData loanProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId);
Map<String, Object> accountingMappings = null; Map<String, Object> accountingMappings = null;
Map<Long, Long> paymentChannelToFundSourceMappings = null;
if (loanProduct.hasAccountingEnabled()) { if (loanProduct.hasAccountingEnabled()) {
accountingMappings = accountMappingReadPlatformService.fetchAccountMappingDetailsForLoanProduct(productId, loanProduct accountingMappings = accountMappingReadPlatformService.fetchAccountMappingDetailsForLoanProduct(productId, loanProduct
.accountingRuleType().getId().intValue()); .accountingRuleType().getId().intValue());
loanProduct = LoanProductData.withAccountingMappings(loanProduct, accountingMappings); paymentChannelToFundSourceMappings = accountMappingReadPlatformService
.fetchPaymentTypeToFundSourceMappingsForLoanProduct(productId);
loanProduct = LoanProductData.withAccountingDetails(loanProduct, accountingMappings, paymentChannelToFundSourceMappings);
} }
if (settings.isTemplate()) { if (settings.isTemplate()) {
loanProduct = handleTemplate(loanProduct, accountingMappings); loanProduct = handleTemplate(loanProduct, accountingMappings, paymentChannelToFundSourceMappings);
} }
return this.toApiJsonSerializer.serialize(settings, loanProduct, LOAN_PRODUCT_DATA_PARAMETERS); return this.toApiJsonSerializer.serialize(settings, loanProduct, LOAN_PRODUCT_DATA_PARAMETERS);
} }
@@ -181,7 +190,8 @@ public class LoanProductsApiResource {
return this.toApiJsonSerializer.serialize(result); return this.toApiJsonSerializer.serialize(result);
} }
private LoanProductData handleTemplate(final LoanProductData productData, final Map<String, Object> accountingMappings) { private LoanProductData handleTemplate(final LoanProductData productData, final Map<String, Object> accountingMappings,
final Map<Long, Long> paymentChannelToFundSourceMappings) {
final boolean feeChargesOnly = true; final boolean feeChargesOnly = true;
Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly); Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly);
@@ -197,6 +207,8 @@ public class LoanProductsApiResource {
final List<EnumOptionData> repaymentFrequencyTypeOptions = dropdownReadPlatformService.retrieveRepaymentFrequencyTypeOptions(); final List<EnumOptionData> repaymentFrequencyTypeOptions = dropdownReadPlatformService.retrieveRepaymentFrequencyTypeOptions();
final List<EnumOptionData> interestRateFrequencyTypeOptions = dropdownReadPlatformService final List<EnumOptionData> interestRateFrequencyTypeOptions = dropdownReadPlatformService
.retrieveInterestRateFrequencyTypeOptions(); .retrieveInterestRateFrequencyTypeOptions();
final Collection<CodeValueData> paymentTypeOptions = codeValueReadPlatformService
.retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName);
Collection<FundData> fundOptions = this.fundReadPlatformService.retrieveAllFunds(); Collection<FundData> fundOptions = this.fundReadPlatformService.retrieveAllFunds();
if (fundOptions.isEmpty()) { if (fundOptions.isEmpty()) {
@@ -226,8 +238,9 @@ public class LoanProductsApiResource {
List<EnumOptionData> accountingRuleTypeOptions = dropdownReadPlatformService.retrieveAccountingRuleTypeOptions(); List<EnumOptionData> accountingRuleTypeOptions = dropdownReadPlatformService.retrieveAccountingRuleTypeOptions();
return new LoanProductData(productData, chargeOptions, currencyOptions, amortizationTypeOptions, interestTypeOptions, return new LoanProductData(productData, chargeOptions, paymentTypeOptions, currencyOptions, amortizationTypeOptions,
interestCalculationPeriodTypeOptions, repaymentFrequencyTypeOptions, interestRateFrequencyTypeOptions, fundOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, repaymentFrequencyTypeOptions, interestRateFrequencyTypeOptions,
transactionProcessingStrategyOptions, accountOptions, accountingRuleTypeOptions, accountingMappings); fundOptions, transactionProcessingStrategyOptions, accountOptions, accountingRuleTypeOptions, accountingMappings,
paymentChannelToFundSourceMappings);
} }
} }
@@ -12,6 +12,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.mifosplatform.accounting.glaccount.data.GLAccountData; import org.mifosplatform.accounting.glaccount.data.GLAccountData;
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.portfolio.charge.data.ChargeData; import org.mifosplatform.portfolio.charge.data.ChargeData;
@@ -65,9 +66,12 @@ public class LoanProductData {
private final EnumOptionData accountingRule; private final EnumOptionData accountingRule;
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final Map<String, Object> accountingMappings; private final Map<String, Object> accountingMappings;
@SuppressWarnings("unused")
private final Map<Long, Long> paymentChannelToFundSourceMappings;
// template related // template related
private final Collection<FundData> fundOptions; private final Collection<FundData> fundOptions;
private final Collection<CodeValueData> paymentTypeOptions;
private final Collection<CurrencyData> currencyOptions; private final Collection<CurrencyData> currencyOptions;
private final List<EnumOptionData> repaymentFrequencyTypeOptions; private final List<EnumOptionData> repaymentFrequencyTypeOptions;
private final List<EnumOptionData> interestRateFrequencyTypeOptions; private final List<EnumOptionData> interestRateFrequencyTypeOptions;
@@ -186,13 +190,14 @@ public class LoanProductData {
transactionProcessingStrategyName, charges, accountingType); transactionProcessingStrategyName, charges, accountingType);
} }
public static LoanProductData withAccountingMappings(final LoanProductData productData, final Map<String, Object> accountingMappings) { public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map<String, Object> accountingMappings,
final Map<Long, Long> paymentChannelToFundSourceMappings) {
return new LoanProductData(productData, productData.chargeOptions, productData.currencyOptions, return new LoanProductData(productData, productData.chargeOptions, productData.paymentTypeOptions, productData.currencyOptions,
productData.amortizationTypeOptions, productData.interestTypeOptions, productData.interestCalculationPeriodTypeOptions, productData.amortizationTypeOptions, productData.interestTypeOptions, productData.interestCalculationPeriodTypeOptions,
productData.repaymentFrequencyTypeOptions, productData.interestRateFrequencyTypeOptions, productData.fundOptions, productData.repaymentFrequencyTypeOptions, productData.interestRateFrequencyTypeOptions, productData.fundOptions,
productData.transactionProcessingStrategyOptions, productData.accountingMappingOptions, productData.accountingRuleOptions, productData.transactionProcessingStrategyOptions, productData.accountingMappingOptions, productData.accountingRuleOptions,
accountingMappings); accountingMappings, paymentChannelToFundSourceMappings);
} }
public LoanProductData(final Long id, final String name, final String description, final CurrencyData currency, public LoanProductData(final Long id, final String name, final String description, final CurrencyData currency,
@@ -242,6 +247,7 @@ public class LoanProductData {
this.accountingRule = accountingType; this.accountingRule = accountingType;
this.chargeOptions = null; this.chargeOptions = null;
this.paymentTypeOptions = null;
this.currencyOptions = null; this.currencyOptions = null;
this.fundOptions = null; this.fundOptions = null;
this.transactionProcessingStrategyOptions = null; this.transactionProcessingStrategyOptions = null;
@@ -254,15 +260,17 @@ public class LoanProductData {
this.accountingMappingOptions = null; this.accountingMappingOptions = null;
this.accountingRuleOptions = null; this.accountingRuleOptions = null;
this.accountingMappings = null; this.accountingMappings = null;
this.paymentChannelToFundSourceMappings = null;
} }
public LoanProductData(final LoanProductData productData, final Collection<ChargeData> chargeOptions, public LoanProductData(final LoanProductData productData, final Collection<ChargeData> chargeOptions,
final Collection<CurrencyData> currencyOptions, final List<EnumOptionData> amortizationTypeOptions, final Collection<CodeValueData> paymentTypeOptions, final Collection<CurrencyData> currencyOptions,
final List<EnumOptionData> interestTypeOptions, final List<EnumOptionData> interestCalculationPeriodTypeOptions, final List<EnumOptionData> amortizationTypeOptions, final List<EnumOptionData> interestTypeOptions,
final List<EnumOptionData> repaymentFrequencyTypeOptions, final List<EnumOptionData> interestRateFrequencyTypeOptions, final List<EnumOptionData> interestCalculationPeriodTypeOptions, final List<EnumOptionData> repaymentFrequencyTypeOptions,
final Collection<FundData> fundOptions, final Collection<TransactionProcessingStrategyData> transactionStrategyOptions, final List<EnumOptionData> interestRateFrequencyTypeOptions, final Collection<FundData> fundOptions,
final Collection<TransactionProcessingStrategyData> transactionStrategyOptions,
final Map<String, List<GLAccountData>> accountingMappingOptions, final List<EnumOptionData> accountingRuleOptions, final Map<String, List<GLAccountData>> accountingMappingOptions, final List<EnumOptionData> accountingRuleOptions,
final Map<String, Object> accountingMappings) { final Map<String, Object> accountingMappings, final Map<Long, Long> paymentChannelToFundSourceMappings) {
this.id = productData.id; this.id = productData.id;
this.name = productData.name; this.name = productData.name;
this.description = productData.description; this.description = productData.description;
@@ -291,6 +299,7 @@ public class LoanProductData {
this.accountingRule = productData.accountingRule; this.accountingRule = productData.accountingRule;
this.chargeOptions = chargeOptions; this.chargeOptions = chargeOptions;
this.paymentTypeOptions = paymentTypeOptions;
this.currencyOptions = currencyOptions; this.currencyOptions = currencyOptions;
this.currency = productData.currency; this.currency = productData.currency;
this.fundOptions = fundOptions; this.fundOptions = fundOptions;
@@ -320,6 +329,8 @@ public class LoanProductData {
} else { } else {
this.accountingMappings = accountingMappings; this.accountingMappings = accountingMappings;
} }
this.paymentChannelToFundSourceMappings = paymentChannelToFundSourceMappings;
} }
private Collection<ChargeData> nullIfEmpty(final Collection<ChargeData> charges) { private Collection<ChargeData> nullIfEmpty(final Collection<ChargeData> charges) {
@@ -27,7 +27,9 @@ import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
@Component @Component
@@ -45,7 +47,8 @@ public final class LoanProductCommandFromApiJsonDeserializer {
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.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.INTEREST_ON_LOANS.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue())); LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue()));
private final FromJsonHelper fromApiJsonHelper; private final FromJsonHelper fromApiJsonHelper;
@@ -250,6 +253,8 @@ public final class LoanProductCommandFromApiJsonDeserializer {
baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue()).value(writeOffAccountId) baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue()).value(writeOffAccountId)
.notNull().integerGreaterThanZero(); .notNull().integerGreaterThanZero();
validatePaymentChannelFundSourceMappings(baseDataValidator, element);
} }
if (isAccrualBasedAccounting(accountingRuleType)) { if (isAccrualBasedAccounting(accountingRuleType)) {
@@ -461,11 +466,48 @@ public final class LoanProductCommandFromApiJsonDeserializer {
baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue()) baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue())
.value(receivablePenaltyAccountId).ignoreIfNull().integerGreaterThanZero(); .value(receivablePenaltyAccountId).ignoreIfNull().integerGreaterThanZero();
validatePaymentChannelFundSourceMappings(baseDataValidator, element);
validateMinMaxConstraints(element, baseDataValidator, loanProduct); validateMinMaxConstraints(element, baseDataValidator, loanProduct);
throwExceptionIfValidationWarningsExist(dataValidationErrors); throwExceptionIfValidationWarningsExist(dataValidationErrors);
} }
/**
* Validation for advanced accounting options
*
* @param baseDataValidator
* @param element
*/
private void validatePaymentChannelFundSourceMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
if (fromApiJsonHelper.parameterExists(LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element)) {
JsonArray paymentChannelMappingArray = fromApiJsonHelper.extractJsonArrayNamed(
LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element);
if (paymentChannelMappingArray != null) {
int i = 0;
do {
final JsonObject jsonObject = paymentChannelMappingArray.get(i).getAsJsonObject();
final Long paymentTypeId = jsonObject.get(LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_TYPE.getValue()).getAsLong();
final Long paymentSpecificFundAccountId = jsonObject.get(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue())
.getAsLong();
baseDataValidator
.reset()
.parameter(
LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue() + "[" + i + "]."
+ LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_TYPE.toString()).value(paymentTypeId).notNull()
.integerGreaterThanZero();
baseDataValidator
.reset()
.parameter(
LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue() + "[" + i + "]."
+ LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue()).value(paymentSpecificFundAccountId)
.notNull().integerGreaterThanZero();
i++;
} while (i < paymentChannelMappingArray.size());
}
}
}
public void validateMinMaxConstraints(final JsonElement element, final DataValidatorBuilder baseDataValidator, public void validateMinMaxConstraints(final JsonElement element, final DataValidatorBuilder baseDataValidator,
final LoanProduct loanProduct) { final LoanProduct loanProduct) {
@@ -29,5 +29,4 @@ public interface LoanDropdownReadPlatformService {
List<EnumOptionData> retrieveAccountingRuleTypeOptions(); List<EnumOptionData> retrieveAccountingRuleTypeOptions();
List<EnumOptionData> retrievePaymentTypeOptions();
} }
@@ -5,13 +5,13 @@
*/ */
package org.mifosplatform.portfolio.loanproduct.service; package org.mifosplatform.portfolio.loanproduct.service;
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.accountingRuleType;
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.amortizationType; import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.amortizationType;
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.interestCalculationPeriodType; import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.interestCalculationPeriodType;
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.interestRateFrequencyType; import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.interestRateFrequencyType;
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.interestType; import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.interestType;
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.loanTermFrequencyType; import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.loanTermFrequencyType;
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.repaymentFrequencyType; import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.repaymentFrequencyType;
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.accountingRuleType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -20,7 +20,6 @@ import java.util.List;
import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionProcessingStrategyRepository; import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionProcessingStrategyRepository;
import org.mifosplatform.portfolio.loanaccount.domain.PaymentType;
import org.mifosplatform.portfolio.loanproduct.data.TransactionProcessingStrategyData; import org.mifosplatform.portfolio.loanproduct.data.TransactionProcessingStrategyData;
import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType; import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType;
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod; import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
@@ -111,8 +110,4 @@ public class LoanDropdownReadPlatformServiceImpl implements LoanDropdownReadPlat
return accountingRuleTypeOptions; return accountingRuleTypeOptions;
} }
@Override
public List<EnumOptionData> retrievePaymentTypeOptions() {
return LoanEnumerations.paymentTypes(PaymentType.values());
}
} }
@@ -5,16 +5,12 @@
*/ */
package org.mifosplatform.portfolio.loanproduct.service; package org.mifosplatform.portfolio.loanproduct.service;
import java.util.ArrayList;
import java.util.List;
import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.portfolio.loanaccount.data.LoanStatusEnumData; import org.mifosplatform.portfolio.loanaccount.data.LoanStatusEnumData;
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData; import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData;
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus; import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionType; import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionType;
import org.mifosplatform.portfolio.loanaccount.domain.LoanType; import org.mifosplatform.portfolio.loanaccount.domain.LoanType;
import org.mifosplatform.portfolio.loanaccount.domain.PaymentType;
import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType; import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType;
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod; import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod; import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
@@ -49,8 +45,6 @@ public class LoanEnumerations {
return interestType(id); return interestType(id);
} else if (typeName.equals(INTEREST_CALCULATION_PERIOD_TYPE)) { } else if (typeName.equals(INTEREST_CALCULATION_PERIOD_TYPE)) {
return interestCalculationPeriodType(id); return interestCalculationPeriodType(id);
} else if (typeName.equals(PAYMENT_TYPE)) {
return paymentType(id);
} else if (typeName.equals(ACCOUNTING_RULE_TYPE)) { } else if (typeName.equals(ACCOUNTING_RULE_TYPE)) {
return accountingRuleType(id); return accountingRuleType(id);
} else if (typeName.equals(LOAN_TYPE)) { return loanType(id); } } else if (typeName.equals(LOAN_TYPE)) { return loanType(id); }
@@ -236,27 +230,6 @@ public class LoanEnumerations {
return optionData; return optionData;
} }
public static List<EnumOptionData> paymentTypes(final PaymentType[] paymentTypes) {
final List<EnumOptionData> optionDatas = new ArrayList<EnumOptionData>();
for (final PaymentType paymentType : paymentTypes) {
optionDatas.add(paymentType(paymentType));
}
return optionDatas;
}
public static EnumOptionData paymentType(final PaymentType paymentType) {
final EnumOptionData optionData = new EnumOptionData(paymentType.getValue().longValue(), paymentType.getCode(),
paymentType.toString());
return optionData;
}
public static EnumOptionData paymentType(final Integer id) {
PaymentType paymentType = PaymentType.fromInt(id);
EnumOptionData enumOptionData = new EnumOptionData(paymentType.getValue().longValue(), paymentType.getCode(), paymentType
.getValue().toString());
return enumOptionData;
}
public static LoanTransactionEnumData transactionType(final Integer id) { public static LoanTransactionEnumData transactionType(final Integer id) {
return transactionType(LoanTransactionType.fromInt(id)); return transactionType(LoanTransactionType.fromInt(id));
} }
@@ -0,0 +1,31 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.paymentdetail;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class PaymentDetailConstants {
// Code representing Payment Details
public static final String paymentTypeCodeName = "PaymentType";
// request parameters
public static final String paymentTypeParamName = "paymentTypeId";
public static final String accountNumberParamName = "accountNumber";
public static final String checkNumberParamName = "checkNumber";
public static final String routingCodeParamName = "routingCode";
public static final String receiptNumberParamName = "receiptNumber";
public static final String bankNumberParamName = "bankNumber";
// template related part of response
public static final String officeOptionsParamName = "paymentTypeOptions";
public static final Set<String> PAYMENT_CREATE_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(accountNumberParamName,
checkNumberParamName, routingCodeParamName, receiptNumberParamName, bankNumberParamName));
}
@@ -3,9 +3,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file, * License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. * You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package org.mifosplatform.portfolio.loanaccount.data; package org.mifosplatform.portfolio.paymentdetail.data;
import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.codes.data.CodeValueData;
/** /**
* Immutable data object representing a payment. * Immutable data object representing a payment.
@@ -15,7 +15,7 @@ public class PaymentDetailData {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final Long id; private final Long id;
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final EnumOptionData paymentType; private final CodeValueData paymentType;
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final String accountNumber; private final String accountNumber;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@@ -27,7 +27,7 @@ public class PaymentDetailData {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final String bankNumber; private final String bankNumber;
public PaymentDetailData(Long id, EnumOptionData paymentType, String accountNumber, String checkNumber, String routingCode, public PaymentDetailData(Long id, CodeValueData paymentType, String accountNumber, String checkNumber, String routingCode,
String receiptNumber, String bankNumber) { String receiptNumber, String bankNumber) {
this.id = id; this.id = id;
this.paymentType = paymentType; this.paymentType = paymentType;
@@ -0,0 +1,99 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.paymentdetail.domain;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants;
import org.mifosplatform.portfolio.paymentdetail.data.PaymentDetailData;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity
@Table(name = "m_payment_detail")
public final class PaymentDetail extends AbstractPersistable<Long> {
@ManyToOne
@JoinColumn(name = "payment_type_cv_id", nullable = false)
private CodeValue paymentType;
@Column(name = "account_number", length = 50)
private String accountNumber;
@Column(name = "check_number", length = 50)
private String checkNumber;
@Column(name = "routing_code", length = 50)
private String routingCode;
@Column(name = "receipt_number", length = 50)
private String receiptNumber;
@Column(name = "bank_number", length = 50)
private String bankNumber;
protected PaymentDetail() {
}
public static PaymentDetail generatePaymentDetail(final CodeValue paymentType, final JsonCommand command,
final Map<String, Object> changes) {
final String accountNumber = command.stringValueOfParameterNamed(PaymentDetailConstants.accountNumberParamName);
final String checkNumber = command.stringValueOfParameterNamed(PaymentDetailConstants.checkNumberParamName);
final String routingCode = command.stringValueOfParameterNamed(PaymentDetailConstants.routingCodeParamName);
final String receiptNumber = command.stringValueOfParameterNamed(PaymentDetailConstants.receiptNumberParamName);
final String bankNumber = command.stringValueOfParameterNamed(PaymentDetailConstants.bankNumberParamName);
if (StringUtils.isNotBlank(accountNumber)) {
changes.put(PaymentDetailConstants.accountNumberParamName, accountNumber);
}
if (StringUtils.isNotBlank(checkNumber)) {
changes.put(PaymentDetailConstants.checkNumberParamName, checkNumber);
}
if (StringUtils.isNotBlank(routingCode)) {
changes.put(PaymentDetailConstants.routingCodeParamName, routingCode);
}
if (StringUtils.isNotBlank(receiptNumber)) {
changes.put(PaymentDetailConstants.receiptNumberParamName, receiptNumber);
}
if (StringUtils.isNotBlank(bankNumber)) {
changes.put(PaymentDetailConstants.bankNumberParamName, bankNumber);
}
PaymentDetail paymentDetail = new PaymentDetail(paymentType, accountNumber, checkNumber, routingCode, receiptNumber, bankNumber);
return paymentDetail;
}
private PaymentDetail(final CodeValue paymentType, final String accountNumber, final String checkNumber, final String routingCode,
final String receiptNumber, final String bankNumber) {
this.paymentType = paymentType;
this.accountNumber = accountNumber;
this.checkNumber = checkNumber;
this.routingCode = routingCode;
this.receiptNumber = receiptNumber;
this.bankNumber = bankNumber;
}
public PaymentDetailData toData() {
CodeValueData paymentTypeData = paymentType.toData();
final PaymentDetailData paymentDetailData = new PaymentDetailData(getId(), paymentTypeData, this.accountNumber, this.checkNumber,
this.routingCode, this.receiptNumber, this.bankNumber);
return paymentDetailData;
}
public CodeValue getPaymentType() {
return this.paymentType;
}
}
@@ -3,8 +3,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file, * License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. * You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package org.mifosplatform.portfolio.loanaccount.domain; package org.mifosplatform.portfolio.paymentdetail.domain;
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
@@ -0,0 +1,20 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.paymentdetail.service;
import java.util.Map;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
public interface PaymentDetailWritePlatformService {
PaymentDetail createAndPersistPaymentDetail(final JsonCommand command, Map<String, Object> changes);
PaymentDetail createPaymentDetail(final JsonCommand command, Map<String, Object> changes);
PaymentDetail persistPaymentDetail(PaymentDetail paymentDetail);
}
@@ -0,0 +1,59 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.paymentdetail.service;
import java.util.Map;
import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.mifosplatform.infrastructure.codes.domain.CodeValueRepositoryWrapper;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants;
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetailRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class PaymentDetailWritePlatformServiceJpaRepositoryImpl implements PaymentDetailWritePlatformService {
private final PaymentDetailRepository paymentDetailRepository;
private final CodeValueRepositoryWrapper codeValueRepositoryWrapper;
@Autowired
public PaymentDetailWritePlatformServiceJpaRepositoryImpl(final PaymentDetailRepository paymentDetailRepository,
final CodeValueRepositoryWrapper codeValueRepositoryWrapper) {
this.paymentDetailRepository = paymentDetailRepository;
this.codeValueRepositoryWrapper = codeValueRepositoryWrapper;
}
@Override
@Transactional
public PaymentDetail createPaymentDetail(JsonCommand command, Map<String, Object> changes) {
final Long paymentTypeId = command.longValueOfParameterNamed(PaymentDetailConstants.paymentTypeParamName);
if (paymentTypeId == null) { return null; }
CodeValue paymentType = codeValueRepositoryWrapper.findOneByCodeNameAndIdWithNotFoundDetection(
PaymentDetailConstants.paymentTypeCodeName, paymentTypeId);
PaymentDetail paymentDetail = PaymentDetail.generatePaymentDetail(paymentType, command, changes);
return paymentDetail;
}
@Override
@Transactional
public PaymentDetail persistPaymentDetail(PaymentDetail paymentDetail) {
return paymentDetailRepository.save(paymentDetail);
}
@Override
@Transactional
public PaymentDetail createAndPersistPaymentDetail(JsonCommand command, Map<String, Object> changes) {
PaymentDetail paymentDetail = createPaymentDetail(command, changes);
if (paymentDetail != null) { return persistPaymentDetail(paymentDetail); }
return paymentDetail;
}
}