SettleDebtRentalsService.java

package com.github.jenkaby.bikerental.rental.application.service;

import com.github.jenkaby.bikerental.finance.FinanceFacade;
import com.github.jenkaby.bikerental.rental.application.usecase.SettleDebtUseCase;
import com.github.jenkaby.bikerental.rental.domain.model.Rental;
import com.github.jenkaby.bikerental.rental.domain.repository.RentalRepository;
import com.github.jenkaby.bikerental.shared.exception.OverBudgetSettlementException;
import com.github.jenkaby.bikerental.shared.exception.ResourceNotFoundException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@RequiredArgsConstructor
@Service
class SettleDebtRentalsService implements SettleDebtUseCase {

    private final RentalRepository rentalRepository;
    private final FinanceFacade financeFacade;

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public SettleDebtResult execute(SettleDebtCommand command) {
        Rental rental = rentalRepository.findById(command.rentalRef().id())
                .orElseThrow(() -> new ResourceNotFoundException(Rental.class, command.rentalRef().id().toString()));

        try {
            financeFacade.settleRental(
                    command.customerRef(),
                    command.rentalRef(),
                    rental.getFinalCost(),
                    command.operatorId()
            );
            rental.completeForDebt();
            rentalRepository.save(rental);
            log.info("DEBT rental {} settled successfully for customer {}",
                    command.rentalRef().id(), command.customerRef().id());
            return SettleDebtResult.success();
        } catch (OverBudgetSettlementException e) {
            log.warn("DEBT rental {} could not be settled — insufficient funds {} for customer {}",
                    command.rentalRef().id(), e.getDetails().availableAmount(), command.customerRef().id());
            return SettleDebtResult.failure();
        }
    }
}