package com.paymentlink.service; import com.paymentlink.model.entity.Order; import com.paymentlink.model.entity.OrderItem; import com.paymentlink.model.entity.Product; import com.paymentlink.repository.OrderRepository; import com.paymentlink.reservation.ReservationService; import com.paymentlink.util.IdGenerator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.Optional; @Service public class OrderService { private static final Logger logger = LoggerFactory.getLogger(OrderService.class); private final OrderRepository orderRepository; private final ProductService productService; private final TaxService taxService; private final ShippingService shippingService; private final ReservationService reservationService; private final NodeIdService nodeIdService; public OrderService(OrderRepository orderRepository, ProductService productService, TaxService taxService, ShippingService shippingService, ReservationService reservationService, NodeIdService nodeIdService) { this.orderRepository = orderRepository; this.productService = productService; this.taxService = taxService; this.shippingService = shippingService; this.reservationService = reservationService; this.nodeIdService = nodeIdService; } /** * Create a new order */ @Transactional public Order createOrder(List items, String customerEmail, String customerName, String customerPhone, String customerContactPreference, String shippingAddress, String shippingCity, String shippingState, String shippingZip, String shippingCountry, String shippingMethod, String sessionId) { logger.info("Creating order for customer: {}", customerEmail); // Validate stock and calculate totals long subtotal = 0; String currency = "USD"; for (OrderItem item : items) { Optional productOpt = productService.getProductByIdRaw(item.getProductId()); if (productOpt.isEmpty()) { throw new IllegalArgumentException("Product not found: " + item.getProductId()); } Product product = productOpt.get(); currency = product.getCurrency(); // Check stock availability (considering reservations) if (product.getStock() != null) { int reservedByOthers = reservationService.getReservedCountExcludingSession( product.getId(), sessionId ); int effectiveStock = product.getStock() - reservedByOthers; if (effectiveStock < item.getQuantity()) { throw new IllegalStateException( String.format("Insufficient stock for %s. Only %d available.", product.getName(), effectiveStock) ); } } // Set item details item.setProductName(product.getName()); item.setPrice(product.getPrice()); subtotal += product.getPrice() * item.getQuantity(); } // Calculate shipping long shippingCost = shippingService.calculateShippingCost(shippingMethod, shippingCountry); // Calculate tax long taxAmount = taxService.calculateTax(subtotal, shippingCountry, shippingState); // Calculate total long total = subtotal + shippingCost + taxAmount; // Create order Order order = Order.builder() .orderId(IdGenerator.generateOrderId()) .status("pending") .subtotal(subtotal) .total(total) .currency(currency) .customerEmail(customerEmail) .customerName(customerName) .customerPhone(customerPhone) .customerContactPreference(customerContactPreference) .shippingAddress(shippingAddress) .shippingCity(shippingCity) .shippingState(shippingState) .shippingZip(shippingZip) .shippingCountry(shippingCountry) .shippingMethod(shippingMethod) .shippingCost(shippingCost) .taxAmount(taxAmount) .nodeId(nodeIdService.getNodeId()) .build(); // Add items for (OrderItem item : items) { order.addItem(item); } // Save order order = orderRepository.save(order); logger.info("Created order: {}", order.getOrderId()); return order; } /** * Complete an order (update stock, release reservations) */ @Transactional public void completeOrder(String orderId, String sessionId) { Optional orderOpt = orderRepository.findByOrderId(orderId); if (orderOpt.isEmpty()) { throw new IllegalArgumentException("Order not found: " + orderId); } Order order = orderOpt.get(); // Update stock for each item for (OrderItem item : order.getItems()) { productService.decreaseStock(item.getProductId(), item.getQuantity()); // Release reservation if (sessionId != null) { reservationService.release(sessionId, item.getProductId()); } } // Update order status order.setStatus("completed"); orderRepository.save(order); logger.info("Completed order: {}", orderId); } /** * Get order by ID */ public Optional getOrderById(String orderId) { return orderRepository.findByOrderIdWithItems(orderId); } /** * Get orders by customer email */ public List getOrdersByCustomerEmail(String email) { return orderRepository.findByCustomerEmail(email); } /** * Get all orders (admin) */ public List getAllOrders() { return orderRepository.findAllWithItems(); } /** * Update order tracking information */ @Transactional public Optional updateTracking(String orderId, String trackingId, String carrier) { return orderRepository.findByOrderId(orderId).map(order -> { order.setTrackingId(trackingId); order.setCarrier(carrier); return orderRepository.save(order); }); } /** * Verify email matches order */ public boolean verifyOrderEmail(String orderId, String email) { Optional order = orderRepository.findByOrderId(orderId); return order.isPresent() && order.get().getCustomerEmail().equalsIgnoreCase(email); } }