CsvImportService.java

package cz.vsb.crm.service.export;

import com.google.common.base.Preconditions;
import cz.vsb.crm.dto.ImportReport;
import cz.vsb.crm.model.Product;
import cz.vsb.crm.repository.ProductRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

@Service
@RequiredArgsConstructor
public class CsvImportService {

    private final ProductRepository productRepository;

    @Transactional
    public ImportReport importProducts(InputStream inputStream) throws IOException {
        int created = 0;
        int updated = 0;
        List<String> errors = new ArrayList<>();

        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
            reader.readLine();
            String line;
            int rowNumber = 1;
            while ((line = reader.readLine()) != null) {
                rowNumber++;
                if (line.isBlank()) {
                    continue;
                }
                try {
                    List<String> columns = CsvSupport.parseLine(line);
                    Preconditions.checkArgument(columns.size() >= 2 && !columns.get(1).isBlank(),
                            "missing product name");
                    String name = columns.get(1).trim();
                    String description = columns.size() > 2 ? columns.get(2) : null;
                    BigDecimal price = parsePrice(columns.size() > 3 ? columns.get(3) : null);
                    Integer stock = parseStock(columns.size() > 4 ? columns.get(4) : null);

                    Product product = productRepository.findFirstByName(name).orElse(null);
                    boolean isNew = product == null;
                    if (isNew) {
                        product = new Product();
                        product.setName(name);
                    }
                    product.setDescription(description);
                    product.setPrice(price);
                    product.setStock(stock);
                    productRepository.save(product);

                    if (isNew) {
                        created++;
                    } else {
                        updated++;
                    }
                } catch (RuntimeException ex) {
                    errors.add("Row " + rowNumber + ": " + ex.getMessage());
                }
            }
        }
        return new ImportReport(created, updated, errors);
    }

    private BigDecimal parsePrice(String raw) {
        if (raw == null || raw.isBlank()) {
            return BigDecimal.ZERO;
        }
        return new BigDecimal(raw.trim());
    }

    private Integer parseStock(String raw) {
        if (raw == null || raw.isBlank()) {
            return 0;
        }
        return Integer.valueOf(raw.trim());
    }
}