I am making a REST API by using Java Spring Boot Hibernate JPA H2 Database, I would need use PUT method for that, through the value of cantidadProducto in ProductoDTO inserted in the body, subtracts the stock value of my Producto entity. please help to solve this problem, I would greatly appreciate it
Producto.java
package com.coder.billing.models;
import lombok.*;
import javax.persistence.*;
@Entity
@Table(name = "productos")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Producto {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long idProducto;
@Column(name = "nombre")
private String nombreProducto;
@Column(name = "precio")
private Integer precioProducto;
@Column(name = "descripcion")
private String descripcion;
@Column(name = "stock")
private Integer stock;
}
ProductoDTO.java
package com.coder.billing.dto;
import lombok.*;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProductoDTO {
private Long idProducto;
private String nombreProducto;
private Integer precioProducto;
private String descripcion;
private Integer stock;
private Integer cantidadProducto;
}
ProductoRepository.java
package com.coder.billing.repositories.Producto;
import com.coder.billing.models.Producto;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ProductoRepository extends JpaRepository<Producto, Long> {
}
ProductoServiceImpl.java
package com.coder.billing.services.Producto;
import com.coder.billing.dto.ProductoDTO;
import com.coder.billing.models.Producto;
import com.coder.billing.repositories.Producto.ProductoRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
// productoDTO.setTotalParcial(productoDTO.getPrecioProducto() * productoDTO.getCantidadProducto());
@Service
public class ProductoServiceImp implements ProductoService {
@Autowired
ProductoRepository productoRepository;
public List<Producto> getAllProductos() {
return productoRepository.findAll();
}
public Producto getOneProduct(Long id) {
return productoRepository.findById(id).orElseThrow(() -> new RuntimeException("Producto no encontrado"));
}
public Producto createProduct(Producto producto) {
return productoRepository.save(producto);
}
public Producto updateProduct(Producto producto, Long id) {
Producto productoActual = productoRepository.findById(id).orElseThrow(() -> new RuntimeException("Producto no encontrado"));
productoActual.setIdProducto(id);
productoActual.setNombreProducto(producto.getNombreProducto());
productoActual.setPrecioProducto(producto.getPrecioProducto());
productoActual.setDescripcion(producto.getDescripcion());
productoActual.setStock(producto.getStock());
return productoRepository.save(productoActual);
}
public void deleteProduct(Long id) {
productoRepository.deleteById(id);
}
}
ProductoService.java
package com.coder.billing.services.Producto;
import com.coder.billing.models.Producto;
import java.util.List;
public interface ProductoService {
List<Producto> getAllProductos();
Producto getOneProduct(Long id);
Producto createProduct(Producto producto);
Producto updateProduct(Producto producto, Long id);
void deleteProduct(Long id);
}
ProductoController.java
package com.coder.billing.controllers.Producto;
import com.coder.billing.dto.ProductoDTO;
import com.coder.billing.models.Producto;
import com.coder.billing.services.Producto.ProductoService;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/api/productos")
public class ProductoController {
@Autowired
ModelMapper modelMapper;
@Autowired
ProductoService productoService;
@GetMapping()
public List<ProductoDTO> getAllProductos() {
return productoService.getAllProductos().stream().map(producto -> modelMapper.map(producto, ProductoDTO.class)).collect(Collectors.toList());
}
@GetMapping("/{id}")
public ResponseEntity<ProductoDTO> getProductoById(@PathVariable Long id) {
Producto producto = productoService.getOneProduct(id);
if (producto == null) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
ProductoDTO productoDTO = modelMapper.map(producto, ProductoDTO.class);
return ResponseEntity.ok().body(productoDTO);
}
@PostMapping()
public ResponseEntity<ProductoDTO> createProduct(@RequestBody ProductoDTO productoDTO) {
Producto producto = modelMapper.map(productoDTO, Producto.class);
Producto productoCreacion = productoService.createProduct(producto);
ProductoDTO conversion = modelMapper.map(productoCreacion, ProductoDTO.class);
return new ResponseEntity<ProductoDTO>(conversion, HttpStatus.CREATED);
}
@PutMapping("/{id}")
public ResponseEntity<ProductoDTO> updateProduct(@PathVariable Long id, @RequestBody ProductoDTO productoDTO) {
Producto productoPeticion = modelMapper.map(productoDTO, Producto.class);
Producto producto = productoService.updateProduct(productoPeticion, id);
ProductoDTO productoDTOPeticion = modelMapper.map(producto, ProductoDTO.class);
return ResponseEntity.ok().body(productoDTOPeticion);
}
@DeleteMapping("/{id}")
public ResponseEntity<ProductoDTO> deleteProduct(@PathVariable Long id) {
productoService.deleteProduct(id);
return new ResponseEntity<>(HttpStatus.OK);
}
}
CodePudding user response:
public ResponseEntity<ProductoDTO> productoService(@PathVariable Long id, @RequestBody ProductoDTO productoDTO) {
//(1) Retrieve product object using id
Producto producto = productoRepository.findById(id).get();
//(2) get current stock value from producto object
Integer stock = product.getStock();
//(3) stock = ProductoDTO.getCantidadProducto();[if stock increase]
OR
stock -= ProductoDTO.getCantidadProducto(); [if stock reduce]
//(4) update the object with latest stock value
product.setStock(stock);
//(5) save product object
productoRepository.save(product);
return ResponseEntity.ok().body(productoDTOPeticion);
}
CodePudding user response:
For example, your service can accept ProductoDTO
instead of a Producto
object and work directly on DTO fields, thus you won't loose "cantidadProducto" variable value:
public Producto updateProduct(ProductoDTO productoDTO, Long id) {
Producto productoActual = productoRepository.findById(id).orElseThrow(() -> new RuntimeException("Producto no encontrado"));
productoActual.setNombreProducto(productoDTO.getNombreProducto());
productoActual.setPrecioProducto(productoDTO.getPrecioProducto());
productoActual.setDescripcion(productoDTO.getDescripcion());
if (productoActual.getStock() < productoDTO.getCantidadProducto()) {
throw new RuntimeException("Not enough stock");
}
productoActual.setStock(productoActual.getStock() - productoDTO.getCantidadProducto());
return productoRepository.save(productoActual);
}
Also deliberate whether there's really a need for your ProductoDTO
to have a "cantidadProducto" field, because you can pass it to a controller as a path variable:
@PutMapping("/{id}")
public ResponseEntity<ProductoDTO> updateProduct(
@PathVariable Long id,
@RequestParam(required = false) Integer cantidadProducto,
@RequestBody ProductoDTO productoDTO) {
// calling service method here
}
In this case you will also need to change service method to accept Integer cantidadProducto argument. And a request to your API would look like this:
/api/productos/100?cantidadProducto=7
Also it might be simpler to decouple entity update logic (like change name, price, description) from reduce quantity (stock) logic, because the first one is more about product itself, and the second one is like the action lets say "buy product".
Then in a new controller method all you need is an ID and cantidad
value, without any DTO objects, like this:
@PutMapping("/{id}/stock/buy")
public ResponseEntity<ProductoDTO> updateProduct(
@PathVariable Long id,
@RequestParam Integer cantidad) {
Producto producto = productoService.changeStock(id, cantidad, false);
ProductoDTO productoDTOPeticion = modelMapper.map(producto, ProductoDTO.class);
return ResponseEntity.ok().body(productoDTOPeticion);
}
And a simple service method like this:
public Producto changeStock(Long id, Integer cantidad, boolean increase) {
Producto producto = productoRepository.findById(id).orElseThrow(() -> new RuntimeException("Producto no encontrado"));
Integer stock = product.getStock();
if (!increase && cantidad > stock) {
throw new RuntimeException("Not enough stock");
}
stock = increase ? stock cantidad : stock - cantidad ;
producto.setStock(stock);
return productoRepository.save(producto);
}
It might look like now it's not a RESTful API, but I think it would be easier to maintain this structure.