merging ashoks changes for group closure

This commit is contained in:
Vishwas Babu A J
2013-09-06 17:27:08 +05:30
28 changed files with 467 additions and 36 deletions
@@ -0,0 +1,8 @@
INSERT INTO `m_code` (`code_name`, `is_system_defined`) VALUES ('GroupClosureReason', 1);
ALTER TABLE `m_group` ADD COLUMN `closure_reason_cv_id` INT(11) NULL DEFAULT NULL,
ADD COLUMN `closedon_date` DATE NULL DEFAULT NULL,
ADD CONSTRAINT `FK_m_group_m_code` FOREIGN KEY (`closure_reason_cv_id`) REFERENCES `m_code_value` (`id`);
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`) VALUES ('portfolio', 'CLOSE_GROUP', 'GROUP', 'CLOSE');
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`) VALUES ('portfolio', 'CLOSE_CENTER', 'CENTER', 'CLOSE');
@@ -289,10 +289,18 @@ public class CommandWrapper {
return this.actionName.equalsIgnoreCase("ACTIVATE") && this.entityName.equalsIgnoreCase("GROUP"); return this.actionName.equalsIgnoreCase("ACTIVATE") && this.entityName.equalsIgnoreCase("GROUP");
} }
public boolean isGroupClose() {
return this.actionName.equalsIgnoreCase("CLOSE") && this.entityName.equalsIgnoreCase("GROUP");
}
public boolean isCenterActivation() { public boolean isCenterActivation() {
return this.actionName.equalsIgnoreCase("ACTIVATE") && this.entityName.equalsIgnoreCase("CENTER"); return this.actionName.equalsIgnoreCase("ACTIVATE") && this.entityName.equalsIgnoreCase("CENTER");
} }
public boolean isCenterClose() {
return this.actionName.equalsIgnoreCase("CLOSE") && this.entityName.equalsIgnoreCase("CENTER");
}
public boolean isClientIdentifierResource() { public boolean isClientIdentifierResource() {
return this.entityName.equals("CLIENTIDENTIFIER"); return this.entityName.equals("CLIENTIDENTIFIER");
} }
@@ -1077,6 +1077,15 @@ public class CommandWrapperBuilder {
return this; return this;
} }
public CommandWrapperBuilder closeGroup(final Long groupId) {
this.actionName = "CLOSE";
this.entityName = "GROUP";
this.entityId = groupId;
this.groupId = groupId;
this.href = "/groups/" + groupId + "?command=close";
return this;
}
public CommandWrapperBuilder createCollateral(final Long loanId) { public CommandWrapperBuilder createCollateral(final Long loanId) {
this.actionName = "CREATE"; this.actionName = "CREATE";
this.entityName = "COLLATERAL"; this.entityName = "COLLATERAL";
@@ -1154,6 +1163,15 @@ public class CommandWrapperBuilder {
return this; return this;
} }
public CommandWrapperBuilder closeCenter(final Long centerId) {
this.actionName = "CLOSE";
this.entityName = "CENTER";
this.entityId = centerId;
this.groupId = centerId;
this.href = "/centers/" + centerId + "?command=close";
return this;
}
public CommandWrapperBuilder createAccountingRule() { public CommandWrapperBuilder createAccountingRule() {
this.actionName = "CREATE"; this.actionName = "CREATE";
this.entityName = "ACCOUNTINGRULE"; this.entityName = "ACCOUNTINGRULE";
@@ -464,6 +464,8 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
handler = this.applicationContext.getBean("assignGroupStaffCommandHandler", NewCommandSourceHandler.class); handler = this.applicationContext.getBean("assignGroupStaffCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isTransferClientsBetweenGroups()) { } else if (wrapper.isTransferClientsBetweenGroups()) {
handler = this.applicationContext.getBean("transferClientsBetweenGroupsCommandHandler", NewCommandSourceHandler.class); handler = this.applicationContext.getBean("transferClientsBetweenGroupsCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isGroupClose()) {
handler = this.applicationContext.getBean("closeGroupCommandHandler", NewCommandSourceHandler.class);
} else { } else {
throw new UnsupportedCommandException(wrapper.commandName()); throw new UnsupportedCommandException(wrapper.commandName());
} }
@@ -478,6 +480,8 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
handler = this.applicationContext.getBean("activateCenterCommandHandler", NewCommandSourceHandler.class); handler = this.applicationContext.getBean("activateCenterCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isSaveCenterCollectionSheet()) { } else if (wrapper.isSaveCenterCollectionSheet()) {
handler = this.applicationContext.getBean("saveCenterCollectionSheetCommandHandler", NewCommandSourceHandler.class); handler = this.applicationContext.getBean("saveCenterCollectionSheetCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isCenterClose()) {
handler = this.applicationContext.getBean("closeCenterCommandHandler", NewCommandSourceHandler.class);
} else { } else {
throw new UnsupportedCommandException(wrapper.commandName()); throw new UnsupportedCommandException(wrapper.commandName());
} }
@@ -28,6 +28,8 @@ import javax.persistence.Transient;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.infrastructure.codes.domain.CodeValue; import org.mifosplatform.infrastructure.codes.domain.CodeValue;
@@ -99,6 +101,7 @@ public final class Client extends AbstractPersistable<Long> {
@JoinColumn(name = "staff_id") @JoinColumn(name = "staff_id")
private Staff staff; private Staff staff;
@LazyCollection(LazyCollectionOption.FALSE)
@ManyToMany @ManyToMany
@JoinTable(name = "m_group_client", joinColumns = @JoinColumn(name = "client_id"), inverseJoinColumns = @JoinColumn(name = "group_id")) @JoinTable(name = "m_group_client", joinColumns = @JoinColumn(name = "client_id"), inverseJoinColumns = @JoinColumn(name = "group_id"))
private Set<Group> groups; private Set<Group> groups;
@@ -270,11 +273,15 @@ public final class Client extends AbstractPersistable<Long> {
return ClientStatus.fromInt(this.status).isActive(); return ClientStatus.fromInt(this.status).isActive();
} }
public boolean isClosed() {
return ClientStatus.fromInt(this.status).isClosed();
}
public boolean isTransferInProgress() { public boolean isTransferInProgress() {
return ClientStatus.fromInt(this.status).isTransferInProgress(); return ClientStatus.fromInt(this.status).isTransferInProgress();
} }
public boolean isTransferOnHold() { public boolean isTransferOnHold () {
return ClientStatus.fromInt(this.status).isTransferOnHold(); return ClientStatus.fromInt(this.status).isTransferOnHold();
} }
@@ -96,10 +96,17 @@ public class CentersApiResource {
@Path("template") @Path("template")
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String retrieveTemplate(@Context final UriInfo uriInfo, @QueryParam("officeId") final Long officeId) { public String retrieveTemplate(@Context final UriInfo uriInfo, @QueryParam("command") final String commandParam,
@QueryParam("officeId") final Long officeId) {
this.context.authenticatedUser().validateHasReadPermission(GroupingTypesApiConstants.CENTER_RESOURCE_NAME); this.context.authenticatedUser().validateHasReadPermission(GroupingTypesApiConstants.CENTER_RESOURCE_NAME);
if (is(commandParam, "close")) {
final CenterData centerClosureTemplate = this.centerReadPlatformService.retrieveCenterWithClosureReasons();
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.centerApiJsonSerializer.serialize(settings, centerClosureTemplate, GroupingTypesApiConstants.CENTER_RESPONSE_DATA_PARAMETERS);
}
final CenterData template = this.centerReadPlatformService.retrieveTemplate(officeId); final CenterData template = this.centerReadPlatformService.retrieveTemplate(officeId);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
@@ -229,6 +236,10 @@ public class CentersApiResource {
final CommandWrapper commandRequest = builder.saveCenterCollectionSheet(centerId).build(); final CommandWrapper commandRequest = builder.saveCenterCollectionSheet(centerId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result); return this.toApiJsonSerializer.serialize(result);
} else if (is(commandParam, "close")) {
final CommandWrapper commandRequest = builder.closeCenter(centerId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
} else { } else {
throw new UnrecognizedQueryParamException("command", commandParam, new Object[] { "activate", "generateCollectionSheet", throw new UnrecognizedQueryParamException("command", commandParam, new Object[] { "activate", "generateCollectionSheet",
"createRole" }); "createRole" });
@@ -21,11 +21,14 @@ public class GroupingTypesApiConstants {
public static final String GROUP_ROLE_RESOURCE_NAME = "grouprole"; public static final String GROUP_ROLE_RESOURCE_NAME = "grouprole";
public static final String GROUP_ROLE_NAME = "GROUPROLE"; public static final String GROUP_ROLE_NAME = "GROUPROLE";
public static final String GROUP_CLOSURE_REASON = "GroupClosureReason";
public static final String roleParamName = "role"; public static final String roleParamName = "role";
public static final String groupIdParamName = "groupId"; public static final String groupIdParamName = "groupId";
public static final String clientIdParamName = "clientId"; public static final String clientIdParamName = "clientId";
public static final String groupRolesParamName = "groupRoles"; public static final String groupRolesParamName = "groupRoles";
// general // general
public static final String localeParamName = "locale"; public static final String localeParamName = "locale";
public static final String dateFormatParamName = "dateFormat"; public static final String dateFormatParamName = "dateFormat";
@@ -54,6 +57,10 @@ public class GroupingTypesApiConstants {
public static final String clientOptionsParamName = "clientOptions"; public static final String clientOptionsParamName = "clientOptions";
public static final String collectionMeetingCalendar = "collectionMeetingCalendar"; public static final String collectionMeetingCalendar = "collectionMeetingCalendar";
//group close parameters
public static final String closureDateParamName = "closureDate";
public static final String closureReasonIdParamName = "closureReasonId";
public static final Set<String> CENTER_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName, public static final Set<String> CENTER_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
dateFormatParamName, idParamName, nameParamName, externalIdParamName, officeIdParamName, staffIdParamName, activeParamName, dateFormatParamName, idParamName, nameParamName, externalIdParamName, officeIdParamName, staffIdParamName, activeParamName,
activationDateParamName, groupMembersParamName)); activationDateParamName, groupMembersParamName));
@@ -87,4 +94,6 @@ public class GroupingTypesApiConstants {
public static final Set<String> COLLECTIONSHEET_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("dueDate", "loanProducts", "groups")); public static final Set<String> COLLECTIONSHEET_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("dueDate", "loanProducts", "groups"));
public static final Set<String> GROUP_CLOSE_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
dateFormatParamName, closureDateParamName, closureReasonIdParamName));
} }
@@ -117,10 +117,17 @@ public class GroupsApiResource {
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String retrieveTemplate(@Context final UriInfo uriInfo, @QueryParam("officeId") final Long officeId, public String retrieveTemplate(@Context final UriInfo uriInfo, @QueryParam("officeId") final Long officeId,
@QueryParam("center") final boolean isCenterGroup, @QueryParam("centerId") final Long centerId, @QueryParam("center") final boolean isCenterGroup, @QueryParam("centerId") final Long centerId,
@QueryParam("command") final String commandParam,
@DefaultValue("false") @QueryParam("staffInSelectedOfficeOnly") final boolean staffInSelectedOfficeOnly) { @DefaultValue("false") @QueryParam("staffInSelectedOfficeOnly") final boolean staffInSelectedOfficeOnly) {
this.context.authenticatedUser().validateHasReadPermission(GroupingTypesApiConstants.GROUP_RESOURCE_NAME); this.context.authenticatedUser().validateHasReadPermission(GroupingTypesApiConstants.GROUP_RESOURCE_NAME);
if (is(commandParam, "close")) {
final GroupGeneralData groupClosureTemplate = this.groupReadPlatformService.retrieveGroupWithClosureReasons();
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.groupGeneralApiJsonSerializer.serialize(settings, groupClosureTemplate, GroupingTypesApiConstants.GROUP_RESPONSE_DATA_PARAMETERS);
}
if (centerId != null) { if (centerId != null) {
final GroupGeneralData centerGroupTemplate = this.centerReadPlatformService.retrieveCenterGroupTemplate(centerId); final GroupGeneralData centerGroupTemplate = this.centerReadPlatformService.retrieveCenterGroupTemplate(centerId);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
@@ -344,6 +351,10 @@ public class GroupsApiResource {
final CommandWrapper commandRequest = builder.transferClientsBetweenGroups(groupId).build(); final CommandWrapper commandRequest = builder.transferClientsBetweenGroups(groupId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result); return this.toApiJsonSerializer.serialize(result);
} else if (is(commandParam, "close")) {
final CommandWrapper commandRequest = builder.closeGroup(groupId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
} else { } else {
throw new UnrecognizedQueryParamException("command", commandParam, new Object[] { "activate", "generateCollectionSheet", throw new UnrecognizedQueryParamException("command", commandParam, new Object[] { "activate", "generateCollectionSheet",
"saveCollectionSheet", "unassignStaff", "assignRole", "unassignRole", "updateassignRole" }); "saveCollectionSheet", "unassignStaff", "assignRole", "unassignRole", "updateassignRole" });
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.group.data;
import java.util.Collection; import java.util.Collection;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
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.office.data.OfficeData; import org.mifosplatform.organisation.office.data.OfficeData;
import org.mifosplatform.organisation.staff.data.StaffData; import org.mifosplatform.organisation.staff.data.StaffData;
@@ -42,18 +43,21 @@ public class CenterData {
private final Collection<StaffData> staffOptions; private final Collection<StaffData> staffOptions;
private final Collection<GroupGeneralData> groupMembersOptions; private final Collection<GroupGeneralData> groupMembersOptions;
private final CalendarData collectionMeetingCalendar; private final CalendarData collectionMeetingCalendar;
private final Collection<CodeValueData> closureReasons;
public static CenterData template(final Long officeId, final LocalDate activationDate, final Collection<OfficeData> officeOptions, public static CenterData template(final Long officeId, final LocalDate activationDate, final Collection<OfficeData> officeOptions,
final Collection<StaffData> staffOptions, final Collection<GroupGeneralData> groupMembersOptions) { final Collection<StaffData> staffOptions, final Collection<GroupGeneralData> groupMembersOptions) {
final CalendarData collectionMeetingCalendar = null; final CalendarData collectionMeetingCalendar = null;
final Collection<CodeValueData> closureReasons = null;
return new CenterData(null, null, null, null, activationDate, officeId, null, null, null, null, null, officeOptions, staffOptions, return new CenterData(null, null, null, null, activationDate, officeId, null, null, null, null, null, officeOptions, staffOptions,
groupMembersOptions, collectionMeetingCalendar); groupMembersOptions, collectionMeetingCalendar, closureReasons);
} }
public static CenterData withTemplate(final CenterData templateCenter, final CenterData center) { public static CenterData withTemplate(final CenterData templateCenter, final CenterData center) {
return new CenterData(center.id, center.name, center.externalId, center.status, center.activationDate, center.officeId, return new CenterData(center.id, center.name, center.externalId, center.status, center.activationDate, center.officeId,
center.officeName, center.staffId, center.staffName, center.hierarchy, center.groupMembers, templateCenter.officeOptions, center.officeName, center.staffId, center.staffName, center.hierarchy, center.groupMembers, templateCenter.officeOptions,
templateCenter.staffOptions, templateCenter.groupMembersOptions, templateCenter.collectionMeetingCalendar); templateCenter.staffOptions, templateCenter.groupMembersOptions, templateCenter.collectionMeetingCalendar,
templateCenter.closureReasons);
} }
public static CenterData instance(final Long id, final String name, final String externalId, final EnumOptionData status, public static CenterData instance(final Long id, final String name, final String externalId, final EnumOptionData status,
@@ -65,21 +69,43 @@ public class CenterData {
final Collection<StaffData> staffOptions = null; final Collection<StaffData> staffOptions = null;
final Collection<GroupGeneralData> groupMembersOptions = null; final Collection<GroupGeneralData> groupMembersOptions = null;
final CalendarData collectionMeetingCalendar = null; final CalendarData collectionMeetingCalendar = null;
final Collection<CodeValueData> closureReasons = null;
return new CenterData(id, name, externalId, status, activationDate, officeId, officeName, staffId, staffName, hierarchy, return new CenterData(id, name, externalId, status, activationDate, officeId, officeName, staffId, staffName, hierarchy,
groupMembers, officeOptions, staffOptions, groupMembersOptions, collectionMeetingCalendar); groupMembers, officeOptions, staffOptions, groupMembersOptions, collectionMeetingCalendar, closureReasons);
} }
public static CenterData withAssociations(final CenterData centerData, final Collection<GroupGeneralData> groupMembers, final CalendarData collectionMeetingCalendar) { public static CenterData withAssociations(final CenterData centerData, final Collection<GroupGeneralData> groupMembers, final CalendarData collectionMeetingCalendar) {
return new CenterData(centerData.id, centerData.name, centerData.externalId, centerData.status, centerData.activationDate, return new CenterData(centerData.id, centerData.name, centerData.externalId, centerData.status, centerData.activationDate,
centerData.officeId, centerData.officeName, centerData.staffId, centerData.staffName, centerData.hierarchy, groupMembers, centerData.officeId, centerData.officeName, centerData.staffId, centerData.staffName, centerData.hierarchy, groupMembers,
centerData.officeOptions, centerData.staffOptions, centerData.groupMembersOptions, collectionMeetingCalendar); centerData.officeOptions, centerData.staffOptions, centerData.groupMembersOptions, collectionMeetingCalendar, centerData.closureReasons);
}
public static CenterData withClosureReasons(final Collection<CodeValueData> closureReasons) {
final Long id = null;
final String name = null;
final String externalId = null;
final EnumOptionData status = null;
final LocalDate activationDate = null;
final Long officeId = null;
final String officeName = null;
final Long staffId = null;
final String staffName = null;
final String hierarchy = null;
final Collection<GroupGeneralData> groupMembers = null;
final Collection<OfficeData> officeOptions = null;
final Collection<StaffData> staffOptions = null;
final Collection<GroupGeneralData> groupMembersOptions = null;
final CalendarData collectionMeetingCalendar = null;
return new CenterData(id, name, externalId, status, activationDate, officeId, officeName, staffId, staffName, hierarchy,
groupMembers, officeOptions, staffOptions, groupMembersOptions, collectionMeetingCalendar, closureReasons);
} }
private CenterData(final Long id, final String name, final String externalId, final EnumOptionData status, private CenterData(final Long id, final String name, final String externalId, final EnumOptionData status,
final LocalDate activationDate, final Long officeId, final String officeName, final Long staffId, final String staffName, final LocalDate activationDate, final Long officeId, final String officeName, final Long staffId, final String staffName,
final String hierarchy, final Collection<GroupGeneralData> groupMembers, final Collection<OfficeData> officeOptions, final String hierarchy, final Collection<GroupGeneralData> groupMembers, final Collection<OfficeData> officeOptions,
final Collection<StaffData> staffOptions, final Collection<GroupGeneralData> groupMembersOptions, final CalendarData collectionMeetingCalendar) { final Collection<StaffData> staffOptions, final Collection<GroupGeneralData> groupMembersOptions,
final CalendarData collectionMeetingCalendar, final Collection<CodeValueData> closureReasons) {
this.id = id; this.id = id;
this.name = name; this.name = name;
this.externalId = externalId; this.externalId = externalId;
@@ -103,6 +129,7 @@ public class CenterData {
this.staffOptions = staffOptions; this.staffOptions = staffOptions;
this.groupMembersOptions = groupMembersOptions; this.groupMembersOptions = groupMembersOptions;
this.collectionMeetingCalendar = collectionMeetingCalendar; this.collectionMeetingCalendar = collectionMeetingCalendar;
this.closureReasons = closureReasons;
} }
public Long officeId() { public Long officeId() {
@@ -51,13 +51,14 @@ public class GroupGeneralData {
private final Collection<ClientData> clientOptions; private final Collection<ClientData> clientOptions;
private final Collection<CodeValueData> availableRoles; private final Collection<CodeValueData> availableRoles;
private final GroupRoleData selectedRole; private final GroupRoleData selectedRole;
private final Collection<CodeValueData> closureReasons;
public static GroupGeneralData lookup(final Long groupId, final String groupName) { public static GroupGeneralData lookup(final Long groupId, final String groupName) {
final Collection<ClientData> clientMembers = null; final Collection<ClientData> clientMembers = null;
final Collection<GroupRoleData> groupRoles = null; final Collection<GroupRoleData> groupRoles = null;
final Collection<CodeValueData> closureReasons = null;
return new GroupGeneralData(groupId, groupName, null, null, null, null, null, null, null, null, null, null, clientMembers, null, return new GroupGeneralData(groupId, groupName, null, null, null, null, null, null, null, null, null, null, clientMembers, null,
null, null, null, groupRoles, null, null, null, null); null, null, null, groupRoles, null, null, null, null, closureReasons);
} }
public static GroupGeneralData template(final Long officeId, final Long centerId, final String centerName, final Long staffId, public static GroupGeneralData template(final Long officeId, final Long centerId, final String centerName, final Long staffId,
@@ -67,9 +68,10 @@ public class GroupGeneralData {
final Collection<ClientData> clientMembers = null; final Collection<ClientData> clientMembers = null;
final Collection<GroupRoleData> groupRoles = null; final Collection<GroupRoleData> groupRoles = null;
final Collection<CodeValueData> closureReasons = null;
return new GroupGeneralData(null, null, null, null, null, officeId, null, centerId, centerName, staffId, staffName, null, return new GroupGeneralData(null, null, null, null, null, officeId, null, centerId, centerName, staffId, staffName, null,
clientMembers, centerOptions, officeOptions, staffOptions, clientOptions, groupRoles, availableRoles, null, null, null); clientMembers, centerOptions, officeOptions, staffOptions, clientOptions, groupRoles, availableRoles, null, null, null, closureReasons);
} }
public static GroupGeneralData withTemplate(final GroupGeneralData templatedGrouping, final GroupGeneralData grouping) { public static GroupGeneralData withTemplate(final GroupGeneralData templatedGrouping, final GroupGeneralData grouping) {
@@ -77,7 +79,7 @@ public class GroupGeneralData {
grouping.officeId, grouping.officeName, grouping.centerId, grouping.centerName, grouping.staffId, grouping.staffName, grouping.officeId, grouping.officeName, grouping.centerId, grouping.centerName, grouping.staffId, grouping.staffName,
grouping.hierarchy, grouping.clientMembers, templatedGrouping.centerOptions, templatedGrouping.officeOptions, grouping.hierarchy, grouping.clientMembers, templatedGrouping.centerOptions, templatedGrouping.officeOptions,
templatedGrouping.staffOptions, templatedGrouping.clientOptions, grouping.groupRoles, templatedGrouping.availableRoles, templatedGrouping.staffOptions, templatedGrouping.clientOptions, grouping.groupRoles, templatedGrouping.availableRoles,
grouping.selectedRole, grouping.calendarsData, grouping.collectionMeetingCalendar); grouping.selectedRole, grouping.calendarsData, grouping.collectionMeetingCalendar, grouping.closureReasons);
} }
public static GroupGeneralData withAssocations(final GroupGeneralData grouping, final Collection<ClientData> membersOfGroup, public static GroupGeneralData withAssocations(final GroupGeneralData grouping, final Collection<ClientData> membersOfGroup,
@@ -85,7 +87,7 @@ public class GroupGeneralData {
return new GroupGeneralData(grouping.id, grouping.name, grouping.externalId, grouping.status, grouping.activationDate, return new GroupGeneralData(grouping.id, grouping.name, grouping.externalId, grouping.status, grouping.activationDate,
grouping.officeId, grouping.officeName, grouping.centerId, grouping.centerName, grouping.staffId, grouping.staffName, grouping.officeId, grouping.officeName, grouping.centerId, grouping.centerName, grouping.staffId, grouping.staffName,
grouping.hierarchy, membersOfGroup, grouping.centerOptions, grouping.officeOptions, grouping.staffOptions, grouping.hierarchy, membersOfGroup, grouping.centerOptions, grouping.officeOptions, grouping.staffOptions,
grouping.clientOptions, groupRoles, grouping.availableRoles, grouping.selectedRole, calendarsData, collectionMeetingCalendar); grouping.clientOptions, groupRoles, grouping.availableRoles, grouping.selectedRole, calendarsData, collectionMeetingCalendar, grouping.closureReasons);
} }
public static GroupGeneralData instance(final Long id, final String name, final String externalId, final EnumOptionData status, public static GroupGeneralData instance(final Long id, final String name, final String externalId, final EnumOptionData status,
@@ -102,10 +104,11 @@ public class GroupGeneralData {
final GroupRoleData role = null; final GroupRoleData role = null;
final Collection<CalendarData> calendarsData = null; final Collection<CalendarData> calendarsData = null;
final CalendarData collectionMeetingCalendar = null; final CalendarData collectionMeetingCalendar = null;
final Collection<CodeValueData> closureReasons = null;
return new GroupGeneralData(id, name, externalId, status, activationDate, officeId, officeName, centerId, centerName, staffId, return new GroupGeneralData(id, name, externalId, status, activationDate, officeId, officeName, centerId, centerName, staffId,
staffName, hierarchy, clientMembers, centerOptions, officeOptions, staffOptions, clientOptions, groupRoles, availableRoles, staffName, hierarchy, clientMembers, centerOptions, officeOptions, staffOptions, clientOptions, groupRoles, availableRoles,
role, calendarsData, collectionMeetingCalendar); role, calendarsData, collectionMeetingCalendar, closureReasons);
} }
private GroupGeneralData(final Long id, final String name, final String externalId, final EnumOptionData status, private GroupGeneralData(final Long id, final String name, final String externalId, final EnumOptionData status,
@@ -114,7 +117,7 @@ public class GroupGeneralData {
final Collection<CenterData> centerOptions, final Collection<OfficeData> officeOptions, final Collection<CenterData> centerOptions, final Collection<OfficeData> officeOptions,
final Collection<StaffData> staffOptions, final Collection<ClientData> clientOptions, final Collection<StaffData> staffOptions, final Collection<ClientData> clientOptions,
final Collection<GroupRoleData> groupRoles, final Collection<CodeValueData> availableRoles, final GroupRoleData role, final Collection<GroupRoleData> groupRoles, final Collection<CodeValueData> availableRoles, final GroupRoleData role,
final Collection<CalendarData> calendarsData, final CalendarData collectionMeetingCalendar) { final Collection<CalendarData> calendarsData, final CalendarData collectionMeetingCalendar, final Collection<CodeValueData> closureReasons) {
this.id = id; this.id = id;
this.name = name; this.name = name;
this.externalId = externalId; this.externalId = externalId;
@@ -151,6 +154,7 @@ public class GroupGeneralData {
this.selectedRole = role; this.selectedRole = role;
this.calendarsData = calendarsData; this.calendarsData = calendarsData;
this.collectionMeetingCalendar = collectionMeetingCalendar; this.collectionMeetingCalendar = collectionMeetingCalendar;
this.closureReasons = closureReasons;
} }
public Long getId() { public Long getId() {
@@ -182,7 +186,35 @@ public class GroupGeneralData {
return new GroupGeneralData(grouping.id, grouping.name, grouping.externalId, grouping.status, grouping.activationDate, return new GroupGeneralData(grouping.id, grouping.name, grouping.externalId, grouping.status, grouping.activationDate,
grouping.officeId, grouping.officeName, grouping.centerId, grouping.centerName, grouping.staffId, grouping.staffName, grouping.officeId, grouping.officeName, grouping.centerId, grouping.centerName, grouping.staffId, grouping.staffName,
grouping.hierarchy, grouping.clientMembers, grouping.centerOptions, grouping.officeOptions, grouping.staffOptions, grouping.hierarchy, grouping.clientMembers, grouping.centerOptions, grouping.officeOptions, grouping.staffOptions,
grouping.clientOptions, grouping.groupRoles, grouping.availableRoles, selectedRole, grouping.calendarsData, grouping.collectionMeetingCalendar); grouping.clientOptions, grouping.groupRoles, grouping.availableRoles, selectedRole, grouping.calendarsData, grouping.collectionMeetingCalendar, grouping.closureReasons);
} }
public static GroupGeneralData withClosureReasons(final Collection<CodeValueData> closureReasons) {
final Long id = null;
final String name = null;
final String externalId = null;
final EnumOptionData status = null;
final LocalDate activationDate = null;
final Long officeId = null;
final String officeName = null;
final Long centerId = null;
final String centerName = null;
final Long staffId = null;
final String staffName = null;
final String hierarchy = null;
final Collection<ClientData> clientMembers = null;
final Collection<CenterData> centerOptions = null;
final Collection<OfficeData> officeOptions = null;
final Collection<StaffData> staffOptions = null;
final Collection<ClientData> clientOptions = null;
final Collection<GroupRoleData> groupRoles = null;
final Collection<CodeValueData> availableRoles = null;
final GroupRoleData role = null;
final Collection<CalendarData> calendarsData = null;
final CalendarData collectionMeetingCalendar = null;
return new GroupGeneralData(id, name, externalId, status, activationDate, officeId, officeName, centerId, centerName, staffId,
staffName, hierarchy, clientMembers, centerOptions, officeOptions, staffOptions, clientOptions, groupRoles, availableRoles,
role, calendarsData, collectionMeetingCalendar, closureReasons);
}
} }
@@ -31,6 +31,7 @@ import javax.persistence.TemporalType;
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.DateTimeFormatter; import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.ApiParameterError; import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
@@ -41,6 +42,7 @@ import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.group.api.GroupingTypesApiConstants; import org.mifosplatform.portfolio.group.api.GroupingTypesApiConstants;
import org.mifosplatform.portfolio.group.exception.ClientExistInGroupException; import org.mifosplatform.portfolio.group.exception.ClientExistInGroupException;
import org.mifosplatform.portfolio.group.exception.ClientNotInGroupException; import org.mifosplatform.portfolio.group.exception.ClientNotInGroupException;
import org.mifosplatform.portfolio.group.exception.InvalidGroupStateTransitionException;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.springframework.data.jpa.domain.AbstractPersistable;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
@@ -96,6 +98,14 @@ public final class Group extends AbstractPersistable<Long> {
@JoinTable(name = "m_group_client", joinColumns = @JoinColumn(name = "group_id"), inverseJoinColumns = @JoinColumn(name = "client_id")) @JoinTable(name = "m_group_client", joinColumns = @JoinColumn(name = "group_id"), inverseJoinColumns = @JoinColumn(name = "client_id"))
private Set<Client> clientMembers; private Set<Client> clientMembers;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "closure_reason_cv_id", nullable = true)
private CodeValue closureReason;
@Column(name = "closedon_date", nullable = true)
@Temporal(TemporalType.DATE)
private Date closureDate;
public Group() { public Group() {
this.name = null; this.name = null;
this.externalId = null; this.externalId = null;
@@ -409,5 +419,41 @@ public final class Group extends AbstractPersistable<Long> {
public boolean isChildGroup(){ public boolean isChildGroup(){
return (this.parent == null) ? false : true; return (this.parent == null) ? false : true;
}
public boolean isClosed(){
return GroupingTypeStatus.fromInt(this.status).isClosed();
}
public void close(final CodeValue closureReason, final LocalDate closureDate){
if (this.isClosed()) {
final String errorMessage = "Group with identifier " + this.getId() + " is alread closed.";
throw new InvalidGroupStateTransitionException(this.groupLevel.getLevelName(), "close", "already.closed", errorMessage, this.getId());
}
if (this.isNotPending() && this.getActivationLocalDate().isAfter(closureDate)) {
final String errorMessage = "The Group closure Date " + closureDate + " cannot be before the group Activation Date " + this.getActivationLocalDate() + ".";
throw new InvalidGroupStateTransitionException(this.groupLevel.getLevelName(), "close", "date.cannot.before.group.actvation.date", errorMessage, closureDate, this.getActivationLocalDate());
}
this.closureReason = closureReason;
this.closureDate = closureDate.toDate();
this.status = GroupingTypeStatus.CLOSED.getValue();
}
public boolean hasActiveClients(){
for (Client client : this.clientMembers) {
if(!client.isClosed()) return true;
}
return false;
}
public boolean hasActiveGroups(){
for(Group group : this.groupMembers){
if(!group.isClosed()) return true;
}
return false;
} }
} }
@@ -33,6 +33,14 @@ public class GroupingTypeEnumerations {
optionData = new EnumOptionData(GroupingTypeStatus.CLOSED.getValue().longValue(), GroupingTypeStatus.CLOSED.getCode(), optionData = new EnumOptionData(GroupingTypeStatus.CLOSED.getValue().longValue(), GroupingTypeStatus.CLOSED.getCode(),
"Closed"); "Closed");
break; break;
case TRANSFER_IN_PROGRESS:
optionData = new EnumOptionData(GroupingTypeStatus.TRANSFER_IN_PROGRESS.getValue().longValue(), GroupingTypeStatus.TRANSFER_IN_PROGRESS.getCode(),
"Transfer in progress");
break;
case TRANSFER_ON_HOLD:
optionData = new EnumOptionData(GroupingTypeStatus.TRANSFER_ON_HOLD.getValue().longValue(), GroupingTypeStatus.TRANSFER_ON_HOLD.getCode(),
"Transfer on hold");
break;
} }
return optionData; return optionData;
@@ -0,0 +1,27 @@
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 CloseCenterCommandHandler implements NewCommandSourceHandler {
private final GroupingTypesWritePlatformService groupingTypesWritePlatformService;
@Autowired
public CloseCenterCommandHandler(final GroupingTypesWritePlatformService groupingTypesWritePlatformService) {
this.groupingTypesWritePlatformService = groupingTypesWritePlatformService;
}
@Override
@Transactional
public CommandProcessingResult processCommand(JsonCommand command) {
return this.groupingTypesWritePlatformService.closeCenter(command.entityId(), command);
}
}
@@ -0,0 +1,27 @@
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 CloseGroupCommandHandler implements NewCommandSourceHandler {
private final GroupingTypesWritePlatformService groupingTypesWritePlatformService;
@Autowired
public CloseGroupCommandHandler(final GroupingTypesWritePlatformService groupingTypesWritePlatformService) {
this.groupingTypesWritePlatformService = groupingTypesWritePlatformService;
}
@Override
@Transactional
public CommandProcessingResult processCommand(JsonCommand command) {
return this.groupingTypesWritePlatformService.closeGroup(command.entityId(), command);
}
}
@@ -406,4 +406,52 @@ public final class GroupingTypesDataValidator {
throwExceptionIfValidationWarningsExist(dataValidationErrors); throwExceptionIfValidationWarningsExist(dataValidationErrors);
} }
public void validateForGroupClose(final JsonCommand command) {
final String json = command.json();
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, GroupingTypesApiConstants.GROUP_CLOSE_REQUEST_DATA_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(GroupingTypesApiConstants.GROUP_RESOURCE_NAME);
final JsonElement element = command.parsedJson();
final LocalDate closureDate = this.fromApiJsonHelper.extractLocalDateNamed(GroupingTypesApiConstants.closureDateParamName, element);
baseDataValidator.reset().parameter(GroupingTypesApiConstants.closureDateParamName).value(closureDate).notNull();
final Long closureReasonId = this.fromApiJsonHelper.extractLongNamed(GroupingTypesApiConstants.closureReasonIdParamName, element);
baseDataValidator.reset().parameter(GroupingTypesApiConstants.closureReasonIdParamName).value(closureReasonId).notNull().longGreaterThanZero();
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateForCenterClose(final JsonCommand command) {
final String json = command.json();
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, GroupingTypesApiConstants.GROUP_CLOSE_REQUEST_DATA_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(GroupingTypesApiConstants.CENTER_RESOURCE_NAME);
final JsonElement element = command.parsedJson();
final LocalDate closureDate = this.fromApiJsonHelper.extractLocalDateNamed(GroupingTypesApiConstants.closureDateParamName, element);
baseDataValidator.reset().parameter(GroupingTypesApiConstants.closureDateParamName).value(closureDate).notNull();
final Long closureReasonId = this.fromApiJsonHelper.extractLongNamed(GroupingTypesApiConstants.closureReasonIdParamName, element);
baseDataValidator.reset().parameter(GroupingTypesApiConstants.closureReasonIdParamName).value(closureReasonId).notNull().longGreaterThanZero();
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
} }
@@ -24,4 +24,6 @@ public interface CenterReadPlatformService {
GroupGeneralData retrieveCenterGroupTemplate(Long centerId); GroupGeneralData retrieveCenterGroupTemplate(Long centerId);
Collection<GroupGeneralData> retrieveAssociatedGroups(Long centerId); Collection<GroupGeneralData> retrieveAssociatedGroups(Long centerId);
CenterData retrieveCenterWithClosureReasons();
} }
@@ -7,11 +7,15 @@ package org.mifosplatform.portfolio.group.service;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
import org.mifosplatform.infrastructure.codes.service.CodeValueReadPlatformService;
import org.mifosplatform.infrastructure.core.api.ApiParameterHelper; import org.mifosplatform.infrastructure.core.api.ApiParameterHelper;
import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.infrastructure.core.domain.JdbcSupport; import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
@@ -26,6 +30,7 @@ import org.mifosplatform.organisation.staff.service.StaffReadPlatformService;
import org.mifosplatform.portfolio.client.data.ClientData; import org.mifosplatform.portfolio.client.data.ClientData;
import org.mifosplatform.portfolio.client.domain.ClientEnumerations; import org.mifosplatform.portfolio.client.domain.ClientEnumerations;
import org.mifosplatform.portfolio.client.service.ClientReadPlatformService; import org.mifosplatform.portfolio.client.service.ClientReadPlatformService;
import org.mifosplatform.portfolio.group.api.GroupingTypesApiConstants;
import org.mifosplatform.portfolio.group.data.CenterData; import org.mifosplatform.portfolio.group.data.CenterData;
import org.mifosplatform.portfolio.group.data.GroupGeneralData; import org.mifosplatform.portfolio.group.data.GroupGeneralData;
import org.mifosplatform.portfolio.group.domain.GroupTypes; import org.mifosplatform.portfolio.group.domain.GroupTypes;
@@ -47,6 +52,7 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
private final ClientReadPlatformService clientReadPlatformService; private final ClientReadPlatformService clientReadPlatformService;
private final OfficeReadPlatformService officeReadPlatformService; private final OfficeReadPlatformService officeReadPlatformService;
private final StaffReadPlatformService staffReadPlatformService; private final StaffReadPlatformService staffReadPlatformService;
private final CodeValueReadPlatformService codeValueReadPlatformService;
// data mappers // data mappers
private final AllGroupTypesDataMapper allGroupTypesDataMapper = new AllGroupTypesDataMapper(); private final AllGroupTypesDataMapper allGroupTypesDataMapper = new AllGroupTypesDataMapper();
@@ -60,12 +66,13 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
@Autowired @Autowired
public CenterReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource, public CenterReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
final ClientReadPlatformService clientReadPlatformService, final OfficeReadPlatformService officeReadPlatformService, final ClientReadPlatformService clientReadPlatformService, final OfficeReadPlatformService officeReadPlatformService,
final StaffReadPlatformService staffReadPlatformService) { final StaffReadPlatformService staffReadPlatformService, final CodeValueReadPlatformService codeValueReadPlatformService) {
this.context = context; this.context = context;
this.clientReadPlatformService = clientReadPlatformService; this.clientReadPlatformService = clientReadPlatformService;
this.jdbcTemplate = new JdbcTemplate(dataSource); this.jdbcTemplate = new JdbcTemplate(dataSource);
this.officeReadPlatformService = officeReadPlatformService; this.officeReadPlatformService = officeReadPlatformService;
this.staffReadPlatformService = staffReadPlatformService; this.staffReadPlatformService = staffReadPlatformService;
this.codeValueReadPlatformService = codeValueReadPlatformService;
} }
// 'g.' preffix because of ERROR 1052 (23000): Column 'column_name' in where // 'g.' preffix because of ERROR 1052 (23000): Column 'column_name' in where
@@ -331,4 +338,11 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
String sql = "select " + this.groupDataMapper.schema() + " where g.parent_id = ? "; String sql = "select " + this.groupDataMapper.schema() + " where g.parent_id = ? ";
return this.jdbcTemplate.query(sql, this.groupDataMapper, new Object[] { centerId }); return this.jdbcTemplate.query(sql, this.groupDataMapper, new Object[] { centerId });
} }
@Override
public CenterData retrieveCenterWithClosureReasons() {
final List<CodeValueData> closureReasons = new ArrayList<CodeValueData>(
codeValueReadPlatformService.retrieveCodeValuesByCode(GroupingTypesApiConstants.GROUP_CLOSURE_REASON));
return CenterData.withClosureReasons(closureReasons);
}
} }
@@ -19,4 +19,6 @@ public interface GroupReadPlatformService {
GroupGeneralData retrieveOne(Long groupId); GroupGeneralData retrieveOne(Long groupId);
Collection<GroupGeneralData> retrieveGroupsForLookup(Long officeId); Collection<GroupGeneralData> retrieveGroupsForLookup(Long officeId);
GroupGeneralData retrieveGroupWithClosureReasons();
} }
@@ -7,7 +7,9 @@ package org.mifosplatform.portfolio.group.service;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.mifosplatform.infrastructure.codes.data.CodeValueData; import org.mifosplatform.infrastructure.codes.data.CodeValueData;
@@ -227,4 +229,11 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService {
} }
} }
@Override
public GroupGeneralData retrieveGroupWithClosureReasons() {
final List<CodeValueData> closureReasons = new ArrayList<CodeValueData>(
codeValueReadPlatformService.retrieveCodeValuesByCode(GroupingTypesApiConstants.GROUP_CLOSURE_REASON));
return GroupGeneralData.withClosureReasons(closureReasons);
}
} }
@@ -22,6 +22,10 @@ public interface GroupingTypesWritePlatformService {
CommandProcessingResult deleteGroup(Long groupId); CommandProcessingResult deleteGroup(Long groupId);
CommandProcessingResult closeGroup(final Long groupId, final JsonCommand command);
CommandProcessingResult closeCenter(final Long centerId, final JsonCommand command);
CommandProcessingResult unassignGroupOrCenterStaff(Long groupId, JsonCommand command); CommandProcessingResult unassignGroupOrCenterStaff(Long groupId, JsonCommand command);
CommandProcessingResult assignGroupOrCenterStaff(Long groupId, JsonCommand command); CommandProcessingResult assignGroupOrCenterStaff(Long groupId, JsonCommand command);
@@ -17,6 +17,8 @@ import java.util.Set;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.mifosplatform.infrastructure.codes.domain.CodeValueRepositoryWrapper;
import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder; import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
@@ -30,6 +32,7 @@ import org.mifosplatform.organisation.staff.domain.Staff;
import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper; import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper;
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.service.LoanStatusMapper;
import org.mifosplatform.portfolio.group.api.GroupingTypesApiConstants; import org.mifosplatform.portfolio.group.api.GroupingTypesApiConstants;
import org.mifosplatform.portfolio.group.domain.Group; import org.mifosplatform.portfolio.group.domain.Group;
import org.mifosplatform.portfolio.group.domain.GroupLevel; import org.mifosplatform.portfolio.group.domain.GroupLevel;
@@ -64,24 +67,26 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
private final GroupRepositoryWrapper groupRepository; private final GroupRepositoryWrapper groupRepository;
private final ClientRepositoryWrapper clientRepository; private final ClientRepositoryWrapper clientRepositoryWrapper;
private final OfficeRepository officeRepository; private final OfficeRepository officeRepository;
private final StaffRepositoryWrapper staffRepository; private final StaffRepositoryWrapper staffRepository;
private final NoteRepository noteRepository; private final NoteRepository noteRepository;
private final GroupLevelRepository groupLevelRepository; private final GroupLevelRepository groupLevelRepository;
private final GroupingTypesDataValidator fromApiJsonDeserializer; private final GroupingTypesDataValidator fromApiJsonDeserializer;
private final LoanRepository loanRepository; private final LoanRepository loanRepository;
private final CodeValueRepositoryWrapper codeValueRepository;
private final SavingsAccountRepository savingsRepository; private final SavingsAccountRepository savingsRepository;
@Autowired @Autowired
public GroupingTypesWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, public GroupingTypesWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
final GroupRepositoryWrapper groupRepository, final ClientRepositoryWrapper clientRepository, final GroupRepositoryWrapper groupRepository, final ClientRepositoryWrapper clientRepositoryWrapper,
final OfficeRepository officeRepository, final StaffRepositoryWrapper staffRepository, final NoteRepository noteRepository, final OfficeRepository officeRepository, final StaffRepositoryWrapper staffRepository,
final GroupLevelRepository groupLevelRepository, final GroupingTypesDataValidator fromApiJsonDeserializer, final NoteRepository noteRepository, final GroupLevelRepository groupLevelRepository,
final LoanRepository loanRepository, final SavingsAccountRepository savingsRepository) { final GroupingTypesDataValidator fromApiJsonDeserializer, final LoanRepository loanRepository,
final SavingsAccountRepository savingsRepository, final CodeValueRepositoryWrapper codeValueRepository) {
this.context = context; this.context = context;
this.groupRepository = groupRepository; this.groupRepository = groupRepository;
this.clientRepository = clientRepository; this.clientRepositoryWrapper = clientRepositoryWrapper;
this.officeRepository = officeRepository; this.officeRepository = officeRepository;
this.staffRepository = staffRepository; this.staffRepository = staffRepository;
this.noteRepository = noteRepository; this.noteRepository = noteRepository;
@@ -89,6 +94,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.fromApiJsonDeserializer = fromApiJsonDeserializer;
this.loanRepository = loanRepository; this.loanRepository = loanRepository;
this.savingsRepository = savingsRepository; this.savingsRepository = savingsRepository;
this.codeValueRepository = codeValueRepository;
} }
private CommandProcessingResult createGroupingType(final JsonCommand command, final GroupTypes groupingType, final Long centerId) { private CommandProcessingResult createGroupingType(final JsonCommand command, final GroupTypes groupingType, final Long centerId) {
@@ -403,6 +409,99 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
.build(); .build();
} }
@Override
public CommandProcessingResult closeGroup(Long groupId, JsonCommand command) {
this.fromApiJsonDeserializer.validateForGroupClose(command);
final Group group = this.groupRepository.findOneWithNotFoundDetection(groupId);
final LocalDate closureDate = command.localDateValueOfParameterNamed(GroupingTypesApiConstants.closureDateParamName);
final Long closureReasonId = command.longValueOfParameterNamed(GroupingTypesApiConstants.closureReasonIdParamName);
CodeValue closureReason = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(
GroupingTypesApiConstants.GROUP_CLOSURE_REASON, closureReasonId);
if(group.hasActiveClients()){
final String errorMessage = group.getGroupLevel().getLevelName() + " cannot be closed because of active clients associated with it.";
throw new InvalidGroupStateTransitionException(group.getGroupLevel().getLevelName(), "close", "active.clients.exist",
errorMessage);
}
validateLoansAndSavingsForGroupOrCenterClose(group, closureDate);
group.close(closureReason, closureDate);
this.groupRepository.saveAndFlush(group);
return new CommandProcessingResultBuilder() //
.withGroupId(groupId) //
.withEntityId(groupId) //
.build();
}
private void validateLoansAndSavingsForGroupOrCenterClose(final Group groupOrCenter, final LocalDate closureDate) {
Collection<Loan> groupLoans = this.loanRepository.findByGroupId(groupOrCenter.getId());
for (Loan loan : groupLoans) {
LoanStatusMapper loanStatus = new LoanStatusMapper(loan.status().getValue());
if (loanStatus.isOpen()) {
final String errorMessage = groupOrCenter.getGroupLevel().getLevelName() + " cannot be closed because of non-closed loans.";
throw new InvalidGroupStateTransitionException(groupOrCenter.getGroupLevel().getLevelName(), "close", "loan.not.closed",
errorMessage);
} else if (loanStatus.isClosed() && loan.getClosedOnDate().after(closureDate.toDate())) {
final String errorMessage = groupOrCenter.getGroupLevel().getLevelName() + "closureDate cannot be before the loan closedOnDate.";
throw new InvalidGroupStateTransitionException(groupOrCenter.getGroupLevel().getLevelName(), "close",
"date.cannot.before.loan.closed.date", errorMessage, closureDate, loan.getClosedOnDate());
} else if (loanStatus.isPendingApproval()) {
final String errorMessage = groupOrCenter.getGroupLevel().getLevelName() + " cannot be closed because of non-closed loans.";
throw new InvalidGroupStateTransitionException(groupOrCenter.getGroupLevel().getLevelName(), "close", "loan.not.closed",
errorMessage);
} else if (loanStatus.isAwaitingDisbursal()) {
final String errorMessage = "Group cannot be closed because of non-closed loans.";
throw new InvalidGroupStateTransitionException(groupOrCenter.getGroupLevel().getLevelName(), "close", "loan.not.closed",
errorMessage);
}
}
List<SavingsAccount> groupSavingAccounts = this.savingsRepository.findByGroupId(groupOrCenter.getId());
for (SavingsAccount saving : groupSavingAccounts) {
if (saving.isActive() || saving.isSubmittedAndPendingApproval() || saving.isApproved()) {
final String errorMessage = groupOrCenter.getGroupLevel().getLevelName() + " cannot be closed with active savings accounts associated.";
throw new InvalidGroupStateTransitionException(groupOrCenter.getGroupLevel().getLevelName(), "close", "savings.account.not.closed",
errorMessage);
} else if (saving.isClosed() && saving.getClosedOnDate().isAfter(closureDate)) {
final String errorMessage = groupOrCenter.getGroupLevel().getLevelName() + " closureDate cannot be before the loan closedOnDate.";
throw new InvalidGroupStateTransitionException(groupOrCenter.getGroupLevel().getLevelName(), "close",
"date.cannot.before.loan.closed.date", errorMessage, closureDate, saving.getClosedOnDate());
}
}
}
@Override
public CommandProcessingResult closeCenter(Long centerId, JsonCommand command) {
this.fromApiJsonDeserializer.validateForCenterClose(command);
final Group center = this.groupRepository.findOneWithNotFoundDetection(centerId);
final LocalDate closureDate = command.localDateValueOfParameterNamed(GroupingTypesApiConstants.closureDateParamName);
final Long closureReasonId = command.longValueOfParameterNamed(GroupingTypesApiConstants.closureReasonIdParamName);
CodeValue closureReason = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(
GroupingTypesApiConstants.GROUP_CLOSURE_REASON, closureReasonId);
if(center.hasActiveGroups()){
final String errorMessage = center.getGroupLevel().getLevelName() + " cannot be closed because of active groups associated with it.";
throw new InvalidGroupStateTransitionException(center.getGroupLevel().getLevelName(), "close", "active.groups.exist",
errorMessage);
}
validateLoansAndSavingsForGroupOrCenterClose(center, closureDate);
center.close(closureReason, closureDate);
this.groupRepository.saveAndFlush(center);
return new CommandProcessingResultBuilder() //
.withEntityId(centerId) //
.build();
}
private Set<Client> assembleSetOfClients(final Long groupOfficeId, final JsonCommand command) { private Set<Client> assembleSetOfClients(final Long groupOfficeId, final JsonCommand command) {
final Set<Client> clientMembers = new HashSet<Client>(); final Set<Client> clientMembers = new HashSet<Client>();
@@ -411,7 +510,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
if (!ObjectUtils.isEmpty(clientMembersArray)) { if (!ObjectUtils.isEmpty(clientMembersArray)) {
for (final String clientId : clientMembersArray) { for (final String clientId : clientMembersArray) {
final Long id = Long.valueOf(clientId); final Long id = Long.valueOf(clientId);
final Client client = this.clientRepository.findOneWithNotFoundDetection(id); final Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(id);
if (!client.isOfficeIdentifiedBy(groupOfficeId)) { if (!client.isOfficeIdentifiedBy(groupOfficeId)) {
final String errorMessage = "Client with identifier " + clientId + " must have the same office as group."; final String errorMessage = "Client with identifier " + clientId + " must have the same office as group.";
throw new InvalidOfficeException("client", "attach.to.group", errorMessage, clientId, groupOfficeId); throw new InvalidOfficeException("client", "attach.to.group", errorMessage, clientId, groupOfficeId);
@@ -95,6 +95,9 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat
@Query("from Loan loan where loan.client.id = :clientId") @Query("from Loan loan where loan.client.id = :clientId")
List<Loan> findLoanByClientId(@Param("clientId") Long clientId); List<Loan> findLoanByClientId(@Param("clientId") Long clientId);
@Query("from Loan loan where loan.group.id = :groupId and loan.client.id is null")
List<Loan> findByGroupId(@Param("groupId") Long groupId);
@Query("from Loan loan where loan.id IN :ids and loan.loanStatus IN :loanStatuses and loan.loanType IN :loanTypes") @Query("from Loan loan where loan.id IN :ids and loan.loanStatus IN :loanStatuses and loan.loanType IN :loanTypes")
List<Loan> findByIdsAndLoanStatusAndLoanType(@Param("ids") Collection<Long> ids, List<Loan> findByIdsAndLoanStatusAndLoanType(@Param("ids") Collection<Long> ids,
@Param("loanStatuses") Collection<Integer> loanStatuses, @Param("loanTypes") Collection<Integer> loanTypes); @Param("loanStatuses") Collection<Integer> loanStatuses, @Param("loanTypes") Collection<Integer> loanTypes);
@@ -41,6 +41,7 @@ import javax.persistence.TemporalType;
import javax.persistence.Transient; import javax.persistence.Transient;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.hibernate.annotations.LazyCollection; import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption; import org.hibernate.annotations.LazyCollectionOption;
@@ -349,6 +350,10 @@ public class SavingsAccount extends AbstractPersistable<Long> {
return SavingsAccountStatusType.fromInt(this.status).isApproved(); return SavingsAccountStatusType.fromInt(this.status).isApproved();
} }
public boolean isClosed(){
return SavingsAccountStatusType.fromInt(this.status).isClosed();
}
public void postInterest(final MathContext mc, final LocalDate interestPostingUpToDate, final List<Long> existingTransactionIds, public void postInterest(final MathContext mc, final LocalDate interestPostingUpToDate, final List<Long> existingTransactionIds,
final List<Long> existingReversedTransactionIds) { final List<Long> existingReversedTransactionIds) {
@@ -1762,9 +1767,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
return this.withdrawalFeeApplicableForTransfer; return this.withdrawalFeeApplicableForTransfer;
} }
public void activateAccountBasedOnBalance() {
if (SavingsAccountStatusType.fromInt(this.status).isClosed() && !this.summary.getAccountBalance(getCurrency()).isZero()) { public LocalDate getClosedOnDate() {
this.status = SavingsAccountStatusType.ACTIVE.getValue(); return (LocalDate) ObjectUtils.defaultIfNull(new LocalDate(this.closedOnDate), null);
}
} }
} }
@@ -25,4 +25,7 @@ public interface SavingsAccountRepository extends JpaRepository<SavingsAccount,
@Query("select case when (count (saving) > 0) then true else false end from SavingsAccount saving where saving.client.id = :clientId and saving.status in (100,200,300,303,304)") @Query("select case when (count (saving) > 0) then true else false end from SavingsAccount saving where saving.client.id = :clientId and saving.status in (100,200,300,303,304)")
boolean doNonClosedSavingAccountsExistForClient(@Param("clientId") Long clientId); boolean doNonClosedSavingAccountsExistForClient(@Param("clientId") Long clientId);
@Query("from SavingsAccount sa where sa.client.id is null and sa.group.id = :groupId")
List<SavingsAccount> findByGroupId(@Param("groupId") Long groupId);
} }