diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index 7fe3fc9de..c002f6e63 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -3040,6 +3040,30 @@ + + Report Mailing Job + reportmailingjob + Create a Report Mailing Job + List Reports Mailing Jobs + + + + + + reportmailingjob/{id} + + Retrieve a Report Mailing Job + Update a Report Mailing Job + Delete a Report Mailing Job + + + + reportmailingjobrunhistory/{jobId} + + Retrieve Reports Mailing Job History + + + @@ -33710,6 +33734,426 @@ GET https://DomainName/api/v1/runreports/{reportName} + + +   +
+
+

Report Mailing Jobs

+

This resource allows you to create a scheduled job that runs a report and sents it by email to specified email addresses.

+

The scheduled job can be configured to run once or on a regular basis (once a day, twice a week, etc).

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Field Descriptions
name
The name of the report mailing job. It must be unique.
description
Optional: Description of the report mailing job.
startDateTime
Date and time to start the report mailing job.
stretchyReportId
The identifier of the stretchy report to be sent.
emailRecipients
Comma separated report recipient email addresses.
emailSubject
The subject of the email to be sent.
emailMessage
The body of the email to be sent.
emailAttachmentFileFormatId
The Enum constant id of the email attachment file format.
recurrence
Rule or repeating pattern for recurring events. See - http://www.kanzaki.com/docs/ical/rrule.html
isActive
Indicates whether or not the scheduler should be created as active.
stretchyReportParamMap
Optional: A map of the stretchy report parameter names to values.
+
+
+ +   +
+
+

Retrieve Report Mailing Job Details Template

+

This is a convenience resource. It can be useful when + building maintenance user interface screens for report mailing job + applications. The template data returned consists of any or all + of: +

+

+

Example Request:

+
reportmailingjobs/template
+
+
+ +GET https://DomainName/api/v1/reportmailingjobs/template + + +{ + "isActive": false, + "emailAttachmentFileFormatOptions": [ + { + "id": 1, + "code": "ReportMailingJobEmailAttachmentFileFormat.xls", + "value": "xls" + }, + { + "id": 2, + "code": "ReportMailingJobEmailAttachmentFileFormat.pdf", + "value": "pdf" + }, + { + "id": 3, + "code": "ReportMailingJobEmailAttachmentFileFormat.csv", + "value": "csv" + } + ], + "stretchyReportParamDateOptions": [ + { + "id": 1, + "code": "reportMailingJobStretchyReportParamDateOption.today", + "value": "today" + }, + { + "id": 2, + "code": "reportMailingJobStretchyReportParamDateOption.yesterday", + "value": "yesterday" + }, + { + "id": 3, + "code": "reportMailingJobStretchyReportParamDateOption.tomorrow", + "value": "tomorrow" + } + ] +} + +
+
+ +   +
+
+

Retrieve a Report Mailing Job

+

Example Requests:

+
reportmailingjobs/1
+
+
+
reportmailingjobs/1?template=true
+
+
+ +GET https://DomainName/api/v1/reportmailingjobs/{id} + + +{ + "id": 1, + "name": "Client Numbers Report", + "description": "Client Numbers Report", + "startDateTime": 1469627093000, + "recurrence": "", + "timeline": { + "createdOnDate": [ + 2016, + 7, + 27 + ], + "createdByUsername": "musoni", + "createdByFirstname": "firstname", + "createdByLastname": "lastname" + }, + "emailRecipients": "info@musonisystem.com", + "emailSubject": "Client Numbers Report", + "emailMessage": "Client Numbers Report", + "emailAttachmentFileFormat": { + "id": 1, + "code": "ReportMailingJobEmailAttachmentFileFormat.xls", + "value": "xls" + }, + "stretchyReport": { + "id": 120, + "reportName": "Client Numbers Report", + "reportType": "Pentaho", + "reportCategory": "Client", + "description": "", + "coreReport": false, + "useReport": true + }, + "stretchyReportParamMap": "{\"startDate\":\"2016-07-01\",\"endDate\":\"2016-08-02\",\"selectOffice\":\"1\",\"environementUrl\":\"environementUrl\"}", + "nextRunDateTime": 1469627093000, + "numberOfRuns": 0, + "isActive": true, + "runAsUserId": 1 +} + +
+
+ +   +
+
+

List Report Mailing Jobs

+

Example Requests:

+
reportmailingjobs
+
+
+ +GET https://DomainName/api/v1/reportmailingjobs + + +[ + { + "id": 1, + "name": "Client Numbers Report", + "description": "Client Numbers Report", + "startDateTime": 1469627093000, + "recurrence": "", + "timeline": { + "createdOnDate": [ + 2016, + 7, + 27 + ], + "createdByUsername": "musoni", + "createdByFirstname": "firstname", + "createdByLastname": "lastname" + }, + "emailRecipients": "info@musonisystem.com", + "emailSubject": "Client Numbers Report", + "emailMessage": "Client Numbers Report", + "emailAttachmentFileFormat": { + "id": 1, + "code": "ReportMailingJobEmailAttachmentFileFormat.xls", + "value": "xls" + }, + "stretchyReport": { + "id": 120, + "reportName": "Client Numbers Report", + "reportType": "Pentaho", + "reportCategory": "Client", + "description": "", + "coreReport": false, + "useReport": true + }, + "stretchyReportParamMap": "{\"startDate\":\"2016-07-01\",\"endDate\":\"2016-08-02\",\"selectOffice\":\"1\",\"environementUrl\":\"environementUrl\"}", + "nextRunDateTime": 1469627093000, + "numberOfRuns": 0, + "isActive": true, + "runAsUserId": 1 + } +] + +
+
+ +   +
+
+

List Report Mailing Job History

+

The list capability of report mailing job history can support pagination and sorting.

+
Optional Arguments
+
+
offset
+
+ Integer optional, defaults to 0 +
+
Indicates the result from which pagination starts
+ +
limit
+
+ Integer optional, defaults to 200 +
+
Restricts the size of results returned. To override the default and return all entries you must explicitly pass a non-positive integer value for limit e.g. limit=0, or limit=-1
+ +
orderBy
+
+ String optional, one of startDateTime, endDateTime, status +
+
Orders results by the indicated field.
+ +
sortBy
+
+ String optional, one of ASC, DESC +
+
Indicates what way to order results if orderBy is used.
+
+

Example Requests:

+
reportmailingjobrunhistory/1
+
+
+ +GET https://DomainName/api/v1/reportmailingjobrunhistory/{reportMailingJobId} + + +[ + { + "id": 1, + "reportMailingJobId": 1, + "startDateTime": 1469627093000", + "endDateTime": 1469627093050, + "status": "success", + "errorMessage": "", + "errorLog": "" + } +] + +
+
+ +   +
+
+

Create a Report Mailing Job

+ + + + + + + +
Mandatory Fields
name, startDateTime, stretchyReportId, emailRecipients, emailSubject, emailMessage, emailAttachmentFileFormatId, recurrence, isActive
+
+ + + + + + + +
Optional Fields
description, stretchyReportParamMap
+
+
+ +POST https://DomainName/api/v1/reportmailingjobs + + +POST reportmailingjobs +Content-Type: application/json Request Body: +{ + "locale": "en_GB", + "dateFormat": "dd-MM-yyyy HH:mm:ss", + "name": "Client Numbers Report", + "description": "Client Numbers Report", + "startDateTime": "02-08-2016 11:34:18", + "stretchyReportId": "120", + "emailRecipients": "info@musonisystem.com", + "emailSubject": "Client Numbers Report", + "emailMessage": "Client Numbers Report", + "emailAttachmentFileFormatId": "1", + "recurrence": "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,WE,FR", + "isActive": true, + "stretchyReportParamMap": "{\"startDate\":\"2016-07-01\",\"endDate\":\"2016-08-02\",\"selectOffice\":\"1\",\"environementUrl\":\"environementUrl\"}" +} + + +{ + "resourceId": 1 +} + +
+
+ +   +
+
+

Update a Report Mailing Job

+
+
+ +PUT https://DomainName/api/v1/reportmailingjobs/{id} + + +PUT reportmailingjobs/1 +Content-Type: application/json +Request Body: +{ + "locale": "en_GB", + "dateFormat": "dd-MM-yyyy HH:mm:ss", + "startDateTime": "10-08-2016 23:30:00" +} + + + +{ + "resourceId": 1, + "changes": { + "startDateTime": "10-08-2016 23:30:00" + } +} + +
+
+ +   +
+
+

Delete a Report Mailing Job

