Skip to content

Commit

Permalink
#1105 process to checkout - AC1: Create API to get Product information (
Browse files Browse the repository at this point in the history
#1188)

* add API GET product checkout list

* add test for new method

* add image to response

* fix checkstyle in old code

* config API url

* remove duplicate init product data in test
  • Loading branch information
khanhduzz authored Oct 17, 2024
1 parent e831407 commit c09fd0b
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,18 @@ void test_subtractProductQuantity_shouldSuccess() {

}

@Test
void test_getProductCheckoutList_shouldReturnProductList() {
getGivenSpecificationWithAdmin()
.param("ids", List.of(productOne.getId(), productTwo.getId()))
.when()
.get("/v1/products")
.then()
.statusCode(HttpStatus.OK.value())
.body("productCheckoutListVms", hasSize(2))
.log().ifValidationFails();
}

private RequestSpecification getGivenSpecificationWithAdmin() {
return given(getRequestSpecification())
.auth().oauth2(getAccessToken("admin", "admin"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.yas.product.viewmodel.product.ProductEsDetailVm;
import com.yas.product.viewmodel.product.ProductExportingDetailVm;
import com.yas.product.viewmodel.product.ProductFeatureGetVm;
import com.yas.product.viewmodel.product.ProductGetCheckoutListVm;
import com.yas.product.viewmodel.product.ProductGetDetailVm;
import com.yas.product.viewmodel.product.ProductInfoVm;
import com.yas.product.viewmodel.product.ProductListGetFromCategoryVm;
Expand Down Expand Up @@ -75,10 +76,10 @@ public ResponseEntity<List<ProductExportingDetailVm>> exportProducts(

@PostMapping(path = "/backoffice/products", consumes = {MediaType.APPLICATION_JSON_VALUE})
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "Created",
content = @Content(schema = @Schema(implementation = ProductGetDetailVm.class))),
@ApiResponse(responseCode = "400", description = "Bad request",
content = @Content(schema = @Schema(implementation = ErrorVm.class)))
@ApiResponse(responseCode = "201", description = "Created",
content = @Content(schema = @Schema(implementation = ProductGetDetailVm.class))),
@ApiResponse(responseCode = "400", description = "Bad request",
content = @Content(schema = @Schema(implementation = ErrorVm.class)))
})
public ResponseEntity<ProductGetDetailVm> createProduct(@Valid @RequestBody ProductPostVm productPostVm) {
ProductGetDetailVm productGetDetailVm = productService.createProduct(productPostVm);
Expand All @@ -87,11 +88,11 @@ public ResponseEntity<ProductGetDetailVm> createProduct(@Valid @RequestBody Prod

@PutMapping(path = "/backoffice/products/{id}")
@ApiResponses(value = {
@ApiResponse(responseCode = "204", description = "Updated"),
@ApiResponse(responseCode = "404", description = "Not found",
content = @Content(schema = @Schema(implementation = ErrorVm.class))),
@ApiResponse(responseCode = "400", description = "Bad request",
content = @Content(schema = @Schema(implementation = ErrorVm.class)))
@ApiResponse(responseCode = "204", description = "Updated"),
@ApiResponse(responseCode = "404", description = "Not found",
content = @Content(schema = @Schema(implementation = ErrorVm.class))),
@ApiResponse(responseCode = "400", description = "Bad request",
content = @Content(schema = @Schema(implementation = ErrorVm.class)))
})
public ResponseEntity<Void> updateProduct(@PathVariable long id, @Valid @RequestBody ProductPutVm productPutVm) {
productService.updateProduct(id, productPutVm);
Expand Down Expand Up @@ -139,11 +140,11 @@ public ResponseEntity<ProductDetailGetVm> getProductDetail(@PathVariable("slug")

@DeleteMapping("/backoffice/products/{id}")
@ApiResponses(value = {
@ApiResponse(responseCode = "204", description = "No content", content = @Content()),
@ApiResponse(responseCode = "404", description = "Not found",
content = @Content(schema = @Schema(implementation = ErrorVm.class))),
@ApiResponse(responseCode = "400", description = "Bad request",
content = @Content(schema = @Schema(implementation = ErrorVm.class)))})
@ApiResponse(responseCode = "204", description = "No content", content = @Content()),
@ApiResponse(responseCode = "404", description = "Not found",
content = @Content(schema = @Schema(implementation = ErrorVm.class))),
@ApiResponse(responseCode = "400", description = "Bad request",
content = @Content(schema = @Schema(implementation = ErrorVm.class)))})
public ResponseEntity<Void> deleteProduct(@PathVariable Long id) {
productService.deleteProduct(id);
return ResponseEntity.noContent().build();
Expand All @@ -164,13 +165,13 @@ public ResponseEntity<ProductsGetVm> getProductsByMultiQuery(
}

@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Get product variations by parent id successfully",
content = @Content(mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = ProductVariationGetVm.class)))),
@ApiResponse(responseCode = "400", description = "Bad request",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorVm.class))),
@ApiResponse(responseCode = "404", description = "Not found",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorVm.class)))
@ApiResponse(responseCode = "200", description = "Get product variations by parent id successfully",
content = @Content(mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = ProductVariationGetVm.class)))),
@ApiResponse(responseCode = "400", description = "Bad request",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorVm.class))),
@ApiResponse(responseCode = "404", description = "Not found",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorVm.class)))
})
@GetMapping({"/storefront/product-variations/{id}", "/backoffice/product-variations/{id}"})
public ResponseEntity<List<ProductVariationGetVm>> getProductVariationsByParentId(@PathVariable Long id) {
Expand All @@ -188,23 +189,23 @@ public ResponseEntity<ProductEsDetailVm> getProductEsDetailById(@PathVariable lo
}

@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Get related products by product id successfully",
content = @Content(mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = ProductVariationGetVm.class)))),
@ApiResponse(responseCode = "404", description = "Not found",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorVm.class)))
@ApiResponse(responseCode = "200", description = "Get related products by product id successfully",
content = @Content(mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = ProductVariationGetVm.class)))),
@ApiResponse(responseCode = "404", description = "Not found",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorVm.class)))
})
@GetMapping("/backoffice/products/related-products/{id}")
public ResponseEntity<List<ProductListVm>> getRelatedProductsBackoffice(@PathVariable Long id) {
return ResponseEntity.ok(productService.getRelatedProductsBackoffice(id));
}

