diff --git a/mifosng-db/migrations/core_db/V32__associate-disassociate-clients-from-group-permissions.sql b/mifosng-db/migrations/core_db/V32__associate-disassociate-clients-from-group-permissions.sql new file mode 100644 index 000000000..700eb36c5 --- /dev/null +++ b/mifosng-db/migrations/core_db/V32__associate-disassociate-clients-from-group-permissions.sql @@ -0,0 +1,4 @@ +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'ASSOCIATECLIENTS_GROUP', 'GROUP', 'ASSOCIATECLIENTS', 0); + + +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'DISASSOCIATECLIENTS_GROUP', 'GROUP', 'DISASSOCIATECLIENTS', 0); \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java index 914ff937e..ac1393b3d 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java @@ -498,4 +498,12 @@ public class CommandWrapper { public boolean isReportResource() { return this.entityName.equalsIgnoreCase("REPORT"); } + + public boolean isAssociateClients(){ + return this.actionName.equalsIgnoreCase("ASSOCIATECLIENTS"); + } + + public boolean isDisassociateClients(){ + return this.actionName.equalsIgnoreCase("DISASSOCIATECLIENTS"); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java index 0df1e2f7b..678520288 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java @@ -857,6 +857,24 @@ public class CommandWrapperBuilder { return this; } + public CommandWrapperBuilder associateClientsToGroup(final Long groupId) { + this.actionName = "ASSOCIATECLIENTS"; + this.entityName = "GROUP"; + this.entityId = groupId; + this.groupId = groupId; + this.href = "/groups/" + groupId + "?command=associateClients"; + return this; + } + + public CommandWrapperBuilder disassociateClientsFromGroup(final Long groupId) { + this.actionName = "DISASSOCIATECLIENTS"; + this.entityName = "GROUP"; + this.entityId = groupId; + this.groupId = groupId; + this.href = "/groups/" + groupId + "?command=disassociateClients"; + return this; + } + public CommandWrapperBuilder unassignStaff(final Long groupId) { this.actionName = "UNASSIGNSTAFF"; this.entityName = "GROUP"; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java index 16ecf3af1..3fc193fdb 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java @@ -400,6 +400,10 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer handler = applicationContext.getBean("deleteGroupCommandHandler", NewCommandSourceHandler.class); } else if (wrapper.isGroupActivation()) { handler = applicationContext.getBean("activateGroupCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isAssociateClients()) { + handler = applicationContext.getBean("associateClientsToGroupCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isDisassociateClients()) { + handler = applicationContext.getBean("disassociateClientsFromGroupCommandHandler", NewCommandSourceHandler.class); } else { throw new UnsupportedCommandException(wrapper.commandName()); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/api/GroupsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/api/GroupsApiResource.java index 1ffd8cc7b..cf994e6f8 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/api/GroupsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/api/GroupsApiResource.java @@ -223,6 +223,12 @@ public class GroupsApiResource { if (is(commandParam, "activate")) { final CommandWrapper commandRequest = builder.activateGroup(groupId).build(); result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + }else if (is(commandParam, "associateClients")) { + final CommandWrapper commandRequest = builder.associateClientsToGroup(groupId).build(); + result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + }else if (is(commandParam, "disassociateClients")) { + final CommandWrapper commandRequest = builder.disassociateClientsFromGroup(groupId).build(); + result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); } if (result == null) { 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 736a70d0b..277240716 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 @@ -39,6 +39,8 @@ import org.mifosplatform.organisation.office.domain.Office; import org.mifosplatform.organisation.staff.domain.Staff; import org.mifosplatform.portfolio.client.domain.Client; import org.mifosplatform.portfolio.group.api.GroupingTypesApiConstants; +import org.mifosplatform.portfolio.group.exception.ClientExistInGroupException; +import org.mifosplatform.portfolio.group.exception.ClientNotInGroupException; import org.springframework.data.jpa.domain.AbstractPersistable; import com.google.common.collect.Sets; @@ -312,6 +314,33 @@ public final class Group extends AbstractPersistable { return differences; } + public List associateClients(final Set clientMembersSet) { + List differences = new ArrayList(); + for (Client client : clientMembersSet) { + if(this.hasClientAsMember(client)){ + throw new ClientExistInGroupException(client.getId(), this.getId()); + } + this.clientMembers.add(client); + differences.add(client.getId().toString()); + } + + return differences; + } + + public List disassociateClients(final Set clientMembersSet) { + List differences = new ArrayList(); + for (Client client : clientMembersSet) { + if(this.hasClientAsMember(client)){ + this.clientMembers.remove(client); + differences.add(client.getId().toString()); + }else{ + throw new ClientNotInGroupException(client.getId(), this.getId()); + } + } + + return differences; + } + private String[] getClientIds(final Set clients) { String[] clientIds = new String[clients.size()]; Iterator it = clients.iterator(); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/exception/ClientExistInGroupException.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/exception/ClientExistInGroupException.java new file mode 100644 index 000000000..b7c47ed2f --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/exception/ClientExistInGroupException.java @@ -0,0 +1,17 @@ +/** + * 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.group.exception; + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException; + +public class ClientExistInGroupException extends AbstractPlatformDomainRuleException { + + public ClientExistInGroupException(final Long clientId, final Long groupId) { + super("error.msg.group.client.exist.in.group", "Client with identifier " + clientId + " is already exists in Group with identifier " + groupId, + clientId, groupId); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/exception/GroupLoanExistsException.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/exception/GroupLoanExistsException.java new file mode 100644 index 000000000..ccf76e171 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/exception/GroupLoanExistsException.java @@ -0,0 +1,15 @@ +/** + * 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.group.exception; + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException; + +public class GroupLoanExistsException extends AbstractPlatformDomainRuleException { + + public GroupLoanExistsException(final String action, String postFix, String defaultUserMessage, Object... defaultUserMessageArgs) { + super("error.msg.group." + action + "." + postFix, defaultUserMessage, defaultUserMessageArgs); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/handler/AssociateClientsToGroupCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/handler/AssociateClientsToGroupCommandHandler.java new file mode 100644 index 000000000..9542ed237 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/handler/AssociateClientsToGroupCommandHandler.java @@ -0,0 +1,32 @@ +/** + * 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.group.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.group.service.GroupingTypesWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class AssociateClientsToGroupCommandHandler implements NewCommandSourceHandler { + + private final GroupingTypesWritePlatformService writePlatformService; + + @Autowired + public AssociateClientsToGroupCommandHandler(final GroupingTypesWritePlatformService clientWritePlatformService) { + this.writePlatformService = clientWritePlatformService; + } + + @Transactional + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + + return this.writePlatformService.associateClientsToGroup(command.entityId(), command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/handler/DisassociateClientsFromGroupCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/handler/DisassociateClientsFromGroupCommandHandler.java new file mode 100644 index 000000000..f3e5bb480 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/handler/DisassociateClientsFromGroupCommandHandler.java @@ -0,0 +1,31 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.portfolio.group.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.group.service.GroupingTypesWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class DisassociateClientsFromGroupCommandHandler implements NewCommandSourceHandler { + + private final GroupingTypesWritePlatformService writePlatformService; + + @Autowired + public DisassociateClientsFromGroupCommandHandler(final GroupingTypesWritePlatformService clientWritePlatformService) { + this.writePlatformService = clientWritePlatformService; + } + + @Transactional + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + return this.writePlatformService.disassociateClientsFromGroup(command.entityId(), command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/serialization/GroupingTypesDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/serialization/GroupingTypesDataValidator.java index 7ecc9b0f3..bd0b242c5 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/serialization/GroupingTypesDataValidator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/serialization/GroupingTypesDataValidator.java @@ -344,4 +344,44 @@ public final class GroupingTypesDataValidator { if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } } + + public void validateForAssociateClients(final String json){ + + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } + + final Type typeOfMap = new TypeToken>() {}.getType(); + + final Set supportedParameters = new HashSet(Arrays.asList(GroupingTypesApiConstants.clientMembersParamName)); + + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); + final JsonElement element = this.fromApiJsonHelper.parse(json); + + final List dataValidationErrors = new ArrayList(); + + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("group"); + final String[] clients = fromApiJsonHelper.extractArrayNamed(GroupingTypesApiConstants.clientMembersParamName, element); + baseDataValidator.reset().parameter(GroupingTypesApiConstants.clientMembersParamName).value(clients).arrayNotEmpty(); + + throwExceptionIfValidationWarningsExist(dataValidationErrors); + } + + public void validateForDisassociateClients(final String json){ + + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } + + final Type typeOfMap = new TypeToken>() {}.getType(); + + final Set supportedParameters = new HashSet(Arrays.asList(GroupingTypesApiConstants.clientMembersParamName)); + + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); + final JsonElement element = this.fromApiJsonHelper.parse(json); + + final List dataValidationErrors = new ArrayList(); + + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("group"); + final String[] clients = fromApiJsonHelper.extractArrayNamed(GroupingTypesApiConstants.clientMembersParamName, element); + baseDataValidator.reset().parameter(GroupingTypesApiConstants.clientMembersParamName).value(clients).arrayNotEmpty(); + + throwExceptionIfValidationWarningsExist(dataValidationErrors); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupingTypesWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupingTypesWritePlatformService.java index dab557b0d..b19f80c62 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupingTypesWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupingTypesWritePlatformService.java @@ -22,5 +22,9 @@ public interface GroupingTypesWritePlatformService { CommandProcessingResult deleteGroup(Long groupId); - CommandProcessingResult unassignStaff(Long grouptId, JsonCommand command); + CommandProcessingResult unassignStaff(Long groupId, JsonCommand command); + + CommandProcessingResult associateClientsToGroup(Long groupId, JsonCommand command); + + CommandProcessingResult disassociateClientsFromGroup(Long groupId, JsonCommand command); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java index 6abde8f22..57e420cdf 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java @@ -5,6 +5,8 @@ */ package org.mifosplatform.portfolio.group.service; +import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -35,9 +37,12 @@ import org.mifosplatform.portfolio.group.domain.GroupLevelRepository; import org.mifosplatform.portfolio.group.domain.GroupRepositoryWrapper; import org.mifosplatform.portfolio.group.domain.GroupTypes; import org.mifosplatform.portfolio.group.exception.GroupHasNoStaffException; +import org.mifosplatform.portfolio.group.exception.GroupLoanExistsException; import org.mifosplatform.portfolio.group.exception.GroupMustBePendingToBeDeletedException; import org.mifosplatform.portfolio.group.exception.InvalidGroupLevelException; import org.mifosplatform.portfolio.group.serialization.GroupingTypesDataValidator; +import org.mifosplatform.portfolio.loanaccount.domain.Loan; +import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository; import org.mifosplatform.portfolio.note.domain.Note; import org.mifosplatform.portfolio.note.domain.NoteRepository; import org.slf4j.Logger; @@ -46,6 +51,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; @Service @@ -61,12 +67,14 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group private final NoteRepository noteRepository; private final GroupLevelRepository groupLevelRepository; private final GroupingTypesDataValidator fromApiJsonDeserializer; + private final LoanRepository loanRepository; @Autowired public GroupingTypesWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final GroupRepositoryWrapper groupRepository, final ClientRepositoryWrapper clientRepository, final OfficeRepository officeRepository, final StaffRepositoryWrapper staffRepository, final NoteRepository noteRepository, - final GroupLevelRepository groupLevelRepository, final GroupingTypesDataValidator fromApiJsonDeserializer) { + final GroupLevelRepository groupLevelRepository, final GroupingTypesDataValidator fromApiJsonDeserializer, + final LoanRepository loanRepository) { this.context = context; this.groupRepository = groupRepository; this.clientRepository = clientRepository; @@ -75,6 +83,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group this.noteRepository = noteRepository; this.groupLevelRepository = groupLevelRepository; this.fromApiJsonDeserializer = fromApiJsonDeserializer; + this.loanRepository = loanRepository; } private CommandProcessingResult createGroupingType(final JsonCommand command, final GroupTypes groupingType, final Long centerId) { @@ -101,7 +110,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group staff = this.staffRepository.findByOfficeWithNotFoundDetection(staffId, officeId); } - final Set clientMembers = assembleSetOfClients(officeId, command); + final Set clientMembers = assembleSetOfClients(parentGroup, command); final Set groupMembers = assembleSetOfChildGroups(officeId, command); @@ -269,11 +278,11 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group } } - final Set clientMembers = assembleSetOfClients(officeId, command); + /*final Set clientMembers = assembleSetOfClients(officeId, command); List changes = groupForUpdate.updateClientMembersIfDifferent(clientMembers); if (!changes.isEmpty()) { actualChanges.put(GroupingTypesApiConstants.clientMembersParamName, changes); - } + }*/ this.groupRepository.saveAndFlush(groupForUpdate); @@ -345,7 +354,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group .build(); } - private Set assembleSetOfClients(final Long officeId, final JsonCommand command) { + private Set assembleSetOfClients(final Group group, final JsonCommand command) { final Set clientMembers = new HashSet(); final String[] clientMembersArray = command.arrayValueOfParameterNamed(GroupingTypesApiConstants.clientMembersParamName); @@ -354,9 +363,9 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group for (final String clientId : clientMembersArray) { final Long id = Long.valueOf(clientId); final Client client = this.clientRepository.findOneWithNotFoundDetection(id); - if (!client.isOfficeIdentifiedBy(officeId)) { - final String errorMessage = "Group and Client must have the same office."; - throw new InvalidOfficeException("client", "attach.to.group", errorMessage); + if (!client.isOfficeIdentifiedBy(group.officeId())) { + final String errorMessage = "Group with identifier " + group.getId() + " and Client with identifier " + clientId + " must have the same office."; + throw new InvalidOfficeException("client", "attach.to.group", errorMessage, group.getId(), clientId); } clientMembers.add(client); } @@ -429,4 +438,69 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group throw new PlatformDataIntegrityException("error.msg.group.unknown.data.integrity.issue", "Unknown data integrity issue with resource."); } + + @Override + public CommandProcessingResult associateClientsToGroup(Long groupId, JsonCommand command) { + + this.fromApiJsonDeserializer.validateForAssociateClients(command.json()); + + final Group groupForUpdate = this.groupRepository.findOneWithNotFoundDetection(groupId); + final Set clientMembers = assembleSetOfClients(groupForUpdate, command); + Map actualChanges = new HashMap(); + + List changes = groupForUpdate.associateClients(clientMembers); + if (!changes.isEmpty()) { + actualChanges.put(GroupingTypesApiConstants.clientMembersParamName, changes); + } + + this.groupRepository.saveAndFlush(groupForUpdate); + + return new CommandProcessingResultBuilder() // + .withCommandId(command.commandId()) // + .withOfficeId(groupForUpdate.officeId()) // + .withGroupId(groupForUpdate.getId()) // + .withEntityId(groupForUpdate.getId()) // + .with(actualChanges) // + .build(); + } + + @Transactional + @Override + public CommandProcessingResult disassociateClientsFromGroup(Long groupId, JsonCommand command) { + this.fromApiJsonDeserializer.validateForDisassociateClients(command.json()); + + final Group groupForUpdate = this.groupRepository.findOneWithNotFoundDetection(groupId); + final Set clientMembers = assembleSetOfClients(groupForUpdate, command); + + //check if any client has got group loans + validateForJLGLoan(groupForUpdate.getId(), clientMembers); + Map actualChanges = new HashMap(); + + List changes = groupForUpdate.disassociateClients(clientMembers); + if (!changes.isEmpty()) { + actualChanges.put(GroupingTypesApiConstants.clientMembersParamName, changes); + } + + this.groupRepository.saveAndFlush(groupForUpdate); + + return new CommandProcessingResultBuilder() // + .withCommandId(command.commandId()) // + .withOfficeId(groupForUpdate.officeId()) // + .withGroupId(groupForUpdate.getId()) // + .withEntityId(groupForUpdate.getId()) // + .with(actualChanges) // + .build(); + } + + @Transactional + private void validateForJLGLoan(Long groupId, Set clientMembers) { + for (Client client : clientMembers) { + Collection loans = this.loanRepository.findByClientIdAndGroupId(client.getId(), groupId); + if(!CollectionUtils.isEmpty(loans)){ + final String defaultUserMessage = "Client with identifier " + client.getId() + " cannot be disassociated it has group loans."; + throw new GroupLoanExistsException("disassociate", "client.has.group.loan", defaultUserMessage, client.getId(), groupId); + } + } + } + } \ No newline at end of file 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 b4ce5cf55..6d3f09e62 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 @@ -89,11 +89,11 @@ public class Loan extends AbstractPersistable { @Column(name = "external_id") private String externalId; - @ManyToOne(optional = true) + @ManyToOne @JoinColumn(name = "client_id", nullable = true) private Client client; - @ManyToOne(optional = true) + @ManyToOne @JoinColumn(name = "group_id", nullable = true) private Group group; @@ -300,7 +300,7 @@ public class Loan extends AbstractPersistable { } protected Loan() { - // + this.client = null; } private Loan(final String accountNo, final Client client, final Group group, final Integer loanType, final Fund fund, final Staff loanOfficer, diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanRepository.java index d85727213..d27ac4ef9 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanRepository.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanRepository.java @@ -5,10 +5,15 @@ */ package org.mifosplatform.portfolio.loanaccount.domain; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface LoanRepository extends JpaRepository, JpaSpecificationExecutor { - // no added behaviour + @Query("from Loan loan where loan.client.id = :clientId and loan.group.id = :groupId") + List findByClientIdAndGroupId(@Param("clientId") Long clientId, @Param("groupId") Long groupId); } \ No newline at end of file