Skip to content

Commit

Permalink
Feature/SU-461-SU-507: SMS - Parametrización | Suspended to be parame…
Browse files Browse the repository at this point in the history
…trized (#1369)
  • Loading branch information
fiter-julius-oketayot authored Dec 10, 2024
1 parent 1325016 commit 035aaa5
Show file tree
Hide file tree
Showing 12 changed files with 140 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ public interface ConfigurationDomainService {

Long retriveMinimumDaysOfArrearsToWriteOff();

Long retriveMinimumDaysInArrearsToSuspendLoanAccount();

Long retrieveInvoiceResolutionExpiryDays();

Long retrieveInvoiceThreshold();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,71 +298,77 @@ private void notifyWriteOffLoanOwner(final LoanTransaction loanTransaction) {
}
}

private void sendSmsForLoanRepayment(LoanTransaction loanTransaction) {
List<SmsCampaign> smsCampaigns = retrieveSmsCampaigns("Loan Repayment");
if (!smsCampaigns.isEmpty()) {
for (SmsCampaign smsCampaign : smsCampaigns) {
try {
Loan loan = loanTransaction.getLoan();
final Set<Client> groupClients = new HashSet<>();
if (loan.hasInvalidLoanType()) {
throw new InvalidLoanTypeException("Loan Type cannot be Invalid for the Triggered Sms Campaign");
}
if (loan.isGroupLoan()) {
Group group = this.groupRepository.findById(loan.getGroupId())
.orElseThrow(() -> new GroupNotFoundException(loan.getGroupId()));
groupClients.addAll(group.getClientMembers());
} else {
groupClients.add(loan.client());
}
HashMap<String, String> campaignParams = new ObjectMapper().readValue(smsCampaign.getParamValue(),
new TypeReference<>() {

});

if (!groupClients.isEmpty()) {
for (Client client : groupClients) {
HashMap<String, Object> smsParams = processRepaymentDataForSms(loanTransaction, client);
for (Map.Entry<String, String> entry : campaignParams.entrySet()) {
String value = entry.getValue();
String spvalue = null;
boolean spkeycheck = smsParams.containsKey(entry.getKey());
if (spkeycheck) {
spvalue = smsParams.get(entry.getKey()).toString();
}
if (spkeycheck && !(value.equals("-1") || spvalue.equals(value))) {
if (entry.getKey().equals("officeId")) {
Long officeId = Long.valueOf(value);
Office campaignOffice = this.officeRepository.findById(Long.valueOf(value))
.orElseThrow(() -> new OfficeNotFoundException(officeId));
if (campaignOffice.doesNotHaveAnOfficeInHierarchyWithId(client.getOffice().getId())) {
throw new SmsRuntimeException("error.msg.no.office", "Office not found for the id");
private void sendSmsForLoanRepayment(final LoanTransaction loanTransaction) {
final Loan loan = loanTransaction.getLoan();
final LoanProduct loanProduct = loan.getLoanProduct();
if (loanProduct != null) {
if (loanProduct.getCustomAllowCollectionsSms()) {
final List<SmsCampaign> smsCampaigns = retrieveSmsCampaigns("Loan Repayment");
if (!smsCampaigns.isEmpty()) {
for (SmsCampaign smsCampaign : smsCampaigns) {
try {
final Set<Client> groupClients = new HashSet<>();
if (loan.hasInvalidLoanType()) {
throw new InvalidLoanTypeException("Loan Type cannot be Invalid for the Triggered Sms Campaign");
}
if (loan.isGroupLoan()) {
Group group = this.groupRepository.findById(loan.getGroupId())
.orElseThrow(() -> new GroupNotFoundException(loan.getGroupId()));
groupClients.addAll(group.getClientMembers());
} else {
groupClients.add(loan.client());
}
HashMap<String, String> campaignParams = new ObjectMapper().readValue(smsCampaign.getParamValue(),
new TypeReference<>() {

});

if (!groupClients.isEmpty()) {
for (Client client : groupClients) {
HashMap<String, Object> smsParams = processRepaymentDataForSms(loanTransaction, client);
for (Map.Entry<String, String> entry : campaignParams.entrySet()) {
String value = entry.getValue();
String spvalue = null;
boolean spkeycheck = smsParams.containsKey(entry.getKey());
if (spkeycheck) {
spvalue = smsParams.get(entry.getKey()).toString();
}
if (spkeycheck && !(value.equals("-1") || spvalue.equals(value))) {
if (entry.getKey().equals("officeId")) {
Long officeId = Long.valueOf(value);
Office campaignOffice = this.officeRepository.findById(Long.valueOf(value))
.orElseThrow(() -> new OfficeNotFoundException(officeId));
if (campaignOffice.doesNotHaveAnOfficeInHierarchyWithId(client.getOffice().getId())) {
throw new SmsRuntimeException("error.msg.no.office", "Office not found for the id");
}
} else {
throw new SmsRuntimeException("error.msg.no.id.attribute",
"Office Id attribute is notfound");
}
}
} else {
throw new SmsRuntimeException("error.msg.no.id.attribute", "Office Id attribute is notfound");
}
String message = this.smsCampaignWritePlatformCommandHandler
.compileSmsTemplate(smsCampaign.getMessage(), smsCampaign.getCampaignName(), smsParams);
Object mobileNo = smsParams.get("mobileNo");
if (this.smsCampaignValidator.isValidNotificationOrSms(client, smsCampaign, mobileNo)) {
String mobileNumber = null;
if (mobileNo != null) {
mobileNumber = mobileNo.toString();
}
SmsMessage smsMessage = SmsMessage.pendingSms(null, null, client, null, message, mobileNumber,
smsCampaign, smsCampaign.isNotification());
Map<SmsCampaign, Collection<SmsMessage>> smsDataMap = new HashMap<>();
smsDataMap.put(smsCampaign, Collections.singletonList(smsMessage));
this.smsMessageScheduledJobService.sendTriggeredMessages(smsDataMap);
}
}
}
String message = this.smsCampaignWritePlatformCommandHandler.compileSmsTemplate(smsCampaign.getMessage(),
smsCampaign.getCampaignName(), smsParams);
Object mobileNo = smsParams.get("mobileNo");
if (this.smsCampaignValidator.isValidNotificationOrSms(client, smsCampaign, mobileNo)) {
String mobileNumber = null;
if (mobileNo != null) {
mobileNumber = mobileNo.toString();
}
SmsMessage smsMessage = SmsMessage.pendingSms(null, null, client, null, message, mobileNumber, smsCampaign,
smsCampaign.isNotification());
Map<SmsCampaign, Collection<SmsMessage>> smsDataMap = new HashMap<>();
smsDataMap.put(smsCampaign, Collections.singletonList(smsMessage));
this.smsMessageScheduledJobService.sendTriggeredMessages(smsDataMap);
}
} catch (final IOException e) {
log.error("smsParams does not contain the key: ", e);
} catch (final RuntimeException e) {
log.debug("Client Office Id and SMS Campaign Office id doesn't match ", e);
}
}
} catch (final IOException e) {
log.error("smsParams does not contain the key: ", e);
} catch (final RuntimeException e) {
log.debug("Client Office Id and SMS Campaign Office id doesn't match ", e);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,13 @@ public Long retriveMinimumDaysOfArrearsToWriteOff() {
return property.getValue();
}

@Override
public Long retriveMinimumDaysInArrearsToSuspendLoanAccount() {
final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(
"Dias a partir de los cuales empezar a considerar suspendido");
return property.getValue();
}

@Override
public Long retrieveInvoiceResolutionExpiryDays() {
final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(INVOICE_RESOLUTION_EXPIRY);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,13 +284,16 @@ public LoanTransaction makeRepayment(final LoanTransactionType repaymentTransact
recalculateAccruals(loan);

setLoanDelinquencyTag(loan, transactionDate);

Long minimumDaysInArrearsToSuspendLoanAccount = this.configurationDomainService.retriveMinimumDaysInArrearsToSuspendLoanAccount();
if (minimumDaysInArrearsToSuspendLoanAccount == null) {
minimumDaysInArrearsToSuspendLoanAccount = 90L;
}
if (!repaymentTransactionType.isChargeRefund()) {
LoanTransactionBusinessEvent transactionRepaymentEvent = getTransactionRepaymentTypeBusinessEvent(repaymentTransactionType,
isRecoveryRepayment, newRepaymentTransaction);
final LoanTransactionBusinessEvent transactionRepaymentEvent = getTransactionRepaymentTypeBusinessEvent(
repaymentTransactionType, isRecoveryRepayment, newRepaymentTransaction);
businessEventNotifierService.notifyPostBusinessEvent(new LoanBalanceChangedBusinessEvent(loan));
businessEventNotifierService.notifyPostBusinessEvent(transactionRepaymentEvent);
if (daysInArrears >= 90) {
if (daysInArrears >= minimumDaysInArrearsToSuspendLoanAccount) {
businessEventNotifierService.notifyPostBusinessEvent(new LoanInvoiceGenerationPostBusinessEvent(newRepaymentTransaction));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,17 @@ public RepeatStatus execute(@NotNull StepContribution contribution, @NotNull Chu
final LocalDate secondLastDayOfMonth = lastDayOfMonth.minusDays(1);
final boolean enableMonthlyInvoiceGenerationOnJobTrigger = this.configurationDomainService
.enableMonthlyInvoiceGenerationOnJobTrigger();
Long minimumDaysInArrearsToSuspendLoanAccount = this.configurationDomainService.retriveMinimumDaysInArrearsToSuspendLoanAccount();
if (minimumDaysInArrearsToSuspendLoanAccount == null) {
minimumDaysInArrearsToSuspendLoanAccount = 90L;
}
if (businessLocalDate.equals(secondLastDayOfMonth) || enableMonthlyInvoiceGenerationOnJobTrigger) {
final List<LoanProductParameterization> loanProductParameterizations = this.productParameterizationRepository.findAll();
final LoanInvoiceMapper loanInvoiceMapper = new LoanInvoiceMapper();
final String invoiceQuery = "SELECT " + loanInvoiceMapper.invoiceSchema();
final String creditNoteQuery = "SELECT " + loanInvoiceMapper.creditNoteSchema();
final List<LoanDocumentData> loanInvoiceDataList = this.jdbcTemplate.query(invoiceQuery, loanInvoiceMapper, firstDayOfMonth,
secondLastDayOfMonth);
secondLastDayOfMonth, minimumDaysInArrearsToSuspendLoanAccount);
final List<LoanDocumentData> groupedLoanInvoices = groupByClientIdAndProductType(loanInvoiceDataList);
final List<FacturaElectronicaMensual> facturaElectronicaMensuals = new ArrayList<>();
for (final LoanDocumentData groupedLoanInvoice : groupedLoanInvoices) {
Expand All @@ -92,7 +96,7 @@ public RepeatStatus execute(@NotNull StepContribution contribution, @NotNull Chu
this.facturaElectronicMensualRepository.saveAllAndFlush(facturaElectronicaMensuals);
this.productParameterizationRepository.saveAllAndFlush(loanProductParameterizations);
final List<LoanDocumentData> loanCreditNoteDataList = this.jdbcTemplate.query(creditNoteQuery, loanInvoiceMapper,
firstDayOfMonth, secondLastDayOfMonth);
firstDayOfMonth, secondLastDayOfMonth, minimumDaysInArrearsToSuspendLoanAccount);
final List<LoanDocumentData> groupedLoanCreditNotes = groupByClientIdAndProductType(loanCreditNoteDataList);
for (final LoanDocumentData groupedLoanCreditNote : groupedLoanCreditNotes) {
groupedLoanCreditNote.setDocumentType(LoanDocumentData.LoanDocumentType.CREDIT_NOTE);
Expand Down Expand Up @@ -368,7 +372,7 @@ LEFT JOIN (
GROUP BY mlc.loan_id
) voluntary_insurance_code ON voluntary_insurance_code.loan_id = ml.id
WHERE ml.loan_status_id = 300
AND COALESCE(CURRENT_DATE - mlaa.overdue_since_date_derived::DATE, 0) < 90
AND COALESCE(CURRENT_DATE - mlaa.overdue_since_date_derived::DATE, 0) < ?
AND mlt."totalPaid" > 0
ORDER BY mc.id, ml.id
""";
Expand Down Expand Up @@ -578,7 +582,7 @@ LEFT JOIN (
GROUP BY mlc.loan_id
) voluntary_insurance_code ON voluntary_insurance_code.loan_id = ml.id
WHERE ml.loan_status_id = 300
AND COALESCE(CURRENT_DATE - mlaa.overdue_since_date_derived::DATE, 0) < 90
AND COALESCE(CURRENT_DATE - mlaa.overdue_since_date_derived::DATE, 0) < ?
AND mlt."totalPaid" > 0
ORDER BY mc.id, ml.id
""";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
package org.apache.fineract.portfolio.loanaccount.jobs.suspensionduetodefaultCharges;

import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.infrastructure.jobs.service.JobName;
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
Expand Down Expand Up @@ -46,6 +47,9 @@ public class SuspensionDueToDefaultChargesConfig {
@Autowired
private LoanReadPlatformService loanReadPlatformService;

@Autowired
private ConfigurationDomainService configurationDomainService;

@Bean
protected Step suspensionDueToDefaultChargesStep() {
return new StepBuilder(JobName.INSURANCE_CHARGE_SUSPENSION_DUE_TO_DEFAULT.name(), jobRepository)
Expand All @@ -60,6 +64,6 @@ public Job temporarySuspensionDueToDefaultChargesJob() {

@Bean
public SuspensionDueToDefaultChargesTasklet suspensionDueToDefaultChargesTasklet() {
return new SuspensionDueToDefaultChargesTasklet(loanWritePlatformService, loanReadPlatformService);
return new SuspensionDueToDefaultChargesTasklet(loanWritePlatformService, loanReadPlatformService, configurationDomainService);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.portfolio.loanaccount.data.DefaultOrCancelInsuranceInstallmentData;
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
Expand All @@ -35,11 +36,16 @@ public class SuspensionDueToDefaultChargesTasklet implements Tasklet {

private final LoanWritePlatformService loanWritePlatformService;
private final LoanReadPlatformService loanReadPlatformService;
private final ConfigurationDomainService configurationDomainService;

@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
Long minimumDaysInArrearsToSuspendLoanAccount = this.configurationDomainService.retriveMinimumDaysInArrearsToSuspendLoanAccount();
if (minimumDaysInArrearsToSuspendLoanAccount == null) {
minimumDaysInArrearsToSuspendLoanAccount = 90L;
}
List<DefaultOrCancelInsuranceInstallmentData> defaultLoanIds = this.loanReadPlatformService
.getLoanDataWithDefaultMandatoryInsurance(90L);
.getLoanDataWithDefaultMandatoryInsurance(minimumDaysInArrearsToSuspendLoanAccount);
loanWritePlatformService.temporarySuspendDefaultInsuranceCharges(defaultLoanIds);

return RepeatStatus.FINISHED;
Expand Down
Loading

0 comments on commit 035aaa5

Please sign in to comment.