LeadService.java

package cz.vsb.crm.service;

import cz.vsb.crm.dto.LeadLineRequest;
import cz.vsb.crm.dto.LeadLineResponse;
import cz.vsb.crm.dto.LeadProductView;
import cz.vsb.crm.dto.LeadRequest;
import cz.vsb.crm.dto.LeadResponse;
import cz.vsb.crm.exception.ResourceNotFoundException;
import cz.vsb.crm.model.Lead;
import cz.vsb.crm.model.LeadProduct;
import cz.vsb.crm.model.Product;
import cz.vsb.crm.repository.AccountRepository;
import cz.vsb.crm.repository.LeadProductRepository;
import cz.vsb.crm.repository.LeadRepository;
import cz.vsb.crm.repository.ProductRepository;
import cz.vsb.crm.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@RequiredArgsConstructor
@Transactional
public class LeadService {

    private final LeadRepository leadRepository;
    private final LeadProductRepository leadProductRepository;
    private final AccountRepository accountRepository;
    private final UserRepository userRepository;
    private final ProductRepository productRepository;

    @Transactional(readOnly = true)
    public List<LeadResponse> findAll() {
        return leadRepository.findAll().stream().map(LeadResponse::from).toList();
    }

    @Transactional(readOnly = true)
    public LeadResponse findById(Long id) {
        return LeadResponse.from(get(id));
    }

    public LeadResponse create(LeadRequest request) {
        return LeadResponse.from(save(new Lead(), request));
    }

    public LeadResponse update(Long id, LeadRequest request) {
        return LeadResponse.from(save(get(id), request));
    }

    public void delete(Long id) {
        leadRepository.delete(get(id));
    }

    @Transactional(readOnly = true)
    public List<LeadLineResponse> getProducts(Long id) {
        return get(id).getLeadProducts().stream().map(LeadLineResponse::from).toList();
    }

    @Transactional(readOnly = true)
    public List<LeadProductView> getAllProductLines() {
        return leadProductRepository.findAll().stream().map(LeadProductView::from).toList();
    }

    private Lead get(Long id) {
        return leadRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("Lead", id));
    }

    private Lead save(Lead lead, LeadRequest request) {
        lead.setAccount(accountRepository.findById(request.accountId())
                .orElseThrow(() -> new ResourceNotFoundException("Account", request.accountId())));
        lead.setAssignedTo(request.assignedToId() == null ? null
                : userRepository.findById(request.assignedToId())
                        .orElseThrow(() -> new ResourceNotFoundException("User", request.assignedToId())));
        if (request.source() != null) {
            lead.setSource(request.source());
        }
        if (request.status() != null) {
            lead.setStatus(request.status());
        }
        lead.setValue(request.value());
        if (request.createdDate() != null) {
            lead.setCreatedDate(request.createdDate());
        }

        lead.getLeadProducts().clear();
        leadRepository.saveAndFlush(lead);

        if (request.products() != null) {
            for (LeadLineRequest line : request.products()) {
                Product product = productRepository.findById(line.productId())
                        .orElseThrow(() -> new ResourceNotFoundException("Product", line.productId()));
                LeadProduct leadProduct = new LeadProduct();
                leadProduct.setLead(lead);
                leadProduct.setProduct(product);
                leadProduct.setQuantity(line.quantity());
                lead.getLeadProducts().add(leadProduct);
            }
        }
        return leadRepository.save(lead);
    }
}