FINERACT-2169: Refactor calendar controller and service;

This commit is contained in:
viktorpavlenko
2025-04-10 10:59:59 +02:00
committed by Adam Saghy
parent 64b453e9ab
commit 3260f76ca7
6 changed files with 107 additions and 118 deletions
@@ -18,6 +18,7 @@
*/ */
package org.apache.fineract.portfolio.calendar.data; package org.apache.fineract.portfolio.calendar.data;
import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalTime; import java.time.LocalTime;
@@ -42,6 +43,9 @@ import org.apache.fineract.portfolio.common.domain.NthDayType;
@Accessors(chain = true) @Accessors(chain = true)
public final class CalendarData implements Serializable { public final class CalendarData implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private Long id; private Long id;
private Long calendarInstanceId; private Long calendarInstanceId;
private Long entityId; private Long entityId;
@@ -0,0 +1,42 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.calendar.data.request;
import java.io.Serial;
import java.io.Serializable;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class CalendarRequest implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private String repeatsOnDay;
private String dateFormat;
private String repeating;
private String interval;
private String typeId;
private String locale;
private String title;
private String startDate;
private String frequency;
}
@@ -20,7 +20,9 @@ package org.apache.fineract.portfolio.calendar.domain;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import lombok.Getter;
@Getter
public enum CalendarEntityType { public enum CalendarEntityType {
INVALID(0, "calendarEntityType.invalid"), // INVALID(0, "calendarEntityType.invalid"), //
@@ -40,16 +42,10 @@ public enum CalendarEntityType {
this.code = code; this.code = code;
} }
public Integer getValue() {
return this.value;
}
public String getCode() {
return this.code;
}
private static final Map<Integer, CalendarEntityType> intToEnumMap = new HashMap<>(); private static final Map<Integer, CalendarEntityType> intToEnumMap = new HashMap<>();
@Getter
private static int minValue; private static int minValue;
@Getter
private static int maxValue; private static int maxValue;
static { static {
@@ -70,21 +66,12 @@ public enum CalendarEntityType {
} }
public static CalendarEntityType fromInt(final int i) { public static CalendarEntityType fromInt(final int i) {
final CalendarEntityType entityType = intToEnumMap.get(Integer.valueOf(i)); return intToEnumMap.get(i);
return entityType;
}
public static int getMinValue() {
return minValue;
}
public static int getMaxValue() {
return maxValue;
} }
@Override @Override
public String toString() { public String toString() {
return name().toString(); return name();
} }
public static boolean isGroup(final Integer value) { public static boolean isGroup(final Integer value) {
@@ -18,6 +18,12 @@
*/ */
package org.apache.fineract.portfolio.calendar.api; package org.apache.fineract.portfolio.calendar.api;
import static org.apache.fineract.portfolio.calendar.domain.CalendarEntityType.CENTERS;
import static org.apache.fineract.portfolio.calendar.domain.CalendarEntityType.CLIENTS;
import static org.apache.fineract.portfolio.calendar.domain.CalendarEntityType.GROUPS;
import static org.apache.fineract.portfolio.calendar.domain.CalendarEntityType.LOANS;
import static org.apache.fineract.portfolio.calendar.domain.CalendarEntityType.SAVINGS;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE; import jakarta.ws.rs.DELETE;
@@ -34,10 +40,9 @@ import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.UriInfo; import jakarta.ws.rs.core.UriInfo;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.domain.CommandWrapper; import org.apache.fineract.commands.domain.CommandWrapper;
@@ -51,7 +56,7 @@ import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSeria
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer; import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.portfolio.calendar.data.CalendarData; import org.apache.fineract.portfolio.calendar.data.CalendarData;
import org.apache.fineract.portfolio.calendar.domain.Calendar; import org.apache.fineract.portfolio.calendar.data.request.CalendarRequest;
import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType; import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
import org.apache.fineract.portfolio.calendar.exception.CalendarEntityTypeNotSupportedException; import org.apache.fineract.portfolio.calendar.exception.CalendarEntityTypeNotSupportedException;
import org.apache.fineract.portfolio.calendar.service.CalendarDropdownReadPlatformService; import org.apache.fineract.portfolio.calendar.service.CalendarDropdownReadPlatformService;
@@ -65,15 +70,6 @@ import org.springframework.stereotype.Component;
@RequiredArgsConstructor @RequiredArgsConstructor
public class CalendarsApiResource { public class CalendarsApiResource {
/**
* The set of parameters that are supported in response for {@link Calendar}
*/
private static final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<>(
Arrays.asList("id", "entityId", "entityType", "title", "description", "location", "startDate", "endDate", "duration", "type",
"repeating", "recurrence", "frequency", "interval", "repeatsOnDay", "remindBy", "firstReminder", "secondReminder",
"humanReadable", "createdDate", "lastUpdatedDate", "createdByUserId", "createdByUsername", "lastUpdatedByUserId",
"lastUpdatedByUsername", "recurringDates", "nextTenRecurringDates", "entityTypeOptions", "calendarTypeOptions",
"remindByOptions", "frequencyOptions", "repeatsOnDayOptions"));
private static final String RESOURCE_NAME_FOR_PERMISSIONS = "CALENDAR"; private static final String RESOURCE_NAME_FOR_PERMISSIONS = "CALENDAR";
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
@@ -87,26 +83,23 @@ public class CalendarsApiResource {
@Path("{calendarId}") @Path("{calendarId}")
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String retrieveCalendar(@PathParam("calendarId") final Long calendarId, @PathParam("entityType") final String entityType, public CalendarData retrieveCalendar(@PathParam("calendarId") final Long calendarId, @PathParam("entityType") final String entityType,
@PathParam("entityId") final Long entityId, @Context final UriInfo uriInfo) { @PathParam("entityId") final Long entityId, @Context final UriInfo uriInfo) {
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
final Integer entityTypeId = CalendarEntityType.valueOf(entityType.toUpperCase()).getValue(); final Integer entityTypeId = CalendarEntityType.valueOf(entityType.toUpperCase()).getValue();
CalendarData calendarData = this.readPlatformService.retrieveCalendar(calendarId, entityId, entityTypeId); final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
// Include recurring date details CalendarData calendarData = readPlatformService.retrieveCalendar(calendarId, entityId, entityTypeId);
final boolean withHistory = true; final Collection<LocalDate> recurringDates = readPlatformService.generateRecurringDates(calendarData, true, null);
final LocalDate tillDate = null; final Collection<LocalDate> nextTenRecurringDates = readPlatformService.generateNextTenRecurringDates(calendarData);
final Collection<LocalDate> recurringDates = this.readPlatformService.generateRecurringDates(calendarData, withHistory, tillDate); calendarData.setRecurringDates(recurringDates);
final Collection<LocalDate> nextTenRecurringDates = this.readPlatformService.generateNextTenRecurringDates(calendarData); calendarData.setNextTenRecurringDates(nextTenRecurringDates);
final LocalDate recentEligibleMeetingDate = null;
calendarData = CalendarData.withRecurringDates(calendarData, recurringDates, nextTenRecurringDates, recentEligibleMeetingDate);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
if (settings.isTemplate()) { if (settings.isTemplate()) {
calendarData = handleTemplate(calendarData); calendarData = handleTemplate(calendarData);
} }
return this.toApiJsonSerializer.serialize(settings, calendarData, RESPONSE_DATA_PARAMETERS); return calendarData;
} }
/** /**
@@ -119,53 +112,42 @@ public class CalendarsApiResource {
@GET @GET
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String retrieveCalendarsByEntity(@PathParam("entityType") final String entityType, @PathParam("entityId") final Long entityId, public List<CalendarData> retrieveCalendarsByEntity(@PathParam("entityType") final String entityType,
@Context final UriInfo uriInfo, @DefaultValue("all") @QueryParam("calendarType") final String calendarType) { @PathParam("entityId") final Long entityId, @Context final UriInfo uriInfo,
@DefaultValue("all") @QueryParam("calendarType") final String calendarType) {
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
final Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters()); final Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
final List<CalendarData> calendarsData = new ArrayList<>();
Collection<CalendarData> calendarsData = new ArrayList<>();
final List<Integer> calendarTypeOptions = CalendarUtils.createIntegerListFromQueryParameter(calendarType); final List<Integer> calendarTypeOptions = CalendarUtils.createIntegerListFromQueryParameter(calendarType);
if (!associationParameters.isEmpty() && associationParameters.contains("parentCalendars")) { if (!associationParameters.isEmpty() && associationParameters.contains("parentCalendars")) {
calendarsData.addAll(this.readPlatformService.retrieveParentCalendarsByEntity(entityId, calendarsData.addAll(readPlatformService.retrieveParentCalendarsByEntity(entityId,
CalendarEntityType.valueOf(entityType.toUpperCase()).getValue(), calendarTypeOptions)); CalendarEntityType.valueOf(entityType.toUpperCase()).getValue(), calendarTypeOptions));
} }
calendarsData.addAll(this.readPlatformService.retrieveCalendarsByEntity(entityId, calendarsData.addAll(readPlatformService.retrieveCalendarsByEntity(entityId,
CalendarEntityType.valueOf(entityType.toUpperCase()).getValue(), calendarTypeOptions)); CalendarEntityType.valueOf(entityType.toUpperCase()).getValue(), calendarTypeOptions));
// Add recurring dates return readPlatformService.updateWithRecurringDates(calendarsData);
calendarsData = this.readPlatformService.updateWithRecurringDates(calendarsData);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, calendarsData, RESPONSE_DATA_PARAMETERS);
} }
@GET @GET
@Path("template") @Path("template")
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String retrieveNewCalendarDetails(@Context final UriInfo uriInfo, @PathParam("entityType") final String entityType, public CalendarData retrieveNewCalendarDetails(@Context final UriInfo uriInfo, @PathParam("entityType") final String entityType,
@PathParam("entityId") final Long entityId) { @PathParam("entityId") final Long entityId) {
context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); return handleTemplate(readPlatformService.retrieveNewCalendarDetails());
CalendarData calendarData = this.readPlatformService.retrieveNewCalendarDetails();
calendarData = handleTemplate(calendarData);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, calendarData, RESPONSE_DATA_PARAMETERS);
} }
@POST @POST
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String createCalendar(@PathParam("entityType") final String entityType, @PathParam("entityId") final Long entityId, public CommandProcessingResult createCalendar(@PathParam("entityType") final String entityType,
final String apiRequestBodyAsJson) { @PathParam("entityId") final Long entityId, CalendarRequest calendarRequest) {
final CalendarEntityType calendarEntityType = CalendarEntityType.getEntityType(entityType); final CalendarEntityType calendarEntityType = CalendarEntityType.getEntityType(entityType);
if (calendarEntityType == null) { if (calendarEntityType == null) {
@@ -174,11 +156,9 @@ public class CalendarsApiResource {
final CommandWrapper resourceDetails = getResourceDetails(calendarEntityType, entityId); final CommandWrapper resourceDetails = getResourceDetails(calendarEntityType, entityId);
final CommandWrapper commandRequest = new CommandWrapperBuilder().createCalendar(resourceDetails, entityType, entityId) final CommandWrapper commandRequest = new CommandWrapperBuilder().createCalendar(resourceDetails, entityType, entityId)
.withJson(apiRequestBodyAsJson).build(); .withJson(toApiJsonSerializer.serialize(calendarRequest)).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); return commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
} }
@@ -186,69 +166,45 @@ public class CalendarsApiResource {
@Path("{calendarId}") @Path("{calendarId}")
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String updateCalendar(@PathParam("entityType") final String entityType, @PathParam("entityId") final Long entityId, public CommandProcessingResult updateCalendar(@PathParam("entityType") final String entityType,
@PathParam("calendarId") final Long calendarId, final String jsonRequestBody) { @PathParam("entityId") final Long entityId, @PathParam("calendarId") final Long calendarId, final String jsonRequestBody) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateCalendar(entityType, entityId, calendarId) final CommandWrapper commandRequest = new CommandWrapperBuilder().updateCalendar(entityType, entityId, calendarId)
.withJson(jsonRequestBody).build(); .withJson(jsonRequestBody).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); return commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
} }
@DELETE @DELETE
@Path("{calendarId}") @Path("{calendarId}")
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String deleteCalendar(@PathParam("entityType") final String entityType, @PathParam("entityId") final Long entityId, public CommandProcessingResult deleteCalendar(@PathParam("entityType") final String entityType,
@PathParam("calendarId") final Long calendarId) { @PathParam("entityId") final Long entityId, @PathParam("calendarId") final Long calendarId) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteCalendar(entityType, entityId, calendarId).build(); final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteCalendar(entityType, entityId, calendarId).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); return commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
} }
private CalendarData handleTemplate(final CalendarData calendarData) { private CalendarData handleTemplate(final CalendarData calendarData) {
final List<EnumOptionData> entityTypeOptions = this.dropdownReadPlatformService.retrieveCalendarEntityTypeOptions(); final List<EnumOptionData> entityTypeOptions = dropdownReadPlatformService.retrieveCalendarEntityTypeOptions();
final List<EnumOptionData> calendarTypeOptions = this.dropdownReadPlatformService.retrieveCalendarTypeOptions(); final List<EnumOptionData> calendarTypeOptions = dropdownReadPlatformService.retrieveCalendarTypeOptions();
final List<EnumOptionData> remindByOptions = this.dropdownReadPlatformService.retrieveCalendarRemindByOptions(); final List<EnumOptionData> remindByOptions = dropdownReadPlatformService.retrieveCalendarRemindByOptions();
final List<EnumOptionData> frequencyOptions = this.dropdownReadPlatformService.retrieveCalendarFrequencyTypeOptions(); final List<EnumOptionData> frequencyOptions = dropdownReadPlatformService.retrieveCalendarFrequencyTypeOptions();
final List<EnumOptionData> repeatsOnDayOptions = this.dropdownReadPlatformService.retrieveCalendarWeekDaysTypeOptions(); final List<EnumOptionData> repeatsOnDayOptions = dropdownReadPlatformService.retrieveCalendarWeekDaysTypeOptions();
final List<EnumOptionData> frequencyNthDayTypeOptions = this.dropdownReadPlatformService final List<EnumOptionData> frequencyNthDayTypeOptions = dropdownReadPlatformService.retrieveCalendarFrequencyNthDayTypeOptions();
.retrieveCalendarFrequencyNthDayTypeOptions();
return CalendarData.withTemplateOptions(calendarData, entityTypeOptions, calendarTypeOptions, remindByOptions, frequencyOptions, return calendarData.setEntityTypeOptions(entityTypeOptions).setCalendarTypeOptions(calendarTypeOptions)
repeatsOnDayOptions, frequencyNthDayTypeOptions); .setRemindByOptions(remindByOptions).setFrequencyOptions(frequencyOptions).setRepeatsOnDayOptions(repeatsOnDayOptions)
.setFrequencyNthDayTypeOptions(frequencyNthDayTypeOptions);
} }
private CommandWrapper getResourceDetails(final CalendarEntityType type, final Long entityId) { private CommandWrapper getResourceDetails(final CalendarEntityType type, final Long entityId) {
CommandWrapperBuilder resourceDetails = new CommandWrapperBuilder(); final CommandWrapperBuilder resourceDetails = new CommandWrapperBuilder();
switch (type) { return Map.of(CENTERS, resourceDetails.withGroupId(entityId).build(), CLIENTS, resourceDetails.withClientId(entityId).build(),
case CENTERS: GROUPS, resourceDetails.withGroupId(entityId).build(), LOANS, resourceDetails.withLoanId(entityId).build(), SAVINGS,
resourceDetails.withGroupId(entityId); resourceDetails.withSavingsId(entityId).build()).getOrDefault(type, resourceDetails.build());
break;
case CLIENTS:
resourceDetails.withClientId(entityId);
break;
case GROUPS:
resourceDetails.withGroupId(entityId);
break;
case LOANS:
resourceDetails.withLoanId(entityId);
break;
case SAVINGS:
resourceDetails.withSavingsId(entityId);
break;
case INVALID:
break;
case LOAN_RECALCULATION_REST_DETAIL:
break;
default:
break;
}
return resourceDetails.build();
} }
} }
@@ -40,7 +40,7 @@ public interface CalendarReadPlatformService {
Collection<LocalDate> generateNextTenRecurringDates(CalendarData calendarData); Collection<LocalDate> generateNextTenRecurringDates(CalendarData calendarData);
Collection<CalendarData> updateWithRecurringDates(Collection<CalendarData> calendarsData); List<CalendarData> updateWithRecurringDates(Collection<CalendarData> calendarsData);
CalendarData retrieveLoanCalendar(Long loanId); CalendarData retrieveLoanCalendar(Long loanId);
@@ -355,8 +355,8 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
} }
@Override @Override
public Collection<CalendarData> updateWithRecurringDates(final Collection<CalendarData> calendarsData) { public List<CalendarData> updateWithRecurringDates(final Collection<CalendarData> calendarsData) {
final Collection<CalendarData> recuCalendarsData = new ArrayList<>(); final List<CalendarData> recuCalendarsData = new ArrayList<>();
final boolean withHistory = true; final boolean withHistory = true;
final LocalDate tillDate = null; final LocalDate tillDate = null;
for (final CalendarData calendarData : calendarsData) { for (final CalendarData calendarData : calendarsData) {