FINERACT-1273: Triggered emails

Basically send an email when a client does an action: for now when a loan is approved, rejected and when a repayment is done. More triggers should be added in the future
This commit is contained in:
Adonay
2021-09-22 09:43:25 +08:00
committed by Petri Tuomola
parent 07f395ef7f
commit 8146a7399c
12 changed files with 305 additions and 80 deletions
@@ -75,11 +75,11 @@ public class EmailCampaign extends AbstractPersistableCustom {
@Column(name = "email_message", nullable = false)
private String emailMessage;
@Column(name = "email_attachment_file_format", nullable = false)
@Column(name = "email_attachment_file_format")
private String emailAttachmentFileFormat;
@ManyToOne
@JoinColumn(name = "stretchy_report_id", nullable = false)
@JoinColumn(name = "stretchy_report_id")
private Report stretchyReport;
@Column(name = "stretchy_report_param_map", nullable = true)
@@ -109,18 +109,18 @@ public class EmailCampaign extends AbstractPersistableCustom {
@JoinColumn(name = "approvedon_userid", nullable = true)
private AppUser approvedBy;
@Column(name = "recurrence", nullable = false)
@Column(name = "recurrence")
private String recurrence;
@Column(name = "next_trigger_date", nullable = false)
@Column(name = "next_trigger_date")
@Temporal(TemporalType.TIMESTAMP)
private Date nextTriggerDate;
@Column(name = "last_trigger_date", nullable = false)
@Column(name = "last_trigger_date")
@Temporal(TemporalType.TIMESTAMP)
private Date lastTriggerDate;
@Column(name = "recurrence_start_date", nullable = false)
@Column(name = "recurrence_start_date")
@Temporal(TemporalType.TIMESTAMP)
private Date recurrenceStartDate;
@@ -18,7 +18,14 @@
*/
package org.apache.fineract.infrastructure.campaigns.email.domain;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface EmailCampaignRepository extends JpaRepository<EmailCampaign, Long>, JpaSpecificationExecutor<EmailCampaign> {}
public interface EmailCampaignRepository extends JpaRepository<EmailCampaign, Long>, JpaSpecificationExecutor<EmailCampaign> {
@Query("SELECT campaign FROM EmailCampaign campaign WHERE campaign.paramValue LIKE :reportPattern AND campaign.campaignType=:type AND campaign.status=300")
List<EmailCampaign> findActiveEmailCampaigns(@Param("reportPattern") String reportPattern, @Param("type") Integer type);
}
@@ -20,7 +20,8 @@ package org.apache.fineract.infrastructure.campaigns.email.domain;
public enum EmailCampaignType {
DIRECT(1, "emailCampaignStatusType.direct"), SCHEDULE(2, "emailCampaignStatusType.schedule");
DIRECT(1, "emailCampaignStatusType.direct"), SCHEDULE(2, "emailCampaignStatusType.schedule"), TRIGGERED(3,
"emailCampaignStatusType.triggered");
private final Integer value;
private final String code;
@@ -47,6 +48,9 @@ public enum EmailCampaignType {
case 2:
type = SCHEDULE;
break;
case 3:
type = TRIGGERED;
break;
}
return type;
}
@@ -58,4 +62,8 @@ public enum EmailCampaignType {
public boolean isSchedule() {
return this.value.equals(EmailCampaignType.SCHEDULE.getValue());
}
public boolean isTriggered() {
return this.value.equals(EmailCampaignType.TRIGGERED.getValue());
}
}
@@ -0,0 +1,21 @@
/**
* 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.campaigns.email.service;
public interface EmailCampaignDomainService {}
@@ -0,0 +1,151 @@
/**
* 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.campaigns.email.service;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.apache.fineract.infrastructure.campaigns.email.domain.EmailCampaign;
import org.apache.fineract.infrastructure.campaigns.email.domain.EmailCampaignRepository;
import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignTriggerType;
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants;
import org.apache.fineract.portfolio.common.service.BusinessEventListener;
import org.apache.fineract.portfolio.common.service.BusinessEventNotifierService;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class EmailCampaignDomainServiceImpl implements EmailCampaignDomainService {
private static final Logger LOG = LoggerFactory.getLogger(EmailCampaignDomainServiceImpl.class);
private final BusinessEventNotifierService businessEventNotifierService;
private final EmailCampaignWritePlatformService emailCampaignWritePlatformService;
private final EmailCampaignRepository emailCampaignRepository;
@Autowired
public EmailCampaignDomainServiceImpl(BusinessEventNotifierService businessEventNotifierService,
EmailCampaignWritePlatformService emailCampaignWritePlatformService, EmailCampaignRepository emailCampaignRepository) {
this.businessEventNotifierService = businessEventNotifierService;
this.emailCampaignWritePlatformService = emailCampaignWritePlatformService;
this.emailCampaignRepository = emailCampaignRepository;
}
@PostConstruct
public void addListeners() {
this.businessEventNotifierService.addBusinessEventPostListeners(BusinessEventNotificationConstants.BusinessEvents.LOAN_APPROVED,
new EmailCampaignDomainServiceImpl.SendEmailOnLoanApproved());
this.businessEventNotifierService.addBusinessEventPostListeners(BusinessEventNotificationConstants.BusinessEvents.LOAN_REJECTED,
new EmailCampaignDomainServiceImpl.SendEmailOnLoanRejected());
this.businessEventNotifierService.addBusinessEventPostListeners(
BusinessEventNotificationConstants.BusinessEvents.LOAN_MAKE_REPAYMENT,
new EmailCampaignDomainServiceImpl.SendEmailOnLoanRepayment());
}
private class SendEmailOnLoanRepayment extends EmailBusinessEventAdapter {
@Override
public void businessEventWasExecuted(Map<BusinessEventNotificationConstants.BusinessEntity, Object> businessEventEntity) {
Object entity = businessEventEntity.get(BusinessEventNotificationConstants.BusinessEntity.LOAN_TRANSACTION);
if (entity instanceof LoanTransaction) {
LoanTransaction loanTransaction = (LoanTransaction) entity;
try {
notifyLoanOwner(loanTransaction, "Loan Repayment");
} catch (IOException e) {
LOG.error("Exception when trying to send triggered email: {}", e.getMessage());
}
}
}
}
private class SendEmailOnLoanRejected extends EmailBusinessEventAdapter {
@Override
public void businessEventWasExecuted(Map<BusinessEventNotificationConstants.BusinessEntity, Object> businessEventEntity) {
Object entity = businessEventEntity.get(BusinessEventNotificationConstants.BusinessEntity.LOAN);
if (entity instanceof Loan) {
Loan loan = (Loan) entity;
try {
notifyLoanOwner(loan, "Loan Rejected");
} catch (IOException e) {
LOG.error("Exception when trying to send triggered email: {}", e.getMessage());
}
}
}
}
private class SendEmailOnLoanApproved extends EmailBusinessEventAdapter {
@Override
public void businessEventWasExecuted(Map<BusinessEventNotificationConstants.BusinessEntity, Object> businessEventEntity) {
Object entity = businessEventEntity.get(BusinessEventNotificationConstants.BusinessEntity.LOAN);
if (entity instanceof Loan) {
Loan loan = (Loan) entity;
try {
notifyLoanOwner(loan, "Loan Approved");
} catch (IOException e) {
LOG.error("Exception when trying to send triggered email: {}", e.getMessage());
}
}
}
}
private void notifyLoanOwner(LoanTransaction loanTransaction, String paramValue) throws IOException {
List<EmailCampaign> campaigns = this.retrieveEmailCampaigns(paramValue);
for (EmailCampaign emailCampaign : campaigns) {
HashMap<String, String> campaignParams = new ObjectMapper().readValue(emailCampaign.getParamValue(),
new TypeReference<HashMap<String, String>>() {});
campaignParams.put("loanId", loanTransaction.getLoan().getId().toString());
campaignParams.put("loanTransactionId", loanTransaction.getId().toString());
this.emailCampaignWritePlatformService.insertDirectCampaignIntoEmailOutboundTable(loanTransaction.getLoan(), emailCampaign,
campaignParams);
}
}
private void notifyLoanOwner(Loan loan, String paramValue) throws IOException {
List<EmailCampaign> campaigns = this.retrieveEmailCampaigns(paramValue);
for (EmailCampaign emailCampaign : campaigns) {
HashMap<String, String> campaignParams = new ObjectMapper().readValue(emailCampaign.getParamValue(),
new TypeReference<HashMap<String, String>>() {});
campaignParams.put("loanId", loan.getId().toString());
this.emailCampaignWritePlatformService.insertDirectCampaignIntoEmailOutboundTable(loan, emailCampaign, campaignParams);
}
}
private abstract static class EmailBusinessEventAdapter implements BusinessEventListener {
@Override
public void businessEventToBeExecuted(Map<BusinessEventNotificationConstants.BusinessEntity, Object> businessEventEntity) {
// Nothing to do
}
}
private List<EmailCampaign> retrieveEmailCampaigns(String paramValue) {
List<EmailCampaign> emailCampaigns = emailCampaignRepository.findActiveEmailCampaigns("%" + paramValue + "%",
SmsCampaignTriggerType.TRIGGERED.getValue());
return emailCampaigns;
}
}
@@ -158,20 +158,24 @@ public class EmailCampaignWritePlatformCommandHandlerImpl implements EmailCampai
final Long reportId = command.longValueOfParameterNamed(EmailCampaignValidator.stretchyReportId);
final Report report = this.reportRepository.findById(reportId).orElseThrow(() -> new ReportNotFoundException(reportId));
Report report = null;
Map<String, String> stretchyReportParams = null;
if (reportId != null) {
report = this.reportRepository.findById(reportId).orElseThrow(() -> new ReportNotFoundException(reportId));
final Set<ReportParameterUsage> reportParameterUsages = report.getReportParameterUsages();
stretchyReportParams = new HashMap<>();
// find all report parameters and store them as json string
final Set<ReportParameterUsage> reportParameterUsages = report.getReportParameterUsages();
final Map<String, String> stretchyReportParams = new HashMap<>();
if (reportParameterUsages != null && !reportParameterUsages.isEmpty()) {
for (final ReportParameterUsage reportParameterUsage : reportParameterUsages) {
stretchyReportParams.put(reportParameterUsage.getReportParameterName(), "");
if (reportParameterUsages != null && !reportParameterUsages.isEmpty()) {
for (final ReportParameterUsage reportParameterUsage : reportParameterUsages) {
stretchyReportParams.put(reportParameterUsage.getReportParameterName(), "");
}
}
}
EmailCampaign emailCampaign = EmailCampaign.instance(currentUser, businessRule, report, command);
emailCampaign.setStretchyReportParamMap(new Gson().toJson(stretchyReportParams));
if (stretchyReportParams != null) {
emailCampaign.setStretchyReportParamMap(new Gson().toJson(stretchyReportParams));
}
this.emailCampaignRepository.save(emailCampaign);
@@ -241,6 +245,32 @@ public class EmailCampaignWritePlatformCommandHandlerImpl implements EmailCampai
}
@Override
public void insertDirectCampaignIntoEmailOutboundTable(final Loan loan, final EmailCampaign emailCampaign,
HashMap<String, String> campaignParams) {
try {
List<HashMap<String, Object>> runReportObject = this.getRunReportByServiceImpl(campaignParams.get("reportName"),
campaignParams);
if (runReportObject != null) {
for (HashMap<String, Object> entry : runReportObject) {
String message = this.compileEmailTemplate(emailCampaign.getEmailMessage(), emailCampaign.getCampaignName(), entry);
Client client = loan.getClient();
String emailAddress = client.emailAddress();
if (emailAddress != null && isValidEmail(emailAddress)) {
EmailMessage emailMessage = EmailMessage.pendingEmail(null, client, null, emailCampaign,
emailCampaign.getEmailSubject(), message, emailAddress, emailCampaign.getCampaignName());
this.emailMessageRepository.save(emailMessage);
}
}
}
} catch (final IOException e) {
// TODO throw something here
}
}
private void insertDirectCampaignIntoEmailOutboundTable(final String emailParams, final String emailSubject,
final String messageTemplate, final String campaignName, final Long campaignId) {
try {
@@ -589,8 +619,11 @@ public class EmailCampaignWritePlatformCommandHandlerImpl implements EmailCampai
final EmailCampaign emailCampaign = this.emailCampaignRepository.findById(emailMessage.getEmailCampaign().getId())
.orElse(null); //
final ScheduledEmailAttachmentFileFormat emailAttachmentFileFormat = ScheduledEmailAttachmentFileFormat
.instance(emailCampaign.getEmailAttachmentFileFormat());
ScheduledEmailAttachmentFileFormat emailAttachmentFileFormat = null;
if (emailCampaign.getEmailAttachmentFileFormat() != null) {
emailAttachmentFileFormat = ScheduledEmailAttachmentFileFormat
.instance(emailCampaign.getEmailAttachmentFileFormat());
}
final List<File> attachmentList = new ArrayList<>();
@@ -690,29 +723,16 @@ public class EmailCampaignWritePlatformCommandHandlerImpl implements EmailCampai
final EmailMessageWithAttachmentData emailMessageWithAttachmentData = EmailMessageWithAttachmentData.createNew(
emailMessage.getEmailAddress(), emailMessage.getMessage(), emailMessage.getEmailSubject(), attachmentList);
if (!attachmentList.isEmpty() && attachmentList.size() > 0) { // only
// send
// email
// message
// if
// there
// is
// an
// attachment
// to
// it
try {
this.emailMessageJobEmailService.sendEmailWithAttachment(emailMessageWithAttachmentData);
emailMessage.setStatusType(EmailMessageStatusType.SENT.getValue());
this.emailMessageRepository.save(emailMessage);
} else {
emailMessage.updateErrorMessage(errorLog.toString());
} catch (Exception e) {
emailMessage.updateErrorMessage(e.getMessage());
emailMessage.setStatusType(EmailMessageStatusType.FAILED.getValue());
this.emailMessageRepository.save(emailMessage);
}
}
@@ -734,7 +754,9 @@ public class EmailCampaignWritePlatformCommandHandlerImpl implements EmailCampai
*/
private File generateAttachments(final EmailCampaign emailCampaign, final ScheduledEmailAttachmentFileFormat emailAttachmentFileFormat,
final Map<String, String> reportParams, final String reportName, final StringBuilder errorLog) {
if (reportName == null) {
return null;
}
try {
final ByteArrayOutputStream byteArrayOutputStream = this.readReportingService.generatePentahoReportAsOutputStream(reportName,
emailAttachmentFileFormat.getValue(), reportParams, null, emailCampaign.getApprovedBy(), errorLog);
@@ -18,11 +18,14 @@
*/
package org.apache.fineract.infrastructure.campaigns.email.service;
import java.util.HashMap;
import org.apache.fineract.infrastructure.campaigns.email.data.PreviewCampaignMessage;
import org.apache.fineract.infrastructure.campaigns.email.domain.EmailCampaign;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.api.JsonQuery;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
public interface EmailCampaignWritePlatformService {
@@ -44,4 +47,6 @@ public interface EmailCampaignWritePlatformService {
void sendEmailMessage() throws JobExecutionException;
void insertDirectCampaignIntoEmailOutboundTable(Loan loan, EmailCampaign emailCampaign, HashMap<String, String> campaignParams);
}
@@ -23,10 +23,9 @@ import java.util.List;
import java.util.Properties;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import org.apache.fineract.infrastructure.campaigns.email.EmailApiConstants;
import org.apache.fineract.infrastructure.campaigns.email.data.EmailMessageWithAttachmentData;
import org.apache.fineract.infrastructure.campaigns.email.domain.EmailConfiguration;
import org.apache.fineract.infrastructure.campaigns.email.domain.EmailConfigurationRepository;
import org.apache.fineract.infrastructure.configuration.data.SMTPCredentialsData;
import org.apache.fineract.infrastructure.configuration.service.ExternalServicesPropertiesReadPlatformService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -38,30 +37,33 @@ import org.springframework.stereotype.Service;
public final class EmailMessageJobEmailServiceImpl implements EmailMessageJobEmailService {
private static final Logger LOG = LoggerFactory.getLogger(EmailMessageJobEmailServiceImpl.class);
private EmailConfigurationRepository emailConfigurationRepository;
private final ExternalServicesPropertiesReadPlatformService externalServicesReadPlatformService;
@Autowired
private EmailMessageJobEmailServiceImpl(final EmailConfigurationRepository emailConfigurationRepository) {
this.emailConfigurationRepository = emailConfigurationRepository;
private EmailMessageJobEmailServiceImpl(ExternalServicesPropertiesReadPlatformService externalServicesReadPlatformService) {
this.externalServicesReadPlatformService = externalServicesReadPlatformService;
}
@Override
public void sendEmailWithAttachment(EmailMessageWithAttachmentData emailMessageWithAttachmentData) {
final SMTPCredentialsData smtpCredentialsData = this.externalServicesReadPlatformService.getSMTPCredentials();
try {
JavaMailSenderImpl javaMailSenderImpl = new JavaMailSenderImpl();
javaMailSenderImpl.setHost(this.getGmailSmtpServer());
javaMailSenderImpl.setPort(this.getGmailSmtpPort());
javaMailSenderImpl.setUsername(this.getGmailSmtpUsername());
javaMailSenderImpl.setPassword(this.getGmailSmtpPassword());
javaMailSenderImpl.setJavaMailProperties(this.getJavaMailProperties());
javaMailSenderImpl.setHost(smtpCredentialsData.getHost());
javaMailSenderImpl.setPort(Integer.parseInt(smtpCredentialsData.getPort()));
javaMailSenderImpl.setUsername(smtpCredentialsData.getUsername());
javaMailSenderImpl.setPassword(smtpCredentialsData.getPassword());
javaMailSenderImpl
.setJavaMailProperties(this.getJavaMailProperties(smtpCredentialsData, javaMailSenderImpl.getJavaMailProperties()));
MimeMessage mimeMessage = javaMailSenderImpl.createMimeMessage();
// use the true flag to indicate you need a multipart message
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
mimeMessageHelper.setFrom(smtpCredentialsData.getFromEmail());
mimeMessageHelper.setTo(emailMessageWithAttachmentData.getTo());
mimeMessageHelper.setText(emailMessageWithAttachmentData.getText());
mimeMessageHelper.setText(emailMessageWithAttachmentData.getText(), true);
mimeMessageHelper.setSubject(emailMessageWithAttachmentData.getSubject());
final List<File> attachments = emailMessageWithAttachmentData.getAttachments();
if (attachments != null && attachments.size() > 0) {
@@ -80,32 +82,18 @@ public final class EmailMessageJobEmailServiceImpl implements EmailMessageJobEma
}
private String getGmailSmtpServer() {
final EmailConfiguration gmailSmtpServer = this.emailConfigurationRepository.findByName(EmailApiConstants.SMTP_SERVER);
return (gmailSmtpServer != null) ? gmailSmtpServer.getValue() : null;
}
private Integer getGmailSmtpPort() {
final EmailConfiguration gmailSmtpPort = this.emailConfigurationRepository.findByName(EmailApiConstants.SMTP_PORT);
return (gmailSmtpPort != null) ? Integer.parseInt(gmailSmtpPort.getValue()) : null;
}
private String getGmailSmtpUsername() {
final EmailConfiguration gmailSmtpUsername = this.emailConfigurationRepository.findByName(EmailApiConstants.SMTP_USERNAME);
return (gmailSmtpUsername != null) ? gmailSmtpUsername.getValue() : null;
}
private String getGmailSmtpPassword() {
final EmailConfiguration gmailSmtpPassword = this.emailConfigurationRepository.findByName(EmailApiConstants.SMTP_PASSWORD);
return (gmailSmtpPassword != null) ? gmailSmtpPassword.getValue() : null;
}
private Properties getJavaMailProperties() {
Properties properties = new Properties();
properties.setProperty("mail.smtp.starttls.enable", "true");
properties.setProperty("mail.smtp.auth", "true");
properties.setProperty("mail.smtp.ssl.trust", this.getGmailSmtpServer());
private Properties getJavaMailProperties(SMTPCredentialsData smtpCredentialsData, Properties properties) {
properties.put("mail.smtp.starttls.enable", "true");
properties.put("mail.transport.protocol", "smtp");
properties.put("mail.smtp.auth", "true");
properties.put("mail.smtp.ssl.trust", smtpCredentialsData.getHost());
if (smtpCredentialsData.isUseTLS()) {
// Needs to disable startTLS if the port is 465 in order to send the email successfully when using the
// smtp.gmail.com as the host
if (smtpCredentialsData.getPort().equals("465")) {
properties.put("mail.smtp.starttls.enable", "false");
}
}
return properties;
}
}
@@ -74,9 +74,7 @@ public class AddressCommandFromApiJsonDeserializer {
final List<FieldConfigurationData> configData = configurationData.stream().filter(FieldConfigurationData::isEnabled)
.collect(Collectors.toList());
final Set<String> supportedParameters = configData.stream()
.map(FieldConfigurationData::getField)
.collect(Collectors.toSet());
final Set<String> supportedParameters = configData.stream().map(FieldConfigurationData::getField).collect(Collectors.toSet());
supportedParameters.add("locale");
supportedParameters.add("dateFormat");
@@ -85,8 +83,7 @@ public class AddressCommandFromApiJsonDeserializer {
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
configData.forEach(fieldConfiguration -> {
final String field =
fieldConfiguration.getField().equals("addressType") ? "addressTypeId" : fieldConfiguration.getField();
final String field = fieldConfiguration.getField().equals("addressType") ? "addressTypeId" : fieldConfiguration.getField();
final String fieldValue = this.fromApiJsonHelper.extractStringNamed(field, element);
if (fieldConfiguration.getField().equals("addressType") && fromNewClient) {
@@ -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.
--
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_sql`, `description`, `core_report`, `use_report`, `self_service_user_report`) VALUES ('Loan Approved - Email', 'Email', 'Triggered', 'select ml.id as loanId, ifnull(mc.id,mc2.id) as id, ifnull(mc.firstname,mc2.firstname) as firstname, \nifnull(mc.middlename,ifnull(mc2.middlename,(\'\'))) as middlename, ifnull(mc.lastname,mc2.lastname) as lastname, \nifnull(mc.display_name,mc2.display_name) as display_name, ifnull(mc.status_enum,mc2.status_enum) as status_enum, \nifnull(mc.mobile_no,mc2.mobile_no) as mobile_no, ifnull(mg.office_id,mc2.office_id) as office_id, ifnull(mg.staff_id,mc2.staff_id) as staff_id, \nmg.id as group_id, mg.display_name as group_name, ifnull(mc.email_address,mc2.email_address) as emailAddress\nfrom m_loan ml left join m_group mg on mg.id = ml.group_id \nleft join m_group_client mgc on mgc.group_id = mg.id \nleft join m_client mc on mc.id = mgc.client_id \nleft join m_client mc2 on mc2.id = ml.client_id\nWHERE (mc.status_enum = 300 or mc2.status_enum = 300) and (mc.email_address is not null or mc2.email_address is not null) and ml.id = ${loanId}\n', 'Loan and client data of approved loan', '0', '1', '0');
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_sql`, `description`, `core_report`, `use_report`, `self_service_user_report`) VALUES ('Loan Rejected - Email', 'Email', 'Triggered', 'select ml.id as loanId, ifnull(mc.id,mc2.id) as id, ifnull(mc.firstname,mc2.firstname) as firstname, \nifnull(mc.middlename,ifnull(mc2.middlename,(\'\'))) as middlename, ifnull(mc.lastname,mc2.lastname) as lastname, \nifnull(mc.display_name,mc2.display_name) as display_name, ifnull(mc.status_enum,mc2.status_enum) as status_enum, \nifnull(mc.mobile_no,mc2.mobile_no) as mobile_no, ifnull(mg.office_id,mc2.office_id) as office_id, ifnull(mg.staff_id,mc2.staff_id) as staff_id, \nmg.id as group_id, mg.display_name as group_name, ifnull(mc.email_address,mc2.email_address) as emailAddress\nfrom m_loan ml left join m_group mg on mg.id = ml.group_id \nleft join m_group_client mgc on mgc.group_id = mg.id \nleft join m_client mc on mc.id = mgc.client_id \nleft join m_client mc2 on mc2.id = ml.client_id\nWHERE (mc.status_enum = 300 or mc2.status_enum = 300) and (mc.email_address is not null or mc2.email_address is not null) and ml.id = ${loanId}\n', 'Loan and client data of rejected loan', '0', '1', '0');
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_sql`, `description`, `core_report`, `use_report`, `self_service_user_report`) VALUES ('Loan Repayment - Email', 'Email', 'Triggered', 'select ml.id as loanId, ifnull(mc.id,mc2.id) as id, ifnull(mc.firstname,mc2.firstname) as firstname, \nifnull(mc.middlename,ifnull(mc2.middlename,(\'\'))) as middlename, ifnull(mc.lastname,mc2.lastname) as lastname, \nifnull(mc.display_name,mc2.display_name) as display_name, ifnull(mc.status_enum,mc2.status_enum) as status_enum, \nifnull(mc.mobile_no,mc2.mobile_no) as mobile_no, ifnull(mg.office_id,mc2.office_id) as office_id, ifnull(mg.staff_id,mc2.staff_id) as staff_id, \nmg.id as group_id, mg.display_name as group_name, ifnull(mc.email_address,mc2.email_address) as emailAddress, lt.amount as repaymentAmount \nfrom m_loan_transaction lt join m_loan ml on ml.id=lt.loan_id left join m_group mg on mg.id = ml.group_id \nleft join m_group_client mgc on mgc.group_id = mg.id \nleft join m_client mc on mc.id = mgc.client_id \nleft join m_client mc2 on mc2.id = ml.client_id\nWHERE (mc.status_enum = 300 or mc2.status_enum = 300) and (mc.email_address is not null or mc2.email_address is not null) and ml.id = ${loanId} and lt.id = ${loanTransactionId}\n', 'Loan and client data of rejected loan', '0', '1', '0');
ALTER TABLE `scheduled_email_campaign`
CHANGE COLUMN `email_attachment_file_format` `email_attachment_file_format` VARCHAR(10) NULL ,
CHANGE COLUMN `stretchy_report_id` `stretchy_report_id` INT(11) NULL ;
@@ -35,7 +35,7 @@ public class ReportsTest extends IntegrationTest {
@Test
void listReports() {
assertThat(ok(fineract().reports.retrieveReportList())).hasSize(117);
assertThat(ok(fineract().reports.retrieveReportList())).hasSize(120);
}
@Test