diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/domain/Group.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/domain/Group.java index 262c1f30c..3f3ed1450 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/domain/Group.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/domain/Group.java @@ -90,6 +90,10 @@ public class Group extends AbstractAuditableCustom { public void addClientMember(final Client member){ this.clientMembers.add(member); } + + public boolean hasClientAsMember(final Client client){ + return this.clientMembers.contains(client); + } /** * Delete is a soft delete. Updates flag on group so it wont appear in query/report results. diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/exception/ClientNotInGroupException.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/exception/ClientNotInGroupException.java new file mode 100644 index 000000000..2a094a2c5 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/exception/ClientNotInGroupException.java @@ -0,0 +1,12 @@ +package org.mifosplatform.portfolio.group.exception; + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException; + +public class ClientNotInGroupException extends AbstractPlatformDomainRuleException { + + public ClientNotInGroupException(final Long clientId, final Long groupId) { + super("error.msg.group.client.not.in.group", "Client with identifier " + clientId + " is not in Group with identifier " + groupId, + clientId, groupId); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupReadPlatformServiceImpl.java index c3aabea0c..446e30a22 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupReadPlatformServiceImpl.java @@ -154,7 +154,7 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService { GroupLoanAccountSummaryDataMapper rm = new GroupLoanAccountSummaryDataMapper(); - String sql = "select " + rm.loanAccountSummarySchema() + " where l.group_id = ?"; + String sql = "select " + rm.loanAccountSummarySchema() + " where l.group_id = ? and l.client_id is null"; List results = this.jdbcTemplate.query(sql, rm, new Object[] {groupId}); if (results != null) { @@ -191,7 +191,7 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService { GroupLoanAccountSummaryDataMapper rm = new GroupLoanAccountSummaryDataMapper(); - String sql = "select " + rm.loanAccountSummarySchema() + " where l.group_id = ? and l.loan_officer_id = ?"; + String sql = "select " + rm.loanAccountSummarySchema() + " where l.group_id = ? and l.client_id is null and l.loan_officer_id = ?"; List loanAccounts = this.jdbcTemplate.query(sql, rm, new Object[] {groupId, loanOfficerId}); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/command/LoanApplicationCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/command/LoanApplicationCommand.java index b637140e4..20f709636 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/command/LoanApplicationCommand.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/command/LoanApplicationCommand.java @@ -108,13 +108,11 @@ public class LoanApplicationCommand { DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan"); - if (this.groupId != null) { - baseDataValidator.reset().parameter("clientId").value(this.clientId).mustBeBlankWhenParameterProvided("groupId", this.groupId) - .longGreaterThanZero(); - } if (this.clientId != null) { - baseDataValidator.reset().parameter("groupId").value(this.groupId).mustBeBlankWhenParameterProvided("clientId", this.clientId) - .longGreaterThanZero(); + baseDataValidator.reset().parameter("clientId").value(this.clientId).longGreaterThanZero(); + } + if (this.groupId != null) { + baseDataValidator.reset().parameter("groupId").value(this.groupId).longGreaterThanZero(); } if (this.clientId == null && this.groupId == null) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java index 421ad54d0..fa0b7d8ae 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java @@ -195,7 +195,7 @@ public class Loan extends AbstractAuditableCustom { public static Loan createNew(final Fund fund, final Staff loanOfficer, final LoanTransactionProcessingStrategy transactionProcessingStrategy, final LoanProduct loanProduct, final Client client, final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set loanCharges) { - return new Loan(client, fund, loanOfficer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, null, + return new Loan(client, null, fund, loanOfficer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, null, loanCharges); } @@ -203,7 +203,7 @@ public class Loan extends AbstractAuditableCustom { public static Loan createNew(final Fund fund, final Staff loanOfficer, final LoanTransactionProcessingStrategy transactionProcessingStrategy, final LoanProduct loanProduct, final Group group, final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set loanCharges) { - return new Loan(group, fund, loanOfficer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, null, + return new Loan(null, group, fund, loanOfficer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, null, loanCharges); } @@ -212,7 +212,7 @@ public class Loan extends AbstractAuditableCustom { final Set loanCharges) { final LoanStatus status = null; LoanProductRelatedDetail loanRepaymentScheduleDetail = loanSchedule.loanProductRelatedDetail(); - return new Loan(client, fund, officer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, status, loanCharges); + return new Loan(client, null, fund, officer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, status, loanCharges); } public static Loan newGroupLoanApplication(final Group group, final LoanProduct loanProduct, final Fund fund, final Staff officer, @@ -220,39 +220,26 @@ public class Loan extends AbstractAuditableCustom { final Set loanCharges) { final LoanStatus status = null; LoanProductRelatedDetail loanRepaymentScheduleDetail = loanSchedule.loanProductRelatedDetail(); - return new Loan(group, fund, officer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, status, loanCharges); + return new Loan(null, group, fund, officer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, status, loanCharges); + } + + public static Loan newMemberLoanApplication(final Client client, final Group group, final LoanProduct loanProduct, final Fund fund, + final Staff officer, final LoanTransactionProcessingStrategy transactionProcessingStrategy, final LoanSchedule loanSchedule, + final Set loanCharges) { + final LoanStatus status = null; + LoanProductRelatedDetail loanRepaymentScheduleDetail = loanSchedule.loanProductRelatedDetail(); + return new Loan(client, group, fund, officer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, status, + loanCharges); } protected Loan() { // } - private Loan(final Client client, Fund fund, Staff loanOfficer, final LoanTransactionProcessingStrategy transactionProcessingStrategy, + private Loan(final Client client, final Group group, Fund fund, Staff loanOfficer, final LoanTransactionProcessingStrategy transactionProcessingStrategy, final LoanProduct loanProduct, final LoanProductRelatedDetail loanRepaymentScheduleDetail, final LoanStatus loanStatus, final Set loanCharges) { this.client = client; - this.fund = fund; - this.loanofficer = loanOfficer; - this.transactionProcessingStrategy = transactionProcessingStrategy; - this.loanProduct = loanProduct; - this.loanRepaymentScheduleDetail = loanRepaymentScheduleDetail; - if (loanStatus != null) { - this.loanStatus = loanStatus.getValue(); - } else { - this.loanStatus = null; - } - if (loanCharges != null && !loanCharges.isEmpty()) { - this.charges = associateChargesWithThisLoan(loanCharges); - this.totalChargesDueAtDisbursement = deriveSumTotalOfChargesDueAtDisbursement(); - } else { - this.charges = null; - } - this.loanOfficerHistory = null; - } - - private Loan(final Group group, Fund fund, Staff loanOfficer, final LoanTransactionProcessingStrategy transactionProcessingStrategy, - final LoanProduct loanProduct, final LoanProductRelatedDetail loanRepaymentScheduleDetail, final LoanStatus loanStatus, - final Set loanCharges) { this.group = group; this.fund = fund; this.loanofficer = loanOfficer; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAssembler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAssembler.java index 67c868c49..b71cd8f3f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAssembler.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAssembler.java @@ -20,6 +20,7 @@ import org.mifosplatform.portfolio.fund.domain.FundRepository; import org.mifosplatform.portfolio.fund.exception.FundNotFoundException; import org.mifosplatform.portfolio.group.domain.Group; import org.mifosplatform.portfolio.group.domain.GroupRepository; +import org.mifosplatform.portfolio.group.exception.ClientNotInGroupException; import org.mifosplatform.portfolio.group.exception.GroupNotFoundException; import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine; import org.mifosplatform.portfolio.loanaccount.domain.Loan; @@ -98,8 +99,10 @@ public class LoanAssembler { LoanSchedule loanSchedule = this.loanScheduleAssembler.fromJson(element, inArrearsTolerance); Loan loanApplication = null; + Client client = null; + Group group = null; if (clientId != null) { - final Client client = this.clientRepository.findOne(clientId); + client = this.clientRepository.findOne(clientId); if (client == null || client.isDeleted()) { throw new ClientNotFoundException(clientId); } loanApplication = Loan.newIndividualLoanApplication(client, loanProduct, fund, loanOfficer, loanTransactionProcessingStrategy, @@ -107,13 +110,19 @@ public class LoanAssembler { } if (groupId != null) { - final Group group = this.groupRepository.findOne(groupId); + group = this.groupRepository.findOne(groupId); if (group == null || group.isDeleted()) { throw new GroupNotFoundException(groupId); } loanApplication = Loan.newGroupLoanApplication(group, loanProduct, fund, loanOfficer, loanTransactionProcessingStrategy, loanSchedule, loanCharges); } + if (clientId != null && groupId != null){ + if (!group.hasClientAsMember(client)) { throw new ClientNotInGroupException(clientId, groupId); } + loanApplication = Loan.newMemberLoanApplication(client, group, loanProduct, fund, loanOfficer, loanTransactionProcessingStrategy, + loanSchedule, loanCharges); + } + final String externalId = fromApiJsonHelper.extractStringNamed("externalId", element); final LocalDate submittedOnDate = fromApiJsonHelper.extractLocalDateNamed("submittedOnDate", element);