package com.imprimelibros.erp.cart; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import org.springframework.web.server.ResponseStatusException; import jakarta.servlet.http.HttpServletRequest; import org.springframework.context.MessageSource; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import com.imprimelibros.erp.common.Utils; import com.imprimelibros.erp.direcciones.Direccion; import com.imprimelibros.erp.direcciones.DireccionService; import com.imprimelibros.erp.i18n.TranslationService; import java.security.Principal; import java.util.List; import java.util.Locale; import java.util.Map; import com.imprimelibros.erp.cart.dto.UpdateCartRequest; @Controller @RequestMapping("/cart") public class CartController { protected final CartService service; protected DireccionService direccionService; protected MessageSource messageSource; protected TranslationService translationService; public CartController(CartService service, DireccionService direccionService, MessageSource messageSource, TranslationService translationService) { this.service = service; this.direccionService = direccionService; this.messageSource = messageSource; this.translationService = translationService; } /** Vista del carrito */ @GetMapping public String viewCart(Model model, Principal principal, Locale locale) { List keys = List.of( "app.cancelar", "app.seleccionar", "cart.shipping.add.title", "cart.shipping.select-placeholder", "cart.shipping.new-address", "cart.shipping.errors.noAddressSelected", "cart.shipping.enter-units", "cart.shipping.units-label", "cart.shipping.errors.units-error", "cart.shipping.ud", "cart.shipping.uds", "cart.shipping.send-in-palets", "cart.shipping.send-in-palets.info", "cart.shipping.tipo-envio", "cart.pass-to.customer.error", "cart.pass-to.customer.error-move", "app.yes", "app.aceptar", "app.cancelar"); Map translations = translationService.getTranslations(locale, keys); model.addAttribute("languageBundle", translations); Long userId = Utils.currentUserId(principal); Cart cart = service.getOrCreateActiveCart(userId); var items = service.listItems(userId, locale); model.addAttribute("items", items); Map direcciones = service.getCartDirecciones(cart.getId(), locale); if (direcciones != null && direcciones.containsKey("mainDir")) model.addAttribute("mainDir", direcciones.get("mainDir")); else if (direcciones != null && direcciones.containsKey("direcciones")) model.addAttribute("direcciones", direcciones.get("direcciones")); var summary = service.getCartSummary(cart, locale); model.addAttribute("cartSummary", summary); if (summary.get("errorShipmentCost") != null && (Boolean) summary.get("errorShipmentCost")) model.addAttribute("errorEnvio", true); else model.addAttribute("errorEnvio", false); model.addAttribute("cart", cart); return "imprimelibros/cart/cart"; // crea esta vista si quieres (tabla simple) } /** Añadir presupuesto via POST form */ @PostMapping("/add") public String add(@PathVariable(name = "presupuestoId", required = true) Long presupuestoId, Principal principal) { service.addPresupuesto(Utils.currentUserId(principal), presupuestoId); return "redirect:/cart"; } /** Añadir presupuesto con ruta REST (opcional) */ @PostMapping("/add/{presupuestoId}") public Object addPath(@PathVariable Long presupuestoId, Principal principal, HttpServletRequest request) { service.addPresupuesto(Utils.currentUserId(principal), presupuestoId); boolean isAjax = "XMLHttpRequest".equals(request.getHeader("X-Requested-With")); if (isAjax) { // Responder 200 con la URL a la que quieres ir return ResponseEntity.ok( Map.of("redirect", "/cart")); } // Navegación normal: redirección server-side return "redirect:/cart"; } @GetMapping("/count") @ResponseBody public long getCount(Principal principal) { if (principal == null) return 0; return service.countItems(Utils.currentUserId(principal)); } /** Eliminar línea por ID de item */ @DeleteMapping("/{itemId}/remove") public String remove(@PathVariable Long itemId, Principal principal) { service.removeItem(Utils.currentUserId(principal), itemId); return "redirect:/cart"; } /** Eliminar línea por presupuesto_id (opcional) */ @DeleteMapping("/delete/item/{presupuestoId}") @ResponseBody public String removeByPresupuesto(@PathVariable Long presupuestoId, Principal principal) { service.removeByPresupuesto(Utils.currentUserId(principal), presupuestoId); return "redirect:/cart"; } /** Vaciar carrito completo */ @DeleteMapping("/clear") public String clear(Principal principal) { service.clear(Utils.currentUserId(principal)); return "redirect:/cart"; } @GetMapping("/get-address/{id}") public String getDireccionCard(@PathVariable Long id, @RequestParam(required = false) Long presupuestoId, @RequestParam(required = false) Integer unidades, @RequestParam(required = false) Integer isPalets, Model model, Locale locale) { Direccion dir = direccionService.findById(id) .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); model.addAttribute("pais", messageSource.getMessage("paises." + dir.getPais().getKeyword(), null, dir.getPais().getKeyword(), locale)); model.addAttribute("presupuestoId", presupuestoId); model.addAttribute("unidades", unidades); model.addAttribute("isPalets", isPalets); model.addAttribute("direccion", dir); return "imprimelibros/direcciones/direccionCard :: direccionCard(direccion=${direccion})"; } @PostMapping(value = "/update/{id}", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) public String updateCart(@PathVariable Long id, UpdateCartRequest updateRequest, Model model, Locale locale, Principal principal) { try { service.updateCart(id, updateRequest); var cartSummary = service.getCartSummary(service.getCartById(id), locale); model.addAttribute("cartSummary", cartSummary); return "imprimelibros/cart/_cartSummary :: cartSummary(summary=${cartSummary})"; } catch (Exception e) { // redirect to cart with error message String errorMessage = messageSource.getMessage("cart.update.error", null, "Error updating cart", locale); model.addAttribute("errorMessage", errorMessage); return "redirect:/cart"; } } @PostMapping(value = "/pass-to-customer/{customerId}") public ResponseEntity moveToCustomer( @PathVariable Long customerId, Principal principal) { if(!Utils.isCurrentUserAdmin()) { return ResponseEntity.status(403).body(Map.of("error", "Forbidden")); } Long userId = Utils.currentUserId(principal); Cart cart = service.getOrCreateActiveCart(userId); boolean ok = service.moveCartToCustomer(cart.getId(), customerId); if (ok) return ResponseEntity.ok().build(); return ResponseEntity.status(400).body(Map.of("error", "cart.errors.move-cart")); } }