OrderService.java
package com.ctrlbuy.webshop.service;
import com.ctrlbuy.webshop.entity.Cart;
import com.ctrlbuy.webshop.entity.CartItem;
import com.ctrlbuy.webshop.entity.Order;
import com.ctrlbuy.webshop.entity.OrderItem;
import com.ctrlbuy.webshop.security.entity.User;
import com.ctrlbuy.webshop.repository.OrderRepository;
// ===== JPA IMPORTS =====
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.Query;
// ===== SPRING IMPORTS =====
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
// ===== LOGGING IMPORTS =====
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* đĄïž RAILWAY COMPATIBLE OrderService
* KOMPLETT VERSION MED ALLA IMPORTER OCH METODER
*/
@Service
@Transactional
public class OrderService {
private static final Logger logger = LoggerFactory.getLogger(OrderService.class);
private final OrderRepository orderRepository;
private final UserService userService;
@PersistenceContext
private EntityManager entityManager;
// Constructor injection
public OrderService(OrderRepository orderRepository, UserService userService) {
this.orderRepository = orderRepository;
this.userService = userService;
logger.info("â
OrderService initialiserad med Repository och UserService");
}
// ===== ADMIN METHODS FOR ADMIN CONTROLLER - ENTITYMANAGER VERSIONER =====
/**
* Get all orders (for admin) - ANVĂND ENTITYMANAGER
*/
public List<Order> getAllOrders() {
try {
Query query = entityManager.createQuery(
"SELECT o FROM Order o ORDER BY o.orderDate DESC", Order.class);
@SuppressWarnings("unchecked")
List<Order> results = query.getResultList();
logger.info("â
HÀmtade {} orders för admin", results.size());
return results;
} catch (Exception e) {
logger.error("Error fetching all orders", e);
return new ArrayList<>();
}
}
/**
* Get orders by user ID - ANVĂND ENTITYMANAGER
*/
public List<Order> getOrdersByUserId(Long userId) {
try {
Query query = entityManager.createQuery(
"SELECT o FROM Order o WHERE o.user.id = :userId ORDER BY o.orderDate DESC", Order.class);
query.setParameter("userId", userId);
@SuppressWarnings("unchecked")
List<Order> results = query.getResultList();
logger.info("â
HÀmtade {} orders för user ID: {}", results.size(), userId);
return results;
} catch (Exception e) {
logger.error("Error fetching orders for user: {}", userId, e);
return new ArrayList<>();
}
}
/**
* Get order by ID - ANVĂND ENTITYMANAGER
*/
public Order getOrderById(Long id) {
try {
Query query = entityManager.createQuery(
"SELECT o FROM Order o LEFT JOIN FETCH o.orderItems WHERE o.id = :id", Order.class);
query.setParameter("id", id);
@SuppressWarnings("unchecked")
List<Order> results = query.getResultList();
if (results.isEmpty()) {
logger.warn("Ingen order hittades med ID: {}", id);
return null;
}
Order order = results.get(0);
logger.info("â
Order hittades: {} (ID: {})", order.getOrderNumber(), id);
return order;
} catch (Exception e) {
logger.error("Error fetching order by ID: {}", id, e);
return null;
}
}
/**
* Update order status - ENKEL VERSION
*/
public void updateOrderStatus(Long orderId, String status) {
try {
Order order = entityManager.find(Order.class, orderId);
if (order != null) {
// SĂ€tt status som String direkt (Order entity hanterar konvertering)
order.setStatus(status);
entityManager.merge(order);
logger.info("Updated order {} status to {}", orderId, status);
} else {
logger.warn("Order med ID {} hittades inte", orderId);
}
} catch (Exception e) {
logger.error("Error updating order status", e);
}
}
/**
* Search orders by order number and user ID - ANVĂND ENTITYMANAGER
*/
public List<Order> searchOrdersByNumberAndUserId(String orderNumber, Long userId) {
try {
Query query = entityManager.createQuery(
"SELECT o FROM Order o WHERE o.orderNumber LIKE :orderPattern AND o.user.id = :userId ORDER BY o.orderDate DESC",
Order.class);
query.setParameter("orderPattern", "%" + orderNumber + "%");
query.setParameter("userId", userId);
@SuppressWarnings("unchecked")
List<Order> results = query.getResultList();
logger.info("â
Hittade {} orders för sökning: {} (user {})", results.size(), orderNumber, userId);
return results;
} catch (Exception e) {
logger.error("Error searching orders", e);
return new ArrayList<>();
}
}
/**
* Calculate total spent by user - ANVĂND ENTITYMANAGER
*/
public double getTotalSpentByUser(Long userId) {
try {
Query query = entityManager.createQuery(
"SELECT COALESCE(SUM(o.totalAmount), 0.0) FROM Order o WHERE o.user.id = :userId");
query.setParameter("userId", userId);
Double total = (Double) query.getSingleResult();
if (total == null) {
total = 0.0;
}
logger.info("â
Total spenderat för user {}: {} kr", userId, total);
return total;
} catch (Exception e) {
logger.error("Error calculating total spent for user: {}", userId, e);
return 0.0;
}
}
// ===== BEFINTLIGA METODER - SAKNADE METODER FĂR COMPILATION FIX =====
/**
* â
NYTT: getLatestOrderByUser - HÀmta senaste order för anvÀndare (för OrderHistoryController)
*/
public Optional<Order> getLatestOrderByUser(User user) {
try {
logger.info("đ HĂ€mtar senaste order för anvĂ€ndare: {}", user.getUsername());
Query query = entityManager.createQuery(
"SELECT o FROM Order o WHERE o.user = :user ORDER BY o.orderDate DESC", Order.class);
query.setParameter("user", user);
query.setMaxResults(1); // Bara första (senaste) resultat
@SuppressWarnings("unchecked")
List<Order> results = query.getResultList();
if (results.isEmpty()) {
logger.info("âčïž Ingen order hittades för anvĂ€ndare: {}", user.getUsername());
return Optional.empty();
}
Order latestOrder = results.get(0);
logger.info("â
Senaste order hittades: {} för anvÀndare {}",
latestOrder.getOrderNumber(), user.getUsername());
return Optional.of(latestOrder);
} catch (Exception e) {
logger.error("â Fel vid hĂ€mtning av senaste order för anvĂ€ndare {}: {}",
user.getUsername(), e.getMessage());
return Optional.empty();
}
}
/**
* â
NYTT: getOrderByOrderNumberAndUser - HÀmta order baserat pÄ ordernummer och anvÀndare (för OrderHistoryController)
*/
public Optional<Order> getOrderByOrderNumberAndUser(String orderNumber, User user) {
try {
logger.info("đ HĂ€mtar order {} för anvĂ€ndare: {}", orderNumber, user.getUsername());
if (orderNumber == null || orderNumber.trim().isEmpty()) {
logger.error("â Tomt ordernummer för anvĂ€ndare: {}", user.getUsername());
return Optional.empty();
}
Query query = entityManager.createQuery(
"SELECT o FROM Order o WHERE o.orderNumber = :orderNumber AND o.user = :user", Order.class);
query.setParameter("orderNumber", orderNumber.trim());
query.setParameter("user", user);
@SuppressWarnings("unchecked")
List<Order> results = query.getResultList();
if (results.isEmpty()) {
logger.warn("â ïž Ingen order med nummer {} hittades för anvĂ€ndare {}",
orderNumber, user.getUsername());
return Optional.empty();
}
Order order = results.get(0);
logger.info("â
Order {} hittades för anvÀndare {}",
order.getOrderNumber(), user.getUsername());
return Optional.of(order);
} catch (Exception e) {
logger.error("â Fel vid hĂ€mtning av order {} för anvĂ€ndare {}: {}",
orderNumber, user.getUsername(), e.getMessage());
return Optional.empty();
}
}
// ===== ORDER CREATION METHODS =====
/**
* đ Skapa bestĂ€llning frĂ„n checkout-formulĂ€r
*/
public Order createOrder(Cart cart, String email, String firstName, String lastName,
String address, String city, String postalCode, String phone,
String notes, String paymentMethod, Authentication auth) {
logger.info("đ Skapar order frĂ„n checkout för: {} {}", firstName, lastName);
try {
if (cart == null || cart.getItems().isEmpty()) {
logger.error("â Försöker skapa order med tom kundvagn");
throw new RuntimeException("Kundvagnen Àr tom");
}
// đĄïž SAFE USER LOOKUP - anvĂ€nd UserService istĂ€llet för repository direkt
User user = null;
if (auth != null && auth.isAuthenticated()) {
Optional<User> userOpt = userService.findByUsername(auth.getName());
user = userOpt.orElse(null);
if (user != null) {
logger.info("đ€ Order skapas för inloggad anvĂ€ndare: {}", user.getUsername());
} else {
logger.warn("â ïž AnvĂ€ndare inte hittad för autentiserad session: {}", auth.getName());
}
} else {
logger.info("đ€ Order skapas för gĂ€st");
}
// BerÀkna totaler
BigDecimal subtotal = cart.getTotalAmount();
BigDecimal shipping = BigDecimal.valueOf(49.00);
BigDecimal total = subtotal.add(shipping);
logger.info("đ° Order totaler - Subtotal: {}, Frakt: {}, Total: {}", subtotal, shipping, total);
// Generera ordernummer
String orderNumber = generateOrderNumber();
logger.info("đą Genererat ordernummer: {}", orderNumber);
// Skapa bestÀllning
Order order = new Order();
order.setUser(user);
order.setOrderNumber(orderNumber);
order.setTotalAmount(total.doubleValue());
order.setStatus(Order.OrderStatus.PENDING);
order.setOrderDate(LocalDateTime.now());
// Leveransadress
order.setDeliveryName(firstName + " " + lastName);
order.setDeliveryAddress(address);
order.setDeliveryCity(city);
order.setDeliveryPostalCode(postalCode);
order.setDeliveryPhone(phone);
order.setPaymentMethod(paymentMethod);
// Spara bestÀllning först
order = orderRepository.save(order);
logger.info("đŸ Bas-order sparad med ID: {}", order.getId());
// LÀgg till orderitems frÄn cart
for (CartItem cartItem : cart.getItems()) {
OrderItem orderItem = new OrderItem();
orderItem.setOrder(order);
orderItem.setProduct(cartItem.getProduct());
orderItem.setQuantity(cartItem.getQuantity());
orderItem.setPrice(cartItem.getUnitPrice().doubleValue());
orderItem.setProductName(cartItem.getProduct().getName());
order.addOrderItem(orderItem);
logger.info("đŠ Lagt till orderitem: {} x{}", cartItem.getProduct().getName(), cartItem.getQuantity());
}
// Spara igen med orderitems
order = orderRepository.save(order);
logger.info("â
Order komplett sparad: {} med {} items", orderNumber, order.getOrderItems().size());
return order;
} catch (Exception e) {
logger.error("â Fel vid skapande av order frĂ„n checkout: {}", e.getMessage(), e);
throw new RuntimeException("Kunde inte skapa bestÀllning: " + e.getMessage(), e);
}
}
/**
* đ Skapa ny bestĂ€llning frĂ„n kundvagn (för inloggade anvĂ€ndare)
*/
public Order createOrderFromCart(User user, List<com.ctrlbuy.webshop.controller.CartController.CartItem> cartItems, OrderDetails orderDetails) {
logger.info("đ Skapar order frĂ„n kundvagn för anvĂ€ndare: {}", user.getUsername());
try {
if (cartItems == null || cartItems.isEmpty()) {
logger.error("â Försöker skapa order med tom kundvagn för anvĂ€ndare: {}", user.getUsername());
throw new RuntimeException("Kundvagnen Àr tom");
}
// BerÀkna totaler
BigDecimal subtotal = cartItems.stream()
.map(com.ctrlbuy.webshop.controller.CartController.CartItem::getTotalPrice)
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal shipping = subtotal.compareTo(new BigDecimal("499")) >= 0
? BigDecimal.ZERO
: new BigDecimal("49");
BigDecimal total = subtotal.add(shipping);
logger.info("đ° User order totaler - Subtotal: {}, Frakt: {}, Total: {}", subtotal, shipping, total);
// Generera ordernummer
String orderNumber = generateOrderNumber();
logger.info("đą Genererat ordernummer för anvĂ€ndare: {}", orderNumber);
// Skapa bestÀllning
Order order = new Order();
order.setUser(user);
order.setOrderNumber(orderNumber);
order.setTotalAmount(total.doubleValue());
order.setStatus(Order.OrderStatus.PENDING);
order.setOrderDate(LocalDateTime.now());
// Leveransadress
order.setDeliveryName(orderDetails.getDeliveryName());
order.setDeliveryAddress(orderDetails.getDeliveryAddress());
order.setDeliveryCity(orderDetails.getDeliveryCity());
order.setDeliveryPostalCode(orderDetails.getDeliveryPostalCode());
order.setDeliveryPhone(orderDetails.getDeliveryPhone());
order.setPaymentMethod(orderDetails.getPaymentMethod());
// Spara bestÀllning först
order = orderRepository.save(order);
logger.info("đŸ User bas-order sparad med ID: {}", order.getId());
// LĂ€gg till orderitems
for (com.ctrlbuy.webshop.controller.CartController.CartItem cartItem : cartItems) {
OrderItem orderItem = new OrderItem();
orderItem.setOrder(order);
orderItem.setProduct(cartItem.getProduct());
orderItem.setQuantity(cartItem.getQuantity());
orderItem.setPrice(cartItem.getUnitPrice().doubleValue());
orderItem.setProductName(cartItem.getProduct().getName());
order.addOrderItem(orderItem);
logger.info("đŠ User orderitem tillagt: {} x{}", cartItem.getProduct().getName(), cartItem.getQuantity());
}
// Spara igen med orderitems
order = orderRepository.save(order);
logger.info("â
User order komplett: {} med {} items", orderNumber, order.getOrderItems().size());
return order;
} catch (Exception e) {
logger.error("â Fel vid skapande av user order: {}", e.getMessage(), e);
throw new RuntimeException("Kunde inte skapa anvÀndarens bestÀllning: " + e.getMessage(), e);
}
}
/**
* đ€ Skapa bestĂ€llning för icke-inloggad anvĂ€ndare (gĂ€st)
*/
public Order createGuestOrder(List<com.ctrlbuy.webshop.controller.CartController.CartItem> cartItems, GuestOrderDetails guestDetails) {
logger.info("đ€ Skapar gĂ€st-order för: {} {}", guestDetails.getFirstName(), guestDetails.getLastName());
try {
if (cartItems == null || cartItems.isEmpty()) {
logger.error("â Försöker skapa gĂ€st-order med tom kundvagn");
throw new RuntimeException("Kundvagnen Àr tom");
}
// BerÀkna totaler
BigDecimal subtotal = cartItems.stream()
.map(com.ctrlbuy.webshop.controller.CartController.CartItem::getTotalPrice)
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal shipping = subtotal.compareTo(new BigDecimal("499")) >= 0
? BigDecimal.ZERO
: new BigDecimal("49");
BigDecimal total = subtotal.add(shipping);
logger.info("đ° GĂ€st order totaler - Subtotal: {}, Frakt: {}, Total: {}", subtotal, shipping, total);
// Generera ordernummer
String orderNumber = generateOrderNumber();
logger.info("đą Genererat ordernummer för gĂ€st: {}", orderNumber);
// Skapa bestÀllning utan User
Order order = new Order();
order.setOrderNumber(orderNumber);
order.setTotalAmount(total.doubleValue());
order.setStatus(Order.OrderStatus.PENDING);
order.setOrderDate(LocalDateTime.now());
// Leveransadress frÄn gÀst
order.setDeliveryName(guestDetails.getFirstName() + " " + guestDetails.getLastName());
order.setDeliveryAddress(guestDetails.getAddress());
order.setDeliveryCity(guestDetails.getCity());
order.setDeliveryPostalCode(guestDetails.getPostalCode());
order.setDeliveryPhone(guestDetails.getPhone());
order.setPaymentMethod(guestDetails.getPaymentMethod());
// Spara bestÀllning först
order = orderRepository.save(order);
logger.info("đŸ GĂ€st bas-order sparad med ID: {}", order.getId());
// LĂ€gg till orderitems
for (com.ctrlbuy.webshop.controller.CartController.CartItem cartItem : cartItems) {
OrderItem orderItem = new OrderItem();
orderItem.setOrder(order);
orderItem.setProduct(cartItem.getProduct());
orderItem.setQuantity(cartItem.getQuantity());
orderItem.setPrice(cartItem.getUnitPrice().doubleValue());
orderItem.setProductName(cartItem.getProduct().getName());
order.addOrderItem(orderItem);
logger.info("đŠ GĂ€st orderitem tillagt: {} x{}", cartItem.getProduct().getName(), cartItem.getQuantity());
}
// Spara igen med orderitems
order = orderRepository.save(order);
logger.info("â
GĂ€st order komplett: {} med {} items", orderNumber, order.getOrderItems().size());
return order;
} catch (Exception e) {
logger.error("â Fel vid skapande av gĂ€st-order: {}", e.getMessage(), e);
throw new RuntimeException("Kunde inte skapa gÀst-bestÀllning: " + e.getMessage(), e);
}
}
// ===== SAFE ORDER LOOKUP METHODS =====
/**
* đĄïž SAFE findByOrderNumberAndUser - anvĂ€nder EntityManager
*/
public Order findByOrderNumberAndUser(String orderNumber, User user) {
try {
logger.info("đ Söker order med nummer {} för anvĂ€ndare: {}", orderNumber, user.getUsername());
Query query = entityManager.createQuery(
"SELECT o FROM Order o WHERE o.orderNumber = :orderNumber AND o.user = :user", Order.class);
query.setParameter("orderNumber", orderNumber);
query.setParameter("user", user);
@SuppressWarnings("unchecked")
List<Order> results = query.getResultList();
if (results.isEmpty()) {
logger.warn("â ïž Ingen order hittades med nummer {} för anvĂ€ndare {}", orderNumber, user.getUsername());
return null;
}
Order order = results.get(0);
logger.info("â
Order hittades: {} för anvÀndare {}", orderNumber, user.getUsername());
return order;
} catch (Exception e) {
logger.error("â Fel vid sökning av order {} för anvĂ€ndare {}: {}", orderNumber, user.getUsername(), e.getMessage());
return null;
}
}
/**
* đĄïž SAFE findByOrderNumber - anvĂ€nder EntityManager
*/
public Order findByOrderNumber(String orderNumber) {
try {
logger.info("đ Söker order med nummer: {}", orderNumber);
Query query = entityManager.createQuery(
"SELECT o FROM Order o WHERE o.orderNumber = :orderNumber", Order.class);
query.setParameter("orderNumber", orderNumber);
@SuppressWarnings("unchecked")
List<Order> results = query.getResultList();
if (results.isEmpty()) {
logger.warn("â ïž Ingen order hittades med nummer: {}", orderNumber);
return null;
}
Order order = results.get(0);
logger.info("â
Order hittades: {}", orderNumber);
return order;
} catch (Exception e) {
logger.error("â Fel vid sökning av order {}: {}", orderNumber, e.getMessage());
return null;
}
}
/**
* đĄïž SAFE findByUser - anvĂ€nder EntityManager
*/
public List<Order> findByUser(User user) {
try {
logger.info("đ HĂ€mtar alla orders för anvĂ€ndare: {}", user.getUsername());
Query query = entityManager.createQuery(
"SELECT o FROM Order o WHERE o.user = :user ORDER BY o.orderDate DESC", Order.class);
query.setParameter("user", user);
@SuppressWarnings("unchecked")
List<Order> results = query.getResultList();
logger.info("â
Hittade {} orders för anvÀndare: {}", results.size(), user.getUsername());
return results;
} catch (Exception e) {
logger.error("â Fel vid hĂ€mtning av orders för anvĂ€ndare {}: {}", user.getUsername(), e.getMessage());
return List.of();
}
}
// ===== ORDER STATUS MANAGEMENT =====
/**
* đ Uppdatera orderstatus
*/
public Order updateOrderStatus(Long orderId, Order.OrderStatus status) {
try {
logger.info("đ Uppdaterar orderstatus för ID {} till: {}", orderId, status);
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new RuntimeException("BestÀllning hittades inte"));
Order.OrderStatus oldStatus = order.getStatus();
order.setStatus(status);
Order savedOrder = orderRepository.save(order);
logger.info("â
Orderstatus uppdaterad: {} frÄn {} till {}", order.getOrderNumber(), oldStatus, status);
return savedOrder;
} catch (Exception e) {
logger.error("â Fel vid uppdatering av orderstatus för ID {}: {}", orderId, e.getMessage(), e);
throw new RuntimeException("Kunde inte uppdatera orderstatus: " + e.getMessage(), e);
}
}
/**
* đ Uppdatera orderstatus med notifieringar (för AdminController)
*/
@Transactional
public void updateOrderStatusWithNotifications(Long orderId, Order.OrderStatus newStatus) {
try {
logger.info("đ Uppdaterar orderstatus med notifieringar för ID {} till: {}", orderId, newStatus);
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new RuntimeException("Order not found: " + orderId));
Order.OrderStatus oldStatus = order.getStatus();
order.setStatus(newStatus);
orderRepository.save(order);
logger.info("â
Orderstatus med notifieringar uppdaterad: {} frÄn {} till {}",
order.getOrderNumber(), oldStatus, newStatus);
} catch (Exception e) {
logger.error("â Fel vid uppdatering av orderstatus med notifieringar för ID {}: {}", orderId, e.getMessage(), e);
throw new RuntimeException("Kunde inte uppdatera orderstatus: " + e.getMessage(), e);
}
}
// ===== ORDER NUMBER GENERATION =====
/**
* đą Generera unikt ordernummer med datum och sekvens
* Format: CB20250707001, CB20250707002, etc.
*/
private String generateOrderNumber() {
try {
// HĂ€mta dagens datum i format YYYYMMDD
String datePrefix = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
logger.info("đ
Genererar ordernummer för datum: {}", datePrefix);
// Sök efter högsta ordernummer för idag
String todayPattern = "CB" + datePrefix + "%";
// đĄïž SAFE QUERY - anvĂ€nd EntityManager istĂ€llet för repository method
Query query = entityManager.createQuery(
"SELECT o.orderNumber FROM Order o WHERE o.orderNumber LIKE :pattern");
query.setParameter("pattern", todayPattern);
@SuppressWarnings("unchecked")
List<String> todaysOrders = query.getResultList();
int nextSequence = 1;
if (!todaysOrders.isEmpty()) {
// Hitta högsta sekvensen för idag
int maxSequence = 0;
for (String orderNum : todaysOrders) {
if (orderNum.length() >= 13) { // CB + 8 datum + 3 sekvens = 13
try {
String sequencePart = orderNum.substring(10); // Ta sista 3 siffrorna
int sequence = Integer.parseInt(sequencePart);
maxSequence = Math.max(maxSequence, sequence);
} catch (NumberFormatException e) {
logger.warn("â ïž Felaktigt ordernummer format: {}", orderNum);
}
}
}
nextSequence = maxSequence + 1;
}
// Generera unikt ordernummer: CB + datum + 3-siffrig sekvens
String orderNumber = String.format("CB%s%03d", datePrefix, nextSequence);
logger.info("đą Genererat ordernummer: {} (sekvens: {})", orderNumber, nextSequence);
return orderNumber;
} catch (Exception e) {
logger.error("â Fel vid generering av ordernummer: {}", e.getMessage(), e);
// Fallback: anvÀnd timestamp
String fallbackNumber = "CB" + System.currentTimeMillis();
logger.warn("â ïž AnvĂ€nder fallback ordernummer: {}", fallbackNumber);
return fallbackNumber;
}
}
// ===== ORDER RETRIEVAL METHODS =====
/**
* đ Hitta bestĂ€llning baserat pĂ„ ID
*/
public Order findById(Long id) {
try {
logger.info("đ Söker order med ID: {}", id);
return orderRepository.findById(id)
.orElseThrow(() -> new RuntimeException("BestÀllning hittades inte"));
} catch (Exception e) {
logger.error("â Fel vid sökning av order med ID {}: {}", id, e.getMessage());
throw e;
}
}
/**
* đ Hitta bestĂ€llning med orderItems (för att undvika LazyInitializationException)
*/
@Transactional(readOnly = true)
public Order findOrderWithItemsById(Long orderId) {
try {
logger.info("đ Söker order med items för ID: {}", orderId);
Query query = entityManager.createQuery(
"SELECT o FROM Order o LEFT JOIN FETCH o.orderItems WHERE o.id = :orderId", Order.class);
query.setParameter("orderId", orderId);
@SuppressWarnings("unchecked")
List<Order> results = query.getResultList();
if (results.isEmpty()) {
logger.warn("â ïž Ingen order med items hittades för ID: {}", orderId);
return null;
}
Order order = results.get(0);
logger.info("â
Order med {} items hittades för ID: {}",
order.getOrderItems().size(), orderId);
return order;
} catch (Exception e) {
logger.error("â Fel vid hĂ€mtning av order med items för ID {}: {}", orderId, e.getMessage());
return null;
}
}
/**
* đ Alla bestĂ€llningar (admin) - ANVĂND ENTITYMANAGER
*/
public List<Order> findAll() {
return getAllOrders(); // AnvÀnd vÄr EntityManager-version
}
// ===== USER-SPECIFIC ORDER METHODS =====
/**
* đ RĂ€kna antal bestĂ€llningar för anvĂ€ndare
*/
public Long countOrdersByUser(User user) {
try {
logger.info("đ RĂ€knar orders för anvĂ€ndare: {}", user.getUsername());
Query query = entityManager.createQuery(
"SELECT COUNT(o) FROM Order o WHERE o.user = :user");
query.setParameter("user", user);
Long count = (Long) query.getSingleResult();
logger.info("đ AnvĂ€ndare {} har {} orders", user.getUsername(), count);
return count;
} catch (Exception e) {
logger.error("â Fel vid rĂ€kning av orders för anvĂ€ndare {}: {}", user.getUsername(), e.getMessage());
return 0L;
}
}
/**
* đ HĂ€mta orders med paginering för orderhistorik
*/
public Page<Order> getOrdersByUserWithPagination(User user, int page, int size) {
try {
logger.info("đ HĂ€mtar orders med paginering för anvĂ€ndare: {} (sida {}, storlek {})",
user.getUsername(), page, size);
Pageable pageable = PageRequest.of(page, size, Sort.by("orderDate").descending());
// đĄïž SAFE PAGINATION - anvĂ€nd findByUser och manuell paginering
List<Order> allOrders = findByUser(user);
int start = (int) pageable.getOffset();
int end = Math.min((start + pageable.getPageSize()), allOrders.size());
List<Order> pageContent = allOrders.subList(start, end);
Page<Order> result = new PageImpl<>(pageContent, pageable, allOrders.size());
logger.info("â
Returnerar sida {} av {} orders för anvÀndare {}",
page, pageContent.size(), user.getUsername());
return result;
} catch (Exception e) {
logger.error("â Fel vid hĂ€mtning av paginerade orders för anvĂ€ndare {}: {}",
user.getUsername(), e.getMessage());
return new PageImpl<>(List.of(), PageRequest.of(page, size), 0);
}
}
/**
* đ HĂ€mta specifik order för anvĂ€ndare (sĂ€kerhetscheck)
*/
public Optional<Order> getOrderByIdAndUser(Long orderId, User user) {
try {
logger.info("đ SĂ€kerhetscheck - hĂ€mtar order ID {} för anvĂ€ndare: {}", orderId, user.getUsername());
Query query = entityManager.createQuery(
"SELECT o FROM Order o WHERE o.id = :orderId AND o.user = :user", Order.class);
query.setParameter("orderId", orderId);
query.setParameter("user", user);
@SuppressWarnings("unchecked")
List<Order> results = query.getResultList();
if (results.isEmpty()) {
logger.warn("â ïž Ingen order med ID {} hittades för anvĂ€ndare {}", orderId, user.getUsername());
return Optional.empty();
}
Order order = results.get(0);
logger.info("â
SÀkerhetscheck OK - order {} tillhör anvÀndare {}",
order.getOrderNumber(), user.getUsername());
return Optional.of(order);
} catch (Exception e) {
logger.error("â Fel vid sĂ€kerhetscheck av order ID {} för anvĂ€ndare {}: {}",
orderId, user.getUsername(), e.getMessage());
return Optional.empty();
}
}
/**
* đ° BerĂ€kna total summa för alla orders av anvĂ€ndare
*/
public Double getTotalSpentByUser(User user) {
try {
logger.info("đ° BerĂ€knar total summa för anvĂ€ndare: {}", user.getUsername());
Query query = entityManager.createQuery(
"SELECT SUM(o.totalAmount) FROM Order o WHERE o.user = :user AND o.status != :cancelledStatus");
query.setParameter("user", user);
query.setParameter("cancelledStatus", Order.OrderStatus.CANCELLED);
Double total = (Double) query.getSingleResult();
if (total == null) {
total = 0.0;
}
logger.info("đ° AnvĂ€ndare {} har spenderat totalt: {} kr", user.getUsername(), total);
return total;
} catch (Exception e) {
logger.error("â Fel vid berĂ€kning av total summa för anvĂ€ndare {}: {}",
user.getUsername(), e.getMessage());
return 0.0;
}
}
// ===== UTILITY METHODS =====
/**
* đ countOrdersForUser - AdminController-kompatibel
*/
public long countOrdersForUser(User user) {
Long count = countOrdersByUser(user);
return count != null ? count : 0L;
}
/**
* đ getRecentOrdersForUser - HĂ€mta senaste bestĂ€llningar
*/
public List<Order> getRecentOrdersForUser(User user) {
List<Order> allOrders = findByUser(user);
return allOrders.stream().limit(5).collect(Collectors.toList());
}
/**
* â cancelOrder - Avbryt bestĂ€llning (endast om PENDING)
*/
@Transactional
public boolean cancelOrder(Long orderId, User user) {
try {
logger.info("â Försöker avbryta order ID {} för anvĂ€ndare: {}", orderId, user.getUsername());
Optional<Order> orderOpt = getOrderByIdAndUser(orderId, user);
if (!orderOpt.isPresent()) {
logger.warn("â ïž Order ID {} tillhör inte anvĂ€ndare {}", orderId, user.getUsername());
return false;
}
Order order = orderOpt.get();
// Kan bara avbryta vÀntande bestÀllningar
if (order.getStatus() != Order.OrderStatus.PENDING) {
logger.warn("â ïž Kan inte avbryta order {} med status: {}",
order.getOrderNumber(), order.getStatus());
return false;
}
order.setStatus(Order.OrderStatus.CANCELLED);
orderRepository.save(order);
logger.info("â
Order {} avbruten för anvÀndare: {}",
order.getOrderNumber(), user.getUsername());
return true;
} catch (Exception e) {
logger.error("â Fel vid avbrytning av order ID {} för anvĂ€ndare {}: {}",
orderId, user.getUsername(), e.getMessage());
return false;
}
}
// ===== ADMIN METHODS =====
/**
* đ getAllOrders - HĂ€mta alla bestĂ€llningar med paginering (för admin)
*/
public Page<Order> getAllOrders(Pageable pageable) {
try {
logger.info("đ Admin - hĂ€mtar alla orders med paginering");
List<Order> allOrders = findAll();
int start = (int) pageable.getOffset();
int end = Math.min((start + pageable.getPageSize()), allOrders.size());
List<Order> pageContent = allOrders.subList(start, end);
Page<Order> result = new PageImpl<>(pageContent, pageable, allOrders.size());
logger.info("â
Admin - returnerar {} orders av {} totalt", pageContent.size(), allOrders.size());
return result;
} catch (Exception e) {
logger.error("â Fel vid admin-hĂ€mtning av paginerade orders: {}", e.getMessage());
return new PageImpl<>(List.of(), pageable, 0);
}
}
// ===== DTO CLASSES =====
/**
* đ OrderDetails - DTO för bestĂ€llningsdata
*/
public static class OrderDetails {
private String deliveryName;
private String deliveryAddress;
private String deliveryCity;
private String deliveryPostalCode;
private String deliveryPhone;
private String paymentMethod;
// Getters
public String getDeliveryName() { return deliveryName; }
public String getDeliveryAddress() { return deliveryAddress; }
public String getDeliveryCity() { return deliveryCity; }
public String getDeliveryPostalCode() { return deliveryPostalCode; }
public String getDeliveryPhone() { return deliveryPhone; }
public String getPaymentMethod() { return paymentMethod; }
// Setters
public void setDeliveryName(String deliveryName) { this.deliveryName = deliveryName; }
public void setDeliveryAddress(String deliveryAddress) { this.deliveryAddress = deliveryAddress; }
public void setDeliveryCity(String deliveryCity) { this.deliveryCity = deliveryCity; }
public void setDeliveryPostalCode(String deliveryPostalCode) { this.deliveryPostalCode = deliveryPostalCode; }
public void setDeliveryPhone(String deliveryPhone) { this.deliveryPhone = deliveryPhone; }
public void setPaymentMethod(String paymentMethod) { this.paymentMethod = paymentMethod; }
}
/**
* đ€ GuestOrderDetails - DTO för gĂ€st-bestĂ€llningar
*/
public static class GuestOrderDetails {
private String firstName;
private String lastName;
private String email;
private String phone;
private String address;
private String city;
private String postalCode;
private String paymentMethod;
// Konstruktor
public GuestOrderDetails() {}
// Getters
public String getFirstName() { return firstName; }
public String getLastName() { return lastName; }
public String getEmail() { return email; }
public String getPhone() { return phone; }
public String getAddress() { return address; }
public String getCity() { return city; }
public String getPostalCode() { return postalCode; }
public String getPaymentMethod() { return paymentMethod; }
// Setters
public void setFirstName(String firstName) { this.firstName = firstName; }
public void setLastName(String lastName) { this.lastName = lastName; }
public void setEmail(String email) { this.email = email; }
public void setPhone(String phone) { this.phone = phone; }
public void setAddress(String address) { this.address = address; }
public void setCity(String city) { this.city = city; }
public void setPostalCode(String postalCode) { this.postalCode = postalCode; }
public void setPaymentMethod(String paymentMethod) { this.paymentMethod = paymentMethod; }
}
}