diff --git a/pom.xml b/pom.xml index a4d8bf9..6524c3a 100644 --- a/pom.xml +++ b/pom.xml @@ -33,11 +33,17 @@ true + + org.springframework.boot + spring-boot-starter-validation + + org.springframework.boot spring-boot-starter-web + org.postgresql postgresql diff --git a/src/main/java/com/orderflow/ecommerce/controllers/CartController.java b/src/main/java/com/orderflow/ecommerce/controllers/CartController.java new file mode 100644 index 0000000..35531d5 --- /dev/null +++ b/src/main/java/com/orderflow/ecommerce/controllers/CartController.java @@ -0,0 +1,67 @@ +package com.orderflow.ecommerce.controllers; + +import com.orderflow.ecommerce.dtos.AddItemRequest; +import com.orderflow.ecommerce.dtos.CartItemResponse; +import com.orderflow.ecommerce.dtos.UpdateQuantityRequest; +import com.orderflow.ecommerce.entities.Cart; +import com.orderflow.ecommerce.entities.CartItem; +import com.orderflow.ecommerce.repositories.CartItemRepository; +import com.orderflow.ecommerce.repositories.CartRepository; +import com.orderflow.ecommerce.services.CartService; +import jakarta.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; + + +import java.util.Optional; + +@RestController +@RequestMapping("/api/cart") +public class CartController { + + @Autowired + private CartService cartService; + + @Autowired + private CartRepository repository; + + @Autowired + private CartItemRepository itemRepository; + + @GetMapping + public Optional listCart() { + return repository.findByUserId(1L); + } + + @PostMapping + public CartItemResponse addItem(@Valid @RequestBody AddItemRequest request) { + return cartService.addItemToCart(request); + } + + + @DeleteMapping("/{id}") + public ResponseEntity removeItem(@PathVariable Long id) { + repository.deleteById(id); + return ResponseEntity.noContent().build(); + } + + @PutMapping("/items/{id}") + public CartItemResponse updateItem(@PathVariable Long id, @Valid @RequestBody UpdateQuantityRequest request) { + + CartItem item = itemRepository.findById(id) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Cart item not found with id: " + id)); + + item.setQuantity(request.quantity()); + + return CartItemResponse.from(itemRepository.save(item)); + } + + @DeleteMapping("/clear") + public ResponseEntity clearCart() { + cartService.clearCurrentCart(); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/com/orderflow/ecommerce/controllers/CategoryController.java b/src/main/java/com/orderflow/ecommerce/controllers/CategoryController.java deleted file mode 100644 index 7d1292d..0000000 --- a/src/main/java/com/orderflow/ecommerce/controllers/CategoryController.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.orderflow.ecommerce.controllers; - -import com.orderflow.ecommerce.entities.Category; -import com.orderflow.ecommerce.repositories.CategoryRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -@RestController -@RequestMapping(value = "/categories") -public class CategoryController { - - @Autowired - private CategoryRepository repository; - - @GetMapping - public ResponseEntity> findAll() { - return ResponseEntity.ok().body(repository.findAll()); - } - - @GetMapping(value = "/{id}") - public ResponseEntity findById(@PathVariable Long id) { - - - return repository.findById(id) - .map(obj -> ResponseEntity.ok().body(obj)) - .orElse(ResponseEntity.notFound().build()); - } - - @PostMapping - public ResponseEntity insert(@RequestBody Category obj) { - return ResponseEntity.ok().body(repository.save(obj)); - } - - @DeleteMapping(value = "/{id}") - public ResponseEntity delete(@PathVariable Long id) { - repository.deleteById(id); - return ResponseEntity.noContent().build(); - } - - @PutMapping(value = "/{id}") - public ResponseEntity update(@PathVariable Long id, @RequestBody Category obj) { - return repository.findById(id) - .map(entity -> { - entity.setName(obj.getName()); - Category updated = repository.save(entity); - return ResponseEntity.ok().body(updated); - }) - .orElse(ResponseEntity.notFound().build()); - } -} \ No newline at end of file diff --git a/src/main/java/com/orderflow/ecommerce/controllers/ProductController.java b/src/main/java/com/orderflow/ecommerce/controllers/ProductController.java deleted file mode 100644 index 8c14bb0..0000000 --- a/src/main/java/com/orderflow/ecommerce/controllers/ProductController.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.orderflow.ecommerce.controllers; - -import com.orderflow.ecommerce.entities.Product; -import com.orderflow.ecommerce.repositories.ProductRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -@RestController -@RequestMapping(value = "/products") -public class ProductController { - - @Autowired - private ProductRepository repository; - - @GetMapping - public ResponseEntity> findAll() { - return ResponseEntity.ok().body(repository.findAll()); - } - - @GetMapping(value = "/{id}") - public ResponseEntity findById(@PathVariable Long id) { - return repository.findById(id) - .map(obj -> ResponseEntity.ok().body(obj)) - .orElse(ResponseEntity.notFound().build()); - } - - @PostMapping - public ResponseEntity insert(@RequestBody Product obj) { - return ResponseEntity.ok().body(repository.save(obj)); - } - - @DeleteMapping(value = "/{id}") - public ResponseEntity delete(@PathVariable Long id) { - repository.deleteById(id); - return ResponseEntity.noContent().build(); - } - - @PutMapping(value = "/{id}") - public ResponseEntity update(@PathVariable Long id, @RequestBody Product obj) { - Product entity = repository.findById(id).get(); - entity.setName(obj.getName()); - entity.setDescription(obj.getDescription()); - entity.setPrice(obj.getPrice()); - entity.setStockQuantity(obj.getStockQuantity()); - entity.setCategory(obj.getCategory()); - System.out.println("aavavvvv"); - return ResponseEntity.ok().body(repository.save(entity)); - - } -} \ No newline at end of file diff --git a/src/main/java/com/orderflow/ecommerce/controllers/TestController.java b/src/main/java/com/orderflow/ecommerce/controllers/TestController.java deleted file mode 100644 index 746932c..0000000 --- a/src/main/java/com/orderflow/ecommerce/controllers/TestController.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.orderflow.ecommerce.controllers; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.time.LocalDateTime; -import java.util.Map; - -@RestController -@RequestMapping("/test") -public class TestController { - - @GetMapping("/ping") - public Map ping() { - - return Map.of( - "status", "ok", - "message", "versão 1.", - "timestamp", LocalDateTime.now().toString() - ); - } - -} diff --git a/src/main/java/com/orderflow/ecommerce/dtos/AddItemRequest.java b/src/main/java/com/orderflow/ecommerce/dtos/AddItemRequest.java new file mode 100644 index 0000000..0803457 --- /dev/null +++ b/src/main/java/com/orderflow/ecommerce/dtos/AddItemRequest.java @@ -0,0 +1,12 @@ +package com.orderflow.ecommerce.dtos; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; + +public record AddItemRequest( + @NotNull Long productId, + @NotNull @Positive Integer quantity, + @NotNull @Positive Double price +) { + +} \ No newline at end of file diff --git a/src/main/java/com/orderflow/ecommerce/dtos/CartItemResponse.java b/src/main/java/com/orderflow/ecommerce/dtos/CartItemResponse.java new file mode 100644 index 0000000..07ff16b --- /dev/null +++ b/src/main/java/com/orderflow/ecommerce/dtos/CartItemResponse.java @@ -0,0 +1,21 @@ +package com.orderflow.ecommerce.dtos; + +import com.orderflow.ecommerce.entities.CartItem; + +public record CartItemResponse( + Long id, + Long productId, + String productName, + Integer quantity, + Double price +) { + public static CartItemResponse from(CartItem item) { + return new CartItemResponse( + item.getId(), + item.getProductId(), + "Produto #" + item.getProductId(), + item.getQuantity(), + item.getPrice() + ); + } +} \ No newline at end of file diff --git a/src/main/java/com/orderflow/ecommerce/dtos/UpdateQuantityRequest.java b/src/main/java/com/orderflow/ecommerce/dtos/UpdateQuantityRequest.java new file mode 100644 index 0000000..ebb25c6 --- /dev/null +++ b/src/main/java/com/orderflow/ecommerce/dtos/UpdateQuantityRequest.java @@ -0,0 +1,10 @@ +package com.orderflow.ecommerce.dtos; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; + +public record UpdateQuantityRequest( + @NotNull(message = "A quantidade não pode ser nula") + @Min(value = 1, message = "A quantidade deve ser no mínimo 1") + Integer quantity +) {} \ No newline at end of file diff --git a/src/main/java/com/orderflow/ecommerce/entities/Cart.java b/src/main/java/com/orderflow/ecommerce/entities/Cart.java new file mode 100644 index 0000000..9f478a0 --- /dev/null +++ b/src/main/java/com/orderflow/ecommerce/entities/Cart.java @@ -0,0 +1,39 @@ +package com.orderflow.ecommerce.entities; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; + +import java.io.Serial; +import java.io.Serializable; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +@Entity +@Table(name = "tb_cart") +@Getter @Setter +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(onlyExplicitlyIncluded = true) +public class Cart implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @EqualsAndHashCode.Include + private Long id; + + private Instant createdAt = Instant.now(); + + @OneToMany(mappedBy = "cart", cascade = CascadeType.ALL) + private List items = new ArrayList<>(); + + @Column(name = "user_id") + private Long userId; +} \ No newline at end of file diff --git a/src/main/java/com/orderflow/ecommerce/entities/CartItem.java b/src/main/java/com/orderflow/ecommerce/entities/CartItem.java new file mode 100644 index 0000000..96ec591 --- /dev/null +++ b/src/main/java/com/orderflow/ecommerce/entities/CartItem.java @@ -0,0 +1,29 @@ +package com.orderflow.ecommerce.entities; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.persistence.*; +import lombok.*; +import java.io.Serializable; + +@Entity +@Table(name = "tb_cart_item") +@Getter @Setter +@NoArgsConstructor +@AllArgsConstructor +public class CartItem implements Serializable { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private Integer quantity; + private Double price; + + @JsonIgnore + @ManyToOne + @JoinColumn(name = "cart_id") + private Cart cart; + + @Column(name = "product_id_temp") + private Long productId; +} \ No newline at end of file diff --git a/src/main/java/com/orderflow/ecommerce/entities/Category.java b/src/main/java/com/orderflow/ecommerce/entities/Category.java deleted file mode 100644 index 3c08a5e..0000000 --- a/src/main/java/com/orderflow/ecommerce/entities/Category.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.orderflow.ecommerce.entities; - -import jakarta.persistence.*; -import lombok.*; - -@Entity -@Table(name = "tb_category") -@Getter @Setter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor -@EqualsAndHashCode(of = "id") -public class Category { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(nullable = false, unique = true) - private String name; -} diff --git a/src/main/java/com/orderflow/ecommerce/entities/Product.java b/src/main/java/com/orderflow/ecommerce/entities/Product.java index e72b010..d64acfc 100644 --- a/src/main/java/com/orderflow/ecommerce/entities/Product.java +++ b/src/main/java/com/orderflow/ecommerce/entities/Product.java @@ -27,7 +27,4 @@ public class Product { private Integer stockQuantity; - @ManyToOne - @JoinColumn(name = "category_id") - private Category category; } \ No newline at end of file diff --git a/src/main/java/com/orderflow/ecommerce/repositories/CartItemRepository.java b/src/main/java/com/orderflow/ecommerce/repositories/CartItemRepository.java new file mode 100644 index 0000000..a423b33 --- /dev/null +++ b/src/main/java/com/orderflow/ecommerce/repositories/CartItemRepository.java @@ -0,0 +1,17 @@ +package com.orderflow.ecommerce.repositories; + +import com.orderflow.ecommerce.entities.CartItem; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +@Repository +public interface CartItemRepository extends JpaRepository { + + @Modifying + @Transactional + @Query("DELETE FROM CartItem c WHERE c.cart.userId = :userId") + void deleteByCartUserId(Long userId); +} \ No newline at end of file diff --git a/src/main/java/com/orderflow/ecommerce/repositories/CartRepository.java b/src/main/java/com/orderflow/ecommerce/repositories/CartRepository.java new file mode 100644 index 0000000..3858c14 --- /dev/null +++ b/src/main/java/com/orderflow/ecommerce/repositories/CartRepository.java @@ -0,0 +1,12 @@ +package com.orderflow.ecommerce.repositories; + +import com.orderflow.ecommerce.entities.Cart; +import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; // <--- Importante ter esse import! + +public interface CartRepository extends JpaRepository { + + Optional findByUserId(Long userId); + + void deleteByUserId(Long userId); +} diff --git a/src/main/java/com/orderflow/ecommerce/repositories/CategoryRepository.java b/src/main/java/com/orderflow/ecommerce/repositories/CategoryRepository.java deleted file mode 100644 index cebc3c0..0000000 --- a/src/main/java/com/orderflow/ecommerce/repositories/CategoryRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.orderflow.ecommerce.repositories; - -import com.orderflow.ecommerce.entities.Category; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface CategoryRepository extends JpaRepository { -} \ No newline at end of file diff --git a/src/main/java/com/orderflow/ecommerce/repositories/ProductRepository.java b/src/main/java/com/orderflow/ecommerce/repositories/ProductRepository.java deleted file mode 100644 index d49a9fe..0000000 --- a/src/main/java/com/orderflow/ecommerce/repositories/ProductRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.orderflow.ecommerce.repositories; - -import com.orderflow.ecommerce.entities.Product; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface ProductRepository extends JpaRepository { -} diff --git a/src/main/java/com/orderflow/ecommerce/services/CartService.java b/src/main/java/com/orderflow/ecommerce/services/CartService.java new file mode 100644 index 0000000..2cc687c --- /dev/null +++ b/src/main/java/com/orderflow/ecommerce/services/CartService.java @@ -0,0 +1,61 @@ +package com.orderflow.ecommerce.services; + +import com.orderflow.ecommerce.dtos.AddItemRequest; +import com.orderflow.ecommerce.dtos.CartItemResponse; +import com.orderflow.ecommerce.entities.Cart; +import com.orderflow.ecommerce.entities.CartItem; +import com.orderflow.ecommerce.repositories.CartItemRepository; +import com.orderflow.ecommerce.repositories.CartRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class CartService { + + @Autowired + private CartRepository cartRepository; + + @Autowired + private CartItemRepository cartItemRepository; + + @Transactional + public CartItemResponse addItemToCart(AddItemRequest request) { + Cart cart = cartRepository.findByUserId(1L) + .orElseGet(() -> { + Cart newCart = new Cart(); + newCart.setUserId(1L); + + return cartRepository.saveAndFlush(newCart); + }); + + CartItem item = new CartItem(); + item.setQuantity(request.quantity()); + item.setPrice(request.price()); + item.setCart(cart); + item.setProductId(request.productId()); + + CartItem savedItem = cartItemRepository.saveAndFlush(item); + return CartItemResponse.from(savedItem); + } + + @Transactional + public CartItemResponse updateItem(Long itemId, AddItemRequest request) { + CartItem item = cartItemRepository.findById(itemId) + .orElseThrow(() -> new RuntimeException("Item não encontrado")); + + item.setQuantity(request.quantity()); + item.setPrice(request.price()); + item.setProductId(request.productId()); + + CartItem updatedItem = cartItemRepository.saveAndFlush(item); + return CartItemResponse.from(updatedItem); + } + + @Transactional + public void clearCurrentCart() { + cartRepository.deleteByUserId(1L); + + cartRepository.flush(); + } +} \ No newline at end of file diff --git a/src/main/resources/application.dev.properties b/src/main/resources/application.dev.properties new file mode 100644 index 0000000..57ded54 --- /dev/null +++ b/src/main/resources/application.dev.properties @@ -0,0 +1,15 @@ +spring.profiles.active=dev + +spring.datasource.url=jdbc:postgresql://postgres:5432/orderflow +spring.datasource.username=orderflow +spring.datasource.password=orderflow123 +spring.datasource.driver-class-name=org.postgresql.Driver + +spring.jpa.hibernate.ddl-auto=update +spring.jpa.show-sql=true +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect + +spring.rabbitmq.host=rabbitmq +spring.rabbitmq.port=5672 +spring.rabbitmq.username=orderflow +spring.rabbitmq.password=orderflow123 \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8685680..842455d 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -8,6 +8,7 @@ spring.jpa.show-sql=true spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect spring.rabbitmq.host=rabbitmq + spring.rabbitmq.port=5672 spring.rabbitmq.username=orderflow spring.rabbitmq.password=orderflow123