adamsaghy commented on code in PR #4046:
URL: https://github.com/apache/fineract/pull/4046#discussion_r1744139685


##########
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java:
##########
@@ -295,6 +303,139 @@ public CommandProcessingResult disburseLoan(Long loanId, 
JsonCommand command, Bo
         return disburseLoan(loanId, command, isAccountTransfer, false);
     }
 
+    @Transactional
+    @Override
+    public CommandProcessingResult disburseLoanToLinkedAccount(Long loanId, 
JsonCommand command, Boolean isAccountTransfer) {
+        Boolean isWithoutAutoPayment = false;
+        boolean isPaymentHubIntegrationEnabled = 
configurationDomainService.isPaymentHubIntegrationEnabled();
+        if (!isPaymentHubIntegrationEnabled) {
+            throw new 
GlobalConfigurationNotEnabledException("enable-payment-hub-integration");
+        }
+        loanTransactionValidator.validateDisbursement(command, 
isAccountTransfer, loanId);
+
+        Loan loan = loanAssembler.assembleFrom(loanId);
+
+        if (loan.loanProduct().isDisallowExpectedDisbursements()) {
+            List<LoanDisbursementDetails> filteredList = 
loan.getDisbursementDetails().stream()
+                    .filter(disbursementDetails -> 
disbursementDetails.actualDisbursementDate() == null).toList();
+            // Check whether a new LoanDisbursementDetails is required
+            if (filteredList.isEmpty()) {
+                // create artificial 'tranche/expected disbursal' as current 
disburse code expects it for
+                // multi-disbursal products
+                final LocalDate artificialExpectedDate = 
loan.getExpectedDisbursedOnLocalDate();
+                LoanDisbursementDetails disbursementDetail = new 
LoanDisbursementDetails(artificialExpectedDate, null,
+                        loan.getDisbursedAmount(), null, false);
+                disbursementDetail.updateLoan(loan);
+                loan.getAllDisbursementDetails().add(disbursementDetail);
+            }
+        }
+
+        final LocalDate nextPossibleRepaymentDate = 
loan.getNextPossibleRepaymentDateForRescheduling();
+        final LocalDate rescheduledRepaymentDate = 
command.localDateValueOfParameterNamed("adjustRepaymentDate");
+        final LocalDate actualDisbursementDate = 
command.localDateValueOfParameterNamed("actualDisbursementDate");
+        if (!loan.isMultiDisburmentLoan()) {
+            loan.setActualDisbursementDate(actualDisbursementDate);
+        }
+
+        // validate actual disbursement date against meeting date
+        ScheduleGeneratorDTO scheduleGeneratorDTO = 
this.loanUtilService.buildScheduleGeneratorDTO(loan, null);
+
+        final AppUser currentUser = getAppUserIfPresent();
+        final Map<String, Object> changes = new LinkedHashMap<>();
+
+        final PaymentDetail paymentDetail = 
this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, 
changes);
+        if (paymentDetail != null && paymentDetail.getPaymentType() != null && 
paymentDetail.getPaymentType().getIsCashPayment()) {
+            BigDecimal transactionAmount = 
command.bigDecimalValueOfParameterNamed("transactionAmount");
+            
this.cashierTransactionDataValidator.validateOnLoanDisbursal(currentUser, 
loan.getCurrencyCode(), transactionAmount);
+        }
+        final boolean isPaymentTypeApplicableForDisbursementCharge = 
configurationDomainService
+                .isPaymentTypeApplicableForDisbursementCharge();
+
+        Money amountBeforeAdjust = loan.getPrincipal();
+        final Locale locale = command.extractLocale();
+        final DateTimeFormatter fmt = 
DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
+
+        if (loan.canDisburse()) {
+            // Get netDisbursalAmount from disbursal screen field.
+            final BigDecimal netDisbursalAmount = command
+                    
.bigDecimalValueOfParameterNamed(LoanApiConstants.disbursementNetDisbursalAmountParameterName);
+            if (netDisbursalAmount != null) {
+                loan.setNetDisbursalAmount(netDisbursalAmount);
+            }
+            Money disburseAmount = loan.adjustDisburseAmount(command, 
actualDisbursementDate);
+            boolean recalculateSchedule = 
amountBeforeAdjust.isNotEqualTo(loan.getPrincipal());
+            final ExternalId txnExternalId = 
externalIdFactory.createFromCommand(command, 
LoanApiConstants.externalIdParameterName);
+
+            if (loan.isTopup() && loan.getClientId() != null) {
+                final Long loanIdToClose = 
loan.getTopupLoanDetails().getLoanIdToClose();
+                final Loan loanToClose = 
this.loanRepositoryWrapper.findNonClosedLoanThatBelongsToClient(loanIdToClose, 
loan.getClientId());
+                if (loanToClose == null) {
+                    throw new 
GeneralPlatformDomainRuleException("error.msg.loan.to.be.closed.with.topup.is.not.active",
+                            "Loan to be closed with this topup is not 
active.");
+                }
+                final LocalDate lastUserTransactionOnLoanToClose = 
loanToClose.getLastUserTransactionDate();
+                if (DateUtils.isBefore(loan.getDisbursementDate(), 
lastUserTransactionOnLoanToClose)) {
+                    throw new GeneralPlatformDomainRuleException(
+                            
"error.msg.loan.disbursal.date.should.be.after.last.transaction.date.of.loan.to.be.closed",
+                            "Disbursal date of this loan application " + 
loan.getDisbursementDate()
+                                    + " should be after last transaction date 
of loan to be closed " + lastUserTransactionOnLoanToClose);
+                }
+
+                BigDecimal loanOutstanding = this.loanReadPlatformService
+                        
.retrieveLoanPrePaymentTemplate(LoanTransactionType.REPAYMENT, loanIdToClose, 
actualDisbursementDate).getAmount();
+                final BigDecimal firstDisbursalAmount = 
loan.getFirstDisbursalAmount();
+                if (loanOutstanding.compareTo(firstDisbursalAmount) > 0) {
+                    throw new 
GeneralPlatformDomainRuleException("error.msg.loan.amount.less.than.outstanding.of.loan.to.be.closed",
+                            "Topup loan amount should be greater than 
outstanding amount of loan to be closed.");
+                }
+            }
+            if (loan.getRepaymentScheduleInstallments().isEmpty()) {
+                /*
+                 * If no schedule, generate one (applicable to non-tranche 
multi-disbursal loans)
+                 */
+                recalculateSchedule = true;
+            }
+
+            regenerateScheduleOnDisbursement(command, loan, 
recalculateSchedule, scheduleGeneratorDTO, nextPossibleRepaymentDate,
+                    rescheduledRepaymentDate);
+            boolean downPaymentEnabled = 
loan.repaymentScheduleDetail().isEnableDownPayment();
+            if 
(loan.repaymentScheduleDetail().isInterestRecalculationEnabled() || 
downPaymentEnabled) {
+                createAndSaveLoanScheduleArchive(loan, scheduleGeneratorDTO);
+            }
+        }
+
+        final PortfolioAccountData portfolioAccountData = 
this.accountAssociationsReadPlatformService
+                .retriveLoanLinkedAssociation(loan.getId());
+        if (portfolioAccountData == null) {
+            final String errorMessage = "Disburse Loan with id:" + 
loan.getId() + " requires linked savings account for payment";
+            throw new 
LinkedAccountRequiredException("loan.disburse.to.savings", errorMessage, 
loan.getId());
+        }
+
+        InteropIdentifier identifier1 = 
interopService.getIdentifierByAccountId(portfolioAccountData.getId());
+        String payerIdentifierType = 
InteropIdentifierType.ACCOUNT_ID.toString();
+        String payerIdentifierValue = loan.getAccountNumber();
+        String payeeIdentifierType = identifier1.getType().toString();
+        String payeeIdentifierValue = identifier1.getValue();
+        String currency = amountBeforeAdjust.getCurrencyCode();
+        String amount = 
Integer.toString(amountBeforeAdjust.getAmount().intValue());
+        SdkDisbursalService sdkDisbursalService = new 
SdkDisbursalServiceImpl();
+        try {
+            String id = 
sdkDisbursalService.processDisbursal(payerIdentifierType, payerIdentifierValue, 
payeeIdentifierType,
+                    payeeIdentifierValue, amount, currency);
+            logger.info("Payment hub transaction started with transaction id: 
" + id);
+        } catch (Exception e) {
+            logger.error(e.getMessage());

Review Comment:
   Please dont just silently swallow the outcome. How can the `disbursement` 
action be successful when the `sdkDisbursalService` failed for any reason...
   
   Please review this logic!



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to