@@ -0,0 +1,27 @@
|
|||||||
|
CREATE TABLE `m_portfolio_account_associations` (
|
||||||
|
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`loan_account_id` BIGINT NULL DEFAULT NULL,
|
||||||
|
`savings_account_id` BIGINT NULL DEFAULT NULL,
|
||||||
|
`linked_loan_account_id` BIGINT NULL DEFAULT NULL,
|
||||||
|
`linked_savings_account_id` BIGINT NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
CONSTRAINT `account_association_loan_fk` FOREIGN KEY (`loan_account_id`) REFERENCES `m_loan` (`id`),
|
||||||
|
CONSTRAINT `account_association_savings_fk` FOREIGN KEY (`savings_account_id`) REFERENCES `m_savings_account` (`id`),
|
||||||
|
CONSTRAINT `linked_loan_fk` FOREIGN KEY (`linked_loan_account_id`) REFERENCES `m_loan` (`id`),
|
||||||
|
CONSTRAINT `linked_savings_fk` FOREIGN KEY (`linked_savings_account_id`) REFERENCES `m_savings_account` (`id`)
|
||||||
|
)
|
||||||
|
COLLATE='utf8_general_ci'
|
||||||
|
ENGINE=InnoDB;
|
||||||
|
|
||||||
|
ALTER TABLE `m_charge`
|
||||||
|
ADD COLUMN `charge_payment_mode_enum` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `charge_calculation_enum`;
|
||||||
|
|
||||||
|
ALTER TABLE `m_loan_charge`
|
||||||
|
ADD COLUMN `charge_payment_mode_enum` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `charge_calculation_enum`;
|
||||||
|
|
||||||
|
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('transaction_loan', 'PAY_LOANCHARGE', 'LOANCHARGE', 'PAY', 0);
|
||||||
|
|
||||||
|
INSERT INTO `job` (`name`, `display_name`, `cron_expression`, `create_time`, `task_priority`, `group_name`, `previous_run_start_time`, `next_run_time`, `job_key`, `initializing_errorlog`, `is_active`, `currently_running`, `updates_allowed`, `scheduler_group`, `is_misfired`) VALUES ('Transfer Fee For Loans From Savings', 'Transfer Fee For Loans From Savings', '0 1 0 1/1 * ? *', now(), 5, NULL, NULL, NULL, NULL, NULL, 1, 0, 1, 0, 0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+4
-4
@@ -54,9 +54,9 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
* Repayments and Repayments at disbursement
|
* Repayments and Repayments at disbursement
|
||||||
***/
|
***/
|
||||||
else if (loanTransactionDTO.getTransactionType().isRepayment()
|
else if (loanTransactionDTO.getTransactionType().isRepayment()
|
||||||
|| loanTransactionDTO.getTransactionType().isRepaymentAtDisbursement()) {
|
|| loanTransactionDTO.getTransactionType().isRepaymentAtDisbursement() || loanTransactionDTO.getTransactionType().isChargePayment()) {
|
||||||
createJournalEntriesForRepaymentsAndWriteOffs(loanDTO, loanTransactionDTO, office, false, loanTransactionDTO
|
createJournalEntriesForRepaymentsAndWriteOffs(loanDTO, loanTransactionDTO, office, false, loanTransactionDTO
|
||||||
.getTransactionType().isRepaymentAtDisbursement());
|
.getTransactionType().isRepaymentAtDisbursement() || loanTransactionDTO.getTransactionType().isChargePayment());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Handle Write Offs, waivers and their reversals **/
|
/** Handle Write Offs, waivers and their reversals **/
|
||||||
@@ -170,7 +170,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private void createJournalEntriesForRepaymentsAndWriteOffs(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO,
|
private void createJournalEntriesForRepaymentsAndWriteOffs(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO,
|
||||||
final Office office, final boolean writeOff, final boolean repaymentAtDisbursement) {
|
final Office office, final boolean writeOff, final boolean isIncomeFromFee) {
|
||||||
// loan properties
|
// loan properties
|
||||||
final Long loanProductId = loanDTO.getLoanProductId();
|
final Long loanProductId = loanDTO.getLoanProductId();
|
||||||
final Long loanId = loanDTO.getLoanId();
|
final Long loanId = loanDTO.getLoanId();
|
||||||
@@ -208,7 +208,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
|||||||
|
|
||||||
ACCRUAL_ACCOUNTS_FOR_LOAN feeAccountToCredit = ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE;
|
ACCRUAL_ACCOUNTS_FOR_LOAN feeAccountToCredit = ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE;
|
||||||
|
|
||||||
if (repaymentAtDisbursement) {
|
if (isIncomeFromFee) {
|
||||||
feeAccountToCredit = ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES;
|
feeAccountToCredit = ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -51,7 +51,8 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF
|
|||||||
* Repayments and Repayments at disbursement
|
* Repayments and Repayments at disbursement
|
||||||
***/
|
***/
|
||||||
else if (loanTransactionDTO.getTransactionType().isRepayment()
|
else if (loanTransactionDTO.getTransactionType().isRepayment()
|
||||||
|| loanTransactionDTO.getTransactionType().isRepaymentAtDisbursement()) {
|
|| loanTransactionDTO.getTransactionType().isRepaymentAtDisbursement()
|
||||||
|
|| loanTransactionDTO.getTransactionType().isChargePayment()) {
|
||||||
createJournalEntriesForRepayments(loanDTO, loanTransactionDTO, office);
|
createJournalEntriesForRepayments(loanDTO, loanTransactionDTO, office);
|
||||||
}
|
}
|
||||||
/***
|
/***
|
||||||
|
|||||||
@@ -385,6 +385,10 @@ public class CommandWrapper {
|
|||||||
return this.actionName.equalsIgnoreCase("WAIVE") && this.entityName.equalsIgnoreCase("LOANCHARGE");
|
return this.actionName.equalsIgnoreCase("WAIVE") && this.entityName.equalsIgnoreCase("LOANCHARGE");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isPayLoanCharge() {
|
||||||
|
return this.actionName.equalsIgnoreCase("PAY") && this.entityName.equalsIgnoreCase("LOANCHARGE");
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isUpdateLoanOfficer() {
|
public boolean isUpdateLoanOfficer() {
|
||||||
return this.actionName.equalsIgnoreCase("UPDATELOANOFFICER") && this.entityName.equalsIgnoreCase("LOAN");
|
return this.actionName.equalsIgnoreCase("UPDATELOANOFFICER") && this.entityName.equalsIgnoreCase("LOAN");
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-2
@@ -489,9 +489,21 @@ public class CommandWrapperBuilder {
|
|||||||
this.loanId = loanId;
|
this.loanId = loanId;
|
||||||
this.href = "/loans/" + loanId + "/charges/" + loanChargeId;
|
this.href = "/loans/" + loanId + "/charges/" + loanChargeId;
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CommandWrapperBuilder payLoanCharge(final Long loanId, final Long loanChargeId) {
|
||||||
|
this.actionName = "PAY";
|
||||||
|
this.entityName = "LOANCHARGE";
|
||||||
|
this.entityId = loanChargeId;
|
||||||
|
this.loanId = loanId;
|
||||||
|
if(loanChargeId == null){
|
||||||
|
this.href = "/loans/" + loanId;
|
||||||
|
}else{
|
||||||
|
this.href = "/loans/" + loanId + "/charges/" + loanChargeId;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public CommandWrapperBuilder deleteLoanCharge(final Long loanId, final Long loanChargeId) {
|
public CommandWrapperBuilder deleteLoanCharge(final Long loanId, final Long loanChargeId) {
|
||||||
this.actionName = "DELETE";
|
this.actionName = "DELETE";
|
||||||
this.entityName = "LOANCHARGE";
|
this.entityName = "LOANCHARGE";
|
||||||
|
|||||||
+2
@@ -348,6 +348,8 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
|||||||
handler = this.applicationContext.getBean("updateLoanChargeCommandHandler", NewCommandSourceHandler.class);
|
handler = this.applicationContext.getBean("updateLoanChargeCommandHandler", NewCommandSourceHandler.class);
|
||||||
} else if (wrapper.isWaiveLoanCharge()) {
|
} else if (wrapper.isWaiveLoanCharge()) {
|
||||||
handler = this.applicationContext.getBean("waiveLoanChargeCommandHandler", NewCommandSourceHandler.class);
|
handler = this.applicationContext.getBean("waiveLoanChargeCommandHandler", NewCommandSourceHandler.class);
|
||||||
|
} else if (wrapper.isPayLoanCharge()) {
|
||||||
|
handler = this.applicationContext.getBean("payLoanChargeCommandHandler", NewCommandSourceHandler.class);
|
||||||
}
|
}
|
||||||
} else if (wrapper.isGLAccountResource()) {
|
} else if (wrapper.isGLAccountResource()) {
|
||||||
if (wrapper.isCreate()) {
|
if (wrapper.isCreate()) {
|
||||||
|
|||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package org.mifosplatform.infrastructure.jobs.exception;
|
||||||
|
|
||||||
|
|
||||||
|
public class JobExecutionException extends Exception{
|
||||||
|
|
||||||
|
public JobExecutionException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -4,7 +4,8 @@ public enum JobName {
|
|||||||
|
|
||||||
UPDATE_LOAN_SUMMARY("Update loan Summary"), UPDATE_LOAN_ARREARS_AGEING("Update Loan Arrears Ageing"), UPDATE_LOAN_PAID_IN_ADVANCE(
|
UPDATE_LOAN_SUMMARY("Update loan Summary"), UPDATE_LOAN_ARREARS_AGEING("Update Loan Arrears Ageing"), UPDATE_LOAN_PAID_IN_ADVANCE(
|
||||||
"Update Loan Paid In Advance"), APPLY_ANNUAL_FEE_FOR_SAVINGS("Apply Annual Fee For Savings"), APPLY_HOLIDAYS_TO_LOANS(
|
"Update Loan Paid In Advance"), APPLY_ANNUAL_FEE_FOR_SAVINGS("Apply Annual Fee For Savings"), APPLY_HOLIDAYS_TO_LOANS(
|
||||||
"Apply Holidays To Loans"), POST_INTEREST_FOR_SAVINGS("Post Interest For Savings");
|
"Apply Holidays To Loans"), POST_INTEREST_FOR_SAVINGS("Post Interest For Savings"), TRANSFER_FEE_CHARGE_FOR_LOANS(
|
||||||
|
"Transfer Fee For Loans From Savings");
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
|
|||||||
mifosng-provider/src/main/java/org/mifosplatform/portfolio/account/data/AccountAssociationsData.java
Executable
+18
@@ -0,0 +1,18 @@
|
|||||||
|
package org.mifosplatform.portfolio.account.data;
|
||||||
|
|
||||||
|
public class AccountAssociationsData {
|
||||||
|
|
||||||
|
private final Long id;
|
||||||
|
private final PortfolioAccountData account;
|
||||||
|
private final PortfolioAccountData linkedAccount;
|
||||||
|
|
||||||
|
public AccountAssociationsData(final Long id, final PortfolioAccountData account, final PortfolioAccountData linkedAccount) {
|
||||||
|
this.id = id;
|
||||||
|
this.account = account;
|
||||||
|
this.linkedAccount = linkedAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PortfolioAccountData linkedAccount() {
|
||||||
|
return this.linkedAccount;
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+99
@@ -0,0 +1,99 @@
|
|||||||
|
package org.mifosplatform.portfolio.account.data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
|
import org.joda.time.format.DateTimeFormatter;
|
||||||
|
import org.mifosplatform.portfolio.account.PortfolioAccountType;
|
||||||
|
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
|
||||||
|
|
||||||
|
public class AccountTransferDTO {
|
||||||
|
|
||||||
|
private LocalDate transactionDate;
|
||||||
|
private BigDecimal transactionAmount;
|
||||||
|
private PortfolioAccountType fromAccountType;
|
||||||
|
private PortfolioAccountType toAccountType;
|
||||||
|
private Long fromAccountId;
|
||||||
|
private Long toAccountId;
|
||||||
|
private String description;
|
||||||
|
private Locale locale;
|
||||||
|
private DateTimeFormatter fmt;
|
||||||
|
private PaymentDetail paymentDetail;
|
||||||
|
private Integer fromTransferType;
|
||||||
|
private Integer toTransferType;
|
||||||
|
private Long chargeId;
|
||||||
|
|
||||||
|
public AccountTransferDTO(final LocalDate transactionDate, final BigDecimal transactionAmount,
|
||||||
|
final PortfolioAccountType fromAccountType, final PortfolioAccountType toAccountType, final Long fromAccountId,
|
||||||
|
final Long toAccountId, final String description, final Locale locale, final DateTimeFormatter fmt,
|
||||||
|
final PaymentDetail paymentDetail, final Integer fromTransferType, final Integer toTransferType, final Long chargeId) {
|
||||||
|
this.transactionDate = transactionDate;
|
||||||
|
this.transactionAmount = transactionAmount;
|
||||||
|
this.fromAccountType = fromAccountType;
|
||||||
|
this.toAccountType = toAccountType;
|
||||||
|
this.fromAccountId = fromAccountId;
|
||||||
|
this.toAccountId = toAccountId;
|
||||||
|
this.description = description;
|
||||||
|
this.locale = locale;
|
||||||
|
this.fmt = fmt;
|
||||||
|
this.paymentDetail = paymentDetail;
|
||||||
|
this.fromTransferType = fromTransferType;
|
||||||
|
this.toTransferType = toTransferType;
|
||||||
|
this.chargeId = chargeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getTransactionDate() {
|
||||||
|
return this.transactionDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getTransactionAmount() {
|
||||||
|
return this.transactionAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PortfolioAccountType getFromAccountType() {
|
||||||
|
return this.fromAccountType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PortfolioAccountType getToAccountType() {
|
||||||
|
return this.toAccountType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getFromAccountId() {
|
||||||
|
return this.fromAccountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getToAccountId() {
|
||||||
|
return this.toAccountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return this.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Locale getLocale() {
|
||||||
|
return this.locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTimeFormatter getFmt() {
|
||||||
|
return this.fmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PaymentDetail getPaymentDetail() {
|
||||||
|
return this.paymentDetail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getFromTransferType() {
|
||||||
|
return this.fromTransferType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getToTransferType() {
|
||||||
|
return this.toTransferType;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Long getChargeId() {
|
||||||
|
return this.chargeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+4
@@ -103,4 +103,8 @@ public class PortfolioAccountData {
|
|||||||
public BigDecimal getAmtForTransfer() {
|
public BigDecimal getAmtForTransfer() {
|
||||||
return this.amtForTransfer;
|
return this.amtForTransfer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long accountId(){
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Executable
+53
@@ -0,0 +1,53 @@
|
|||||||
|
package org.mifosplatform.portfolio.account.domain;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||||
|
import org.mifosplatform.portfolio.savings.domain.SavingsAccount;
|
||||||
|
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "m_portfolio_account_associations")
|
||||||
|
public class AccountAssociations extends AbstractPersistable<Long> {
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "loan_account_id", nullable = true)
|
||||||
|
private Loan loanAccount;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "savings_account_id", nullable = true)
|
||||||
|
private SavingsAccount savingsAccount;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "linked_loan_account_id", nullable = true)
|
||||||
|
private Loan linkedLoanAccount;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "linked_savings_account_id", nullable = true)
|
||||||
|
private SavingsAccount linkedSavingsAccount;
|
||||||
|
|
||||||
|
protected AccountAssociations() {}
|
||||||
|
|
||||||
|
private AccountAssociations(final Loan loanAccount, final SavingsAccount savingsAccount, final Loan linkedLoanAccount,
|
||||||
|
final SavingsAccount linkedSavingsAccount) {
|
||||||
|
this.loanAccount = loanAccount;
|
||||||
|
this.savingsAccount = savingsAccount;
|
||||||
|
this.linkedLoanAccount = linkedLoanAccount;
|
||||||
|
this.linkedSavingsAccount = linkedSavingsAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AccountAssociations associateSavingsAccount(Loan loan, SavingsAccount savingsAccount) {
|
||||||
|
return new AccountAssociations(loan, null, null, savingsAccount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SavingsAccount linkedSavingsAccount() {
|
||||||
|
return this.linkedSavingsAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateLinkedSavingsAccount(final SavingsAccount savingsAccount) {
|
||||||
|
this.linkedSavingsAccount = savingsAccount;
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
package org.mifosplatform.portfolio.account.domain;
|
||||||
|
|
||||||
|
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 AccountAssociationsRepository extends JpaRepository<AccountAssociations, Long>,
|
||||||
|
JpaSpecificationExecutor<AccountAssociations> {
|
||||||
|
|
||||||
|
@Query("from AccountAssociations aa where aa.loanAccount.id= :loanId")
|
||||||
|
AccountAssociations findByLoanId(@Param("loanId") Long loanId);
|
||||||
|
|
||||||
|
}
|
||||||
+15
@@ -23,6 +23,7 @@ import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
|||||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||||
import org.mifosplatform.organisation.office.domain.Office;
|
import org.mifosplatform.organisation.office.domain.Office;
|
||||||
import org.mifosplatform.organisation.office.domain.OfficeRepository;
|
import org.mifosplatform.organisation.office.domain.OfficeRepository;
|
||||||
|
import org.mifosplatform.portfolio.account.data.AccountTransferDTO;
|
||||||
import org.mifosplatform.portfolio.client.domain.Client;
|
import org.mifosplatform.portfolio.client.domain.Client;
|
||||||
import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper;
|
import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||||
@@ -139,4 +140,18 @@ public class AccountTransferAssembler {
|
|||||||
deposit, loanRefundTransaction, transactionDate, transactionMonetaryAmount, description);
|
deposit, loanRefundTransaction, transactionDate, transactionMonetaryAmount, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AccountTransfer assembleSavingsToLoanTransfer(final AccountTransferDTO accountTransferDTO,
|
||||||
|
final SavingsAccount fromSavingsAccount, final Loan toLoanAccount, final SavingsAccountTransaction savingsAccountTransaction,
|
||||||
|
final LoanTransaction loanTransaction) {
|
||||||
|
final Office fromOffice = fromSavingsAccount.office();
|
||||||
|
final Client fromClient = fromSavingsAccount.getClient();
|
||||||
|
final Office toOffice = toLoanAccount.getOffice();
|
||||||
|
final Client toClient = toLoanAccount.client();
|
||||||
|
|
||||||
|
final Money transactionMonetaryAmount = Money.of(fromSavingsAccount.getCurrency(), accountTransferDTO.getTransactionAmount());
|
||||||
|
return AccountTransfer.savingsToLoanTransfer(fromOffice, fromClient, fromSavingsAccount, toOffice, toClient, toLoanAccount,
|
||||||
|
savingsAccountTransaction, loanTransaction, accountTransferDTO.getTransactionDate(), transactionMonetaryAmount,
|
||||||
|
accountTransferDTO.getDescription());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+4
-1
@@ -15,5 +15,8 @@ import org.springframework.data.repository.query.Param;
|
|||||||
public interface AccountTransferRepository extends JpaRepository<AccountTransfer, Long>, JpaSpecificationExecutor<AccountTransfer> {
|
public interface AccountTransferRepository extends JpaRepository<AccountTransfer, Long>, JpaSpecificationExecutor<AccountTransfer> {
|
||||||
|
|
||||||
@Query("from AccountTransfer at where at.fromLoanAccount.id= :accountNumber and at.reversed=false")
|
@Query("from AccountTransfer at where at.fromLoanAccount.id= :accountNumber and at.reversed=false")
|
||||||
List<AccountTransfer> findByLoanId(@Param("accountNumber") Long accountNumber);
|
List<AccountTransfer> findByFromLoanId(@Param("accountNumber") Long accountNumber);
|
||||||
|
|
||||||
|
@Query("from AccountTransfer at where (at.fromLoanAccount.id= :accountNumber or at.toLoanAccount.id=:accountNumber) and at.reversed=false")
|
||||||
|
List<AccountTransfer> findAllByLoanId(@Param("accountNumber") Long accountNumber);
|
||||||
}
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package org.mifosplatform.portfolio.account.service;
|
||||||
|
|
||||||
|
import org.mifosplatform.portfolio.account.data.PortfolioAccountData;
|
||||||
|
|
||||||
|
|
||||||
|
public interface AccountAssociationsReadPlatformService {
|
||||||
|
|
||||||
|
public PortfolioAccountData retriveLoanAssociation(final Long loanId);
|
||||||
|
|
||||||
|
public boolean isLinkedWithAnyActiveLoan(final Long savingsId);
|
||||||
|
}
|
||||||
+124
@@ -0,0 +1,124 @@
|
|||||||
|
package org.mifosplatform.portfolio.account.service;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||||
|
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||||
|
import org.mifosplatform.portfolio.account.data.AccountAssociationsData;
|
||||||
|
import org.mifosplatform.portfolio.account.data.PortfolioAccountData;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.dao.EmptyResultDataAccessException;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.jdbc.core.RowMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class AccountAssociationsReadPlatformServiceImpl implements AccountAssociationsReadPlatformService {
|
||||||
|
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger(AccountAssociationsReadPlatformServiceImpl.class);
|
||||||
|
private final JdbcTemplate jdbcTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public AccountAssociationsReadPlatformServiceImpl(final RoutingDataSource dataSource) {
|
||||||
|
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PortfolioAccountData retriveLoanAssociation(final Long loanId) {
|
||||||
|
PortfolioAccountData linkedAccount = null;
|
||||||
|
AccountAssociationsMapper mapper = new AccountAssociationsMapper();
|
||||||
|
String sql = "select " + mapper.schema() + " where aa.loan_account_id = ? ";
|
||||||
|
try {
|
||||||
|
AccountAssociationsData accountAssociationsData = jdbcTemplate.queryForObject(sql, mapper, loanId);
|
||||||
|
if (accountAssociationsData != null) {
|
||||||
|
linkedAccount = accountAssociationsData.linkedAccount();
|
||||||
|
}
|
||||||
|
} catch (EmptyResultDataAccessException e) {
|
||||||
|
logger.debug("Linking account is not configured");
|
||||||
|
}
|
||||||
|
return linkedAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLinkedWithAnyActiveLoan(final Long savingsId) {
|
||||||
|
boolean hasActiveLoan = false;
|
||||||
|
String sql = "select loanAccount.loan_status_id as status from m_portfolio_account_associations aa " +
|
||||||
|
"left join m_loan loanAccount on loanAccount.id = aa.loan_account_id " +
|
||||||
|
"where aa.linked_savings_account_id = ?";
|
||||||
|
|
||||||
|
List<Integer> statusList= this.jdbcTemplate.queryForList(sql,Integer.class, savingsId);
|
||||||
|
for(Integer status:statusList){
|
||||||
|
LoanStatus loanStatus= LoanStatus.fromInt(status);
|
||||||
|
if(loanStatus.isActiveOrAwaitingApprovalOrDisbursal() || loanStatus.isUnderTransfer()){
|
||||||
|
hasActiveLoan = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hasActiveLoan;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class AccountAssociationsMapper implements RowMapper<AccountAssociationsData> {
|
||||||
|
|
||||||
|
private final String schemaSql;
|
||||||
|
|
||||||
|
public AccountAssociationsMapper() {
|
||||||
|
StringBuilder sqlBuilder = new StringBuilder();
|
||||||
|
sqlBuilder.append("aa.id as id,");
|
||||||
|
// sqlBuilder.append("savingsAccount.id as savingsAccountId, savingsAccount.account_no as savingsAccountNo,");
|
||||||
|
sqlBuilder.append("loanAccount.id as loanAccountId, loanAccount.account_no as loanAccountNo,");
|
||||||
|
// sqlBuilder.append("linkLoanAccount.id as linkLoanAccountId, linkLoanAccount.account_no as linkLoanAccountNo, ");
|
||||||
|
sqlBuilder.append("linkSavingsAccount.id as linkSavingsAccountId, linkSavingsAccount.account_no as linkSavingsAccountNo ");
|
||||||
|
sqlBuilder.append("from m_portfolio_account_associations aa ");
|
||||||
|
// sqlBuilder.append("left join m_savings_account savingsAccount on savingsAccount.id = aa.savings_account_id ");
|
||||||
|
sqlBuilder.append("left join m_loan loanAccount on loanAccount.id = aa.loan_account_id ");
|
||||||
|
sqlBuilder.append("left join m_savings_account linkSavingsAccount on linkSavingsAccount.id = aa.linked_savings_account_id ");
|
||||||
|
// sqlBuilder.append("left join m_loan linkLoanAccount on linkLoanAccount.id = aa.linked_loan_account_id ");
|
||||||
|
this.schemaSql = sqlBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String schema() {
|
||||||
|
return this.schemaSql;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AccountAssociationsData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException {
|
||||||
|
|
||||||
|
final Long id = rs.getLong("id");
|
||||||
|
// final Long savingsAccountId = JdbcSupport.getLong(rs,
|
||||||
|
// "savingsAccountId");
|
||||||
|
// final String savingsAccountNo = rs.getString("savingsAccountNo");
|
||||||
|
final Long loanAccountId = JdbcSupport.getLong(rs, "loanAccountId");
|
||||||
|
final String loanAccountNo = rs.getString("loanAccountNo");
|
||||||
|
PortfolioAccountData account = PortfolioAccountData.lookup(loanAccountId, loanAccountNo);
|
||||||
|
;
|
||||||
|
/*
|
||||||
|
* if (savingsAccountId != null) { account =
|
||||||
|
* PortfolioAccountData.lookup(savingsAccountId, savingsAccountNo);
|
||||||
|
* } else if (loanAccountId != null) { account =
|
||||||
|
* PortfolioAccountData.lookup(loanAccountId, loanAccountNo); }
|
||||||
|
*/
|
||||||
|
final Long linkSavingsAccountId = JdbcSupport.getLong(rs, "linkSavingsAccountId");
|
||||||
|
final String linkSavingsAccountNo = rs.getString("linkSavingsAccountNo");
|
||||||
|
// final Long linkLoanAccountId = JdbcSupport.getLong(rs,
|
||||||
|
// "linkLoanAccountId");
|
||||||
|
// final String linkLoanAccountNo =
|
||||||
|
// rs.getString("linkLoanAccountNo");
|
||||||
|
PortfolioAccountData linkedAccount = PortfolioAccountData.lookup(linkSavingsAccountId, linkSavingsAccountNo);
|
||||||
|
/*
|
||||||
|
* if (linkSavingsAccountId != null) { linkedAccount =
|
||||||
|
* PortfolioAccountData.lookup(linkSavingsAccountId,
|
||||||
|
* linkSavingsAccountNo); } else if (linkLoanAccountId != null) {
|
||||||
|
* linkedAccount = PortfolioAccountData.lookup(linkLoanAccountId,
|
||||||
|
* linkLoanAccountNo); }
|
||||||
|
*/
|
||||||
|
|
||||||
|
return new AccountAssociationsData(id, account, linkedAccount);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -261,7 +261,7 @@ public class AccountTransfersReadPlatformServiceImpl implements AccountTransfers
|
|||||||
sqlBuilder.append("join m_client fromclient on fromclient.id = sat.from_client_id ");
|
sqlBuilder.append("join m_client fromclient on fromclient.id = sat.from_client_id ");
|
||||||
sqlBuilder.append("join m_client toclient on toclient.id = sat.to_client_id ");
|
sqlBuilder.append("join m_client toclient on toclient.id = sat.to_client_id ");
|
||||||
sqlBuilder.append("left join m_savings_account fromsavacc on fromsavacc.id = sat.from_savings_account_id ");
|
sqlBuilder.append("left join m_savings_account fromsavacc on fromsavacc.id = sat.from_savings_account_id ");
|
||||||
sqlBuilder.append("left join m_savings_account fromloanacc on fromloanacc.id = sat.from_loan_account_id ");
|
sqlBuilder.append("left join m_loan fromloanacc on fromloanacc.id = sat.from_loan_account_id ");
|
||||||
sqlBuilder.append("left join m_savings_account tosavacc on tosavacc.id = sat.to_savings_account_id ");
|
sqlBuilder.append("left join m_savings_account tosavacc on tosavacc.id = sat.to_savings_account_id ");
|
||||||
sqlBuilder.append("left join m_loan toloanacc on toloanacc.id = sat.to_loan_account_id ");
|
sqlBuilder.append("left join m_loan toloanacc on toloanacc.id = sat.to_loan_account_id ");
|
||||||
sqlBuilder.append("left join m_savings_account_transaction fromsavtran on fromsavtran.id = sat.from_savings_transaction_id ");
|
sqlBuilder.append("left join m_savings_account_transaction fromsavtran on fromsavtran.id = sat.from_savings_transaction_id ");
|
||||||
|
|||||||
+6
-1
@@ -8,10 +8,15 @@ package org.mifosplatform.portfolio.account.service;
|
|||||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||||
import org.mifosplatform.portfolio.account.PortfolioAccountType;
|
import org.mifosplatform.portfolio.account.PortfolioAccountType;
|
||||||
|
import org.mifosplatform.portfolio.account.data.AccountTransferDTO;
|
||||||
|
|
||||||
public interface AccountTransfersWritePlatformService {
|
public interface AccountTransfersWritePlatformService {
|
||||||
|
|
||||||
CommandProcessingResult create(JsonCommand command);
|
CommandProcessingResult create(JsonCommand command);
|
||||||
|
|
||||||
void reverseTransfers(Long accountNumber, PortfolioAccountType accountTypeId);
|
void reverseTransfersWithFromAccountType(Long accountNumber, PortfolioAccountType accountTypeId);
|
||||||
|
|
||||||
|
Long transferFunds(AccountTransferDTO accountTransferDTO);
|
||||||
|
|
||||||
|
void reverseAllTransactions(Long accountId, PortfolioAccountType accountTypeId);
|
||||||
}
|
}
|
||||||
+67
-10
@@ -23,6 +23,7 @@ import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
|||||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||||
import org.mifosplatform.portfolio.account.PortfolioAccountType;
|
import org.mifosplatform.portfolio.account.PortfolioAccountType;
|
||||||
|
import org.mifosplatform.portfolio.account.data.AccountTransferDTO;
|
||||||
import org.mifosplatform.portfolio.account.data.AccountTransfersDataValidator;
|
import org.mifosplatform.portfolio.account.data.AccountTransfersDataValidator;
|
||||||
import org.mifosplatform.portfolio.account.domain.AccountTransfer;
|
import org.mifosplatform.portfolio.account.domain.AccountTransfer;
|
||||||
import org.mifosplatform.portfolio.account.domain.AccountTransferAssembler;
|
import org.mifosplatform.portfolio.account.domain.AccountTransferAssembler;
|
||||||
@@ -120,7 +121,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
|||||||
final Long toLoanAccountId = command.longValueOfParameterNamed(toAccountIdParamName);
|
final Long toLoanAccountId = command.longValueOfParameterNamed(toAccountIdParamName);
|
||||||
final Loan toLoanAccount = this.loanAccountAssembler.assembleFrom(toLoanAccountId);
|
final Loan toLoanAccount = this.loanAccountAssembler.assembleFrom(toLoanAccountId);
|
||||||
|
|
||||||
final LoanTransaction loanRepaymentTransaction = this.loanAccountDomainService.makeRepayment(toLoanAccountId,
|
final LoanTransaction loanRepaymentTransaction = this.loanAccountDomainService.makeRepayment(toLoanAccount,
|
||||||
new CommandProcessingResultBuilder(), transactionDate, transactionAmount, paymentDetail, null, null);
|
new CommandProcessingResultBuilder(), transactionDate, transactionAmount, paymentDetail, null, null);
|
||||||
|
|
||||||
final AccountTransfer transferTransaction = this.accountTransferAssembler.assembleSavingsToLoanTransfer(command,
|
final AccountTransfer transferTransaction = this.accountTransferAssembler.assembleSavingsToLoanTransfer(command,
|
||||||
@@ -166,23 +167,79 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public void reverseTransfers(Long accountNumber, PortfolioAccountType accountTypeId) {
|
public void reverseTransfersWithFromAccountType(Long accountNumber, PortfolioAccountType accountTypeId) {
|
||||||
List<AccountTransfer> acccountTransfers = null;
|
List<AccountTransfer> acccountTransfers = null;
|
||||||
if (accountTypeId.isLoanAccount()) {
|
if (accountTypeId.isLoanAccount()) {
|
||||||
acccountTransfers = this.accountTransferRepository.findByLoanId(accountNumber);
|
acccountTransfers = this.accountTransferRepository.findByFromLoanId(accountNumber);
|
||||||
}
|
}
|
||||||
if (acccountTransfers != null && acccountTransfers.size() > 0) {
|
if (acccountTransfers != null && acccountTransfers.size() > 0) {
|
||||||
for (AccountTransfer accountTransfer : acccountTransfers) {
|
undoTransactions(acccountTransfers);
|
||||||
this.loanAccountDomainService.reverseTransfer(accountTransfer.getFromLoanTransaction());
|
|
||||||
this.savingsAccountWritePlatformService.undoTransaction(accountTransfer.getToSavingsAccount().getId(), accountTransfer
|
|
||||||
.getToSavingsTransaction().getId());
|
|
||||||
accountTransfer.reverse();
|
|
||||||
this.accountTransferRepository.save(accountTransfer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void reverseAllTransactions(Long accountId, PortfolioAccountType accountTypeId) {
|
||||||
|
List<AccountTransfer> acccountTransfers = null;
|
||||||
|
if (accountTypeId.isLoanAccount()) {
|
||||||
|
acccountTransfers = this.accountTransferRepository.findAllByLoanId(accountId);
|
||||||
|
}
|
||||||
|
if (acccountTransfers != null && acccountTransfers.size() > 0) {
|
||||||
|
undoTransactions(acccountTransfers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param acccountTransfers
|
||||||
|
*/
|
||||||
|
private void undoTransactions(List<AccountTransfer> acccountTransfers) {
|
||||||
|
for (AccountTransfer accountTransfer : acccountTransfers) {
|
||||||
|
if (accountTransfer.getFromLoanTransaction() != null) {
|
||||||
|
this.loanAccountDomainService.reverseTransfer(accountTransfer.getFromLoanTransaction());
|
||||||
|
} else if (accountTransfer.getToLoanTransaction() != null) {
|
||||||
|
this.loanAccountDomainService.reverseTransfer(accountTransfer.getToLoanTransaction());
|
||||||
|
}
|
||||||
|
if (accountTransfer.getFromTransaction() != null) {
|
||||||
|
this.savingsAccountWritePlatformService.undoTransaction(accountTransfer.getFromAccount().getId(), accountTransfer
|
||||||
|
.getFromTransaction().getId(), true);
|
||||||
|
}
|
||||||
|
if (accountTransfer.getToSavingsTransaction() != null) {
|
||||||
|
this.savingsAccountWritePlatformService.undoTransaction(accountTransfer.getToSavingsAccount().getId(), accountTransfer
|
||||||
|
.getToSavingsTransaction().getId(), true);
|
||||||
|
}
|
||||||
|
accountTransfer.reverse();
|
||||||
|
this.accountTransferRepository.save(accountTransfer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public Long transferFunds(AccountTransferDTO accountTransferDTO) {
|
||||||
|
Long transferTransactionId = null;
|
||||||
|
if (isSavingsToLoanAccountTransfer(accountTransferDTO.getFromAccountType(), accountTransferDTO.getToAccountType())) {
|
||||||
|
//
|
||||||
|
final SavingsAccount fromSavingsAccount = this.savingsAccountAssembler.assembleFrom(accountTransferDTO.getFromAccountId());
|
||||||
|
|
||||||
|
final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount,
|
||||||
|
accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(),
|
||||||
|
accountTransferDTO.getPaymentDetail(), fromSavingsAccount.isWithdrawalFeeApplicableForTransfer());
|
||||||
|
|
||||||
|
final Loan toLoanAccount = this.loanAccountAssembler.assembleFrom(accountTransferDTO.getToAccountId());
|
||||||
|
|
||||||
|
final LoanTransaction loanRepaymentTransaction = this.loanAccountDomainService.makeChargePayment(toLoanAccount,
|
||||||
|
accountTransferDTO.getChargeId(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(),
|
||||||
|
accountTransferDTO.getPaymentDetail(), null, null, accountTransferDTO.getToTransferType());
|
||||||
|
|
||||||
|
final AccountTransfer transferTransaction = this.accountTransferAssembler.assembleSavingsToLoanTransfer(accountTransferDTO,
|
||||||
|
fromSavingsAccount, toLoanAccount, withdrawal, loanRepaymentTransaction);
|
||||||
|
this.accountTransferRepository.saveAndFlush(transferTransaction);
|
||||||
|
transferTransactionId = transferTransaction.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
return transferTransactionId;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isLoanToSavingsAccountTransfer(final PortfolioAccountType fromAccountType, final PortfolioAccountType toAccountType) {
|
private boolean isLoanToSavingsAccountTransfer(final PortfolioAccountType fromAccountType, final PortfolioAccountType toAccountType) {
|
||||||
return fromAccountType.isLoanAccount() && toAccountType.isSavingsAccount();
|
return fromAccountType.isLoanAccount() && toAccountType.isSavingsAccount();
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-14
@@ -28,30 +28,33 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
|||||||
private final EnumOptionData chargeTimeType;
|
private final EnumOptionData chargeTimeType;
|
||||||
private final EnumOptionData chargeAppliesTo;
|
private final EnumOptionData chargeAppliesTo;
|
||||||
private final EnumOptionData chargeCalculationType;
|
private final EnumOptionData chargeCalculationType;
|
||||||
|
private final EnumOptionData chargePaymentMode;
|
||||||
|
|
||||||
private final Collection<CurrencyData> currencyOptions;
|
private final Collection<CurrencyData> currencyOptions;
|
||||||
private final List<EnumOptionData> chargeCalculationTypeOptions;
|
private final List<EnumOptionData> chargeCalculationTypeOptions;
|
||||||
private final List<EnumOptionData> chargeAppliesToOptions;
|
private final List<EnumOptionData> chargeAppliesToOptions;
|
||||||
private final List<EnumOptionData> chargeTimeTypeOptions;
|
private final List<EnumOptionData> chargeTimeTypeOptions;
|
||||||
|
private final List<EnumOptionData> chargePaymetModeOptions;
|
||||||
|
|
||||||
public static ChargeData template(final Collection<CurrencyData> currencyOptions,
|
public static ChargeData template(final Collection<CurrencyData> currencyOptions,
|
||||||
final List<EnumOptionData> chargeCalculationTypeOptions, final List<EnumOptionData> chargeAppliesToOptions,
|
final List<EnumOptionData> chargeCalculationTypeOptions, final List<EnumOptionData> chargeAppliesToOptions,
|
||||||
final List<EnumOptionData> chargeTimeTypeOptions) {
|
final List<EnumOptionData> chargeTimeTypeOptions, List<EnumOptionData> chargePaymentModeOptions) {
|
||||||
return new ChargeData(null, null, null, null, null, null, null, false, false, currencyOptions, chargeCalculationTypeOptions,
|
return new ChargeData(null, null, null, null, null, null, null, null, false, false, currencyOptions,
|
||||||
chargeAppliesToOptions, chargeTimeTypeOptions);
|
chargeCalculationTypeOptions, chargeAppliesToOptions, chargeTimeTypeOptions, chargePaymentModeOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ChargeData withTemplate(final ChargeData charge, final ChargeData template) {
|
public static ChargeData withTemplate(final ChargeData charge, final ChargeData template) {
|
||||||
return new ChargeData(charge.id, charge.name, charge.amount, charge.currency, charge.chargeTimeType, charge.chargeAppliesTo,
|
return new ChargeData(charge.id, charge.name, charge.amount, charge.currency, charge.chargeTimeType, charge.chargeAppliesTo,
|
||||||
charge.chargeCalculationType, charge.penalty, charge.active, template.currencyOptions,
|
charge.chargeCalculationType, charge.chargePaymentMode, charge.penalty, charge.active,
|
||||||
template.chargeCalculationTypeOptions, template.chargeAppliesToOptions, template.chargeTimeTypeOptions);
|
template.currencyOptions, template.chargeCalculationTypeOptions, template.chargeAppliesToOptions, template.chargeTimeTypeOptions,
|
||||||
|
template.chargePaymetModeOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ChargeData instance(final Long id, final String name, final BigDecimal amount, final CurrencyData currency,
|
public static ChargeData instance(final Long id, final String name, final BigDecimal amount, final CurrencyData currency,
|
||||||
final EnumOptionData chargeTimeType, final EnumOptionData chargeAppliesTo, final EnumOptionData chargeCalculationType,
|
final EnumOptionData chargeTimeType, final EnumOptionData chargeAppliesTo, final EnumOptionData chargeCalculationType,
|
||||||
final boolean penalty, final boolean active) {
|
final EnumOptionData chargePaymentMode, final boolean penalty, final boolean active) {
|
||||||
return new ChargeData(id, name, amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType, penalty, active, null,
|
return new ChargeData(id, name, amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType, chargePaymentMode, penalty, active,
|
||||||
null, null, null);
|
null, null, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ChargeData lookup(final Long id, final String name, final boolean isPenalty) {
|
public static ChargeData lookup(final Long id, final String name, final boolean isPenalty) {
|
||||||
@@ -60,21 +63,23 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
|||||||
EnumOptionData chargeTimeType = null;
|
EnumOptionData chargeTimeType = null;
|
||||||
EnumOptionData chargeAppliesTo = null;
|
EnumOptionData chargeAppliesTo = null;
|
||||||
EnumOptionData chargeCalculationType = null;
|
EnumOptionData chargeCalculationType = null;
|
||||||
|
EnumOptionData chargePaymentMode = null;
|
||||||
Boolean penalty = isPenalty;
|
Boolean penalty = isPenalty;
|
||||||
Boolean active = false;
|
Boolean active = false;
|
||||||
Collection<CurrencyData> currencyOptions = null;
|
Collection<CurrencyData> currencyOptions = null;
|
||||||
List<EnumOptionData> chargeCalculationTypeOptions = null;
|
List<EnumOptionData> chargeCalculationTypeOptions = null;
|
||||||
List<EnumOptionData> chargeAppliesToOptions = null;
|
List<EnumOptionData> chargeAppliesToOptions = null;
|
||||||
List<EnumOptionData> chargeTimeTypeOptions = null;
|
List<EnumOptionData> chargeTimeTypeOptions = null;
|
||||||
return new ChargeData(id, name, amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType, penalty, active,
|
List<EnumOptionData> chargePaymentModeOptions = null;
|
||||||
currencyOptions, chargeCalculationTypeOptions, chargeAppliesToOptions, chargeTimeTypeOptions);
|
return new ChargeData(id, name, amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType, chargePaymentMode, penalty,
|
||||||
|
active, currencyOptions, chargeCalculationTypeOptions, chargeAppliesToOptions, chargeTimeTypeOptions, chargePaymentModeOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChargeData(final Long id, final String name, final BigDecimal amount, final CurrencyData currency,
|
private ChargeData(final Long id, final String name, final BigDecimal amount, final CurrencyData currency,
|
||||||
final EnumOptionData chargeTimeType, final EnumOptionData chargeAppliesTo, final EnumOptionData chargeCalculationType,
|
final EnumOptionData chargeTimeType, final EnumOptionData chargeAppliesTo, final EnumOptionData chargeCalculationType,
|
||||||
final boolean penalty, final boolean active, final Collection<CurrencyData> currencyOptions,
|
EnumOptionData chargePaymentMode, final boolean penalty, final boolean active,
|
||||||
final List<EnumOptionData> chargeCalculationTypeOptions, final List<EnumOptionData> chargeAppliesToOptions,
|
final Collection<CurrencyData> currencyOptions, final List<EnumOptionData> chargeCalculationTypeOptions,
|
||||||
final List<EnumOptionData> chargeTimeTypeOptions) {
|
final List<EnumOptionData> chargeAppliesToOptions, final List<EnumOptionData> chargeTimeTypeOptions, List<EnumOptionData> chargePaymentModeOptions) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
@@ -82,12 +87,14 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
|||||||
this.chargeTimeType = chargeTimeType;
|
this.chargeTimeType = chargeTimeType;
|
||||||
this.chargeAppliesTo = chargeAppliesTo;
|
this.chargeAppliesTo = chargeAppliesTo;
|
||||||
this.chargeCalculationType = chargeCalculationType;
|
this.chargeCalculationType = chargeCalculationType;
|
||||||
|
this.chargePaymentMode = chargePaymentMode;
|
||||||
this.penalty = penalty;
|
this.penalty = penalty;
|
||||||
this.active = active;
|
this.active = active;
|
||||||
this.currencyOptions = currencyOptions;
|
this.currencyOptions = currencyOptions;
|
||||||
this.chargeCalculationTypeOptions = chargeCalculationTypeOptions;
|
this.chargeCalculationTypeOptions = chargeCalculationTypeOptions;
|
||||||
this.chargeAppliesToOptions = chargeAppliesToOptions;
|
this.chargeAppliesToOptions = chargeAppliesToOptions;
|
||||||
this.chargeTimeTypeOptions = chargeTimeTypeOptions;
|
this.chargeTimeTypeOptions = chargeTimeTypeOptions;
|
||||||
|
this.chargePaymetModeOptions = chargePaymentModeOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -116,6 +123,6 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return LoanChargeData.newLoanChargeDetails(this.id, this.name, this.currency, this.amount, percentage, this.chargeTimeType,
|
return LoanChargeData.newLoanChargeDetails(this.id, this.name, this.currency, this.amount, percentage, this.chargeTimeType,
|
||||||
this.chargeCalculationType, this.penalty);
|
this.chargeCalculationType, this.penalty,this.chargePaymentMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+24
-4
@@ -46,6 +46,9 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
@Column(name = "charge_calculation_enum")
|
@Column(name = "charge_calculation_enum")
|
||||||
private Integer chargeCalculation;
|
private Integer chargeCalculation;
|
||||||
|
|
||||||
|
@Column(name = "charge_payment_mode_enum")
|
||||||
|
private Integer chargePaymentMode;
|
||||||
|
|
||||||
@Column(name = "is_penalty", nullable = false)
|
@Column(name = "is_penalty", nullable = false)
|
||||||
private boolean penalty;
|
private boolean penalty;
|
||||||
@@ -66,11 +69,12 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
final ChargeTimeType chargeTimeType = ChargeTimeType.fromInt(command.integerValueOfParameterNamed("chargeTimeType"));
|
final ChargeTimeType chargeTimeType = ChargeTimeType.fromInt(command.integerValueOfParameterNamed("chargeTimeType"));
|
||||||
final ChargeCalculationType chargeCalculationType = ChargeCalculationType.fromInt(command
|
final ChargeCalculationType chargeCalculationType = ChargeCalculationType.fromInt(command
|
||||||
.integerValueOfParameterNamed("chargeCalculationType"));
|
.integerValueOfParameterNamed("chargeCalculationType"));
|
||||||
|
final ChargePaymentMode paymentMode = ChargePaymentMode.fromInt(command.integerValueOfParameterNamed("chargePaymentMode"));
|
||||||
|
|
||||||
final boolean penalty = command.booleanPrimitiveValueOfParameterNamed("penalty");
|
final boolean penalty = command.booleanPrimitiveValueOfParameterNamed("penalty");
|
||||||
final boolean active = command.booleanPrimitiveValueOfParameterNamed("active");
|
final boolean active = command.booleanPrimitiveValueOfParameterNamed("active");
|
||||||
|
|
||||||
return new Charge(name, amount, currencyCode, chargeAppliesTo, chargeTimeType, chargeCalculationType, penalty, active);
|
return new Charge(name, amount, currencyCode, chargeAppliesTo, chargeTimeType, chargeCalculationType, penalty, active, paymentMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Charge() {
|
protected Charge() {
|
||||||
@@ -78,7 +82,8 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Charge(final String name, final BigDecimal amount, final String currencyCode, final ChargeAppliesTo chargeAppliesTo,
|
private Charge(final String name, final BigDecimal amount, final String currencyCode, final ChargeAppliesTo chargeAppliesTo,
|
||||||
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculationType, final boolean penalty, final boolean active) {
|
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculationType, final boolean penalty, final boolean active,
|
||||||
|
final ChargePaymentMode paymentMode) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
this.currencyCode = currencyCode;
|
this.currencyCode = currencyCode;
|
||||||
@@ -87,6 +92,7 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
this.chargeCalculation = chargeCalculationType.getValue();
|
this.chargeCalculation = chargeCalculationType.getValue();
|
||||||
this.penalty = penalty;
|
this.penalty = penalty;
|
||||||
this.active = active;
|
this.active = active;
|
||||||
|
this.chargePaymentMode = paymentMode.getValue();
|
||||||
if (penalty && chargeTime.isTimeOfDisbursement()) { throw new ChargeDueAtDisbursementCannotBePenaltyException(name); }
|
if (penalty && chargeTime.isTimeOfDisbursement()) { throw new ChargeDueAtDisbursementCannotBePenaltyException(name); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,6 +197,15 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
actualChanges.put("locale", localeAsInput);
|
actualChanges.put("locale", localeAsInput);
|
||||||
this.chargeCalculation = ChargeCalculationType.fromInt(newValue).getValue();
|
this.chargeCalculation = ChargeCalculationType.fromInt(newValue).getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final String paymentModeParamName = "chargePaymentMode";
|
||||||
|
if (command.isChangeInIntegerParameterNamed(paymentModeParamName, this.chargePaymentMode)) {
|
||||||
|
final Integer newValue = command.integerValueOfParameterNamed(paymentModeParamName);
|
||||||
|
actualChanges.put(paymentModeParamName, newValue);
|
||||||
|
actualChanges.put("locale", localeAsInput);
|
||||||
|
this.chargePaymentMode = ChargePaymentMode.fromInt(newValue).getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
final String penaltyParamName = "penalty";
|
final String penaltyParamName = "penalty";
|
||||||
if (command.isChangeInBooleanParameterNamed(penaltyParamName, this.penalty)) {
|
if (command.isChangeInBooleanParameterNamed(penaltyParamName, this.penalty)) {
|
||||||
@@ -228,9 +243,14 @@ public class Charge extends AbstractPersistable<Long> {
|
|||||||
EnumOptionData chargeTimeType = ChargeEnumerations.chargeTimeType(this.chargeTime);
|
EnumOptionData chargeTimeType = ChargeEnumerations.chargeTimeType(this.chargeTime);
|
||||||
EnumOptionData chargeAppliesTo = ChargeEnumerations.chargeAppliesTo(this.chargeAppliesTo);
|
EnumOptionData chargeAppliesTo = ChargeEnumerations.chargeAppliesTo(this.chargeAppliesTo);
|
||||||
EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(this.chargeCalculation);
|
EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(this.chargeCalculation);
|
||||||
|
EnumOptionData chargePaymentmode = ChargeEnumerations.chargePaymentMode(this.chargePaymentMode);
|
||||||
CurrencyData currency = new CurrencyData(this.currencyCode, null, 0, 0, null, null);
|
CurrencyData currency = new CurrencyData(this.currencyCode, null, 0, 0, null, null);
|
||||||
return ChargeData.instance(this.getId(), this.name, this.amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType,
|
return ChargeData.instance(this.getId(), this.name, this.amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType,
|
||||||
penalty, active);
|
chargePaymentmode, penalty, active);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Integer getChargePaymentMode() {
|
||||||
|
return this.chargePaymentMode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Executable
+40
@@ -0,0 +1,40 @@
|
|||||||
|
package org.mifosplatform.portfolio.charge.domain;
|
||||||
|
|
||||||
|
public enum ChargePaymentMode {
|
||||||
|
|
||||||
|
REGULAR(0, "chargepaymentmode.regular"), //
|
||||||
|
ACCOUNT_TRANSFER(1, "chargepaymentmode.accounttransfer");
|
||||||
|
|
||||||
|
private final Integer value;
|
||||||
|
private final String code;
|
||||||
|
|
||||||
|
private ChargePaymentMode(Integer value, String code) {
|
||||||
|
this.value = value;
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ChargePaymentMode fromInt(final Integer paymentMode) {
|
||||||
|
ChargePaymentMode chargeAppliesToType = ChargePaymentMode.REGULAR;
|
||||||
|
switch (paymentMode) {
|
||||||
|
case 1:
|
||||||
|
chargeAppliesToType = ACCOUNT_TRANSFER;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
chargeAppliesToType = REGULAR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return chargeAppliesToType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPaymentModeAccountTransfer(){
|
||||||
|
return this.value.equals(ChargePaymentMode.ACCOUNT_TRANSFER.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* 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.charge.exception;
|
||||||
|
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||||
|
|
||||||
|
public class LoanChargeCannotBePayedException extends AbstractPlatformDomainRuleException {
|
||||||
|
|
||||||
|
/*** enum of reasons of why Loan Charge cannot be waived **/
|
||||||
|
public static enum LOAN_CHARGE_CANNOT_BE_PAYED_REASON {
|
||||||
|
ALREADY_PAID, ALREADY_WAIVED, LOAN_INACTIVE, CHARGE_NOT_ACCOUNT_TRANSFER;
|
||||||
|
|
||||||
|
public String errorMessage() {
|
||||||
|
if (name().toString().equalsIgnoreCase("ALREADY_PAID")) {
|
||||||
|
return "This loan charge has been completely paid";
|
||||||
|
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
|
||||||
|
return "This loan charge has already been waived";
|
||||||
|
} else if (name().toString().equalsIgnoreCase("LOAN_INACTIVE")) {
|
||||||
|
return "This loan charge can be payed as the loan associated with it is currently inactive";
|
||||||
|
}else if(name().toString().equalsIgnoreCase("CHARGE_NOT_ACCOUNT_TRANSFER")) {
|
||||||
|
return "This loan charge can be payed as the charge payment mode is not account transfer";
|
||||||
|
}
|
||||||
|
|
||||||
|
return name().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String errorCode() {
|
||||||
|
if (name().toString().equalsIgnoreCase("ALREADY_PAID")) {
|
||||||
|
return "error.msg.loan.charge.already.paid";
|
||||||
|
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
|
||||||
|
return "error.msg.loan.charge.already.waived";
|
||||||
|
} else if (name().toString().equalsIgnoreCase("LOAN_INACTIVE")) {
|
||||||
|
return "error.msg.loan.charge.associated.loan.inactive";
|
||||||
|
}else if(name().toString().equalsIgnoreCase("CHARGE_NOT_ACCOUNT_TRANSFER")) {
|
||||||
|
return "error.msg.loan.charge.payment.mode.not.account.transfer";
|
||||||
|
}
|
||||||
|
return name().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanChargeCannotBePayedException(final LOAN_CHARGE_CANNOT_BE_PAYED_REASON reason, final Long loanChargeId) {
|
||||||
|
super(reason.errorCode(), reason.errorMessage(), loanChargeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
-1
@@ -35,7 +35,7 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer {
|
|||||||
*/
|
*/
|
||||||
private final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("name", "amount", "locale", "currencyCode",
|
private final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("name", "amount", "locale", "currencyCode",
|
||||||
"currencyOptions", "chargeAppliesTo", "chargeTimeType", "chargeCalculationType", "chargeCalculationTypeOptions", "penalty",
|
"currencyOptions", "chargeAppliesTo", "chargeTimeType", "chargeCalculationType", "chargeCalculationTypeOptions", "penalty",
|
||||||
"active"));
|
"active","chargePaymentMode"));
|
||||||
|
|
||||||
private final FromJsonHelper fromApiJsonHelper;
|
private final FromJsonHelper fromApiJsonHelper;
|
||||||
|
|
||||||
@@ -73,6 +73,9 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer {
|
|||||||
final Integer chargeCalculationType = fromApiJsonHelper.extractIntegerNamed("chargeCalculationType", element, Locale.getDefault());
|
final Integer chargeCalculationType = fromApiJsonHelper.extractIntegerNamed("chargeCalculationType", element, Locale.getDefault());
|
||||||
baseDataValidator.reset().parameter("chargeCalculationType").value(chargeCalculationType).notNull().inMinMaxRange(1, 4);
|
baseDataValidator.reset().parameter("chargeCalculationType").value(chargeCalculationType).notNull().inMinMaxRange(1, 4);
|
||||||
|
|
||||||
|
final Integer chargePaymentMode = fromApiJsonHelper.extractIntegerNamed("chargePaymentMode", element, Locale.getDefault());
|
||||||
|
baseDataValidator.reset().parameter("chargePaymentMode").value(chargePaymentMode).notNull().inMinMaxRange(0, 1);
|
||||||
|
|
||||||
if (fromApiJsonHelper.parameterExists("penalty", element)) {
|
if (fromApiJsonHelper.parameterExists("penalty", element)) {
|
||||||
final Boolean penalty = fromApiJsonHelper.extractBooleanNamed("penalty", element);
|
final Boolean penalty = fromApiJsonHelper.extractBooleanNamed("penalty", element);
|
||||||
baseDataValidator.reset().parameter("penalty").value(penalty).notNull();
|
baseDataValidator.reset().parameter("penalty").value(penalty).notNull();
|
||||||
@@ -126,6 +129,11 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer {
|
|||||||
Locale.getDefault());
|
Locale.getDefault());
|
||||||
baseDataValidator.reset().parameter("chargeCalculationType").value(chargeCalculationType).notNull().inMinMaxRange(1, 4);
|
baseDataValidator.reset().parameter("chargeCalculationType").value(chargeCalculationType).notNull().inMinMaxRange(1, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fromApiJsonHelper.parameterExists("chargePaymentMode", element)) {
|
||||||
|
final Integer chargePaymentMode = fromApiJsonHelper.extractIntegerNamed("chargePaymentMode", element, Locale.getDefault());
|
||||||
|
baseDataValidator.reset().parameter("chargePaymentMode").value(chargePaymentMode).notNull().inMinMaxRange(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (fromApiJsonHelper.parameterExists("penalty", element)) {
|
if (fromApiJsonHelper.parameterExists("penalty", element)) {
|
||||||
final Boolean penalty = fromApiJsonHelper.extractBooleanNamed("penalty", element);
|
final Boolean penalty = fromApiJsonHelper.extractBooleanNamed("penalty", element);
|
||||||
|
|||||||
+2
@@ -16,4 +16,6 @@ public interface ChargeDropdownReadPlatformService {
|
|||||||
List<EnumOptionData> retrieveApplicableToTypes();
|
List<EnumOptionData> retrieveApplicableToTypes();
|
||||||
|
|
||||||
List<EnumOptionData> retrieveCollectionTimeTypes();
|
List<EnumOptionData> retrieveCollectionTimeTypes();
|
||||||
|
|
||||||
|
List<EnumOptionData> retrivePaymentModes();
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.charge.service;
|
|||||||
import static org.mifosplatform.portfolio.charge.service.ChargeEnumerations.chargeAppliesTo;
|
import static org.mifosplatform.portfolio.charge.service.ChargeEnumerations.chargeAppliesTo;
|
||||||
import static org.mifosplatform.portfolio.charge.service.ChargeEnumerations.chargeCalculationType;
|
import static org.mifosplatform.portfolio.charge.service.ChargeEnumerations.chargeCalculationType;
|
||||||
import static org.mifosplatform.portfolio.charge.service.ChargeEnumerations.chargeTimeType;
|
import static org.mifosplatform.portfolio.charge.service.ChargeEnumerations.chargeTimeType;
|
||||||
|
import static org.mifosplatform.portfolio.charge.service.ChargeEnumerations.chargePaymentMode;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -15,6 +16,7 @@ import java.util.List;
|
|||||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||||
import org.mifosplatform.portfolio.charge.domain.ChargeAppliesTo;
|
import org.mifosplatform.portfolio.charge.domain.ChargeAppliesTo;
|
||||||
import org.mifosplatform.portfolio.charge.domain.ChargeCalculationType;
|
import org.mifosplatform.portfolio.charge.domain.ChargeCalculationType;
|
||||||
|
import org.mifosplatform.portfolio.charge.domain.ChargePaymentMode;
|
||||||
import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
|
import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@@ -40,4 +42,9 @@ public class ChargeDropdownReadPlatformServiceImpl implements ChargeDropdownRead
|
|||||||
public List<EnumOptionData> retrieveCollectionTimeTypes() {
|
public List<EnumOptionData> retrieveCollectionTimeTypes() {
|
||||||
return Arrays.asList(chargeTimeType(ChargeTimeType.DISBURSEMENT), chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE));
|
return Arrays.asList(chargeTimeType(ChargeTimeType.DISBURSEMENT), chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<EnumOptionData> retrivePaymentModes() {
|
||||||
|
return Arrays.asList(chargePaymentMode(ChargePaymentMode.REGULAR), chargePaymentMode(ChargePaymentMode.ACCOUNT_TRANSFER));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+22
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.charge.service;
|
|||||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||||
import org.mifosplatform.portfolio.charge.domain.ChargeAppliesTo;
|
import org.mifosplatform.portfolio.charge.domain.ChargeAppliesTo;
|
||||||
import org.mifosplatform.portfolio.charge.domain.ChargeCalculationType;
|
import org.mifosplatform.portfolio.charge.domain.ChargeCalculationType;
|
||||||
|
import org.mifosplatform.portfolio.charge.domain.ChargePaymentMode;
|
||||||
import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
|
import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
|
||||||
|
|
||||||
public class ChargeEnumerations {
|
public class ChargeEnumerations {
|
||||||
@@ -82,4 +83,25 @@ public class ChargeEnumerations {
|
|||||||
}
|
}
|
||||||
return optionData;
|
return optionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static EnumOptionData chargePaymentMode(final int id) {
|
||||||
|
return chargePaymentMode(ChargePaymentMode.fromInt(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static EnumOptionData chargePaymentMode(final ChargePaymentMode type) {
|
||||||
|
EnumOptionData optionData = null;
|
||||||
|
switch (type) {
|
||||||
|
case ACCOUNT_TRANSFER:
|
||||||
|
optionData = new EnumOptionData(ChargePaymentMode.ACCOUNT_TRANSFER.getValue().longValue(),
|
||||||
|
ChargePaymentMode.ACCOUNT_TRANSFER.getCode(), ChargePaymentMode.ACCOUNT_TRANSFER.getCode());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
optionData = new EnumOptionData(ChargePaymentMode.REGULAR.getValue().longValue(), ChargePaymentMode.REGULAR.getCode(),
|
||||||
|
ChargePaymentMode.REGULAR.getCode());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return optionData;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-3
@@ -81,9 +81,10 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
|
|||||||
final List<EnumOptionData> allowedChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService.retrieveCalculationTypes();
|
final List<EnumOptionData> allowedChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService.retrieveCalculationTypes();
|
||||||
final List<EnumOptionData> allowedChargeAppliesToOptions = this.chargeDropdownReadPlatformService.retrieveApplicableToTypes();
|
final List<EnumOptionData> allowedChargeAppliesToOptions = this.chargeDropdownReadPlatformService.retrieveApplicableToTypes();
|
||||||
final List<EnumOptionData> allowedChargeTimeOptions = this.chargeDropdownReadPlatformService.retrieveCollectionTimeTypes();
|
final List<EnumOptionData> allowedChargeTimeOptions = this.chargeDropdownReadPlatformService.retrieveCollectionTimeTypes();
|
||||||
|
final List<EnumOptionData> chargePaymentOptions = this.chargeDropdownReadPlatformService.retrivePaymentModes();
|
||||||
|
|
||||||
return ChargeData.template(currencyOptions, allowedChargeCalculationTypeOptions, allowedChargeAppliesToOptions,
|
return ChargeData.template(currencyOptions, allowedChargeCalculationTypeOptions, allowedChargeAppliesToOptions,
|
||||||
allowedChargeTimeOptions);
|
allowedChargeTimeOptions, chargePaymentOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -130,6 +131,7 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
|
|||||||
public String chargeSchema() {
|
public String chargeSchema() {
|
||||||
return "c.id as id, c.name as name, c.amount as amount, c.currency_code as currencyCode, "
|
return "c.id as id, c.name as name, c.amount as amount, c.currency_code as currencyCode, "
|
||||||
+ "c.charge_applies_to_enum as chargeAppliesTo, c.charge_time_enum as chargeTime, "
|
+ "c.charge_applies_to_enum as chargeAppliesTo, c.charge_time_enum as chargeTime, "
|
||||||
|
+"c.charge_payment_mode_enum as chargePaymentMode, "
|
||||||
+ "c.charge_calculation_enum as chargeCalculation, c.is_penalty as penalty, c.is_active as active, oc.name as currencyName, "
|
+ "c.charge_calculation_enum as chargeCalculation, c.is_penalty as penalty, c.is_active as active, oc.name as currencyName, "
|
||||||
+ "oc.decimal_places as currencyDecimalPlaces,oc.currency_multiplesof as inMultiplesOf, oc.display_symbol as currencyDisplaySymbol, "
|
+ "oc.decimal_places as currencyDecimalPlaces,oc.currency_multiplesof as inMultiplesOf, oc.display_symbol as currencyDisplaySymbol, "
|
||||||
+ "oc.internationalized_name_code as currencyNameCode from m_charge c "
|
+ "oc.internationalized_name_code as currencyNameCode from m_charge c "
|
||||||
@@ -164,11 +166,16 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
|
|||||||
|
|
||||||
final int chargeCalculation = rs.getInt("chargeCalculation");
|
final int chargeCalculation = rs.getInt("chargeCalculation");
|
||||||
final EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(chargeCalculation);
|
final EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(chargeCalculation);
|
||||||
|
|
||||||
|
final int paymentMode = rs.getInt("chargePaymentMode");
|
||||||
|
final EnumOptionData chargePaymentMode = ChargeEnumerations.chargePaymentMode(paymentMode);
|
||||||
|
|
||||||
|
|
||||||
final boolean penalty = rs.getBoolean("penalty");
|
final boolean penalty = rs.getBoolean("penalty");
|
||||||
final boolean active = rs.getBoolean("active");
|
final boolean active = rs.getBoolean("active");
|
||||||
|
|
||||||
return ChargeData.instance(id, name, amount, currency, chargeTimeType, chargeAppliesToType, chargeCalculationType, penalty,
|
return ChargeData.instance(id, name, amount, currency, chargeTimeType, chargeAppliesToType, chargeCalculationType, chargePaymentMode,
|
||||||
active);
|
penalty, active);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+23
-14
@@ -124,11 +124,19 @@ public class LoanChargesApiResource {
|
|||||||
@POST
|
@POST
|
||||||
@Consumes({ MediaType.APPLICATION_JSON })
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
@Produces({ MediaType.APPLICATION_JSON })
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
public String addLoanCharge(@PathParam("loanId") final Long loanId, final String apiRequestBodyAsJson) {
|
public String executeLoanCharge(@PathParam("loanId") final Long loanId, @QueryParam("command") final String commandParam,
|
||||||
|
final String apiRequestBodyAsJson) {
|
||||||
|
|
||||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().createLoanCharge(loanId).withJson(apiRequestBodyAsJson).build();
|
CommandProcessingResult result = null;
|
||||||
|
if (is(commandParam, "pay")) {
|
||||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
final CommandWrapper commandRequest = new CommandWrapperBuilder().payLoanCharge(loanId, null).withJson(apiRequestBodyAsJson)
|
||||||
|
.build();
|
||||||
|
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||||
|
} else {
|
||||||
|
final CommandWrapper commandRequest = new CommandWrapperBuilder().createLoanCharge(loanId).withJson(apiRequestBodyAsJson)
|
||||||
|
.build();
|
||||||
|
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||||
|
}
|
||||||
|
|
||||||
return this.toApiJsonSerializer.serialize(result);
|
return this.toApiJsonSerializer.serialize(result);
|
||||||
}
|
}
|
||||||
@@ -152,21 +160,22 @@ public class LoanChargesApiResource {
|
|||||||
@Path("{chargeId}")
|
@Path("{chargeId}")
|
||||||
@Consumes({ MediaType.APPLICATION_JSON })
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
@Produces({ MediaType.APPLICATION_JSON })
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
public String waiveLoanCharge(@PathParam("loanId") final Long loanId, @PathParam("chargeId") final Long loanChargeId,
|
public String executeLoanCharge(@PathParam("loanId") final Long loanId, @PathParam("chargeId") final Long loanChargeId,
|
||||||
@QueryParam("command") final String commandParam) {
|
@QueryParam("command") final String commandParam, final String apiRequestBodyAsJson) {
|
||||||
|
|
||||||
String json = "";
|
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson);
|
||||||
|
CommandProcessingResult result = null;
|
||||||
if (is(commandParam, "waive")) {
|
if (is(commandParam, "waive")) {
|
||||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().waiveLoanCharge(loanId, loanChargeId).build();
|
final CommandWrapper commandRequest = builder.waiveLoanCharge(loanId, loanChargeId).build();
|
||||||
|
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
} else if (is(commandParam, "pay")) {
|
||||||
|
final CommandWrapper commandRequest = builder.payLoanCharge(loanId, loanChargeId).build();
|
||||||
json = this.toApiJsonSerializer.serialize(result);
|
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||||
} else {
|
} else {
|
||||||
throw new UnrecognizedQueryParamException("command", commandParam);
|
throw new UnrecognizedQueryParamException("command", commandParam);
|
||||||
}
|
}
|
||||||
|
if (result == null) { throw new UnrecognizedQueryParamException("command", commandParam); }
|
||||||
return json;
|
return this.toApiJsonSerializer.serialize(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DELETE
|
@DELETE
|
||||||
|
|||||||
+63
-14
@@ -41,7 +41,12 @@ import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSeria
|
|||||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||||
import org.mifosplatform.infrastructure.core.service.Page;
|
import org.mifosplatform.infrastructure.core.service.Page;
|
||||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||||
|
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||||
import org.mifosplatform.organisation.staff.data.StaffData;
|
import org.mifosplatform.organisation.staff.data.StaffData;
|
||||||
|
import org.mifosplatform.portfolio.account.PortfolioAccountType;
|
||||||
|
import org.mifosplatform.portfolio.account.data.PortfolioAccountData;
|
||||||
|
import org.mifosplatform.portfolio.account.service.AccountAssociationsReadPlatformService;
|
||||||
|
import org.mifosplatform.portfolio.account.service.PortfolioAccountReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
||||||
import org.mifosplatform.portfolio.calendar.service.CalendarReadPlatformService;
|
import org.mifosplatform.portfolio.calendar.service.CalendarReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
||||||
@@ -73,6 +78,7 @@ import org.mifosplatform.portfolio.loanproduct.service.LoanProductReadPlatformSe
|
|||||||
import org.mifosplatform.portfolio.note.data.NoteData;
|
import org.mifosplatform.portfolio.note.data.NoteData;
|
||||||
import org.mifosplatform.portfolio.note.domain.NoteType;
|
import org.mifosplatform.portfolio.note.domain.NoteType;
|
||||||
import org.mifosplatform.portfolio.note.service.NoteReadPlatformServiceImpl;
|
import org.mifosplatform.portfolio.note.service.NoteReadPlatformServiceImpl;
|
||||||
|
import org.mifosplatform.portfolio.savings.domain.SavingsAccountStatusType;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -89,14 +95,15 @@ public class LoansApiResource {
|
|||||||
"clientId", "group", "loanProductId", "loanProductName", "loanProductDescription", "fundId", "fundName", "loanPurposeId",
|
"clientId", "group", "loanProductId", "loanProductName", "loanProductDescription", "fundId", "fundName", "loanPurposeId",
|
||||||
"loanPurposeName", "loanOfficerId", "loanOfficerName", "currency", "principal", "totalOverpaid", "inArrearsTolerance",
|
"loanPurposeName", "loanOfficerId", "loanOfficerName", "currency", "principal", "totalOverpaid", "inArrearsTolerance",
|
||||||
"termFrequency", "termPeriodFrequencyType", "numberOfRepayments", "repaymentEvery", "interestRatePerPeriod",
|
"termFrequency", "termPeriodFrequencyType", "numberOfRepayments", "repaymentEvery", "interestRatePerPeriod",
|
||||||
"annualInterestRate", "repaymentFrequencyType", "transactionProcessingStrategyId", "transactionProcessingStrategyName", "interestRateFrequencyType",
|
"annualInterestRate", "repaymentFrequencyType", "transactionProcessingStrategyId", "transactionProcessingStrategyName",
|
||||||
"amortizationType", "interestType", "interestCalculationPeriodType", "expectedFirstRepaymentOnDate", "graceOnPrincipalPayment",
|
"interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType",
|
||||||
"graceOnInterestPayment", "graceOnInterestCharged", "interestChargedFromDate", "timeline", "totalFeeChargesAtDisbursement",
|
"expectedFirstRepaymentOnDate", "graceOnPrincipalPayment", "graceOnInterestPayment", "graceOnInterestCharged",
|
||||||
"summary", "repaymentSchedule", "transactions", "charges", "collateral", "guarantors", "meeting", "productOptions",
|
"interestChargedFromDate", "timeline", "totalFeeChargesAtDisbursement", "summary", "repaymentSchedule", "transactions",
|
||||||
"amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", "repaymentFrequencyTypeOptions",
|
"charges", "collateral", "guarantors", "meeting", "productOptions", "amortizationTypeOptions", "interestTypeOptions",
|
||||||
"termFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "repaymentStrategyOptions", "chargeOptions",
|
"interestCalculationPeriodTypeOptions", "repaymentFrequencyTypeOptions", "termFrequencyTypeOptions",
|
||||||
"loanOfficerOptions", "loanPurposeOptions", "loanCollateralOptions", "chargeTemplate", "calendarOptions", "syncDisbursementWithMeeting",
|
"interestRateFrequencyTypeOptions", "fundOptions", "repaymentStrategyOptions", "chargeOptions", "loanOfficerOptions",
|
||||||
"loanCounter", "loanProductCounter", "notes"));
|
"loanPurposeOptions", "loanCollateralOptions", "chargeTemplate", "calendarOptions", "syncDisbursementWithMeeting",
|
||||||
|
"loanCounter", "loanProductCounter", "notes","accountLinkingOptions","linkedAccount"));
|
||||||
|
|
||||||
private final String resourceNameForPermissions = "LOAN";
|
private final String resourceNameForPermissions = "LOAN";
|
||||||
|
|
||||||
@@ -119,6 +126,8 @@ public class LoansApiResource {
|
|||||||
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||||
private final CalendarReadPlatformService calendarReadPlatformService;
|
private final CalendarReadPlatformService calendarReadPlatformService;
|
||||||
private final NoteReadPlatformServiceImpl noteReadPlatformService;
|
private final NoteReadPlatformServiceImpl noteReadPlatformService;
|
||||||
|
private final PortfolioAccountReadPlatformService portfolioAccountReadPlatformService;
|
||||||
|
private final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoansApiResource(final PlatformSecurityContext context, final LoanReadPlatformService loanReadPlatformService,
|
public LoansApiResource(final PlatformSecurityContext context, final LoanReadPlatformService loanReadPlatformService,
|
||||||
@@ -133,7 +142,9 @@ public class LoansApiResource {
|
|||||||
final DefaultToApiJsonSerializer<LoanScheduleData> loanScheduleToApiJsonSerializer,
|
final DefaultToApiJsonSerializer<LoanScheduleData> loanScheduleToApiJsonSerializer,
|
||||||
final ApiRequestParameterHelper apiRequestParameterHelper, final FromJsonHelper fromJsonHelper,
|
final ApiRequestParameterHelper apiRequestParameterHelper, final FromJsonHelper fromJsonHelper,
|
||||||
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
|
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
|
||||||
final CalendarReadPlatformService calendarReadPlatformService, final NoteReadPlatformServiceImpl noteReadPlatformService) {
|
final CalendarReadPlatformService calendarReadPlatformService, final NoteReadPlatformServiceImpl noteReadPlatformService,
|
||||||
|
final PortfolioAccountReadPlatformService portfolioAccountReadPlatformServiceImpl,
|
||||||
|
final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.loanReadPlatformService = loanReadPlatformService;
|
this.loanReadPlatformService = loanReadPlatformService;
|
||||||
this.loanProductReadPlatformService = loanProductReadPlatformService;
|
this.loanProductReadPlatformService = loanProductReadPlatformService;
|
||||||
@@ -153,6 +164,8 @@ public class LoansApiResource {
|
|||||||
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
|
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
|
||||||
this.calendarReadPlatformService = calendarReadPlatformService;
|
this.calendarReadPlatformService = calendarReadPlatformService;
|
||||||
this.noteReadPlatformService = noteReadPlatformService;
|
this.noteReadPlatformService = noteReadPlatformService;
|
||||||
|
this.portfolioAccountReadPlatformService = portfolioAccountReadPlatformServiceImpl;
|
||||||
|
this.accountAssociationsReadPlatformService = accountAssociationsReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@@ -225,10 +238,23 @@ public class LoansApiResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
allowedLoanOfficers = this.loanReadPlatformService.retrieveAllowedLoanOfficers(officeId, staffInSelectedOfficeOnly);
|
allowedLoanOfficers = this.loanReadPlatformService.retrieveAllowedLoanOfficers(officeId, staffInSelectedOfficeOnly);
|
||||||
|
|
||||||
|
Collection<PortfolioAccountData> accountLinkingOptions = null;
|
||||||
|
if(clientId != null){
|
||||||
|
CurrencyData currencyData = newLoanAccount.currency();
|
||||||
|
String currencyCode = null;
|
||||||
|
if (currencyData != null) {
|
||||||
|
currencyCode = currencyData.code();
|
||||||
|
}
|
||||||
|
long[] accountStatus = { SavingsAccountStatusType.ACTIVE.getValue() };
|
||||||
|
accountLinkingOptions = this.portfolioAccountReadPlatformService.retrieveAllForLookup(
|
||||||
|
PortfolioAccountType.SAVINGS.getValue(), clientId, currencyCode, accountStatus);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// add product options, allowed loan officers and calendar options
|
// add product options, allowed loan officers and calendar options
|
||||||
// (calendar options will be null in individual loan)
|
// (calendar options will be null in individual loan)
|
||||||
newLoanAccount = LoanAccountData.associationsAndTemplate(newLoanAccount, productOptions, allowedLoanOfficers, calendarOptions);
|
newLoanAccount = LoanAccountData.associationsAndTemplate(newLoanAccount, productOptions, allowedLoanOfficers, calendarOptions,accountLinkingOptions);
|
||||||
}
|
}
|
||||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||||
return this.toApiJsonSerializer.serialize(settings, newLoanAccount, LOAN_DATA_PARAMETERS);
|
return this.toApiJsonSerializer.serialize(settings, newLoanAccount, LOAN_DATA_PARAMETERS);
|
||||||
@@ -253,13 +279,15 @@ public class LoansApiResource {
|
|||||||
Collection<CollateralData> collateral = null;
|
Collection<CollateralData> collateral = null;
|
||||||
CalendarData meeting = null;
|
CalendarData meeting = null;
|
||||||
Collection<NoteData> notes = null;
|
Collection<NoteData> notes = null;
|
||||||
|
PortfolioAccountData linkedAccount = null;
|
||||||
|
|
||||||
final Set<String> mandatoryResponseParameters = new HashSet<String>();
|
final Set<String> mandatoryResponseParameters = new HashSet<String>();
|
||||||
final Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
|
final Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
|
||||||
if (!associationParameters.isEmpty()) {
|
if (!associationParameters.isEmpty()) {
|
||||||
|
|
||||||
if (associationParameters.contains("all")) {
|
if (associationParameters.contains("all")) {
|
||||||
associationParameters.addAll(Arrays.asList("repaymentSchedule", "transactions", "charges", "guarantors", "collateral","notes"));
|
associationParameters.addAll(Arrays.asList("repaymentSchedule", "transactions", "charges", "guarantors", "collateral",
|
||||||
|
"notes", "linkedAccount"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (associationParameters.contains("guarantors")) {
|
if (associationParameters.contains("guarantors")) {
|
||||||
@@ -305,7 +333,7 @@ public class LoansApiResource {
|
|||||||
mandatoryResponseParameters.add("meeting");
|
mandatoryResponseParameters.add("meeting");
|
||||||
meeting = this.calendarReadPlatformService.retrieveLoanCalendar(loanId);
|
meeting = this.calendarReadPlatformService.retrieveLoanCalendar(loanId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (associationParameters.contains("notes")) {
|
if (associationParameters.contains("notes")) {
|
||||||
mandatoryResponseParameters.add("notes");
|
mandatoryResponseParameters.add("notes");
|
||||||
notes = this.noteReadPlatformService.retrieveNotesByResource(loanId, NoteType.LOAN.getValue());
|
notes = this.noteReadPlatformService.retrieveNotesByResource(loanId, NoteType.LOAN.getValue());
|
||||||
@@ -313,6 +341,11 @@ public class LoansApiResource {
|
|||||||
notes = null;
|
notes = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (associationParameters.contains("linkedAccount")) {
|
||||||
|
mandatoryResponseParameters.add("linkedAccount");
|
||||||
|
linkedAccount = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loanId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<LoanProductData> productOptions = null;
|
Collection<LoanProductData> productOptions = null;
|
||||||
@@ -330,6 +363,9 @@ public class LoansApiResource {
|
|||||||
Collection<CodeValueData> loanPurposeOptions = null;
|
Collection<CodeValueData> loanPurposeOptions = null;
|
||||||
Collection<CodeValueData> loanCollateralOptions = null;
|
Collection<CodeValueData> loanCollateralOptions = null;
|
||||||
Collection<CalendarData> calendarOptions = null;
|
Collection<CalendarData> calendarOptions = null;
|
||||||
|
Collection<PortfolioAccountData> accountLinkingOptions = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
final boolean template = ApiParameterHelper.template(uriInfo.getQueryParameters());
|
final boolean template = ApiParameterHelper.template(uriInfo.getQueryParameters());
|
||||||
if (template) {
|
if (template) {
|
||||||
@@ -348,11 +384,24 @@ public class LoansApiResource {
|
|||||||
chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly);
|
chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly);
|
||||||
chargeTemplate = this.loanChargeReadPlatformService.retrieveLoanChargeTemplate();
|
chargeTemplate = this.loanChargeReadPlatformService.retrieveLoanChargeTemplate();
|
||||||
|
|
||||||
allowedLoanOfficers = this.loanReadPlatformService.retrieveAllowedLoanOfficers(loanBasicDetails.officeId(), staffInSelectedOfficeOnly);
|
allowedLoanOfficers = this.loanReadPlatformService.retrieveAllowedLoanOfficers(loanBasicDetails.officeId(),
|
||||||
|
staffInSelectedOfficeOnly);
|
||||||
|
|
||||||
loanPurposeOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode("LoanPurpose");
|
loanPurposeOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode("LoanPurpose");
|
||||||
loanCollateralOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode("LoanCollateral");
|
loanCollateralOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode("LoanCollateral");
|
||||||
|
CurrencyData currencyData = loanBasicDetails.currency();
|
||||||
|
String currencyCode = null;
|
||||||
|
if (currencyData != null) {
|
||||||
|
currencyCode = currencyData.code();
|
||||||
|
}
|
||||||
|
long[] accountStatus = { SavingsAccountStatusType.ACTIVE.getValue() };
|
||||||
|
accountLinkingOptions = this.portfolioAccountReadPlatformService.retrieveAllForLookup(
|
||||||
|
PortfolioAccountType.SAVINGS.getValue(), loanBasicDetails.clientId(), currencyCode, accountStatus);
|
||||||
|
|
||||||
|
if (!associationParameters.contains("linkedAccount")) {
|
||||||
|
mandatoryResponseParameters.add("linkedAccount");
|
||||||
|
linkedAccount = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loanId);
|
||||||
|
}
|
||||||
if (loanBasicDetails.groupId() != null) {
|
if (loanBasicDetails.groupId() != null) {
|
||||||
calendarOptions = this.loanReadPlatformService.retrieveCalendars(loanBasicDetails.groupId());
|
calendarOptions = this.loanReadPlatformService.retrieveCalendars(loanBasicDetails.groupId());
|
||||||
}
|
}
|
||||||
@@ -363,7 +412,7 @@ public class LoansApiResource {
|
|||||||
charges, collateral, guarantors, meeting, productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions,
|
charges, collateral, guarantors, meeting, productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions,
|
||||||
repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
|
repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
|
||||||
interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers, loanPurposeOptions,
|
interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers, loanPurposeOptions,
|
||||||
loanCollateralOptions, calendarOptions, notes);
|
loanCollateralOptions, calendarOptions, notes, accountLinkingOptions, linkedAccount);
|
||||||
|
|
||||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters(),
|
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters(),
|
||||||
mandatoryResponseParameters);
|
mandatoryResponseParameters);
|
||||||
|
|||||||
+45
-16
@@ -21,6 +21,7 @@ import org.mifosplatform.infrastructure.codes.data.CodeValueData;
|
|||||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||||
import org.mifosplatform.organisation.staff.data.StaffData;
|
import org.mifosplatform.organisation.staff.data.StaffData;
|
||||||
|
import org.mifosplatform.portfolio.account.data.PortfolioAccountData;
|
||||||
import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
||||||
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
||||||
import org.mifosplatform.portfolio.collateral.data.CollateralData;
|
import org.mifosplatform.portfolio.collateral.data.CollateralData;
|
||||||
@@ -129,6 +130,10 @@ public class LoanAccountData {
|
|||||||
//loanCycle
|
//loanCycle
|
||||||
private final Integer loanCounter;
|
private final Integer loanCounter;
|
||||||
private final Integer loanProductCounter;
|
private final Integer loanProductCounter;
|
||||||
|
|
||||||
|
//linkable account details
|
||||||
|
private final PortfolioAccountData linkedAccount;
|
||||||
|
private final Collection<PortfolioAccountData> accountLinkingOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to produce a {@link LoanAccountData} with only collateral options
|
* Used to produce a {@link LoanAccountData} with only collateral options
|
||||||
@@ -203,7 +208,8 @@ public class LoanAccountData {
|
|||||||
final Boolean syncDisbursementWithMeeting = null;
|
final Boolean syncDisbursementWithMeeting = null;
|
||||||
final Integer loancounter = null;
|
final Integer loancounter = null;
|
||||||
final Integer loanProductCounter = null;
|
final Integer loanProductCounter = null;
|
||||||
|
final Collection<PortfolioAccountData> accountLinkingOptions = null;
|
||||||
|
final PortfolioAccountData linkedAccount = null;
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
||||||
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
||||||
currencyData, principal, totalOverpaid, inArrearsTolerance, termFrequency, termPeriodFrequencyType, numberOfRepayments,
|
currencyData, principal, totalOverpaid, inArrearsTolerance, termFrequency, termPeriodFrequencyType, numberOfRepayments,
|
||||||
@@ -214,7 +220,7 @@ public class LoanAccountData {
|
|||||||
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, transactionProcessingStrategyOptions,
|
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, transactionProcessingStrategyOptions,
|
||||||
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
||||||
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
||||||
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes);
|
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes,accountLinkingOptions, linkedAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -290,6 +296,8 @@ public class LoanAccountData {
|
|||||||
final Boolean syncDisbursementWithMeeting = null;
|
final Boolean syncDisbursementWithMeeting = null;
|
||||||
final Integer loancounter = null;
|
final Integer loancounter = null;
|
||||||
final Integer loanProductCounter = null;
|
final Integer loanProductCounter = null;
|
||||||
|
final Collection<PortfolioAccountData> accountLinkingOptions = null;
|
||||||
|
final PortfolioAccountData linkedAccount = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
||||||
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
||||||
@@ -301,7 +309,7 @@ public class LoanAccountData {
|
|||||||
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions,
|
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions,
|
||||||
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
||||||
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
||||||
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes);
|
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes,accountLinkingOptions, linkedAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData populateClientDefaults(final LoanAccountData acc, final LoanAccountData clientAcc) {
|
public static LoanAccountData populateClientDefaults(final LoanAccountData acc, final LoanAccountData clientAcc) {
|
||||||
@@ -319,7 +327,7 @@ public class LoanAccountData {
|
|||||||
acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
|
acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
|
||||||
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
|
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
|
||||||
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, acc.syncDisbursementWithMeeting,
|
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, acc.syncDisbursementWithMeeting,
|
||||||
acc.loanCounter, acc.loanProductCounter, acc.notes);
|
acc.loanCounter, acc.loanProductCounter, acc.notes,acc.accountLinkingOptions, acc.linkedAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -396,6 +404,8 @@ public class LoanAccountData {
|
|||||||
final Boolean syncDisbursementWithMeeting = null;
|
final Boolean syncDisbursementWithMeeting = null;
|
||||||
final Integer loancounter = null;
|
final Integer loancounter = null;
|
||||||
final Integer loanProductCounter = null;
|
final Integer loanProductCounter = null;
|
||||||
|
final Collection<PortfolioAccountData> accountLinkingOptions = null;
|
||||||
|
final PortfolioAccountData linkedAccount = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
||||||
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
||||||
@@ -407,7 +417,7 @@ public class LoanAccountData {
|
|||||||
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions,
|
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions,
|
||||||
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
||||||
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
||||||
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes);
|
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes,accountLinkingOptions, linkedAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData populateGroupDefaults(final LoanAccountData acc, final LoanAccountData groupAcc) {
|
public static LoanAccountData populateGroupDefaults(final LoanAccountData acc, final LoanAccountData groupAcc) {
|
||||||
@@ -425,9 +435,9 @@ public class LoanAccountData {
|
|||||||
acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
|
acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
|
||||||
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
|
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
|
||||||
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
|
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
|
||||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes);
|
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes,acc.accountLinkingOptions, acc.linkedAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData loanProductWithTemplateDefaults(final LoanProductData product,
|
public static LoanAccountData loanProductWithTemplateDefaults(final LoanProductData product,
|
||||||
final Collection<EnumOptionData> termFrequencyTypeOptions, final Collection<EnumOptionData> repaymentFrequencyTypeOptions,
|
final Collection<EnumOptionData> termFrequencyTypeOptions, final Collection<EnumOptionData> repaymentFrequencyTypeOptions,
|
||||||
final Collection<TransactionProcessingStrategyData> repaymentStrategyOptions,
|
final Collection<TransactionProcessingStrategyData> repaymentStrategyOptions,
|
||||||
@@ -495,6 +505,8 @@ public class LoanAccountData {
|
|||||||
|
|
||||||
final Integer loancounter = null;
|
final Integer loancounter = null;
|
||||||
final Integer loanProductCounter = null;
|
final Integer loanProductCounter = null;
|
||||||
|
final PortfolioAccountData linkedAccount = null;
|
||||||
|
final Collection<PortfolioAccountData> accountLinkingOptions = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType,
|
||||||
product.getId(), product.getName(), product.getDescription(), product.getFundId(), product.getFundName(), loanPurposeId,
|
product.getId(), product.getName(), product.getDescription(), product.getFundId(), product.getFundName(), loanPurposeId,
|
||||||
@@ -508,7 +520,8 @@ public class LoanAccountData {
|
|||||||
repaymentSchedule, transactions, charges, collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions,
|
repaymentSchedule, transactions, charges, collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions,
|
||||||
repaymentFrequencyTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions,
|
repaymentFrequencyTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions,
|
||||||
interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions,
|
interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions,
|
||||||
loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes);
|
loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes,
|
||||||
|
accountLinkingOptions, linkedAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) {
|
public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) {
|
||||||
@@ -556,7 +569,7 @@ public class LoanAccountData {
|
|||||||
calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions,
|
calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions,
|
||||||
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
||||||
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
||||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, notes);
|
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, notes,acc.accountLinkingOptions, acc.linkedAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -600,6 +613,8 @@ public class LoanAccountData {
|
|||||||
final Collection<CodeValueData> loanPurposeOptions = null;
|
final Collection<CodeValueData> loanPurposeOptions = null;
|
||||||
final Collection<CodeValueData> loanCollateralOptions = null;
|
final Collection<CodeValueData> loanCollateralOptions = null;
|
||||||
final Collection<CalendarData> calendarOptions = null;
|
final Collection<CalendarData> calendarOptions = null;
|
||||||
|
final Collection<PortfolioAccountData> accountLinkingOptions = null;
|
||||||
|
final PortfolioAccountData linkedAccount = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, group, loanType, loanProductId,
|
||||||
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
||||||
@@ -611,7 +626,7 @@ public class LoanAccountData {
|
|||||||
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions,
|
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions,
|
||||||
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
||||||
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
||||||
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes);
|
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes,accountLinkingOptions, linkedAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -628,7 +643,8 @@ public class LoanAccountData {
|
|||||||
final Collection<EnumOptionData> interestTypeOptions, final Collection<EnumOptionData> interestCalculationPeriodTypeOptions,
|
final Collection<EnumOptionData> interestTypeOptions, final Collection<EnumOptionData> interestCalculationPeriodTypeOptions,
|
||||||
final Collection<FundData> fundOptions, final Collection<ChargeData> chargeOptions, final ChargeData chargeTemplate,
|
final Collection<FundData> fundOptions, final Collection<ChargeData> chargeOptions, final ChargeData chargeTemplate,
|
||||||
final Collection<StaffData> loanOfficerOptions, final Collection<CodeValueData> loanPurposeOptions,
|
final Collection<StaffData> loanOfficerOptions, final Collection<CodeValueData> loanPurposeOptions,
|
||||||
final Collection<CodeValueData> loanCollateralOptions, final Collection<CalendarData> calendarOptions, final Collection<NoteData> notes) {
|
final Collection<CodeValueData> loanCollateralOptions, final Collection<CalendarData> calendarOptions, final Collection<NoteData> notes,
|
||||||
|
final Collection<PortfolioAccountData> accountLinkingOptions, PortfolioAccountData linkedAccount) {
|
||||||
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
||||||
acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.fundId, acc.fundName,
|
acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.fundId, acc.fundName,
|
||||||
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.principal,
|
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.principal,
|
||||||
@@ -641,16 +657,16 @@ public class LoanAccountData {
|
|||||||
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, transactionProcessingStrategyOptions,
|
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, transactionProcessingStrategyOptions,
|
||||||
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
||||||
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
||||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, notes);
|
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, notes,accountLinkingOptions, linkedAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData associationsAndTemplate(final LoanAccountData acc, final Collection<LoanProductData> productOptions,
|
public static LoanAccountData associationsAndTemplate(final LoanAccountData acc, final Collection<LoanProductData> productOptions,
|
||||||
final Collection<StaffData> allowedLoanOfficers, final Collection<CalendarData> calendarOptions) {
|
final Collection<StaffData> allowedLoanOfficers, final Collection<CalendarData> calendarOptions,final Collection<PortfolioAccountData> accountLinkingOptions) {
|
||||||
return associationsAndTemplate(acc, acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors,
|
return associationsAndTemplate(acc, acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors,
|
||||||
acc.meeting, productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions,
|
acc.meeting, productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions,
|
||||||
acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
|
acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
|
||||||
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
|
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
|
||||||
allowedLoanOfficers, acc.loanPurposeOptions, acc.loanCollateralOptions, calendarOptions, acc.notes);
|
allowedLoanOfficers, acc.loanPurposeOptions, acc.loanCollateralOptions, calendarOptions, acc.notes, accountLinkingOptions, acc.linkedAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData associateGroup(final LoanAccountData acc, final GroupGeneralData group) {
|
public static LoanAccountData associateGroup(final LoanAccountData acc, final GroupGeneralData group) {
|
||||||
@@ -668,7 +684,7 @@ public class LoanAccountData {
|
|||||||
acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
|
acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
|
||||||
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
|
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
|
||||||
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
|
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
|
||||||
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes);
|
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes,acc.accountLinkingOptions, acc.linkedAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoanAccountData(
|
private LoanAccountData(
|
||||||
@@ -717,7 +733,8 @@ public class LoanAccountData {
|
|||||||
final Collection<FundData> fundOptions, final Collection<ChargeData> chargeOptions, final ChargeData chargeTemplate,
|
final Collection<FundData> fundOptions, final Collection<ChargeData> chargeOptions, final ChargeData chargeTemplate,
|
||||||
final Collection<StaffData> loanOfficerOptions, final Collection<CodeValueData> loanPurposeOptions,
|
final Collection<StaffData> loanOfficerOptions, final Collection<CodeValueData> loanPurposeOptions,
|
||||||
final Collection<CodeValueData> loanCollateralOptions, final Collection<CalendarData> calendarOptions,
|
final Collection<CodeValueData> loanCollateralOptions, final Collection<CalendarData> calendarOptions,
|
||||||
final Boolean syncDisbursementWithMeeting, final Integer loanCounter, final Integer loanProductCounter, final Collection<NoteData> notes) {
|
final Boolean syncDisbursementWithMeeting, final Integer loanCounter, final Integer loanProductCounter, final Collection<NoteData> notes,
|
||||||
|
final Collection<PortfolioAccountData> accountLinkingOptions, PortfolioAccountData linkedAccount) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.accountNo = accountNo;
|
this.accountNo = accountNo;
|
||||||
this.status = status;
|
this.status = status;
|
||||||
@@ -827,6 +844,9 @@ public class LoanAccountData {
|
|||||||
|
|
||||||
this.loanCounter = loanCounter;
|
this.loanCounter = loanCounter;
|
||||||
this.loanProductCounter = loanProductCounter;
|
this.loanProductCounter = loanProductCounter;
|
||||||
|
|
||||||
|
this.linkedAccount = linkedAccount;
|
||||||
|
this.accountLinkingOptions = accountLinkingOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData() {
|
public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData() {
|
||||||
@@ -857,4 +877,13 @@ public class LoanAccountData {
|
|||||||
public Long groupId() {
|
public Long groupId() {
|
||||||
return group == null ? null : group.getId();
|
return group == null ? null : group.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public CurrencyData currency() {
|
||||||
|
return this.currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long clientId(){
|
||||||
|
return this.clientId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+78
-5
@@ -12,6 +12,7 @@ import org.joda.time.LocalDate;
|
|||||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||||
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
||||||
|
import org.mifosplatform.portfolio.charge.domain.ChargePaymentMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Immutable data object for loan charge data.
|
* Immutable data object for loan charge data.
|
||||||
@@ -66,8 +67,18 @@ public class LoanChargeData {
|
|||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private final boolean penalty;
|
private final boolean penalty;
|
||||||
|
|
||||||
|
private final EnumOptionData chargePaymentMode;
|
||||||
|
|
||||||
|
private final boolean paid;
|
||||||
|
|
||||||
|
private final boolean waived;
|
||||||
|
|
||||||
|
private final boolean chargePayable;
|
||||||
|
|
||||||
|
private final Long loanId;
|
||||||
|
|
||||||
public static LoanChargeData template(final Collection<ChargeData> chargeOptions) {
|
public static LoanChargeData template(final Collection<ChargeData> chargeOptions) {
|
||||||
return new LoanChargeData(null, null, null, null, null, null, null, null, chargeOptions, false);
|
return new LoanChargeData(null, null, null, null, null, null, null, null, chargeOptions, false, null, false, false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,15 +87,16 @@ public class LoanChargeData {
|
|||||||
*/
|
*/
|
||||||
public static LoanChargeData newLoanChargeDetails(final Long chargeId, final String name, final CurrencyData currency,
|
public static LoanChargeData newLoanChargeDetails(final Long chargeId, final String name, final CurrencyData currency,
|
||||||
final BigDecimal amount, final BigDecimal percentage, final EnumOptionData chargeTimeType,
|
final BigDecimal amount, final BigDecimal percentage, final EnumOptionData chargeTimeType,
|
||||||
final EnumOptionData chargeCalculationType, final boolean penalty) {
|
final EnumOptionData chargeCalculationType, final boolean penalty, final EnumOptionData chargePaymentMode) {
|
||||||
return new LoanChargeData(null, chargeId, name, currency, amount, percentage, chargeTimeType, chargeCalculationType, null, penalty);
|
return new LoanChargeData(null, chargeId, name, currency, amount, percentage, chargeTimeType, chargeCalculationType, null, penalty,
|
||||||
|
chargePaymentMode, false, false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoanChargeData(final Long id, final Long chargeId, final String name, final CurrencyData currency, final BigDecimal amount,
|
public LoanChargeData(final Long id, final Long chargeId, final String name, final CurrencyData currency, final BigDecimal amount,
|
||||||
final BigDecimal amountPaid, final BigDecimal amountWaived, final BigDecimal amountWrittenOff,
|
final BigDecimal amountPaid, final BigDecimal amountWaived, final BigDecimal amountWrittenOff,
|
||||||
final BigDecimal amountOutstanding, final EnumOptionData chargeTimeType, final LocalDate dueDate,
|
final BigDecimal amountOutstanding, final EnumOptionData chargeTimeType, final LocalDate dueDate,
|
||||||
final EnumOptionData chargeCalculationType, final BigDecimal percentage, final BigDecimal amountPercentageAppliedTo,
|
final EnumOptionData chargeCalculationType, final BigDecimal percentage, final BigDecimal amountPercentageAppliedTo,
|
||||||
final boolean penalty) {
|
final boolean penalty, EnumOptionData chargePaymentMode, boolean paid, boolean waived, Long loanId) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.chargeId = chargeId;
|
this.chargeId = chargeId;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@@ -100,6 +112,9 @@ public class LoanChargeData {
|
|||||||
this.percentage = percentage;
|
this.percentage = percentage;
|
||||||
this.amountPercentageAppliedTo = amountPercentageAppliedTo;
|
this.amountPercentageAppliedTo = amountPercentageAppliedTo;
|
||||||
this.penalty = penalty;
|
this.penalty = penalty;
|
||||||
|
this.chargePaymentMode = chargePaymentMode;
|
||||||
|
this.paid = paid;
|
||||||
|
this.waived = waived;
|
||||||
|
|
||||||
if (chargeCalculationType != null && chargeCalculationType.getId().intValue() > 1) {
|
if (chargeCalculationType != null && chargeCalculationType.getId().intValue() > 1) {
|
||||||
this.amountOrPercentage = this.percentage;
|
this.amountOrPercentage = this.percentage;
|
||||||
@@ -108,11 +123,14 @@ public class LoanChargeData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.chargeOptions = null;
|
this.chargeOptions = null;
|
||||||
|
this.chargePayable = isChargePayable();
|
||||||
|
this.loanId = loanId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoanChargeData(final Long id, final Long chargeId, final String name, final CurrencyData currency, final BigDecimal amount,
|
private LoanChargeData(final Long id, final Long chargeId, final String name, final CurrencyData currency, final BigDecimal amount,
|
||||||
final BigDecimal pecentage, final EnumOptionData chargeTimeType, final EnumOptionData chargeCalculationType,
|
final BigDecimal pecentage, final EnumOptionData chargeTimeType, final EnumOptionData chargeCalculationType,
|
||||||
final Collection<ChargeData> chargeOptions, final boolean penalty) {
|
final Collection<ChargeData> chargeOptions, final boolean penalty, EnumOptionData chargePaymentMode, boolean paid,
|
||||||
|
boolean waived, Long loanId) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.chargeId = chargeId;
|
this.chargeId = chargeId;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@@ -128,6 +146,9 @@ public class LoanChargeData {
|
|||||||
this.percentage = pecentage;
|
this.percentage = pecentage;
|
||||||
this.amountPercentageAppliedTo = null;
|
this.amountPercentageAppliedTo = null;
|
||||||
this.penalty = penalty;
|
this.penalty = penalty;
|
||||||
|
this.chargePaymentMode = chargePaymentMode;
|
||||||
|
this.paid = paid;
|
||||||
|
this.waived = waived;
|
||||||
|
|
||||||
if (chargeCalculationType != null && chargeCalculationType.getId().intValue() > 1) {
|
if (chargeCalculationType != null && chargeCalculationType.getId().intValue() > 1) {
|
||||||
this.amountOrPercentage = this.percentage;
|
this.amountOrPercentage = this.percentage;
|
||||||
@@ -136,5 +157,57 @@ public class LoanChargeData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.chargeOptions = chargeOptions;
|
this.chargeOptions = chargeOptions;
|
||||||
|
this.chargePayable = isChargePayable();
|
||||||
|
this.loanId = loanId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanChargeData(final Long id,final LocalDate dueAsOfDate,final BigDecimal amountOutstanding,final Long loanId) {
|
||||||
|
this.id = id;
|
||||||
|
this.chargeId = null;
|
||||||
|
this.name = null;
|
||||||
|
this.currency = null;
|
||||||
|
this.amount = null;
|
||||||
|
this.amountPaid = null;
|
||||||
|
this.amountWaived = null;
|
||||||
|
this.amountWrittenOff = null;
|
||||||
|
this.amountOutstanding = amountOutstanding;
|
||||||
|
this.chargeTimeType = null;
|
||||||
|
this.dueDate = dueAsOfDate;
|
||||||
|
this.chargeCalculationType = null;
|
||||||
|
this.percentage = null;
|
||||||
|
this.amountPercentageAppliedTo = null;
|
||||||
|
this.penalty = false;
|
||||||
|
this.chargePaymentMode = null;
|
||||||
|
this.paid = false;
|
||||||
|
this.waived = false;
|
||||||
|
this.amountOrPercentage = null;
|
||||||
|
this.chargeOptions = null;
|
||||||
|
this.chargePayable = false;
|
||||||
|
this.loanId = loanId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isChargePayable() {
|
||||||
|
boolean isAccountTransfer = false;
|
||||||
|
if(this.chargePaymentMode!=null){
|
||||||
|
isAccountTransfer = ChargePaymentMode.fromInt(this.chargePaymentMode.getId().intValue()).isPaymentModeAccountTransfer();
|
||||||
|
}
|
||||||
|
return isAccountTransfer && !this.paid && !this.waived;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getDueDate() {
|
||||||
|
return this.dueDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getLoanId() {
|
||||||
|
return this.loanId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public BigDecimal getAmountOutstanding() {
|
||||||
|
return this.amountOutstanding;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+14
@@ -29,6 +29,8 @@ public class LoanTransactionEnumData {
|
|||||||
private final boolean approveTransfer;
|
private final boolean approveTransfer;
|
||||||
private final boolean withdrawTransfer;
|
private final boolean withdrawTransfer;
|
||||||
private final boolean rejectTransfer;
|
private final boolean rejectTransfer;
|
||||||
|
private final boolean chargePayment;
|
||||||
|
private final boolean refund;
|
||||||
|
|
||||||
public LoanTransactionEnumData(final Long id, final String code, final String value) {
|
public LoanTransactionEnumData(final Long id, final String code, final String value) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
@@ -48,6 +50,8 @@ public class LoanTransactionEnumData {
|
|||||||
this.approveTransfer = Long.valueOf(13).equals(this.id);
|
this.approveTransfer = Long.valueOf(13).equals(this.id);
|
||||||
this.withdrawTransfer = Long.valueOf(14).equals(this.id);
|
this.withdrawTransfer = Long.valueOf(14).equals(this.id);
|
||||||
this.rejectTransfer = Long.valueOf(15).equals(this.id);
|
this.rejectTransfer = Long.valueOf(15).equals(this.id);
|
||||||
|
this.refund = Long.valueOf(16).equals(this.id);
|
||||||
|
this.chargePayment = Long.valueOf(17).equals(this.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long id() {
|
public Long id() {
|
||||||
@@ -117,4 +121,14 @@ public class LoanTransactionEnumData {
|
|||||||
return this.rejectTransfer;
|
return this.rejectTransfer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean isChargePayment() {
|
||||||
|
return this.chargePayment;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean isRefund() {
|
||||||
|
return this.refund;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+1
@@ -56,6 +56,7 @@ public class DefaultLoanLifecycleStateMachine implements LoanLifecycleStateMachi
|
|||||||
newState = stateOf(LoanStatus.APPROVED, allowedLoanStatuses);
|
newState = stateOf(LoanStatus.APPROVED, allowedLoanStatuses);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case LOAN_CHARGE_PAYMENT:
|
||||||
case LOAN_REPAYMENT_OR_WAIVER:
|
case LOAN_REPAYMENT_OR_WAIVER:
|
||||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE, LoanStatus.CLOSED_OBLIGATIONS_MET, LoanStatus.OVERPAID)) {
|
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.ACTIVE, LoanStatus.CLOSED_OBLIGATIONS_MET, LoanStatus.OVERPAID)) {
|
||||||
newState = stateOf(LoanStatus.ACTIVE, allowedLoanStatuses);
|
newState = stateOf(LoanStatus.ACTIVE, allowedLoanStatuses);
|
||||||
|
|||||||
+112
-21
@@ -501,6 +501,32 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
return applyLoanChargeTransaction;
|
return applyLoanChargeTransaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleChargePaidTransaction(final LoanCharge charge, final LoanTransaction chargesPayment,
|
||||||
|
final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||||
|
chargesPayment.updateLoan(this);
|
||||||
|
this.loanTransactions.add(chargesPayment);
|
||||||
|
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_CHARGE_PAYMENT,
|
||||||
|
LoanStatus.fromInt(this.loanStatus));
|
||||||
|
this.loanStatus = statusEnum.getValue();
|
||||||
|
|
||||||
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||||
|
.determineProcessor(this.transactionProcessingStrategy);
|
||||||
|
List<LoanRepaymentScheduleInstallment> chargePaymentInstallments = new ArrayList<LoanRepaymentScheduleInstallment>();
|
||||||
|
LocalDate startDate = getDisbursementDate();
|
||||||
|
for (LoanRepaymentScheduleInstallment installment : this.repaymentScheduleInstallments) {
|
||||||
|
if (charge.isDueForCollectionFromAndUpToAndIncluding(startDate, installment.getDueDate())) {
|
||||||
|
chargePaymentInstallments.add(installment);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
startDate = installment.getDueDate();
|
||||||
|
}
|
||||||
|
Set<LoanCharge> loanCharges = new HashSet<LoanCharge>(1);
|
||||||
|
loanCharges.add(charge);
|
||||||
|
loanRepaymentScheduleTransactionProcessor.handleTransaction(chargesPayment, getCurrency(), chargePaymentInstallments, loanCharges);
|
||||||
|
updateLoanSummaryDerivedFields();
|
||||||
|
doPostLoanTransactionChecks(chargesPayment.getTransactionDate(), loanLifecycleStateMachine);
|
||||||
|
}
|
||||||
|
|
||||||
private void validateLoanIsNotClosed(final LoanCharge loanCharge) {
|
private void validateLoanIsNotClosed(final LoanCharge loanCharge) {
|
||||||
if (isClosed()) {
|
if (isClosed()) {
|
||||||
final String defaultUserMessage = "This charge cannot be added as the loan is already closed.";
|
final String defaultUserMessage = "This charge cannot be added as the loan is already closed.";
|
||||||
@@ -1420,13 +1446,6 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
final Money totalFeeChargesDueAtDisbursement = this.summary.getTotalFeeChargesDueAtDisbursement(loanCurrency());
|
final Money totalFeeChargesDueAtDisbursement = this.summary.getTotalFeeChargesDueAtDisbursement(loanCurrency());
|
||||||
if (totalFeeChargesDueAtDisbursement.isGreaterThanZero()) {
|
if (totalFeeChargesDueAtDisbursement.isGreaterThanZero()) {
|
||||||
|
|
||||||
final LoanTransaction chargesPayment = LoanTransaction.repaymentAtDisbursement(this.getOffice(),
|
|
||||||
totalFeeChargesDueAtDisbursement, null, disbursedOn, txnExternalId);
|
|
||||||
final Money zero = Money.zero(getCurrency());
|
|
||||||
chargesPayment.updateComponents(zero, zero, totalFeeChargesDueAtDisbursement, zero);
|
|
||||||
chargesPayment.updateLoan(this);
|
|
||||||
this.loanTransactions.add(chargesPayment);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* all Charges repaid at disbursal is marked as repaid and
|
* all Charges repaid at disbursal is marked as repaid and
|
||||||
* "APPLY Charge" transactions are created for all other fees (
|
* "APPLY Charge" transactions are created for all other fees (
|
||||||
@@ -1434,10 +1453,19 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
**/
|
**/
|
||||||
for (final LoanCharge charge : setOfLoanCharges()) {
|
for (final LoanCharge charge : setOfLoanCharges()) {
|
||||||
if (charge.isDueAtDisbursement()) {
|
if (charge.isDueAtDisbursement()) {
|
||||||
charge.markAsFullyPaid();
|
if (!charge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
|
||||||
// Add "Loan Charge Paid By" details to this transaction
|
final LoanTransaction chargesPayment = LoanTransaction.repaymentAtDisbursement(this.getOffice(),
|
||||||
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(chargesPayment, charge, charge.amount());
|
charge.getAmount(getCurrency()), null, disbursedOn, txnExternalId);
|
||||||
chargesPayment.getLoanChargesPaid().add(loanChargePaidBy);
|
final Money zero = Money.zero(getCurrency());
|
||||||
|
chargesPayment.updateComponents(zero, zero, totalFeeChargesDueAtDisbursement, zero);
|
||||||
|
chargesPayment.updateLoan(this);
|
||||||
|
this.loanTransactions.add(chargesPayment);
|
||||||
|
|
||||||
|
charge.markAsFullyPaid();
|
||||||
|
// Add "Loan Charge Paid By" details to this transaction
|
||||||
|
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(chargesPayment, charge, charge.amount());
|
||||||
|
chargesPayment.getLoanChargesPaid().add(loanChargePaidBy);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
handleChargeAppliedTransaction(charge, disbursedOn);
|
handleChargeAppliedTransaction(charge, disbursedOn);
|
||||||
}
|
}
|
||||||
@@ -1462,6 +1490,24 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
return disbursementTransaction;
|
return disbursementTransaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LoanTransaction handlePayDisbursementTransaction(final Long chargeId, final LoanTransaction chargesPayment) {
|
||||||
|
LoanCharge charge = null;
|
||||||
|
for (LoanCharge loanCharge : this.charges) {
|
||||||
|
if (chargeId.equals(loanCharge.getId())) {
|
||||||
|
charge = loanCharge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@SuppressWarnings("null")
|
||||||
|
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(chargesPayment, charge, charge.amount());
|
||||||
|
chargesPayment.getLoanChargesPaid().add(loanChargePaidBy);
|
||||||
|
final Money zero = Money.zero(getCurrency());
|
||||||
|
chargesPayment.updateComponents(zero, zero, charge.getAmount(getCurrency()), zero);
|
||||||
|
chargesPayment.updateLoan(this);
|
||||||
|
this.loanTransactions.add(chargesPayment);
|
||||||
|
charge.markAsFullyPaid();
|
||||||
|
return chargesPayment;
|
||||||
|
}
|
||||||
|
|
||||||
public Map<String, Object> undoDisbursal(final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) {
|
public Map<String, Object> undoDisbursal(final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) {
|
||||||
|
|
||||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
|
||||||
@@ -1547,6 +1593,31 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
return changedTransactionDetail;
|
return changedTransactionDetail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void makeChargePayment(final Long chargeId, final LoanLifecycleStateMachine loanLifecycleStateMachine,
|
||||||
|
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
|
||||||
|
final boolean allowTransactionsOnHoliday, final List<Holiday> holidays, final WorkingDays workingDays,
|
||||||
|
final boolean allowTransactionsOnNonWorkingDay, LoanTransaction paymentTransaction) {
|
||||||
|
|
||||||
|
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_CHARGE_PAYMENT, paymentTransaction.getTransactionDate());
|
||||||
|
validateRepaymentDateIsOnHoliday(paymentTransaction.getTransactionDate(), allowTransactionsOnHoliday, holidays);
|
||||||
|
validateRepaymentDateIsOnNonWorkingDay(paymentTransaction.getTransactionDate(), workingDays, allowTransactionsOnNonWorkingDay);
|
||||||
|
|
||||||
|
if (paymentTransaction.getTransactionDate().isAfter(new LocalDate())) {
|
||||||
|
final String errorMessage = "The date on which a loan charge paid cannot be in the future.";
|
||||||
|
throw new InvalidLoanStateTransitionException("charge.payment", "cannot.be.a.future.date", errorMessage,
|
||||||
|
paymentTransaction.getTransactionDate());
|
||||||
|
}
|
||||||
|
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||||
|
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||||
|
LoanCharge charge = null;
|
||||||
|
for (LoanCharge loanCharge : this.charges) {
|
||||||
|
if (chargeId.equals(loanCharge.getId())) {
|
||||||
|
charge = loanCharge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handleChargePaidTransaction(charge, paymentTransaction, loanLifecycleStateMachine);
|
||||||
|
}
|
||||||
|
|
||||||
public void makeRefund(final LoanTransaction loanTransaction, final LoanLifecycleStateMachine loanLifecycleStateMachine,
|
public void makeRefund(final LoanTransaction loanTransaction, final LoanLifecycleStateMachine loanLifecycleStateMachine,
|
||||||
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
|
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
|
||||||
final boolean allowTransactionsOnHoliday, final List<Holiday> holidays, final WorkingDays workingDays,
|
final boolean allowTransactionsOnHoliday, final List<Holiday> holidays, final WorkingDays workingDays,
|
||||||
@@ -1571,16 +1642,13 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
final String errorMessage = "Transfer funds is allowed only for loan accounts with overpaid status ";
|
final String errorMessage = "Transfer funds is allowed only for loan accounts with overpaid status ";
|
||||||
throw new InvalidLoanStateTransitionException("transaction", "is.not.a.overpaid.loan", errorMessage);
|
throw new InvalidLoanStateTransitionException("transaction", "is.not.a.overpaid.loan", errorMessage);
|
||||||
}
|
}
|
||||||
this.totalOverpaid = this.totalOverpaid.subtract(loanTransaction.getAmount(getCurrency()).getAmount());
|
|
||||||
if (this.totalOverpaid.compareTo(BigDecimal.ZERO) == 0) {
|
|
||||||
handleLoanRepaymentInFull(loanTransaction.getTransactionDate(), loanLifecycleStateMachine);
|
|
||||||
}
|
|
||||||
loanTransaction.updateLoan(this);
|
loanTransaction.updateLoan(this);
|
||||||
|
|
||||||
if (loanTransaction.isNotZero(loanCurrency())) {
|
if (loanTransaction.isNotZero(loanCurrency())) {
|
||||||
this.loanTransactions.add(loanTransaction);
|
this.loanTransactions.add(loanTransaction);
|
||||||
}
|
}
|
||||||
|
updateLoanSummaryDerivedFields();
|
||||||
|
doPostLoanTransactionChecks(loanTransaction.getTransactionDate(), loanLifecycleStateMachine);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChangedTransactionDetail handleRepaymentOrWaiverTransaction(final LoanTransaction loanTransaction,
|
private ChangedTransactionDetail handleRepaymentOrWaiverTransaction(final LoanTransaction loanTransaction,
|
||||||
@@ -1676,11 +1744,25 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
private void handleLoanRepaymentInFull(final LocalDate transactionDate, final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
private void handleLoanRepaymentInFull(final LocalDate transactionDate, final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||||
|
|
||||||
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.REPAID_IN_FULL, LoanStatus.fromInt(this.loanStatus));
|
boolean isAllChargesPaid = true;
|
||||||
this.loanStatus = statusEnum.getValue();
|
for (LoanCharge loanCharge : this.charges) {
|
||||||
|
if (!(loanCharge.isPaid() || loanCharge.isWaived())) {
|
||||||
|
isAllChargesPaid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isAllChargesPaid) {
|
||||||
|
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.REPAID_IN_FULL,
|
||||||
|
LoanStatus.fromInt(this.loanStatus));
|
||||||
|
this.loanStatus = statusEnum.getValue();
|
||||||
|
|
||||||
this.closedOnDate = transactionDate.toDate();
|
this.closedOnDate = transactionDate.toDate();
|
||||||
this.actualMaturityDate = transactionDate.toDate();
|
this.actualMaturityDate = transactionDate.toDate();
|
||||||
|
} else if (LoanStatus.fromInt(this.loanStatus).isOverpaid()) {
|
||||||
|
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_REPAYMENT_OR_WAIVER,
|
||||||
|
LoanStatus.fromInt(this.loanStatus));
|
||||||
|
this.loanStatus = statusEnum.getValue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleLoanOverpayment(final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
private void handleLoanOverpayment(final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||||
@@ -2194,7 +2276,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
Money cumulativePaid = Money.zero(loanCurrency());
|
Money cumulativePaid = Money.zero(loanCurrency());
|
||||||
|
|
||||||
for (final LoanTransaction repayment : this.loanTransactions) {
|
for (final LoanTransaction repayment : this.loanTransactions) {
|
||||||
if (repayment.isRepayment()) {
|
if (repayment.isRepayment() && !repayment.isReversed()) {
|
||||||
cumulativePaid = cumulativePaid.plus(repayment.getAmount(loanCurrency()));
|
cumulativePaid = cumulativePaid.plus(repayment.getAmount(loanCurrency()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2731,6 +2813,11 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
action = "close";
|
action = "close";
|
||||||
postfix = "cannot.be.undone.before.client.transfer.date";
|
postfix = "cannot.be.undone.before.client.transfer.date";
|
||||||
break;
|
break;
|
||||||
|
case LOAN_CHARGE_PAYMENT:
|
||||||
|
errorMessage = "The date on which a charge payment is made cannot be earlier than client's transfer date to this office";
|
||||||
|
action = "charge.payment";
|
||||||
|
postfix = "cannot.be.made.before.client.transfer.date";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2738,4 +2825,8 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<LoanCharge> charges() {
|
||||||
|
return this.charges;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+4
-1
@@ -13,11 +13,14 @@ import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
|
|||||||
|
|
||||||
public interface LoanAccountDomainService {
|
public interface LoanAccountDomainService {
|
||||||
|
|
||||||
LoanTransaction makeRepayment(Long accountId, CommandProcessingResultBuilder builderResult, LocalDate transactionDate,
|
LoanTransaction makeRepayment(Loan loan, CommandProcessingResultBuilder builderResult, LocalDate transactionDate,
|
||||||
BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, String txnExternalId);
|
BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, String txnExternalId);
|
||||||
|
|
||||||
LoanTransaction makeRefund(Long accountId, CommandProcessingResultBuilder builderResult, LocalDate transactionDate,
|
LoanTransaction makeRefund(Long accountId, CommandProcessingResultBuilder builderResult, LocalDate transactionDate,
|
||||||
BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, String txnExternalId);
|
BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, String txnExternalId);
|
||||||
|
|
||||||
void reverseTransfer(LoanTransaction loanTransaction);
|
void reverseTransfer(LoanTransaction loanTransaction);
|
||||||
|
|
||||||
|
LoanTransaction makeChargePayment(Loan loan, Long chargeId, LocalDate transactionDate, BigDecimal transactionAmount,
|
||||||
|
PaymentDetail paymentDetail, String noteText, String txnExternalId, Integer transactionType);
|
||||||
}
|
}
|
||||||
|
|||||||
+40
-2
@@ -70,11 +70,10 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
public LoanTransaction makeRepayment(final Long accountId, final CommandProcessingResultBuilder builderResult,
|
public LoanTransaction makeRepayment(final Loan loan, final CommandProcessingResultBuilder builderResult,
|
||||||
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final String noteText,
|
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final String noteText,
|
||||||
final String txnExternalId) {
|
final String txnExternalId) {
|
||||||
|
|
||||||
final Loan loan = this.loanAccountAssembler.assembleFrom(accountId);
|
|
||||||
checkClientOrGroupActive(loan);
|
checkClientOrGroupActive(loan);
|
||||||
|
|
||||||
// TODO: Is it required to validate transaction date with meeting dates
|
// TODO: Is it required to validate transaction date with meeting dates
|
||||||
@@ -137,6 +136,45 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
|||||||
return newRepaymentTransaction;
|
return newRepaymentTransaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public LoanTransaction makeChargePayment(final Loan loan, final Long chargeId, final LocalDate transactionDate,
|
||||||
|
final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final String noteText, final String txnExternalId,
|
||||||
|
final Integer transactionType) {
|
||||||
|
|
||||||
|
checkClientOrGroupActive(loan);
|
||||||
|
|
||||||
|
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||||
|
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||||
|
|
||||||
|
final Money paymentAmout = Money.of(loan.getCurrency(), transactionAmount);
|
||||||
|
LoanTransactionType loanTransactionType = LoanTransactionType.fromInt(transactionType);
|
||||||
|
|
||||||
|
final LoanTransaction newPaymentTransaction = LoanTransaction.loanPayment(null, loan.getOffice(), paymentAmout, paymentDetail,
|
||||||
|
transactionDate, txnExternalId, loanTransactionType);
|
||||||
|
final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled();
|
||||||
|
final List<Holiday> holidays = this.holidayRepository
|
||||||
|
.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), transactionDate.toDate());
|
||||||
|
final WorkingDays workingDays = this.workingDaysRepository.findOne();
|
||||||
|
final boolean allowTransactionsOnNonWorkingDay = this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled();
|
||||||
|
if(loanTransactionType.isRepaymentAtDisbursement()){
|
||||||
|
loan.handlePayDisbursementTransaction(chargeId, newPaymentTransaction);
|
||||||
|
}else{
|
||||||
|
loan.makeChargePayment(chargeId, defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds,
|
||||||
|
allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay, newPaymentTransaction);
|
||||||
|
}
|
||||||
|
this.loanTransactionRepository.save(newPaymentTransaction);
|
||||||
|
this.loanRepository.save(loan);
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(noteText)) {
|
||||||
|
final Note note = Note.loanTransactionNote(loan, newPaymentTransaction, noteText);
|
||||||
|
this.noteRepository.save(note);
|
||||||
|
}
|
||||||
|
|
||||||
|
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||||
|
return newPaymentTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
private void postJournalEntries(final Loan loanAccount, final List<Long> existingTransactionIds,
|
private void postJournalEntries(final Loan loanAccount, final List<Long> existingTransactionIds,
|
||||||
final List<Long> existingReversedTransactionIds) {
|
final List<Long> existingReversedTransactionIds) {
|
||||||
|
|
||||||
|
|||||||
+23
-4
@@ -28,6 +28,7 @@ import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
|||||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||||
import org.mifosplatform.portfolio.charge.domain.Charge;
|
import org.mifosplatform.portfolio.charge.domain.Charge;
|
||||||
import org.mifosplatform.portfolio.charge.domain.ChargeCalculationType;
|
import org.mifosplatform.portfolio.charge.domain.ChargeCalculationType;
|
||||||
|
import org.mifosplatform.portfolio.charge.domain.ChargePaymentMode;
|
||||||
import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
|
import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
|
||||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeWithoutMandatoryFieldException;
|
import org.mifosplatform.portfolio.charge.exception.LoanChargeWithoutMandatoryFieldException;
|
||||||
import org.mifosplatform.portfolio.loanaccount.command.LoanChargeCommand;
|
import org.mifosplatform.portfolio.loanaccount.command.LoanChargeCommand;
|
||||||
@@ -54,6 +55,9 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
@Column(name = "charge_calculation_enum")
|
@Column(name = "charge_calculation_enum")
|
||||||
private Integer chargeCalculation;
|
private Integer chargeCalculation;
|
||||||
|
|
||||||
|
@Column(name = "charge_payment_mode_enum")
|
||||||
|
private Integer chargePaymentMode;
|
||||||
|
|
||||||
@Column(name = "calculation_percentage", scale = 6, precision = 19, nullable = true)
|
@Column(name = "calculation_percentage", scale = 6, precision = 19, nullable = true)
|
||||||
private BigDecimal percentage;
|
private BigDecimal percentage;
|
||||||
@@ -92,16 +96,17 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
ChargeTimeType chargeTime = null;
|
ChargeTimeType chargeTime = null;
|
||||||
ChargeCalculationType chargeCalculation = null;
|
ChargeCalculationType chargeCalculation = null;
|
||||||
|
ChargePaymentMode chargePaymentMode = null;
|
||||||
|
|
||||||
return new LoanCharge(loan, chargeDefinition, loan.getPrincpal().getAmount(), amount, chargeTime, chargeCalculation, dueDate);
|
return new LoanCharge(loan, chargeDefinition, loan.getPrincpal().getAmount(), amount, chargeTime, chargeCalculation, dueDate, chargePaymentMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* loanPrincipal is required for charges that are percentage based
|
* loanPrincipal is required for charges that are percentage based
|
||||||
*/
|
*/
|
||||||
public static LoanCharge createNewWithoutLoan(final Charge chargeDefinition, final BigDecimal loanPrincipal, final BigDecimal amount,
|
public static LoanCharge createNewWithoutLoan(final Charge chargeDefinition, final BigDecimal loanPrincipal, final BigDecimal amount,
|
||||||
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculation, final LocalDate dueDate) {
|
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculation, final LocalDate dueDate, ChargePaymentMode chargePaymentMode) {
|
||||||
return new LoanCharge(null, chargeDefinition, loanPrincipal, amount, chargeTime, chargeCalculation, dueDate);
|
return new LoanCharge(null, chargeDefinition, loanPrincipal, amount, chargeTime, chargeCalculation, dueDate, chargePaymentMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected LoanCharge() {
|
protected LoanCharge() {
|
||||||
@@ -109,7 +114,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public LoanCharge(final Loan loan, final Charge chargeDefinition, final BigDecimal loanPrincipal, final BigDecimal amount,
|
public LoanCharge(final Loan loan, final Charge chargeDefinition, final BigDecimal loanPrincipal, final BigDecimal amount,
|
||||||
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculation, final LocalDate dueDate) {
|
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculation, final LocalDate dueDate, ChargePaymentMode chargePaymentMode) {
|
||||||
this.loan = loan;
|
this.loan = loan;
|
||||||
this.charge = chargeDefinition;
|
this.charge = chargeDefinition;
|
||||||
this.penaltyCharge = chargeDefinition.isPenalty();
|
this.penaltyCharge = chargeDefinition.isPenalty();
|
||||||
@@ -141,6 +146,11 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
if (amount != null) {
|
if (amount != null) {
|
||||||
chargeAmount = amount;
|
chargeAmount = amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.chargePaymentMode = chargeDefinition.getChargePaymentMode();
|
||||||
|
if(chargePaymentMode != null){
|
||||||
|
this.chargePaymentMode = chargePaymentMode.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
populateDerivedFields(loanPrincipal, chargeAmount);
|
populateDerivedFields(loanPrincipal, chargeAmount);
|
||||||
this.paid = determineIfFullyPaid();
|
this.paid = determineIfFullyPaid();
|
||||||
@@ -388,6 +398,10 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
public BigDecimal amount() {
|
public BigDecimal amount() {
|
||||||
return this.amount;
|
return this.amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BigDecimal amountOutstanding(){
|
||||||
|
return this.amountOutstanding;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasNotLoanIdentifiedBy(final Long loanId) {
|
public boolean hasNotLoanIdentifiedBy(final Long loanId) {
|
||||||
return !hasLoanIdentifiedBy(loanId);
|
return !hasLoanIdentifiedBy(loanId);
|
||||||
@@ -513,4 +527,9 @@ public class LoanCharge extends AbstractPersistable<Long> {
|
|||||||
.append(this.amount).append(this.getDueLocalDate()) //
|
.append(this.amount).append(this.getDueLocalDate()) //
|
||||||
.toHashCode();
|
.toHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ChargePaymentMode getChargePaymentMode() {
|
||||||
|
return ChargePaymentMode.fromInt(this.chargePaymentMode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+12
@@ -58,5 +58,17 @@ public class LoanChargePaidBy extends AbstractPersistable<Long> {
|
|||||||
public void setAmount(BigDecimal amount) {
|
public void setAmount(BigDecimal amount) {
|
||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
boolean isEqual = false;
|
||||||
|
LoanChargePaidBy paidBy = (LoanChargePaidBy)obj;
|
||||||
|
if(this.loanTransaction.getId() == paidBy.loanTransaction.getId()
|
||||||
|
&& this.loanCharge.getId() == paidBy.loanCharge.getId()
|
||||||
|
&& this.amount == paidBy.amount){
|
||||||
|
isEqual = true;
|
||||||
|
}
|
||||||
|
return isEqual;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -22,5 +22,6 @@ public enum LoanEvent {
|
|||||||
WRITE_OFF_OUTSTANDING, //
|
WRITE_OFF_OUTSTANDING, //
|
||||||
LOAN_RESCHEDULE, //
|
LOAN_RESCHEDULE, //
|
||||||
INTERST_REBATE_OWED, //
|
INTERST_REBATE_OWED, //
|
||||||
LOAN_OVERPAYMENT;
|
LOAN_OVERPAYMENT,
|
||||||
|
LOAN_CHARGE_PAYMENT;
|
||||||
}
|
}
|
||||||
|
|||||||
+21
@@ -108,6 +108,12 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
|||||||
final LocalDate paymentDate, final String externalId) {
|
final LocalDate paymentDate, final String externalId) {
|
||||||
return new LoanTransaction(null, office, LoanTransactionType.REPAYMENT, paymentDetail, amount.getAmount(), paymentDate, externalId);
|
return new LoanTransaction(null, office, LoanTransactionType.REPAYMENT, paymentDetail, amount.getAmount(), paymentDate, externalId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static LoanTransaction loanPayment(final Loan loan ,final Office office, final Money amount, final PaymentDetail paymentDetail,
|
||||||
|
final LocalDate paymentDate, final String externalId,final LoanTransactionType transactionType){
|
||||||
|
return new LoanTransaction(loan, office, transactionType, paymentDetail, amount.getAmount(), paymentDate,
|
||||||
|
externalId);
|
||||||
|
}
|
||||||
|
|
||||||
public static LoanTransaction repaymentAtDisbursement(final Office office, final Money amount, final PaymentDetail paymentDetail,
|
public static LoanTransaction repaymentAtDisbursement(final Office office, final Money amount, final PaymentDetail paymentDetail,
|
||||||
final LocalDate paymentDate, final String externalId) {
|
final LocalDate paymentDate, final String externalId) {
|
||||||
@@ -355,6 +361,21 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
|||||||
public boolean isNotWaiver() {
|
public boolean isNotWaiver() {
|
||||||
return !isInterestWaiver() && !isChargesWaiver();
|
return !isInterestWaiver() && !isChargesWaiver();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isChargePayment(){
|
||||||
|
return getTypeOf().isChargePayment() && isNotReversed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPenaltyPayment(){
|
||||||
|
boolean isPenalty = false;
|
||||||
|
if(isChargePayment()){
|
||||||
|
for(LoanChargePaidBy chargePaidBy:this.loanChargesPaid){
|
||||||
|
isPenalty = chargePaidBy.getLoanCharge().isPenaltyCharge();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isPenalty;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isWriteOff() {
|
public boolean isWriteOff() {
|
||||||
return getTypeOf().isWriteOff() && isNotReversed();
|
return getTypeOf().isWriteOff() && isNotReversed();
|
||||||
|
|||||||
+9
-1
@@ -34,7 +34,8 @@ public enum LoanTransactionType {
|
|||||||
WITHDRAW_TRANSFER(14, "loanTransactionType.withdrawTransfer"), //
|
WITHDRAW_TRANSFER(14, "loanTransactionType.withdrawTransfer"), //
|
||||||
REJECT_TRANSFER(15, "loanTransactionType.rejectTransfer"),
|
REJECT_TRANSFER(15, "loanTransactionType.rejectTransfer"),
|
||||||
|
|
||||||
REFUND(16,"loanTransactionType.refund");
|
REFUND(16,"loanTransactionType.refund"),
|
||||||
|
CHARGE_PAYMENT(17,"loanTransactionType.chargePayment");
|
||||||
|
|
||||||
private final Integer value;
|
private final Integer value;
|
||||||
private final String code;
|
private final String code;
|
||||||
@@ -106,6 +107,9 @@ public enum LoanTransactionType {
|
|||||||
case 16:
|
case 16:
|
||||||
loanTransactionType = LoanTransactionType.REFUND;
|
loanTransactionType = LoanTransactionType.REFUND;
|
||||||
break;
|
break;
|
||||||
|
case 17:
|
||||||
|
loanTransactionType = LoanTransactionType.CHARGE_PAYMENT;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
loanTransactionType = LoanTransactionType.INVALID;
|
loanTransactionType = LoanTransactionType.INVALID;
|
||||||
break;
|
break;
|
||||||
@@ -144,4 +148,8 @@ public enum LoanTransactionType {
|
|||||||
public boolean isWriteOff() {
|
public boolean isWriteOff() {
|
||||||
return this.value.equals(LoanTransactionType.WRITEOFF.getValue());
|
return this.value.equals(LoanTransactionType.WRITEOFF.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isChargePayment(){
|
||||||
|
return this.value.equals(LoanTransactionType.CHARGE_PAYMENT.getValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+27
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor;
|
package org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -64,7 +65,33 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
wrapper.reprocess(currency, disbursementDate, installments, charges);
|
wrapper.reprocess(currency, disbursementDate, installments, charges);
|
||||||
|
|
||||||
ChangedTransactionDetail changedTransactionDetail = new ChangedTransactionDetail();
|
ChangedTransactionDetail changedTransactionDetail = new ChangedTransactionDetail();
|
||||||
|
List<LoanTransaction> transactionstoBeProcessed = new ArrayList<LoanTransaction>();
|
||||||
for (LoanTransaction loanTransaction : transactionsPostDisbursement) {
|
for (LoanTransaction loanTransaction : transactionsPostDisbursement) {
|
||||||
|
if (loanTransaction.isChargePayment()){
|
||||||
|
Set<LoanChargePaidBy> chargePaidBies =loanTransaction.getLoanChargesPaid();
|
||||||
|
Set<LoanCharge> transferCharges = new HashSet<LoanCharge>();
|
||||||
|
for(LoanChargePaidBy chargePaidBy: chargePaidBies){
|
||||||
|
transferCharges.add(chargePaidBy.getLoanCharge());
|
||||||
|
}
|
||||||
|
List<LoanRepaymentScheduleInstallment> chargePaymentInstallments = new ArrayList<LoanRepaymentScheduleInstallment>();
|
||||||
|
LocalDate startDate = disbursementDate;
|
||||||
|
for(LoanRepaymentScheduleInstallment installment:installments){
|
||||||
|
for(LoanCharge loanCharge :transferCharges){
|
||||||
|
if(loanCharge.isDueForCollectionFromAndUpToAndIncluding(startDate, installment.getDueDate())){
|
||||||
|
chargePaymentInstallments.add(installment);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
startDate = installment.getDueDate();
|
||||||
|
}
|
||||||
|
loanTransaction.resetDerivedComponents();
|
||||||
|
handleTransaction(loanTransaction, currency, chargePaymentInstallments, transferCharges);
|
||||||
|
}else{
|
||||||
|
transactionstoBeProcessed.add(loanTransaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (LoanTransaction loanTransaction : transactionstoBeProcessed) {
|
||||||
|
|
||||||
if (loanTransaction.isRepayment() || loanTransaction.isInterestWaiver()) {
|
if (loanTransaction.isRepayment() || loanTransaction.isInterestWaiver()) {
|
||||||
// pass through for new transactions
|
// pass through for new transactions
|
||||||
|
|||||||
+9
-1
@@ -97,7 +97,15 @@ public class CreocoreLoanRepaymentScheduleTransactionProcessor extends AbstractL
|
|||||||
} else if (loanTransaction.isInterestWaiver()) {
|
} else if (loanTransaction.isInterestWaiver()) {
|
||||||
interestPortion = currentInstallment.waiveInterestComponent(transactionDate, transactionAmountRemaining);
|
interestPortion = currentInstallment.waiveInterestComponent(transactionDate, transactionAmountRemaining);
|
||||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||||
} else {
|
} else if(loanTransaction.isChargePayment()){
|
||||||
|
if(loanTransaction.isPenaltyPayment()){
|
||||||
|
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||||
|
}else{
|
||||||
|
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
|
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||||
|
|
||||||
|
|||||||
+18
-2
@@ -81,7 +81,15 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
|
|||||||
if (loanTransaction.isInterestWaiver()) {
|
if (loanTransaction.isInterestWaiver()) {
|
||||||
interestPortion = currentInstallment.waiveInterestComponent(transactionDate, transactionAmountRemaining);
|
interestPortion = currentInstallment.waiveInterestComponent(transactionDate, transactionAmountRemaining);
|
||||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||||
} else {
|
} else if(loanTransaction.isChargePayment()){
|
||||||
|
if(loanTransaction.isPenaltyPayment()){
|
||||||
|
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||||
|
}else{
|
||||||
|
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
|
||||||
if (currentInstallment.isPrincipalNotCompleted(currency)) {
|
if (currentInstallment.isPrincipalNotCompleted(currency)) {
|
||||||
principalPortion = currentInstallment.payPrincipalComponent(transactionDate, transactionAmountRemaining);
|
principalPortion = currentInstallment.payPrincipalComponent(transactionDate, transactionAmountRemaining);
|
||||||
@@ -141,7 +149,15 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
|
|||||||
} else if (loanTransaction.isInterestWaiver()) {
|
} else if (loanTransaction.isInterestWaiver()) {
|
||||||
interestPortion = currentInstallment.waiveInterestComponent(transactionDate, transactionAmountRemaining);
|
interestPortion = currentInstallment.waiveInterestComponent(transactionDate, transactionAmountRemaining);
|
||||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||||
} else {
|
} else if(loanTransaction.isChargePayment()){
|
||||||
|
if(loanTransaction.isPenaltyPayment()){
|
||||||
|
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||||
|
}else{
|
||||||
|
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
// 1. pay of principal before interest.
|
// 1. pay of principal before interest.
|
||||||
|
|
||||||
principalPortion = currentInstallment.payPrincipalComponent(transactionDate, transactionAmountRemaining);
|
principalPortion = currentInstallment.payPrincipalComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
|||||||
+10
-1
@@ -71,7 +71,16 @@ public class InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionPr
|
|||||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||||
|
|
||||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||||
} else {
|
} else if(loanTransaction.isChargePayment()){
|
||||||
|
if(loanTransaction.isPenaltyPayment()){
|
||||||
|
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||||
|
}else{
|
||||||
|
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||||
|
}
|
||||||
|
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||||
|
}else {
|
||||||
interestPortion = currentInstallment.payInterestComponent(transactionDate, transactionAmountRemaining);
|
interestPortion = currentInstallment.payInterestComponent(transactionDate, transactionAmountRemaining);
|
||||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||||
|
|
||||||
|
|||||||
+9
@@ -84,6 +84,15 @@ public class MifosStyleLoanRepaymentScheduleTransactionProcessor extends Abstrac
|
|||||||
interestPortion = currentInstallment.waiveInterestComponent(transactionDate, transactionAmountRemaining);
|
interestPortion = currentInstallment.waiveInterestComponent(transactionDate, transactionAmountRemaining);
|
||||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||||
|
|
||||||
|
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||||
|
} else if(loanTransaction.isChargePayment()){
|
||||||
|
if(loanTransaction.isPenaltyPayment()){
|
||||||
|
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||||
|
}else{
|
||||||
|
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||||
|
}
|
||||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||||
} else {
|
} else {
|
||||||
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
|
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
|||||||
+10
-1
@@ -71,7 +71,16 @@ public class PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionPr
|
|||||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||||
|
|
||||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||||
} else {
|
} else if(loanTransaction.isChargePayment()){
|
||||||
|
if(loanTransaction.isPenaltyPayment()){
|
||||||
|
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||||
|
}else{
|
||||||
|
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||||
|
}
|
||||||
|
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||||
|
}else {
|
||||||
principalPortion = currentInstallment.payPrincipalComponent(transactionDate, transactionAmountRemaining);
|
principalPortion = currentInstallment.payPrincipalComponent(transactionDate, transactionAmountRemaining);
|
||||||
transactionAmountRemaining = transactionAmountRemaining.minus(principalPortion);
|
transactionAmountRemaining = transactionAmountRemaining.minus(principalPortion);
|
||||||
|
|
||||||
|
|||||||
+21
-2
@@ -80,7 +80,18 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
|
|||||||
|
|
||||||
final Money principalPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
final Money principalPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
||||||
loanTransaction.updateComponents(principalPortion, interestWaivedPortion, feeChargesPortion, penaltyChargesPortion);
|
loanTransaction.updateComponents(principalPortion, interestWaivedPortion, feeChargesPortion, penaltyChargesPortion);
|
||||||
} else {
|
} else if(loanTransaction.isChargePayment()){
|
||||||
|
Money principalPortion = Money.zero(currency);
|
||||||
|
Money interestPortion = Money.zero(currency);
|
||||||
|
if(loanTransaction.isPenaltyPayment()){
|
||||||
|
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||||
|
}else{
|
||||||
|
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||||
|
}
|
||||||
|
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||||
|
}else {
|
||||||
|
|
||||||
LoanRepaymentScheduleInstallment currentInstallmentBasedOnTransactionDate = nearestInstallment(
|
LoanRepaymentScheduleInstallment currentInstallmentBasedOnTransactionDate = nearestInstallment(
|
||||||
loanTransaction.getTransactionDate(), installments);
|
loanTransaction.getTransactionDate(), installments);
|
||||||
@@ -161,7 +172,15 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
|
|||||||
} else if (loanTransaction.isInterestWaiver()) {
|
} else if (loanTransaction.isInterestWaiver()) {
|
||||||
interestPortion = currentInstallment.waiveInterestComponent(transactionDate, transactionAmountRemaining);
|
interestPortion = currentInstallment.waiveInterestComponent(transactionDate, transactionAmountRemaining);
|
||||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||||
} else {
|
} else if(loanTransaction.isChargePayment()){
|
||||||
|
if(loanTransaction.isPenaltyPayment()){
|
||||||
|
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||||
|
}else{
|
||||||
|
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
|
||||||
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
|
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||||
|
|||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package org.mifosplatform.portfolio.loanaccount.handler;
|
||||||
|
|
||||||
|
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
|
||||||
|
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.service.LoanWritePlatformService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class PayLoanChargeCommandHandler implements NewCommandSourceHandler {
|
||||||
|
|
||||||
|
private final LoanWritePlatformService writePlatformService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public PayLoanChargeCommandHandler(final LoanWritePlatformService writePlatformService) {
|
||||||
|
this.writePlatformService = writePlatformService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||||
|
return this.writePlatformService.payLoanCharge(command.getLoanId(), command.entityId(), command, command.entityId() == null);
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -42,7 +42,7 @@ public final class CalculateLoanScheduleQueryFromApiJsonHelper {
|
|||||||
"loanTermFrequencyType", "repaymentFrequencyType", "interestRateFrequencyType", "amortizationType", "interestType",
|
"loanTermFrequencyType", "repaymentFrequencyType", "interestRateFrequencyType", "amortizationType", "interestType",
|
||||||
"interestCalculationPeriodType", "expectedDisbursementDate", "repaymentsStartingFromDate", "graceOnPrincipalPayment",
|
"interestCalculationPeriodType", "expectedDisbursementDate", "repaymentsStartingFromDate", "graceOnPrincipalPayment",
|
||||||
"graceOnInterestPayment", "graceOnInterestCharged", "interestChargedFromDate", "submittedOnDate", "submittedOnNote", "locale",
|
"graceOnInterestPayment", "graceOnInterestCharged", "interestChargedFromDate", "submittedOnDate", "submittedOnNote", "locale",
|
||||||
"dateFormat", "charges", "collateral", "syncDisbursementWithMeeting"));
|
"dateFormat", "charges", "collateral", "syncDisbursementWithMeeting","linkAccountId"));
|
||||||
|
|
||||||
private final FromJsonHelper fromApiJsonHelper;
|
private final FromJsonHelper fromApiJsonHelper;
|
||||||
|
|
||||||
|
|||||||
+40
-1
@@ -23,7 +23,9 @@ import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
|||||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||||
import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
|
import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
||||||
|
import org.mifosplatform.portfolio.savings.domain.SavingsAccount;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@@ -48,7 +50,8 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
|||||||
"loanPurposeId", "inArrearsTolerance", "charges", "collateral", // optional
|
"loanPurposeId", "inArrearsTolerance", "charges", "collateral", // optional
|
||||||
"transactionProcessingStrategyId", // settings
|
"transactionProcessingStrategyId", // settings
|
||||||
"calendarId", // optional
|
"calendarId", // optional
|
||||||
"syncDisbursementWithMeeting"//optional
|
"syncDisbursementWithMeeting",//optional
|
||||||
|
"linkAccountId"
|
||||||
));
|
));
|
||||||
|
|
||||||
private final FromJsonHelper fromApiJsonHelper;
|
private final FromJsonHelper fromApiJsonHelper;
|
||||||
@@ -233,6 +236,14 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
|||||||
element);
|
element);
|
||||||
baseDataValidator.reset().parameter(transactionProcessingStrategyIdParameterName).value(transactionProcessingStrategyId).notNull()
|
baseDataValidator.reset().parameter(transactionProcessingStrategyIdParameterName).value(transactionProcessingStrategyId).notNull()
|
||||||
.integerGreaterThanZero();
|
.integerGreaterThanZero();
|
||||||
|
|
||||||
|
final String linkAccountIdParameterName = "linkAccountId";
|
||||||
|
if (fromApiJsonHelper.parameterExists(submittedOnNoteParameterName, element)) {
|
||||||
|
final Long linkAccountId = fromApiJsonHelper.extractLongNamed(linkAccountIdParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(linkAccountIdParameterName).value(linkAccountId).ignoreIfNull()
|
||||||
|
.longGreaterThanZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// charges
|
// charges
|
||||||
final String chargesParameterName = "charges";
|
final String chargesParameterName = "charges";
|
||||||
@@ -533,6 +544,14 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
|||||||
baseDataValidator.reset().parameter(submittedOnNoteParameterName).value(submittedOnNote).ignoreIfNull()
|
baseDataValidator.reset().parameter(submittedOnNoteParameterName).value(submittedOnNote).ignoreIfNull()
|
||||||
.notExceedingLengthOf(500);
|
.notExceedingLengthOf(500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final String linkAccountIdParameterName = "linkAccountId";
|
||||||
|
if (fromApiJsonHelper.parameterExists(submittedOnNoteParameterName, element)) {
|
||||||
|
atLeastOneParameterPassedForUpdate = true;
|
||||||
|
final Long linkAccountId = fromApiJsonHelper.extractLongNamed(linkAccountIdParameterName, element);
|
||||||
|
baseDataValidator.reset().parameter(linkAccountIdParameterName).value(linkAccountId).ignoreIfNull()
|
||||||
|
.longGreaterThanZero();
|
||||||
|
}
|
||||||
|
|
||||||
// charges
|
// charges
|
||||||
final String chargesParameterName = "charges";
|
final String chargesParameterName = "charges";
|
||||||
@@ -677,5 +696,25 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
|||||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
||||||
"Validation errors exist.", dataValidationErrors); }
|
"Validation errors exist.", dataValidationErrors); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void validatelinkedSavingsAccount(final SavingsAccount savingsAccount,final Loan loanApplication) {
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
if(savingsAccount.isNotActive()){
|
||||||
|
ApiParameterError error = ApiParameterError.parameterError(
|
||||||
|
"validation.msg.loan.linked.savings.account.is.not.active",
|
||||||
|
"Linked Savings account with id:"+savingsAccount.getId()+ " is not in active state", "linkAccountId",
|
||||||
|
savingsAccount.getId());
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
}else if(loanApplication.getClientId() != savingsAccount.clientId()){
|
||||||
|
ApiParameterError error = ApiParameterError.parameterError(
|
||||||
|
"validation.msg.loan.linked.savings.account.not.belongs.to.same.client",
|
||||||
|
"Linked Savings account with id:"+savingsAccount.getId()+ " is not belongs to the same client", "linkAccountId",
|
||||||
|
savingsAccount.getId());
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
}
|
||||||
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
||||||
|
"Validation errors exist.", dataValidationErrors); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+47
-19
@@ -50,8 +50,8 @@ public final class LoanEventApiJsonValidator {
|
|||||||
|
|
||||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||||
|
|
||||||
final Set<String> disbursementParameters = new HashSet<String>(Arrays.asList("actualDisbursementDate", "externalId", "note", "locale",
|
final Set<String> disbursementParameters = new HashSet<String>(Arrays.asList("actualDisbursementDate", "externalId", "note",
|
||||||
"dateFormat", "paymentTypeId", "accountNumber", "checkNumber", "routingCode", "receiptNumber", "bankNumber"));
|
"locale", "dateFormat", "paymentTypeId", "accountNumber", "checkNumber", "routingCode", "receiptNumber", "bankNumber"));
|
||||||
|
|
||||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||||
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, disbursementParameters);
|
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, disbursementParameters);
|
||||||
@@ -70,7 +70,7 @@ public final class LoanEventApiJsonValidator {
|
|||||||
|
|
||||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateDisbursementDateWithMeetingDate(final LocalDate actualDisbursementDate, final CalendarInstance calendarInstance) {
|
public void validateDisbursementDateWithMeetingDate(final LocalDate actualDisbursementDate, final CalendarInstance calendarInstance) {
|
||||||
if (null != calendarInstance) {
|
if (null != calendarInstance) {
|
||||||
Calendar calendar = calendarInstance.getCalendar();
|
Calendar calendar = calendarInstance.getCalendar();
|
||||||
@@ -79,21 +79,21 @@ public final class LoanEventApiJsonValidator {
|
|||||||
if (!CalendarUtils.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), actualDisbursementDate)) {
|
if (!CalendarUtils.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), actualDisbursementDate)) {
|
||||||
final String errorMessage = "Expected disbursement date '" + actualDisbursementDate.toString()
|
final String errorMessage = "Expected disbursement date '" + actualDisbursementDate.toString()
|
||||||
+ "' does not fall on a meeting date.";
|
+ "' does not fall on a meeting date.";
|
||||||
throw new NotValidRecurringDateException("loan.actual.disbursement.date", errorMessage, actualDisbursementDate.toString(),
|
throw new NotValidRecurringDateException("loan.actual.disbursement.date", errorMessage,
|
||||||
calendar.getTitle());
|
actualDisbursementDate.toString(), calendar.getTitle());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void validateTransaction(final String json) {
|
public void validateTransaction(final String json) {
|
||||||
|
|
||||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||||
|
|
||||||
final Set<String> transactionParameters = new HashSet<String>(Arrays.asList("transactionDate", "transactionAmount", "externalId", "note",
|
final Set<String> transactionParameters = new HashSet<String>(Arrays.asList("transactionDate", "transactionAmount", "externalId",
|
||||||
"locale", "dateFormat", "paymentTypeId", "accountNumber", "checkNumber", "routingCode", "receiptNumber", "bankNumber"));
|
"note", "locale", "dateFormat", "paymentTypeId", "accountNumber", "checkNumber", "routingCode", "receiptNumber",
|
||||||
|
"bankNumber"));
|
||||||
|
|
||||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||||
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, transactionParameters);
|
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, transactionParameters);
|
||||||
@@ -119,8 +119,9 @@ public final class LoanEventApiJsonValidator {
|
|||||||
|
|
||||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||||
|
|
||||||
final Set<String> transactionParameters = new HashSet<String>(Arrays.asList("transactionDate", "transactionAmount", "externalId", "note",
|
final Set<String> transactionParameters = new HashSet<String>(Arrays.asList("transactionDate", "transactionAmount", "externalId",
|
||||||
"locale", "dateFormat", "paymentTypeId", "accountNumber", "checkNumber", "routingCode", "receiptNumber", "bankNumber"));
|
"note", "locale", "dateFormat", "paymentTypeId", "accountNumber", "checkNumber", "routingCode", "receiptNumber",
|
||||||
|
"bankNumber"));
|
||||||
|
|
||||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||||
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, transactionParameters);
|
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, transactionParameters);
|
||||||
@@ -148,8 +149,7 @@ public final class LoanEventApiJsonValidator {
|
|||||||
if (calendar != null && repaymentDate != null) {
|
if (calendar != null && repaymentDate != null) {
|
||||||
// Disbursement date should fall on a meeting date
|
// Disbursement date should fall on a meeting date
|
||||||
if (!CalendarUtils.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), repaymentDate)) {
|
if (!CalendarUtils.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), repaymentDate)) {
|
||||||
final String errorMessage = "Transaction date '" + repaymentDate.toString()
|
final String errorMessage = "Transaction date '" + repaymentDate.toString() + "' does not fall on a meeting date.";
|
||||||
+ "' does not fall on a meeting date.";
|
|
||||||
throw new NotValidRecurringDateException("loan.transaction.date", errorMessage, repaymentDate.toString(),
|
throw new NotValidRecurringDateException("loan.transaction.date", errorMessage, repaymentDate.toString(),
|
||||||
calendar.getTitle());
|
calendar.getTitle());
|
||||||
}
|
}
|
||||||
@@ -157,7 +157,7 @@ public final class LoanEventApiJsonValidator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validatePaymentDetails(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
|
private void validatePaymentDetails(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
|
||||||
// Validate all string payment detail fields for max length
|
// Validate all string payment detail fields for max length
|
||||||
final Integer paymentTypeId = fromApiJsonHelper.extractIntegerWithLocaleNamed("paymentTypeId", element);
|
final Integer paymentTypeId = fromApiJsonHelper.extractIntegerWithLocaleNamed("paymentTypeId", element);
|
||||||
@@ -260,20 +260,20 @@ public final class LoanEventApiJsonValidator {
|
|||||||
|
|
||||||
final String assignmentDateStr = this.fromApiJsonHelper.extractStringNamed("assignmentDate", element);
|
final String assignmentDateStr = this.fromApiJsonHelper.extractStringNamed("assignmentDate", element);
|
||||||
baseDataValidator.reset().parameter("assignmentDate").value(assignmentDateStr).notBlank();
|
baseDataValidator.reset().parameter("assignmentDate").value(assignmentDateStr).notBlank();
|
||||||
|
|
||||||
if(!StringUtils.isBlank(assignmentDateStr)){
|
if (!StringUtils.isBlank(assignmentDateStr)) {
|
||||||
final LocalDate assignmentDate = this.fromApiJsonHelper.extractLocalDateNamed("assignmentDate", element);
|
final LocalDate assignmentDate = this.fromApiJsonHelper.extractLocalDateNamed("assignmentDate", element);
|
||||||
baseDataValidator.reset().parameter("assignmentDate").value(assignmentDate).notNull();
|
baseDataValidator.reset().parameter("assignmentDate").value(assignmentDate).notNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateForBulkLoanReassignment(final String json) {
|
public void validateForBulkLoanReassignment(final String json) {
|
||||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||||
|
|
||||||
final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("assignmentDate", "fromLoanOfficerId",
|
final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("assignmentDate", "fromLoanOfficerId", "toLoanOfficerId",
|
||||||
"toLoanOfficerId", "loans", "locale", "dateFormat"));
|
"loans", "locale", "dateFormat"));
|
||||||
|
|
||||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
|
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
|
||||||
@@ -294,4 +294,32 @@ public final class LoanEventApiJsonValidator {
|
|||||||
|
|
||||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void validateChargePaymentTransaction(final String json,boolean isChargeIdIncluded) {
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||||
|
Set<String> transactionParameters = null;
|
||||||
|
if(isChargeIdIncluded){
|
||||||
|
transactionParameters = new HashSet<String>(Arrays.asList("transactionDate", "locale", "dateFormat","chargeId"));
|
||||||
|
}else{
|
||||||
|
transactionParameters = new HashSet<String>(Arrays.asList("transactionDate", "locale", "dateFormat"));
|
||||||
|
}
|
||||||
|
|
||||||
|
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||||
|
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, transactionParameters);
|
||||||
|
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||||
|
.resource("loan.charge.payment.transaction");
|
||||||
|
|
||||||
|
final JsonElement element = fromApiJsonHelper.parse(json);
|
||||||
|
final LocalDate transactionDate = fromApiJsonHelper.extractLocalDateNamed("transactionDate", element);
|
||||||
|
if(isChargeIdIncluded){
|
||||||
|
final Long chargeId = fromApiJsonHelper.extractLongNamed("chargeId", element);
|
||||||
|
baseDataValidator.reset().parameter("chargeId").value(chargeId).notNull().integerGreaterThanZero();
|
||||||
|
}
|
||||||
|
baseDataValidator.reset().parameter("transactionDate").value(transactionDate).notNull();
|
||||||
|
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+132
-65
@@ -25,12 +25,15 @@ import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityExce
|
|||||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||||
import org.mifosplatform.organisation.staff.domain.Staff;
|
import org.mifosplatform.organisation.staff.domain.Staff;
|
||||||
|
import org.mifosplatform.portfolio.account.domain.AccountAssociations;
|
||||||
|
import org.mifosplatform.portfolio.account.domain.AccountAssociationsRepository;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarRepository;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarRepository;
|
||||||
import org.mifosplatform.portfolio.calendar.exception.CalendarNotFoundException;
|
import org.mifosplatform.portfolio.calendar.exception.CalendarNotFoundException;
|
||||||
|
import org.mifosplatform.portfolio.charge.domain.ChargePaymentMode;
|
||||||
import org.mifosplatform.portfolio.client.domain.AccountNumberGenerator;
|
import org.mifosplatform.portfolio.client.domain.AccountNumberGenerator;
|
||||||
import org.mifosplatform.portfolio.client.domain.AccountNumberGeneratorFactory;
|
import org.mifosplatform.portfolio.client.domain.AccountNumberGeneratorFactory;
|
||||||
import org.mifosplatform.portfolio.client.domain.Client;
|
import org.mifosplatform.portfolio.client.domain.Client;
|
||||||
@@ -63,10 +66,13 @@ import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
|||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
|
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
|
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
|
||||||
|
import org.mifosplatform.portfolio.loanproduct.exception.LinkedAccountRequiredException;
|
||||||
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
||||||
import org.mifosplatform.portfolio.loanproduct.serialization.LoanProductDataValidator;
|
import org.mifosplatform.portfolio.loanproduct.serialization.LoanProductDataValidator;
|
||||||
import org.mifosplatform.portfolio.note.domain.Note;
|
import org.mifosplatform.portfolio.note.domain.Note;
|
||||||
import org.mifosplatform.portfolio.note.domain.NoteRepository;
|
import org.mifosplatform.portfolio.note.domain.NoteRepository;
|
||||||
|
import org.mifosplatform.portfolio.savings.domain.SavingsAccount;
|
||||||
|
import org.mifosplatform.portfolio.savings.domain.SavingsAccountAssembler;
|
||||||
import org.mifosplatform.useradministration.domain.AppUser;
|
import org.mifosplatform.useradministration.domain.AppUser;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -102,6 +108,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
|
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
|
||||||
private final CalendarRepository calendarRepository;
|
private final CalendarRepository calendarRepository;
|
||||||
private final CalendarInstanceRepository calendarInstanceRepository;
|
private final CalendarInstanceRepository calendarInstanceRepository;
|
||||||
|
private final SavingsAccountAssembler savingsAccountAssembler;
|
||||||
|
private final AccountAssociationsRepository accountAssociationsRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper,
|
public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper,
|
||||||
@@ -114,7 +122,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
final LoanProductRepository loanProductRepository, final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory,
|
final LoanProductRepository loanProductRepository, final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory,
|
||||||
final LoanSummaryWrapper loanSummaryWrapper, final GroupRepositoryWrapper groupRepository,
|
final LoanSummaryWrapper loanSummaryWrapper, final GroupRepositoryWrapper groupRepository,
|
||||||
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
|
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
|
||||||
final CalendarRepository calendarRepository, final CalendarInstanceRepository calendarInstanceRepository) {
|
final CalendarRepository calendarRepository, final CalendarInstanceRepository calendarInstanceRepository,
|
||||||
|
final SavingsAccountAssembler savingsAccountAssembler, final AccountAssociationsRepository accountAssociationsRepository) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.fromJsonHelper = fromJsonHelper;
|
this.fromJsonHelper = fromJsonHelper;
|
||||||
this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator;
|
this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator;
|
||||||
@@ -135,6 +144,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
|
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
|
||||||
this.calendarRepository = calendarRepository;
|
this.calendarRepository = calendarRepository;
|
||||||
this.calendarInstanceRepository = calendarInstanceRepository;
|
this.calendarInstanceRepository = calendarInstanceRepository;
|
||||||
|
this.savingsAccountAssembler = savingsAccountAssembler;
|
||||||
|
this.accountAssociationsRepository = accountAssociationsRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
||||||
@@ -147,73 +158,81 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
public CommandProcessingResult submitApplication(final JsonCommand command) {
|
public CommandProcessingResult submitApplication(final JsonCommand command) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final AppUser currentUser = context.authenticatedUser();
|
final AppUser currentUser = context.authenticatedUser();
|
||||||
|
|
||||||
this.fromApiJsonDeserializer.validateForCreate(command.json());
|
this.fromApiJsonDeserializer.validateForCreate(command.json());
|
||||||
|
|
||||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
|
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
|
||||||
|
|
||||||
final Long productId = fromJsonHelper.extractLongNamed("productId", command.parsedJson());
|
final Long productId = fromJsonHelper.extractLongNamed("productId", command.parsedJson());
|
||||||
final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
|
final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
|
||||||
if (loanProduct == null) { throw new LoanProductNotFoundException(productId); }
|
if (loanProduct == null) { throw new LoanProductNotFoundException(productId); }
|
||||||
|
|
||||||
this.loanProductCommandFromApiJsonDeserializer.validateMinMaxConstraints(command.parsedJson(), baseDataValidator, loanProduct);
|
|
||||||
|
|
||||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
|
||||||
|
|
||||||
final Loan newLoanApplication = loanAssembler.assembleFrom(command, currentUser);
|
this.loanProductCommandFromApiJsonDeserializer.validateMinMaxConstraints(command.parsedJson(), baseDataValidator, loanProduct);
|
||||||
|
|
||||||
validateSubmittedOnDate(newLoanApplication);
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
|
|
||||||
final LoanProductRelatedDetail productRelatedDetail = newLoanApplication.repaymentScheduleDetail();
|
final Loan newLoanApplication = loanAssembler.assembleFrom(command, currentUser);
|
||||||
this.fromApiJsonDeserializer.validateLoanTermAndRepaidEveryValues(newLoanApplication.getTermFrequency(), newLoanApplication.getTermPeriodFrequencyType(),
|
|
||||||
productRelatedDetail.getNumberOfRepayments(), productRelatedDetail.getRepayEvery(),
|
validateSubmittedOnDate(newLoanApplication);
|
||||||
productRelatedDetail.getRepaymentPeriodFrequencyType().getValue());
|
|
||||||
|
final LoanProductRelatedDetail productRelatedDetail = newLoanApplication.repaymentScheduleDetail();
|
||||||
this.loanRepository.save(newLoanApplication);
|
this.fromApiJsonDeserializer.validateLoanTermAndRepaidEveryValues(newLoanApplication.getTermFrequency(),
|
||||||
|
newLoanApplication.getTermPeriodFrequencyType(), productRelatedDetail.getNumberOfRepayments(),
|
||||||
|
productRelatedDetail.getRepayEvery(), productRelatedDetail.getRepaymentPeriodFrequencyType().getValue());
|
||||||
|
|
||||||
if (newLoanApplication.isAccountNumberRequiresAutoGeneration()) {
|
|
||||||
final AccountNumberGenerator accountNoGenerator = this.accountIdentifierGeneratorFactory
|
|
||||||
.determineLoanAccountNoGenerator(newLoanApplication.getId());
|
|
||||||
newLoanApplication.updateAccountNo(accountNoGenerator.generate());
|
|
||||||
this.loanRepository.save(newLoanApplication);
|
this.loanRepository.save(newLoanApplication);
|
||||||
}
|
|
||||||
|
|
||||||
final String submittedOnNote = command.stringValueOfParameterNamed("submittedOnNote");
|
if (newLoanApplication.isAccountNumberRequiresAutoGeneration()) {
|
||||||
if (StringUtils.isNotBlank(submittedOnNote)) {
|
final AccountNumberGenerator accountNoGenerator = this.accountIdentifierGeneratorFactory
|
||||||
Note note = Note.loanNote(newLoanApplication, submittedOnNote);
|
.determineLoanAccountNoGenerator(newLoanApplication.getId());
|
||||||
this.noteRepository.save(note);
|
newLoanApplication.updateAccountNo(accountNoGenerator.generate());
|
||||||
}
|
this.loanRepository.save(newLoanApplication);
|
||||||
|
}
|
||||||
|
|
||||||
// Save calendar instance
|
final String submittedOnNote = command.stringValueOfParameterNamed("submittedOnNote");
|
||||||
final Long calendarId = command.longValueOfParameterNamed("calendarId");
|
if (StringUtils.isNotBlank(submittedOnNote)) {
|
||||||
Calendar calendar = null;
|
Note note = Note.loanNote(newLoanApplication, submittedOnNote);
|
||||||
|
this.noteRepository.save(note);
|
||||||
if (calendarId != null && calendarId != 0) {
|
}
|
||||||
calendar = this.calendarRepository.findOne(calendarId);
|
|
||||||
if (calendar == null) { throw new CalendarNotFoundException(calendarId); }
|
// Save calendar instance
|
||||||
|
final Long calendarId = command.longValueOfParameterNamed("calendarId");
|
||||||
CalendarInstance calendarInstance = new CalendarInstance(calendar, newLoanApplication.getId(),
|
Calendar calendar = null;
|
||||||
CalendarEntityType.LOANS.getValue());
|
|
||||||
this.calendarInstanceRepository.save(calendarInstance);
|
if (calendarId != null && calendarId != 0) {
|
||||||
}
|
calendar = this.calendarRepository.findOne(calendarId);
|
||||||
|
if (calendar == null) { throw new CalendarNotFoundException(calendarId); }
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder() //
|
CalendarInstance calendarInstance = new CalendarInstance(calendar, newLoanApplication.getId(),
|
||||||
.withCommandId(command.commandId()) //
|
CalendarEntityType.LOANS.getValue());
|
||||||
.withEntityId(newLoanApplication.getId()) //
|
this.calendarInstanceRepository.save(calendarInstance);
|
||||||
.withOfficeId(newLoanApplication.getOfficeId()) //
|
}
|
||||||
.withClientId(newLoanApplication.getClientId()) //
|
|
||||||
.withGroupId(newLoanApplication.getGroupId()) //
|
// Save linked account information
|
||||||
.withLoanId(newLoanApplication.getId()) //
|
final Long savingsAccountId = command.longValueOfParameterNamed("linkAccountId");
|
||||||
.build();
|
if (savingsAccountId != null) {
|
||||||
|
SavingsAccount savingsAccount = this.savingsAccountAssembler.assembleFrom(savingsAccountId);
|
||||||
|
this.fromApiJsonDeserializer.validatelinkedSavingsAccount(savingsAccount, newLoanApplication);
|
||||||
|
AccountAssociations accountAssociations = AccountAssociations.associateSavingsAccount(newLoanApplication, savingsAccount);
|
||||||
|
this.accountAssociationsRepository.save(accountAssociations);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CommandProcessingResultBuilder() //
|
||||||
|
.withCommandId(command.commandId()) //
|
||||||
|
.withEntityId(newLoanApplication.getId()) //
|
||||||
|
.withOfficeId(newLoanApplication.getOfficeId()) //
|
||||||
|
.withClientId(newLoanApplication.getClientId()) //
|
||||||
|
.withGroupId(newLoanApplication.getGroupId()) //
|
||||||
|
.withLoanId(newLoanApplication.getId()) //
|
||||||
|
.build();
|
||||||
} catch (DataIntegrityViolationException dve) {
|
} catch (DataIntegrityViolationException dve) {
|
||||||
handleDataIntegrityIssues(command, dve);
|
handleDataIntegrityIssues(command, dve);
|
||||||
return CommandProcessingResult.empty();
|
return CommandProcessingResult.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult modifyApplication(final Long loanId, final JsonCommand command) {
|
public CommandProcessingResult modifyApplication(final Long loanId, final JsonCommand command) {
|
||||||
@@ -225,7 +244,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
|
|
||||||
final Loan existingLoanApplication = retrieveLoanBy(loanId);
|
final Loan existingLoanApplication = retrieveLoanBy(loanId);
|
||||||
checkClientOrGroupActive(existingLoanApplication);
|
checkClientOrGroupActive(existingLoanApplication);
|
||||||
|
|
||||||
if (!existingLoanApplication.isSubmittedAndPendingApproval()) { throw new LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified(
|
if (!existingLoanApplication.isSubmittedAndPendingApproval()) { throw new LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified(
|
||||||
loanId); }
|
loanId); }
|
||||||
|
|
||||||
@@ -269,12 +288,12 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
existingLoanApplication.updateInterestRateFrequencyType();
|
existingLoanApplication.updateInterestRateFrequencyType();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
validateSubmittedOnDate(existingLoanApplication);
|
validateSubmittedOnDate(existingLoanApplication);
|
||||||
final LoanProductRelatedDetail productRelatedDetail = existingLoanApplication.repaymentScheduleDetail();
|
final LoanProductRelatedDetail productRelatedDetail = existingLoanApplication.repaymentScheduleDetail();
|
||||||
this.fromApiJsonDeserializer.validateLoanTermAndRepaidEveryValues(existingLoanApplication.getTermFrequency(), existingLoanApplication.getTermPeriodFrequencyType(),
|
this.fromApiJsonDeserializer.validateLoanTermAndRepaidEveryValues(existingLoanApplication.getTermFrequency(),
|
||||||
productRelatedDetail.getNumberOfRepayments(), productRelatedDetail.getRepayEvery(),
|
existingLoanApplication.getTermPeriodFrequencyType(), productRelatedDetail.getNumberOfRepayments(),
|
||||||
productRelatedDetail.getRepaymentPeriodFrequencyType().getValue());
|
productRelatedDetail.getRepayEvery(), productRelatedDetail.getRepaymentPeriodFrequencyType().getValue());
|
||||||
|
|
||||||
final String fundIdParamName = "fundId";
|
final String fundIdParamName = "fundId";
|
||||||
if (changes.containsKey(fundIdParamName)) {
|
if (changes.containsKey(fundIdParamName)) {
|
||||||
@@ -342,7 +361,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
calendar = this.calendarRepository.findOne(calendarId);
|
calendar = this.calendarRepository.findOne(calendarId);
|
||||||
if (calendar == null) { throw new CalendarNotFoundException(calendarId); }
|
if (calendar == null) { throw new CalendarNotFoundException(calendarId); }
|
||||||
}
|
}
|
||||||
|
|
||||||
List<CalendarInstance> ciList = (List<CalendarInstance>) this.calendarInstanceRepository.findByEntityIdAndEntityTypeId(loanId,
|
List<CalendarInstance> ciList = (List<CalendarInstance>) this.calendarInstanceRepository.findByEntityIdAndEntityTypeId(loanId,
|
||||||
CalendarEntityType.LOANS.getValue());
|
CalendarEntityType.LOANS.getValue());
|
||||||
if (calendar != null) {
|
if (calendar != null) {
|
||||||
@@ -367,6 +386,54 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
this.calendarInstanceRepository.delete(calendarInstance);
|
this.calendarInstanceRepository.delete(calendarInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save linked account information
|
||||||
|
final String linkAccountIdParamName = "linkAccountId";
|
||||||
|
final Long savingsAccountId = command.longValueOfParameterNamed(linkAccountIdParamName);
|
||||||
|
AccountAssociations accountAssociations = this.accountAssociationsRepository.findByLoanId(loanId);
|
||||||
|
boolean isLinkedAccPresent = false;
|
||||||
|
if (savingsAccountId == null) {
|
||||||
|
if (accountAssociations != null) {
|
||||||
|
if (this.fromJsonHelper.parameterExists(linkAccountIdParamName, command.parsedJson())) {
|
||||||
|
this.accountAssociationsRepository.delete(accountAssociations);
|
||||||
|
changes.put(linkAccountIdParamName, null);
|
||||||
|
} else {
|
||||||
|
isLinkedAccPresent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
isLinkedAccPresent = true;
|
||||||
|
boolean isModified = false;
|
||||||
|
if (accountAssociations == null) {
|
||||||
|
isModified = true;
|
||||||
|
} else {
|
||||||
|
SavingsAccount savingsAccount = accountAssociations.linkedSavingsAccount();
|
||||||
|
if (savingsAccount == null || savingsAccount.getId() != savingsAccountId) {
|
||||||
|
isModified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isModified) {
|
||||||
|
SavingsAccount savingsAccount = this.savingsAccountAssembler.assembleFrom(savingsAccountId);
|
||||||
|
this.fromApiJsonDeserializer.validatelinkedSavingsAccount(savingsAccount, existingLoanApplication);
|
||||||
|
if (accountAssociations == null) {
|
||||||
|
accountAssociations = AccountAssociations.associateSavingsAccount(existingLoanApplication, savingsAccount);
|
||||||
|
} else {
|
||||||
|
accountAssociations.updateLinkedSavingsAccount(savingsAccount);
|
||||||
|
}
|
||||||
|
changes.put(linkAccountIdParamName, savingsAccountId);
|
||||||
|
this.accountAssociationsRepository.save(accountAssociations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isLinkedAccPresent) {
|
||||||
|
final Set<LoanCharge> charges = existingLoanApplication.charges();
|
||||||
|
for (LoanCharge loanCharge : charges) {
|
||||||
|
if (loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
|
||||||
|
final String errorMessage = "one of the charges requires linked savings account for payment";
|
||||||
|
throw new LinkedAccountRequiredException("loanCharge", errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withEntityId(loanId) //
|
.withEntityId(loanId) //
|
||||||
.withOfficeId(existingLoanApplication.getOfficeId()) //
|
.withOfficeId(existingLoanApplication.getOfficeId()) //
|
||||||
@@ -401,8 +468,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
|
|
||||||
logAsErrorUnexpectedDataIntegrityException(dve);
|
logAsErrorUnexpectedDataIntegrityException(dve);
|
||||||
throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue", "Unknown data integrity issue with resource.");
|
throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue", "Unknown data integrity issue with resource.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logAsErrorUnexpectedDataIntegrityException(final DataIntegrityViolationException dve) {
|
private void logAsErrorUnexpectedDataIntegrityException(final DataIntegrityViolationException dve) {
|
||||||
logger.error(dve.getMessage(), dve);
|
logger.error(dve.getMessage(), dve);
|
||||||
}
|
}
|
||||||
@@ -572,7 +639,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
loan.setHelpers(defaultLoanLifecycleStateMachine(), this.loanSummaryWrapper, this.loanRepaymentScheduleTransactionProcessorFactory);
|
loan.setHelpers(defaultLoanLifecycleStateMachine(), this.loanSummaryWrapper, this.loanRepaymentScheduleTransactionProcessorFactory);
|
||||||
return loan;
|
return loan;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateSubmittedOnDate(final Loan loan) {
|
private void validateSubmittedOnDate(final Loan loan) {
|
||||||
final LocalDate startDate = loan.loanProduct().getStartDate();
|
final LocalDate startDate = loan.loanProduct().getStartDate();
|
||||||
final LocalDate closeDate = loan.loanProduct().getCloseDate();
|
final LocalDate closeDate = loan.loanProduct().getCloseDate();
|
||||||
@@ -584,7 +651,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
throw new LoanApplicationDateException("submitted.on.date.cannot.be.before.the.loan.product.start.date", defaultUserMessage,
|
throw new LoanApplicationDateException("submitted.on.date.cannot.be.before.the.loan.product.start.date", defaultUserMessage,
|
||||||
submittedOnDate.toString(), startDate.toString());
|
submittedOnDate.toString(), startDate.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (closeDate != null && submittedOnDate.isAfter(closeDate)) {
|
if (closeDate != null && submittedOnDate.isAfter(closeDate)) {
|
||||||
defaultUserMessage = "submittedOnDate cannot be after the loan product closeDate.";
|
defaultUserMessage = "submittedOnDate cannot be after the loan product closeDate.";
|
||||||
throw new LoanApplicationDateException("submitted.on.date.cannot.be.after.the.loan.product.close.date", defaultUserMessage,
|
throw new LoanApplicationDateException("submitted.on.date.cannot.be.after.the.loan.product.close.date", defaultUserMessage,
|
||||||
|
|||||||
+9
@@ -25,6 +25,7 @@ import org.mifosplatform.organisation.staff.exception.StaffRoleException;
|
|||||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
|
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
|
||||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
|
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
|
||||||
import org.mifosplatform.portfolio.accountdetails.service.AccountEnumerations;
|
import org.mifosplatform.portfolio.accountdetails.service.AccountEnumerations;
|
||||||
|
import org.mifosplatform.portfolio.charge.domain.ChargePaymentMode;
|
||||||
import org.mifosplatform.portfolio.client.domain.Client;
|
import org.mifosplatform.portfolio.client.domain.Client;
|
||||||
import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper;
|
import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper;
|
||||||
import org.mifosplatform.portfolio.client.exception.ClientNotActiveException;
|
import org.mifosplatform.portfolio.client.exception.ClientNotActiveException;
|
||||||
@@ -55,6 +56,7 @@ import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
|||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
|
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
|
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
|
||||||
|
import org.mifosplatform.portfolio.loanproduct.exception.LinkedAccountRequiredException;
|
||||||
import org.mifosplatform.portfolio.loanproduct.exception.InvalidCurrencyException;
|
import org.mifosplatform.portfolio.loanproduct.exception.InvalidCurrencyException;
|
||||||
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
||||||
import org.mifosplatform.useradministration.domain.AppUser;
|
import org.mifosplatform.useradministration.domain.AppUser;
|
||||||
@@ -158,6 +160,13 @@ public class LoanAssembler {
|
|||||||
final String errorMessage = "Charge and Loan must have the same currency.";
|
final String errorMessage = "Charge and Loan must have the same currency.";
|
||||||
throw new InvalidCurrencyException("loanCharge", "attach.to.loan", errorMessage);
|
throw new InvalidCurrencyException("loanCharge", "attach.to.loan", errorMessage);
|
||||||
}
|
}
|
||||||
|
if(loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()){
|
||||||
|
final Long savingsAccountId = this.fromApiJsonHelper.extractLongNamed("linkAccountId", element);
|
||||||
|
if(savingsAccountId == null){
|
||||||
|
final String errorMessage = "one of the charges requires linked savings account for payment";
|
||||||
|
throw new LinkedAccountRequiredException("loanCharge", errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Loan loanApplication = null;
|
Loan loanApplication = null;
|
||||||
|
|||||||
+9
-4
@@ -14,6 +14,7 @@ import org.joda.time.LocalDate;
|
|||||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||||
import org.mifosplatform.portfolio.charge.domain.Charge;
|
import org.mifosplatform.portfolio.charge.domain.Charge;
|
||||||
import org.mifosplatform.portfolio.charge.domain.ChargeCalculationType;
|
import org.mifosplatform.portfolio.charge.domain.ChargeCalculationType;
|
||||||
|
import org.mifosplatform.portfolio.charge.domain.ChargePaymentMode;
|
||||||
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
|
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||||
import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
|
import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
|
||||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeNotFoundException;
|
import org.mifosplatform.portfolio.charge.exception.LoanChargeNotFoundException;
|
||||||
@@ -65,19 +66,23 @@ public class LoanChargeAssembler {
|
|||||||
locale);
|
locale);
|
||||||
final LocalDate dueDate = fromApiJsonHelper.extractLocalDateNamed("dueDate", loanChargeElement,
|
final LocalDate dueDate = fromApiJsonHelper.extractLocalDateNamed("dueDate", loanChargeElement,
|
||||||
dateFormat, locale);
|
dateFormat, locale);
|
||||||
|
final Integer chargePaymentMode = fromApiJsonHelper.extractIntegerNamed("chargePaymentMode", loanChargeElement, locale);
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
final Charge chargeDefinition = this.chargeRepository.findOneWithNotFoundDetection(chargeId);
|
final Charge chargeDefinition = this.chargeRepository.findOneWithNotFoundDetection(chargeId);
|
||||||
ChargeTimeType chargeTime = null;
|
ChargeTimeType chargeTime = null;
|
||||||
if (chargeTimeType != null) {
|
if (chargeTimeType != null) {
|
||||||
ChargeTimeType.fromInt(chargeTimeType);
|
chargeTime = ChargeTimeType.fromInt(chargeTimeType);
|
||||||
}
|
}
|
||||||
ChargeCalculationType chargeCalculation = null;
|
ChargeCalculationType chargeCalculation = null;
|
||||||
if (chargeCalculationType != null) {
|
if (chargeCalculationType != null) {
|
||||||
ChargeCalculationType.fromInt(chargeCalculationType);
|
chargeCalculation = ChargeCalculationType.fromInt(chargeCalculationType);
|
||||||
|
}
|
||||||
|
ChargePaymentMode chargePaymentModeEnum = null;
|
||||||
|
if(chargePaymentMode != null){
|
||||||
|
chargePaymentModeEnum = ChargePaymentMode.fromInt(chargePaymentMode);
|
||||||
}
|
}
|
||||||
final LoanCharge loanCharge = LoanCharge.createNewWithoutLoan(chargeDefinition, principal, amount, chargeTime,
|
final LoanCharge loanCharge = LoanCharge.createNewWithoutLoan(chargeDefinition, principal, amount, chargeTime,
|
||||||
chargeCalculation, dueDate);
|
chargeCalculation, dueDate, chargePaymentModeEnum);
|
||||||
loanCharges.add(loanCharge);
|
loanCharges.add(loanCharge);
|
||||||
} else {
|
} else {
|
||||||
final Long loanChargeId = id;
|
final Long loanChargeId = id;
|
||||||
|
|||||||
+2
@@ -17,4 +17,6 @@ public interface LoanChargeReadPlatformService {
|
|||||||
Collection<LoanChargeData> retrieveLoanCharges(Long loanId);
|
Collection<LoanChargeData> retrieveLoanCharges(Long loanId);
|
||||||
|
|
||||||
LoanChargeData retrieveLoanChargeDetails(Long loanChargeId, Long loanId);
|
LoanChargeData retrieveLoanChargeDetails(Long loanChargeId, Long loanId);
|
||||||
|
|
||||||
|
Collection<LoanChargeData> retrieveLoanChargesForFeePayment(Integer paymentMode, Integer loanStatus);
|
||||||
}
|
}
|
||||||
|
|||||||
+39
-2
@@ -55,6 +55,9 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
|
|||||||
+ "lc.is_penalty as penalty, "
|
+ "lc.is_penalty as penalty, "
|
||||||
+ "lc.due_for_collection_as_of_date as dueAsOfDate, "
|
+ "lc.due_for_collection_as_of_date as dueAsOfDate, "
|
||||||
+ "lc.charge_calculation_enum as chargeCalculation, "
|
+ "lc.charge_calculation_enum as chargeCalculation, "
|
||||||
|
+ "lc.charge_payment_mode_enum as chargePaymentMode, "
|
||||||
|
+ "lc.is_paid_derived as paid, "
|
||||||
|
+ "lc.waived as waied, "
|
||||||
+ "c.currency_code as currencyCode, oc.name as currencyName, "
|
+ "c.currency_code as currencyCode, oc.name as currencyName, "
|
||||||
+ "oc.decimal_places as currencyDecimalPlaces, oc.currency_multiplesof as inMultiplesOf, oc.display_symbol as currencyDisplaySymbol, "
|
+ "oc.decimal_places as currencyDecimalPlaces, oc.currency_multiplesof as inMultiplesOf, oc.display_symbol as currencyDisplaySymbol, "
|
||||||
+ "oc.internationalized_name_code as currencyNameCode from m_charge c "
|
+ "oc.internationalized_name_code as currencyNameCode from m_charge c "
|
||||||
@@ -95,8 +98,14 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
|
|||||||
final EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(chargeCalculation);
|
final EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(chargeCalculation);
|
||||||
final boolean penalty = rs.getBoolean("penalty");
|
final boolean penalty = rs.getBoolean("penalty");
|
||||||
|
|
||||||
|
final int chargePaymentMode = rs.getInt("chargePaymentMode");
|
||||||
|
final EnumOptionData paymentMode = ChargeEnumerations.chargePaymentMode(chargePaymentMode);
|
||||||
|
final boolean paid = rs.getBoolean("paid");
|
||||||
|
final boolean waived = rs.getBoolean("waied");
|
||||||
|
|
||||||
return new LoanChargeData(id, chargeId, name, currency, amount, amountPaid, amountWaived, amountWrittenOff, amountOutstanding,
|
return new LoanChargeData(id, chargeId, name, currency, amount, amountPaid, amountWaived, amountWrittenOff, amountOutstanding,
|
||||||
chargeTimeType, dueAsOfDate, chargeCalculationType, percentageOf, amountPercentageAppliedTo, penalty);
|
chargeTimeType, dueAsOfDate, chargeCalculationType, percentageOf, amountPercentageAppliedTo, penalty, paymentMode,
|
||||||
|
paid, waived, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +116,7 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
|
|||||||
final List<EnumOptionData> allowedChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService.retrieveCalculationTypes();
|
final List<EnumOptionData> allowedChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService.retrieveCalculationTypes();
|
||||||
final List<EnumOptionData> allowedChargeTimeOptions = this.chargeDropdownReadPlatformService.retrieveCollectionTimeTypes();
|
final List<EnumOptionData> allowedChargeTimeOptions = this.chargeDropdownReadPlatformService.retrieveCollectionTimeTypes();
|
||||||
|
|
||||||
return ChargeData.template(null, allowedChargeCalculationTypeOptions, null, allowedChargeTimeOptions);
|
return ChargeData.template(null, allowedChargeCalculationTypeOptions, null, allowedChargeTimeOptions, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -132,4 +141,32 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
|
|||||||
|
|
||||||
return this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
|
return this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<LoanChargeData> retrieveLoanChargesForFeePayment(final Integer paymentMode, final Integer loanStatus) {
|
||||||
|
final LoanChargeMapperWithLoanId rm = new LoanChargeMapperWithLoanId();
|
||||||
|
final String sql = "select " + rm.schema()
|
||||||
|
+ "where loan.loan_status_id= ? and lc.charge_payment_mode_enum=? and lc.waived =0 and lc.is_paid_derived=0";
|
||||||
|
return this.jdbcTemplate.query(sql, rm, new Object[] { loanStatus, paymentMode });
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class LoanChargeMapperWithLoanId implements RowMapper<LoanChargeData> {
|
||||||
|
|
||||||
|
public String schema() {
|
||||||
|
return "lc.id as id, lc.due_for_collection_as_of_date as dueAsOfDate, "
|
||||||
|
+ "lc.amount_outstanding_derived as amountOutstanding, "
|
||||||
|
+ "loan.id as loanId " + "from m_loan_charge lc "
|
||||||
|
+ "join m_loan loan on loan.id = lc.loan_id ";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LoanChargeData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||||
|
|
||||||
|
final Long id = rs.getLong("id");
|
||||||
|
final LocalDate dueAsOfDate = JdbcSupport.getLocalDate(rs, "dueAsOfDate");
|
||||||
|
final Long loanId = rs.getLong("loanId");
|
||||||
|
final BigDecimal amountOutstanding = rs.getBigDecimal("amountOutstanding");
|
||||||
|
return new LoanChargeData(id, dueAsOfDate, amountOutstanding, loanId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
@@ -11,6 +11,7 @@ import java.util.Map;
|
|||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
import org.mifosplatform.infrastructure.jobs.exception.JobExecutionException;
|
||||||
import org.mifosplatform.organisation.office.domain.Office;
|
import org.mifosplatform.organisation.office.domain.Office;
|
||||||
import org.mifosplatform.organisation.staff.domain.Staff;
|
import org.mifosplatform.organisation.staff.domain.Staff;
|
||||||
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
||||||
@@ -67,4 +68,9 @@ public interface LoanWritePlatformService {
|
|||||||
|
|
||||||
LoanTransaction acceptLoanTransfer(Long accountId, LocalDate transferDate, Office acceptedInOffice, Staff loanOfficer);
|
LoanTransaction acceptLoanTransfer(Long accountId, LocalDate transferDate, Office acceptedInOffice, Staff loanOfficer);
|
||||||
|
|
||||||
|
CommandProcessingResult payLoanCharge(Long loanId, Long loanChargeId, JsonCommand command, boolean isChargeIdIncludedInJson);
|
||||||
|
|
||||||
|
void transferFeeCharges() throws JobExecutionException;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+127
-14
@@ -11,18 +11,23 @@ import java.util.Arrays;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
|
import org.joda.time.format.DateTimeFormat;
|
||||||
|
import org.joda.time.format.DateTimeFormatter;
|
||||||
import org.mifosplatform.accounting.journalentry.service.JournalEntryWritePlatformService;
|
import org.mifosplatform.accounting.journalentry.service.JournalEntryWritePlatformService;
|
||||||
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
|
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||||
import org.mifosplatform.infrastructure.core.exception.PlatformServiceUnavailableException;
|
import org.mifosplatform.infrastructure.core.exception.PlatformServiceUnavailableException;
|
||||||
import org.mifosplatform.infrastructure.jobs.annotation.CronTarget;
|
import org.mifosplatform.infrastructure.jobs.annotation.CronTarget;
|
||||||
|
import org.mifosplatform.infrastructure.jobs.exception.JobExecutionException;
|
||||||
import org.mifosplatform.infrastructure.jobs.service.JobName;
|
import org.mifosplatform.infrastructure.jobs.service.JobName;
|
||||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||||
import org.mifosplatform.organisation.holiday.domain.Holiday;
|
import org.mifosplatform.organisation.holiday.domain.Holiday;
|
||||||
@@ -36,6 +41,9 @@ import org.mifosplatform.organisation.staff.domain.Staff;
|
|||||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
|
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
|
||||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
|
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
|
||||||
import org.mifosplatform.portfolio.account.PortfolioAccountType;
|
import org.mifosplatform.portfolio.account.PortfolioAccountType;
|
||||||
|
import org.mifosplatform.portfolio.account.data.AccountTransferDTO;
|
||||||
|
import org.mifosplatform.portfolio.account.data.PortfolioAccountData;
|
||||||
|
import org.mifosplatform.portfolio.account.service.AccountAssociationsReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.account.service.AccountTransfersReadPlatformService;
|
import org.mifosplatform.portfolio.account.service.AccountTransfersReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.account.service.AccountTransfersWritePlatformService;
|
import org.mifosplatform.portfolio.account.service.AccountTransfersWritePlatformService;
|
||||||
import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
|
import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
|
||||||
@@ -45,9 +53,12 @@ import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
|||||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository;
|
import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository;
|
||||||
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
|
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
|
||||||
import org.mifosplatform.portfolio.charge.domain.Charge;
|
import org.mifosplatform.portfolio.charge.domain.Charge;
|
||||||
|
import org.mifosplatform.portfolio.charge.domain.ChargePaymentMode;
|
||||||
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
|
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeDeletedException;
|
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeDeletedException;
|
||||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeDeletedException.LOAN_CHARGE_CANNOT_BE_DELETED_REASON;
|
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeDeletedException.LOAN_CHARGE_CANNOT_BE_DELETED_REASON;
|
||||||
|
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBePayedException;
|
||||||
|
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBePayedException.LOAN_CHARGE_CANNOT_BE_PAYED_REASON;
|
||||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeUpdatedException;
|
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeUpdatedException;
|
||||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeUpdatedException.LOAN_CHARGE_CANNOT_BE_UPDATED_REASON;
|
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeUpdatedException.LOAN_CHARGE_CANNOT_BE_UPDATED_REASON;
|
||||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeWaivedException;
|
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeWaivedException;
|
||||||
@@ -62,6 +73,7 @@ import org.mifosplatform.portfolio.collectionsheet.command.SingleRepaymentComman
|
|||||||
import org.mifosplatform.portfolio.group.domain.Group;
|
import org.mifosplatform.portfolio.group.domain.Group;
|
||||||
import org.mifosplatform.portfolio.group.exception.GroupNotActiveException;
|
import org.mifosplatform.portfolio.group.exception.GroupNotActiveException;
|
||||||
import org.mifosplatform.portfolio.loanaccount.command.LoanUpdateCommand;
|
import org.mifosplatform.portfolio.loanaccount.command.LoanUpdateCommand;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.ChangedTransactionDetail;
|
import org.mifosplatform.portfolio.loanaccount.domain.ChangedTransactionDetail;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine;
|
import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||||
@@ -73,6 +85,7 @@ import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
|
|||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionRepository;
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||||
|
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionType;
|
||||||
import org.mifosplatform.portfolio.loanaccount.exception.LoanDisbursalException;
|
import org.mifosplatform.portfolio.loanaccount.exception.LoanDisbursalException;
|
||||||
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerAssignmentException;
|
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerAssignmentException;
|
||||||
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerUnassignmentException;
|
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerUnassignmentException;
|
||||||
@@ -88,6 +101,7 @@ import org.mifosplatform.portfolio.note.domain.Note;
|
|||||||
import org.mifosplatform.portfolio.note.domain.NoteRepository;
|
import org.mifosplatform.portfolio.note.domain.NoteRepository;
|
||||||
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
|
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
|
||||||
import org.mifosplatform.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
|
import org.mifosplatform.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
|
||||||
|
import org.mifosplatform.portfolio.savings.exception.InsufficientAccountBalanceException;
|
||||||
import org.mifosplatform.useradministration.domain.AppUser;
|
import org.mifosplatform.useradministration.domain.AppUser;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -118,6 +132,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
private final LoanProductReadPlatformService loanProductReadPlatformService;
|
private final LoanProductReadPlatformService loanProductReadPlatformService;
|
||||||
private final AccountTransfersWritePlatformService accountTransfersWritePlatformService;
|
private final AccountTransfersWritePlatformService accountTransfersWritePlatformService;
|
||||||
private final AccountTransfersReadPlatformService accountTransfersReadPlatformService;
|
private final AccountTransfersReadPlatformService accountTransfersReadPlatformService;
|
||||||
|
private final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService;
|
||||||
|
private final LoanChargeReadPlatformService LoanChargeReadPlatformService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||||
@@ -133,7 +149,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
final ConfigurationDomainService configurationDomainService, final WorkingDaysRepositoryWrapper workingDaysRepository,
|
final ConfigurationDomainService configurationDomainService, final WorkingDaysRepositoryWrapper workingDaysRepository,
|
||||||
final LoanProductReadPlatformService loanProductReadPlatformService,
|
final LoanProductReadPlatformService loanProductReadPlatformService,
|
||||||
final AccountTransfersWritePlatformService accountTransfersWritePlatformService,
|
final AccountTransfersWritePlatformService accountTransfersWritePlatformService,
|
||||||
final AccountTransfersReadPlatformService accountTransfersReadPlatformService) {
|
final AccountTransfersReadPlatformService accountTransfersReadPlatformService,
|
||||||
|
final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService,
|
||||||
|
final LoanChargeReadPlatformService loanChargeReadPlatformService) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.loanEventApiJsonValidator = loanEventApiJsonValidator;
|
this.loanEventApiJsonValidator = loanEventApiJsonValidator;
|
||||||
this.loanAssembler = loanAssembler;
|
this.loanAssembler = loanAssembler;
|
||||||
@@ -155,6 +173,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
this.loanProductReadPlatformService = loanProductReadPlatformService;
|
this.loanProductReadPlatformService = loanProductReadPlatformService;
|
||||||
this.accountTransfersWritePlatformService = accountTransfersWritePlatformService;
|
this.accountTransfersWritePlatformService = accountTransfersWritePlatformService;
|
||||||
this.accountTransfersReadPlatformService = accountTransfersReadPlatformService;
|
this.accountTransfersReadPlatformService = accountTransfersReadPlatformService;
|
||||||
|
this.accountAssociationsReadPlatformService = accountAssociationsReadPlatformService;
|
||||||
|
this.LoanChargeReadPlatformService = loanChargeReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
||||||
@@ -212,7 +232,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
workingDays, allowTransactionsOnHoliday, allowTransactionsOnNonWorkingDay);
|
workingDays, allowTransactionsOnHoliday, allowTransactionsOnNonWorkingDay);
|
||||||
|
|
||||||
if (!changes.isEmpty()) {
|
if (!changes.isEmpty()) {
|
||||||
this.loanRepository.save(loan);
|
this.loanRepository.saveAndFlush(loan);
|
||||||
|
|
||||||
final String noteText = command.stringValueOfParameterNamed("note");
|
final String noteText = command.stringValueOfParameterNamed("note");
|
||||||
if (StringUtils.isNotBlank(noteText)) {
|
if (StringUtils.isNotBlank(noteText)) {
|
||||||
@@ -223,6 +243,20 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Set<LoanCharge> loanCharges = loan.charges();
|
||||||
|
final Locale locale = command.extractLocale();
|
||||||
|
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||||
|
for (LoanCharge loanCharge : loanCharges) {
|
||||||
|
if (loanCharge.isDueAtDisbursement() && loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) {
|
||||||
|
PortfolioAccountData savingAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loanId);
|
||||||
|
AccountTransferDTO accountTransferDTO = new AccountTransferDTO(actualDisbursementDate, loanCharge.amount(),
|
||||||
|
PortfolioAccountType.SAVINGS, PortfolioAccountType.LOAN, savingAccountData.accountId(), loanId,
|
||||||
|
"Loan Charge Payment", locale, fmt, null, null, LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.getValue(),
|
||||||
|
loanCharge.getId());
|
||||||
|
accountTransfersWritePlatformService.transferFunds(accountTransferDTO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withCommandId(command.commandId()) //
|
.withCommandId(command.commandId()) //
|
||||||
.withEntityId(loan.getId()) //
|
.withEntityId(loan.getId()) //
|
||||||
@@ -332,8 +366,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||||
final Map<String, Object> changes = loan.undoDisbursal(existingTransactionIds, existingReversedTransactionIds);
|
final Map<String, Object> changes = loan.undoDisbursal(existingTransactionIds, existingReversedTransactionIds);
|
||||||
if (!changes.isEmpty()) {
|
if (!changes.isEmpty()) {
|
||||||
this.loanRepository.save(loan);
|
this.loanRepository.saveAndFlush(loan);
|
||||||
|
this.accountTransfersWritePlatformService.reverseAllTransactions(loanId, PortfolioAccountType.LOAN);
|
||||||
final String noteText = command.stringValueOfParameterNamed("note");
|
final String noteText = command.stringValueOfParameterNamed("note");
|
||||||
if (StringUtils.isNotBlank(noteText)) {
|
if (StringUtils.isNotBlank(noteText)) {
|
||||||
final Note note = Note.loanNote(loan, noteText);
|
final Note note = Note.loanNote(loan, noteText);
|
||||||
@@ -381,11 +415,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
if (StringUtils.isNotBlank(noteText)) {
|
if (StringUtils.isNotBlank(noteText)) {
|
||||||
changes.put("note", noteText);
|
changes.put("note", noteText);
|
||||||
}
|
}
|
||||||
|
final Loan loan = this.loanAssembler.assembleFrom(loanId);
|
||||||
final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes);
|
final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes);
|
||||||
|
|
||||||
final CommandProcessingResultBuilder commandProcessingResultBuilder = new CommandProcessingResultBuilder();
|
final CommandProcessingResultBuilder commandProcessingResultBuilder = new CommandProcessingResultBuilder();
|
||||||
this.loanAccountDomainService.makeRepayment(loanId, commandProcessingResultBuilder, transactionDate, transactionAmount,
|
this.loanAccountDomainService.makeRepayment(loan, commandProcessingResultBuilder, transactionDate, transactionAmount,
|
||||||
paymentDetail, noteText, txnExternalId);
|
paymentDetail, noteText, txnExternalId);
|
||||||
|
|
||||||
return commandProcessingResultBuilder.withCommandId(command.commandId()) //
|
return commandProcessingResultBuilder.withCommandId(command.commandId()) //
|
||||||
@@ -409,11 +443,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
* TODO Vishwas, have a re-look at this implementation, defaulting
|
* TODO Vishwas, have a re-look at this implementation, defaulting
|
||||||
* it to null for now
|
* it to null for now
|
||||||
***/
|
***/
|
||||||
|
final Loan loan = this.loanAssembler.assembleFrom(singleLoanRepaymentCommand.getLoanId());
|
||||||
final PaymentDetail paymentDetail = null;
|
final PaymentDetail paymentDetail = null;
|
||||||
final CommandProcessingResultBuilder commandProcessingResultBuilder = new CommandProcessingResultBuilder();
|
final CommandProcessingResultBuilder commandProcessingResultBuilder = new CommandProcessingResultBuilder();
|
||||||
this.loanAccountDomainService.makeRepayment(singleLoanRepaymentCommand.getLoanId(), commandProcessingResultBuilder,
|
this.loanAccountDomainService.makeRepayment(loan, commandProcessingResultBuilder, bulkRepaymentCommand.getTransactionDate(),
|
||||||
bulkRepaymentCommand.getTransactionDate(), singleLoanRepaymentCommand.getTransactionAmount(), paymentDetail,
|
singleLoanRepaymentCommand.getTransactionAmount(), paymentDetail, bulkRepaymentCommand.getNote(), null);
|
||||||
bulkRepaymentCommand.getNote(), null);
|
|
||||||
|
|
||||||
changes.put("bulkTransations", singleLoanRepaymentCommand);
|
changes.put("bulkTransations", singleLoanRepaymentCommand);
|
||||||
}
|
}
|
||||||
@@ -433,10 +467,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
|
|
||||||
final LoanTransaction transactionToAdjust = this.loanTransactionRepository.findOne(transactionId);
|
final LoanTransaction transactionToAdjust = this.loanTransactionRepository.findOne(transactionId);
|
||||||
if (transactionToAdjust == null) { throw new LoanTransactionNotFoundException(transactionId); }
|
if (transactionToAdjust == null) { throw new LoanTransactionNotFoundException(transactionId); }
|
||||||
|
|
||||||
if(accountTransfersReadPlatformService.isAccountTransfer(transactionId, PortfolioAccountType.LOAN)){
|
if (accountTransfersReadPlatformService.isAccountTransfer(transactionId, PortfolioAccountType.LOAN)) { throw new PlatformServiceUnavailableException(
|
||||||
throw new PlatformServiceUnavailableException("error.msg.loan.transfer.transaction.update.not.allowed","Loan transaction:"+transactionId+" update not allowed as it involves in account transfer",transactionId);
|
"error.msg.loan.transfer.transaction.update.not.allowed", "Loan transaction:" + transactionId
|
||||||
}
|
+ " update not allowed as it involves in account transfer", transactionId); }
|
||||||
|
|
||||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
|
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
|
||||||
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
|
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
|
||||||
@@ -505,7 +539,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
}
|
}
|
||||||
this.noteRepository.save(note);
|
this.noteRepository.save(note);
|
||||||
}
|
}
|
||||||
this.accountTransfersWritePlatformService.reverseTransfers(loanId, PortfolioAccountType.LOAN);
|
this.accountTransfersWritePlatformService.reverseTransfersWithFromAccountType(loanId, PortfolioAccountType.LOAN);
|
||||||
|
|
||||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||||
|
|
||||||
@@ -898,6 +932,85 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public CommandProcessingResult payLoanCharge(final Long loanId, Long loanChargeId, final JsonCommand command,
|
||||||
|
boolean isChargeIdIncludedInJson) {
|
||||||
|
|
||||||
|
this.loanEventApiJsonValidator.validateChargePaymentTransaction(command.json(), isChargeIdIncludedInJson);
|
||||||
|
if (isChargeIdIncludedInJson) {
|
||||||
|
loanChargeId = command.longValueOfParameterNamed("chargeId");
|
||||||
|
}
|
||||||
|
final Loan loan = this.loanAssembler.assembleFrom(loanId);
|
||||||
|
checkClientOrGroupActive(loan);
|
||||||
|
final LoanCharge loanCharge = retrieveLoanChargeBy(loanId, loanChargeId);
|
||||||
|
|
||||||
|
// Charges may be waived only when the loan associated with them are
|
||||||
|
// active
|
||||||
|
if (!loan.status().isActive()) { throw new LoanChargeCannotBePayedException(LOAN_CHARGE_CANNOT_BE_PAYED_REASON.LOAN_INACTIVE,
|
||||||
|
loanCharge.getId()); }
|
||||||
|
|
||||||
|
// validate loan charge is not already paid or waived
|
||||||
|
if (loanCharge.isWaived()) {
|
||||||
|
throw new LoanChargeCannotBePayedException(LOAN_CHARGE_CANNOT_BE_PAYED_REASON.ALREADY_WAIVED, loanCharge.getId());
|
||||||
|
} else if (loanCharge.isPaid()) { throw new LoanChargeCannotBePayedException(LOAN_CHARGE_CANNOT_BE_PAYED_REASON.ALREADY_PAID,
|
||||||
|
loanCharge.getId()); }
|
||||||
|
|
||||||
|
if (!loanCharge.getChargePaymentMode().isPaymentModeAccountTransfer()) { throw new LoanChargeCannotBePayedException(
|
||||||
|
LOAN_CHARGE_CANNOT_BE_PAYED_REASON.CHARGE_NOT_ACCOUNT_TRANSFER, loanCharge.getId()); }
|
||||||
|
|
||||||
|
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
|
||||||
|
|
||||||
|
final Locale locale = command.extractLocale();
|
||||||
|
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||||
|
|
||||||
|
PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService.retriveLoanAssociation(loanId);
|
||||||
|
AccountTransferDTO accountTransferDTO = new AccountTransferDTO(transactionDate, loanCharge.amountOutstanding(),
|
||||||
|
PortfolioAccountType.SAVINGS, PortfolioAccountType.LOAN, portfolioAccountData.accountId(), loanId, "Loan Charge Payment",
|
||||||
|
locale, fmt, null, null, LoanTransactionType.CHARGE_PAYMENT.getValue(), loanChargeId);
|
||||||
|
accountTransfersWritePlatformService.transferFunds(accountTransferDTO);
|
||||||
|
|
||||||
|
return new CommandProcessingResultBuilder() //
|
||||||
|
.withCommandId(command.commandId()) //
|
||||||
|
.withEntityId(loanChargeId) //
|
||||||
|
.withOfficeId(loan.getOfficeId()) //
|
||||||
|
.withClientId(loan.getClientId()) //
|
||||||
|
.withGroupId(loan.getGroupId()) //
|
||||||
|
.withLoanId(loanId) //
|
||||||
|
.withSavingsId(portfolioAccountData.accountId()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CronTarget(jobName = JobName.TRANSFER_FEE_CHARGE_FOR_LOANS)
|
||||||
|
public void transferFeeCharges() throws JobExecutionException {
|
||||||
|
Collection<LoanChargeData> chargeDatas = this.LoanChargeReadPlatformService.retrieveLoanChargesForFeePayment(
|
||||||
|
ChargePaymentMode.ACCOUNT_TRANSFER.getValue(), LoanStatus.ACTIVE.getValue());
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
if (chargeDatas != null) {
|
||||||
|
for (LoanChargeData chargeData : chargeDatas) {
|
||||||
|
if (chargeData.getDueDate()!=null && !chargeData.getDueDate().isAfter(new LocalDate())) {
|
||||||
|
PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService
|
||||||
|
.retriveLoanAssociation(chargeData.getLoanId());
|
||||||
|
AccountTransferDTO accountTransferDTO = new AccountTransferDTO(new LocalDate(), chargeData.getAmountOutstanding(),
|
||||||
|
PortfolioAccountType.SAVINGS, PortfolioAccountType.LOAN, portfolioAccountData.accountId(),
|
||||||
|
chargeData.getLoanId(), "Loan Charge Payment", null, null, null, null,
|
||||||
|
LoanTransactionType.CHARGE_PAYMENT.getValue(), chargeData.getId());
|
||||||
|
try {
|
||||||
|
accountTransfersWritePlatformService.transferFunds(accountTransferDTO);
|
||||||
|
} catch (PlatformApiDataValidationException e) {
|
||||||
|
sb.append("Validation exception while paying charge ").append(chargeData.getId()).append(" for loan id:")
|
||||||
|
.append(chargeData.getLoanId()).append("--------");
|
||||||
|
} catch (InsufficientAccountBalanceException e) {
|
||||||
|
sb.append("InsufficientAccountBalance Exception while paying charge ").append(chargeData.getId())
|
||||||
|
.append("for loan id:").append(chargeData.getLoanId()).append("--------");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sb.length() > 0) { throw new JobExecutionException(sb.toString()); }
|
||||||
|
}
|
||||||
|
|
||||||
private LoanCharge retrieveLoanChargeBy(final Long loanId, final Long loanChargeId) {
|
private LoanCharge retrieveLoanChargeBy(final Long loanId, final Long loanChargeId) {
|
||||||
final LoanCharge loanCharge = this.loanChargeRepository.findOne(loanChargeId);
|
final LoanCharge loanCharge = this.loanChargeRepository.findOne(loanChargeId);
|
||||||
if (loanCharge == null) { throw new LoanChargeNotFoundException(loanChargeId); }
|
if (loanCharge == null) { throw new LoanChargeNotFoundException(loanChargeId); }
|
||||||
|
|||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
package org.mifosplatform.portfolio.loanproduct.exception;
|
||||||
|
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||||
|
|
||||||
|
|
||||||
|
public class LinkedAccountRequiredException extends AbstractPlatformDomainRuleException {
|
||||||
|
|
||||||
|
public LinkedAccountRequiredException(final String entity, String defaultUserMessage, Object... defaultUserMessageArgs) {
|
||||||
|
super("error.msg." + entity + ".requires.linked.account", defaultUserMessage, defaultUserMessageArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+4
@@ -302,6 +302,10 @@ public class LoanEnumerations {
|
|||||||
optionData = new LoanTransactionEnumData(LoanTransactionType.REFUND.getValue().longValue(),
|
optionData = new LoanTransactionEnumData(LoanTransactionType.REFUND.getValue().longValue(),
|
||||||
LoanTransactionType.REFUND.getCode(), "Transfer Refund");
|
LoanTransactionType.REFUND.getCode(), "Transfer Refund");
|
||||||
break;
|
break;
|
||||||
|
case CHARGE_PAYMENT:
|
||||||
|
optionData = new LoanTransactionEnumData(LoanTransactionType.CHARGE_PAYMENT.getValue().longValue(),
|
||||||
|
LoanTransactionType.CHARGE_PAYMENT.getCode(), "Charge Payment");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
package org.mifosplatform.portfolio.savings.exception;
|
||||||
|
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||||
|
|
||||||
|
|
||||||
|
public class SavingsAccountClosingNotAllowedException extends AbstractPlatformDomainRuleException {
|
||||||
|
|
||||||
|
public SavingsAccountClosingNotAllowedException(final String entity, String defaultUserMessage, Object... defaultUserMessageArgs) {
|
||||||
|
super("error.msg." + entity + ".saving.account.close.notallowed", defaultUserMessage, defaultUserMessageArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+1
-1
@@ -27,6 +27,6 @@ public class UndoTransactionSavingsAccountCommandHandler implements NewCommandSo
|
|||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||||
final Long transactionId = Long.valueOf(command.getTransactionId());
|
final Long transactionId = Long.valueOf(command.getTransactionId());
|
||||||
return this.writePlatformService.undoTransaction(command.getSavingsId(), transactionId);
|
return this.writePlatformService.undoTransaction(command.getSavingsId(), transactionId, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -26,7 +26,7 @@ public interface SavingsAccountWritePlatformService {
|
|||||||
|
|
||||||
CommandProcessingResult postInterest(Long savingsId);
|
CommandProcessingResult postInterest(Long savingsId);
|
||||||
|
|
||||||
CommandProcessingResult undoTransaction(Long savingsId, Long transactionId);
|
CommandProcessingResult undoTransaction(Long savingsId, Long transactionId, boolean allowAccountTransferModification);
|
||||||
|
|
||||||
void postInterestForAccounts();
|
void postInterestForAccounts();
|
||||||
|
|
||||||
|
|||||||
+14
-3
@@ -38,6 +38,7 @@ import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
|||||||
import org.mifosplatform.organisation.office.domain.Office;
|
import org.mifosplatform.organisation.office.domain.Office;
|
||||||
import org.mifosplatform.organisation.staff.domain.Staff;
|
import org.mifosplatform.organisation.staff.domain.Staff;
|
||||||
import org.mifosplatform.portfolio.account.PortfolioAccountType;
|
import org.mifosplatform.portfolio.account.PortfolioAccountType;
|
||||||
|
import org.mifosplatform.portfolio.account.service.AccountAssociationsReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.account.service.AccountTransfersReadPlatformService;
|
import org.mifosplatform.portfolio.account.service.AccountTransfersReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.client.domain.Client;
|
import org.mifosplatform.portfolio.client.domain.Client;
|
||||||
import org.mifosplatform.portfolio.client.exception.ClientNotActiveException;
|
import org.mifosplatform.portfolio.client.exception.ClientNotActiveException;
|
||||||
@@ -57,6 +58,7 @@ import org.mifosplatform.portfolio.savings.domain.SavingsAccountRepository;
|
|||||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccountStatusType;
|
import org.mifosplatform.portfolio.savings.domain.SavingsAccountStatusType;
|
||||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransaction;
|
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransaction;
|
||||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransactionRepository;
|
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransactionRepository;
|
||||||
|
import org.mifosplatform.portfolio.savings.exception.SavingsAccountClosingNotAllowedException;
|
||||||
import org.mifosplatform.portfolio.savings.exception.SavingsAccountTransactionNotFoundException;
|
import org.mifosplatform.portfolio.savings.exception.SavingsAccountTransactionNotFoundException;
|
||||||
import org.mifosplatform.portfolio.savings.exception.TransactionUpdateNotAllowedException;
|
import org.mifosplatform.portfolio.savings.exception.TransactionUpdateNotAllowedException;
|
||||||
import org.mifosplatform.useradministration.domain.AppUser;
|
import org.mifosplatform.useradministration.domain.AppUser;
|
||||||
@@ -78,6 +80,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
|||||||
private final SavingsAccountDomainService savingsAccountDomainService;
|
private final SavingsAccountDomainService savingsAccountDomainService;
|
||||||
private final NoteRepository noteRepository;
|
private final NoteRepository noteRepository;
|
||||||
private final AccountTransfersReadPlatformService accountTransfersReadPlatformService;
|
private final AccountTransfersReadPlatformService accountTransfersReadPlatformService;
|
||||||
|
private final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public SavingsAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
public SavingsAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||||
@@ -89,7 +92,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
|||||||
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper,
|
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper,
|
||||||
final JournalEntryWritePlatformService journalEntryWritePlatformService,
|
final JournalEntryWritePlatformService journalEntryWritePlatformService,
|
||||||
final SavingsAccountDomainService savingsAccountDomainService, final NoteRepository noteRepository,
|
final SavingsAccountDomainService savingsAccountDomainService, final NoteRepository noteRepository,
|
||||||
final AccountTransfersReadPlatformService accountTransfersReadPlatformService) {
|
final AccountTransfersReadPlatformService accountTransfersReadPlatformService,
|
||||||
|
final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.savingAccountRepository = savingAccountRepository;
|
this.savingAccountRepository = savingAccountRepository;
|
||||||
this.savingsAccountTransactionRepository = savingsAccountTransactionRepository;
|
this.savingsAccountTransactionRepository = savingsAccountTransactionRepository;
|
||||||
@@ -101,6 +105,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
|||||||
this.savingsAccountDomainService = savingsAccountDomainService;
|
this.savingsAccountDomainService = savingsAccountDomainService;
|
||||||
this.noteRepository = noteRepository;
|
this.noteRepository = noteRepository;
|
||||||
this.accountTransfersReadPlatformService = accountTransfersReadPlatformService;
|
this.accountTransfersReadPlatformService = accountTransfersReadPlatformService;
|
||||||
|
this.accountAssociationsReadPlatformService = accountAssociationsReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -299,7 +304,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult undoTransaction(final Long savingsId, final Long transactionId) {
|
public CommandProcessingResult undoTransaction(final Long savingsId, final Long transactionId, boolean allowAccountTransferModification) {
|
||||||
|
|
||||||
final List<Long> newTransactionIds = new ArrayList<Long>();
|
final List<Long> newTransactionIds = new ArrayList<Long>();
|
||||||
final List<Long> reversedTransactionIds = new ArrayList<Long>();
|
final List<Long> reversedTransactionIds = new ArrayList<Long>();
|
||||||
@@ -308,7 +313,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
|||||||
transactionId, savingsId);
|
transactionId, savingsId);
|
||||||
if (savingsAccountTransaction == null) { throw new SavingsAccountTransactionNotFoundException(savingsId, transactionId); }
|
if (savingsAccountTransaction == null) { throw new SavingsAccountTransactionNotFoundException(savingsId, transactionId); }
|
||||||
|
|
||||||
if(accountTransfersReadPlatformService.isAccountTransfer(transactionId, PortfolioAccountType.SAVINGS)){
|
if(!allowAccountTransferModification && accountTransfersReadPlatformService.isAccountTransfer(transactionId, PortfolioAccountType.SAVINGS)){
|
||||||
throw new PlatformServiceUnavailableException("error.msg.saving.account.transfer.transaction.update.not.allowed","Savings account transaction:"+transactionId+" update not allowed as it involves in account transfer",transactionId);
|
throw new PlatformServiceUnavailableException("error.msg.saving.account.transfer.transaction.update.not.allowed","Savings account transaction:"+transactionId+" update not allowed as it involves in account transfer",transactionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,6 +456,12 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
|||||||
|
|
||||||
this.savingsAccountTransactionDataValidator.validateClosing(command);
|
this.savingsAccountTransactionDataValidator.validateClosing(command);
|
||||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||||
|
final boolean isLinkedWithAnyActiveLoan = accountAssociationsReadPlatformService.isLinkedWithAnyActiveLoan(savingsId);
|
||||||
|
if(isLinkedWithAnyActiveLoan){
|
||||||
|
String defaultUserMessage = "Closing savings account with id:"+savingsId+" is not allowed, since it is linked with one of the active loans";
|
||||||
|
throw new SavingsAccountClosingNotAllowedException("linked", defaultUserMessage, savingsId);
|
||||||
|
}
|
||||||
|
|
||||||
final Map<String, Object> changes = account.close(user, command, DateUtils.getLocalDateOfTenant());
|
final Map<String, Object> changes = account.close(user, command, DateUtils.getLocalDateOfTenant());
|
||||||
if (!changes.isEmpty()) {
|
if (!changes.isEmpty()) {
|
||||||
this.savingAccountRepository.save(account);
|
this.savingAccountRepository.save(account);
|
||||||
|
|||||||
Reference in New Issue
Block a user