diff --git a/mifosng-db/migrations/core_db/V131__holiday-status-column-and-permissions.sql b/mifosng-db/migrations/core_db/V131__holiday-status-column-and-permissions.sql new file mode 100644 index 000000000..fca399788 --- /dev/null +++ b/mifosng-db/migrations/core_db/V131__holiday-status-column-and-permissions.sql @@ -0,0 +1,16 @@ +ALTER TABLE `m_holiday` + ADD COLUMN `status_enum` INT(5) NOT NULL DEFAULT '100' AFTER `repayments_rescheduled_to`; + +ALTER TABLE `m_holiday` + DROP INDEX `holiday_name`, + ADD UNIQUE INDEX `holiday_name` (`name`, `from_date`); + +UPDATE `m_holiday` set `status_enum`=300; + +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('organisation', 'CREATE_HOLIDAY_CHECKER', 'HOLIDAY', 'CREATE', 0); +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('organisation', 'ACTIVATE_HOLIDAY', 'HOLIDAY', 'ACTIVATE', 0); +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('organisation', 'ACTIVATE_HOLIDAY_CHECKER', 'HOLIDAY', 'ACTIVATE', 0); +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('organisation', 'UPDATE_HOLIDAY', 'HOLIDAY', 'UPDATE', 0); +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('organisation', 'UPDATE_HOLIDAY_CHECKER', 'HOLIDAY', 'UPDATE', 0); +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('organisation', 'DELETE_HOLIDAY', 'HOLIDAY', 'DELETE', 0); +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('organisation', 'DELETE_HOLIDAY_CHECKER', 'HOLIDAY', 'DELETE', 0); 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 52ebbd3cb..9ebc65d32 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 @@ -592,6 +592,10 @@ public class CommandWrapper { public boolean isHolidayResource() { return this.entityName.equalsIgnoreCase("HOLIDAY"); } + + public boolean isHolidayActivation() { + return this.entityName.equalsIgnoreCase("HOLIDAY") && this.actionName.equalsIgnoreCase("ACTIVATE") && this.entityId != null; + } public boolean isAccountingRuleResource() { return this.entityName.equalsIgnoreCase("ACCOUNTINGRULE"); 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 6af616141..338d480a1 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 @@ -1311,6 +1311,30 @@ public class CommandWrapperBuilder { this.href = "/holidays/template"; return this; } + + public CommandWrapperBuilder activateHoliday(final Long holidayId) { + this.actionName = "ACTIVATE"; + this.entityName = "HOLIDAY"; + this.entityId = holidayId; + this.href = "/holidays/" + holidayId + "command=activate"; + return this; + } + + public CommandWrapperBuilder updateHoliday(final Long holidayId) { + this.actionName = "UPDATE"; + this.entityName = "HOLIDAY"; + this.entityId = holidayId; + this.href = "/holidays/" + holidayId ; + return this; + } + + public CommandWrapperBuilder deleteHoliday(final Long holidayId) { + this.actionName = "DELETE"; + this.entityName = "HOLIDAY"; + this.entityId = holidayId; + this.href = "/holidays/" + holidayId + "command=delete"; + return this; + } public CommandWrapperBuilder assignRole(final Long groupId) { this.actionName = "ASSIGNROLE"; 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 1d37d1264..761499204 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 @@ -548,6 +548,14 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer } else if (wrapper.isHolidayResource()) { if (wrapper.isCreate()) { handler = this.applicationContext.getBean("createHolidayCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isHolidayActivation()) { + handler = this.applicationContext.getBean("activateHolidayCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isUpdate()) { + handler = this.applicationContext.getBean("updateHolidayCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isDelete()) { + handler = this.applicationContext.getBean("deleteHolidayCommandHandler", NewCommandSourceHandler.class); + } else { + throw new UnsupportedCommandException(wrapper.commandName()); } } else if (wrapper.isProductMixResource()) { if (wrapper.isCreate()) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/api/HolidayApiConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/api/HolidayApiConstants.java index 580e8038c..cf506274e 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/api/HolidayApiConstants.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/api/HolidayApiConstants.java @@ -13,18 +13,19 @@ public class HolidayApiConstants { public static final String dateFormatParamName = "dateFormat"; // request parameters - public static final String name = "name"; - public static final String fromDate = "fromDate"; - public static final String toDate = "toDate"; - public static final String description = "description"; - public static final String offices = "offices"; - public static final String officeId = "officeId"; - public static final String repaymentsRescheduledTo = "repaymentsRescheduledTo"; + public static final String idParamName = "id"; + public static final String nameParamName = "name"; + public static final String fromDateParamName = "fromDate"; + public static final String toDateParamName = "toDate"; + public static final String descriptionParamName = "description"; + public static final String officesParamName = "offices"; + public static final String officeIdParamName = "officeId"; + public static final String repaymentsRescheduledToParamName = "repaymentsRescheduledTo"; public static final String processed = "processed"; - public static final Set HOLIDAY_CREATE_REQUEST_DATA_PARAMETERS = new HashSet(Arrays.asList(localeParamName, - dateFormatParamName, name, fromDate, toDate, description, offices, repaymentsRescheduledTo)); - - public static final Set HOLIDAY_REQUEST_DATA_PARAMETERS = new HashSet(Arrays.asList(localeParamName, - dateFormatParamName, name, fromDate, toDate, repaymentsRescheduledTo)); + public static final Set HOLIDAY_CREATE_OR_UPDATE_REQUEST_DATA_PARAMETERS = new HashSet(Arrays.asList(localeParamName, + dateFormatParamName, nameParamName, fromDateParamName, toDateParamName, descriptionParamName, officesParamName, repaymentsRescheduledToParamName)); + + public static final Set HOLIDAY_RESPONSE_DATA_PARAMETERS = new HashSet(Arrays.asList(idParamName, nameParamName, + fromDateParamName, descriptionParamName, toDateParamName, repaymentsRescheduledToParamName, localeParamName, dateFormatParamName)); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/api/HolidaysApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/api/HolidaysApiResource.java index 58ed77d4f..beb5c18b5 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/api/HolidaysApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/api/HolidaysApiResource.java @@ -1,24 +1,32 @@ package org.mifosplatform.organisation.holiday.api; +import static org.mifosplatform.organisation.holiday.api.HolidayApiConstants.HOLIDAY_RESOURCE_NAME; +import static org.mifosplatform.organisation.holiday.api.HolidayApiConstants.HOLIDAY_RESPONSE_DATA_PARAMETERS; + import java.util.Collection; import java.util.Date; import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; +import javax.ws.rs.PUT; import javax.ws.rs.Path; +import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.UriInfo; +import org.apache.commons.lang.StringUtils; import org.mifosplatform.accounting.journalentry.api.DateParam; import org.mifosplatform.commands.domain.CommandWrapper; import org.mifosplatform.commands.service.CommandWrapperBuilder; import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService; import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamException; import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; @@ -33,8 +41,6 @@ import org.springframework.stereotype.Component; @Scope("singleton") public class HolidaysApiResource { - private final String resourceNameForPermissions = "HOLIDAY"; - private final DefaultToApiJsonSerializer toApiJsonSerializer; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; private final PlatformSecurityContext context; @@ -64,15 +70,84 @@ public class HolidaysApiResource { return this.toApiJsonSerializer.serialize(result); } + + @POST + @Path("{holidayId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String handleCommands(@PathParam("holidayId") final Long holidayId, @QueryParam("command") final String commandParam, + final String apiRequestBodyAsJson) { + + String jsonApiRequest = apiRequestBodyAsJson; + if (StringUtils.isBlank(jsonApiRequest)) { + jsonApiRequest = "{}"; + } + + final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(jsonApiRequest); + + CommandProcessingResult result = null; + if (is(commandParam, "activate")) { + final CommandWrapper commandRequest = builder.activateHoliday(holidayId).build(); + result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + } + + if (result == null) { throw new UnrecognizedQueryParamException("command", commandParam, new Object[] { "activate" }); } + + return this.toApiJsonSerializer.serialize(result); + } + + @GET + @Path("{holidayId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveOne(@PathParam("holidayId") final Long holidayId, @Context final UriInfo uriInfo) { + + this.context.authenticatedUser().validateHasReadPermission(HOLIDAY_RESOURCE_NAME); + + final HolidayData holidayData = this.holidayReadPlatformService.retrieveHoliday(holidayId); + + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + + + return this.toApiJsonSerializer.serialize(settings, holidayData, HOLIDAY_RESPONSE_DATA_PARAMETERS); + } + + @PUT + @Path("{holidayId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String update(@PathParam("holidayId") final Long holidayId, final String jsonRequestBody) { + + final CommandWrapper commandRequest = new CommandWrapperBuilder().updateHoliday(holidayId) + .withJson(jsonRequestBody).build(); + + final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + + return this.toApiJsonSerializer.serialize(result); + } + + @DELETE + @Path("{holidayId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String delete(@PathParam("holidayId") final Long holidayId) { + final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteHoliday(holidayId).build(); + final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + return this.toApiJsonSerializer.serialize(result); + } + + private boolean is(final String commandParam, final String commandValue) { + return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue); + } @GET @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) - public String retrieveAllLoanProducts(@Context final UriInfo uriInfo, @QueryParam("officeId") final Long officeId, + public String retrieveAllHolidays(@Context final UriInfo uriInfo, @QueryParam("officeId") final Long officeId, @QueryParam("fromDate") final DateParam fromDateParam, @QueryParam("toDate") final DateParam toDateParam, @QueryParam("locale") final String locale, @QueryParam("dateFormat") final String dateFormat) { - this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions); + this.context.authenticatedUser().validateHasReadPermission(HOLIDAY_RESOURCE_NAME); Date fromDate = null; if (fromDateParam != null) { @@ -87,7 +162,6 @@ public class HolidaysApiResource { toDate); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); - return this.toApiJsonSerializer.serialize(settings, holidays, HolidayApiConstants.HOLIDAY_REQUEST_DATA_PARAMETERS); + return this.toApiJsonSerializer.serialize(settings, holidays, HOLIDAY_RESPONSE_DATA_PARAMETERS); } - } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/data/HolidayData.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/data/HolidayData.java index 82e73c9c7..f31f6f9a5 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/data/HolidayData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/data/HolidayData.java @@ -13,17 +13,17 @@ public class HolidayData { @SuppressWarnings("unused") private final LocalDate toDate; @SuppressWarnings("unused") - private final LocalDate repaymentsScheduleTO; + private final LocalDate repaymentsRescheduledTo; @SuppressWarnings("unused") private final Long officeId; public HolidayData(final Long id, final String name, final LocalDate fromDate, final LocalDate toDate, - final LocalDate repaymentsScheduleTO) { + final LocalDate repaymentsRescheduledTo) { this.id = id; this.name = name; this.fromDate = fromDate; this.toDate = toDate; - this.repaymentsScheduleTO = repaymentsScheduleTO; + this.repaymentsRescheduledTo = repaymentsRescheduledTo; this.officeId = null; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/data/HolidayDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/data/HolidayDataValidator.java index c815aab89..bf5bad476 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/data/HolidayDataValidator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/data/HolidayDataValidator.java @@ -38,7 +38,7 @@ public class HolidayDataValidator { if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } final Type typeOfMap = new TypeToken>() {}.getType(); - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, HolidayApiConstants.HOLIDAY_CREATE_REQUEST_DATA_PARAMETERS); + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, HolidayApiConstants.HOLIDAY_CREATE_OR_UPDATE_REQUEST_DATA_PARAMETERS); final JsonElement element = this.fromApiJsonHelper.parse(json); final List dataValidationErrors = new ArrayList(); @@ -46,38 +46,94 @@ public class HolidayDataValidator { final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) .resource(HolidayApiConstants.HOLIDAY_RESOURCE_NAME); - final String name = this.fromApiJsonHelper.extractStringNamed(HolidayApiConstants.name, element); - baseDataValidator.reset().parameter(HolidayApiConstants.name).value(name).notNull().notExceedingLengthOf(100); + final String name = this.fromApiJsonHelper.extractStringNamed(HolidayApiConstants.nameParamName, element); + baseDataValidator.reset().parameter(HolidayApiConstants.nameParamName).value(name).notNull().notExceedingLengthOf(100); - final LocalDate fromDate = this.fromApiJsonHelper.extractLocalDateNamed(HolidayApiConstants.fromDate, element); - baseDataValidator.reset().parameter(HolidayApiConstants.fromDate).value(fromDate).notNull(); + final LocalDate fromDate = this.fromApiJsonHelper.extractLocalDateNamed(HolidayApiConstants.fromDateParamName, element); + baseDataValidator.reset().parameter(HolidayApiConstants.fromDateParamName).value(fromDate).notNull(); - final LocalDate toDate = this.fromApiJsonHelper.extractLocalDateNamed(HolidayApiConstants.toDate, element); - baseDataValidator.reset().parameter(HolidayApiConstants.toDate).value(toDate).notNull(); + final LocalDate toDate = this.fromApiJsonHelper.extractLocalDateNamed(HolidayApiConstants.toDateParamName, element); + baseDataValidator.reset().parameter(HolidayApiConstants.toDateParamName).value(toDate).notNull(); - final LocalDate repaymentsRescheduledTo = this.fromApiJsonHelper.extractLocalDateNamed(HolidayApiConstants.repaymentsRescheduledTo, + final LocalDate repaymentsRescheduledTo = this.fromApiJsonHelper.extractLocalDateNamed(HolidayApiConstants.repaymentsRescheduledToParamName, element); - baseDataValidator.reset().parameter(HolidayApiConstants.repaymentsRescheduledTo).value(repaymentsRescheduledTo).notNull(); + baseDataValidator.reset().parameter(HolidayApiConstants.repaymentsRescheduledToParamName).value(repaymentsRescheduledTo).notNull(); Set offices = null; final JsonObject topLevelJsonElement = element.getAsJsonObject(); - if (topLevelJsonElement.has(HolidayApiConstants.offices) && topLevelJsonElement.get(HolidayApiConstants.offices).isJsonArray()) { + if (topLevelJsonElement.has(HolidayApiConstants.officesParamName) && topLevelJsonElement.get(HolidayApiConstants.officesParamName).isJsonArray()) { - final JsonArray array = topLevelJsonElement.get(HolidayApiConstants.offices).getAsJsonArray(); + final JsonArray array = topLevelJsonElement.get(HolidayApiConstants.officesParamName).getAsJsonArray(); if (array.size() > 0) { offices = new HashSet(array.size()); for (int i = 0; i < array.size(); i++) { final JsonObject officeElement = array.get(i).getAsJsonObject(); - final Long officeId = this.fromApiJsonHelper.extractLongNamed(HolidayApiConstants.officeId, officeElement); - baseDataValidator.reset().parameter(HolidayApiConstants.offices).value(officeId).notNull(); + final Long officeId = this.fromApiJsonHelper.extractLongNamed(HolidayApiConstants.officeIdParamName, officeElement); + baseDataValidator.reset().parameter(HolidayApiConstants.officesParamName).value(officeId).notNull(); offices.add(officeId); } } } - baseDataValidator.reset().parameter(HolidayApiConstants.offices).value(offices).notNull(); + baseDataValidator.reset().parameter(HolidayApiConstants.officesParamName).value(offices).notNull(); throwExceptionIfValidationWarningsExist(dataValidationErrors); } + + public void validateForUpdate(final String json) { + + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } + + final Type typeOfMap = new TypeToken>() {}.getType(); + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, + HolidayApiConstants.HOLIDAY_CREATE_OR_UPDATE_REQUEST_DATA_PARAMETERS); + final JsonElement element = this.fromApiJsonHelper.parse(json); + + final List dataValidationErrors = new ArrayList(); + + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) + .resource(HolidayApiConstants.HOLIDAY_RESOURCE_NAME); + + if (this.fromApiJsonHelper.parameterExists(HolidayApiConstants.nameParamName, element)) { + final String name = this.fromApiJsonHelper.extractStringNamed(HolidayApiConstants.nameParamName, element); + baseDataValidator.reset().parameter(HolidayApiConstants.nameParamName).value(name).notNull().notExceedingLengthOf(100); + } + + if (this.fromApiJsonHelper.parameterExists(HolidayApiConstants.fromDateParamName, element)) { + final LocalDate fromDate = this.fromApiJsonHelper.extractLocalDateNamed(HolidayApiConstants.fromDateParamName, element); + baseDataValidator.reset().parameter(HolidayApiConstants.fromDateParamName).value(fromDate).notNull(); + } + + if (this.fromApiJsonHelper.parameterExists(HolidayApiConstants.toDateParamName, element)) { + final LocalDate toDate = this.fromApiJsonHelper.extractLocalDateNamed(HolidayApiConstants.toDateParamName, element); + baseDataValidator.reset().parameter(HolidayApiConstants.toDateParamName).value(toDate).notNull(); + } + + if (this.fromApiJsonHelper.parameterExists(HolidayApiConstants.repaymentsRescheduledToParamName, element)) { + final LocalDate repaymentsRescheduledTo = this.fromApiJsonHelper.extractLocalDateNamed( + HolidayApiConstants.repaymentsRescheduledToParamName, element); + baseDataValidator.reset().parameter(HolidayApiConstants.repaymentsRescheduledToParamName).value(repaymentsRescheduledTo).notNull(); + } + + Set offices = null; + final JsonObject topLevelJsonElement = element.getAsJsonObject(); + if (this.fromApiJsonHelper.parameterExists(HolidayApiConstants.officesParamName, element)) { + if (topLevelJsonElement.has(HolidayApiConstants.officesParamName) && topLevelJsonElement.get(HolidayApiConstants.officesParamName).isJsonArray()) { + + final JsonArray array = topLevelJsonElement.get(HolidayApiConstants.officesParamName).getAsJsonArray(); + if (array.size() > 0) { + offices = new HashSet(array.size()); + for (int i = 0; i < array.size(); i++) { + final JsonObject officeElement = array.get(i).getAsJsonObject(); + final Long officeId = this.fromApiJsonHelper.extractLongNamed(HolidayApiConstants.officeIdParamName, officeElement); + baseDataValidator.reset().parameter(HolidayApiConstants.officesParamName).value(officeId).notNull(); + offices.add(officeId); + } + } + } + baseDataValidator.reset().parameter(HolidayApiConstants.officesParamName).value(offices).notNull(); + throwExceptionIfValidationWarningsExist(dataValidationErrors); + } + } private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { if (!dataValidationErrors.isEmpty()) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/domain/Holiday.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/domain/Holiday.java index f041ef38e..738ba940a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/domain/Holiday.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/domain/Holiday.java @@ -5,7 +5,21 @@ */ package org.mifosplatform.organisation.holiday.domain; +import static org.mifosplatform.organisation.holiday.api.HolidayApiConstants.descriptionParamName; +import static org.mifosplatform.organisation.holiday.api.HolidayApiConstants.fromDateParamName; +import static org.mifosplatform.organisation.holiday.api.HolidayApiConstants.nameParamName; +import static org.mifosplatform.organisation.holiday.api.HolidayApiConstants.officesParamName; +import static org.mifosplatform.organisation.holiday.api.HolidayApiConstants.repaymentsRescheduledToParamName; +import static org.mifosplatform.organisation.holiday.api.HolidayApiConstants.toDateParamName; +import static org.mifosplatform.portfolio.savings.SavingsApiConstants.dateFormatParamName; +import static org.mifosplatform.portfolio.savings.SavingsApiConstants.localeParamName; + +import java.util.ArrayList; import java.util.Date; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.Set; import javax.persistence.Column; @@ -22,10 +36,15 @@ import javax.persistence.UniqueConstraint; import org.apache.commons.lang.StringUtils; import org.joda.time.LocalDate; import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.ApiParameterError; +import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; +import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; import org.mifosplatform.organisation.holiday.api.HolidayApiConstants; import org.mifosplatform.organisation.office.domain.Office; import org.springframework.data.jpa.domain.AbstractPersistable; +import com.google.gson.JsonArray; + @Entity @Table(name = "m_holiday", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "holiday_name") }) public class Holiday extends AbstractPersistable { @@ -45,6 +64,9 @@ public class Holiday extends AbstractPersistable { @Temporal(TemporalType.DATE) private Date repaymentsRescheduledTo; + @Column(name = "status_enum", nullable = false) + private Integer status; + @Column(name = "processed", nullable = false) private boolean processed; @@ -56,18 +78,121 @@ public class Holiday extends AbstractPersistable { private Set offices; public static Holiday createNew(final Set offices, final JsonCommand command) { - final String name = command.stringValueOfParameterNamed(HolidayApiConstants.name); - final LocalDate fromDate = command.localDateValueOfParameterNamed(HolidayApiConstants.fromDate); - final LocalDate toDate = command.localDateValueOfParameterNamed(HolidayApiConstants.toDate); - final LocalDate repaymentsRescheduledTo = command.localDateValueOfParameterNamed(HolidayApiConstants.repaymentsRescheduledTo); + final String name = command.stringValueOfParameterNamed(HolidayApiConstants.nameParamName); + final LocalDate fromDate = command.localDateValueOfParameterNamed(HolidayApiConstants.fromDateParamName); + final LocalDate toDate = command.localDateValueOfParameterNamed(HolidayApiConstants.toDateParamName); + final LocalDate repaymentsRescheduledTo = command.localDateValueOfParameterNamed(HolidayApiConstants.repaymentsRescheduledToParamName); + final Integer status = HolidayStatusType.PENDING_FOR_ACTIVATION.getValue(); final boolean processed = false;// default it to false. Only batch job // should update this field. - final String description = command.stringValueOfParameterNamed(HolidayApiConstants.description); - return new Holiday(name, fromDate, toDate, repaymentsRescheduledTo, processed, description, offices); + final String description = command.stringValueOfParameterNamed(HolidayApiConstants.descriptionParamName); + return new Holiday(name, fromDate, toDate, repaymentsRescheduledTo, status, processed, description, offices); + } + + public Map update(final JsonCommand command) { + final Map actualChanges = new LinkedHashMap(7); + + final List dataValidationErrors = new ArrayList(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) + .resource("holiday" + ".update"); + + final HolidayStatusType currentStatus = HolidayStatusType.fromInt(this.status); + + final String dateFormatAsInput = command.dateFormat(); + final String localeAsInput = command.locale(); + + if (command.isChangeInStringParameterNamed(nameParamName, this.name)) { + final String newValue = command.stringValueOfParameterNamed(nameParamName); + actualChanges.put(nameParamName, newValue); + this.name = StringUtils.defaultIfEmpty(newValue, null); + } + + if (command.isChangeInStringParameterNamed(descriptionParamName, this.description)) { + final String newValue = command.stringValueOfParameterNamed(descriptionParamName); + actualChanges.put(descriptionParamName, newValue); + this.description = StringUtils.defaultIfEmpty(newValue, null); + } + + if (currentStatus.isPendingActivation()) { + if (command.isChangeInLocalDateParameterNamed(fromDateParamName, getFromDateLocalDate())) { + final String valueAsInput = command.stringValueOfParameterNamed(fromDateParamName); + actualChanges.put(fromDateParamName, valueAsInput); + actualChanges.put(dateFormatParamName, dateFormatAsInput); + actualChanges.put(localeParamName, localeAsInput); + final LocalDate newValue = command.localDateValueOfParameterNamed(fromDateParamName); + this.fromDate = newValue.toDate(); + } + + if (command.isChangeInLocalDateParameterNamed(toDateParamName, getToDateLocalDate())) { + final String valueAsInput = command.stringValueOfParameterNamed(toDateParamName); + actualChanges.put(toDateParamName, valueAsInput); + actualChanges.put(dateFormatParamName, dateFormatAsInput); + actualChanges.put(localeParamName, localeAsInput); + + final LocalDate newValue = command.localDateValueOfParameterNamed(toDateParamName); + this.toDate = newValue.toDate(); + } + + if (command.isChangeInLocalDateParameterNamed(repaymentsRescheduledToParamName, getRepaymentsRescheduledToLocalDate())) { + final String valueAsInput = command.stringValueOfParameterNamed(repaymentsRescheduledToParamName); + actualChanges.put(repaymentsRescheduledToParamName, valueAsInput); + actualChanges.put(dateFormatParamName, dateFormatAsInput); + actualChanges.put(localeParamName, localeAsInput); + + final LocalDate newValue = command.localDateValueOfParameterNamed(repaymentsRescheduledToParamName); + this.repaymentsRescheduledTo = newValue.toDate(); + } + + if (command.hasParameter(officesParamName)) { + final JsonArray jsonArray = command.arrayOfParameterNamed(officesParamName); + if (jsonArray != null) { + actualChanges.put(officesParamName, command.jsonFragment(officesParamName)); + } + } + } else { + if (command.isChangeInLocalDateParameterNamed(fromDateParamName, getFromDateLocalDate())) { + baseDataValidator.reset().parameter(fromDateParamName).failWithCode("cannot.edit.holiday.in.active.state"); + } + + if (command.isChangeInLocalDateParameterNamed(toDateParamName, getToDateLocalDate())) { + baseDataValidator.reset().parameter(toDateParamName).failWithCode("cannot.edit.holiday.in.active.state"); + } + + if (command.isChangeInLocalDateParameterNamed(repaymentsRescheduledToParamName, getRepaymentsRescheduledToLocalDate())) { + baseDataValidator.reset().parameter(repaymentsRescheduledToParamName).failWithCode("cannot.edit.holiday.in.active.state"); + } + + if (command.hasParameter(officesParamName)) { + baseDataValidator.reset().parameter(repaymentsRescheduledToParamName).failWithCode("cannot.edit.holiday.in.active.state"); + } + + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } + } + + return actualChanges; + } + + public boolean update(final Set newOffices) { + if (newOffices == null) { return false; } + + boolean updated = false; + if (this.offices != null) { + final Set currentSetOfOffices = new HashSet(this.offices); + final Set newSetOfOffices = new HashSet(newOffices); + + if (!(currentSetOfOffices.equals(newSetOfOffices))) { + updated = true; + this.offices = newOffices; + } + } else { + updated = true; + this.offices = newOffices; + } + return updated; } private Holiday(final String name, final LocalDate fromDate, final LocalDate toDate, final LocalDate repaymentsRescheduledTo, - final boolean processed, final String description, final Set offices) { + final Integer status, final boolean processed, final String description, final Set offices) { if (StringUtils.isNotBlank(name)) { this.name = name.trim(); } @@ -84,6 +209,7 @@ public class Holiday extends AbstractPersistable { this.repaymentsRescheduledTo = repaymentsRescheduledTo.toDate(); } + this.status = status; this.processed = processed; if (StringUtils.isNotBlank(name)) { @@ -134,4 +260,30 @@ public class Holiday extends AbstractPersistable { public void processed() { this.processed = true; } + + public void activate() { + final List dataValidationErrors = new ArrayList(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) + .resource("holiday" + ".activate"); + + final HolidayStatusType currentStatus = HolidayStatusType.fromInt(this.status); + if (!currentStatus.isPendingActivation()) { + baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("not.in.pending.for.activation.state"); + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } + } + + this.status = HolidayStatusType.ACTIVE.getValue(); + } + + public void delete() { + final List dataValidationErrors = new ArrayList(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("holiday" + ".delete"); + + final HolidayStatusType currentStatus = HolidayStatusType.fromInt(this.status); + if (currentStatus.isDeleted()) { + baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("already.in.deleted.state"); + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } + } + this.status = HolidayStatusType.DELETED.getValue(); + } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/domain/HolidayRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/domain/HolidayRepository.java index cc2500b2f..d9246a0bd 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/domain/HolidayRepository.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/domain/HolidayRepository.java @@ -15,9 +15,9 @@ import org.springframework.data.repository.query.Param; public interface HolidayRepository extends JpaRepository, JpaSpecificationExecutor { - @Query("select holiday from Holiday holiday, IN(holiday.offices) office where (holiday.fromDate >= :date OR :date <= holiday.toDate) and office.id = :officeId") - List findByOfficeIdAndGreaterThanDate(@Param("officeId") Long officeId, @Param("date") Date date); + @Query("select holiday from Holiday holiday, IN(holiday.offices) office where (holiday.fromDate >= :date OR :date <= holiday.toDate) and holiday.status = :status and office.id = :officeId") + List findByOfficeIdAndGreaterThanDate(@Param("officeId") Long officeId, @Param("date") Date date, @Param("status") Integer status); - @Query("from Holiday holiday where holiday.processed = false") - List findUnprocessed(); + @Query("from Holiday holiday where holiday.processed = false and holiday.status = :status") + List findUnprocessed(@Param("status") Integer status); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/domain/HolidayRepositoryWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/domain/HolidayRepositoryWrapper.java new file mode 100644 index 000000000..4d040ad6d --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/domain/HolidayRepositoryWrapper.java @@ -0,0 +1,60 @@ +/** + * 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.organisation.holiday.domain; + +import java.util.Date; +import java.util.List; + +import org.mifosplatform.organisation.holiday.exception.HolidayNotFoundException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + *

+ * Wrapper for {@link HolidayRepository} that adds NULL checking and Error + * handling capabilities + *

+ */ +@Service +public class HolidayRepositoryWrapper { + + private final HolidayRepository repository; + + @Autowired + public HolidayRepositoryWrapper(final HolidayRepository repository) { + this.repository = repository; + } + + public Holiday findOneWithNotFoundDetection(final Long id) { + final Holiday holiday = this.repository.findOne(id); + if (holiday == null) { throw new HolidayNotFoundException(id); } + return holiday; + } + + public void save(final Holiday holiday) { + this.repository.save(holiday); + } + + public void save(final Iterable holidays){ + this.repository.save(holidays); + } + + public void saveAndFlush(final Holiday holiday) { + this.repository.saveAndFlush(holiday); + } + + public void delete(final Holiday holiday) { + this.repository.delete(holiday); + } + + public List findByOfficeIdAndGreaterThanDate(final Long officeId, final Date date) { + return this.repository.findByOfficeIdAndGreaterThanDate(officeId, date, HolidayStatusType.ACTIVE.getValue()); + } + + public List findUnprocessed() { + return this.repository.findUnprocessed(HolidayStatusType.ACTIVE.getValue()); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/domain/HolidayStatusType.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/domain/HolidayStatusType.java new file mode 100644 index 000000000..cffe51d66 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/domain/HolidayStatusType.java @@ -0,0 +1,66 @@ +/** + * 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.organisation.holiday.domain; + + +/** + * Enum representation of {@link Holiday} status states. + */ +public enum HolidayStatusType { + + INVALID(0, "holidayStatusType.invalid"), // + PENDING_FOR_ACTIVATION(100, "holidayStatusType.pending.for.activation"), // + ACTIVE(300, "holidayStatusType.active"), // + DELETED(600, "savingsAccountStatusType.transfer.in.progress"); + + private final Integer value; + private final String code; + + public static HolidayStatusType fromInt(final Integer type) { + HolidayStatusType enumeration = HolidayStatusType.INVALID; + switch (type) { + case 100: + enumeration = HolidayStatusType.PENDING_FOR_ACTIVATION; + break; + case 300: + enumeration = HolidayStatusType.ACTIVE; + break; + case 600: + enumeration = HolidayStatusType.DELETED; + break; + } + return enumeration; + } + + private HolidayStatusType(final Integer value, final String code) { + this.value = value; + this.code = code; + } + + public boolean hasStateOf(final HolidayStatusType state) { + return this.value.equals(state.getValue()); + } + + public Integer getValue() { + return this.value; + } + + public String getCode() { + return this.code; + } + + public boolean isPendingActivation() { + return this.value.equals(HolidayStatusType.PENDING_FOR_ACTIVATION.getValue()); + } + + public boolean isActive() { + return this.value.equals(HolidayStatusType.ACTIVE.getValue()); + } + + public boolean isDeleted() { + return this.value.equals(HolidayStatusType.DELETED.getValue()); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/exception/HolidayNotFoundException.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/exception/HolidayNotFoundException.java new file mode 100644 index 000000000..59c1bac71 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/exception/HolidayNotFoundException.java @@ -0,0 +1,18 @@ +/** + * 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.organisation.holiday.exception; + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; + +/** + * A {@link RuntimeException} thrown when holiday resources are not found. + */ +public class HolidayNotFoundException extends AbstractPlatformResourceNotFoundException { + + public HolidayNotFoundException(final Long id) { + super("error.msg.holiday.id.invalid", "Holiday with identifier " + id + " does not exist", id); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/handler/ActivateHolidayCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/handler/ActivateHolidayCommandHandler.java new file mode 100644 index 000000000..b4ae4459e --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/handler/ActivateHolidayCommandHandler.java @@ -0,0 +1,26 @@ +package org.mifosplatform.organisation.holiday.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.organisation.holiday.service.HolidayWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class ActivateHolidayCommandHandler implements NewCommandSourceHandler { + + private final HolidayWritePlatformService holidayWritePlatformService; + + @Autowired + public ActivateHolidayCommandHandler(final HolidayWritePlatformService holidayWritePlatformService) { + this.holidayWritePlatformService = holidayWritePlatformService; + } + + @Transactional + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + return this.holidayWritePlatformService.activateHoliday(command.entityId()); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/handler/DeleteHolidayCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/handler/DeleteHolidayCommandHandler.java new file mode 100644 index 000000000..4cd72bd2b --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/handler/DeleteHolidayCommandHandler.java @@ -0,0 +1,26 @@ +package org.mifosplatform.organisation.holiday.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.organisation.holiday.service.HolidayWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class DeleteHolidayCommandHandler implements NewCommandSourceHandler { + + private final HolidayWritePlatformService holidayWritePlatformService; + + @Autowired + public DeleteHolidayCommandHandler(final HolidayWritePlatformService holidayWritePlatformService) { + this.holidayWritePlatformService = holidayWritePlatformService; + } + + @Transactional + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + return this.holidayWritePlatformService.deleteHoliday(command.entityId()); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/handler/UpdateHolidayCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/handler/UpdateHolidayCommandHandler.java new file mode 100644 index 000000000..d55aba8d8 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/handler/UpdateHolidayCommandHandler.java @@ -0,0 +1,26 @@ +package org.mifosplatform.organisation.holiday.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.organisation.holiday.service.HolidayWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class UpdateHolidayCommandHandler implements NewCommandSourceHandler { + + private final HolidayWritePlatformService holidayWritePlatformService; + + @Autowired + public UpdateHolidayCommandHandler(final HolidayWritePlatformService holidayWritePlatformService) { + this.holidayWritePlatformService = holidayWritePlatformService; + } + + @Transactional + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + return this.holidayWritePlatformService.updateHoliday(command); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/service/HolidayEnumerations.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/service/HolidayEnumerations.java new file mode 100644 index 000000000..038472eb6 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/service/HolidayEnumerations.java @@ -0,0 +1,37 @@ +/** + * 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.organisation.holiday.service; + +import org.mifosplatform.infrastructure.core.data.EnumOptionData; +import org.mifosplatform.organisation.holiday.domain.HolidayStatusType; + +public class HolidayEnumerations { + + public static EnumOptionData holidayStatusType(final int id) { + return holidayStatusType(HolidayStatusType.fromInt(id)); + } + + public static EnumOptionData holidayStatusType(final HolidayStatusType type) { + EnumOptionData optionData = null; + switch (type) { + case INVALID: + optionData = new EnumOptionData(HolidayStatusType.INVALID.getValue().longValue(), HolidayStatusType.INVALID.getCode(), + "Invalid"); + break; + case PENDING_FOR_ACTIVATION: + optionData = new EnumOptionData(HolidayStatusType.PENDING_FOR_ACTIVATION.getValue().longValue(), + HolidayStatusType.PENDING_FOR_ACTIVATION.getCode(), "Pending for activation"); + break; + case ACTIVE: + optionData = new EnumOptionData(HolidayStatusType.ACTIVE.getValue().longValue(), HolidayStatusType.ACTIVE.getCode(), "Active"); + break; + case DELETED: + optionData = new EnumOptionData(HolidayStatusType.DELETED.getValue().longValue(), HolidayStatusType.DELETED.getCode(), "Deleted"); + break; + } + return optionData; + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/service/HolidayReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/service/HolidayReadPlatformService.java index f71b3f0a3..5a66047f0 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/service/HolidayReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/service/HolidayReadPlatformService.java @@ -8,4 +8,6 @@ import org.mifosplatform.organisation.holiday.data.HolidayData; public interface HolidayReadPlatformService { Collection retrieveAllHolidaysBySearchParamerters(final Long officeId, Date fromDate, Date toDate); + + HolidayData retrieveHoliday(final Long holidayId); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/service/HolidayReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/service/HolidayReadPlatformServiceImpl.java index ea1f89b05..0867c7350 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/service/HolidayReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/service/HolidayReadPlatformServiceImpl.java @@ -13,7 +13,9 @@ import org.mifosplatform.infrastructure.core.domain.JdbcSupport; import org.mifosplatform.infrastructure.core.service.RoutingDataSource; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.organisation.holiday.data.HolidayData; +import org.mifosplatform.organisation.holiday.exception.HolidayNotFoundException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Service; @@ -38,7 +40,7 @@ public class HolidayReadPlatformServiceImpl implements HolidayReadPlatformServic final StringBuilder sqlBuilder = new StringBuilder(200); sqlBuilder.append("h.id as id, h.name as name, h.from_date as fromDate, h.to_date as toDate, "); sqlBuilder.append("h.repayments_rescheduled_to as repaymentsScheduleTO "); - sqlBuilder.append("from m_holiday h join m_holiday_office hf on h.id = hf.holiday_id and "); + sqlBuilder.append("from m_holiday h "); this.schema = sqlBuilder.toString(); } @@ -69,7 +71,7 @@ public class HolidayReadPlatformServiceImpl implements HolidayReadPlatformServic int arrayPos = 0; final HolidayMapper rm = new HolidayMapper(); - String sql = "select " + rm.schema() + " hf.office_id = ? "; + String sql = "select " + rm.schema() + " join m_holiday_office hf on h.id = hf.holiday_id and hf.office_id = ? "; objectArray[arrayPos] = officeId; arrayPos = arrayPos + 1; @@ -97,4 +99,17 @@ public class HolidayReadPlatformServiceImpl implements HolidayReadPlatformServic return this.jdbcTemplate.query(sql, rm, finalObjectArray); } + @Override + public HolidayData retrieveHoliday(Long holidayId) { + try { + final HolidayMapper rm = new HolidayMapper(); + + final String sql = rm.schema() + " where h.id = ?"; + + return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { holidayId }); + } catch (final EmptyResultDataAccessException e) { + throw new HolidayNotFoundException(holidayId); + } + } + } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/service/HolidayWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/service/HolidayWritePlatformService.java index 6f702fa43..1f0cf0301 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/service/HolidayWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/service/HolidayWritePlatformService.java @@ -8,6 +8,12 @@ public interface HolidayWritePlatformService { CommandProcessingResult createHoliday(JsonCommand command); + CommandProcessingResult updateHoliday(JsonCommand command); + + CommandProcessingResult activateHoliday(final Long holidayId); + + CommandProcessingResult deleteHoliday(final Long holidayId); + boolean isHoliday(Long officeId, LocalDate transactionDate); boolean isTransactionAllowedOnHoliday(); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/service/HolidayWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/service/HolidayWritePlatformServiceJpaRepositoryImpl.java index db8578c2d..b2582ba1b 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/service/HolidayWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/holiday/service/HolidayWritePlatformServiceJpaRepositoryImpl.java @@ -1,7 +1,10 @@ package org.mifosplatform.organisation.holiday.service; +import static org.mifosplatform.organisation.holiday.api.HolidayApiConstants.officesParamName; + import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.joda.time.LocalDate; @@ -15,7 +18,7 @@ import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext import org.mifosplatform.organisation.holiday.api.HolidayApiConstants; import org.mifosplatform.organisation.holiday.data.HolidayDataValidator; import org.mifosplatform.organisation.holiday.domain.Holiday; -import org.mifosplatform.organisation.holiday.domain.HolidayRepository; +import org.mifosplatform.organisation.holiday.domain.HolidayRepositoryWrapper; import org.mifosplatform.organisation.holiday.exception.HolidayDateException; import org.mifosplatform.organisation.office.domain.Office; import org.mifosplatform.organisation.office.domain.OfficeRepository; @@ -39,7 +42,7 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit private final static Logger logger = LoggerFactory.getLogger(HolidayWritePlatformServiceJpaRepositoryImpl.class); private final HolidayDataValidator fromApiJsonDeserializer; - private final HolidayRepository holidayRepository; + private final HolidayRepositoryWrapper holidayRepository; private final WorkingDaysRepositoryWrapper daysRepositoryWrapper; private final ConfigurationDomainService configurationDomainService; private final PlatformSecurityContext context; @@ -48,7 +51,7 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit @Autowired public HolidayWritePlatformServiceJpaRepositoryImpl(final HolidayDataValidator fromApiJsonDeserializer, - final HolidayRepository holidayRepository, final PlatformSecurityContext context, final OfficeRepository officeRepository, + final HolidayRepositoryWrapper holidayRepository, final PlatformSecurityContext context, final OfficeRepository officeRepository, final FromJsonHelper fromApiJsonHelper, final WorkingDaysRepositoryWrapper daysRepositoryWrapper, final ConfigurationDomainService configurationDomainService) { this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.holidayRepository = holidayRepository; @@ -81,17 +84,70 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit return CommandProcessingResult.empty(); } } + + @Transactional + @Override + public CommandProcessingResult updateHoliday(final JsonCommand command) { + + try { + this.context.authenticatedUser(); + this.fromApiJsonDeserializer.validateForUpdate(command.json()); + + final Holiday holiday = this.holidayRepository.findOneWithNotFoundDetection(command.entityId()); + Map changes = holiday.update(command); + + validateInputDates(holiday.getFromDateLocalDate(), holiday.getToDateLocalDate(), holiday.getRepaymentsRescheduledToLocalDate()); + + if (changes.containsKey(officesParamName)) { + final Set offices = getSelectedOffices(command); + final boolean updated = holiday.update(offices); + if (!updated) { + changes.remove(officesParamName); + } + } + + this.holidayRepository.saveAndFlush(holiday); + + return new CommandProcessingResultBuilder().withEntityId(holiday.getId()).with(changes).build(); + } catch (final DataIntegrityViolationException dve) { + handleDataIntegrityIssues(command, dve); + return CommandProcessingResult.empty(); + } + } + + @Transactional + @Override + public CommandProcessingResult activateHoliday(final Long holidayId) { + this.context.authenticatedUser(); + final Holiday holiday = this.holidayRepository.findOneWithNotFoundDetection(holidayId); + + holiday.activate(); + this.holidayRepository.saveAndFlush(holiday); + return new CommandProcessingResultBuilder() + .withEntityId(holiday.getId()).build(); + } + + @Transactional + @Override + public CommandProcessingResult deleteHoliday(final Long holidayId) { + this.context.authenticatedUser(); + final Holiday holiday = this.holidayRepository.findOneWithNotFoundDetection(holidayId); + holiday.delete(); + this.holidayRepository.saveAndFlush(holiday); + return new CommandProcessingResultBuilder() + .withEntityId(holidayId).build(); + } private Set getSelectedOffices(final JsonCommand command) { Set offices = null; final JsonObject topLevelJsonElement = this.fromApiJsonHelper.parse(command.json()).getAsJsonObject(); - if (topLevelJsonElement.has(HolidayApiConstants.offices) && topLevelJsonElement.get(HolidayApiConstants.offices).isJsonArray()) { + if (topLevelJsonElement.has(HolidayApiConstants.officesParamName) && topLevelJsonElement.get(HolidayApiConstants.officesParamName).isJsonArray()) { - final JsonArray array = topLevelJsonElement.get(HolidayApiConstants.offices).getAsJsonArray(); + final JsonArray array = topLevelJsonElement.get(HolidayApiConstants.officesParamName).getAsJsonArray(); offices = new HashSet(array.size()); for (int i = 0; i < array.size(); i++) { final JsonObject officeElement = array.get(i).getAsJsonObject(); - final Long officeId = this.fromApiJsonHelper.extractLongNamed(HolidayApiConstants.officeId, officeElement); + final Long officeId = this.fromApiJsonHelper.extractLongNamed(HolidayApiConstants.officeIdParamName, officeElement); final Office office = this.officeRepository.findOne(officeId); if (office == null) { throw new OfficeNotFoundException(officeId); } offices.add(office); @@ -114,9 +170,13 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit } private void validateInputDates(final JsonCommand command) { - final LocalDate fromDate = command.localDateValueOfParameterNamed(HolidayApiConstants.fromDate); - final LocalDate toDate = command.localDateValueOfParameterNamed(HolidayApiConstants.toDate); - final LocalDate repaymentsRescheduledTo = command.localDateValueOfParameterNamed(HolidayApiConstants.repaymentsRescheduledTo); + final LocalDate fromDate = command.localDateValueOfParameterNamed(HolidayApiConstants.fromDateParamName); + final LocalDate toDate = command.localDateValueOfParameterNamed(HolidayApiConstants.toDateParamName); + final LocalDate repaymentsRescheduledTo = command.localDateValueOfParameterNamed(HolidayApiConstants.repaymentsRescheduledToParamName); + this.validateInputDates(fromDate, toDate, repaymentsRescheduledTo); + } + private void validateInputDates(final LocalDate fromDate, final LocalDate toDate, final LocalDate repaymentsRescheduledTo) { + String defaultUserMessage = ""; if (toDate.isBefore(fromDate)) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java index 315c73bed..e9212ba3e 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java @@ -21,6 +21,7 @@ import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; import org.mifosplatform.organisation.holiday.domain.Holiday; import org.mifosplatform.organisation.holiday.domain.HolidayRepository; +import org.mifosplatform.organisation.holiday.domain.HolidayStatusType; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; @@ -105,8 +106,8 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { final LoanTransaction newRepaymentTransaction = LoanTransaction.repayment(loan.getOffice(), repaymentAmount, paymentDetail, transactionDate, txnExternalId); final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled(); - final List holidays = this.holidayRepository - .findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), transactionDate.toDate()); + final List holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), + transactionDate.toDate(), HolidayStatusType.ACTIVE.getValue()); final WorkingDays workingDays = this.workingDaysRepository.findOne(); final boolean allowTransactionsOnNonWorkingDay = this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled(); @@ -176,8 +177,8 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { final LoanTransaction newPaymentTransaction = LoanTransaction.loanPayment(null, loan.getOffice(), paymentAmout, paymentDetail, transactionDate, txnExternalId, loanTransactionType); final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled(); - final List holidays = this.holidayRepository - .findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), transactionDate.toDate()); + final List holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), + transactionDate.toDate(), HolidayStatusType.ACTIVE.getValue()); final WorkingDays workingDays = this.workingDaysRepository.findOne(); final boolean allowTransactionsOnNonWorkingDay = this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled(); if (loanTransactionType.isRepaymentAtDisbursement()) { @@ -239,8 +240,8 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { final LoanTransaction newRefundTransaction = LoanTransaction.refund(loan.getOffice(), refundAmount, paymentDetail, transactionDate, txnExternalId); final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled(); - final List holidays = this.holidayRepository - .findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), transactionDate.toDate()); + final List holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), + transactionDate.toDate(), HolidayStatusType.ACTIVE.getValue()); final WorkingDays workingDays = this.workingDaysRepository.findOne(); final boolean allowTransactionsOnNonWorkingDay = this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled(); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java index 1b01162e2..5fb77f88c 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java @@ -16,6 +16,7 @@ import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomain import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.organisation.holiday.domain.Holiday; import org.mifosplatform.organisation.holiday.domain.HolidayRepository; +import org.mifosplatform.organisation.holiday.domain.HolidayStatusType; import org.mifosplatform.organisation.holiday.service.HolidayUtil; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; @@ -261,7 +262,8 @@ public class LoanScheduleAssembler { } final LocalDate expectedDisbursementDate = this.fromApiJsonHelper.extractLocalDateNamed("expectedDisbursementDate", element); - final List holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(officeId, expectedDisbursementDate.toDate()); + final List holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(officeId, expectedDisbursementDate.toDate(), + HolidayStatusType.ACTIVE.getValue()); final WorkingDays workingDays = this.workingDaysRepository.findOne(); validateDisbursementDateIsOnNonWorkingDay(loanApplicationTerms.getExpectedDisbursementDate(), workingDays); 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 2a05f8354..30bd3e713 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 @@ -18,6 +18,7 @@ import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.organisation.holiday.domain.Holiday; import org.mifosplatform.organisation.holiday.domain.HolidayRepository; +import org.mifosplatform.organisation.holiday.domain.HolidayStatusType; import org.mifosplatform.organisation.staff.domain.Staff; import org.mifosplatform.organisation.staff.domain.StaffRepository; import org.mifosplatform.organisation.staff.exception.StaffNotFoundException; @@ -214,7 +215,7 @@ public class LoanAssembler { final LoanApplicationTerms loanApplicationTerms = this.loanScheduleAssembler.assembleLoanTerms(element); final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled(); final List holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loanApplication.getOfficeId(), - loanApplicationTerms.getExpectedDisbursementDate().toDate()); + loanApplicationTerms.getExpectedDisbursementDate().toDate(), HolidayStatusType.ACTIVE.getValue()); final WorkingDays workingDays = this.workingDaysRepository.findOne(); final boolean allowTransactionsOnNonWorkingDay = this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled(); final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled(); @@ -272,7 +273,7 @@ public class LoanAssembler { final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled(); final List holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loanApplication.getOfficeId(), - loanApplication.getExpectedDisbursedOnLocalDate().toDate()); + loanApplication.getExpectedDisbursedOnLocalDate().toDate(), HolidayStatusType.ACTIVE.getValue()); final WorkingDays workingDays = this.workingDaysRepository.findOne(); final boolean allowTransactionsOnNonWorkingDay = this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled(); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java index d4a5f88e3..d724fefc5 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -34,7 +34,7 @@ import org.mifosplatform.infrastructure.jobs.exception.JobExecutionException; import org.mifosplatform.infrastructure.jobs.service.JobName; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.organisation.holiday.domain.Holiday; -import org.mifosplatform.organisation.holiday.domain.HolidayRepository; +import org.mifosplatform.organisation.holiday.domain.HolidayRepositoryWrapper; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; @@ -133,7 +133,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf private final LoanScheduleGeneratorFactory loanScheduleFactory; private final CalendarInstanceRepository calendarInstanceRepository; private final PaymentDetailWritePlatformService paymentDetailWritePlatformService; - private final HolidayRepository holidayRepository; + private final HolidayRepositoryWrapper holidayRepository; private final ConfigurationDomainService configurationDomainService; private final WorkingDaysRepositoryWrapper workingDaysRepository; private final LoanProductReadPlatformService loanProductReadPlatformService; @@ -152,7 +152,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository, final JournalEntryWritePlatformService journalEntryWritePlatformService, final LoanScheduleGeneratorFactory loanScheduleFactory, final CalendarInstanceRepository calendarInstanceRepository, - final PaymentDetailWritePlatformService paymentDetailWritePlatformService, final HolidayRepository holidayRepository, + final PaymentDetailWritePlatformService paymentDetailWritePlatformService, final HolidayRepositoryWrapper holidayRepository, final ConfigurationDomainService configurationDomainService, final WorkingDaysRepositoryWrapper workingDaysRepository, final LoanProductReadPlatformService loanProductReadPlatformService, final AccountTransfersWritePlatformService accountTransfersWritePlatformService, @@ -1538,7 +1538,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final Collection loanStatuses = new ArrayList(Arrays.asList(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue(), LoanStatus.APPROVED.getValue(), LoanStatus.ACTIVE.getValue())); - // Get all Holidays which are yet to applied to loans + // Get all Holidays which are active and not processed final List holidays = this.holidayRepository.findUnprocessed(); // Loop through all holidays