diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/api/DateParam.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/DateParam.java similarity index 85% rename from fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/api/DateParam.java rename to fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/DateParam.java index c4107ca6c..b801f041c 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/api/DateParam.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/DateParam.java @@ -16,17 +16,16 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.fineract.accounting.journalentry.api; +package org.apache.fineract.infrastructure.core.api; import jakarta.ws.rs.WebApplicationException; import java.time.LocalDate; import java.util.Locale; +import org.apache.fineract.infrastructure.core.data.DateFormat; import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper; /** * Class for parsing dates sent as query parameters - * - * TODO: Vishwas Should move this class to a more generic package */ public class DateParam { @@ -36,7 +35,7 @@ public class DateParam { this.dateAsString = dateStr; } - public LocalDate getDate(final String parameterName, final String dateFormat, final String localeAsString) { + public LocalDate getDate(final String parameterName, final DateFormat dateFormat, final String localeAsString) { final Locale locale = JsonParserHelper.localeFromString(localeAsString); return JsonParserHelper.convertFrom(this.dateAsString, parameterName, dateFormat, locale); } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/JsonCommand.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/JsonCommand.java index 32175c5f7..07c6f0023 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/JsonCommand.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/JsonCommand.java @@ -418,10 +418,6 @@ public final class JsonCommand { return this.fromApiJsonHelper.extractLocalTimeNamed(parameterName, this.parsedCommand); } - public LocalDateTime localDateTimeValueOfParameterNamed(final String parameterName) { - return this.fromApiJsonHelper.extractLocalDateTimeNamed(parameterName, this.parsedCommand); - } - public MonthDay extractMonthDayNamed(final String parameterName) { return this.fromApiJsonHelper.extractMonthDayNamed(parameterName, this.parsedCommand); } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/DateFormat.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/DateFormat.java new file mode 100644 index 000000000..af452c010 --- /dev/null +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/DateFormat.java @@ -0,0 +1,62 @@ +/** + * 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.infrastructure.core.data; + +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DateTimeParseException; +import java.time.format.ResolverStyle; +import java.time.temporal.ChronoField; +import java.util.List; +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; + +public class DateFormat { + + @Getter + private final String dateFormat; + + public DateFormat(String rawDateFormat) { + if (StringUtils.isBlank(rawDateFormat)) { + final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.dateFormat.format", + "Dateformat is null", rawDateFormat); + throw new PlatformApiDataValidationException("validation.msg.invalid.dateFormat.format", "Validation errors exist.", + List.of(error)); + } else { + String compatibleDateFormat = rawDateFormat.replace("yyyy", "uuuu"); + validate(compatibleDateFormat); + dateFormat = compatibleDateFormat; + } + } + + private void validate(String dateTimeFormat) { + try { + DateTimeFormatter formatter = new DateTimeFormatterBuilder().parseCaseInsensitive().parseLenient().appendPattern(dateTimeFormat) + .optionalStart().appendPattern(" HH:mm:ss").optionalEnd().parseDefaulting(ChronoField.HOUR_OF_DAY, 0) + .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0).parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0).toFormatter() + .withResolverStyle(ResolverStyle.STRICT); + } catch (final IllegalArgumentException | DateTimeParseException e) { + final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.dateFormat.format", + "Invalid dateFormat: `" + dateTimeFormat, dateTimeFormat); + throw new PlatformApiDataValidationException("validation.msg.invalid.dateFormat.format", "Validation errors exist.", + List.of(error), e); + } + } +} diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/serialization/JsonParserHelper.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/serialization/JsonParserHelper.java index d93b55519..da47385bc 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/serialization/JsonParserHelper.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/serialization/JsonParserHelper.java @@ -27,6 +27,7 @@ import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.NumberFormat; import java.text.ParseException; +import java.time.DateTimeException; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; @@ -34,14 +35,17 @@ import java.time.MonthDay; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; +import java.time.format.ResolverStyle; import java.time.temporal.ChronoField; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; +import java.util.Objects; import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.apache.fineract.infrastructure.core.data.ApiParameterError; +import org.apache.fineract.infrastructure.core.data.DateFormat; import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; import org.springframework.format.number.NumberStyleFormatter; @@ -329,7 +333,7 @@ public class JsonParserHelper { return value; } - public MonthDay extractMonthDayNamed(final String parameterName, final JsonObject element, final String dateFormat, + public MonthDay extractMonthDayNamed(final String parameterName, final JsonObject element, String dateFormat, final Locale clientApplicationLocale) { MonthDay value = null; if (element.isJsonObject()) { @@ -342,9 +346,9 @@ public class JsonParserHelper { if (StringUtils.isNotBlank(valueAsString)) { try { final DateTimeFormatter formatter = new DateTimeFormatterBuilder().parseCaseInsensitive().parseLenient() - .appendPattern(dateFormat).toFormatter(clientApplicationLocale); + .appendPattern(dateFormat).toFormatter(clientApplicationLocale).withResolverStyle(ResolverStyle.STRICT); value = MonthDay.parse(valueAsString, formatter); - } catch (final IllegalArgumentException e) { + } catch (final IllegalArgumentException | DateTimeException e) { final List dataValidationErrors = new ArrayList<>(); final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.month.day", "The parameter `" + parameterName + "` is invalid based on the monthDayFormat: `" + dateFormat @@ -396,7 +400,7 @@ public class JsonParserHelper { if (element.isJsonObject()) { final JsonObject object = element.getAsJsonObject(); - value = extractLocalDateTimeNamed(parameterName, element, extractTimeFormatParameter(object), parametersPassedInCommand); + value = extractLocalDateTimeNamed(parameterName, element, extractDateFormatParameter(object), parametersPassedInCommand); } return value; } @@ -437,11 +441,11 @@ public class JsonParserHelper { parametersPassedInCommand.add(parameterName); try { - DateTimeFormatter timeFormtter = DateTimeFormatter.ofPattern(timeFormat); + DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern(timeFormat); final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive(); timeValueAsString = primitive.getAsString(); if (StringUtils.isNotBlank(timeValueAsString)) { - value = LocalTime.parse(timeValueAsString, timeFormtter); + value = LocalTime.parse(timeValueAsString, timeFormatter); } } catch (IllegalArgumentException e) { final List dataValidationErrors = new ArrayList<>(); @@ -459,28 +463,31 @@ public class JsonParserHelper { return value; } - public LocalDateTime extractLocalDateTimeNamed(final String parameterName, final JsonElement element, final String timeFormat, + public LocalDateTime extractLocalDateTimeNamed(final String parameterName, final JsonElement element, String timeFormat, final Locale clientApplicationLocale, final Set parametersPassedInCommand) { LocalDateTime value = null; - String timeValueAsString = null; + String timeValueAsString; if (element.isJsonObject()) { final JsonObject object = element.getAsJsonObject(); if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) { parametersPassedInCommand.add(parameterName); try { - DateTimeFormatter timeFormtter = DateTimeFormatter.ofPattern(timeFormat); + timeFormat = timeFormat.replace("y", "u"); final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive(); timeValueAsString = primitive.getAsString(); + DateTimeFormatter timeFormatter = new DateTimeFormatterBuilder().parseCaseInsensitive().parseLenient() + .appendPattern(timeFormat).toFormatter(clientApplicationLocale).withResolverStyle(ResolverStyle.STRICT); if (StringUtils.isNotBlank(timeValueAsString)) { - value = LocalDateTime.parse(timeValueAsString, timeFormtter); + value = LocalDateTime.parse(timeValueAsString, timeFormatter); } - } catch (IllegalArgumentException e) { + } catch (IllegalArgumentException | DateTimeParseException e) { final List dataValidationErrors = new ArrayList<>(); - final String defaultMessage = new StringBuilder("The parameter `" + timeValueAsString + "` is not in correct format.") - .toString(); - final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.TimeFormat", defaultMessage, - parameterName); + final ApiParameterError error = ApiParameterError + .parameterError("validation.msg.invalid.dateFormat.format", + "The parameter `" + parameterName + "` is invalid based on the dateFormat: `" + timeFormat + + "` and locale: `" + clientApplicationLocale + "` provided:", + parameterName, value, timeFormat); dataValidationErrors.add(error); throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors, e); @@ -518,17 +525,27 @@ public class JsonParserHelper { return convertDateTimeFrom(dateAsString, parameterName, dateFormat, clientApplicationLocale).toLocalDate(); } - public static LocalDateTime convertDateTimeFrom(final String dateTimeAsString, final String parameterName, final String dateTimeFormat, + public static LocalDate convertFrom(final String dateAsString, final String parameterName, final DateFormat dateFormat, + final Locale clientApplicationLocale) { + + String rawDateFormat = Objects.isNull(dateFormat) ? null : dateFormat.getDateFormat(); + + return convertDateTimeFrom(dateAsString, parameterName, rawDateFormat, clientApplicationLocale).toLocalDate(); + } + + public static LocalDateTime convertDateTimeFrom(final String dateTimeAsString, final String parameterName, String dateTimeFormat, final Locale clientApplicationLocale) { validateDateFormatAndLocale(parameterName, dateTimeFormat, clientApplicationLocale); LocalDateTime eventLocalDateTime = null; if (StringUtils.isNotBlank(dateTimeAsString)) { try { + dateTimeFormat = dateTimeFormat.replace("y", "u"); DateTimeFormatter formatter = new DateTimeFormatterBuilder().parseCaseInsensitive().parseLenient() .appendPattern(dateTimeFormat).optionalStart().appendPattern(" HH:mm:ss").optionalEnd() .parseDefaulting(ChronoField.HOUR_OF_DAY, 0).parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0) - .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0).toFormatter(clientApplicationLocale); + .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0).toFormatter(clientApplicationLocale) + .withResolverStyle(ResolverStyle.STRICT); eventLocalDateTime = LocalDateTime.parse(dateTimeAsString, formatter); } catch (final IllegalArgumentException | DateTimeParseException e) { final List dataValidationErrors = new ArrayList<>(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/api/JournalEntriesApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/api/JournalEntriesApiResource.java index c5fc810ab..c107c8a60 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/api/JournalEntriesApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/api/JournalEntriesApiResource.java @@ -57,7 +57,9 @@ import org.apache.fineract.infrastructure.bulkimport.data.GlobalEntityType; import org.apache.fineract.infrastructure.bulkimport.service.BulkImportWorkbookPopulatorService; import org.apache.fineract.infrastructure.bulkimport.service.BulkImportWorkbookService; import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper; +import org.apache.fineract.infrastructure.core.api.DateParam; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.infrastructure.core.data.DateFormat; import org.apache.fineract.infrastructure.core.data.UploadRequest; import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException; import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; @@ -117,7 +119,7 @@ public class JournalEntriesApiResource { @QueryParam("orderBy") @Parameter(description = "orderBy") final String orderBy, @QueryParam("sortOrder") @Parameter(description = "sortOrder") final String sortOrder, @QueryParam("locale") @Parameter(description = "locale") final String locale, - @QueryParam("dateFormat") @Parameter(description = "dateFormat") final String dateFormat, + @QueryParam("dateFormat") @Parameter(description = "dateFormat") final String rawDateFormat, @QueryParam("loanId") @Parameter(description = "loanId") final Long loanId, @QueryParam("savingsId") @Parameter(description = "savingsId") final Long savingsId, @QueryParam("runningBalance") @Parameter(description = "runningBalance") final boolean runningBalance, @@ -125,6 +127,8 @@ public class JournalEntriesApiResource { this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermission); + final DateFormat dateFormat = StringUtils.isBlank(rawDateFormat) ? null : new DateFormat(rawDateFormat); + LocalDate fromDate = null; if (fromDateParam != null) { fromDate = fromDateParam.getDate("fromDate", dateFormat, locale); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/email/api/EmailApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/email/api/EmailApiResource.java index 85b33c6d6..50e90b12d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/email/api/EmailApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/email/api/EmailApiResource.java @@ -33,14 +33,16 @@ import jakarta.ws.rs.core.UriInfo; import java.time.LocalDate; import java.util.Collection; import lombok.RequiredArgsConstructor; -import org.apache.fineract.accounting.journalentry.api.DateParam; +import org.apache.commons.lang3.StringUtils; import org.apache.fineract.commands.domain.CommandWrapper; import org.apache.fineract.commands.service.CommandWrapperBuilder; import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; import org.apache.fineract.infrastructure.campaigns.email.data.EmailData; import org.apache.fineract.infrastructure.campaigns.email.service.EmailReadPlatformService; import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper; +import org.apache.fineract.infrastructure.core.api.DateParam; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.infrastructure.core.data.DateFormat; import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer; import org.apache.fineract.infrastructure.core.service.Page; @@ -104,7 +106,10 @@ public class EmailApiResource { @QueryParam("limit") final Integer limit, @QueryParam("status") final Integer status, @QueryParam("orderBy") final String orderBy, @QueryParam("sortOrder") final String sortOrder, @QueryParam("fromDate") final DateParam fromDateParam, @QueryParam("toDate") final DateParam toDateParam, - @QueryParam("locale") final String locale, @QueryParam("dateFormat") final String dateFormat, @Context final UriInfo uriInfo) { + @QueryParam("locale") final String locale, @QueryParam("dateFormat") final String rawDateFormat, + @Context final UriInfo uriInfo) { + + final DateFormat dateFormat = StringUtils.isBlank(rawDateFormat) ? null : new DateFormat(rawDateFormat); this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); LocalDate fromDate = null; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/api/SmsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/api/SmsApiResource.java index 4e191ec1d..e6a7bc455 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/api/SmsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/api/SmsApiResource.java @@ -34,12 +34,14 @@ import jakarta.ws.rs.core.UriInfo; import java.time.LocalDate; import java.util.Collection; import lombok.RequiredArgsConstructor; -import org.apache.fineract.accounting.journalentry.api.DateParam; +import org.apache.commons.lang3.StringUtils; import org.apache.fineract.commands.domain.CommandWrapper; import org.apache.fineract.commands.service.CommandWrapperBuilder; import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper; +import org.apache.fineract.infrastructure.core.api.DateParam; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.infrastructure.core.data.DateFormat; import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer; import org.apache.fineract.infrastructure.core.service.Page; @@ -93,12 +95,14 @@ public class SmsApiResource { public String retrieveAllSmsByStatus(@PathParam("campaignId") final Long campaignId, @Context final UriInfo uriInfo, @QueryParam("status") final Long status, @QueryParam("fromDate") final DateParam fromDateParam, @QueryParam("toDate") final DateParam toDateParam, @QueryParam("locale") final String locale, - @QueryParam("dateFormat") final String dateFormat, @QueryParam("sqlSearch") final String sqlSearch, + @QueryParam("dateFormat") final String rawDateFormat, @QueryParam("sqlSearch") final String sqlSearch, @QueryParam("offset") final Integer offset, @QueryParam("limit") final Integer limit, @QueryParam("orderBy") final String orderBy, @QueryParam("sortOrder") final String sortOrder) { context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions); final SearchParameters searchParameters = SearchParameters.forSMSCampaign(sqlSearch, offset, limit, orderBy, sortOrder); + final DateFormat dateFormat = StringUtils.isBlank(rawDateFormat) ? null : new DateFormat(rawDateFormat); + LocalDate fromDate = null; if (fromDateParam != null) { fromDate = fromDateParam.getDate("fromDate", dateFormat, locale); diff --git a/fineract-provider/src/main/java/org/apache/fineract/interoperation/util/InteropUtil.java b/fineract-provider/src/main/java/org/apache/fineract/interoperation/util/InteropUtil.java index d93c24ec2..e120ac7b5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/interoperation/util/InteropUtil.java +++ b/fineract-provider/src/main/java/org/apache/fineract/interoperation/util/InteropUtil.java @@ -26,7 +26,7 @@ public final class InteropUtil { } - public static final String ISO8601_DATE_TIME_FORMAT = "yyyy-MM-ddTHH:mm:ss.SSS[-HH:MM]"; + public static final String ISO8601_DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS[-HH:MM]"; public static final String ISO8601_DATE_FORMAT = "yyyy-MM-dd"; public static final Locale DEFAULT_LOCALE = Locale.US; diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/api/HolidaysApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/api/HolidaysApiResource.java index ddac2519d..916bf63aa 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/api/HolidaysApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/holiday/api/HolidaysApiResource.java @@ -46,12 +46,13 @@ import java.time.LocalDate; import java.util.Collection; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; -import org.apache.fineract.accounting.journalentry.api.DateParam; import org.apache.fineract.commands.domain.CommandWrapper; import org.apache.fineract.commands.service.CommandWrapperBuilder; import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper; +import org.apache.fineract.infrastructure.core.api.DateParam; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.infrastructure.core.data.DateFormat; import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException; import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer; @@ -192,10 +193,12 @@ public class HolidaysApiResource { @QueryParam("fromDate") @Parameter(description = "fromDate") final DateParam fromDateParam, @QueryParam("toDate") @Parameter(description = "toDate") final DateParam toDateParam, @QueryParam("locale") @Parameter(description = "locale") final String locale, - @QueryParam("dateFormat") @Parameter(description = "dateFormat") final String dateFormat) { + @QueryParam("dateFormat") @Parameter(description = "dateFormat") final String rawDateFormat) { this.context.authenticatedUser().validateHasReadPermission(HOLIDAY_RESOURCE_NAME); + final DateFormat dateFormat = StringUtils.isBlank(rawDateFormat) ? null : new DateFormat(rawDateFormat); + LocalDate fromDate = null; if (fromDateParam != null) { fromDate = fromDateParam.getDate("fromDate", dateFormat, locale); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/api/StandingInstructionHistoryApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/api/StandingInstructionHistoryApiResource.java index 4648830f1..ced9d6390 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/api/StandingInstructionHistoryApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/api/StandingInstructionHistoryApiResource.java @@ -35,8 +35,10 @@ import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.UriInfo; import java.time.LocalDate; import lombok.RequiredArgsConstructor; -import org.apache.fineract.accounting.journalentry.api.DateParam; +import org.apache.commons.lang3.StringUtils; import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper; +import org.apache.fineract.infrastructure.core.api.DateParam; +import org.apache.fineract.infrastructure.core.data.DateFormat; import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer; import org.apache.fineract.infrastructure.core.service.Page; @@ -79,12 +81,14 @@ public class StandingInstructionHistoryApiResource { @QueryParam("fromAccountId") @Parameter(description = "fromAccountId") final Long fromAccount, @QueryParam("fromAccountType") @Parameter(description = "fromAccountType") final Integer fromAccountType, @QueryParam("locale") @Parameter(description = "locale") final String locale, - @QueryParam("dateFormat") @Parameter(description = "dateFormat") final String dateFormat, + @QueryParam("dateFormat") @Parameter(description = "dateFormat") final String rawDateFormat, @QueryParam("fromDate") @Parameter(description = "fromDate") final DateParam fromDateParam, @QueryParam("toDate") @Parameter(description = "toDate") final DateParam toDateParam) { this.context.authenticatedUser().validateHasReadPermission(StandingInstructionApiConstants.STANDING_INSTRUCTION_RESOURCE_NAME); + final DateFormat dateFormat = StringUtils.isBlank(rawDateFormat) ? null : new DateFormat(rawDateFormat); + final SearchParameters searchParameters = SearchParameters.forAccountTransfer(sqlSearch, externalId, offset, limit, orderBy, sortOrder); LocalDate startDateRange = null; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java index 0b491d5df..35c273474 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java @@ -50,7 +50,6 @@ import java.util.List; import java.util.Set; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; -import org.apache.fineract.accounting.journalentry.api.DateParam; import org.apache.fineract.commands.domain.CommandWrapper; import org.apache.fineract.commands.service.CommandWrapperBuilder; import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; @@ -59,8 +58,10 @@ import org.apache.fineract.infrastructure.bulkimport.service.BulkImportWorkbookP import org.apache.fineract.infrastructure.bulkimport.service.BulkImportWorkbookService; import org.apache.fineract.infrastructure.core.api.ApiParameterHelper; import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper; +import org.apache.fineract.infrastructure.core.api.DateParam; import org.apache.fineract.infrastructure.core.api.JsonQuery; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.infrastructure.core.data.DateFormat; import org.apache.fineract.infrastructure.core.data.PaginationParameters; import org.apache.fineract.infrastructure.core.data.UploadRequest; import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException; @@ -170,7 +171,7 @@ public class CentersApiResource { this.context.authenticatedUser().validateHasReadPermission(GroupingTypesApiConstants.CENTER_RESOURCE_NAME); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); if (meetingDateParam != null && officeId != null) { - LocalDate meetingDate = meetingDateParam.getDate("meetingDate", dateFormat, locale); + LocalDate meetingDate = meetingDateParam.getDate("meetingDate", new DateFormat(dateFormat), locale); Collection staffCenterDataArray = this.centerReadPlatformService.retriveAllCentersByMeetingDate(officeId, meetingDate, staffId); return this.toApiJsonSerializer.serialize(settings, staffCenterDataArray, diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java index 1fd74e59b..c1425e938 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java @@ -45,12 +45,14 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import lombok.AllArgsConstructor; -import org.apache.fineract.accounting.journalentry.api.DateParam; +import org.apache.commons.lang3.StringUtils; import org.apache.fineract.commands.domain.CommandWrapper; import org.apache.fineract.commands.service.CommandWrapperBuilder; import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper; +import org.apache.fineract.infrastructure.core.api.DateParam; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.infrastructure.core.data.DateFormat; import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException; import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; @@ -111,10 +113,12 @@ public class LoanTransactionsApiResource { @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = LoanTransactionsApiResourceSwagger.GetLoansLoanIdTransactionsTemplateResponse.class))) }) public String retrieveTransactionTemplate(@PathParam("loanId") @Parameter(description = "loanId", required = true) final Long loanId, @QueryParam("command") @Parameter(description = "command") final String commandParam, @Context final UriInfo uriInfo, - @QueryParam("dateFormat") @Parameter(description = "dateFormat") final String dateFormat, + @QueryParam("dateFormat") @Parameter(description = "dateFormat") final String rawDateFormat, @QueryParam("transactionDate") @Parameter(description = "transactionDate") final DateParam transactionDateParam, @QueryParam("locale") @Parameter(description = "locale") final String locale) { + final DateFormat dateFormat = StringUtils.isBlank(rawDateFormat) ? null : new DateFormat(rawDateFormat); + return retrieveTransactionTemplate(loanId, null, commandParam, uriInfo, dateFormat, transactionDateParam, locale); } @@ -139,10 +143,12 @@ public class LoanTransactionsApiResource { public String retrieveTransactionTemplate( @PathParam("loanExternalId") @Parameter(description = "loanExternalId", required = true) final String loanExternalId, @QueryParam("command") @Parameter(description = "command") final String commandParam, @Context final UriInfo uriInfo, - @QueryParam("dateFormat") @Parameter(description = "dateFormat") final String dateFormat, + @QueryParam("dateFormat") @Parameter(description = "dateFormat") final String rawDateFormat, @QueryParam("transactionDate") @Parameter(description = "transactionDate") final DateParam transactionDateParam, @QueryParam("locale") @Parameter(description = "locale") final String locale) { + final DateFormat dateFormat = StringUtils.isBlank(rawDateFormat) ? null : new DateFormat(rawDateFormat); + return retrieveTransactionTemplate(null, loanExternalId, commandParam, uriInfo, dateFormat, transactionDateParam, locale); } @@ -476,7 +482,7 @@ public class LoanTransactionsApiResource { } private String retrieveTransactionTemplate(Long loanId, String loanExternalIdStr, String commandParam, UriInfo uriInfo, - String dateFormat, DateParam transactionDateParam, String locale) { + DateFormat dateFormat, DateParam transactionDateParam, String locale) { this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions); ExternalId loanExternalId = ExternalIdFactory.produce(loanExternalIdStr); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/DepositAccountDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/DepositAccountDataValidator.java index 5603a1526..a28eab439 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/DepositAccountDataValidator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/DepositAccountDataValidator.java @@ -720,10 +720,6 @@ public class DepositAccountDataValidator { final JsonObject savingsChargeElement = array.get(i).getAsJsonObject(); - // final Long id = - // this.fromApiJsonHelper.extractLongNamed(idParamName, - // savingsChargeElement); - final Long chargeId = this.fromApiJsonHelper.extractLongNamed(chargeIdParamName, savingsChargeElement); baseDataValidator.reset().parameter(chargeIdParamName).value(chargeId).longGreaterThanZero(); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AccountingScenarioIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AccountingScenarioIntegrationTest.java index f9f72b8cf..db4dfe687 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AccountingScenarioIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AccountingScenarioIntegrationTest.java @@ -544,7 +544,7 @@ public class AccountingScenarioIntegrationTest { LOG.info("--------------------------------APPLYING FOR FIXED DEPOSIT ACCOUNT --------------------------------"); final String fixedDepositApplicationJSON = new FixedDepositAccountHelper(requestSpec, responseSpec) // .withSubmittedOnDate(submittedOnDate).build(clientID, productID, penalInterestType); - return FixedDepositAccountHelper.applyFixedDepositApplication(fixedDepositApplicationJSON, requestSpec, responseSpec); + return FixedDepositAccountHelper.applyFixedDepositApplicationGetId(fixedDepositApplicationJSON, requestSpec, responseSpec); } private Integer createRecurringDepositProduct(final String validFrom, final String validTo, Account... accounts) { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/DateValidationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/DateValidationTest.java new file mode 100644 index 000000000..57a5270fd --- /dev/null +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/DateValidationTest.java @@ -0,0 +1,229 @@ +/** + * 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.integrationtests; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import io.restassured.builder.RequestSpecBuilder; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.http.ContentType; +import io.restassured.specification.RequestSpecification; +import io.restassured.specification.ResponseSpecification; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; +import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.client.models.PostClientsRequest; +import org.apache.fineract.client.models.PostClientsResponse; +import org.apache.fineract.integrationtests.common.ClientHelper; +import org.apache.fineract.integrationtests.common.Utils; +import org.apache.fineract.integrationtests.common.accounting.Account; +import org.apache.fineract.integrationtests.common.accounting.AccountHelper; +import org.apache.fineract.integrationtests.common.fixeddeposit.FixedDepositAccountHelper; +import org.apache.fineract.integrationtests.common.fixeddeposit.FixedDepositProductHelper; +import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; +import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; +import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper; +import org.apache.fineract.integrationtests.interoperation.InteropHelper; +import org.apache.fineract.interoperation.domain.InteropInitiatorType; +import org.apache.fineract.interoperation.domain.InteropTransactionRole; +import org.apache.fineract.interoperation.domain.InteropTransactionScenario; +import org.apache.fineract.interoperation.util.InteropUtil; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +@Slf4j +public class DateValidationTest { + + public static final String WHOLE_TERM = "1"; + public static final String MINIMUM_OPENING_BALANCE = "1000.0"; + public static final String ACCOUNT_TYPE_INDIVIDUAL = "INDIVIDUAL"; + + private ResponseSpecification responseSpec; + private ResponseSpecification errorResponseSpec; + private RequestSpecification requestSpec; + private ClientHelper clientHelper; + private LoanTransactionHelper loanTransactionHelper; + private InteropHelper interopHelper; + private AccountHelper accountHelper; + + @BeforeEach + public void setup() { + Utils.initializeRESTAssured(); + this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); + this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); + this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); + this.errorResponseSpec = new ResponseSpecBuilder().expectStatusCode(400).build(); + this.clientHelper = new ClientHelper(this.requestSpec, this.responseSpec); + this.loanTransactionHelper = new LoanTransactionHelper(requestSpec, responseSpec); + this.interopHelper = new InteropHelper(requestSpec, errorResponseSpec); + this.accountHelper = new AccountHelper(requestSpec, responseSpec); + } + + @Test + public void testShouldFailIfDateIsInvalid() { + + String invalidDate = "31 June 2022"; + + PostClientsRequest postClientsRequest = ClientHelper.defaultClientCreationRequest(); + + PostClientsResponse client = clientHelper.createClient(postClientsRequest); + Long clientId = client.getClientId(); + + final String loanProductJSON = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentTypeAsMonth() + .withRepaymentAfterEvery("1").withNumberOfRepayments("1").withRepaymentTypeAsMonth().withinterestRatePerPeriod("0") + .withInterestRateFrequencyTypeAsMonths().withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsDecliningBalance() + .withAccountingRuleAsNone().withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withDaysInMonth("30") + .withDaysInYear("365").withMoratorium("0", "0").withInArrearsTolerance("1001").withMultiDisburse() + .withDisallowExpectedDisbursements(true).build(null); + final Integer loanProductID = loanTransactionHelper.getLoanProductId(loanProductJSON); + + loanTransactionHelper = new LoanTransactionHelper(requestSpec, errorResponseSpec); + + final String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("1") + .withLoanTermFrequencyAsMonths().withNumberOfRepayments("1").withRepaymentEveryAfter("1") + .withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("0").withInterestTypeAsFlatBalance() + .withAmortizationTypeAsEqualPrincipalPayments().withInterestCalculationPeriodTypeSameAsRepaymentPeriod() + .withExpectedDisbursementDate(invalidDate).withSubmittedOnDate("01 March 2022").withLoanType("individual") + .build(clientId.toString(), loanProductID.toString(), null); + HashMap response = (HashMap) loanTransactionHelper.createLoanAccount(loanApplicationJSON, ""); + List> errors = (List) response.get("errors"); + assertNotNull(errors); + HashMap error = errors.get(0); + assertNotNull(error); + assertEquals( + "The parameter `expectedDisbursementDate` is invalid based on the dateFormat: `dd MMMM uuuu` and locale: `en_GB` provided:", + error.get("developerMessage")); + } + + @Test + public void testShouldFailWithInvalidDateTime() { + String requestCode = UUID.randomUUID().toString(); + InteropTransactionRole role = InteropTransactionRole.PAYER; + String requestBody = buildRequestBody(requestCode, role); + String response = interopHelper.postTransactionRequest(requestCode, role, requestBody); + HashMap map = new Gson().fromJson(response, new TypeToken>() {}.getType()); + List> errors = (List) map.get("errors"); + assertNotNull(errors); + Map error = errors.get(0); + assertNotNull(error); + assertEquals("The parameter `expiration` is invalid based on the dateFormat: `dd MMMM uuuu HH:mm:ss` and locale: `en` provided:", + error.get("developerMessage")); + } + + @Test + public void testShouldFailWithInvalidMonthDay() { + final Account assetAccount = this.accountHelper.createAssetAccount(); + final Account incomeAccount = this.accountHelper.createIncomeAccount(); + final Account expenseAccount = this.accountHelper.createExpenseAccount(); + final Account liabilityAccount = this.accountHelper.createLiabilityAccount(); + + DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendPattern("dd MMMM yyyy").toFormatter(Locale.US); + + LocalDate todaysDate = LocalDate.now(ZoneId.systemDefault()).minusMonths(3); + final String VALID_FROM = todaysDate.format(formatter); + todaysDate = todaysDate.plusYears(10); + final String VALID_TO = todaysDate.format(formatter); + + todaysDate = LocalDate.now(ZoneId.systemDefault()).minusMonths(1); + final String SUBMITTED_ON_DATE = todaysDate.format(formatter); + + PostClientsRequest postClientsRequest = ClientHelper.defaultClientCreationRequest(); + + Long clientId = clientHelper.createClient(postClientsRequest).getClientId(); + Assertions.assertNotNull(clientId); + + Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, assetAccount, liabilityAccount, incomeAccount, + expenseAccount); + Assertions.assertNotNull(fixedDepositProductId); + + final Integer maturityInstructionId = 400; + String response = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(), SUBMITTED_ON_DATE, + maturityInstructionId, getCharges()); + HashMap map = new Gson().fromJson(response, new TypeToken>() {}.getType()); + List> errors = (List) map.get("errors"); + assertNotNull(errors); + Map error = errors.get(0); + assertNotNull(error); + assertEquals("The parameter `feeOnMonthDay` is invalid based on the monthDayFormat: `dd MMM` and locale: `en_GB` provided:", + error.get("developerMessage")); + } + + private String buildRequestBody(final String requestCode, final InteropTransactionRole role) { + HashMap map = new HashMap<>(); + map.put(InteropUtil.PARAM_TRANSACTION_CODE, UUID.randomUUID().toString()); + map.put(InteropUtil.PARAM_REQUEST_CODE, requestCode); + map.put(InteropUtil.PARAM_ACCOUNT_ID, UUID.randomUUID().toString()); + map.put(InteropUtil.PARAM_TRANSACTION_ROLE, role); + map.put(InteropUtil.PARAM_EXPIRATION, "31 November 2022 11:11:11"); + map.put(InteropUtil.PARAM_LOCALE, "en"); + map.put(InteropUtil.PARAM_DATE_FORMAT, "dd MMMM yyyy HH:mm:ss"); + + HashMap amountMap = new HashMap<>(); + amountMap.put(InteropUtil.PARAM_AMOUNT, "10"); + amountMap.put(InteropUtil.PARAM_CURRENCY, "EUR"); + map.put(InteropUtil.PARAM_AMOUNT, amountMap); + + HashMap typeMap = new HashMap<>(); + typeMap.put(InteropUtil.PARAM_SCENARIO, InteropTransactionScenario.PAYMENT); + typeMap.put(InteropUtil.PARAM_INITIATOR, InteropTransactionRole.PAYEE); + typeMap.put(InteropUtil.PARAM_INITIATOR_TYPE, InteropInitiatorType.CONSUMER); + map.put(InteropUtil.PARAM_TRANSACTION_TYPE, typeMap); + + return new Gson().toJson(map); + } + + private Integer createFixedDepositProduct(final String validFrom, final String validTo, Account... accounts) { + log.info("------------------------------CREATING NEW FIXED DEPOSIT PRODUCT ---------------------------------------"); + FixedDepositProductHelper fixedDepositProductHelper = new FixedDepositProductHelper(this.requestSpec, this.responseSpec); + fixedDepositProductHelper = fixedDepositProductHelper.withAccountingRuleAsCashBased(accounts); + final String fixedDepositProductJSON = fixedDepositProductHelper.withPeriodRangeChart() // + .build(validFrom, validTo, true); + return FixedDepositProductHelper.createFixedDepositProduct(fixedDepositProductJSON, requestSpec, responseSpec); + } + + private String applyForFixedDepositApplication(final String clientID, final String productID, final String submittedOnDate, + final Integer maturityInstructionId, final List> charges) { + log.info("--------------------------------APPLYING FOR FIXED DEPOSIT ACCOUNT --------------------------------"); + final String fixedDepositApplicationJSON = new FixedDepositAccountHelper(this.requestSpec, this.errorResponseSpec) // + .withSubmittedOnDate(submittedOnDate).withMaturityInstructionId(maturityInstructionId).withCharges(charges) + .build(clientID, productID, WHOLE_TERM); + return FixedDepositAccountHelper.applyFixedDepositApplication(fixedDepositApplicationJSON, this.requestSpec, + this.errorResponseSpec); + } + + private List> getCharges() { + List> list = new ArrayList<>(); + HashMap map = new HashMap<>(); + map.put("feeOnMonthDay", "31 June"); + list.add(map); + return list; + } +} diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/FixedDepositTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/FixedDepositTest.java index 5da091e8c..69741dcb5 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/FixedDepositTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/FixedDepositTest.java @@ -2584,7 +2584,8 @@ public class FixedDepositTest { log.info("--------------------------------APPLYING FOR FIXED DEPOSIT ACCOUNT --------------------------------"); final String fixedDepositApplicationJSON = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec) // .withSubmittedOnDate(submittedOnDate).build(clientID, productID, penalInterestType); - return FixedDepositAccountHelper.applyFixedDepositApplication(fixedDepositApplicationJSON, this.requestSpec, this.responseSpec); + return FixedDepositAccountHelper.applyFixedDepositApplicationGetId(fixedDepositApplicationJSON, this.requestSpec, + this.responseSpec); } private Integer applyForFixedDepositApplication(final String clientID, final String productID, final String submittedOnDate, @@ -2593,7 +2594,8 @@ public class FixedDepositTest { final String fixedDepositApplicationJSON = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec) // .withSubmittedOnDate(submittedOnDate).withMaturityInstructionId(maturityInstructionId) .build(clientID, productID, penalInterestType); - return FixedDepositAccountHelper.applyFixedDepositApplication(fixedDepositApplicationJSON, this.requestSpec, this.responseSpec); + return FixedDepositAccountHelper.applyFixedDepositApplicationGetId(fixedDepositApplicationJSON, this.requestSpec, + this.responseSpec); } private Integer applyForFixedDepositApplication(final String clientID, final String productID, final String submittedOnDate, @@ -2603,7 +2605,8 @@ public class FixedDepositTest { // .withSubmittedOnDate(submittedOnDate).withDepositPeriod(depositPeriod).withDepositAmount(depositAmount) .build(clientID, productID, penalInterestType); - return FixedDepositAccountHelper.applyFixedDepositApplication(fixedDepositApplicationJSON, this.requestSpec, this.responseSpec); + return FixedDepositAccountHelper.applyFixedDepositApplicationGetId(fixedDepositApplicationJSON, this.requestSpec, + this.responseSpec); } private Integer createSavingsProduct(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java index c6c7e3500..445437797 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SchedulerJobsTestResults.java @@ -1288,7 +1288,7 @@ public class SchedulerJobsTestResults { final String fixedDepositApplicationJSON = new FixedDepositAccountHelper(requestSpec, responseSpec) .withSubmittedOnDate(submittedOnDate).withSavings(savingsId).transferInterest(true) .withLockinPeriodFrequency("1", FixedDepositAccountHelper.DAYS).build(clientID, productID, penalInterestType); - return FixedDepositAccountHelper.applyFixedDepositApplication(fixedDepositApplicationJSON, requestSpec, responseSpec); + return FixedDepositAccountHelper.applyFixedDepositApplicationGetId(fixedDepositApplicationJSON, requestSpec, responseSpec); } private void validateNumberForEqualExcludePrecision(String val, String val2) { diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/fixeddeposit/FixedDepositAccountHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/fixeddeposit/FixedDepositAccountHelper.java index 9021b5d73..67860327b 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/fixeddeposit/FixedDepositAccountHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/fixeddeposit/FixedDepositAccountHelper.java @@ -24,6 +24,7 @@ import io.restassured.specification.ResponseSpecification; import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; +import java.util.List; import org.apache.fineract.integrationtests.common.CommonConstants; import org.apache.fineract.integrationtests.common.Utils; import org.slf4j.Logger; @@ -97,6 +98,7 @@ public class FixedDepositAccountHelper { private String savingsId = null; private boolean transferInterest = false; private Integer maturityInstructionId; + private List> charges; public String build(final String clientId, final String productId, final String penalInterestType) { final HashMap map = new HashMap<>(); @@ -129,19 +131,26 @@ public class FixedDepositAccountHelper { map.put("linkAccountId", savingsId); map.put("transferInterestToSavings", transferInterest); map.put("maturityInstructionId", maturityInstructionId); + map.put("charges", charges); String fixedDepositAccountJson = new Gson().toJson(map); LOG.info("{}", fixedDepositAccountJson); return fixedDepositAccountJson; } - public static Integer applyFixedDepositApplication(final String fixedDepositAccountAsJson, final RequestSpecification requestSpec, + public static Integer applyFixedDepositApplicationGetId(final String fixedDepositAccountAsJson, final RequestSpecification requestSpec, final ResponseSpecification responseSpec) { LOG.info("--------------------- APPLYING FOR FIXED DEPOSIT ACCOUNT ------------------------"); return Utils.performServerPost(requestSpec, responseSpec, APPLY_FIXED_DEPOSIT_ACCOUNT_URL, fixedDepositAccountAsJson, CommonConstants.RESPONSE_RESOURCE_ID); } + public static String applyFixedDepositApplication(final String fixedDepositAccountAsJson, final RequestSpecification requestSpec, + final ResponseSpecification responseSpec) { + LOG.info("--------------------- APPLYING FOR FIXED DEPOSIT ACCOUNT ------------------------"); + return Utils.performServerPost(requestSpec, responseSpec, APPLY_FIXED_DEPOSIT_ACCOUNT_URL, fixedDepositAccountAsJson); + } + public static HashMap getFixedDepositAccountById(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, final Integer accountID) { final String GET_FIXED_DEPOSIT_BY_ID_URL = FIXED_DEPOSIT_ACCOUNT_URL + "/" + accountID + "?" + Utils.TENANT_IDENTIFIER; @@ -475,4 +484,9 @@ public class FixedDepositAccountHelper { this.maturityInstructionId = maturityInstructionId; return this; } + + public FixedDepositAccountHelper withCharges(List> charges) { + this.charges = charges; + return this; + } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/interoperation/InteropHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/interoperation/InteropHelper.java index 0f4103e01..22a36c394 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/interoperation/InteropHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/interoperation/InteropHelper.java @@ -214,6 +214,15 @@ public class InteropHelper { return response; } + public String postTransactionRequest(String requestCode, InteropTransactionRole role, String request) { + String url = buildUrl(REQUESTS_URL); + LOG.debug("Calling Interoperable POST Request: {}, body: {}", url, request); + + String response = Utils.performServerPost(requestSpec, responseSpec, url, request, null); + LOG.debug("Response Interoperable POST Request: {}", response); + return response; + } + private String buildTransactionRequestJson(String requestCode, InteropTransactionRole role) { HashMap map = new HashMap<>(); map.put(InteropUtil.PARAM_TRANSACTION_CODE, transactionCode);