diff --git a/backend/src/main/java/com/petshop/backend/service/AdoptionService.java b/backend/src/main/java/com/petshop/backend/service/AdoptionService.java index 6a6c32e9..b99be2e2 100644 --- a/backend/src/main/java/com/petshop/backend/service/AdoptionService.java +++ b/backend/src/main/java/com/petshop/backend/service/AdoptionService.java @@ -56,6 +56,7 @@ public class AdoptionService { this.eventPublisher = eventPublisher; } + @Transactional(readOnly = true) public Page getAllAdoptions(String query, Long customerId, String status, Long storeId, LocalDate date, Pageable pageable) { String normalizedQuery = StringUtils.trimToNull(query); String normalizedStatus = StringUtils.trimToNull(status); @@ -72,6 +73,7 @@ public class AdoptionService { return adoptions.map(this::mapToResponse); } + @Transactional(readOnly = true) public AdoptionResponse getAdoptionById(Long id, Long customerId) { Adoption adoption = adoptionRepository.findById(id) .orElseThrow(() -> new ResourceNotFoundException("Adoption not found with id: " + id)); diff --git a/backend/src/main/java/com/petshop/backend/service/CouponService.java b/backend/src/main/java/com/petshop/backend/service/CouponService.java index 4cb9f295..173be890 100644 --- a/backend/src/main/java/com/petshop/backend/service/CouponService.java +++ b/backend/src/main/java/com/petshop/backend/service/CouponService.java @@ -28,16 +28,19 @@ public class CouponService { this.saleRepository = saleRepository; } + @Transactional(readOnly = true) public Page getAllCoupons(String query, Boolean active, Pageable pageable) { return couponRepository.searchCoupons(query, active, pageable).map(this::mapToResponse); } + @Transactional(readOnly = true) public CouponResponse getCouponById(Long id) { Coupon coupon = couponRepository.findById(id) .orElseThrow(() -> new ResourceNotFoundException("Coupon not found with id: " + id)); return mapToResponse(coupon); } + @Transactional(readOnly = true) public CouponResponse getCouponByCode(String code) { Coupon coupon = couponRepository.findByCouponCode(code) .orElseThrow(() -> new ResourceNotFoundException("Coupon not found with code: " + code)); diff --git a/backend/src/main/java/com/petshop/backend/service/InventoryService.java b/backend/src/main/java/com/petshop/backend/service/InventoryService.java index 021ed021..af133e68 100644 --- a/backend/src/main/java/com/petshop/backend/service/InventoryService.java +++ b/backend/src/main/java/com/petshop/backend/service/InventoryService.java @@ -29,12 +29,14 @@ public class InventoryService { this.storeRepository = storeRepository; } + @Transactional(readOnly = true) public Page getAllInventory(String query, Long storeId, Pageable pageable) { String normalizedQuery = StringUtils.trimToNull(query); Page inventory = inventoryRepository.searchInventory(normalizedQuery, storeId, pageable); return inventory.map(this::mapToResponse); } + @Transactional(readOnly = true) public InventoryResponse getInventoryById(Long id) { Inventory inventory = inventoryRepository.findById(id) .orElseThrow(() -> new ResourceNotFoundException("Inventory not found with id: " + id)); diff --git a/backend/src/main/java/com/petshop/backend/service/ProductService.java b/backend/src/main/java/com/petshop/backend/service/ProductService.java index fc292f36..ad4524fe 100644 --- a/backend/src/main/java/com/petshop/backend/service/ProductService.java +++ b/backend/src/main/java/com/petshop/backend/service/ProductService.java @@ -11,8 +11,6 @@ import com.petshop.backend.exception.BusinessException; import com.petshop.backend.exception.ResourceNotFoundException; import com.petshop.backend.repository.CategoryRepository; import com.petshop.backend.repository.ProductRepository; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.core.io.Resource; import org.springframework.http.MediaType; import org.springframework.data.domain.Page; @@ -27,8 +25,6 @@ import java.io.IOException; @Service public class ProductService { - private static final Logger log = LoggerFactory.getLogger(ProductService.class); - private final ProductRepository productRepository; private final CategoryRepository categoryRepository; private final CatalogImageStorageService catalogImageStorageService; @@ -39,11 +35,13 @@ public class ProductService { this.catalogImageStorageService = catalogImageStorageService; } + @Transactional(readOnly = true) public Page getAllProducts(String query, Long categoryId, Pageable pageable) { return productRepository.searchProducts(StringUtils.trimToNull(query), categoryId, pageable) .map(this::mapToResponse); } + @Transactional(readOnly = true) public ProductResponse getProductById(Long id) { Product product = productRepository.findById(id) .orElseThrow(() -> new ResourceNotFoundException("Product not found with id: " + id)); @@ -93,13 +91,13 @@ public class ProductService { @Transactional public void deleteProduct(Long id) { Product product = findProduct(id); - deleteStoredImageIfPresent(product.getImageUrl()); + catalogImageStorageService.deleteProductImageIfPresent(product.getImageUrl()); productRepository.delete(product); } @Transactional public void bulkDeleteProducts(BulkDeleteRequest request) { - productRepository.findAllById(request.getIds()).forEach(product -> deleteStoredImageIfPresent(product.getImageUrl())); + productRepository.findAllById(request.getIds()).forEach(product -> catalogImageStorageService.deleteProductImageIfPresent(product.getImageUrl())); productRepository.deleteAllById(request.getIds()); } @@ -107,7 +105,7 @@ public class ProductService { public ProductResponse uploadProductImage(Long id, MultipartFile file) throws IOException { validateImageFile(file); Product product = findProduct(id); - deleteStoredImageIfPresent(product.getImageUrl()); + catalogImageStorageService.deleteProductImageIfPresent(product.getImageUrl()); product.setImageUrl(catalogImageStorageService.storeProductImage(file)); return mapToResponse(productRepository.save(product)); } @@ -115,11 +113,12 @@ public class ProductService { @Transactional public ProductResponse deleteProductImage(Long id) { Product product = findProduct(id); - deleteStoredImageIfPresent(product.getImageUrl()); + catalogImageStorageService.deleteProductImageIfPresent(product.getImageUrl()); product.setImageUrl(null); return mapToResponse(productRepository.save(product)); } + @Transactional(readOnly = true) public ImagePayload loadProductImage(Long id) { Product product = findProduct(id); if (product.getImageUrl() == null || product.getImageUrl().isBlank()) { @@ -142,17 +141,6 @@ public class ProductService { ImageValidationUtil.validate(file); } - private void deleteStoredImageIfPresent(String storedImagePath) { - if (storedImagePath == null || storedImagePath.isBlank()) { - return; - } - try { - catalogImageStorageService.deleteProductImage(storedImagePath); - } catch (IOException | IllegalArgumentException e) { - log.warn("Failed to delete stored image {}: {}", storedImagePath, e.getMessage()); - } - } - private ProductResponse mapToResponse(Product product) { return new ProductResponse( product.getProdId(), diff --git a/backend/src/main/java/com/petshop/backend/service/ProductSupplierService.java b/backend/src/main/java/com/petshop/backend/service/ProductSupplierService.java index 0f6250d2..5adc79fb 100644 --- a/backend/src/main/java/com/petshop/backend/service/ProductSupplierService.java +++ b/backend/src/main/java/com/petshop/backend/service/ProductSupplierService.java @@ -34,6 +34,7 @@ public class ProductSupplierService { this.supplierRepository = supplierRepository; } + @Transactional(readOnly = true) public Page getAllProductSuppliers(String query, Long productId, Long supplierId, Pageable pageable) { String normalizedQuery = StringUtils.trimToNull(query); Pageable mappedPageable = mapSortProperties(pageable); @@ -41,6 +42,7 @@ public class ProductSupplierService { return productSuppliers.map(this::mapToResponse); } + @Transactional(readOnly = true) public ProductSupplierResponse getProductSupplierById(Long productId, Long supplierId) { ProductSupplier.ProductSupplierId id = new ProductSupplier.ProductSupplierId(productId, supplierId); ProductSupplier productSupplier = productSupplierRepository.findById(id) diff --git a/backend/src/main/java/com/petshop/backend/service/PurchaseOrderService.java b/backend/src/main/java/com/petshop/backend/service/PurchaseOrderService.java index 0f2a1d07..a6803d37 100644 --- a/backend/src/main/java/com/petshop/backend/service/PurchaseOrderService.java +++ b/backend/src/main/java/com/petshop/backend/service/PurchaseOrderService.java @@ -9,6 +9,7 @@ import com.petshop.backend.repository.PurchaseOrderRepository; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service public class PurchaseOrderService { @@ -19,12 +20,14 @@ public class PurchaseOrderService { this.purchaseOrderRepository = purchaseOrderRepository; } + @Transactional(readOnly = true) public Page getAllPurchaseOrders(String query, Long storeId, Pageable pageable) { String normalizedQuery = StringUtils.trimToNull(query); Page purchaseOrders = purchaseOrderRepository.searchPurchaseOrders(normalizedQuery, storeId, pageable); return purchaseOrders.map(this::mapToResponse); } + @Transactional(readOnly = true) public PurchaseOrderResponse getPurchaseOrderById(Long id) { PurchaseOrder purchaseOrder = purchaseOrderRepository.findById(id) .orElseThrow(() -> new ResourceNotFoundException("PurchaseOrder not found with id: " + id)); diff --git a/backend/src/main/java/com/petshop/backend/service/UserService.java b/backend/src/main/java/com/petshop/backend/service/UserService.java index d5cd1243..99e25747 100644 --- a/backend/src/main/java/com/petshop/backend/service/UserService.java +++ b/backend/src/main/java/com/petshop/backend/service/UserService.java @@ -44,6 +44,7 @@ public class UserService { this.userAuthCacheService = userAuthCacheService; } + @Transactional(readOnly = true) public Page getAllUsers(String query, String role, Pageable pageable) { User.Role parsedRole = parseRole(role); Page users; @@ -60,6 +61,7 @@ public class UserService { return users.map(this::mapToResponse); } + @Transactional(readOnly = true) public UserResponse getUserById(Long id) { return getUserById(id, null); }