From af97d8689d4040462e3e9756257044e2d3c14e2b Mon Sep 17 00:00:00 2001 From: Julius Peter Oketayot Date: Tue, 10 Dec 2024 18:12:57 +0300 Subject: [PATCH] =?UTF-8?q?Feature/SU-461-SU-507:=20SMS=20-=20Parametrizac?= =?UTF-8?q?i=C3=B3n=20|=20Suspended=20to=20be=20parametrized?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/ConfigurationDomainService.java | 2 + .../service/SmsCampaignDomainServiceImpl.java | 124 +++++++++--------- .../domain/ConfigurationDomainServiceJpa.java | 7 + .../domain/LoanAccountDomainServiceJpa.java | 11 +- .../FacturaElectronicaMensualTasklet.java | 12 +- .../SuspensionDueToDefaultChargesConfig.java | 6 +- .../SuspensionDueToDefaultChargesTasklet.java | 8 +- .../service/LoanArrearsAgingServiceImpl.java | 11 +- .../LoanCreditNoteWriteServiceImpl.java | 8 +- ...WritePlatformServiceJpaRepositoryImpl.java | 6 +- .../starter/LoanAccountConfiguration.java | 4 +- ...008011009141_SU_200_electronic_invoice.xml | 17 +++ 12 files changed, 140 insertions(+), 76 deletions(-) diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java index a0a6af41142..7f3a95f9814 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java @@ -152,6 +152,8 @@ public interface ConfigurationDomainService { Long retriveMinimumDaysOfArrearsToWriteOff(); + Long retriveMinimumDaysInArrearsToSuspendLoanAccount(); + Long retrieveInvoiceResolutionExpiryDays(); Long retrieveInvoiceThreshold(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignDomainServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignDomainServiceImpl.java index d32c3d9f07f..bfa3472a06f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignDomainServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignDomainServiceImpl.java @@ -298,71 +298,77 @@ private void notifyWriteOffLoanOwner(final LoanTransaction loanTransaction) { } } - private void sendSmsForLoanRepayment(LoanTransaction loanTransaction) { - List smsCampaigns = retrieveSmsCampaigns("Loan Repayment"); - if (!smsCampaigns.isEmpty()) { - for (SmsCampaign smsCampaign : smsCampaigns) { - try { - Loan loan = loanTransaction.getLoan(); - final Set 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 campaignParams = new ObjectMapper().readValue(smsCampaign.getParamValue(), - new TypeReference<>() { - - }); - - if (!groupClients.isEmpty()) { - for (Client client : groupClients) { - HashMap smsParams = processRepaymentDataForSms(loanTransaction, client); - for (Map.Entry 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 smsCampaigns = retrieveSmsCampaigns("Loan Repayment"); + if (!smsCampaigns.isEmpty()) { + for (SmsCampaign smsCampaign : smsCampaigns) { + try { + final Set 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 campaignParams = new ObjectMapper().readValue(smsCampaign.getParamValue(), + new TypeReference<>() { + + }); + + if (!groupClients.isEmpty()) { + for (Client client : groupClients) { + HashMap smsParams = processRepaymentDataForSms(loanTransaction, client); + for (Map.Entry 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> 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> 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); } } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java index 826977a7f12..9820b14f780 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java @@ -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); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java index 42add4cc06d..1fc653ac67e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java @@ -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)); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/facturaelectronicamensual/FacturaElectronicaMensualTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/facturaelectronicamensual/FacturaElectronicaMensualTasklet.java index 39015f6ee4c..d612856375c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/facturaelectronicamensual/FacturaElectronicaMensualTasklet.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/facturaelectronicamensual/FacturaElectronicaMensualTasklet.java @@ -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 loanProductParameterizations = this.productParameterizationRepository.findAll(); final LoanInvoiceMapper loanInvoiceMapper = new LoanInvoiceMapper(); final String invoiceQuery = "SELECT " + loanInvoiceMapper.invoiceSchema(); final String creditNoteQuery = "SELECT " + loanInvoiceMapper.creditNoteSchema(); final List loanInvoiceDataList = this.jdbcTemplate.query(invoiceQuery, loanInvoiceMapper, firstDayOfMonth, - secondLastDayOfMonth); + secondLastDayOfMonth, minimumDaysInArrearsToSuspendLoanAccount); final List groupedLoanInvoices = groupByClientIdAndProductType(loanInvoiceDataList); final List facturaElectronicaMensuals = new ArrayList<>(); for (final LoanDocumentData groupedLoanInvoice : groupedLoanInvoices) { @@ -92,7 +96,7 @@ public RepeatStatus execute(@NotNull StepContribution contribution, @NotNull Chu this.facturaElectronicMensualRepository.saveAllAndFlush(facturaElectronicaMensuals); this.productParameterizationRepository.saveAllAndFlush(loanProductParameterizations); final List loanCreditNoteDataList = this.jdbcTemplate.query(creditNoteQuery, loanInvoiceMapper, - firstDayOfMonth, secondLastDayOfMonth); + firstDayOfMonth, secondLastDayOfMonth, minimumDaysInArrearsToSuspendLoanAccount); final List groupedLoanCreditNotes = groupByClientIdAndProductType(loanCreditNoteDataList); for (final LoanDocumentData groupedLoanCreditNote : groupedLoanCreditNotes) { groupedLoanCreditNote.setDocumentType(LoanDocumentData.LoanDocumentType.CREDIT_NOTE); @@ -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 """; @@ -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 """; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/suspensionduetodefaultCharges/SuspensionDueToDefaultChargesConfig.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/suspensionduetodefaultCharges/SuspensionDueToDefaultChargesConfig.java index 63aba9b7879..e0c5a0b0de5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/suspensionduetodefaultCharges/SuspensionDueToDefaultChargesConfig.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/suspensionduetodefaultCharges/SuspensionDueToDefaultChargesConfig.java @@ -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; @@ -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) @@ -60,6 +64,6 @@ public Job temporarySuspensionDueToDefaultChargesJob() { @Bean public SuspensionDueToDefaultChargesTasklet suspensionDueToDefaultChargesTasklet() { - return new SuspensionDueToDefaultChargesTasklet(loanWritePlatformService, loanReadPlatformService); + return new SuspensionDueToDefaultChargesTasklet(loanWritePlatformService, loanReadPlatformService, configurationDomainService); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/suspensionduetodefaultCharges/SuspensionDueToDefaultChargesTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/suspensionduetodefaultCharges/SuspensionDueToDefaultChargesTasklet.java index 84680571280..0b3cd9df5b0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/suspensionduetodefaultCharges/SuspensionDueToDefaultChargesTasklet.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/suspensionduetodefaultCharges/SuspensionDueToDefaultChargesTasklet.java @@ -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; @@ -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 defaultLoanIds = this.loanReadPlatformService - .getLoanDataWithDefaultMandatoryInsurance(90L); + .getLoanDataWithDefaultMandatoryInsurance(minimumDaysInArrearsToSuspendLoanAccount); loanWritePlatformService.temporarySuspendDefaultInsuranceCharges(defaultLoanIds); return RepeatStatus.FINISHED; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanArrearsAgingServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanArrearsAgingServiceImpl.java index 9e1bedf542e..b9f1f17a59d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanArrearsAgingServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanArrearsAgingServiceImpl.java @@ -32,6 +32,7 @@ import org.apache.fineract.infrastructure.clientblockingreasons.domain.BlockLevel; import org.apache.fineract.infrastructure.clientblockingreasons.domain.BlockingReasonSetting; import org.apache.fineract.infrastructure.clientblockingreasons.domain.BlockingReasonSettingsRepositoryWrapper; +import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; import org.apache.fineract.infrastructure.core.domain.JdbcSupport; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.MathUtil; @@ -88,7 +89,7 @@ public class LoanArrearsAgingServiceImpl implements LoanArrearsAgingService { private final PlatformSecurityContext context; private final InsuranceIncidentRepository insuranceIncidentRepository; private final InsuranceIncidentNoveltyNewsRepository insuranceIncidentNoveltyNewsRepository; - private final LoanReadPlatformService loanReadPlatformService; + private final ConfigurationDomainService configurationDomainService; @PostConstruct public void registerForNotification() { @@ -642,6 +643,10 @@ private void handleUnBlockingCredit(Loan loan) { } private void createSuspensionRemovedNews(Loan loan) { + Long minimumDaysInArrearsToSuspendLoanAccount = this.configurationDomainService.retriveMinimumDaysInArrearsToSuspendLoanAccount(); + if (minimumDaysInArrearsToSuspendLoanAccount == null) { + minimumDaysInArrearsToSuspendLoanAccount = 90L; + } /// CREATE Salida de suspensiĆ³n news if loan is in TEMPORARY_SUSPENSION_DUE_TO_DEFAULT novelty news status and /// arrears less than 90 days Integer daysInArrears = null; @@ -653,7 +658,7 @@ private void createSuspensionRemovedNews(Loan loan) { // not in arrears daysInArrears = 0; } - if (daysInArrears >= 90) { + if (daysInArrears >= minimumDaysInArrearsToSuspendLoanAccount) { // In case of transaction rollback, a loan can move again to suspension LocalDate date = null; try { @@ -664,7 +669,7 @@ private void createSuspensionRemovedNews(Loan loan) { // not in arrears } if (date != null) { - temporarySuspendDefaultInsuranceCharges(loan, date.plusDays(90)); + temporarySuspendDefaultInsuranceCharges(loan, date.plusDays(minimumDaysInArrearsToSuspendLoanAccount)); } return; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanCreditNoteWriteServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanCreditNoteWriteServiceImpl.java index eece56a2788..cc098b0e6e1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanCreditNoteWriteServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanCreditNoteWriteServiceImpl.java @@ -13,6 +13,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.fineract.custom.infrastructure.core.service.CustomDateUtils; import org.apache.fineract.infrastructure.bulkimport.importhandler.helper.DateSerializer; +import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException; @@ -54,6 +55,7 @@ public class LoanCreditNoteWriteServiceImpl implements LoanCreditNoteWriteServic private final BusinessEventNotifierService businessEventNotifierService; private final LoanTransactionRepository loanTransactionRepository; private final DelinquencyReadPlatformService delinquencyReadPlatformService; + private final ConfigurationDomainService configurationDomainService; @Override public CommandProcessingResult addLoanCreditNote(Long loanId, JsonCommand command) { @@ -70,7 +72,11 @@ public CommandProcessingResult addLoanCreditNote(Long loanId, JsonCommand comman final LoanCreditNote creditNote = this.assembleLoanCreditNote(loan, command); final LoanTransaction loanTransaction = this.loanTransactionRepository.findById(creditNote.getTransactionId()) .orElseThrow(() -> new LoanTransactionNotFoundException(creditNote.getTransactionId())); - if (daysInArrears >= 90) { + Long minimumDaysInArrearsToSuspendLoanAccount = this.configurationDomainService.retriveMinimumDaysInArrearsToSuspendLoanAccount(); + if (minimumDaysInArrearsToSuspendLoanAccount == null) { + minimumDaysInArrearsToSuspendLoanAccount = 90L; + } + if (daysInArrears >= minimumDaysInArrearsToSuspendLoanAccount) { this.businessEventNotifierService.notifyPostBusinessEvent(new LoanCreditNoteBusinessEvent(loanTransaction)); } return CommandProcessingResult.commandOnlyResult(creditNote.getId()); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java index 287720dde43..36a1cd6c065 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -1184,6 +1184,10 @@ public CommandProcessingResult makeLoanRepaymentWithChargeRefundChargeType(final } Loan loan = this.loanAssembler.assembleFrom(loanId); final LoanProduct loanProduct = loan.loanProduct(); + if (!loanProduct.getCustomAllowCollections()) { + throw new GeneralPlatformDomainRuleException("error.msg.loan.collection.not.allowed.on.this.product", + "Collection is not allowed for this loan product", loanProduct.getName()); + } final Long repaymentChannelId = command.longValueOfParameterNamed("repaymentChannelId"); final boolean isImportedTransaction = command.booleanPrimitiveValueOfParameterNamed("isImportedTransaction"); ChannelData channelData; @@ -4134,7 +4138,7 @@ public void processAndSaveLoanDocument(final LoanDocumentData loanDocumentData) facturaElectronicaMensual.setDescuento(BigDecimal.ZERO); facturaElectronicaMensual.setPorcentaje_impuesto_item(BigDecimal.ZERO); facturaElectronicaMensual.setImpuesto_item(BigDecimal.ZERO); - long itemPosition = 1L; + long itemPosition = 0L; if (interestPaid.compareTo(BigDecimal.ZERO) > 0) { final LoanDocumentConcept loanDocumentConcept = LoanDocumentConcept.INT_CORRIENTE; final FacturaElectronicaMensual facturaElectronicaMensualDuplicate = facturaElectronicaMensual.clone(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java index b699c958d7f..c135beb87b6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java @@ -273,10 +273,10 @@ public LoanArrearsAgingService loanArrearsAgingService(JdbcTemplate jdbcTemplate BlockingReasonSettingsRepositoryWrapper blockingReasonSettingsRepositoryWrapper, LoanRepository loanRepository, PlatformSecurityContext context, InsuranceIncidentRepository insuranceIncidentRepository, InsuranceIncidentNoveltyNewsRepository insuranceIncidentNoveltyNewsRepository, - LoanReadPlatformService loanReadPlatformService) { + ConfigurationDomainService configurationDomainService) { return new LoanArrearsAgingServiceImpl(jdbcTemplate, businessEventNotifierService, sqlGenerator, clientWritePlatformService, loanBlockWritePlatformService, blockingReasonSettingsRepositoryWrapper, loanRepository, context, - insuranceIncidentRepository, insuranceIncidentNoveltyNewsRepository, loanReadPlatformService); + insuranceIncidentRepository, insuranceIncidentNoveltyNewsRepository, configurationDomainService); } @Bean diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/20243008011009141_SU_200_electronic_invoice.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/20243008011009141_SU_200_electronic_invoice.xml index 233437c01c9..b78a97df4d5 100644 --- a/fineract-provider/src/main/resources/db/changelog/tenant/parts/20243008011009141_SU_200_electronic_invoice.xml +++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/20243008011009141_SU_200_electronic_invoice.xml @@ -411,4 +411,21 @@ + + + + SELECT COUNT(*) FROM c_configuration WHERE name = 'Dias a partir de los cuales empezar a considerar suspendido' + + + + + + + + + + + + +