@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Get related products by product id successfully",
content = @Content(mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = ProductVariationGetVm.class)))),
@ApiResponse(responseCode = "404", description = "Not found",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorVm.class)))
@ApiResponse(responseCode = "200", description = "Get related products by product id successfully",
content = @Content(mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = ProductVariationGetVm.class)))),
@ApiResponse(responseCode = "404", description = "Not found",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorVm.class)))
})
@GetMapping("/storefront/products/related-products/{id}")
public ResponseEntity<ProductsGetVm> getRelatedProductsStorefront(
Expand All @@ -226,11 +227,11 @@ public ResponseEntity<List<ProductInfoVm>> getProductsForWarehouse(

@PutMapping(path = "/backoffice/products/update-quantity")
@ApiResponses(value = {
@ApiResponse(responseCode = "204", description = "Updated"),
@ApiResponse(responseCode = "404", description = "Not found",
content = @Content(schema = @Schema(implementation = ErrorVm.class))),
@ApiResponse(responseCode = "400", description = "Bad request",
content = @Content(schema = @Schema(implementation = ErrorVm.class)))})
@ApiResponse(responseCode = "204", description = "Updated"),
@ApiResponse(responseCode = "404", description = "Not found",
content = @Content(schema = @Schema(implementation = ErrorVm.class))),
@ApiResponse(responseCode = "400", description = "Bad request",
content = @Content(schema = @Schema(implementation = ErrorVm.class)))})
public ResponseEntity<Void> updateProductQuantity(
@Valid @RequestBody List<ProductQuantityPostVm> productQuantityPostVms
) {
Expand All @@ -241,11 +242,11 @@ public ResponseEntity<Void> updateProductQuantity(

@PutMapping(path = "/backoffice/products/subtract-quantity", consumes = {MediaType.APPLICATION_JSON_VALUE})
@ApiResponses(value = {
@ApiResponse(responseCode = "204", description = "Updated"),
@ApiResponse(responseCode = "404", description = "Not found",
content = @Content(schema = @Schema(implementation = ErrorVm.class))),
@ApiResponse(responseCode = "400", description = "Bad request",
content = @Content(schema = @Schema(implementation = ErrorVm.class)))})
@ApiResponse(responseCode = "204", description = "Updated"),
@ApiResponse(responseCode = "404", description = "Not found",
content = @Content(schema = @Schema(implementation = ErrorVm.class))),
@ApiResponse(responseCode = "400", description = "Bad request",
content = @Content(schema = @Schema(implementation = ErrorVm.class)))})
public ResponseEntity<Void> subtractProductQuantity(
@Valid @RequestBody List<ProductQuantityPutVm> productQuantityPutVm
) {
Expand Down Expand Up @@ -279,4 +280,12 @@ public ResponseEntity<List<ProductListVm>> getLatestProducts(@PathVariable int c
public ResponseEntity<ProductDetailInfoVm> getProductDetailById(@PathVariable("productId") long productId) {
return ResponseEntity.ok(productDetailService.getProductDetailById(productId));
}

@GetMapping("/products")
public ResponseEntity<ProductGetCheckoutListVm> getProductCheckoutList(
@RequestParam(value = "pageNo", defaultValue = "0", required = false) int pageNo,
@RequestParam(value = "pageSize", defaultValue = "20", required = false) int pageSize,
@RequestParam(value = "ids", required = false) List<Long> productIds) {
return ResponseEntity.ok(productService.getProductCheckoutList(pageNo, pageSize, productIds));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,7 @@ List<Product> findProductForWarehouse(@Param("name") String name, @Param("sku")

@Query("SELECT p FROM Product p ORDER BY p.createdOn DESC")
List<Product> getLatestProducts(Pageable pageable);

@Query("SELECT p FROM Product p WHERE p.id IN :productIds AND p.isPublished = TRUE")
Page<Product> findAllPublishedProductsByIds(@Param("productIds") List<Long> productIds, Pageable pageable);
}
24 changes: 24 additions & 0 deletions product/src/main/java/com/yas/product/service/ProductService.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@
import com.yas.product.repository.ProductRepository;
import com.yas.product.utils.Constants;
import com.yas.product.viewmodel.ImageVm;
import com.yas.product.viewmodel.product.ProductCheckoutListVm;
import com.yas.product.viewmodel.product.ProductDetailGetVm;
import com.yas.product.viewmodel.product.ProductDetailVm;
import com.yas.product.viewmodel.product.ProductEsDetailVm;
import com.yas.product.viewmodel.product.ProductExportingDetailVm;
import com.yas.product.viewmodel.product.ProductFeatureGetVm;
import com.yas.product.viewmodel.product.ProductGetCheckoutListVm;
import com.yas.product.viewmodel.product.ProductGetDetailVm;
import com.yas.product.viewmodel.product.ProductInfoVm;
import com.yas.product.viewmodel.product.ProductListGetFromCategoryVm;
Expand Down Expand Up @@ -1152,4 +1154,26 @@ public List<ProductListVm> getProductByBrandIds(List<Long> brandIds) {
return this.productRepository.findByBrandIdsIn(brandIds).stream().map(ProductListVm::fromModel).toList();
}

public ProductGetCheckoutListVm getProductCheckoutList(int pageNo, int pageSize, List<Long> productIds) {
Pageable pageable = PageRequest.of(pageNo, pageSize);
Page<Product> productPage = productRepository.findAllPublishedProductsByIds(productIds, pageable);

List<ProductCheckoutListVm> productCheckoutListVms = productPage.getContent()
.stream().map(product -> {
String thumbnailUrl = mediaService.getMedia(product.getThumbnailMediaId()).url();
ProductCheckoutListVm productCheckoutListVm = ProductCheckoutListVm.fromModel(product);
if (StringUtils.isNotEmpty(thumbnailUrl)) {
return productCheckoutListVm.toBuilder().thumbnailUrl(thumbnailUrl).build();
}
return productCheckoutListVm;
}).toList();
return new ProductGetCheckoutListVm(
productCheckoutListVms,
productPage.getNumber(),
productPage.getSize(),
(int) productPage.getTotalElements(),
productPage.getTotalPages(),
productPage.isLast()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.yas.product.viewmodel.product;

import com.yas.product.model.Product;
import java.time.ZonedDateTime;
import java.util.Objects;
import lombok.Builder;

@Builder(toBuilder = true)
public record ProductCheckoutListVm(Long id,
String name,
String description,
String shortDescription,
String sku,
Long parentId,
Long brandId,
Double price,
Long taxClassId,
String thumbnailUrl,
ZonedDateTime createdOn,
String createdBy,
ZonedDateTime lastModifiedOn,
String lastModifiedBy) {
public static ProductCheckoutListVm fromModel(Product product) {
return new ProductCheckoutListVm(
product.getId(),
product.getName(),
product.getDescription(),
product.getShortDescription(),
product.getSku(),
Objects.isNull(product.getParent()) ? null : product.getParent().getId(),
product.getBrand().getId(),
product.getPrice(),
product.getTaxClassId(),
"",
product.getCreatedOn(),
product.getCreatedBy(),
product.getLastModifiedOn(),
product.getLastModifiedBy()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.yas.product.viewmodel.product;

import java.util.List;

public record ProductGetCheckoutListVm(
List<ProductCheckoutListVm> productCheckoutListVms,
int pageNo,
int pageSize,
int totalElements,
int totalPages,
boolean isLast
) {
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.yas.product.controller;

import com.yas.product.ProductApplication;
import com.yas.product.model.Product;
import com.yas.product.model.enumeration.DimensionUnit;
import com.yas.product.service.ProductDetailService;
import com.yas.product.service.ProductService;
Expand All @@ -9,9 +10,12 @@
import com.yas.product.viewmodel.product.ProductPutVm;
import com.yas.product.viewmodel.product.ProductQuantityPutVm;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
Expand All @@ -20,6 +24,8 @@
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
Expand Down Expand Up @@ -291,4 +297,13 @@ void testGetProductDetailById() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/storefront/products/detail/{productId}", 1))
.andExpect(status().isOk());
}

@Test
void testGetProductCheckoutList_returnListProduct() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/products")
.param("pageNo", "0")
.param("pageSize", "10")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}

0 comments on commit c09fd0b

Please sign in to comment.