diff --git a/mifosng-db/migrations/core_db/V39__payment-channels-updates.sql b/mifosng-db/migrations/core_db/V39__payment-channels-updates.sql new file mode 100755 index 000000000..ba6f956ce --- /dev/null +++ b/mifosng-db/migrations/core_db/V39__payment-channels-updates.sql @@ -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`); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingConstants.java index 14dd6904b..3091270f6 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingConstants.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingConstants.java @@ -84,7 +84,8 @@ public class AccountingConstants { FUND_SOURCE("fundSourceAccountId"), LOAN_PORTFOLIO("loanPortfolioAccountId"), INTEREST_ON_LOANS("interestOnLoanAccountId"), INCOME_FROM_FEES( "incomeFromFeeAccountId"), INCOME_FROM_PENALTIES("incomeFromPenaltyAccountId"), LOSSES_WRITTEN_OFF("writeOffAccountId"), INTEREST_RECEIVABLE( "receivableInterestAccountId"), FEES_RECEIVABLE("receivableFeeAccountId"), PENALTIES_RECEIVABLE( - "receivablePenaltyAccountId"); + "receivablePenaltyAccountId"), PAYMENT_CHANNEL_FUND_SOURCE_MAPPING("paymentChannelFundSourceMappings"), PAYMENT_TYPE( + "paymentTypeId"); private final String value; @@ -101,7 +102,7 @@ public class AccountingConstants { return this.value; } } - + public static final String ASSESTS_TAG_OPTION_CODE_NAME = "AssetAccountTags"; public static final String LIABILITIES_TAG_OPTION_CODE_NAME = "LiabilityAccountTags"; public static final String EQUITY_TAG_OPTION_CODE_NAME = "EquityAccountTags"; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/command/JournalEntryCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/command/JournalEntryCommand.java index 3aa4d3bd9..e1ca55109 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/command/JournalEntryCommand.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/command/JournalEntryCommand.java @@ -27,8 +27,7 @@ public class JournalEntryCommand { private final SingleDebitOrCreditEntryCommand[] debits; public JournalEntryCommand(final Long officeId, final LocalDate transactionDate, final String comments, - final SingleDebitOrCreditEntryCommand[] credits, final SingleDebitOrCreditEntryCommand[] debits, - final String referenceNumber) { + final SingleDebitOrCreditEntryCommand[] credits, final SingleDebitOrCreditEntryCommand[] debits, final String referenceNumber) { this.officeId = officeId; this.transactionDate = transactionDate; this.comments = comments; @@ -52,7 +51,7 @@ public class JournalEntryCommand { baseDataValidator.reset().parameter("credits").value(this.credits).notNull(); baseDataValidator.reset().parameter("debits").value(this.debits).notNull(); - + baseDataValidator.reset().parameter("referenceNumber").value(this.referenceNumber).ignoreIfNull().notExceedingLengthOf(100); // validation for credit array elements @@ -118,8 +117,8 @@ public class JournalEntryCommand { return this.debits; } - public String getReferenceNumber() { - return this.referenceNumber; - } + public String getReferenceNumber() { + return this.referenceNumber; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/LoanTransactionDTO.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/LoanTransactionDTO.java index 4b0ef2c0c..e277c3a3a 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/LoanTransactionDTO.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/LoanTransactionDTO.java @@ -14,6 +14,7 @@ public class LoanTransactionDTO { private final String transactionId; private final Date transactionDate; + private final Long paymentTypeId; private final LoanTransactionEnumData transactionType; private final BigDecimal amount; @@ -27,9 +28,10 @@ public class LoanTransactionDTO { /*** Boolean values determines if the transaction is reversed ***/ private final boolean reversed; - public LoanTransactionDTO(final String transactionId, final Date transactionDate, final LoanTransactionEnumData transactionType, - final BigDecimal amount, final BigDecimal principal, final BigDecimal interest, final BigDecimal fees, - final BigDecimal penalties, final boolean reversed) { + public LoanTransactionDTO(final Long paymentTypeId, final String transactionId, final Date transactionDate, + final LoanTransactionEnumData transactionType, final BigDecimal amount, final BigDecimal principal, final BigDecimal interest, + final BigDecimal fees, final BigDecimal penalties, final boolean reversed) { + this.paymentTypeId = paymentTypeId; this.transactionId = transactionId; this.transactionDate = transactionDate; this.amount = amount; @@ -77,4 +79,8 @@ public class LoanTransactionDTO { return this.reversed; } + public Long getPaymentTypeId() { + return this.paymentTypeId; + } + } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccountingProcessorHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccountingProcessorHelper.java index b5443ffe7..1f84db58d 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccountingProcessorHelper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccountingProcessorHelper.java @@ -71,9 +71,10 @@ public class AccountingProcessorHelper { final BigDecimal fees = (BigDecimal) map.get("feeChargesPortion"); final BigDecimal penalties = (BigDecimal) map.get("penaltyChargesPortion"); final boolean reversed = (Boolean) map.get("reversed"); + final Long paymentTypeId = (Long) map.get("paymentTypeId"); - final LoanTransactionDTO transaction = new LoanTransactionDTO(transactionId, transactionDate, transactionType, amount, - principal, interest, fees, penalties, reversed); + final LoanTransactionDTO transaction = new LoanTransactionDTO(paymentTypeId, transactionId, transactionDate, transactionType, + amount, principal, interest, fees, penalties, reversed); newLoanTransactions.add(transaction); @@ -95,6 +96,7 @@ public class AccountingProcessorHelper { * @param accountTypeToBeCredited * Enum of the placeholder of the GLAccount to be credited * @param loanProductId + * @param paymentTypeId * @param loanId * @param transactionId * @param transactionDate @@ -103,8 +105,8 @@ public class AccountingProcessorHelper { */ public void createAccrualBasedJournalEntriesAndReversalsForLoan(final Office office, 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 Boolean isReversal) { + final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate, + final BigDecimal amount, final Boolean isReversal) { int accountTypeToDebitId = accountTypeToBeDebited.getValue(); int accountTypeToCreditId = accountTypeToBeCredited.getValue(); // reverse debits and credits for reversals @@ -112,8 +114,8 @@ public class AccountingProcessorHelper { accountTypeToDebitId = accountTypeToBeCredited.getValue(); accountTypeToCreditId = accountTypeToBeDebited.getValue(); } - createJournalEntriesForLoan(office, accountTypeToDebitId, accountTypeToCreditId, loanProductId, loanId, transactionId, - transactionDate, amount); + createJournalEntriesForLoan(office, accountTypeToDebitId, accountTypeToCreditId, loanProductId, paymentTypeId, loanId, + transactionId, transactionDate, amount); } /** @@ -129,6 +131,7 @@ public class AccountingProcessorHelper { * @param accountTypeToBeCredited * Enum of the placeholder of the GLAccount to be credited * @param loanProductId + * @param paymentTypeId * @param loanId * @param transactionId * @param transactionDate @@ -136,8 +139,8 @@ public class AccountingProcessorHelper { * @param isReversal */ 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 Date transactionDate, final BigDecimal amount, final Boolean isReversal) { + final CASH_ACCOUNTS_FOR_LOAN accountTypeToBeCredited, final Long loanProductId, final Long paymentTypeId, final Long loanId, + final String transactionId, final Date transactionDate, final BigDecimal amount, final Boolean isReversal) { int accountTypeToDebitId = accountTypeToBeDebited.getValue(); int accountTypeToCreditId = accountTypeToBeCredited.getValue(); // reverse debits and credits for reversals @@ -145,40 +148,40 @@ public class AccountingProcessorHelper { accountTypeToDebitId = accountTypeToBeCredited.getValue(); accountTypeToCreditId = accountTypeToBeDebited.getValue(); } - createJournalEntriesForLoan(office, accountTypeToDebitId, accountTypeToCreditId, loanProductId, loanId, transactionId, - transactionDate, amount); + createJournalEntriesForLoan(office, accountTypeToDebitId, accountTypeToCreditId, loanProductId, paymentTypeId, loanId, + transactionId, transactionDate, amount); } 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 Boolean isReversal) { + final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate, + final BigDecimal amount, final Boolean isReversal) { int accountMappingTypeId = accountMappingType.getValue(); - createCreditJournalEntryOrReversalForLoan(office, accountMappingTypeId, loanProductId, loanId, transactionId, transactionDate, - amount, isReversal); + createCreditJournalEntryOrReversalForLoan(office, accountMappingTypeId, loanProductId, paymentTypeId, loanId, transactionId, + transactionDate, amount, isReversal); } 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 Boolean isReversal) { + final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate, + final BigDecimal amount, final Boolean isReversal) { int accountMappingTypeId = accountMappingType.getValue(); - createCreditJournalEntryOrReversalForLoan(office, accountMappingTypeId, loanProductId, loanId, transactionId, transactionDate, - amount, isReversal); + createCreditJournalEntryOrReversalForLoan(office, accountMappingTypeId, loanProductId, paymentTypeId, loanId, transactionId, + transactionDate, amount, isReversal); } 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 Boolean isReversal) { + final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate, + final BigDecimal amount, final Boolean isReversal) { int accountMappingTypeId = accountMappingType.getValue(); - createDebitJournalEntryOrReversalForLoan(office, accountMappingTypeId, loanProductId, loanId, transactionId, transactionDate, - amount, isReversal); + createDebitJournalEntryOrReversalForLoan(office, accountMappingTypeId, loanProductId, paymentTypeId, loanId, transactionId, + transactionDate, amount, isReversal); } 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 Boolean isReversal) { + final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate, + final BigDecimal amount, final Boolean isReversal) { int accountMappingTypeId = accountMappingType.getValue(); - createDebitJournalEntryOrReversalForLoan(office, accountMappingTypeId, loanProductId, loanId, transactionId, transactionDate, - amount, isReversal); + createDebitJournalEntryOrReversalForLoan(office, accountMappingTypeId, loanProductId, paymentTypeId, loanId, transactionId, + transactionDate, amount, isReversal); } /** @@ -205,16 +208,18 @@ public class AccountingProcessorHelper { } 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) { - GLAccount debitAccount = getLinkedGLAccountForLoanProduct(loanProductId, accountTypeToDebitId); - GLAccount creditAccount = getLinkedGLAccountForLoanProduct(loanProductId, accountTypeToCreditId); + final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate, + final BigDecimal amount) { + GLAccount debitAccount = getLinkedGLAccountForLoanProduct(loanProductId, accountTypeToDebitId, paymentTypeId); + GLAccount creditAccount = getLinkedGLAccountForLoanProduct(loanProductId, accountTypeToCreditId, paymentTypeId); createDebitJournalEntryForLoan(office, debitAccount, loanId, transactionId, transactionDate, amount); createCreditJournalEntryForLoan(office, creditAccount, loanId, transactionId, transactionDate, amount); } 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) { - GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, accountMappingTypeId); + final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount, + final Boolean isReversal) { + GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, accountMappingTypeId, paymentTypeId); if (isReversal) { createCreditJournalEntryForLoan(office, account, loanId, transactionId, transactionDate, amount); } else { @@ -223,8 +228,9 @@ public class AccountingProcessorHelper { } 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) { - GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, accountMappingTypeId); + final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount, + final Boolean isReversal) { + GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, accountMappingTypeId, paymentTypeId); if (isReversal) { createDebitJournalEntryForLoan(office, account, loanId, transactionId, transactionDate, amount); } else { @@ -248,11 +254,22 @@ public class AccountingProcessorHelper { this.glJournalEntryRepository.saveAndFlush(journalEntry); } - private GLAccount getLinkedGLAccountForLoanProduct(final Long loanProductId, final int accountMappingTypeId) { - final ProductToGLAccountMapping accountMapping = this.accountMappingRepository - .findByProductIdAndProductTypeAndFinancialAccountType(loanProductId, PortfolioProductType.LOAN.getValue(), - accountMappingTypeId); + private GLAccount getLinkedGLAccountForLoanProduct(final Long loanProductId, final int accountMappingTypeId, final Long paymentTypeId) { + ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(loanProductId, + PortfolioProductType.LOAN.getValue(), 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(); } - } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java index 9bcea57a3..fe6ecd5ba 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java @@ -86,11 +86,13 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess final Date transactionDate = loanTransactionDTO.getTransactionDate(); final BigDecimal disbursalAmount = loanTransactionDTO.getAmount(); final boolean isReversed = loanTransactionDTO.isReversed(); + final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId(); // create journal entries for the disbursement (or disbursement // reversal) 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 BigDecimal amount = loanTransactionDTO.getAmount(); final boolean isReversed = loanTransactionDTO.isReversed(); + final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId(); // create journal entries for recognising interest (or reversal) if (amount != null && !(amount.compareTo(BigDecimal.ZERO) == 0)) { 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 feesAmount = loanTransactionDTO.getFees(); final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties(); + final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId(); final boolean isReversal = loanTransactionDTO.isReversed(); BigDecimal totalDebitAmount = new BigDecimal(0); @@ -183,15 +188,15 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess // handle principal payment or writeOff (and reversals) if (principalAmount != null && !(principalAmount.compareTo(BigDecimal.ZERO) == 0)) { totalDebitAmount = totalDebitAmount.add(principalAmount); - helper.createCreditJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, loanProductId, loanId, - transactionId, transactionDate, principalAmount, isReversal); + helper.createCreditJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, loanProductId, + paymentTypeId, loanId, transactionId, transactionDate, principalAmount, isReversal); } // handle interest payment of writeOff (and reversals) if (interestAmount != null && !(interestAmount.compareTo(BigDecimal.ZERO) == 0)) { totalDebitAmount = totalDebitAmount.add(interestAmount); - helper.createCreditJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE, loanProductId, loanId, - transactionId, transactionDate, interestAmount, isReversal); + helper.createCreditJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE, loanProductId, + paymentTypeId, loanId, transactionId, transactionDate, interestAmount, isReversal); } // handle fees payment of writeOff (and reversals) @@ -204,15 +209,15 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess feeAccountToCredit = ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES; } - helper.createCreditJournalEntryOrReversalForLoan(office, feeAccountToCredit, loanProductId, loanId, transactionId, - transactionDate, feesAmount, isReversal); + helper.createCreditJournalEntryOrReversalForLoan(office, feeAccountToCredit, loanProductId, paymentTypeId, loanId, + transactionId, transactionDate, feesAmount, isReversal); } // handle penalties payment of writeOff (and reversals) if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) { totalDebitAmount = totalDebitAmount.add(penaltiesAmount); - helper.createCreditJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE, loanProductId, loanId, - transactionId, transactionDate, penaltiesAmount, isReversal); + helper.createCreditJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE, loanProductId, + paymentTypeId, loanId, transactionId, transactionDate, penaltiesAmount, isReversal); } /** @@ -220,11 +225,11 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess * reversals) ***/ if (writeOff) { - helper.createDebitJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF, loanProductId, loanId, - transactionId, transactionDate, totalDebitAmount, isReversal); + helper.createDebitJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF, loanProductId, + paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal); } else { - helper.createDebitJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId, loanId, - transactionId, transactionDate, totalDebitAmount, isReversal); + helper.createDebitJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId, paymentTypeId, + loanId, transactionId, transactionDate, totalDebitAmount, isReversal); } } @@ -256,19 +261,19 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess final BigDecimal feesAmount = loanTransactionDTO.getFees(); final BigDecimal penaltiesAmount = loanTransactionDTO.getPenalties(); final boolean isReversed = loanTransactionDTO.isReversed(); + final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId(); // create journal entries for the fees application (or reversal) if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 0)) { helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE, - ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES, loanProductId, loanId, transactionId, transactionDate, feesAmount, - isReversed); + ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES, loanProductId, paymentTypeId, loanId, transactionId, transactionDate, + feesAmount, isReversed); } // create journal entries for the penalties application (or reversal) else if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) { 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); } } - } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/CashBasedAccountingProcessorForLoan.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/CashBasedAccountingProcessorForLoan.java index 7569f5819..e22aa54e8 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/CashBasedAccountingProcessorForLoan.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/CashBasedAccountingProcessorForLoan.java @@ -34,6 +34,7 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF for (final LoanTransactionDTO loanTransactionDTO : loanDTO.getNewLoanTransactions()) { final Date transactionDate = loanTransactionDTO.getTransactionDate(); final String transactionId = loanTransactionDTO.getTransactionId(); + final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId(); final Long loanId = loanDTO.getLoanId(); helper.checkForBranchClosures(latestGLClosure, transactionDate); @@ -58,8 +59,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF else if (loanTransactionDTO.getTransactionType().isWriteOff() && !loanTransactionDTO.isReversed()) { final BigDecimal principalAmount = loanTransactionDTO.getPrincipal(); helper.createCashBasedJournalEntriesAndReversalsForLoan(office, CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF, - CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, loanProductId, loanId, transactionId, transactionDate, principalAmount, - false); + CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, loanProductId, paymentTypeId, loanId, transactionId, transactionDate, + principalAmount, false); } } } @@ -86,9 +87,11 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF final Date transactionDate = loanTransactionDTO.getTransactionDate(); final BigDecimal disbursalAmount = loanTransactionDTO.getAmount(); final boolean isReversal = loanTransactionDTO.isReversed(); + final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId(); 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 penaltiesAmount = loanTransactionDTO.getPenalties(); final boolean isReversal = loanTransactionDTO.isReversed(); + final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId(); BigDecimal totalDebitAmount = new BigDecimal(0); if (principalAmount != null && !(principalAmount.compareTo(BigDecimal.ZERO) == 0)) { totalDebitAmount = totalDebitAmount.add(principalAmount); - helper.createCreditJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, loanProductId, loanId, - transactionId, transactionDate, principalAmount, isReversal); + helper.createCreditJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, loanProductId, paymentTypeId, + loanId, transactionId, transactionDate, principalAmount, isReversal); } if (interestAmount != null && !(interestAmount.compareTo(BigDecimal.ZERO) == 0)) { totalDebitAmount = totalDebitAmount.add(interestAmount); - helper.createCreditJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS, loanProductId, loanId, - transactionId, transactionDate, interestAmount, isReversal); + helper.createCreditJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS, loanProductId, + paymentTypeId, loanId, transactionId, transactionDate, interestAmount, isReversal); } if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 0)) { totalDebitAmount = totalDebitAmount.add(feesAmount); - helper.createCreditJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES, loanProductId, loanId, - transactionId, transactionDate, feesAmount, isReversal); + helper.createCreditJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES, loanProductId, paymentTypeId, + loanId, transactionId, transactionDate, feesAmount, isReversal); } if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) { totalDebitAmount = totalDebitAmount.add(penaltiesAmount); - helper.createCreditJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES, loanProductId, loanId, - transactionId, transactionDate, penaltiesAmount, isReversal); + helper.createCreditJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES, loanProductId, + paymentTypeId, loanId, transactionId, transactionDate, penaltiesAmount, isReversal); } /*** create a single debit entry (or reversal) for the entire amount **/ - helper.createDebitJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId, loanId, transactionId, - transactionDate, totalDebitAmount, isReversal); + helper.createDebitJournalEntryOrReversalForLoan(office, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId, paymentTypeId, loanId, + transactionId, transactionDate, totalDebitAmount, isReversal); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/domain/ProductToGLAccountMapping.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/domain/ProductToGLAccountMapping.java index 310b64277..40146f0de 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/domain/ProductToGLAccountMapping.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/domain/ProductToGLAccountMapping.java @@ -14,11 +14,12 @@ import javax.persistence.Table; import javax.persistence.UniqueConstraint; import org.mifosplatform.accounting.glaccount.domain.GLAccount; +import org.mifosplatform.infrastructure.codes.domain.CodeValue; import org.springframework.data.jpa.domain.AbstractPersistable; @Entity @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 { @ManyToOne(fetch = FetchType.LAZY) @@ -28,6 +29,10 @@ public class ProductToGLAccountMapping extends AbstractPersistable { @Column(name = "product_id", nullable = false) private Long productId; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "payment_type", nullable = true) + private CodeValue paymentType; + @Column(name = "product_type", nullable = false) private int productType; @@ -44,10 +49,16 @@ public class ProductToGLAccountMapping extends AbstractPersistable { } 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.productId = productId; this.productType = productType; this.financialAccountType = financialAccountType; + this.paymentType = paymentType; } public GLAccount getGlAccount() { @@ -82,4 +93,12 @@ public class ProductToGLAccountMapping extends AbstractPersistable { this.financialAccountType = financialAccountType; } + public CodeValue getPaymentType() { + return this.paymentType; + } + + public void setPaymentType(CodeValue paymentType) { + this.paymentType = paymentType; + } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/domain/ProductToGLAccountMappingRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/domain/ProductToGLAccountMappingRepository.java index b12116bee..8238b1225 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/domain/ProductToGLAccountMappingRepository.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/domain/ProductToGLAccountMappingRepository.java @@ -9,11 +9,23 @@ import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface ProductToGLAccountMappingRepository extends JpaRepository, JpaSpecificationExecutor { - 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 findAllPaymentTypeToFundSourceMappings(@Param("productId") Long productId, + @Param("productType") int productType); List findByProductIdAndProductType(Long productId, int productType); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformService.java index 7b5e009e7..72473b67d 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformService.java @@ -10,4 +10,6 @@ import java.util.Map; public interface ProductToGLAccountMappingReadPlatformService { Map fetchAccountMappingDetailsForLoanProduct(final Long loanProductId, final Integer accountingType); + + Map fetchPaymentTypeToFundSourceMappingsForLoanProduct(final Long loanProductId); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java index da8987119..a016d49e5 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java @@ -34,8 +34,8 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product private static final class LoanProductToGLAccountMappingMapper implements RowMapper> { 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" - + " from acc_product_mapping " + " where product_type=1 "; + return " id as id, gl_account_id as glAccountId,product_id as productId,product_type as productType,financial_account_type as financialAccountType," + + " payment_type as paymentTypeId from acc_product_mapping " + " where product_type=1 "; } @Override @@ -44,6 +44,7 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product final Long id = rs.getLong("id"); final Long glAccountId = rs.getLong("glAccountId"); final Long productId = rs.getLong("productId"); + final Long paymentTypeId = rs.getLong("paymentTypeId"); final Integer productType = rs.getInt("productType"); final Integer financialAccountType = rs.getInt("financialAccountType"); @@ -53,6 +54,7 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product loanProductToGLAccountMap.put("productId", productId); loanProductToGLAccountMap.put("productType", productType); loanProductToGLAccountMap.put("financialAccountType", financialAccountType); + loanProductToGLAccountMap.put("paymentTypeId", paymentTypeId); return loanProductToGLAccountMap; } @@ -124,4 +126,25 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product return accountMappingDetails; } + + @Override + public Map fetchPaymentTypeToFundSourceMappingsForLoanProduct(Long loanProductId) { + Map paymentTypeToFundSourceMappingDetails = null; + + final LoanProductToGLAccountMappingMapper rm = new LoanProductToGLAccountMappingMapper(); + final String sql = "select " + rm.schema() + " and product_id = ? and payment_type is not null"; + + final List> paymentTypeToFundSourceMappingsList = this.jdbcTemplate.query(sql, rm, + new Object[] { loanProductId }); + + for (final Map productToGLAccountMap : paymentTypeToFundSourceMappingsList) { + if (paymentTypeToFundSourceMappingDetails == null) { + paymentTypeToFundSourceMappingDetails = new LinkedHashMap(); + } + final Long glAccountId = (Long) productToGLAccountMap.get("glAccountId"); + final Long paymentTypeId = (Long) productToGLAccountMap.get("paymentTypeId"); + paymentTypeToFundSourceMappingDetails.put(paymentTypeId, glAccountId); + } + return paymentTypeToFundSourceMappingDetails; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java index 28afe4615..42cfe6a30 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingWritePlatformServiceImpl.java @@ -6,9 +6,11 @@ package org.mifosplatform.accounting.producttoaccountmapping.service; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; import org.mifosplatform.accounting.common.AccountingConstants.ACCRUAL_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.ProductToGLAccountMappingNotFoundException; 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.serialization.FromJsonHelper; import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType; +import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; +import com.google.gson.JsonObject; @Service public class ProductToGLAccountMappingWritePlatformServiceImpl implements ProductToGLAccountMappingWritePlatformService { @@ -39,15 +46,17 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc private final ProductToGLAccountMappingRepository accountMappingRepository; private final FromJsonHelper fromApiJsonHelper; private final ProductToGLAccountMappingFromApiJsonDeserializer deserializer; + private final CodeValueRepositoryWrapper codeValueRepositoryWrapper; @Autowired public ProductToGLAccountMappingWritePlatformServiceImpl(final GLAccountRepository glAccountRepository, final ProductToGLAccountMappingRepository glAccountMappingRepository, final FromJsonHelper fromApiJsonHelper, - final ProductToGLAccountMappingFromApiJsonDeserializer deserializer) { + final ProductToGLAccountMappingFromApiJsonDeserializer deserializer, final CodeValueRepositoryWrapper codeValueRepositoryWrapper) { this.accountRepository = glAccountRepository; this.accountMappingRepository = glAccountMappingRepository; this.fromApiJsonHelper = fromApiJsonHelper; this.deserializer = deserializer; + this.codeValueRepositoryWrapper = codeValueRepositoryWrapper; } @Override @@ -78,6 +87,9 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc // expenses saveLoanToExpenseAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), loanProductId, CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue()); + + // advanced accounting mappings + savePaymentChannelToFundSourceMappings(command, element, loanProductId, null); break; case ACCRUAL_BASED: @@ -104,6 +116,9 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc // expenses saveLoanToExpenseAccountMapping(element, LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), loanProductId, ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue()); + + // advanced accounting mappings + savePaymentChannelToFundSourceMappings(command, element, loanProductId, null); break; } } @@ -127,9 +142,11 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc if (accountingRuleChanged) { this.deserializer.validateForCreate(command.json()); handleChangesToAccountingRuleType(loanProductId, command, changes, element, accountingRuleType); + savePaymentChannelToFundSourceMappings(command, element, loanProductId, changes); }/*** else examine and update individual changes ***/ else { handleChangesToLoanProductToGLAccountMappings(loanProductId, changes, element, accountingRuleType); + updatePaymentChannelToFundSourceMappings(command, element, loanProductId, 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 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 changes) { + // find all existing payment Channel to Fund source Mappings + List 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 inputPaymentChannelFundSourceMap = new HashMap(); + /*** + * Variable stores all payment types which hae already been mapped to + * Fund Sources in the system + **/ + Set existingPaymentTypes = new HashSet(); + 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,
+ * update existing mappings OR
+ * delete old mappings (which re already present, but not passed in + * as a part of Jsoncommand)
+ * 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 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 * changes passed in from the Json element @@ -396,8 +536,8 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc // get the existing product if (accountId != null) { - final ProductToGLAccountMapping accountMapping = this.accountMappingRepository - .findByProductIdAndProductTypeAndFinancialAccountType(productId, PortfolioProductType.LOAN.getValue(), accountTypeId); + final ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(productId, + PortfolioProductType.LOAN.getValue(), accountTypeId); if (accountMapping == null) { throw new ProductToGLAccountMappingNotFoundException(PortfolioProductType.LOAN, productId, accountTypeName); } 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 - * of the expected Account Category ('DEBIT','CREDIT' etc) + * of the expected Account Category ('ASSET','liability' etc) * * @param paramName * @param expectedAccountType diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoanTransactionsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoanTransactionsApiResource.java index 887d20867..0c59ccc06 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoanTransactionsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoanTransactionsApiResource.java @@ -6,8 +6,8 @@ package org.mifosplatform.portfolio.loanaccount.api; import java.util.Arrays; +import java.util.Collection; import java.util.HashSet; -import java.util.List; import java.util.Set; 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.service.CommandWrapperBuilder; 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.data.CommandProcessingResult; -import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamException; import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; 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.loanproduct.service.LoanEnumerations; +import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @@ -54,17 +54,20 @@ public class LoanTransactionsApiResource { private final ApiRequestParameterHelper apiRequestParameterHelper; private final DefaultToApiJsonSerializer toApiJsonSerializer; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; + private final CodeValueReadPlatformService codeValueReadPlatformService; @Autowired public LoanTransactionsApiResource(final PlatformSecurityContext context, final LoanReadPlatformService loanReadPlatformService, final ApiRequestParameterHelper apiRequestParameterHelper, final DefaultToApiJsonSerializer toApiJsonSerializer, - final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { + final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService, + final CodeValueReadPlatformService codeValueReadPlatformService) { this.context = context; this.loanReadPlatformService = loanReadPlatformService; this.apiRequestParameterHelper = apiRequestParameterHelper; this.toApiJsonSerializer = toApiJsonSerializer; this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; + this.codeValueReadPlatformService = codeValueReadPlatformService; } private boolean is(final String commandParam, final String commandValue) { @@ -113,7 +116,8 @@ public class LoanTransactionsApiResource { LoanTransactionData transactionData = this.loanReadPlatformService.retrieveLoanTransaction(loanId, transactionId); final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); if (settings.isTemplate()) { - final List paymentTypeOptions = LoanEnumerations.paymentTypes(PaymentType.values()); + final Collection paymentTypeOptions = codeValueReadPlatformService + .retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName); transactionData = LoanTransactionData.templateOnTop(transactionData, paymentTypeOptions); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanTransactionData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanTransactionData.java index 5af5a048b..a79bb13d9 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanTransactionData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanTransactionData.java @@ -6,11 +6,12 @@ package org.mifosplatform.portfolio.loanaccount.data; import java.math.BigDecimal; -import java.util.List; +import java.util.Collection; 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.portfolio.paymentdetail.data.PaymentDetailData; /** * Immutable data object representing a loan transaction. @@ -33,9 +34,9 @@ public class LoanTransactionData { private final BigDecimal penaltyChargesPortion; // templates - final List paymentTypeOptions; + final Collection paymentTypeOptions; - public static LoanTransactionData templateOnTop(LoanTransactionData loanTransactionData, List paymentTypeOptions) { + public static LoanTransactionData templateOnTop(LoanTransactionData loanTransactionData, Collection paymentTypeOptions) { return new LoanTransactionData(loanTransactionData.id, loanTransactionData.type, loanTransactionData.paymentDetailData, loanTransactionData.currency, loanTransactionData.date, loanTransactionData.amount, loanTransactionData.principalPortion, loanTransactionData.interestPortion, loanTransactionData.feeChargesPortion, loanTransactionData.penaltyChargesPortion, @@ -52,7 +53,7 @@ public class LoanTransactionData { public LoanTransactionData(final Long id, final LoanTransactionEnumData transactionType, final PaymentDetailData paymentDetailData, final CurrencyData currency, final LocalDate date, final BigDecimal amount, final BigDecimal principalPortion, final BigDecimal interestPortion, final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion, - final List paymentTypeOptions) { + final Collection paymentTypeOptions) { this.id = id; this.type = transactionType; this.paymentDetailData = paymentDetailData; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java index c054887ad..19a24602f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java @@ -75,6 +75,7 @@ import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail; import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy; import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType; import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations; +import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail; import org.mifosplatform.useradministration.domain.AppUser; import org.springframework.data.jpa.domain.AbstractPersistable; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransaction.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransaction.java index 4bc814745..f7209a663 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransaction.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransaction.java @@ -24,8 +24,9 @@ import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.organisation.monetary.domain.Money; import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData; 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.paymentdetail.data.PaymentDetailData; +import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail; import org.springframework.data.jpa.domain.AbstractPersistable; /** @@ -353,6 +354,10 @@ public final class LoanTransaction extends AbstractPersistable { thisTransactionData.put("feeChargesPortion", this.feeChargesPortion); thisTransactionData.put("penaltyChargesPortion", this.penaltyChargesPortion); + if (this.paymentDetail != null) { + thisTransactionData.put("paymentTypeId", this.paymentDetail.getPaymentType().getId()); + } + return thisTransactionData; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/PaymentDetail.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/PaymentDetail.java deleted file mode 100755 index 9acdedca8..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/PaymentDetail.java +++ /dev/null @@ -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 { - - @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 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; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/PaymentType.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/PaymentType.java deleted file mode 100755 index 0811df29d..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/PaymentType.java +++ /dev/null @@ -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 intToEnumMap = new HashMap(); - 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); - } - -} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/LoanEventApiJsonValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/LoanEventApiJsonValidator.java index b6ba762e6..571c8d51c 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/LoanEventApiJsonValidator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/LoanEventApiJsonValidator.java @@ -21,7 +21,6 @@ import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; -import org.mifosplatform.portfolio.loanaccount.domain.PaymentType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -102,8 +101,7 @@ public final class LoanEventApiJsonValidator { private void validatePaymentDetails(final DataValidatorBuilder baseDataValidator, final JsonElement element) { // Validate all string payment detail fields for max length final Integer paymentTypeId = fromApiJsonHelper.extractIntegerWithLocaleNamed("paymentTypeId", element); - baseDataValidator.reset().parameter("paymentTypeId").value(paymentTypeId) - .inMinMaxRange(PaymentType.getMinValue(), PaymentType.getMaxValue()); + baseDataValidator.reset().parameter("paymentTypeId").value(paymentTypeId).ignoreIfNull().integerGreaterThanZero(); final Set paymentDetailParameters = new HashSet(Arrays.asList("accountNumber", "checkNumber", "routingCode", "receiptNumber", "bankNumber")); for (String paymentDetailParameterName : paymentDetailParameters) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java index 573c37e3b..181c9b4b1 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java @@ -11,7 +11,6 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.List; import org.apache.commons.lang.StringUtils; 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.LoanTransactionData; 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.domain.Loan; 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.LoanEnumerations; 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.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; @@ -92,10 +92,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { private final ChargeReadPlatformService chargeReadPlatformService; private final CodeValueReadPlatformService codeValueReadPlatformService; private final CalendarReadPlatformService calendarReadPlatformService; - private final PaginationHelper paginationHelper = new PaginationHelper(); private final LoanMapper loaanLoanMapper = new LoanMapper(); + @Autowired public LoanReadPlatformServiceImpl(final PlatformSecurityContext context, final LoanRepository loanRepository, final LoanTransactionRepository loanTransactionRepository, @@ -313,7 +313,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final Money possibleNextRepaymentAmount = loan.possibleNextRepaymentAmount(); final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.REPAYMENT); - final List paymentOptions = loanDropdownReadPlatformService.retrievePaymentTypeOptions(); + final Collection paymentOptions = codeValueReadPlatformService + .retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName); return new LoanTransactionData(null, transactionType, null, currencyData, earliestUnpaidInstallmentDate, possibleNextRepaymentAmount.getAmount(), null, null, null, null, paymentOptions); } @@ -356,7 +357,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final Loan loan = this.loanRepository.findOne(loanId); if (loan == null) { throw new LoanNotFoundException(loanId); } final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.DISBURSEMENT); - final List paymentOptions = loanDropdownReadPlatformService.retrievePaymentTypeOptions(); + final Collection paymentOptions = codeValueReadPlatformService + .retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName); return new LoanTransactionData(null, transactionType, null, null, loan.getExpectedDisbursedOnLocalDate(), null, null, null, null, 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, " + " 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, " - + " 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, " + " 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 " - + " from m_loan l join m_loan_transaction tr on tr.loan_id = l.id" + + " rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, " + + " 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 " - + " 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 @@ -833,9 +836,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { PaymentDetailData paymentDetailData = null; if (transactionType.isPaymentOrReceipt()) { - final Integer paymentTypeId = JdbcSupport.getInteger(rs, "paymentType"); + final Long paymentTypeId = JdbcSupport.getLong(rs, "paymentType"); 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 checkNumber = rs.getString("checkNumber"); final String routingCode = rs.getString("routingCode"); @@ -860,6 +864,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { @Override public LoanAccountData retrieveLoanProductDetailsTemplate(final Long productId) { + context.authenticatedUser(); final LoanProductData loanProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java index 5461994a5..a54c6346b 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -57,8 +57,6 @@ import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus; import org.mifosplatform.portfolio.loanaccount.domain.LoanSummaryWrapper; import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction; 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.LoanNotFoundException; 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.note.domain.Note; import org.mifosplatform.portfolio.note.domain.NoteRepository; +import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail; +import org.mifosplatform.portfolio.paymentdetail.service.PaymentDetailWritePlatformService; import org.mifosplatform.useradministration.domain.AppUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -91,8 +91,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf private final JournalEntryWritePlatformService journalEntryWritePlatformService; private final LoanSummaryWrapper loanSummaryWrapper; private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory; - private final PaymentDetailRepository paymentDetailRepository; private final CalendarInstanceRepository calendarInstanceRepository; + private final PaymentDetailWritePlatformService paymentDetailWritePlatformService; @Autowired public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, @@ -103,7 +103,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final LoanChargeRepository loanChargeRepository, final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository, final JournalEntryWritePlatformService journalEntryWritePlatformService, final LoanSummaryWrapper loanSummaryWrapper, final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory, - final PaymentDetailRepository paymentDetailRepository, final CalendarInstanceRepository calendarInstanceRepository) { + final CalendarInstanceRepository calendarInstanceRepository, + final PaymentDetailWritePlatformService paymentDetailWritePlatformService) { this.context = context; this.loanEventApiJsonValidator = loanEventApiJsonValidator; this.loanAssembler = loanAssembler; @@ -117,8 +118,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf this.loanUpdateCommandFromApiJsonDeserializer = loanUpdateCommandFromApiJsonDeserializer; this.loanSummaryWrapper = loanSummaryWrapper; this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory; - this.paymentDetailRepository = paymentDetailRepository; this.calendarInstanceRepository = calendarInstanceRepository; + this.paymentDetailWritePlatformService = paymentDetailWritePlatformService; } private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() { @@ -135,11 +136,12 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf this.loanEventApiJsonValidator.validateDisbursement(command.json()); final Loan loan = retrieveLoanBy(loanId); - - //validate actual disbursement date against meeting date - Collection calendarInstances = this.calendarInstanceRepository.findByEntityIdAndEntityTypeId(loan.getId(), CalendarEntityType.LOANS.getValue()); + + // validate actual disbursement date against meeting date + Collection calendarInstances = this.calendarInstanceRepository.findByEntityIdAndEntityTypeId(loan.getId(), + CalendarEntityType.LOANS.getValue()); validateDisbursementDate(command.localDateValueOfParameterNamed("actualDisbursementDate"), calendarInstances); - + final MonetaryCurrency currency = loan.getCurrency(); final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency); @@ -147,10 +149,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final List existingReversedTransactionIds = new ArrayList(); final Map changes = new LinkedHashMap(); - PaymentDetail paymentDetail = PaymentDetail.generatePaymentDetail(command, changes); - if (paymentDetail != null) { - paymentDetailRepository.save(paymentDetail); - } + + PaymentDetail paymentDetail = paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes); loan.disburse(currentUser, command, applicationCurrency, existingTransactionIds, existingReversedTransactionIds, changes, paymentDetail); @@ -192,13 +192,14 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf if (disbursementDate.isBefore(calendar.getStartDateLocalDate())) { final String errorMessage = "Actual disbursement date '" + disbursementDate.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(), - calendar.getStartDate()); + throw new LoanApplicationDateException("actual.disbursement.date.cannot.be.before.meeting.start.date", errorMessage, + disbursementDate.toString(), calendar.getStartDate()); } // Disbursement date should fall on a meeting date 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(), calendar.getTitle()); } @@ -231,10 +232,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final List existingTransactionIds = new ArrayList(); final List existingReversedTransactionIds = new ArrayList(); - PaymentDetail paymentDetail = PaymentDetail.generatePaymentDetail(command, changes); - if (paymentDetail != null) { - paymentDetailRepository.save(paymentDetail); - } + PaymentDetail paymentDetail = paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes); loan.disburse(currentUser, command, applicationCurrency, existingTransactionIds, existingReversedTransactionIds, changes, paymentDetail); @@ -314,10 +312,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf changes.put("note", noteText); } - PaymentDetail paymentDetail = PaymentDetail.generatePaymentDetail(command, changes); - if (paymentDetail != null) { - paymentDetailRepository.save(paymentDetail); - } + PaymentDetail paymentDetail = paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes); + CommandProcessingResultBuilder commandProcessingResultBuilder = saveLoanRepayment(loanId, paymentDetail, transactionAmount, transactionDate, noteText); @@ -418,7 +414,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final List existingReversedTransactionIds = new ArrayList(); 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); if (transactionToAdjust.isInterestWaiver()) { newTransactionDetail = LoanTransaction.waiver(loan, transactionAmountAsMoney, transactionDate); @@ -429,7 +425,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf if (newTransactionDetail.isGreaterThanZero(loan.getPrincpal().getCurrency())) { if (paymentDetail != null) { - paymentDetailRepository.save(paymentDetail); + paymentDetailWritePlatformService.persistPaymentDetail(paymentDetail); } this.loanTransactionRepository.save(newTransactionDetail); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java index bea254c7e..c49f77f8c 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java @@ -31,6 +31,8 @@ import org.mifosplatform.accounting.producttoaccountmapping.service.ProductToGLA import org.mifosplatform.commands.domain.CommandWrapper; import org.mifosplatform.commands.service.CommandWrapperBuilder; 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.data.CommandProcessingResult; 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.service.LoanDropdownReadPlatformService; import org.mifosplatform.portfolio.loanproduct.service.LoanProductReadPlatformService; +import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @@ -61,10 +64,10 @@ public class LoanProductsApiResource { "maxNumberOfRepayments", "repaymentEvery", "repaymentFrequencyType", "interestRatePerPeriod", "minInterestRatePerPeriod", "maxInterestRatePerPeriod", "interestRateFrequencyType", "annualInterestRate", "amortizationType", "interestType", "interestCalculationPeriodType", "inArrearsTolerance", "transactionProcessingStrategyId", "transactionProcessingStrategyName", - "charges", "accountingRule", "accountingMappings", "fundOptions", "currencyOptions", "repaymentFrequencyTypeOptions", - "interestRateFrequencyTypeOptions", "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", - "transactionProcessingStrategyOptions", "chargeOptions", "accountingOptions", "accountingRuleOptions", - "accountingMappingOptions")); + "charges", "accountingRule", "accountingMappings", "paymentChannelToFundSourceMappings", "fundOptions", "paymentTypeOptions", + "currencyOptions", "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "amortizationTypeOptions", + "interestTypeOptions", "interestCalculationPeriodTypeOptions", "transactionProcessingStrategyOptions", "chargeOptions", + "accountingOptions", "accountingRuleOptions", "accountingMappingOptions")); private final String resourceNameForPermissions = "LOANPRODUCT"; @@ -79,6 +82,7 @@ public class LoanProductsApiResource { private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; private final GLAccountReadPlatformService accountReadPlatformService; private final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService; + private final CodeValueReadPlatformService codeValueReadPlatformService; @Autowired public LoanProductsApiResource(final PlatformSecurityContext context, final LoanProductReadPlatformService readPlatformService, @@ -88,7 +92,8 @@ public class LoanProductsApiResource { final ApiRequestParameterHelper apiRequestParameterHelper, final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService, final GLAccountReadPlatformService accountReadPlatformService, - final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService) { + final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService, + final CodeValueReadPlatformService codeValueReadPlatformService) { this.context = context; this.loanProductReadPlatformService = readPlatformService; this.chargeReadPlatformService = chargeReadPlatformService; @@ -100,6 +105,7 @@ public class LoanProductsApiResource { this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; this.accountReadPlatformService = accountReadPlatformService; this.accountMappingReadPlatformService = accountMappingReadPlatformService; + this.codeValueReadPlatformService = codeValueReadPlatformService; } @POST @@ -136,7 +142,7 @@ public class LoanProductsApiResource { context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions); LoanProductData loanProduct = this.loanProductReadPlatformService.retrieveNewLoanProductDetails(); - loanProduct = handleTemplate(loanProduct, new HashMap()); + loanProduct = handleTemplate(loanProduct, new HashMap(), null); final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); return this.toApiJsonSerializer.serialize(settings, loanProduct, LOAN_PRODUCT_DATA_PARAMETERS); @@ -155,14 +161,17 @@ public class LoanProductsApiResource { LoanProductData loanProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId); Map accountingMappings = null; + Map paymentChannelToFundSourceMappings = null; if (loanProduct.hasAccountingEnabled()) { accountingMappings = accountMappingReadPlatformService.fetchAccountMappingDetailsForLoanProduct(productId, loanProduct .accountingRuleType().getId().intValue()); - loanProduct = LoanProductData.withAccountingMappings(loanProduct, accountingMappings); + paymentChannelToFundSourceMappings = accountMappingReadPlatformService + .fetchPaymentTypeToFundSourceMappingsForLoanProduct(productId); + loanProduct = LoanProductData.withAccountingDetails(loanProduct, accountingMappings, paymentChannelToFundSourceMappings); } if (settings.isTemplate()) { - loanProduct = handleTemplate(loanProduct, accountingMappings); + loanProduct = handleTemplate(loanProduct, accountingMappings, paymentChannelToFundSourceMappings); } return this.toApiJsonSerializer.serialize(settings, loanProduct, LOAN_PRODUCT_DATA_PARAMETERS); } @@ -181,7 +190,8 @@ public class LoanProductsApiResource { return this.toApiJsonSerializer.serialize(result); } - private LoanProductData handleTemplate(final LoanProductData productData, final Map accountingMappings) { + private LoanProductData handleTemplate(final LoanProductData productData, final Map accountingMappings, + final Map paymentChannelToFundSourceMappings) { final boolean feeChargesOnly = true; Collection chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly); @@ -197,6 +207,8 @@ public class LoanProductsApiResource { final List repaymentFrequencyTypeOptions = dropdownReadPlatformService.retrieveRepaymentFrequencyTypeOptions(); final List interestRateFrequencyTypeOptions = dropdownReadPlatformService .retrieveInterestRateFrequencyTypeOptions(); + final Collection paymentTypeOptions = codeValueReadPlatformService + .retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName); Collection fundOptions = this.fundReadPlatformService.retrieveAllFunds(); if (fundOptions.isEmpty()) { @@ -226,8 +238,9 @@ public class LoanProductsApiResource { List accountingRuleTypeOptions = dropdownReadPlatformService.retrieveAccountingRuleTypeOptions(); - return new LoanProductData(productData, chargeOptions, currencyOptions, amortizationTypeOptions, interestTypeOptions, - interestCalculationPeriodTypeOptions, repaymentFrequencyTypeOptions, interestRateFrequencyTypeOptions, fundOptions, - transactionProcessingStrategyOptions, accountOptions, accountingRuleTypeOptions, accountingMappings); + return new LoanProductData(productData, chargeOptions, paymentTypeOptions, currencyOptions, amortizationTypeOptions, + interestTypeOptions, interestCalculationPeriodTypeOptions, repaymentFrequencyTypeOptions, interestRateFrequencyTypeOptions, + fundOptions, transactionProcessingStrategyOptions, accountOptions, accountingRuleTypeOptions, accountingMappings, + paymentChannelToFundSourceMappings); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java index 173149150..6b0efe4c1 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java @@ -12,6 +12,7 @@ import java.util.List; import java.util.Map; import org.mifosplatform.accounting.glaccount.data.GLAccountData; +import org.mifosplatform.infrastructure.codes.data.CodeValueData; import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.portfolio.charge.data.ChargeData; @@ -65,9 +66,12 @@ public class LoanProductData { private final EnumOptionData accountingRule; @SuppressWarnings("unused") private final Map accountingMappings; + @SuppressWarnings("unused") + private final Map paymentChannelToFundSourceMappings; // template related private final Collection fundOptions; + private final Collection paymentTypeOptions; private final Collection currencyOptions; private final List repaymentFrequencyTypeOptions; private final List interestRateFrequencyTypeOptions; @@ -186,13 +190,14 @@ public class LoanProductData { transactionProcessingStrategyName, charges, accountingType); } - public static LoanProductData withAccountingMappings(final LoanProductData productData, final Map accountingMappings) { + public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map accountingMappings, + final Map 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.repaymentFrequencyTypeOptions, productData.interestRateFrequencyTypeOptions, productData.fundOptions, productData.transactionProcessingStrategyOptions, productData.accountingMappingOptions, productData.accountingRuleOptions, - accountingMappings); + accountingMappings, paymentChannelToFundSourceMappings); } 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.chargeOptions = null; + this.paymentTypeOptions = null; this.currencyOptions = null; this.fundOptions = null; this.transactionProcessingStrategyOptions = null; @@ -254,15 +260,17 @@ public class LoanProductData { this.accountingMappingOptions = null; this.accountingRuleOptions = null; this.accountingMappings = null; + this.paymentChannelToFundSourceMappings = null; } public LoanProductData(final LoanProductData productData, final Collection chargeOptions, - final Collection currencyOptions, final List amortizationTypeOptions, - final List interestTypeOptions, final List interestCalculationPeriodTypeOptions, - final List repaymentFrequencyTypeOptions, final List interestRateFrequencyTypeOptions, - final Collection fundOptions, final Collection transactionStrategyOptions, + final Collection paymentTypeOptions, final Collection currencyOptions, + final List amortizationTypeOptions, final List interestTypeOptions, + final List interestCalculationPeriodTypeOptions, final List repaymentFrequencyTypeOptions, + final List interestRateFrequencyTypeOptions, final Collection fundOptions, + final Collection transactionStrategyOptions, final Map> accountingMappingOptions, final List accountingRuleOptions, - final Map accountingMappings) { + final Map accountingMappings, final Map paymentChannelToFundSourceMappings) { this.id = productData.id; this.name = productData.name; this.description = productData.description; @@ -291,6 +299,7 @@ public class LoanProductData { this.accountingRule = productData.accountingRule; this.chargeOptions = chargeOptions; + this.paymentTypeOptions = paymentTypeOptions; this.currencyOptions = currencyOptions; this.currency = productData.currency; this.fundOptions = fundOptions; @@ -320,6 +329,8 @@ public class LoanProductData { } else { this.accountingMappings = accountingMappings; } + + this.paymentChannelToFundSourceMappings = paymentChannelToFundSourceMappings; } private Collection nullIfEmpty(final Collection charges) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductCommandFromApiJsonDeserializer.java index 37aadfab9..5f5f93826 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductCommandFromApiJsonDeserializer.java @@ -27,7 +27,9 @@ import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.google.gson.reflect.TypeToken; @Component @@ -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.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.PENALTIES_RECEIVABLE.getValue())); + LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue())); 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) .notNull().integerGreaterThanZero(); + validatePaymentChannelFundSourceMappings(baseDataValidator, element); + } if (isAccrualBasedAccounting(accountingRuleType)) { @@ -461,11 +466,48 @@ public final class LoanProductCommandFromApiJsonDeserializer { baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue()) .value(receivablePenaltyAccountId).ignoreIfNull().integerGreaterThanZero(); + validatePaymentChannelFundSourceMappings(baseDataValidator, element); + validateMinMaxConstraints(element, baseDataValidator, loanProduct); 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, final LoanProduct loanProduct) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanDropdownReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanDropdownReadPlatformService.java index 21d621547..b9324e277 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanDropdownReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanDropdownReadPlatformService.java @@ -29,5 +29,4 @@ public interface LoanDropdownReadPlatformService { List retrieveAccountingRuleTypeOptions(); - List retrievePaymentTypeOptions(); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java index c12b3b2d8..9453f3282 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanDropdownReadPlatformServiceImpl.java @@ -5,13 +5,13 @@ */ 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.interestCalculationPeriodType; 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.loanTermFrequencyType; 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.Arrays; @@ -20,7 +20,6 @@ import java.util.List; import org.mifosplatform.infrastructure.core.data.EnumOptionData; 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.domain.AccountingRuleType; import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod; @@ -111,8 +110,4 @@ public class LoanDropdownReadPlatformServiceImpl implements LoanDropdownReadPlat return accountingRuleTypeOptions; } - @Override - public List retrievePaymentTypeOptions() { - return LoanEnumerations.paymentTypes(PaymentType.values()); - } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java index ac8ed84c8..d65ee98e9 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java @@ -5,16 +5,12 @@ */ package org.mifosplatform.portfolio.loanproduct.service; -import java.util.ArrayList; -import java.util.List; - import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.portfolio.loanaccount.data.LoanStatusEnumData; import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData; import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus; import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionType; 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.AmortizationMethod; import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod; @@ -49,8 +45,6 @@ public class LoanEnumerations { return interestType(id); } else if (typeName.equals(INTEREST_CALCULATION_PERIOD_TYPE)) { return interestCalculationPeriodType(id); - } else if (typeName.equals(PAYMENT_TYPE)) { - return paymentType(id); } else if (typeName.equals(ACCOUNTING_RULE_TYPE)) { return accountingRuleType(id); } else if (typeName.equals(LOAN_TYPE)) { return loanType(id); } @@ -236,27 +230,6 @@ public class LoanEnumerations { return optionData; } - public static List paymentTypes(final PaymentType[] paymentTypes) { - final List optionDatas = new ArrayList(); - 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) { return transactionType(LoanTransactionType.fromInt(id)); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/paymentdetail/PaymentDetailConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/paymentdetail/PaymentDetailConstants.java new file mode 100755 index 000000000..ea4708069 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/paymentdetail/PaymentDetailConstants.java @@ -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 PAYMENT_CREATE_REQUEST_DATA_PARAMETERS = new HashSet(Arrays.asList(accountNumberParamName, + checkNumberParamName, routingCodeParamName, receiptNumberParamName, bankNumberParamName)); + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/PaymentDetailData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/paymentdetail/data/PaymentDetailData.java similarity index 78% rename from mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/PaymentDetailData.java rename to mifosng-provider/src/main/java/org/mifosplatform/portfolio/paymentdetail/data/PaymentDetailData.java index 55ba9c1b4..6739acc8d 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/PaymentDetailData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/paymentdetail/data/PaymentDetailData.java @@ -3,9 +3,9 @@ * 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.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. @@ -15,7 +15,7 @@ public class PaymentDetailData { @SuppressWarnings("unused") private final Long id; @SuppressWarnings("unused") - private final EnumOptionData paymentType; + private final CodeValueData paymentType; @SuppressWarnings("unused") private final String accountNumber; @SuppressWarnings("unused") @@ -27,7 +27,7 @@ public class PaymentDetailData { @SuppressWarnings("unused") 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) { this.id = id; this.paymentType = paymentType; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/paymentdetail/domain/PaymentDetail.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/paymentdetail/domain/PaymentDetail.java new file mode 100755 index 000000000..730d5f0ba --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/paymentdetail/domain/PaymentDetail.java @@ -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 { + + @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 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; + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/PaymentDetailRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/paymentdetail/domain/PaymentDetailRepository.java similarity index 80% rename from mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/PaymentDetailRepository.java rename to mifosng-provider/src/main/java/org/mifosplatform/portfolio/paymentdetail/domain/PaymentDetailRepository.java index 90353b22d..f6d70e6c8 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/PaymentDetailRepository.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/paymentdetail/domain/PaymentDetailRepository.java @@ -3,8 +3,9 @@ * 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; +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.JpaSpecificationExecutor; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/paymentdetail/service/PaymentDetailWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/paymentdetail/service/PaymentDetailWritePlatformService.java new file mode 100755 index 000000000..c8f16248e --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/paymentdetail/service/PaymentDetailWritePlatformService.java @@ -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 changes); + + PaymentDetail createPaymentDetail(final JsonCommand command, Map changes); + + PaymentDetail persistPaymentDetail(PaymentDetail paymentDetail); +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/paymentdetail/service/PaymentDetailWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/paymentdetail/service/PaymentDetailWritePlatformServiceJpaRepositoryImpl.java new file mode 100755 index 000000000..a6667f10e --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/paymentdetail/service/PaymentDetailWritePlatformServiceJpaRepositoryImpl.java @@ -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 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 changes) { + PaymentDetail paymentDetail = createPaymentDetail(command, changes); + if (paymentDetail != null) { return persistPaymentDetail(paymentDetail); } + return paymentDetail; + } +} \ No newline at end of file