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());
}
}