diff --git a/.idea/compiler.xml b/.idea/compiler.xml index bb087f3..09f7e11 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -9,7 +9,7 @@ - + diff --git a/.idea/workspace.xml b/.idea/workspace.xml index e7c6a5b..b9a1078 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -2,7 +2,20 @@ + + + + + + + + + + + + + + + - - + + - + - + - - + + - + - + @@ -388,7 +415,7 @@ - + @@ -452,78 +479,31 @@ - + - - + + - - + + - + - - - - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + @@ -537,10 +517,105 @@ - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 83ac68a..613f30a 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,15 @@ org.springframework.boot spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 11 + + diff --git a/src/main/java/com/dino/scrum/sysmag/controller/ProductController.java b/src/main/java/com/dino/scrum/sysmag/controller/ProductController.java index 3f0ce5e..84c6361 100644 --- a/src/main/java/com/dino/scrum/sysmag/controller/ProductController.java +++ b/src/main/java/com/dino/scrum/sysmag/controller/ProductController.java @@ -3,12 +3,15 @@ package com.dino.scrum.sysmag.controller; import com.dino.scrum.sysmag.model.Product; import com.dino.scrum.sysmag.model.dto.IdDto; import com.dino.scrum.sysmag.model.dto.QuantityChange; -import com.dino.scrum.sysmag.service.ProductService; import com.dino.scrum.sysmag.service.ProductServiceImpl; +import com.dino.scrum.sysmag.validator.QuantityChangeValidator; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; +import javax.validation.Valid; import java.util.Collections; import java.util.Map; @@ -16,53 +19,70 @@ import java.util.Map; * Created by prgres on 2019-01-12. */ -@Controller +@RestController @RequestMapping(value = "/api") public class ProductController { - private final ProductServiceImpl productService; + private final + ProductServiceImpl productService; + private final + QuantityChangeValidator quantityChangeValidator; @Autowired - public ProductController(ProductServiceImpl productService) { + public ProductController(ProductServiceImpl productService, QuantityChangeValidator quantityChangeValidator) { this.productService = productService; + this.quantityChangeValidator = quantityChangeValidator; } @GetMapping(value = "/get-all") - public @ResponseBody - Iterable getAll(){ - return productService.getAllProducts(); + public Iterable getAll(Pageable pageable) { + return productService.getAll(pageable); } - @GetMapping(value = "/get-price-of-all") - public @ResponseBody + public Map getPriceOfAllProducts(){ - return Collections.singletonMap("price-of-all", productService.getPriceOfAllProducts()); + return Collections.singletonMap("price-of-all", productService.getPriceOfAll()); } @PostMapping(value = "/product/add") - public @ResponseBody - Product addProduct(@RequestBody Product product){ - return productService.addProduct(product); + public Product addProduct(@Valid @RequestBody Product product) { + try { + return productService.add(product); + } catch (Exception e) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.toString()); + } } @DeleteMapping(value = "/product/delete") - public @ResponseBody + public String deleteProduct(@RequestBody IdDto id){ - productService.deleteProduct(id.getId()); - return "Deleted" + id; + try { + productService.delete(id.getId()); + return "Deleted" + id; + } catch (Exception e) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.toString()); + } } @GetMapping(value = "/product/get-by-id") - public @ResponseBody + public Product getById(@RequestBody IdDto id){ - return productService.getById(id.getId()); + try { + return productService.getById(id.getId()); + } catch (Exception e) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.toString()); + } } @PostMapping(value = "/product/change-quantity") - public @ResponseBody + public Product changeQuantity(@RequestBody QuantityChange quantityChange){ - return productService.changeQuantity(quantityChange); + try { + quantityChangeValidator.validate(quantityChange); + return productService.changeQuantity(quantityChange); + } catch (Exception e) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.toString()); + } } - } \ No newline at end of file diff --git a/src/main/java/com/dino/scrum/sysmag/exception/ProductNotFoundException.java b/src/main/java/com/dino/scrum/sysmag/exception/ProductNotFoundException.java new file mode 100644 index 0000000..bf339b6 --- /dev/null +++ b/src/main/java/com/dino/scrum/sysmag/exception/ProductNotFoundException.java @@ -0,0 +1,8 @@ +package com.dino.scrum.sysmag.exception; + +/** + * Created by prgres on 2019-01-21. + */ + +public class ProductNotFoundException extends ClassNotFoundException { +} diff --git a/src/main/java/com/dino/scrum/sysmag/model/Product.java b/src/main/java/com/dino/scrum/sysmag/model/Product.java index bc2d178..d67df37 100644 --- a/src/main/java/com/dino/scrum/sysmag/model/Product.java +++ b/src/main/java/com/dino/scrum/sysmag/model/Product.java @@ -5,6 +5,10 @@ import lombok.Setter; import lombok.ToString; import javax.persistence.*; +import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; import java.math.BigDecimal; /** @@ -23,16 +27,33 @@ public class Product { @Column(name = "id") private Long id; + @NotNull(message = "name cannot be null") + @Size(min = 2, message = "name cannot be shorter that 2") @Column(name = "name") private String name; + @NotNull(message = "price cannot be null") + @DecimalMin(value = "0.00", message = "price cannot be under 0.00") @Column(name = "price") private BigDecimal price; + @NotNull(message = "quantity cannot be null") + @Min(value = 0, message = "quantity cannot be under 0") @Column(name = "quantity") private long quantity; + @NotNull(message = "quantityMax cannot be null") + @Min(value = 1, message = "quantityMax cannot be under 1") + @Column(name = "quantityMax") + private long quantityMax; + + @NotNull(message = "image_link cannot be null") @Column(name = "image_link") private String imageLink; + public Product setChangeQuantity(long change) { + this.quantity += change; + return this; + } + } diff --git a/src/main/java/com/dino/scrum/sysmag/model/dto/IdDto.java b/src/main/java/com/dino/scrum/sysmag/model/dto/IdDto.java index 0b5e89c..f8e2f26 100644 --- a/src/main/java/com/dino/scrum/sysmag/model/dto/IdDto.java +++ b/src/main/java/com/dino/scrum/sysmag/model/dto/IdDto.java @@ -8,5 +8,6 @@ import lombok.Getter; @Getter public class IdDto { + long id; } diff --git a/src/main/java/com/dino/scrum/sysmag/model/dto/QuantityChange.java b/src/main/java/com/dino/scrum/sysmag/model/dto/QuantityChange.java index 62718fc..81d2881 100644 --- a/src/main/java/com/dino/scrum/sysmag/model/dto/QuantityChange.java +++ b/src/main/java/com/dino/scrum/sysmag/model/dto/QuantityChange.java @@ -1,5 +1,6 @@ package com.dino.scrum.sysmag.model.dto; +import lombok.EqualsAndHashCode; import lombok.Getter; /** @@ -7,6 +8,7 @@ import lombok.Getter; */ @Getter +@EqualsAndHashCode public class QuantityChange { long id; long change; diff --git a/src/main/java/com/dino/scrum/sysmag/repository/ProductRepository.java b/src/main/java/com/dino/scrum/sysmag/repository/ProductRepository.java index f1b5f0f..f9aebcb 100644 --- a/src/main/java/com/dino/scrum/sysmag/repository/ProductRepository.java +++ b/src/main/java/com/dino/scrum/sysmag/repository/ProductRepository.java @@ -1,16 +1,19 @@ package com.dino.scrum.sysmag.repository; import com.dino.scrum.sysmag.model.Product; -import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.stereotype.Repository; -import java.math.BigDecimal; -import java.util.List; import java.util.Optional; /** * Created by prgres on 2019-01-12. */ +@Repository +public interface ProductRepository extends PagingAndSortingRepository { + boolean existsByName(String name); -public interface ProductRepository extends CrudRepository { - List findAll(); + Optional findByName(String name); + + Product findById(long id); } diff --git a/src/main/java/com/dino/scrum/sysmag/service/ProductService.java b/src/main/java/com/dino/scrum/sysmag/service/ProductService.java index 869e29e..77434e9 100644 --- a/src/main/java/com/dino/scrum/sysmag/service/ProductService.java +++ b/src/main/java/com/dino/scrum/sysmag/service/ProductService.java @@ -2,19 +2,24 @@ package com.dino.scrum.sysmag.service; import com.dino.scrum.sysmag.model.Product; import com.dino.scrum.sysmag.model.dto.QuantityChange; - -import java.util.List; -import java.util.Optional; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; /** * Created by prgres on 2019-01-12. */ public interface ProductService { - List getAllProducts(); - Product changeQuantity(QuantityChange quantityChange); - Product getById(Long id); - float getPriceOfAllProducts(); - Product addProduct(Product product); - void deleteProduct(long id); + Slice getAll(Pageable pageable); + + Product changeQuantity(QuantityChange quantityChange) throws Exception; + + Product getById(Long id) throws Exception; + + Product add(Product product) throws Exception; + + float getPriceOfAll(); + + void delete(long id) throws Exception; } + diff --git a/src/main/java/com/dino/scrum/sysmag/service/ProductServiceImpl.java b/src/main/java/com/dino/scrum/sysmag/service/ProductServiceImpl.java index 1c77e15..f1569ad 100644 --- a/src/main/java/com/dino/scrum/sysmag/service/ProductServiceImpl.java +++ b/src/main/java/com/dino/scrum/sysmag/service/ProductServiceImpl.java @@ -3,14 +3,15 @@ package com.dino.scrum.sysmag.service; import com.dino.scrum.sysmag.model.Product; import com.dino.scrum.sysmag.model.dto.QuantityChange; import com.dino.scrum.sysmag.repository.ProductRepository; +import com.dino.scrum.sysmag.validator.ProductValidator; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; -import javax.persistence.EntityNotFoundException; import java.math.BigDecimal; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; /** * Created by prgres on 2019-01-12. @@ -19,57 +20,60 @@ import java.util.stream.Collectors; @Service public class ProductServiceImpl implements ProductService { - private final ProductRepository productRepository; + private final + ProductRepository productRepository; + + private final + ProductValidator productValidator; @Autowired - public ProductServiceImpl(ProductRepository productRepository) { + public ProductServiceImpl(ProductRepository productRepository, ProductValidator productValidator) { this.productRepository = productRepository; + this.productValidator = productValidator; } @Override - public List getAllProducts() { - return productRepository.findAll(); + public Slice getAll(Pageable pageable) { + if (pageable.getSort().isUnsorted()) { + pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), new Sort(Sort.Direction.ASC, "id")); + } + return productRepository.findAll(pageable); } @Override - public Product changeQuantity(QuantityChange quantityChange) { - return productRepository.findById(quantityChange.getId()) - .map(product -> { - product.setQuantity( - product.getQuantity() + quantityChange.getChange() - ); - return productRepository.save(product); - }).orElse(null); + public Product changeQuantity(QuantityChange quantityChange) throws Exception { + productValidator.checkIfExists(quantityChange.getId()); + return productRepository.findById(quantityChange.getId()).setChangeQuantity(quantityChange.getChange()); } @Override - public Product getById(Long id) { - return productRepository.findById(id).orElse(null); + public Product getById(Long id) throws Exception { + productValidator.checkIfExists(id); + return productRepository.findById(id.longValue()); } @Override - public float getPriceOfAllProducts() { + public float getPriceOfAll() { BigDecimal result = new BigDecimal(0); - List tempProductList = productRepository.findAll(); + Iterable tempProductList = productRepository.findAll(); for (Product product : tempProductList) { result = result.add( product.getPrice() .multiply( new BigDecimal(product.getQuantity()))); } - return result.floatValue(); - } @Override - public Product addProduct(Product product) { + public Product add(Product product) throws Exception { + productValidator.checkIfExists(product.getName()); return productRepository.save(product); } @Override - public void deleteProduct(long id) { + public void delete(long id) throws Exception { + productValidator.checkIfExists(id); productRepository.deleteById(id); } - } diff --git a/src/main/java/com/dino/scrum/sysmag/validator/ProductValidator.java b/src/main/java/com/dino/scrum/sysmag/validator/ProductValidator.java new file mode 100644 index 0000000..45556dd --- /dev/null +++ b/src/main/java/com/dino/scrum/sysmag/validator/ProductValidator.java @@ -0,0 +1,38 @@ +package com.dino.scrum.sysmag.validator; + +import com.dino.scrum.sysmag.repository.ProductRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Created by prgres on 2019-01-22. + */ + +@Component +public class ProductValidator { + + private final ProductRepository productRepository; + + @Autowired + public ProductValidator(ProductRepository productRepository) { + this.productRepository = productRepository; + } + + private boolean existsById(long id) { + return productRepository.existsById(id); + } + + private boolean existsByName(String name) { + return productRepository.existsByName(name); + } + + public void checkIfExists(long id) throws Exception { + if (existsById(id)) + throw new Exception("Product with id: " + id + " not found"); + } + + public void checkIfExists(String name) throws Exception { + if (existsByName(name)) + throw new Exception("Product " + name + " already exists"); + } +} diff --git a/src/main/java/com/dino/scrum/sysmag/validator/QuantityChangeValidator.java b/src/main/java/com/dino/scrum/sysmag/validator/QuantityChangeValidator.java new file mode 100644 index 0000000..915a051 --- /dev/null +++ b/src/main/java/com/dino/scrum/sysmag/validator/QuantityChangeValidator.java @@ -0,0 +1,44 @@ +package com.dino.scrum.sysmag.validator; + +import com.dino.scrum.sysmag.model.Product; +import com.dino.scrum.sysmag.model.dto.QuantityChange; +import com.dino.scrum.sysmag.service.ProductServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * Created by prgres on 2019-01-20. + */ + +@Component +public class QuantityChangeValidator { + + private final + ProductServiceImpl productService; + + @Autowired + public QuantityChangeValidator(ProductServiceImpl productService) { + this.productService = productService; + } + + public void validate(QuantityChange quantityChange) throws Exception { + + Product product = productService.getById(quantityChange.getId()); + + if (ifUnderStock(product.getQuantity(), quantityChange.getChange())) { + throw new RuntimeException("Too low product with id: " + quantityChange.getId() + " on stock"); + } + + if (ifAboveMaxLimitStock(product.getQuantity(), product.getQuantityMax(), quantityChange.getChange())) { + throw new RuntimeException("Over max quantity limit of product with id: " + quantityChange.getId()); + } + } + + private boolean ifUnderStock(long quantityOfProduct, long quantityChange) { + return ((quantityOfProduct + quantityChange) < 0); + } + + private boolean ifAboveMaxLimitStock(long quantityOfProduct, long maxQuantityOfProduct, long quantityChange) { + return ((quantityOfProduct + quantityChange) > maxQuantityOfProduct); + } +} \ No newline at end of file