+
+
+ +DELETE https://DomainName/api/v1/reportmailingjobs/{id} + + +DELETE reportmailingjobs/1 +Content-Type: application/json +Request Body: +{ +} + + +{ + "resourceId": 1 +} + +
+
  diff --git a/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java b/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java index 3b26e1df1..0fdb0ecef 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java +++ b/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java @@ -2736,4 +2736,27 @@ public class CommandWrapperBuilder { return this; } -} \ No newline at end of file + public CommandWrapperBuilder createReportMailingJob(final String entityName) { + this.actionName = "CREATE"; + this.entityName = entityName; + this.entityId = null; + this.href = "/reportmailingjobs"; + return this; + } + + public CommandWrapperBuilder updateReportMailingJob(final String entityName, final Long entityId) { + this.actionName = "UPDATE"; + this.entityName = entityName; + this.entityId = entityId; + this.href = "/reportmailingjobs/" + entityId; + return this; + } + + public CommandWrapperBuilder deleteReportMailingJob(final String entityName, final Long entityId) { + this.actionName = "DELETE"; + this.entityName = entityName; + this.entityId = entityId; + this.href = "/reportmailingjobs/" + entityId; + return this; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/SearchParameters.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/SearchParameters.java index 97c98ba9c..c1da25245 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/SearchParameters.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/SearchParameters.java @@ -443,4 +443,33 @@ public final class SearchParameters { return this.isSelfUser; } -} \ No newline at end of file + /** + * creates an instance of the SearchParameters from a request for the report mailing job run history + * + * @return SearchParameters object + **/ + public static SearchParameters fromReportMailingJobRunHistory(final Integer offset, + final Integer limit, final String orderBy, final String sortOrder) { + final Integer maxLimitAllowed = getCheckedLimit(limit); + + return new SearchParameters(null, null, null, null, null, null, null, offset, maxLimitAllowed, orderBy, + sortOrder, null, null, null, null, null, false); + } + + /** + * creates an instance of the {@link SearchParameters} from a request for the report mailing job + * + * @param offset + * @param limit + * @param orderBy + * @param sortOrder + * @return {@link SearchParameters} object + */ + public static SearchParameters fromReportMailingJob(final Integer offset, + final Integer limit, final String orderBy, final String sortOrder) { + final Integer maxLimitAllowed = getCheckedLimit(limit); + + return new SearchParameters(null, null, null, null, null, null, null, offset, maxLimitAllowed, orderBy, + sortOrder, null, null, null, null, null, false); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/domain/ReportRepositoryWrapper.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/domain/ReportRepositoryWrapper.java new file mode 100644 index 000000000..6421053b9 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/domain/ReportRepositoryWrapper.java @@ -0,0 +1,54 @@ +/** + * 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.dataqueries.domain; + +import org.apache.fineract.infrastructure.dataqueries.exception.ReportNotFoundException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * A wrapper class for the ReportRepository that provides a method that returns a Report entity if it exists, + * else throws "ReportNotFoundException" exception if the Report does not exist + **/ +@Service +public class ReportRepositoryWrapper { + private final ReportRepository reportRepository; + + @Autowired + public ReportRepositoryWrapper(final ReportRepository reportRepository) { + this.reportRepository = reportRepository; + } + + /** + * Retrieves an entity by its id + * + * @param id must not be null + * @throws ReportNotFoundException if entity not found + * @return {@link Report} object + */ + public Report findOneThrowExceptionIfNotFound(final Long id) { + final Report report = this.reportRepository.findOne(id); + + if (report == null) { + throw new ReportNotFoundException(id); + } + + return report; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadReportingServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadReportingServiceImpl.java index 69c805638..a6e97aed8 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadReportingServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadReportingServiceImpl.java @@ -484,5 +484,4 @@ public class ReadReportingServiceImpl implements ReadReportingService { return new ReportParameterData(id, null, null, parameterName); } } - -} \ No newline at end of file +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobName.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobName.java index 0580a4c4e..d893c3b68 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobName.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/JobName.java @@ -41,7 +41,8 @@ public enum JobName { GENERATE_LOANLOSS_PROVISIONING("Generate Loan Loss Provisioning"), // POST_DIVIDENTS_FOR_SHARES("Post Dividends For Shares"), // UPDATE_SAVINGS_DORMANT_ACCOUNTS("Update Savings Dormant Accounts"), // - ADD_PERIODIC_ACCRUAL_ENTRIES_FOR_LOANS_WITH_INCOME_POSTED_AS_TRANSACTIONS("Add Accrual Transactions For Loans With Income Posted As Transactions"); + ADD_PERIODIC_ACCRUAL_ENTRIES_FOR_LOANS_WITH_INCOME_POSTED_AS_TRANSACTIONS("Add Accrual Transactions For Loans With Income Posted As Transactions"), + EXECUTE_REPORT_MAILING_JOBS("Execute Report Mailing Jobs"); private final String name; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/ReportMailingJobConstants.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/ReportMailingJobConstants.java new file mode 100644 index 000000000..ab5f11082 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/ReportMailingJobConstants.java @@ -0,0 +1,88 @@ +/** + * 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.reportmailingjob; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class ReportMailingJobConstants { + + // define the API resource entity name + public static final String REPORT_MAILING_JOB_ENTITY_NAME = "REPORTMAILINGJOB"; + + // define the API resource name for the report mailing job resource + public static final String REPORT_MAILING_JOB_RESOURCE_NAME = "reportmailingjobs"; + + // define the API resource name for the report mailing job history resource + public static final String REPORT_MAILING_JOB_RUN_HISTORY_RESOURCE_NAME = "reportmailingjobrunhistory"; + + // general API resource request parameter constants + public static final String LOCALE_PARAM_NAME = "locale"; + public static final String DATE_FORMAT_PARAM_NAME = "dateFormat"; + + // parameter constants for create/update entity API request + public static final String NAME_PARAM_NAME = "name"; + public static final String DESCRIPTION_PARAM_NAME = "description"; + public static final String START_DATE_TIME_PARAM_NAME = "startDateTime"; + public static final String RECURRENCE_PARAM_NAME = "recurrence"; + public static final String EMAIL_RECIPIENTS_PARAM_NAME = "emailRecipients"; + public static final String EMAIL_SUBJECT_PARAM_NAME = "emailSubject"; + public static final String EMAIL_MESSAGE_PARAM_NAME = "emailMessage"; + public static final String EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME = "emailAttachmentFileFormatId"; + public static final String STRETCHY_REPORT_ID_PARAM_NAME = "stretchyReportId"; + public static final String STRETCHY_REPORT_PARAM_MAP_PARAM_NAME = "stretchyReportParamMap"; + public static final String IS_ACTIVE_PARAM_NAME = "isActive"; + + // other parameter constants + public static final String ID_PARAM_NAME = "id"; + public static final String EMAIL_ATTACHMENT_FILE_FORMAT_PARAM_NAME = "emailAttachmentFileFormat"; + public static final String PREVIOUS_RUN_DATE_TIME_PARAM_NAME = "previousRunDateTime"; + public static final String NEXT_RUN_DATE_TIME_PARAM_NAME = "nextRunDateTime"; + public static final String PREVIOUS_RUN_STATUS = "previousRunStatus"; + public static final String PREVIOUS_RUN_ERROR_LOG = "previousRunErrorLog"; + public static final String PREVIOUS_RUN_ERROR_MESSAGE = "previousRunErrorMessage"; + public static final String NUMBER_OF_RUNS = "numberOfRuns"; + public static final String STRETCHY_REPORT_PARAM_NAME = "stretchyReport"; + + // list of permitted parameters for the create report mailing job request + public static final Set CREATE_REQUEST_PARAMETERS = new HashSet<>(Arrays.asList(LOCALE_PARAM_NAME, DATE_FORMAT_PARAM_NAME, + NAME_PARAM_NAME, DESCRIPTION_PARAM_NAME, RECURRENCE_PARAM_NAME, EMAIL_RECIPIENTS_PARAM_NAME, EMAIL_SUBJECT_PARAM_NAME, + EMAIL_MESSAGE_PARAM_NAME, EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME, STRETCHY_REPORT_ID_PARAM_NAME, + STRETCHY_REPORT_PARAM_MAP_PARAM_NAME, IS_ACTIVE_PARAM_NAME, START_DATE_TIME_PARAM_NAME)); + + // list of permitted parameters for the update report mailing job request + public static final Set UPDATE_REQUEST_PARAMETERS = new HashSet<>(Arrays.asList(LOCALE_PARAM_NAME, DATE_FORMAT_PARAM_NAME, + NAME_PARAM_NAME, DESCRIPTION_PARAM_NAME, RECURRENCE_PARAM_NAME, EMAIL_RECIPIENTS_PARAM_NAME, EMAIL_SUBJECT_PARAM_NAME, + EMAIL_MESSAGE_PARAM_NAME, EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME, STRETCHY_REPORT_ID_PARAM_NAME, + STRETCHY_REPORT_PARAM_MAP_PARAM_NAME, IS_ACTIVE_PARAM_NAME, START_DATE_TIME_PARAM_NAME)); + + // list of parameters that represent the properties of a report mailing job + public static final Set REPORT_MAILING_JOB_DATA_PARAMETERS = new HashSet<>(Arrays.asList(ID_PARAM_NAME, NAME_PARAM_NAME, + DESCRIPTION_PARAM_NAME, RECURRENCE_PARAM_NAME, EMAIL_RECIPIENTS_PARAM_NAME, EMAIL_SUBJECT_PARAM_NAME, EMAIL_MESSAGE_PARAM_NAME, + EMAIL_ATTACHMENT_FILE_FORMAT_PARAM_NAME, STRETCHY_REPORT_PARAM_NAME, STRETCHY_REPORT_PARAM_MAP_PARAM_NAME, IS_ACTIVE_PARAM_NAME, + START_DATE_TIME_PARAM_NAME, PREVIOUS_RUN_DATE_TIME_PARAM_NAME, NEXT_RUN_DATE_TIME_PARAM_NAME, PREVIOUS_RUN_STATUS, + PREVIOUS_RUN_ERROR_LOG, PREVIOUS_RUN_ERROR_MESSAGE, NUMBER_OF_RUNS)); + + // report mailing job configuration names + public static final String GMAIL_SMTP_SERVER = "GMAIL_SMTP_SERVER"; + public static final String GMAIL_SMTP_PORT = "GMAIL_SMTP_PORT"; + public static final String GMAIL_SMTP_USERNAME = "GMAIL_SMTP_USERNAME"; + public static final String GMAIL_SMTP_PASSWORD = "GMAIL_SMTP_PASSWORD"; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/api/ReportMailingJobApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/api/ReportMailingJobApiResource.java new file mode 100644 index 000000000..da6da6d8f --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/api/ReportMailingJobApiResource.java @@ -0,0 +1,162 @@ +/** + * 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.reportmailingjob.api; + +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.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.data.CommandProcessingResult; +import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; +import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer; +import org.apache.fineract.infrastructure.core.service.Page; +import org.apache.fineract.infrastructure.core.service.SearchParameters; +import org.apache.fineract.infrastructure.reportmailingjob.ReportMailingJobConstants; +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobData; +import org.apache.fineract.infrastructure.reportmailingjob.service.ReportMailingJobReadPlatformService; +import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +@Path("/" + ReportMailingJobConstants.REPORT_MAILING_JOB_RESOURCE_NAME) +@Component +@Scope("singleton") +public class ReportMailingJobApiResource { + + private final PlatformSecurityContext platformSecurityContext; + private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; + private final ApiRequestParameterHelper apiRequestParameterHelper; + private final DefaultToApiJsonSerializer reportMailingToApiJsonSerializer; + private final ReportMailingJobReadPlatformService reportMailingJobReadPlatformService; + + @Autowired + public ReportMailingJobApiResource(final PlatformSecurityContext platformSecurityContext, + final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService, + final ApiRequestParameterHelper apiRequestParameterHelper, + final DefaultToApiJsonSerializer reportMailingToApiJsonSerializer, + final ReportMailingJobReadPlatformService reportMailingJobReadPlatformService) { + this.platformSecurityContext = platformSecurityContext; + this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; + this.apiRequestParameterHelper = apiRequestParameterHelper; + this.reportMailingToApiJsonSerializer = reportMailingToApiJsonSerializer; + this.reportMailingJobReadPlatformService = reportMailingJobReadPlatformService; + } + + @POST + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String createReportMailingJob(final String apiRequestBodyAsJson) { + final CommandWrapper commandWrapper = new CommandWrapperBuilder(). + createReportMailingJob(ReportMailingJobConstants.REPORT_MAILING_JOB_ENTITY_NAME). + withJson(apiRequestBodyAsJson).build(); + + final CommandProcessingResult commandProcessingResult = this.commandsSourceWritePlatformService.logCommandSource(commandWrapper); + + return this.reportMailingToApiJsonSerializer.serialize(commandProcessingResult); + } + + @PUT + @Path("{entityId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String updateReportMailingJob(@PathParam("entityId") final Long entityId, final String apiRequestBodyAsJson) { + final CommandWrapper commandWrapper = new CommandWrapperBuilder(). + updateReportMailingJob(ReportMailingJobConstants.REPORT_MAILING_JOB_ENTITY_NAME, entityId). + withJson(apiRequestBodyAsJson).build(); + + final CommandProcessingResult commandProcessingResult = this.commandsSourceWritePlatformService.logCommandSource(commandWrapper); + + return this.reportMailingToApiJsonSerializer.serialize(commandProcessingResult); + } + + @DELETE + @Path("{entityId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String deleteReportMailingJob(@PathParam("entityId") final Long entityId, final String apiRequestBodyAsJson) { + final CommandWrapper commandWrapper = new CommandWrapperBuilder(). + deleteReportMailingJob(ReportMailingJobConstants.REPORT_MAILING_JOB_ENTITY_NAME, entityId). + withJson(apiRequestBodyAsJson).build(); + + final CommandProcessingResult commandProcessingResult = this.commandsSourceWritePlatformService.logCommandSource(commandWrapper); + + return this.reportMailingToApiJsonSerializer.serialize(commandProcessingResult); + } + + @GET + @Path("{entityId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveReportMailingJob(@PathParam("entityId") final Long entityId, @Context final UriInfo uriInfo) { + this.platformSecurityContext.authenticatedUser().validateHasReadPermission(ReportMailingJobConstants.REPORT_MAILING_JOB_ENTITY_NAME); + + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + ReportMailingJobData reportMailingJobData = this.reportMailingJobReadPlatformService.retrieveReportMailingJob(entityId); + + if (settings.isTemplate()) { + final ReportMailingJobData ReportMailingJobDataOptions = this.reportMailingJobReadPlatformService.retrieveReportMailingJobEnumOptions(); + reportMailingJobData = ReportMailingJobData.newInstance(reportMailingJobData, ReportMailingJobDataOptions); + } + + return this.reportMailingToApiJsonSerializer.serialize(settings, reportMailingJobData, ReportMailingJobConstants.REPORT_MAILING_JOB_DATA_PARAMETERS); + } + + @GET + @Path("template") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveReportMailingJobTemplate(@Context final UriInfo uriInfo) { + this.platformSecurityContext.authenticatedUser().validateHasReadPermission(ReportMailingJobConstants.REPORT_MAILING_JOB_ENTITY_NAME); + + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + final ReportMailingJobData ReportMailingJobDataOptions = this.reportMailingJobReadPlatformService.retrieveReportMailingJobEnumOptions(); + + return this.reportMailingToApiJsonSerializer.serialize(settings, ReportMailingJobDataOptions, ReportMailingJobConstants.REPORT_MAILING_JOB_DATA_PARAMETERS); + } + + @GET + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveAllReportMailingJobs(@Context final UriInfo uriInfo, + @QueryParam("offset") final Integer offset, + @QueryParam("limit") final Integer limit, @QueryParam("orderBy") final String orderBy, + @QueryParam("sortOrder") final String sortOrder) { + this.platformSecurityContext.authenticatedUser().validateHasReadPermission(ReportMailingJobConstants.REPORT_MAILING_JOB_ENTITY_NAME); + + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + final SearchParameters searchParameters = SearchParameters.fromReportMailingJob(offset, limit, orderBy, sortOrder); + final Page reportMailingJobData = this.reportMailingJobReadPlatformService.retrieveAllReportMailingJobs(searchParameters); + + return this.reportMailingToApiJsonSerializer.serialize(settings, reportMailingJobData, ReportMailingJobConstants.REPORT_MAILING_JOB_DATA_PARAMETERS); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/api/ReportMailingJobRunHistoryApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/api/ReportMailingJobRunHistoryApiResource.java new file mode 100644 index 000000000..a7802eee9 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/api/ReportMailingJobRunHistoryApiResource.java @@ -0,0 +1,80 @@ +/** + * 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.reportmailingjob.api; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +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.fineract.infrastructure.core.api.ApiRequestParameterHelper; +import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; +import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer; +import org.apache.fineract.infrastructure.core.service.Page; +import org.apache.fineract.infrastructure.core.service.SearchParameters; +import org.apache.fineract.infrastructure.reportmailingjob.ReportMailingJobConstants; +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobRunHistoryData; +import org.apache.fineract.infrastructure.reportmailingjob.service.ReportMailingJobRunHistoryReadPlatformService; +import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +@Path("/" + ReportMailingJobConstants.REPORT_MAILING_JOB_RUN_HISTORY_RESOURCE_NAME) +@Component +@Scope("singleton") +public class ReportMailingJobRunHistoryApiResource { + + private final PlatformSecurityContext platformSecurityContext; + private final ApiRequestParameterHelper apiRequestParameterHelper; + private final DefaultToApiJsonSerializer reportMailingToApiJsonSerializer; + private final ReportMailingJobRunHistoryReadPlatformService reportMailingJobRunHistoryReadPlatformService; + + @Autowired + public ReportMailingJobRunHistoryApiResource(final PlatformSecurityContext platformSecurityContext, + final ApiRequestParameterHelper apiRequestParameterHelper, + final DefaultToApiJsonSerializer reportMailingToApiJsonSerializer, + final ReportMailingJobRunHistoryReadPlatformService reportMailingJobRunHistoryReadPlatformService) { + this.platformSecurityContext = platformSecurityContext; + this.apiRequestParameterHelper = apiRequestParameterHelper; + this.reportMailingToApiJsonSerializer = reportMailingToApiJsonSerializer; + this.reportMailingJobRunHistoryReadPlatformService = reportMailingJobRunHistoryReadPlatformService; + } + + @GET + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveAllByReportMailingJobId(@Context final UriInfo uriInfo, + @QueryParam("reportMailingJobId") final Long reportMailingJobId, @QueryParam("offset") final Integer offset, + @QueryParam("limit") final Integer limit, @QueryParam("orderBy") final String orderBy, + @QueryParam("sortOrder") final String sortOrder) { + this.platformSecurityContext.authenticatedUser().validateHasReadPermission(ReportMailingJobConstants.REPORT_MAILING_JOB_ENTITY_NAME); + final SearchParameters searchParameters = SearchParameters.fromReportMailingJobRunHistory(offset, limit, orderBy, sortOrder); + + final Page reportMailingJobRunHistoryData = this.reportMailingJobRunHistoryReadPlatformService. + retrieveRunHistoryByJobId(reportMailingJobId, searchParameters); + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + + return this.reportMailingToApiJsonSerializer.serialize(settings, reportMailingJobRunHistoryData); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobConfigurationData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobConfigurationData.java new file mode 100644 index 000000000..48d075aef --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobConfigurationData.java @@ -0,0 +1,67 @@ +/** + * 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.reportmailingjob.data; + +/** + * Immutable data object representing report mailing job configuration data. + **/ +public class ReportMailingJobConfigurationData { + private final int id; + private final String name; + private final String value; + + /** + * ReportMailingJobConfigurationData private constructor + **/ + private ReportMailingJobConfigurationData(final int id, final String name, final String value) { + this.id = id; + this.name = name; + this.value = value; + } + + /** + * creates an instance of the ReportMailingJobConfigurationData class + * + * @return ReportMailingJobConfigurationData object + **/ + public static ReportMailingJobConfigurationData newInstance(final int id, final String name, final String value) { + return new ReportMailingJobConfigurationData(id, name, value); + } + + /** + * @return the id + */ + public int getId() { + return id; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @return the value + */ + public String getValue() { + return value; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobData.java new file mode 100644 index 000000000..aa5172f2f --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobData.java @@ -0,0 +1,272 @@ +/** + * 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.reportmailingjob.data; + +import java.util.List; + +import org.apache.fineract.infrastructure.core.data.EnumOptionData; +import org.apache.fineract.infrastructure.dataqueries.data.ReportData; +import org.joda.time.DateTime; + +/** + * Immutable data object representing report mailing job data. + **/ +public class ReportMailingJobData { + private final Long id; + private final String name; + private final String description; + private final DateTime startDateTime; + private final String recurrence; + private final ReportMailingJobTimelineData timeline; + private final String emailRecipients; + private final String emailSubject; + private final String emailMessage; + private final EnumOptionData emailAttachmentFileFormat; + private final ReportData stretchyReport; + private final String stretchyReportParamMap; + private final DateTime previousRunDateTime; + private final DateTime nextRunDateTime; + private final String previousRunStatus; + private final String previousRunErrorLog; + private final String previousRunErrorMessage; + private final Integer numberOfRuns; + private final boolean isActive; + private final List emailAttachmentFileFormatOptions; + private final List stretchyReportParamDateOptions; + private final Long runAsUserId; + + private ReportMailingJobData(final Long id, final String name, final String description, final DateTime startDateTime, + final String recurrence, final ReportMailingJobTimelineData timeline, final String emailRecipients, final String emailSubject, + final String emailMessage, final EnumOptionData emailAttachmentFileFormat, final ReportData stretchyReport, final String stretchyReportParamMap, + final DateTime previousRunDateTime, final DateTime nextRunDateTime, final String previousRunStatus, final String previousRunErrorLog, + final String previousRunErrorMessage, final Integer numberOfRuns, final boolean isActive, final List emailAttachmentFileFormatOptions, + final List stretchyReportParamDateOptions, final Long runAsUserId) { + this.id = id; + this.name = name; + this.description = description; + this.startDateTime = startDateTime; + this.recurrence = recurrence; + this.timeline = timeline; + this.emailRecipients = emailRecipients; + this.emailMessage = emailMessage; + this.emailSubject = emailSubject; + this.emailAttachmentFileFormat = emailAttachmentFileFormat; + this.stretchyReport = stretchyReport; + this.stretchyReportParamMap = stretchyReportParamMap; + this.previousRunDateTime = previousRunDateTime; + this.nextRunDateTime = nextRunDateTime; + this.previousRunStatus = previousRunStatus; + this.previousRunErrorLog = previousRunErrorLog; + this.previousRunErrorMessage = previousRunErrorMessage; + this.isActive = isActive; + this.numberOfRuns = numberOfRuns; + this.emailAttachmentFileFormatOptions = emailAttachmentFileFormatOptions; + this.stretchyReportParamDateOptions = stretchyReportParamDateOptions; + this.runAsUserId = runAsUserId; + } + + /** + * @return an instance of the ReportMailingJobData class + **/ + public static ReportMailingJobData newInstance(final Long id, final String name, final String description, final DateTime startDateTime, + final String recurrence, final ReportMailingJobTimelineData timeline, final String emailRecipients, final String emailSubject, + final String emailMessage, final EnumOptionData emailAttachmentFileFormat, final ReportData stretchyReport, final String stretchyReportParamMap, + final DateTime previousRunDateTime, final DateTime nextRunDateTime, final String previousRunStatus, final String previousRunErrorLog, + final String previousRunErrorMessage, final Integer numberOfRuns, final boolean isActive, final Long runAsUserId) { + return new ReportMailingJobData(id, name, description, startDateTime, recurrence, timeline, emailRecipients, emailSubject, + emailMessage, emailAttachmentFileFormat, stretchyReport, stretchyReportParamMap, previousRunDateTime, nextRunDateTime, + previousRunStatus, previousRunErrorLog, previousRunErrorMessage, numberOfRuns, isActive, null, null, runAsUserId); + } + + /** + * @return an instance of the ReportMailingJobData class + **/ + public static ReportMailingJobData newInstance(final List emailAttachmentFileFormatOptions, + final List stretchyReportParamDateOptions) { + return new ReportMailingJobData(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, false, emailAttachmentFileFormatOptions, stretchyReportParamDateOptions, null); + } + + /** + * @return an instance of the ReportMailingJobData class + **/ + public static ReportMailingJobData newInstance(final ReportMailingJobData dataWithoutEnumOptions, final ReportMailingJobData dataWithEnumOptions) { + return new ReportMailingJobData(dataWithoutEnumOptions.id, dataWithoutEnumOptions.name, dataWithoutEnumOptions.description, dataWithoutEnumOptions.startDateTime, + dataWithoutEnumOptions.recurrence, dataWithoutEnumOptions.timeline, dataWithoutEnumOptions.emailRecipients, dataWithoutEnumOptions.emailSubject, + dataWithoutEnumOptions.emailMessage, dataWithoutEnumOptions.emailAttachmentFileFormat, dataWithoutEnumOptions.stretchyReport, + dataWithoutEnumOptions.stretchyReportParamMap, dataWithoutEnumOptions.previousRunDateTime, dataWithoutEnumOptions.nextRunDateTime, + dataWithoutEnumOptions.previousRunStatus, dataWithoutEnumOptions.previousRunErrorLog, dataWithoutEnumOptions.previousRunErrorMessage, + dataWithoutEnumOptions.numberOfRuns, dataWithoutEnumOptions.isActive, dataWithEnumOptions.emailAttachmentFileFormatOptions, + dataWithEnumOptions.stretchyReportParamDateOptions, dataWithoutEnumOptions.runAsUserId); + } + + /** + * @return the id + */ + public Long getId() { + return id; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @return the description + */ + public String getDescription() { + return description; + } + + /** + * @return the startDateTime + */ + public DateTime getStartDateTime() { + return startDateTime; + } + + /** + * @return the recurrence + */ + public String getRecurrence() { + return recurrence; + } + + /** + * @return the timeline + */ + public ReportMailingJobTimelineData getTimeline() { + return timeline; + } + + /** + * @return the emailRecipients + */ + public String getEmailRecipients() { + return emailRecipients; + } + + /** + * @return the emailSubject + */ + public String getEmailSubject() { + return emailSubject; + } + + /** + * @return the emailMessage + */ + public String getEmailMessage() { + return emailMessage; + } + + /** + * @return the emailAttachmentFileFormat + */ + public EnumOptionData getEmailAttachmentFileFormat() { + return emailAttachmentFileFormat; + } + + /** + * @return the stretchyReport + */ + public ReportData getStretchyReport() { + return stretchyReport; + } + + /** + * @return the stretchyReportParamMap + */ + public String getStretchyReportParamMap() { + return stretchyReportParamMap; + } + + /** + * @return the previousRunDateTime + */ + public DateTime getPreviousRunDateTime() { + return previousRunDateTime; + } + + /** + * @return the nextRunDateTime + */ + public DateTime getNextRunDateTime() { + return nextRunDateTime; + } + + /** + * @return the previousRunStatus + */ + public String getPreviousRunStatus() { + return previousRunStatus; + } + + /** + * @return the previousRunErrorLog + */ + public String getPreviousRunErrorLog() { + return previousRunErrorLog; + } + + /** + * @return the previousRunErrorMessage + */ + public String getPreviousRunErrorMessage() { + return previousRunErrorMessage; + } + + /** + * @return the isActive + */ + public boolean isActive() { + return isActive; + } + + /** + * @return the emailAttachmentFileFormatOptions + */ + public List getEmailAttachmentFileFormatOptions() { + return emailAttachmentFileFormatOptions; + } + + /** + * @return the stretchyReportParamDateOptions + **/ + public List getStretchyReportParamDateOptions() { + return this.stretchyReportParamDateOptions; + } + + /** + * @return the numberOfRuns + */ + public Integer getNumberOfRuns() { + return numberOfRuns; + } + + /** + * @return the runAsUserId + */ + public Long getRunAsUserId() { + return runAsUserId; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobEmailAttachmentFileFormat.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobEmailAttachmentFileFormat.java new file mode 100644 index 000000000..c3e15ca81 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobEmailAttachmentFileFormat.java @@ -0,0 +1,176 @@ +/** + * 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.reportmailingjob.data; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.apache.fineract.infrastructure.core.data.EnumOptionData; + +public enum ReportMailingJobEmailAttachmentFileFormat { + INVALID(0, "ReportMailingJobEmailAttachmentFileFormat.INVALID", "Invalid"), + XLS(1, "ReportMailingJobEmailAttachmentFileFormat.XLS", "XLS"), + PDF(2, "ReportMailingJobEmailAttachmentFileFormat.PDF", "PDF"), + CSV(3, "ReportMailingJobEmailAttachmentFileFormat.CSV", "CSV"); + + private String code; + private String value; + private Integer id; + + private ReportMailingJobEmailAttachmentFileFormat(final Integer id, final String code, final String value) { + this.value = value; + this.code = code; + this.id = id; + } + + /** + * Creates a new {@link ReportMailingJobEmailAttachmentFileFormat} object + * + * @param value the value of the enum constant + * @return {@link ReportMailingJobEmailAttachmentFileFormat} object + */ + public static ReportMailingJobEmailAttachmentFileFormat newInstance(final String value) { + ReportMailingJobEmailAttachmentFileFormat emailAttachmentFileFormat = INVALID; + + if (StringUtils.equalsIgnoreCase(value, XLS.value)) { + emailAttachmentFileFormat = XLS; + } else if (StringUtils.equalsIgnoreCase(value, PDF.value)) { + emailAttachmentFileFormat = PDF; + } else if (StringUtils.equalsIgnoreCase(value, CSV.value)) { + emailAttachmentFileFormat = CSV; + } + + return emailAttachmentFileFormat; + } + + /** + * Creates a new {@link ReportMailingJobEmailAttachmentFileFormat} object + * + * @param id the id of the enum constant + * @return {@link ReportMailingJobEmailAttachmentFileFormat} object + */ + public static ReportMailingJobEmailAttachmentFileFormat newInstance(final Integer id) { + ReportMailingJobEmailAttachmentFileFormat emailAttachmentFileFormat = INVALID; + + if (id == XLS.id) { + emailAttachmentFileFormat = XLS; + } else if (id == PDF.id) { + emailAttachmentFileFormat = PDF; + } else if (id == CSV.id) { + emailAttachmentFileFormat = CSV; + } + + return emailAttachmentFileFormat; + } + + /** + * @return the code + */ + public String getCode() { + return code; + } + + /** + * @return the value + */ + public String getValue() { + return value; + } + + /** + * @return the id + */ + public Integer getId() { + return id; + } + + /** + * @return true if the enum is equals to "INVALID" + */ + public boolean isInvalid() { + return this.equals(INVALID); + } + + /** + * @return true if the enum is not equals to "INVALID" + */ + public boolean isValid() { + return !this.isInvalid(); + } + + /** + * @return list of valid ReportMailingJobEmailAttachmentFileFormat values + **/ + public static Object[] validValues() { + List validValues = new ArrayList<>(); + + for (ReportMailingJobEmailAttachmentFileFormat constant : ReportMailingJobEmailAttachmentFileFormat.values()) { + if (constant.isValid()) { + validValues.add(constant.value); + } + } + + return validValues.toArray(); + } + + /** + * @return list of valid ReportMailingJobEmailAttachmentFileFormat values + **/ + public static Object[] validIds() { + List validValues = new ArrayList<>(); + + for (ReportMailingJobEmailAttachmentFileFormat constant : ReportMailingJobEmailAttachmentFileFormat.values()) { + if (constant.isValid()) { + validValues.add(constant.id); + } + } + + return validValues.toArray(); + } + + /** + * get a {@link EnumOptionData} representation of the {@link ReportMailingJobEmailAttachmentFileFormat} object + * + * @return {@link EnumOptionData} object + */ + public EnumOptionData toEnumOptionData() { + // get the long value of the enum id + final Long id = (this.id != null) ? this.id.longValue() : null; + + return new EnumOptionData(id, code, value); + } + + /** + * get the {@link EnumOptionData} representation of all valid {@link ReportMailingJobEmailAttachmentFileFormat} objects + * + * @return List of {@link EnumOptionData} objects + */ + public static List validOptions() { + List options = new ArrayList<>(); + + for (ReportMailingJobEmailAttachmentFileFormat constant : ReportMailingJobEmailAttachmentFileFormat.values()) { + if (constant.isValid()) { + options.add(constant.toEnumOptionData()); + } + } + + return options; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobEmailData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobEmailData.java new file mode 100644 index 000000000..dda7e2df3 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobEmailData.java @@ -0,0 +1,66 @@ +/** + * 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.reportmailingjob.data; + +import java.io.File; + +/** + * Immutable data object representing report mailing job email data. + **/ +public class ReportMailingJobEmailData { + private final String to; + private final String text; + private final String subject; + private final File attachment; + + public ReportMailingJobEmailData(final String to, final String text, final String subject, final File attachment) { + this.to = to; + this.text = text; + this.subject = subject; + this.attachment = attachment; + } + + /** + * @return the to + */ + public String getTo() { + return to; + } + + /** + * @return the text + */ + public String getText() { + return text; + } + + /** + * @return the subject + */ + public String getSubject() { + return subject; + } + + /** + * @return the attachment + */ + public File getAttachment() { + return attachment; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobPreviousRunStatus.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobPreviousRunStatus.java new file mode 100644 index 000000000..3f49cd994 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobPreviousRunStatus.java @@ -0,0 +1,90 @@ +/** + * 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.reportmailingjob.data; + +import org.apache.commons.lang.StringUtils; + +public enum ReportMailingJobPreviousRunStatus { + INVALID(-1, "ReportMailingJobPreviousRunStatus.INVALID", "Invalid"), + SUCCESS(1, "ReportMailingJobPreviousRunStatus.SUCCESS", "Success"), + ERROR(0, "ReportMailingJobPreviousRunStatus.ERROR", "Error"); + + private final String code; + private final String value; + private final Integer id; + + private ReportMailingJobPreviousRunStatus(final Integer id, final String code, final String value) { + this.value = value; + this.code = code; + this.id = id; + } + + /** + * Creates a {@link ReportMailingJobPreviousRunStatus} object + * + * @param value the value of the enum constant + * @return {@link ReportMailingJobPreviousRunStatus} object + */ + public static ReportMailingJobPreviousRunStatus newInstance(final String value) { + ReportMailingJobPreviousRunStatus previousRunStatus = INVALID; + + if (StringUtils.equalsIgnoreCase(value, SUCCESS.value)) { + previousRunStatus = SUCCESS; + } else if (StringUtils.equalsIgnoreCase(value, ERROR.value)) { + previousRunStatus = ERROR; + } + + return previousRunStatus; + } + + /** + * @return the code + */ + public String getCode() { + return code; + } + + /** + * @return the value + */ + public String getValue() { + return value; + } + + /** + * @return the id + */ + public Integer getId() { + return id; + } + + /** + * @return true/false + **/ + public boolean isSuccess() { + return this.value.equals(SUCCESS.getValue()); + } + + /** + * @return boolean true/false + **/ + public boolean isError() { + return this.value.equals(ERROR.getValue()); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobRunHistoryData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobRunHistoryData.java new file mode 100644 index 000000000..0642f7b0e --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobRunHistoryData.java @@ -0,0 +1,107 @@ +/** + * 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.reportmailingjob.data; + +import org.joda.time.DateTime; + +/** + * Immutable data object representing report mailing job run history data. + **/ +public class ReportMailingJobRunHistoryData { + private final Long id; + private final Long reportMailingJobId; + private final DateTime startDateTime; + private final DateTime endDateTime; + private final String status; + private final String errorMessage; + private final String errorLog; + + /** + * ReportMailingJobRunHistoryData private constructor + **/ + private ReportMailingJobRunHistoryData(Long id, Long reportMailingJobId, DateTime startDateTime, + DateTime endDateTime, String status, String errorMessage, String errorLog) { + this.id = id; + this.reportMailingJobId = reportMailingJobId; + this.startDateTime = startDateTime; + this.endDateTime = endDateTime; + this.status = status; + this.errorMessage = errorMessage; + this.errorLog = errorLog; + } + + /** + * creates an instance of the ReportMailingJobRunHistoryData class + * + * @return ReportMailingJobRunHistoryData object + **/ + public static ReportMailingJobRunHistoryData newInstance(Long id, Long reportMailingJobId, DateTime startDateTime, + DateTime endDateTime, String status, String errorMessage, String errorLog) { + return new ReportMailingJobRunHistoryData(id, reportMailingJobId, startDateTime, endDateTime, status, errorMessage, errorLog); + } + + /** + * @return the id + */ + public Long getId() { + return id; + } + + /** + * @return the reportMailingJobId + */ + public Long getReportMailingJobId() { + return reportMailingJobId; + } + + /** + * @return the startDateTime + */ + public DateTime getStartDateTime() { + return startDateTime; + } + + /** + * @return the endDateTime + */ + public DateTime getEndDateTime() { + return endDateTime; + } + + /** + * @return the status + */ + public String getStatus() { + return status; + } + + /** + * @return the errorMessage + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * @return the errorLog + */ + public String getErrorLog() { + return errorLog; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobStretchyReportParamDateOption.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobStretchyReportParamDateOption.java new file mode 100644 index 000000000..01cf80847 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobStretchyReportParamDateOption.java @@ -0,0 +1,166 @@ +/** + * 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.reportmailingjob.data; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.apache.fineract.infrastructure.core.data.EnumOptionData; + +public enum ReportMailingJobStretchyReportParamDateOption { + INVALID(0, "ReportMailingJobStretchyReportParamDateOption.INVALID", "Invalid"), + TODAY(1, "ReportMailingJobStretchyReportParamDateOption.TODAY", "Today"), + YESTERDAY(2, "ReportMailingJobStretchyReportParamDateOption.YESTERDAY", "Yesterday"), + TOMORROW(3, "ReportMailingJobStretchyReportParamDateOption.TOMORROW", "Tomorrow"); + + private String code; + private String value; + private Integer id; + + /** + * @param id + * @param code + * @param value + */ + private ReportMailingJobStretchyReportParamDateOption(final Integer id, final String code, final String value) { + this.value = value; + this.code = code; + this.id = id; + } + + /** + * Creates a new {@link ReportMailingJobStretchyReportParamDateOption} object + * + * @param value value of the enum constant + * @return {@link ReportMailingJobStretchyReportParamDateOption} object + */ + public static ReportMailingJobStretchyReportParamDateOption newInstance(final String value) { + ReportMailingJobStretchyReportParamDateOption reportMailingJobStretchyReportParamDateOption = INVALID; + + if (StringUtils.equalsIgnoreCase(value, TODAY.value)) { + reportMailingJobStretchyReportParamDateOption = TODAY; + } else if (StringUtils.equalsIgnoreCase(value, YESTERDAY.value)) { + reportMailingJobStretchyReportParamDateOption = YESTERDAY; + } else if (StringUtils.equalsIgnoreCase(value, TOMORROW.value)) { + reportMailingJobStretchyReportParamDateOption = TOMORROW; + } + + return reportMailingJobStretchyReportParamDateOption; + } + + /** + * Creates a new {@link ReportMailingJobStretchyReportParamDateOption} object + * + * @param id id of the enum constant + * @return {@link ReportMailingJobStretchyReportParamDateOption} object + */ + public static ReportMailingJobStretchyReportParamDateOption newInstance(final Integer id) { + ReportMailingJobStretchyReportParamDateOption reportMailingJobStretchyReportParamDateOption = INVALID; + + if (id == TODAY.id) { + reportMailingJobStretchyReportParamDateOption = TODAY; + } else if (id == YESTERDAY.id) { + reportMailingJobStretchyReportParamDateOption = YESTERDAY; + } else if (id == TOMORROW.id) { + reportMailingJobStretchyReportParamDateOption = TOMORROW; + } + + return reportMailingJobStretchyReportParamDateOption; + } + + /** + * @return the code + */ + public String getCode() { + return code; + } + + /** + * @return the value + */ + public String getValue() { + return value; + } + + /** + * @return the id + */ + public Integer getId() { + return id; + } + + /** + * @return true if the enum is equals to "INVALID" + */ + public boolean isInvalid() { + return this.equals(INVALID); + } + + /** + * @return true if the enum is not equals to "INVALID" + */ + public boolean isValid() { + return !this.isInvalid(); + } + + /** + * @return list of valid ReportMailingJobStretchyReportParamDateOption values + **/ + public static Object[] validValues() { + List validValues = new ArrayList<>(); + + for (ReportMailingJobStretchyReportParamDateOption constant : ReportMailingJobStretchyReportParamDateOption.values()) { + if (constant.isValid()) { + validValues.add(constant.value); + } + } + + return validValues.toArray(); + } + + /** + * get a {@link EnumOptionData} representation of the {@link ReportMailingJobStretchyReportParamDateOption} object + * + * @return {@link EnumOptionData} object + */ + public EnumOptionData toEnumOptionData() { + // get the long value of the enum id + final Long id = (this.id != null) ? this.id.longValue() : null; + + return new EnumOptionData(id, code, value); + } + + /** + * get the {@link EnumOptionData} representation of all valid {@link ReportMailingJobStretchyReportParamDateOption} objects + * + * @return List of {@link EnumOptionData} objects + */ + public static List validOptions() { + List options = new ArrayList<>(); + + for (ReportMailingJobStretchyReportParamDateOption constant : ReportMailingJobStretchyReportParamDateOption.values()) { + if (constant.isValid()) { + options.add(constant.toEnumOptionData()); + } + } + + return options; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobTimelineData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobTimelineData.java new file mode 100644 index 000000000..032009762 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/data/ReportMailingJobTimelineData.java @@ -0,0 +1,59 @@ +/** + * 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.reportmailingjob.data; + +import org.joda.time.LocalDate; + +/** + * Immutable data object represent the timeline events of a report mailing job (creation) + **/ +@SuppressWarnings("unused") +public class ReportMailingJobTimelineData { + private final LocalDate createdOnDate; + private final String createdByUsername; + private final String createdByFirstname; + private final String createdByLastname; + private final LocalDate updatedOnDate; + private final String updatedByUsername; + private final String updatedByFirstname; + private final String updatedByLastname; + + /** + * @param createdOnDate + * @param createdByUsername + * @param createdByFirstname + * @param createdByLastname + * @param updatedOnDate + * @param updatedByUsername + * @param updatedByFirstname + * @param updatedByLastname + */ + public ReportMailingJobTimelineData(LocalDate createdOnDate, String createdByUsername, String createdByFirstname, + String createdByLastname, LocalDate updatedOnDate, String updatedByUsername, String updatedByFirstname, + String updatedByLastname) { + this.createdOnDate = createdOnDate; + this.createdByUsername = createdByUsername; + this.createdByFirstname = createdByFirstname; + this.createdByLastname = createdByLastname; + this.updatedOnDate = updatedOnDate; + this.updatedByUsername = updatedByUsername; + this.updatedByFirstname = updatedByFirstname; + this.updatedByLastname = updatedByLastname; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJob.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJob.java new file mode 100644 index 000000000..c7f3bb7d4 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJob.java @@ -0,0 +1,558 @@ +/** + * 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.reportmailingjob.domain; + +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.Map; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.UniqueConstraint; + +import org.apache.commons.lang.StringUtils; +import org.apache.fineract.infrastructure.core.api.JsonCommand; +import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom; +import org.apache.fineract.infrastructure.dataqueries.domain.Report; +import org.apache.fineract.infrastructure.reportmailingjob.ReportMailingJobConstants; +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobEmailAttachmentFileFormat; +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobPreviousRunStatus; +import org.apache.fineract.useradministration.domain.AppUser; +import org.joda.time.DateTime; +import org.joda.time.LocalDateTime; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; + +@Entity +@Table(name = "m_report_mailing_job", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "unique_name") }) +public class ReportMailingJob extends AbstractAuditableCustom { + private static final long serialVersionUID = -2197602941230009227L; + + @Column(name = "name", nullable = false) + private String name; + + @Column(name = "description", nullable = true) + private String description; + + @Column(name = "start_datetime", nullable = false) + @Temporal(TemporalType.TIMESTAMP) + private Date startDateTime; + + @Column(name = "recurrence", nullable = true) + private String recurrence; + + @Column(name = "email_recipients", nullable = false) + private String emailRecipients; + + @Column(name = "email_subject", nullable = false) + private String emailSubject; + + @Column(name = "email_message", nullable = false) + private String emailMessage; + + @Column(name = "email_attachment_file_format", nullable = false) + private String emailAttachmentFileFormat; + + @ManyToOne + @JoinColumn(name = "stretchy_report_id", nullable = false) + private Report stretchyReport; + + @Column(name = "stretchy_report_param_map", nullable = true) + private String stretchyReportParamMap; + + @Column(name = "previous_run_datetime", nullable = true) + @Temporal(TemporalType.TIMESTAMP) + private Date previousRunDateTime; + + @Column(name = "next_run_datetime", nullable = true) + @Temporal(TemporalType.TIMESTAMP) + private Date nextRunDateTime; + + @Column(name = "previous_run_status", nullable = true) + private String previousRunStatus; + + @Column(name = "previous_run_error_log", nullable = true) + private String previousRunErrorLog; + + @Column(name = "previous_run_error_message", nullable = true) + private String previousRunErrorMessage; + + @Column(name = "number_of_runs", nullable = false) + private Integer numberOfRuns; + + @Column(name = "is_active", nullable = false) + private boolean isActive; + + @Column(name = "is_deleted", nullable = false) + private boolean isDeleted; + + @ManyToOne(optional = false) + @JoinColumn(name = "run_as_userid", nullable = false) + private AppUser runAsUser; + + /** + * ReportMailingJob protected constructor + **/ + protected ReportMailingJob() { } + + /** + * ReportMailingJob private constructor + **/ + private ReportMailingJob(final String name, final String description, final LocalDateTime startDateTime, + final String recurrence, final String emailRecipients, final String emailSubject, + final String emailMessage, final ReportMailingJobEmailAttachmentFileFormat emailAttachmentFileFormat, + final Report stretchyReport, final String stretchyReportParamMap, final LocalDateTime previousRunDateTime, final LocalDateTime nextRunDateTime, + final ReportMailingJobPreviousRunStatus previousRunStatus, final String previousRunErrorLog, final String previousRunErrorMessage, + final boolean isActive, final boolean isDeleted, final AppUser runAsUser) { + this.name = name; + this.description = description; + this.startDateTime = null; + + if (startDateTime != null) { + this.startDateTime = startDateTime.toDate(); + } + + this.recurrence = recurrence; + this.emailRecipients = emailRecipients; + this.emailSubject = emailSubject; + this.emailMessage = emailMessage; + this.emailAttachmentFileFormat = emailAttachmentFileFormat.getValue(); + this.stretchyReport = stretchyReport; + this.stretchyReportParamMap = stretchyReportParamMap; + this.previousRunDateTime = null; + + if (previousRunDateTime != null) { + this.previousRunDateTime = previousRunDateTime.toDate(); + } + + this.nextRunDateTime = null; + + if (nextRunDateTime != null) { + this.nextRunDateTime = nextRunDateTime.toDate(); + } + + this.previousRunStatus = null; + + if (previousRunStatus != null) { + this.previousRunStatus = previousRunStatus.getValue(); + } + + if (numberOfRuns == null) { + this.numberOfRuns = 0; + } + + this.previousRunErrorLog = previousRunErrorLog; + this.previousRunErrorMessage = previousRunErrorMessage; + this.isActive = isActive; + this.isDeleted = isDeleted; + this.runAsUser = runAsUser; + } + + /** + * create a new instance of the ReportMailingJob for a new entry + * + * @return ReportMailingJob object + **/ + public static ReportMailingJob newInstance(final String name, final String description, final LocalDateTime startDateTime, final String recurrence, + final String emailRecipients, final String emailSubject, final String emailMessage, + final ReportMailingJobEmailAttachmentFileFormat emailAttachmentFileFormat, final Report stretchyReport, final String stretchyReportParamMap, + final boolean isActive, final AppUser runAsUser) { + return new ReportMailingJob(name, description, startDateTime, recurrence, emailRecipients, emailSubject, + emailMessage, emailAttachmentFileFormat, stretchyReport, stretchyReportParamMap, null, null, null, null, null, isActive, false, runAsUser); + } + + /** + * create a new instance of the ReportmailingJob for a new entry + * + * @return ReportMailingJob object + **/ + public static ReportMailingJob newInstance(JsonCommand jsonCommand, final Report stretchyReport, + final AppUser runAsUser) { + final String name = jsonCommand.stringValueOfParameterNamed(ReportMailingJobConstants.NAME_PARAM_NAME); + final String description = jsonCommand.stringValueOfParameterNamed(ReportMailingJobConstants.DESCRIPTION_PARAM_NAME); + final String recurrence = jsonCommand.stringValueOfParameterNamed(ReportMailingJobConstants.RECURRENCE_PARAM_NAME); + final boolean isActive = jsonCommand.booleanPrimitiveValueOfParameterNamed(ReportMailingJobConstants.IS_ACTIVE_PARAM_NAME); + final String emailRecipients = jsonCommand.stringValueOfParameterNamed(ReportMailingJobConstants.EMAIL_RECIPIENTS_PARAM_NAME); + final String emailSubject = jsonCommand.stringValueOfParameterNamed(ReportMailingJobConstants.EMAIL_SUBJECT_PARAM_NAME); + final String emailMessage = jsonCommand.stringValueOfParameterNamed(ReportMailingJobConstants.EMAIL_MESSAGE_PARAM_NAME); + final String stretchyReportParamMap = jsonCommand.stringValueOfParameterNamed(ReportMailingJobConstants.STRETCHY_REPORT_PARAM_MAP_PARAM_NAME); + final Integer emailAttachmentFileFormatId = jsonCommand.integerValueOfParameterNamed(ReportMailingJobConstants.EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME); + final ReportMailingJobEmailAttachmentFileFormat emailAttachmentFileFormat = ReportMailingJobEmailAttachmentFileFormat.newInstance(emailAttachmentFileFormatId); + LocalDateTime startDateTime = new LocalDateTime(); + + if (jsonCommand.hasParameter(ReportMailingJobConstants.START_DATE_TIME_PARAM_NAME)) { + final String startDateTimeString = jsonCommand.stringValueOfParameterNamed(ReportMailingJobConstants.START_DATE_TIME_PARAM_NAME); + + if (startDateTimeString != null) { + final DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(jsonCommand.dateFormat()).withLocale(jsonCommand.extractLocale()); + startDateTime = LocalDateTime.parse(startDateTimeString, dateTimeFormatter); + } + } + + return new ReportMailingJob(name, description, startDateTime, recurrence, emailRecipients, emailSubject, + emailMessage, emailAttachmentFileFormat, stretchyReport, stretchyReportParamMap, null, startDateTime, null, null, null, isActive, false, runAsUser); + } + + /** + * Update the ReportMailingJob entity + * + * @param jsonCommand JsonCommand object + * @return map of string to object + **/ + public Map update(final JsonCommand jsonCommand) { + final Map actualChanges = new LinkedHashMap<>(); + + if (jsonCommand.isChangeInStringParameterNamed(ReportMailingJobConstants.NAME_PARAM_NAME, this.name)) { + final String name = jsonCommand.stringValueOfParameterNamed(ReportMailingJobConstants.NAME_PARAM_NAME); + actualChanges.put(ReportMailingJobConstants.NAME_PARAM_NAME, name); + + this.name = name; + } + + if (jsonCommand.isChangeInStringParameterNamed(ReportMailingJobConstants.DESCRIPTION_PARAM_NAME, this.description)) { + final String description = jsonCommand.stringValueOfParameterNamed(ReportMailingJobConstants.DESCRIPTION_PARAM_NAME); + actualChanges.put(ReportMailingJobConstants.DESCRIPTION_PARAM_NAME, description); + + this.description = description; + } + + if (jsonCommand.isChangeInStringParameterNamed(ReportMailingJobConstants.RECURRENCE_PARAM_NAME, this.recurrence)) { + final String recurrence = jsonCommand.stringValueOfParameterNamed(ReportMailingJobConstants.RECURRENCE_PARAM_NAME); + actualChanges.put(ReportMailingJobConstants.RECURRENCE_PARAM_NAME, recurrence); + + this.recurrence = recurrence; + } + + if (jsonCommand.isChangeInBooleanParameterNamed(ReportMailingJobConstants.IS_ACTIVE_PARAM_NAME, this.isActive)) { + final boolean isActive = jsonCommand.booleanPrimitiveValueOfParameterNamed(ReportMailingJobConstants.IS_ACTIVE_PARAM_NAME); + actualChanges.put(ReportMailingJobConstants.IS_ACTIVE_PARAM_NAME, isActive); + + this.isActive = isActive; + } + + if (jsonCommand.isChangeInStringParameterNamed(ReportMailingJobConstants.EMAIL_RECIPIENTS_PARAM_NAME, this.emailRecipients)) { + final String emailRecipients = jsonCommand.stringValueOfParameterNamed(ReportMailingJobConstants.EMAIL_RECIPIENTS_PARAM_NAME); + actualChanges.put(ReportMailingJobConstants.EMAIL_RECIPIENTS_PARAM_NAME, emailRecipients); + + this.emailRecipients = emailRecipients; + } + + if (jsonCommand.isChangeInStringParameterNamed(ReportMailingJobConstants.EMAIL_SUBJECT_PARAM_NAME, this.emailSubject)) { + final String emailSubject = jsonCommand.stringValueOfParameterNamed(ReportMailingJobConstants.EMAIL_SUBJECT_PARAM_NAME); + actualChanges.put(ReportMailingJobConstants.EMAIL_SUBJECT_PARAM_NAME, emailSubject); + + this.emailSubject = emailSubject; + } + + if (jsonCommand.isChangeInStringParameterNamed(ReportMailingJobConstants.EMAIL_MESSAGE_PARAM_NAME, this.emailMessage)) { + final String emailMessage = jsonCommand.stringValueOfParameterNamed(ReportMailingJobConstants.EMAIL_MESSAGE_PARAM_NAME); + actualChanges.put(ReportMailingJobConstants.EMAIL_MESSAGE_PARAM_NAME, emailMessage); + + this.emailMessage = emailMessage; + } + + if (jsonCommand.isChangeInStringParameterNamed(ReportMailingJobConstants.STRETCHY_REPORT_PARAM_MAP_PARAM_NAME, this.stretchyReportParamMap)) { + final String stretchyReportParamMap = jsonCommand.stringValueOfParameterNamed(ReportMailingJobConstants.STRETCHY_REPORT_PARAM_MAP_PARAM_NAME); + actualChanges.put(ReportMailingJobConstants.STRETCHY_REPORT_PARAM_MAP_PARAM_NAME, stretchyReportParamMap); + + this.stretchyReportParamMap = stretchyReportParamMap; + } + + final ReportMailingJobEmailAttachmentFileFormat emailAttachmentFileFormat = ReportMailingJobEmailAttachmentFileFormat.newInstance(this.emailAttachmentFileFormat); + + if (jsonCommand.isChangeInIntegerParameterNamed(ReportMailingJobConstants.EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME, emailAttachmentFileFormat.getId())) { + final Integer emailAttachmentFileFormatId = jsonCommand.integerValueOfParameterNamed(ReportMailingJobConstants.EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME); + actualChanges.put(ReportMailingJobConstants.EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME, emailAttachmentFileFormatId); + + final ReportMailingJobEmailAttachmentFileFormat newEmailAttachmentFileFormat = ReportMailingJobEmailAttachmentFileFormat.newInstance(emailAttachmentFileFormatId); + this.emailAttachmentFileFormat = newEmailAttachmentFileFormat.getValue(); + } + + final String newStartDateTimeString = jsonCommand.stringValueOfParameterNamed(ReportMailingJobConstants.START_DATE_TIME_PARAM_NAME); + + if (!StringUtils.isEmpty(newStartDateTimeString)) { + final DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(jsonCommand.dateFormat()).withLocale(jsonCommand.extractLocale()); + final LocalDateTime newStartDateTime = LocalDateTime.parse(newStartDateTimeString, dateTimeFormatter); + final LocalDateTime oldStartDateTime = (this.startDateTime != null) ? new LocalDateTime(this.startDateTime) : null; + + if ((oldStartDateTime != null) && !newStartDateTime.equals(oldStartDateTime)) { + actualChanges.put(ReportMailingJobConstants.START_DATE_TIME_PARAM_NAME, newStartDateTimeString); + + this.startDateTime = newStartDateTime.toDate(); + } + } + + Long currentStretchyReportId = null; + + if (this.stretchyReport != null) { + currentStretchyReportId = this.stretchyReport.getId(); + } + + if (jsonCommand.isChangeInLongParameterNamed(ReportMailingJobConstants.STRETCHY_REPORT_ID_PARAM_NAME, currentStretchyReportId)) { + final Long updatedStretchyReportId = jsonCommand.longValueOfParameterNamed( + ReportMailingJobConstants.STRETCHY_REPORT_ID_PARAM_NAME); + actualChanges.put(ReportMailingJobConstants.STRETCHY_REPORT_ID_PARAM_NAME, updatedStretchyReportId); + } + + return actualChanges; + } + + /** + * update the stretchy report entity associated with the credit check + * + * @param stretchyReport -- Report entity + * @return None + **/ + public void update(final Report stretchyReport) { + if (stretchyReport != null) { + this.stretchyReport = stretchyReport; + } + } + + /** + * delete the report mailing job, set the isDeleted property to 1 and alter the name + * + * @return None + **/ + public void delete() { + this.isDeleted = true; + this.isActive = false; + this.name = this.name + "_deleted_" + this.getId(); + } + + /** + * @return the value of the name property + **/ + public String getName() { + return this.name; + } + + /** + * @return the value of the description property + **/ + public String getDescription() { + return this.description; + } + + /** + * @return the value of the startDateTime property + **/ + public DateTime getStartDateTime() { + return (this.startDateTime != null) ? new DateTime(this.startDateTime) : null; + } + + /** + * @return the value of the recurrence property + **/ + public String getRecurrence() { + return this.recurrence; + } + + /** + * @return value of the isDeleted property + **/ + public boolean isDeleted() { + return this.isDeleted; + } + + /** + * @return boolean true if isDeleted property equals 0, else false + **/ + public boolean isNotDeleted() { + return !this.isDeleted; + } + + /** + * @return the value of the isActive property + **/ + public boolean isActive() { + return this.isActive; + } + + /** + * @return boolean true if isActive property equals 0, else false + **/ + public boolean isNotActive() { + return !this.isActive; + } + + /** + * @return the emailRecipients + */ + public String getEmailRecipients() { + return emailRecipients; + } + + /** + * @return the emailSubject + */ + public String getEmailSubject() { + return emailSubject; + } + + /** + * @return the emailMessage + */ + public String getEmailMessage() { + return emailMessage; + } + + /** + * @return the emailAttachmentFileFormat + */ + public String getEmailAttachmentFileFormat() { + return emailAttachmentFileFormat; + } + + /** + * @return the stretchyReport + */ + public Report getStretchyReport() { + return stretchyReport; + } + + /** + * @return the stretchyReportParamMap + */ + public String getStretchyReportParamMap() { + return stretchyReportParamMap; + } + + /** + * @return the previousRunDateTime + */ + public DateTime getPreviousRunDateTime() { + return (this.previousRunDateTime != null) ? new DateTime(this.previousRunDateTime) : null; + } + + /** + * @return the nextRunDateTime + */ + public DateTime getNextRunDateTime() { + return (this.nextRunDateTime != null) ? new DateTime(this.nextRunDateTime) : null; + } + + /** + * @return the previousRunStatus + */ + public String getPreviousRunStatus() { + return previousRunStatus; + } + + /** + * @return the previousRunErrorLog + */ + public String getPreviousRunErrorLog() { + return previousRunErrorLog; + } + + /** + * @return the previousRunErrorMessage + */ + public String getPreviousRunErrorMessage() { + return previousRunErrorMessage; + } + + /** + * @return the numberOfRuns + */ + public Integer getNumberOfRuns() { + return numberOfRuns; + } + + /** + * @return the runAsUser + */ + public AppUser getRunAsUser() { + return runAsUser; + } + + /** + * increase the numberOfRuns by 1 + * + * @return None + **/ + public void increaseNumberOfRunsByOne() { + this.numberOfRuns++; + } + + /** + * update the previousRunStatus + * + * @param previousRunStatus -- the status of the previous job execution + * @return None + **/ + public void updatePreviousRunStatus(final String previousRunStatus) { + if (!StringUtils.isEmpty(previousRunStatus)) { + this.previousRunStatus = previousRunStatus; + } + } + + /** + * update the previousRunDateTime + * + * @param previousRunDateTime -- previous run date + * @return None + **/ + public void updatePreviousRunDateTime(final DateTime previousRunDateTime) { + if (previousRunDateTime != null) { + this.previousRunDateTime = previousRunDateTime.toDate(); + } + } + + /** + * update the nextRunDateTime + * + * @param nextRunDateTime -- the next run DateTime + * @return None + **/ + public void updateNextRunDateTime(final DateTime nextRunDateTime) { + if (nextRunDateTime != null) { + this.nextRunDateTime = nextRunDateTime.toDate(); + } + + else { + this.nextRunDateTime = null; + } + } + + /** + * deactivate the report mailing job by setting the isActive property to 0 + * + * @return None + **/ + public void deactivate() { + this.isActive = false; + } + + /** + * update the previousRunErrorLog property + * + * @param previousRunErrorLog -- the previous job run error log + * @return None + **/ + public void updatePreviousRunErrorLog(final String previousRunErrorLog) { + this.previousRunErrorLog = previousRunErrorLog; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJobConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJobConfiguration.java new file mode 100644 index 000000000..17eb7b68c --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJobConfiguration.java @@ -0,0 +1,74 @@ +/** + * 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.reportmailingjob.domain; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; + +import org.springframework.data.jpa.domain.AbstractPersistable; + +@Entity +@Table(name = "m_report_mailing_job_configuration", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "unique_name") }) +public class ReportMailingJobConfiguration extends AbstractPersistable { + private static final long serialVersionUID = 3099279770861263184L; + + @Column(name = "name", nullable = false) + private String name; + + @Column(name = "value", nullable = false) + private String value; + + /** + * ReportMailingJobConfiguration protected constructor + **/ + protected ReportMailingJobConfiguration() { } + + /** + * ReportMailingJobConfiguration private constructor + **/ + private ReportMailingJobConfiguration(final String name, final String value) { + this.name = name; + this.value = value; + } + + /** + * creates an instance of the ReportMailingJobConfiguration class + * + * @return ReportMailingJobConfiguration object + **/ + public static ReportMailingJobConfiguration newInstance(final String name, final String value) { + return new ReportMailingJobConfiguration(name, value); + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @return the value + */ + public String getValue() { + return value; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJobConfigurationRepository.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJobConfigurationRepository.java new file mode 100644 index 000000000..8e7168ede --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJobConfigurationRepository.java @@ -0,0 +1,31 @@ +/** + * 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.reportmailingjob.domain; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface ReportMailingJobConfigurationRepository extends JpaRepository, + JpaSpecificationExecutor { + + /** + * find ReportMailingJobConfiguration by name + **/ + ReportMailingJobConfiguration findByName(final String name); +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJobRepository.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJobRepository.java new file mode 100644 index 000000000..94268d837 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJobRepository.java @@ -0,0 +1,33 @@ +/** + * 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.reportmailingjob.domain; + +import java.util.Collection; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface ReportMailingJobRepository extends JpaRepository, JpaSpecificationExecutor { + /** + * Returns all instances of {@link ReportMailingJob} where isActive is true and isDeleted is false + * + * @return instances of {@link ReportMailingJob} + */ + public Collection findByIsActiveTrueAndIsDeletedFalse(); +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJobRepositoryWrapper.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJobRepositoryWrapper.java new file mode 100644 index 000000000..ad9e84ec6 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJobRepositoryWrapper.java @@ -0,0 +1,56 @@ +/** + * 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.reportmailingjob.domain; + +import org.apache.fineract.infrastructure.reportmailingjob.exception.ReportMailingJobNotFoundException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class ReportMailingJobRepositoryWrapper { + private final ReportMailingJobRepository reportMailingJobRepository; + + @Autowired + public ReportMailingJobRepositoryWrapper(final ReportMailingJobRepository reportMailingJobRepository) { + this.reportMailingJobRepository = reportMailingJobRepository; + } + + /** + * find report mailing job by ID, throw a "entity not found" exception if the job does not exist + * + * @param id -- the identifier of the report mailing job to be found + * @return ReportMailingJob object + **/ + public ReportMailingJob findOneThrowExceptionIfNotFound(final Long id) { + final ReportMailingJob reportMailingJob = this.reportMailingJobRepository.findOne(id); + + if (reportMailingJob == null || reportMailingJob.isDeleted()) { + throw new ReportMailingJobNotFoundException(id); + } + + return reportMailingJob; + } + + /** + * @return ReportMailingJobRepository Jpa Repository object + **/ + public ReportMailingJobRepository getReportMailingJobRepository() { + return this.reportMailingJobRepository; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJobRunHistory.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJobRunHistory.java new file mode 100644 index 000000000..4839ed637 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJobRunHistory.java @@ -0,0 +1,139 @@ +/** + * 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.reportmailingjob.domain; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +import org.joda.time.DateTime; +import org.springframework.data.jpa.domain.AbstractPersistable; + +@Entity +@Table(name = "m_report_mailing_job_run_history") +public class ReportMailingJobRunHistory extends AbstractPersistable { + private static final long serialVersionUID = -3757370929988421076L; + + @ManyToOne + @JoinColumn(name = "job_id", nullable = false) + private ReportMailingJob reportMailingJob; + + @Column(name = "start_datetime", nullable = false) + @Temporal(TemporalType.TIMESTAMP) + private Date startDateTime; + + @Column(name = "end_datetime", nullable = false) + @Temporal(TemporalType.TIMESTAMP) + private Date endDateTime; + + @Column(name = "status", nullable = false) + private String status; + + @Column(name = "error_message", nullable = false) + private String errorMessage; + + @Column(name = "error_log", nullable = false) + private String errorLog; + + /** + * ReportMailingJobRunHistory protected constructor + **/ + protected ReportMailingJobRunHistory() { } + + /** + * ReportMailingJobRunHistory private constructor + **/ + private ReportMailingJobRunHistory(final ReportMailingJob reportMailingJob, final DateTime startDateTime, final DateTime endDateTime, final String status, + final String errorMessage, final String errorLog) { + this.reportMailingJob = reportMailingJob; + this.startDateTime = null; + + if (startDateTime != null) { + this.startDateTime = startDateTime.toDate(); + } + + this.endDateTime = null; + + if (endDateTime != null) { + this.endDateTime = endDateTime.toDate(); + } + + this.status = status; + this.errorMessage = errorMessage; + this.errorLog = errorLog; + } + + /** + * Creates an instance of the ReportMailingJobRunHistory class + * + * @return ReportMailingJobRunHistory object + **/ + public static ReportMailingJobRunHistory newInstance(final ReportMailingJob reportMailingJob, final DateTime startDateTime, final DateTime endDateTime, + final String status, final String errorMessage, final String errorLog) { + return new ReportMailingJobRunHistory(reportMailingJob, startDateTime, endDateTime, status, errorMessage, errorLog); + } + + /** + * @return the reportMailingJobId + */ + public ReportMailingJob getReportMailingJob() { + return this.reportMailingJob; + } + + /** + * @return the startDateTime + */ + public DateTime getStartDateTime() { + return (this.startDateTime != null) ? new DateTime(this.startDateTime) : null; + } + + /** + * @return the endDateTime + */ + public DateTime getEndDateTime() { + return (this.endDateTime != null) ? new DateTime(this.endDateTime) : null; + } + + /** + * @return the status + */ + public String getStatus() { + return status; + } + + /** + * @return the errorMessage + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * @return the errorLog + */ + public String getErrorLog() { + return errorLog; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJobRunHistoryRepository.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJobRunHistoryRepository.java new file mode 100644 index 000000000..be6cdfaa8 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/domain/ReportMailingJobRunHistoryRepository.java @@ -0,0 +1,26 @@ +/** + * 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.reportmailingjob.domain; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface ReportMailingJobRunHistoryRepository extends JpaRepository, JpaSpecificationExecutor { + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/exception/ReportMailingJobConfigurationNotFoundException.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/exception/ReportMailingJobConfigurationNotFoundException.java new file mode 100644 index 000000000..9d45449eb --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/exception/ReportMailingJobConfigurationNotFoundException.java @@ -0,0 +1,33 @@ +/** + * 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.reportmailingjob.exception; + +import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; + +/** + * A {@link RuntimeException} thrown when report mailing job configuration resources are not found. + **/ +@SuppressWarnings("serial") +public class ReportMailingJobConfigurationNotFoundException extends AbstractPlatformResourceNotFoundException { + + public ReportMailingJobConfigurationNotFoundException(final String name) { + super("error.msg.report.mailing.job.configuration.name.invalid", "Report mailing job configuration with name " + name + + " does not exist", name); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/exception/ReportMailingJobNotFoundException.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/exception/ReportMailingJobNotFoundException.java new file mode 100644 index 000000000..b8e662681 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/exception/ReportMailingJobNotFoundException.java @@ -0,0 +1,33 @@ +/** + * 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.reportmailingjob.exception; + +import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; + +/** + * A {@link RuntimeException} thrown when report mailing job resources are not found. + **/ +@SuppressWarnings("serial") +public class ReportMailingJobNotFoundException extends AbstractPlatformResourceNotFoundException { + + public ReportMailingJobNotFoundException(final Long reportMailingJobId) { + super("error.msg.report.mailing.job.id.invalid", "Report mailing job with identifier " + reportMailingJobId + + " does not exist", reportMailingJobId); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/exception/ReportMailingJobRunHistoryNotFoundException.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/exception/ReportMailingJobRunHistoryNotFoundException.java new file mode 100644 index 000000000..a69999bb5 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/exception/ReportMailingJobRunHistoryNotFoundException.java @@ -0,0 +1,32 @@ +/** + * 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.reportmailingjob.exception; + +import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; + +/** + * A {@link RuntimeException} thrown when report mailing job run history resources are not found. + **/ +@SuppressWarnings("serial") +public class ReportMailingJobRunHistoryNotFoundException extends AbstractPlatformResourceNotFoundException { + public ReportMailingJobRunHistoryNotFoundException(final Long reportMailingJobId) { + super("error.msg.report.mailing.job.run.history.invalid", "Report mailing job run history with job identifier " + + reportMailingJobId + " does not exist", reportMailingJobId); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/handler/CreateReportMailingJobCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/handler/CreateReportMailingJobCommandHandler.java new file mode 100644 index 000000000..501caedca --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/handler/CreateReportMailingJobCommandHandler.java @@ -0,0 +1,46 @@ +/** + * 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.reportmailingjob.handler; + +import org.apache.fineract.commands.annotation.CommandType; +import org.apache.fineract.commands.handler.NewCommandSourceHandler; +import org.apache.fineract.infrastructure.core.api.JsonCommand; +import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.infrastructure.reportmailingjob.ReportMailingJobConstants; +import org.apache.fineract.infrastructure.reportmailingjob.service.ReportMailingJobWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@CommandType(entity = ReportMailingJobConstants.REPORT_MAILING_JOB_ENTITY_NAME, action = "CREATE") +public class CreateReportMailingJobCommandHandler implements NewCommandSourceHandler { + private final ReportMailingJobWritePlatformService reportMailingJobWritePlatformService; + + @Autowired + public CreateReportMailingJobCommandHandler(final ReportMailingJobWritePlatformService reportMailingJobWritePlatformService) { + this.reportMailingJobWritePlatformService = reportMailingJobWritePlatformService; + } + + @Override + @Transactional + public CommandProcessingResult processCommand(JsonCommand jsonCommand) { + return this.reportMailingJobWritePlatformService.createReportMailingJob(jsonCommand); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/handler/DeleteReportMailingJobCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/handler/DeleteReportMailingJobCommandHandler.java new file mode 100644 index 000000000..51d57d756 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/handler/DeleteReportMailingJobCommandHandler.java @@ -0,0 +1,46 @@ +/** + * 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.reportmailingjob.handler; + +import org.apache.fineract.commands.annotation.CommandType; +import org.apache.fineract.commands.handler.NewCommandSourceHandler; +import org.apache.fineract.infrastructure.core.api.JsonCommand; +import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.infrastructure.reportmailingjob.ReportMailingJobConstants; +import org.apache.fineract.infrastructure.reportmailingjob.service.ReportMailingJobWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@CommandType(entity = ReportMailingJobConstants.REPORT_MAILING_JOB_ENTITY_NAME, action = "DELETE") +public class DeleteReportMailingJobCommandHandler implements NewCommandSourceHandler { + private final ReportMailingJobWritePlatformService reportMailingJobWritePlatformService; + + @Autowired + public DeleteReportMailingJobCommandHandler(final ReportMailingJobWritePlatformService reportMailingJobWritePlatformService) { + this.reportMailingJobWritePlatformService = reportMailingJobWritePlatformService; + } + + @Override + @Transactional + public CommandProcessingResult processCommand(JsonCommand jsonCommand) { + return this.reportMailingJobWritePlatformService.deleteReportMailingJob(jsonCommand.entityId()); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/handler/UpdateReportMailingJobCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/handler/UpdateReportMailingJobCommandHandler.java new file mode 100644 index 000000000..7622ca6a2 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/handler/UpdateReportMailingJobCommandHandler.java @@ -0,0 +1,46 @@ +/** + * 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.reportmailingjob.handler; + +import org.apache.fineract.commands.annotation.CommandType; +import org.apache.fineract.commands.handler.NewCommandSourceHandler; +import org.apache.fineract.infrastructure.core.api.JsonCommand; +import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.infrastructure.reportmailingjob.ReportMailingJobConstants; +import org.apache.fineract.infrastructure.reportmailingjob.service.ReportMailingJobWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@CommandType(entity = ReportMailingJobConstants.REPORT_MAILING_JOB_ENTITY_NAME, action = "UPDATE") +public class UpdateReportMailingJobCommandHandler implements NewCommandSourceHandler { + private final ReportMailingJobWritePlatformService reportMailingJobWritePlatformService; + + @Autowired + public UpdateReportMailingJobCommandHandler(final ReportMailingJobWritePlatformService reportMailingJobWritePlatformService) { + this.reportMailingJobWritePlatformService = reportMailingJobWritePlatformService; + } + + @Override + @Transactional + public CommandProcessingResult processCommand(JsonCommand jsonCommand) { + return this.reportMailingJobWritePlatformService.updateReportMailingJob(jsonCommand.entityId(), jsonCommand); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobConfigurationReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobConfigurationReadPlatformService.java new file mode 100644 index 000000000..4812ae070 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobConfigurationReadPlatformService.java @@ -0,0 +1,39 @@ +/** + * 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.reportmailingjob.service; + +import java.util.Collection; + +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobConfigurationData; + +public interface ReportMailingJobConfigurationReadPlatformService { + /** + * Retrieve all report mailing job configurations + * + * @return ReportMailingJobConfigurationData object + **/ + Collection retrieveAllReportMailingJobConfigurations(); + + /** + * Retrieve report mailing job configuration by name + * + * @return ReportMailingJobConfigurationData object + **/ + ReportMailingJobConfigurationData retrieveReportMailingJobConfiguration(final String name); +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobConfigurationReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobConfigurationReadPlatformServiceImpl.java new file mode 100644 index 000000000..fd8dfac66 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobConfigurationReadPlatformServiceImpl.java @@ -0,0 +1,84 @@ +/** + * 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.reportmailingjob.service; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; + +import org.apache.fineract.infrastructure.core.domain.JdbcSupport; +import org.apache.fineract.infrastructure.core.service.RoutingDataSource; +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobConfigurationData; +import org.apache.fineract.infrastructure.reportmailingjob.exception.ReportMailingJobConfigurationNotFoundException; +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; + +@Service +public class ReportMailingJobConfigurationReadPlatformServiceImpl implements ReportMailingJobConfigurationReadPlatformService { + private final JdbcTemplate jdbcTemplate; + + /** + * ReportMailingJobConfigurationReadPlatformServiceImpl constructor + **/ + @Autowired + public ReportMailingJobConfigurationReadPlatformServiceImpl(final RoutingDataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + @Override + public Collection retrieveAllReportMailingJobConfigurations() { + final ReportMailingJobConfigurationMapper mapper = new ReportMailingJobConfigurationMapper(); + final String sql = "select " + mapper.ReportMailingJobConfigurationSchema(); + + return this.jdbcTemplate.query(sql, mapper, new Object[] {}); + } + + @Override + public ReportMailingJobConfigurationData retrieveReportMailingJobConfiguration(String name) { + try { + final ReportMailingJobConfigurationMapper mapper = new ReportMailingJobConfigurationMapper(); + final String sql = "select " + mapper.ReportMailingJobConfigurationSchema() + " where rmjc.name = ?"; + + return this.jdbcTemplate.queryForObject(sql, mapper, new Object[] { name }); + } + + catch (final EmptyResultDataAccessException ex) { + throw new ReportMailingJobConfigurationNotFoundException(name); + } + } + + private static final class ReportMailingJobConfigurationMapper implements RowMapper { + public String ReportMailingJobConfigurationSchema() { + return "rmjc.id, rmjc.name, rmjc.value " + + "from m_report_mailing_job_configuration rmjc"; + } + + @Override + public ReportMailingJobConfigurationData mapRow(ResultSet rs, int rowNum) throws SQLException { + final Integer id = JdbcSupport.getInteger(rs, "id"); + final String name = rs.getString("name"); + final String value = rs.getString("value"); + + return ReportMailingJobConfigurationData.newInstance(id, name, value); + } + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobEmailService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobEmailService.java new file mode 100644 index 000000000..5df05a31b --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobEmailService.java @@ -0,0 +1,30 @@ +/** + * 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.reportmailingjob.service; + +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobEmailData; + +public interface ReportMailingJobEmailService { + /** + * Handles request to send an email with attachment + * + * @param reportMailingJobEmailData {@link ReportMailingJobEmailData} object + */ + void sendEmailWithAttachment(final ReportMailingJobEmailData reportMailingJobEmailData); +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobEmailServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobEmailServiceImpl.java new file mode 100644 index 000000000..58bb09a6d --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobEmailServiceImpl.java @@ -0,0 +1,162 @@ +/** + * 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.reportmailingjob.service; + +import java.util.Collection; +import java.util.Properties; + +import javax.mail.MessagingException; +import javax.mail.internet.MimeMessage; + +import org.apache.commons.lang.StringUtils; +import org.apache.fineract.infrastructure.reportmailingjob.ReportMailingJobConstants; +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobConfigurationData; +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobEmailData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mail.javamail.JavaMailSenderImpl; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.stereotype.Service; + +@Service +public class ReportMailingJobEmailServiceImpl implements ReportMailingJobEmailService { + private final ReportMailingJobConfigurationReadPlatformService reportMailingJobConfigurationReadPlatformService; + private Collection reportMailingJobConfigurationDataCollection; + + /** + * ReportMailingJobEmailServiceImpl constructor + **/ + @Autowired + public ReportMailingJobEmailServiceImpl(final ReportMailingJobConfigurationReadPlatformService reportMailingJobConfigurationReadPlatformService) { + this.reportMailingJobConfigurationReadPlatformService = reportMailingJobConfigurationReadPlatformService; + + } + + @Override + public void sendEmailWithAttachment(ReportMailingJobEmailData reportMailingJobEmailData) { + try { + // get all ReportMailingJobConfiguration objects from the database + this.reportMailingJobConfigurationDataCollection = this.reportMailingJobConfigurationReadPlatformService. + retrieveAllReportMailingJobConfigurations(); + + JavaMailSenderImpl javaMailSenderImpl = new JavaMailSenderImpl(); + javaMailSenderImpl.setHost(this.getGmailSmtpServer()); + javaMailSenderImpl.setPort(this.getGmailSmtpPort()); + javaMailSenderImpl.setUsername(this.getGmailSmtpUsername()); + javaMailSenderImpl.setPassword(this.getGmailSmtpPassword()); + javaMailSenderImpl.setJavaMailProperties(this.getJavaMailProperties()); + + MimeMessage mimeMessage = javaMailSenderImpl.createMimeMessage(); + + // use the true flag to indicate you need a multipart message + MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true); + + mimeMessageHelper.setTo(reportMailingJobEmailData.getTo()); + mimeMessageHelper.setText(reportMailingJobEmailData.getText()); + mimeMessageHelper.setSubject(reportMailingJobEmailData.getSubject()); + + if (reportMailingJobEmailData.getAttachment() != null) { + mimeMessageHelper.addAttachment(reportMailingJobEmailData.getAttachment().getName(), reportMailingJobEmailData.getAttachment()); + } + + javaMailSenderImpl.send(mimeMessage); + } + + catch (MessagingException e) { + // handle the exception + e.printStackTrace(); + } + } + + /** + * @return Properties object containing JavaMail properties + **/ + private Properties getJavaMailProperties() { + Properties properties = new Properties(); + + properties.setProperty("mail.smtp.auth", "true"); + properties.setProperty("mail.smtp.starttls.enable", "true"); + properties.setProperty("mail.smtp.ssl.trust", this.getGmailSmtpServer()); + + return properties; + } + + /** + * get a report mailing job configuration object by name from collection of objects + * + * @param name -- the value of the name property + * @return ReportMailingJobConfigurationData object + **/ + private ReportMailingJobConfigurationData getReportMailingJobConfigurationData(final String name) { + ReportMailingJobConfigurationData reportMailingJobConfigurationData = null; + + if (this.reportMailingJobConfigurationDataCollection != null && !this.reportMailingJobConfigurationDataCollection.isEmpty()) { + for (ReportMailingJobConfigurationData reportMailingJobConfigurationDataObject : this.reportMailingJobConfigurationDataCollection) { + String configurationName = reportMailingJobConfigurationDataObject.getName(); + + if (!StringUtils.isEmpty(configurationName) && configurationName.equals(name)) { + reportMailingJobConfigurationData = reportMailingJobConfigurationDataObject; + break; + } + } + } + + return reportMailingJobConfigurationData; + } + + /** + * @return Gmail smtp server name + **/ + private String getGmailSmtpServer() { + final ReportMailingJobConfigurationData reportMailingJobConfigurationData = this.getReportMailingJobConfigurationData + (ReportMailingJobConstants.GMAIL_SMTP_SERVER); + + return (reportMailingJobConfigurationData != null) ? reportMailingJobConfigurationData.getValue() : null; + } + + /** + * @return Gmail smtp server port number + **/ + private Integer getGmailSmtpPort() { + final ReportMailingJobConfigurationData reportMailingJobConfigurationData = this.getReportMailingJobConfigurationData + (ReportMailingJobConstants.GMAIL_SMTP_PORT); + final String portNumber = (reportMailingJobConfigurationData != null) ? reportMailingJobConfigurationData.getValue() : null; + + return (portNumber != null) ? Integer.parseInt(portNumber) : null; + } + + /** + * @return Gmail smtp username + **/ + private String getGmailSmtpUsername() { + final ReportMailingJobConfigurationData reportMailingJobConfigurationData = this.getReportMailingJobConfigurationData + (ReportMailingJobConstants.GMAIL_SMTP_USERNAME); + + return (reportMailingJobConfigurationData != null) ? reportMailingJobConfigurationData.getValue() : null; + } + + /** + * @return Gmail smtp password + **/ + private String getGmailSmtpPassword() { + final ReportMailingJobConfigurationData reportMailingJobConfigurationData = this.getReportMailingJobConfigurationData + (ReportMailingJobConstants.GMAIL_SMTP_PASSWORD); + + return (reportMailingJobConfigurationData != null) ? reportMailingJobConfigurationData.getValue() : null; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobReadPlatformService.java new file mode 100644 index 000000000..3ac274d4a --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobReadPlatformService.java @@ -0,0 +1,47 @@ +/** + * 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.reportmailingjob.service; + +import java.util.Collection; + +import org.apache.fineract.infrastructure.core.service.Page; +import org.apache.fineract.infrastructure.core.service.SearchParameters; +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobData; + +public interface ReportMailingJobReadPlatformService { + /** + * Retrieve all report mailing jobs that have the isDeleted property set to 0 + **/ + Page retrieveAllReportMailingJobs(SearchParameters searchParameters); + + /** + * Retrieve a report mailing job that has the isDeleted property set to 0 + **/ + ReportMailingJobData retrieveReportMailingJob(Long reportMailingJobId); + + /** + * Retrieve the report mailing job enumeration/dropdown options + **/ + ReportMailingJobData retrieveReportMailingJobEnumOptions(); + + /** + * Retrieve all active report mailing jobs that have their isDeleted property set to 0 + **/ + Collection retrieveAllActiveReportMailingJobs(); +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobReadPlatformServiceImpl.java new file mode 100644 index 000000000..afec18008 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobReadPlatformServiceImpl.java @@ -0,0 +1,203 @@ +/** + * 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.reportmailingjob.service; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.apache.fineract.infrastructure.core.data.EnumOptionData; +import org.apache.fineract.infrastructure.core.domain.JdbcSupport; +import org.apache.fineract.infrastructure.core.service.Page; +import org.apache.fineract.infrastructure.core.service.PaginationHelper; +import org.apache.fineract.infrastructure.core.service.RoutingDataSource; +import org.apache.fineract.infrastructure.core.service.SearchParameters; +import org.apache.fineract.infrastructure.dataqueries.data.ReportData; +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobData; +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobEmailAttachmentFileFormat; +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobStretchyReportParamDateOption; +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobTimelineData; +import org.apache.fineract.infrastructure.reportmailingjob.exception.ReportMailingJobNotFoundException; +import org.joda.time.DateTime; +import org.joda.time.LocalDate; +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; + +@Service +public class ReportMailingJobReadPlatformServiceImpl implements ReportMailingJobReadPlatformService { + private final JdbcTemplate jdbcTemplate; + + @Autowired + public ReportMailingJobReadPlatformServiceImpl(final RoutingDataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + @Override + public Page retrieveAllReportMailingJobs(final SearchParameters searchParameters) { + final StringBuilder sqlStringBuilder = new StringBuilder(200); + final List queryParameters = new ArrayList<>(); + final ReportMailingJobMapper mapper = new ReportMailingJobMapper(); + final PaginationHelper paginationHelper = new PaginationHelper<>(); + + sqlStringBuilder.append("select SQL_CALC_FOUND_ROWS "); + sqlStringBuilder.append(mapper.ReportMailingJobSchema()); + sqlStringBuilder.append(" where rmj.is_deleted = 0"); + + if (searchParameters.isOrderByRequested()) { + sqlStringBuilder.append(" order by ").append(searchParameters.getOrderBy()); + + if (searchParameters.isSortOrderProvided()) { + sqlStringBuilder.append(" ").append(searchParameters.getSortOrder()); + } + } else { + sqlStringBuilder.append(" order by rmj.name "); + } + + if (searchParameters.isLimited()) { + sqlStringBuilder.append(" limit ").append(searchParameters.getLimit()); + + if (searchParameters.isOffset()) { + sqlStringBuilder.append(" offset ").append(searchParameters.getOffset()); + } + } + + return paginationHelper.fetchPage(this.jdbcTemplate, "SELECT FOUND_ROWS()", sqlStringBuilder.toString(), + queryParameters.toArray(), mapper); + } + + @Override + public Collection retrieveAllActiveReportMailingJobs() { + final ReportMailingJobMapper mapper = new ReportMailingJobMapper(); + final String sql = "select " + mapper.ReportMailingJobSchema() + " where rmj.is_deleted = 0 and is_active = 1" + + " order by rmj.name"; + + return this.jdbcTemplate.query(sql, mapper, new Object[] {}); + } + + @Override + public ReportMailingJobData retrieveReportMailingJob(final Long reportMailingJobId) { + try { + final ReportMailingJobMapper mapper = new ReportMailingJobMapper(); + final String sql = "select " + mapper.ReportMailingJobSchema() + " where rmj.id = ? and rmj.is_deleted = 0"; + + return this.jdbcTemplate.queryForObject(sql, mapper, new Object[] { reportMailingJobId }); + } + + catch (final EmptyResultDataAccessException ex) { + throw new ReportMailingJobNotFoundException(reportMailingJobId); + } + } + + @Override + public ReportMailingJobData retrieveReportMailingJobEnumOptions() { + final List emailAttachmentFileFormatOptions = ReportMailingJobEmailAttachmentFileFormat.validOptions(); + final List stretchyReportParamDateOptions = ReportMailingJobStretchyReportParamDateOption.validOptions(); + + return ReportMailingJobData.newInstance(emailAttachmentFileFormatOptions, stretchyReportParamDateOptions); + } + + private static final class ReportMailingJobMapper implements RowMapper { + public String ReportMailingJobSchema() { + return "rmj.id, rmj.name, rmj.description, rmj.start_datetime as startDateTime, rmj.recurrence, rmj.created_date as createdOnDate, " + + "cbu.username as createdByUsername, cbu.firstname as createdByFirstname, cbu.lastname as createdByLastname, " + + "rmj.lastmodified_date as updatedOnDate, " + + "mbu.username as updatedByUsername, mbu.firstname as updatedByFirstname, mbu.lastname as updatedByLastname, " + + "rmj.email_recipients as emailRecipients, " + + "rmj.email_subject as emailSubject, rmj.email_message as emailMessage, " + + "rmj.email_attachment_file_format as emailAttachmentFileFormat, " + + "rmj.stretchy_report_param_map as stretchyReportParamMap, rmj.previous_run_datetime as previousRunDateTime, " + + "rmj.next_run_datetime as nextRunDateTime, rmj.previous_run_status as previousRunStatus, " + + "rmj.previous_run_error_log as previousRunErrorLog, rmj.previous_run_error_message as previousRunErrorMessage, " + + "rmj.number_of_runs as numberOfRuns, rmj.is_active as isActive, rmj.run_as_userid as runAsUserId, " + + "sr.id as reportId, sr.report_name as reportName, sr.report_type as reportType, sr.report_subtype as reportSubType, " + + "sr.report_category as reportCategory, sr.report_sql as reportSql, sr.description as reportDescription, " + + "sr.core_report as coreReport, sr.use_report as useReport " + + "from m_report_mailing_job rmj " + + "inner join m_appuser cbu " + + "on cbu.id = rmj.createdby_id " + + "left join m_appuser mbu " + + "on mbu.id = rmj.lastmodifiedby_id " + + "left join stretchy_report sr " + + "on rmj.stretchy_report_id = sr.id"; + } + + @Override + public ReportMailingJobData mapRow(ResultSet rs, int rowNum) throws SQLException { + final Long id = rs.getLong("id"); + final String name = rs.getString("name"); + final String description = rs.getString("description"); + final DateTime startDateTime = JdbcSupport.getDateTime(rs, "startDateTime"); + final String recurrence = rs.getString("recurrence"); + final LocalDate createdOnDate = JdbcSupport.getLocalDate(rs, "createdOnDate"); + final LocalDate updatedOnDate = JdbcSupport.getLocalDate(rs, "updatedOnDate"); + final String emailRecipients = rs.getString("emailRecipients"); + final String emailSubject = rs.getString("emailSubject"); + final String emailMessage = rs.getString("emailMessage"); + final String emailAttachmentFileFormatString = rs.getString("emailAttachmentFileFormat"); + EnumOptionData emailAttachmentFileFormat = null; + + if (emailAttachmentFileFormatString != null) { + ReportMailingJobEmailAttachmentFileFormat format = ReportMailingJobEmailAttachmentFileFormat.newInstance(emailAttachmentFileFormatString); + + emailAttachmentFileFormat = format.toEnumOptionData(); + } + + final String stretchyReportParamMap = rs.getString("stretchyReportParamMap"); + final DateTime previousRunDateTime = JdbcSupport.getDateTime(rs, "previousRunDateTime"); + final DateTime nextRunDateTime = JdbcSupport.getDateTime(rs, "nextRunDateTime"); + final String previousRunStatus = rs.getString("previousRunStatus"); + final String previousRunErrorLog = rs.getString("previousRunErrorLog"); + final String previousRunErrorMessage = rs.getString("previousRunErrorMessage"); + final Integer numberOfRuns = JdbcSupport.getInteger(rs, "numberOfRuns"); + final boolean isActive = rs.getBoolean("isActive"); + final String createdByUsername = rs.getString("createdByUsername"); + final String createdByFirstname = rs.getString("createdByFirstname"); + final String createdByLastname = rs.getString("createdByLastname"); + final String updatedByUsername = rs.getString("updatedByUsername"); + final String updatedByFirstname = rs.getString("updatedByFirstname"); + final String updatedByLastname = rs.getString("updatedByLastname"); + final ReportMailingJobTimelineData timeline = new ReportMailingJobTimelineData(createdOnDate, createdByUsername, + createdByFirstname, createdByLastname, updatedOnDate, updatedByUsername, updatedByFirstname, updatedByLastname); + final Long runAsUserId = JdbcSupport.getLong(rs, "runAsUserId"); + + final Long reportId = JdbcSupport.getLong(rs, "reportId"); + final String reportName = rs.getString("reportName"); + final String reportType = rs.getString("reportType"); + final String reportSubType = rs.getString("reportSubType"); + final String reportCategory = rs.getString("reportCategory"); + final String reportSql = rs.getString("reportSql"); + final String reportDescription = rs.getString("reportDescription"); + final boolean coreReport = rs.getBoolean("coreReport"); + final boolean useReport = rs.getBoolean("useReport"); + + final ReportData stretchyReport = new ReportData(reportId, reportName, reportType, reportSubType, reportCategory, + reportDescription, reportSql, coreReport, useReport, null); + + return ReportMailingJobData.newInstance(id, name, description, startDateTime, recurrence, timeline, emailRecipients, + emailSubject, emailMessage, emailAttachmentFileFormat, stretchyReport, stretchyReportParamMap, previousRunDateTime, + nextRunDateTime, previousRunStatus, previousRunErrorLog, previousRunErrorMessage, numberOfRuns, isActive, + runAsUserId); + } + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobRunHistoryReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobRunHistoryReadPlatformService.java new file mode 100644 index 000000000..9f4a20412 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobRunHistoryReadPlatformService.java @@ -0,0 +1,34 @@ +/** + * 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.reportmailingjob.service; + +import org.apache.fineract.infrastructure.core.service.Page; +import org.apache.fineract.infrastructure.core.service.SearchParameters; +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobRunHistoryData; + +public interface ReportMailingJobRunHistoryReadPlatformService { + /** + * Retrieve all report mailing run history with similar job id to the one passed + * + * @param reportMailingJobId ReportMailingJob identifier + * @param searchParameters {@link SearchParameters} object + * @return collection of {@link ReportMailingJobRunHistoryData} objects + **/ + Page retrieveRunHistoryByJobId(Long reportMailingJobId, SearchParameters searchParameters); +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobRunHistoryReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobRunHistoryReadPlatformServiceImpl.java new file mode 100644 index 000000000..4aeb68f1f --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobRunHistoryReadPlatformServiceImpl.java @@ -0,0 +1,106 @@ +/** + * 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.reportmailingjob.service; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.fineract.infrastructure.core.domain.JdbcSupport; +import org.apache.fineract.infrastructure.core.service.Page; +import org.apache.fineract.infrastructure.core.service.PaginationHelper; +import org.apache.fineract.infrastructure.core.service.RoutingDataSource; +import org.apache.fineract.infrastructure.core.service.SearchParameters; +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobRunHistoryData; +import org.joda.time.DateTime; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Service; + +@Service +public class ReportMailingJobRunHistoryReadPlatformServiceImpl implements ReportMailingJobRunHistoryReadPlatformService { + private final JdbcTemplate jdbcTemplate; + private final ReportMailingJobRunHistoryMapper reportMailingJobRunHistoryMapper; + private final PaginationHelper paginationHelper = new PaginationHelper<>(); + + @Autowired + public ReportMailingJobRunHistoryReadPlatformServiceImpl(final RoutingDataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + this.reportMailingJobRunHistoryMapper = new ReportMailingJobRunHistoryMapper(); + } + + @Override + public Page retrieveRunHistoryByJobId(final Long reportMailingJobId, + final SearchParameters searchParameters) { + final StringBuilder sqlStringBuilder = new StringBuilder(200); + final List queryParameters = new ArrayList<>(); + + sqlStringBuilder.append("select SQL_CALC_FOUND_ROWS "); + sqlStringBuilder.append(this.reportMailingJobRunHistoryMapper.ReportMailingJobRunHistorySchema()); + + if (reportMailingJobId != null) { + sqlStringBuilder.append(" where rmjrh.job_id = ? "); + queryParameters.add(reportMailingJobId); + } + + if (searchParameters.isOrderByRequested()) { + sqlStringBuilder.append(" order by ").append(searchParameters.getOrderBy()); + + if (searchParameters.isSortOrderProvided()) { + sqlStringBuilder.append(" ").append(searchParameters.getSortOrder()); + } + } + + if (searchParameters.isLimited()) { + sqlStringBuilder.append(" limit ").append(searchParameters.getLimit()); + + if (searchParameters.isOffset()) { + sqlStringBuilder.append(" offset ").append(searchParameters.getOffset()); + } + } + + return this.paginationHelper.fetchPage(this.jdbcTemplate, "SELECT FOUND_ROWS()", sqlStringBuilder.toString(), + queryParameters.toArray(), this.reportMailingJobRunHistoryMapper); + } + + private static final class ReportMailingJobRunHistoryMapper implements RowMapper { + public String ReportMailingJobRunHistorySchema() { + return "rmjrh.id, rmjrh.job_id as reportMailingJobId, rmjrh.start_datetime as startDateTime, " + + "rmjrh.end_datetime as endDateTime, rmjrh.status, rmjrh.error_message as errorMessage, " + + "rmjrh.error_log as errorLog " + + "from m_report_mailing_job_run_history rmjrh"; + } + + @Override + public ReportMailingJobRunHistoryData mapRow(ResultSet rs, int rowNum) throws SQLException { + final Long id = JdbcSupport.getLong(rs, "id"); + final Long reportMailingJobId = JdbcSupport.getLong(rs, "reportMailingJobId"); + final DateTime startDateTime = JdbcSupport.getDateTime(rs, "startDateTime"); + final DateTime endDateTime = JdbcSupport.getDateTime(rs, "endDateTime"); + final String status = rs.getString("status"); + final String errorMessage = rs.getString("errorMessage"); + final String errorLog = rs.getString("errorLog"); + + return ReportMailingJobRunHistoryData.newInstance(id, reportMailingJobId, startDateTime, endDateTime, status, + errorMessage, errorLog); + } + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobWritePlatformService.java new file mode 100644 index 000000000..ce549191c --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobWritePlatformService.java @@ -0,0 +1,30 @@ +/** + * 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.reportmailingjob.service; + +import org.apache.fineract.infrastructure.core.api.JsonCommand; +import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException; + +public interface ReportMailingJobWritePlatformService { + CommandProcessingResult createReportMailingJob(JsonCommand jsonCommand); + CommandProcessingResult updateReportMailingJob(Long reportMailingJobId, JsonCommand jsonCommand); + CommandProcessingResult deleteReportMailingJob(Long reportMailingJobId); + void executeReportMailingJobs() throws JobExecutionException; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobWritePlatformServiceImpl.java new file mode 100644 index 000000000..02972a927 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobWritePlatformServiceImpl.java @@ -0,0 +1,495 @@ +/** + * 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.reportmailingjob.service; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; + +import org.apache.commons.lang.StringUtils; +import org.apache.fineract.infrastructure.core.api.JsonCommand; +import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; +import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; +import org.apache.fineract.infrastructure.core.service.DateUtils; +import org.apache.fineract.infrastructure.dataqueries.domain.Report; +import org.apache.fineract.infrastructure.dataqueries.domain.ReportRepositoryWrapper; +import org.apache.fineract.infrastructure.dataqueries.service.ReadReportingService; +import org.apache.fineract.infrastructure.documentmanagement.contentrepository.FileSystemContentRepository; +import org.apache.fineract.infrastructure.jobs.annotation.CronTarget; +import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException; +import org.apache.fineract.infrastructure.jobs.service.JobName; +import org.apache.fineract.infrastructure.report.provider.ReportingProcessServiceProvider; +import org.apache.fineract.infrastructure.report.service.ReportingProcessService; +import org.apache.fineract.infrastructure.reportmailingjob.ReportMailingJobConstants; +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobEmailAttachmentFileFormat; +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobEmailData; +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobPreviousRunStatus; +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobStretchyReportParamDateOption; +import org.apache.fineract.infrastructure.reportmailingjob.domain.ReportMailingJob; +import org.apache.fineract.infrastructure.reportmailingjob.domain.ReportMailingJobRepository; +import org.apache.fineract.infrastructure.reportmailingjob.domain.ReportMailingJobRepositoryWrapper; +import org.apache.fineract.infrastructure.reportmailingjob.domain.ReportMailingJobRunHistory; +import org.apache.fineract.infrastructure.reportmailingjob.domain.ReportMailingJobRunHistoryRepository; +import org.apache.fineract.infrastructure.reportmailingjob.util.ReportMailingJobDateUtil; +import org.apache.fineract.infrastructure.reportmailingjob.validation.ReportMailingJobValidator; +import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import org.apache.fineract.portfolio.calendar.service.CalendarUtils; +import org.apache.fineract.useradministration.domain.AppUser; +import org.joda.time.DateTime; +import org.joda.time.LocalDate; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.sun.jersey.core.util.MultivaluedMapImpl; + +@Service +public class ReportMailingJobWritePlatformServiceImpl implements ReportMailingJobWritePlatformService { + + private final static Logger logger = LoggerFactory.getLogger(ReportMailingJobWritePlatformServiceImpl.class); + private final ReportRepositoryWrapper reportRepositoryWrapper; + private final ReportMailingJobValidator reportMailingJobValidator; + private final ReportMailingJobRepositoryWrapper reportMailingJobRepositoryWrapper; + private final ReportMailingJobRepository reportMailingJobRepository; + private final PlatformSecurityContext platformSecurityContext; + private final ReportMailingJobEmailService reportMailingJobEmailService; + private final ReadReportingService readReportingService; + private final ReportingProcessServiceProvider reportingProcessServiceProvider; + private final ReportMailingJobRunHistoryRepository reportMailingJobRunHistoryRepository; + private final static String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; + + @Autowired + public ReportMailingJobWritePlatformServiceImpl(final ReportRepositoryWrapper reportRepositoryWrapper, + final ReportMailingJobValidator reportMailingJobValidator, + final ReportMailingJobRepositoryWrapper reportMailingJobRepositoryWrapper, + final ReportMailingJobRepository reportMailingJobRepository, + final PlatformSecurityContext platformSecurityContext, + final ReportMailingJobEmailService reportMailingJobEmailService, + final ReadReportingService readReportingService, + final ReportMailingJobRunHistoryRepository reportMailingJobRunHistoryRepository, + final ReportingProcessServiceProvider reportingProcessServiceProvider) { + this.reportRepositoryWrapper = reportRepositoryWrapper; + this.reportMailingJobValidator = reportMailingJobValidator; + this.reportMailingJobRepositoryWrapper = reportMailingJobRepositoryWrapper; + this.reportMailingJobRepository = reportMailingJobRepositoryWrapper.getReportMailingJobRepository(); + this.platformSecurityContext = platformSecurityContext; + this.reportMailingJobEmailService = reportMailingJobEmailService; + this.readReportingService = readReportingService; + this.reportMailingJobRunHistoryRepository = reportMailingJobRunHistoryRepository; + this.reportingProcessServiceProvider = reportingProcessServiceProvider; + } + + @Override + @Transactional + public CommandProcessingResult createReportMailingJob(JsonCommand jsonCommand) { + try { + // validate the create request + this.reportMailingJobValidator.validateCreateRequest(jsonCommand); + + final AppUser appUser = this.platformSecurityContext.authenticatedUser(); + + // get the stretchy Report object + final Report stretchyReport = this.reportRepositoryWrapper.findOneThrowExceptionIfNotFound(jsonCommand.longValueOfParameterNamed( + ReportMailingJobConstants.STRETCHY_REPORT_ID_PARAM_NAME)); + + // create an instance of ReportMailingJob class from the JsonCommand object + final ReportMailingJob reportMailingJob = ReportMailingJob.newInstance(jsonCommand, stretchyReport, appUser); + + // save entity + this.reportMailingJobRepository.save(reportMailingJob); + + return new CommandProcessingResultBuilder().withCommandId(jsonCommand.commandId()). + withEntityId(reportMailingJob.getId()).build(); + } catch (final DataIntegrityViolationException dve) { + handleDataIntegrityIssues(jsonCommand, dve); + + return CommandProcessingResult.empty(); + } + } + + @Override + @Transactional + public CommandProcessingResult updateReportMailingJob(Long reportMailingJobId, JsonCommand jsonCommand) { + try { + // validate the update request + this.reportMailingJobValidator.validateUpdateRequest(jsonCommand); + + // retrieve the ReportMailingJob object from the database + final ReportMailingJob reportMailingJob = this.reportMailingJobRepositoryWrapper.findOneThrowExceptionIfNotFound(reportMailingJobId); + + final Map changes = reportMailingJob.update(jsonCommand); + + // get the recurrence rule string + final String recurrence = reportMailingJob.getRecurrence(); + + // get the next run DateTime from the ReportMailingJob entity + DateTime nextRunDateTime = reportMailingJob.getNextRunDateTime(); + + // check if the stretchy report id was updated + if (changes.containsKey(ReportMailingJobConstants.STRETCHY_REPORT_ID_PARAM_NAME)) { + final Long stretchyReportId = (Long) changes.get(ReportMailingJobConstants.STRETCHY_REPORT_ID_PARAM_NAME); + final Report stretchyReport = this.reportRepositoryWrapper.findOneThrowExceptionIfNotFound(stretchyReportId); + + // update the stretchy report + reportMailingJob.update(stretchyReport); + } + + // check if the recurrence was updated + if (changes.containsKey(ReportMailingJobConstants.RECURRENCE_PARAM_NAME)) { + + // go ahead if the recurrence is not null + if (StringUtils.isNotBlank(recurrence)) { + // set the start DateTime to the current tenant date time + DateTime startDateTime = DateUtils.getLocalDateTimeOfTenant().toDateTime(); + + // check if the start DateTime was updated + if (changes.containsKey(ReportMailingJobConstants.START_DATE_TIME_PARAM_NAME)) { + // get the updated start DateTime + startDateTime = reportMailingJob.getStartDateTime(); + } + + startDateTime = reportMailingJob.getStartDateTime(); + + // get the next recurring DateTime + final DateTime nextRecurringDateTime = this.createNextRecurringDateTime(recurrence, startDateTime); + + // update the next run time property + reportMailingJob.updateNextRunDateTime(nextRecurringDateTime); + + // check if the next run DateTime is not empty and the recurrence is empty + } else if (StringUtils.isBlank(recurrence) && (nextRunDateTime != null)) { + // the next run DateTime should be set to null + reportMailingJob.updateNextRunDateTime(null); + } + } + + if (changes.containsKey(ReportMailingJobConstants.START_DATE_TIME_PARAM_NAME)) { + final DateTime startDateTime = reportMailingJob.getStartDateTime(); + + // initially set the next recurring date time to the new start date time + DateTime nextRecurringDateTime = startDateTime; + + // ensure that the recurrence pattern string is not empty + if (StringUtils.isNotBlank(recurrence)) { + // get the next recurring DateTime + nextRecurringDateTime = this.createNextRecurringDateTime(recurrence, startDateTime); + } + + // update the next run time property + reportMailingJob.updateNextRunDateTime(nextRecurringDateTime); + } + + if (!changes.isEmpty()) { + // save and flush immediately so any data integrity exception can be handled in the "catch" block + this.reportMailingJobRepository.saveAndFlush(reportMailingJob); + } + + return new CommandProcessingResultBuilder(). + withCommandId(jsonCommand.commandId()). + withEntityId(reportMailingJob.getId()). + with(changes). + build(); + } catch (final DataIntegrityViolationException dve) { + handleDataIntegrityIssues(jsonCommand, dve); + + return CommandProcessingResult.empty(); + } + } + + @Override + @Transactional + public CommandProcessingResult deleteReportMailingJob(Long reportMailingJobId) { + // retrieve the ReportMailingJob object from the database + final ReportMailingJob reportMailingJob = this.reportMailingJobRepositoryWrapper.findOneThrowExceptionIfNotFound(reportMailingJobId); + + // delete the report mailing job by setting the isDeleted property to 1 and altering the name + reportMailingJob.delete(); + + // save the report mailing job entity + this.reportMailingJobRepository.save(reportMailingJob); + + return new CommandProcessingResultBuilder().withEntityId(reportMailingJobId).build(); + } + + @Override + @CronTarget(jobName = JobName.EXECUTE_REPORT_MAILING_JOBS) + public void executeReportMailingJobs() throws JobExecutionException { + final Collection reportMailingJobCollection = this.reportMailingJobRepository.findByIsActiveTrueAndIsDeletedFalse(); + + for (ReportMailingJob reportMailingJob : reportMailingJobCollection) { + // get the tenant's date as a DateTime object + final DateTime localDateTimeOftenant = DateUtils.getLocalDateTimeOfTenant().toDateTime(); + final DateTime nextRunDateTime = reportMailingJob.getNextRunDateTime(); + + if (nextRunDateTime != null && nextRunDateTime.isBefore(localDateTimeOftenant)) { + // get the emailAttachmentFileFormat enum object + final ReportMailingJobEmailAttachmentFileFormat emailAttachmentFileFormat = ReportMailingJobEmailAttachmentFileFormat. + newInstance(reportMailingJob.getEmailAttachmentFileFormat()); + + if (emailAttachmentFileFormat != null && emailAttachmentFileFormat.isValid()) { + final Report stretchyReport = reportMailingJob.getStretchyReport(); + final String reportName = (stretchyReport != null) ? stretchyReport.getReportName() : null; + final StringBuilder errorLog = new StringBuilder(); + final Map validateStretchyReportParamMap = this.reportMailingJobValidator. + validateStretchyReportParamMap(reportMailingJob.getStretchyReportParamMap()); + MultivaluedMap reportParams = new MultivaluedMapImpl(); + + if (validateStretchyReportParamMap != null) { + Iterator> validateStretchyReportParamMapEntries = validateStretchyReportParamMap.entrySet().iterator(); + + while (validateStretchyReportParamMapEntries.hasNext()) { + Map.Entry validateStretchyReportParamMapEntry = validateStretchyReportParamMapEntries.next(); + String key = validateStretchyReportParamMapEntry.getKey(); + String value = validateStretchyReportParamMapEntry.getValue(); + + if (StringUtils.containsIgnoreCase(key, "date")) { + ReportMailingJobStretchyReportParamDateOption reportMailingJobStretchyReportParamDateOption = + ReportMailingJobStretchyReportParamDateOption.newInstance(value); + + if (reportMailingJobStretchyReportParamDateOption.isValid()) { + value = ReportMailingJobDateUtil.getDateAsString(reportMailingJobStretchyReportParamDateOption); + } + } + + reportParams.add(key, value); + } + } + + // generate the report output stream, method in turn call another that sends the file to the email recipients + this.generateReportOutputStream(reportMailingJob, emailAttachmentFileFormat, reportParams, reportName, errorLog); + + // update the previous run time, next run time, status, error log properties + this.updateReportMailingJobAfterJobExecution(reportMailingJob, errorLog, localDateTimeOftenant); + } + } + } + } + + /** + * update the report mailing job entity after job execution + * + * @param reportMailingJob -- the report mailing job entity + * @param errorLog -- StringBuilder object containing the error log if any + * @param jobStartDateTime -- the start DateTime of the job + * @return None + **/ + private void updateReportMailingJobAfterJobExecution(final ReportMailingJob reportMailingJob, final StringBuilder errorLog, + final DateTime jobStartDateTime) { + final String recurrence = reportMailingJob.getRecurrence(); + final DateTime nextRunDateTime = reportMailingJob.getNextRunDateTime(); + ReportMailingJobPreviousRunStatus reportMailingJobPreviousRunStatus = ReportMailingJobPreviousRunStatus.SUCCESS; + + reportMailingJob.updatePreviousRunErrorLog(null); + + if (errorLog != null && errorLog.length() > 0) { + reportMailingJobPreviousRunStatus = ReportMailingJobPreviousRunStatus.ERROR; + reportMailingJob.updatePreviousRunErrorLog(errorLog.toString()); + } + + reportMailingJob.increaseNumberOfRunsByOne(); + reportMailingJob.updatePreviousRunStatus(reportMailingJobPreviousRunStatus.getValue()); + reportMailingJob.updatePreviousRunDateTime(reportMailingJob.getNextRunDateTime()); + + // check if the job has a recurrence pattern, if not deactivate the job. The job will only run once + if (StringUtils.isEmpty(recurrence)) { + // deactivate job + reportMailingJob.deactivate(); + + // job will only run once, no next run time + reportMailingJob.updateNextRunDateTime(null); + } else if (nextRunDateTime != null) { + final DateTime nextRecurringDateTime = this.createNextRecurringDateTime(recurrence, nextRunDateTime); + + // finally update the next run date time property + reportMailingJob.updateNextRunDateTime(nextRecurringDateTime); + } + + // save the ReportMailingJob entity + this.reportMailingJobRepository.save(reportMailingJob); + + // create a new report mailing job run history entity + this.createReportMailingJobRunHistroryAfterJobExecution(reportMailingJob, errorLog, jobStartDateTime, + reportMailingJobPreviousRunStatus.getValue()); + } + + /** + * create the next recurring DateTime from recurrence pattern, start DateTime and current DateTime + * + * @param recurrencePattern + * @param startDateTime + * @return DateTime object + */ + private DateTime createNextRecurringDateTime(final String recurrencePattern, final DateTime startDateTime) { + DateTime nextRecurringDateTime = null; + + // the recurrence pattern/rule cannot be empty + if (StringUtils.isNotBlank(recurrencePattern) && startDateTime != null) { + final LocalDate nextDayLocalDate = startDateTime.plus(1).toLocalDate(); + final LocalDate nextRecurringLocalDate = CalendarUtils.getNextRecurringDate(recurrencePattern, startDateTime.toLocalDate(), + nextDayLocalDate); + final String nextDateTimeString = nextRecurringLocalDate + " " + startDateTime.getHourOfDay() + ":" + startDateTime.getMinuteOfHour() + + ":" + startDateTime.getSecondOfMinute(); + final DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(DATETIME_FORMAT); + + nextRecurringDateTime = DateTime.parse(nextDateTimeString, dateTimeFormatter); + } + + return nextRecurringDateTime; + } + + /** + * create a new report mailing job run history entity after job execution + * + * @param reportMailingJob -- the report mailing job entity + * @param errorLog -- StringBuilder object containing the error log if any + * @param jobStartDateTime -- the start DateTime of the job + * @param jobRunStatus -- the status of the job (success/error) + * @return None + **/ + private void createReportMailingJobRunHistroryAfterJobExecution(final ReportMailingJob reportMailingJob, final StringBuilder errorLog, + final DateTime jobStartDateTime, final String jobRunStatus) { + final DateTime jobEndDateTime = DateUtils.getLocalDateTimeOfTenant().toDateTime(); + final String errorLogToString = (errorLog != null) ? errorLog.toString() : null; + final ReportMailingJobRunHistory reportMailingJobRunHistory = ReportMailingJobRunHistory.newInstance(reportMailingJob, jobStartDateTime, + jobEndDateTime, jobRunStatus, null, errorLogToString); + + this.reportMailingJobRunHistoryRepository.save(reportMailingJobRunHistory); + } + + /** + * Handle any SQL data integrity issue + * + * @param jsonCommand -- JsonCommand object + * @param dve -- data integrity exception object + * @return None + **/ + private void handleDataIntegrityIssues(final JsonCommand jsonCommand, final DataIntegrityViolationException dve) { + final Throwable realCause = dve.getMostSpecificCause(); + + if (realCause.getMessage().contains(ReportMailingJobConstants.NAME_PARAM_NAME)) { + final String name = jsonCommand.stringValueOfParameterNamed(ReportMailingJobConstants.NAME_PARAM_NAME); + throw new PlatformDataIntegrityException("error.msg.report.mailing.job.duplicate.name", "Report mailing job with name `" + name + "` already exists", + ReportMailingJobConstants.NAME_PARAM_NAME, name); + } + + logger.error(dve.getMessage(), dve); + + throw new PlatformDataIntegrityException("error.msg.charge.unknown.data.integrity.issue", + "Unknown data integrity issue with resource: " + realCause.getMessage()); + } + + /** + * generate the report output stream + * + * @param reportMailingJob + * @param emailAttachmentFileFormat + * @param reportParams + * @param reportName + * @param errorLog + * @return the error log StringBuilder object + */ + private StringBuilder generateReportOutputStream(final ReportMailingJob reportMailingJob, final ReportMailingJobEmailAttachmentFileFormat emailAttachmentFileFormat, + final MultivaluedMap reportParams, final String reportName, final StringBuilder errorLog) { + + try { + final String reportType = this.readReportingService.getReportType(reportName); + final ReportingProcessService reportingProcessService = this.reportingProcessServiceProvider.findReportingProcessService(reportType); + + if (reportingProcessService != null) { + final Response processReport = reportingProcessService.processRequest(reportName, reportParams); + final Object reponseObject = (processReport != null) ? processReport.getEntity() : null; + + if (reponseObject != null && reponseObject.getClass().equals(ByteArrayOutputStream.class)) { + final ByteArrayOutputStream byteArrayOutputStream = ByteArrayOutputStream.class.cast(reponseObject); + final String fileLocation = FileSystemContentRepository.FINERACT_BASE_DIR + File.separator + ""; + final String fileNameWithoutExtension = fileLocation + File.separator + reportName; + + // check if file directory exists, if not create directory + if (!new File(fileLocation).isDirectory()) { + new File(fileLocation).mkdirs(); + } + + if ((byteArrayOutputStream == null) || byteArrayOutputStream.size() == 0) { + errorLog.append("Report processing failed, empty output stream created"); + } else if ((errorLog != null && errorLog.length() == 0) && (byteArrayOutputStream.size() > 0)) { + final String fileName = fileNameWithoutExtension + "." + emailAttachmentFileFormat.getValue(); + + // send the file to email recipients + this.sendReportFileToEmailRecipients(reportMailingJob, fileName, byteArrayOutputStream, errorLog); + } + } else { + errorLog.append("Response object entity is not equal to ByteArrayOutputStream ---------- "); + } + } else { + errorLog.append("ReportingProcessService object is null ---------- "); + } + } catch (Exception e) { + errorLog.append("The ReportMailingJobWritePlatformServiceImpl.generateReportOutputStream method threw an Exception: " + + e + " ---------- "); + } + + return errorLog; + } + + /** + * send report file to email recipients + * + * @param reportMailingJob + * @param fileName + * @param byteArrayOutputStream + * @param errorLog + */ + private void sendReportFileToEmailRecipients(final ReportMailingJob reportMailingJob, final String fileName, + final ByteArrayOutputStream byteArrayOutputStream, final StringBuilder errorLog) { + final Set emailRecipients = this.reportMailingJobValidator.validateEmailRecipients(reportMailingJob.getEmailRecipients()); + + try { + final File file = new File(fileName); + final FileOutputStream outputStream = new FileOutputStream(file); + byteArrayOutputStream.writeTo(outputStream); + + for (String emailRecipient : emailRecipients) { + final ReportMailingJobEmailData reportMailingJobEmailData = new ReportMailingJobEmailData(emailRecipient, + reportMailingJob.getEmailMessage(), reportMailingJob.getEmailSubject(), file); + + this.reportMailingJobEmailService.sendEmailWithAttachment(reportMailingJobEmailData); + } + + outputStream.close(); + + } catch (IOException e) { + errorLog.append("The ReportMailingJobWritePlatformServiceImpl.sendReportFileToEmailRecipients method threw an IOException " + + "exception: " + e + " ---------- "); + } + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/util/ReportMailingJobDateUtil.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/util/ReportMailingJobDateUtil.java new file mode 100644 index 000000000..a1d97fa92 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/util/ReportMailingJobDateUtil.java @@ -0,0 +1,114 @@ +/** + * 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.reportmailingjob.util; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobStretchyReportParamDateOption; + +public class ReportMailingJobDateUtil { + public static final String MYSQL_DATE_FORMAT = "yyyy-MM-dd"; + + /** + * get the current date as string using the mysql date format yyyy-MM-dd + **/ + public static String getTodayDateAsString() { + // get a calendar instance, which defaults to "now" + Calendar calendar = Calendar.getInstance(); + + // get a date to represent "today" + Date today = calendar.getTime(); + + // get a SimpleDateFormat instance, passing the mysql date format as parameter + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(MYSQL_DATE_FORMAT); + + // return date as string + return simpleDateFormat.format(today); + } + + /** + * get the yesterday's date as string using the mysql date format yyyy-MM-dd + **/ + public static String getYesterdayDateAsString() { + // get a calendar instance, which defaults to "now" + Calendar calendar = Calendar.getInstance(); + + // add one day to the date/calendar + calendar.add(Calendar.DAY_OF_YEAR, -1); + + // now get "yesterday" + Date yesterday = calendar.getTime(); + + // get a SimpleDateFormat instance, passing the mysql date format as parameter + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(MYSQL_DATE_FORMAT); + + // return date as string + return simpleDateFormat.format(yesterday); + } + + /** + * get the tomorrow's date as string using the mysql date format yyyy-MM-dd + **/ + public static String getTomorrowDateAsString() { + // get a calendar instance, which defaults to "now" + Calendar calendar = Calendar.getInstance(); + + // add one day to the date/calendar + calendar.add(Calendar.DAY_OF_YEAR, 1); + + // now get "tomorrow" + Date tomorrow = calendar.getTime(); + + // get a SimpleDateFormat instance, passing the mysql date format as parameter + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(MYSQL_DATE_FORMAT); + + // return date as string + return simpleDateFormat.format(tomorrow); + } + + /** + * get date as string based on the value of the {@link ReportMailingJobStretchyReportParamDateOption} object + * + * @param reportMailingJobStretchyReportParamDateOption {@link ReportMailingJobStretchyReportParamDateOption} Enum + **/ + public static String getDateAsString(final ReportMailingJobStretchyReportParamDateOption reportMailingJobStretchyReportParamDateOption) { + String dateAsString = null; + + switch (reportMailingJobStretchyReportParamDateOption) { + case TODAY: + dateAsString = getTodayDateAsString(); + break; + + case YESTERDAY: + dateAsString = getYesterdayDateAsString(); + break; + + case TOMORROW: + dateAsString = getTomorrowDateAsString(); + break; + + default: + break; + } + + return dateAsString; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/validation/ReportMailingJobValidator.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/validation/ReportMailingJobValidator.java new file mode 100644 index 000000000..c3bbaf851 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/validation/ReportMailingJobValidator.java @@ -0,0 +1,319 @@ +/** + * 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.reportmailingjob.validation; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang.StringUtils; +import org.apache.fineract.infrastructure.core.api.JsonCommand; +import org.apache.fineract.infrastructure.core.data.ApiParameterError; +import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; +import org.apache.fineract.infrastructure.core.exception.InvalidJsonException; +import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; +import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; +import org.apache.fineract.infrastructure.reportmailingjob.ReportMailingJobConstants; +import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobEmailAttachmentFileFormat; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.type.TypeReference; +import org.joda.time.LocalDateTime; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.google.gson.JsonElement; +import com.google.gson.reflect.TypeToken; + +@Component +public class ReportMailingJobValidator { + private final FromJsonHelper fromJsonHelper; + private static final String EMAIL_REGEX = "^[\\w!#$%&’*+/=?`{|}~^-]+(?:\\.[\\w!#$%&’*+/=?`{|}~^-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$"; + private static final Pattern EMAIL_PATTERN = Pattern.compile(EMAIL_REGEX); + + @Autowired + public ReportMailingJobValidator(final FromJsonHelper fromJsonHelper) { + this.fromJsonHelper = fromJsonHelper; + } + + /** + * validate the request to create a new report mailing job + * + * @param jsonCommand -- the JSON command object (instance of the JsonCommand class) + * @return None + **/ + public void validateCreateRequest(final JsonCommand jsonCommand) { + final String jsonString = jsonCommand.json(); + final JsonElement jsonElement = jsonCommand.parsedJson(); + + if (StringUtils.isBlank(jsonString)) { + throw new InvalidJsonException(); + } + + final Type typeToken = new TypeToken>() {}.getType(); + this.fromJsonHelper.checkForUnsupportedParameters(typeToken, jsonString, + ReportMailingJobConstants.CREATE_REQUEST_PARAMETERS); + + final List dataValidationErrors = new ArrayList<>(); + final DataValidatorBuilder dataValidatorBuilder = new DataValidatorBuilder(dataValidationErrors). + resource(StringUtils.lowerCase(ReportMailingJobConstants.REPORT_MAILING_JOB_RESOURCE_NAME)); + + final String name = this.fromJsonHelper.extractStringNamed(ReportMailingJobConstants.NAME_PARAM_NAME, jsonElement); + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.NAME_PARAM_NAME).value(name).notBlank().notExceedingLengthOf(100); + + final String startDateTime = this.fromJsonHelper.extractStringNamed(ReportMailingJobConstants.START_DATE_TIME_PARAM_NAME, + jsonElement); + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.START_DATE_TIME_PARAM_NAME).value(startDateTime).notBlank(); + + final Integer stretchyReportId = this.fromJsonHelper.extractIntegerWithLocaleNamed(ReportMailingJobConstants.STRETCHY_REPORT_ID_PARAM_NAME, + jsonElement); + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.STRETCHY_REPORT_ID_PARAM_NAME).value(stretchyReportId).notNull(). + integerGreaterThanZero(); + + final String emailRecipients = this.fromJsonHelper.extractStringNamed(ReportMailingJobConstants.EMAIL_RECIPIENTS_PARAM_NAME, jsonElement); + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.EMAIL_RECIPIENTS_PARAM_NAME).value(emailRecipients).notBlank(); + + final String emailSubject = this.fromJsonHelper.extractStringNamed(ReportMailingJobConstants.EMAIL_SUBJECT_PARAM_NAME, jsonElement); + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.EMAIL_SUBJECT_PARAM_NAME).value(emailSubject).notBlank().notExceedingLengthOf(100); + + final String emailMessage = this.fromJsonHelper.extractStringNamed(ReportMailingJobConstants.EMAIL_MESSAGE_PARAM_NAME, jsonElement); + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.EMAIL_MESSAGE_PARAM_NAME).value(emailMessage).notBlank(); + + if (this.fromJsonHelper.parameterExists(ReportMailingJobConstants.IS_ACTIVE_PARAM_NAME, jsonElement)) { + final Boolean isActive = this.fromJsonHelper.extractBooleanNamed(ReportMailingJobConstants.IS_ACTIVE_PARAM_NAME, + jsonElement); + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.IS_ACTIVE_PARAM_NAME).value(isActive).notNull(); + } + + final Integer emailAttachmentFileFormatId = this.fromJsonHelper.extractIntegerSansLocaleNamed( + ReportMailingJobConstants.EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME, jsonElement); + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME). + value(emailAttachmentFileFormatId).notNull(); + + if (emailAttachmentFileFormatId != null) { + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME).value(emailAttachmentFileFormatId). + isOneOfTheseValues(ReportMailingJobEmailAttachmentFileFormat.validIds()); + } + + final String dateFormat = jsonCommand.dateFormat(); + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.DATE_FORMAT_PARAM_NAME).value(dateFormat).notBlank(); + + if (StringUtils.isNotEmpty(dateFormat)) { + + try { + final DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(dateFormat).withLocale(jsonCommand.extractLocale()); + + // try to parse the date time string + LocalDateTime.parse(startDateTime, dateTimeFormatter); + } + + catch(IllegalArgumentException ex) { + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.DATE_FORMAT_PARAM_NAME).value(dateFormat).failWithCode("invalid.date.format"); + } + } + + throwExceptionIfValidationWarningsExist(dataValidationErrors); + } + + /** + * validate the request to update a report mailing job + * + * @param jsonCommand -- the JSON command object (instance of the JsonCommand class) + * @return None + **/ + public void validateUpdateRequest(final JsonCommand jsonCommand) { + final String jsonString = jsonCommand.json(); + final JsonElement jsonElement = jsonCommand.parsedJson(); + + if (StringUtils.isBlank(jsonString)) { + throw new InvalidJsonException(); + } + + final Type typeToken = new TypeToken>() {}.getType(); + this.fromJsonHelper.checkForUnsupportedParameters(typeToken, jsonString, + ReportMailingJobConstants.UPDATE_REQUEST_PARAMETERS); + + final List dataValidationErrors = new ArrayList<>(); + final DataValidatorBuilder dataValidatorBuilder = new DataValidatorBuilder(dataValidationErrors). + resource(StringUtils.lowerCase(ReportMailingJobConstants.REPORT_MAILING_JOB_RESOURCE_NAME)); + + if (this.fromJsonHelper.parameterExists(ReportMailingJobConstants.NAME_PARAM_NAME, jsonElement)) { + final String name = this.fromJsonHelper.extractStringNamed(ReportMailingJobConstants.NAME_PARAM_NAME, jsonElement); + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.NAME_PARAM_NAME).value(name).notBlank().notExceedingLengthOf(100); + } + + if (this.fromJsonHelper.parameterExists(ReportMailingJobConstants.STRETCHY_REPORT_ID_PARAM_NAME, jsonElement)) { + final Integer stretchyReportId = this.fromJsonHelper.extractIntegerWithLocaleNamed(ReportMailingJobConstants.STRETCHY_REPORT_ID_PARAM_NAME, + jsonElement); + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.STRETCHY_REPORT_ID_PARAM_NAME).value(stretchyReportId).notNull(). + integerGreaterThanZero(); + } + + if (this.fromJsonHelper.parameterExists(ReportMailingJobConstants.EMAIL_RECIPIENTS_PARAM_NAME, jsonElement)) { + final String emailRecipients = this.fromJsonHelper.extractStringNamed(ReportMailingJobConstants.EMAIL_RECIPIENTS_PARAM_NAME, jsonElement); + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.EMAIL_RECIPIENTS_PARAM_NAME).value(emailRecipients).notBlank(); + } + + if (this.fromJsonHelper.parameterExists(ReportMailingJobConstants.EMAIL_SUBJECT_PARAM_NAME, jsonElement)) { + final String emailSubject = this.fromJsonHelper.extractStringNamed(ReportMailingJobConstants.EMAIL_SUBJECT_PARAM_NAME, jsonElement); + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.EMAIL_SUBJECT_PARAM_NAME).value(emailSubject).notBlank().notExceedingLengthOf(100); + } + + if (this.fromJsonHelper.parameterExists(ReportMailingJobConstants.EMAIL_MESSAGE_PARAM_NAME, jsonElement)) { + final String emailMessage = this.fromJsonHelper.extractStringNamed(ReportMailingJobConstants.EMAIL_MESSAGE_PARAM_NAME, jsonElement); + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.EMAIL_MESSAGE_PARAM_NAME).value(emailMessage).notBlank(); + } + + if (this.fromJsonHelper.parameterExists(ReportMailingJobConstants.IS_ACTIVE_PARAM_NAME, jsonElement)) { + final Boolean isActive = this.fromJsonHelper.extractBooleanNamed(ReportMailingJobConstants.IS_ACTIVE_PARAM_NAME, + jsonElement); + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.IS_ACTIVE_PARAM_NAME).value(isActive).notNull(); + } + + if (this.fromJsonHelper.parameterExists(ReportMailingJobConstants.EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME, jsonElement)) { + final Integer emailAttachmentFileFormatId = this.fromJsonHelper.extractIntegerSansLocaleNamed( + ReportMailingJobConstants.EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME, jsonElement); + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME). + value(emailAttachmentFileFormatId).notNull(); + + if (emailAttachmentFileFormatId != null) { + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.EMAIL_ATTACHMENT_FILE_FORMAT_ID_PARAM_NAME).value(emailAttachmentFileFormatId). + isOneOfTheseValues(ReportMailingJobEmailAttachmentFileFormat.validIds()); + } + } + + if (this.fromJsonHelper.parameterExists(ReportMailingJobConstants.START_DATE_TIME_PARAM_NAME, jsonElement)) { + final String dateFormat = jsonCommand.dateFormat(); + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.DATE_FORMAT_PARAM_NAME).value(dateFormat).notBlank(); + + final String startDateTime = this.fromJsonHelper.extractStringNamed(ReportMailingJobConstants.START_DATE_TIME_PARAM_NAME, + jsonElement); + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.START_DATE_TIME_PARAM_NAME).value(startDateTime).notBlank(); + + if (StringUtils.isNotEmpty(dateFormat)) { + + try { + final DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(dateFormat).withLocale(jsonCommand.extractLocale()); + + // try to parse the date time string + LocalDateTime.parse(startDateTime, dateTimeFormatter); + } + + catch(IllegalArgumentException ex) { + dataValidatorBuilder.reset().parameter(ReportMailingJobConstants.DATE_FORMAT_PARAM_NAME).value(dateFormat).failWithCode("invalid.date.format"); + } + } + } + + throwExceptionIfValidationWarningsExist(dataValidationErrors); + } + + /** + * check if string is a valid email address + * + * @param email -- string to be validated + * @return true if string is a valid email address + **/ + public boolean isValidEmail(String email) { + // this is the easiest check + if (email == null) { + return false; + } + + // this is another easy check + if (email.endsWith(".")) { + return false; + } + + // Check the whole email address structure + Matcher emailMatcher = EMAIL_PATTERN.matcher(email); + + // check if the Matcher matches the email pattern + if (!emailMatcher.matches()) { + return false; + } + + return true; + } + + /** + * Validate the email recipients string + * + * @param emailRecipients -- the email recipients string to be validated + * @return a hashset containing valid email addresses + **/ + public Set validateEmailRecipients(String emailRecipients) { + Set emailRecipientsSet = new HashSet<>(); + + if (emailRecipients != null) { + String[] split = emailRecipients.split(","); + + for (String emailAddress : split) { + emailAddress = emailAddress.trim(); + + if (this.isValidEmail(emailAddress)) { + emailRecipientsSet.add(emailAddress); + } + } + } + + return emailRecipientsSet; + } + + /** + * validate the stretchy report param json string + * + * @param stretchyReportParamMap -- json string to be validated + * @return if string is valid or empty, a HashMap object, else null + **/ + public HashMap validateStretchyReportParamMap(String stretchyReportParamMap) { + HashMap stretchyReportParamHashMap = new HashMap<>(); + + if (!StringUtils.isEmpty(stretchyReportParamMap)) { + try { + stretchyReportParamHashMap = new ObjectMapper().readValue(stretchyReportParamMap, new TypeReference>(){}); + } + + catch(Exception e) { + stretchyReportParamHashMap = null; + } + } + + return stretchyReportParamHashMap; + } + + /** + * throw a PlatformApiDataValidationException exception if there are validation errors + * + * @param dataValidationErrors -- list of ApiParameterError objects + * @return None + **/ + private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { + if (!dataValidationErrors.isEmpty()) { + throw new PlatformApiDataValidationException(dataValidationErrors); + } + } +} diff --git a/fineract-provider/src/main/resources/sql/migrations/core_db/V312__report_mailing_job_module.sql b/fineract-provider/src/main/resources/sql/migrations/core_db/V312__report_mailing_job_module.sql new file mode 100644 index 000000000..155c77a15 --- /dev/null +++ b/fineract-provider/src/main/resources/sql/migrations/core_db/V312__report_mailing_job_module.sql @@ -0,0 +1,61 @@ +create table if not exists m_report_mailing_job ( +id bigint primary key auto_increment, +name varchar(100) not null, +description text null, +start_datetime datetime not null, +recurrence varchar(100) null, +created_date date not null, +createdby_id bigint not null, +lastmodified_date date null, +lastmodifiedby_id bigint null, +email_recipients text not null, +email_subject varchar(100) not null, +email_message text not null, +email_attachment_file_format varchar(10) not null, +stretchy_report_id int not null, +stretchy_report_param_map text null, +previous_run_datetime datetime null, +next_run_datetime datetime null, +previous_run_status varchar(10) null, +previous_run_error_log text null, +previous_run_error_message text null, +number_of_runs int not null default 0, +is_active tinyint(1) not null default 0, +is_deleted tinyint(1) not null default 0, +run_as_userid bigint not null, +foreign key (createdby_id) references m_appuser(id), +foreign key (lastmodifiedby_id) references m_appuser(id), +foreign key (stretchy_report_id) references stretchy_report(id), +foreign key (run_as_userid) references m_appuser(id), +constraint unique_name unique (name) +); + +create table if not exists m_report_mailing_job_run_history ( +id bigint primary key auto_increment, +job_id bigint not null, +start_datetime datetime not null, +end_datetime datetime not null, +status varchar(10) not null, +error_message text null, +error_log text null, +foreign key (job_id) references m_report_mailing_job (id) +); + +create table if not exists m_report_mailing_job_configuration ( +id int primary key auto_increment, +name varchar(50) not null, +`value` varchar(200) not null, +constraint unique_name unique (name) +); + +insert into m_permission (`grouping`, code, entity_name, action_name, can_maker_checker) +values ('jobs', 'CREATE_REPORTMAILINGJOB', 'REPORTMAILINGJOB', 'CREATE', 0), +('jobs', 'UPDATE_REPORTMAILINGJOB', 'REPORTMAILINGJOB', 'UPDATE', 0), +('jobs', 'DELETE_REPORTMAILINGJOB', 'REPORTMAILINGJOB', 'DELETE', 0), +('jobs', 'READ_REPORTMAILINGJOB', 'REPORTMAILINGJOB', 'READ', 0); + +insert into m_report_mailing_job_configuration (name, `value`) +values ('GMAIL_SMTP_SERVER', 'smtp.gmail.com'), ('GMAIL_SMTP_PORT', 587), ('GMAIL_SMTP_USERNAME', ''), ('GMAIL_SMTP_PASSWORD', ''); + +insert into job (name, display_name, cron_expression, create_time) +values ('Execute Report Mailing Jobs', 'Execute Report Mailing Jobs', '0 0/15 * * * ?', NOW());