Skip to content

Commit

Permalink
add promotion endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
AnuchitO committed Mar 21, 2024
1 parent 14fdf8d commit 3e6ab2d
Show file tree
Hide file tree
Showing 9 changed files with 303 additions and 29 deletions.
31 changes: 3 additions & 28 deletions kbazaar/src/main/java/com/kampus/kbazaar/cart/CartController.java
Original file line number Diff line number Diff line change
@@ -1,39 +1,14 @@
package com.kampus.kbazaar.cart;

import com.kampus.kbazaar.product.Product;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/v1")
public class CartController {
protected static final Cart[] carts =
new Cart[] {
new Cart(1, new Product[] {new Product(11L, "Product 1", "sku-1", 100.0, 10)}),
new Cart(
2,
new Product[] {
new Product(22L, "Product 2", "sku-2", 200.0, 2),
}),
new Cart(
3,
new Product[] {
new Product(33L, "Product 3", "sku-3", 300.0, 3),
}),
};

@PostMapping("/carts/{id}/additems")
public ResponseEntity<Cart> addProductToCart(
@PathVariable String id, @RequestBody Product[] products) {
Cart cart =
new Cart(
1,
new Product[] {
new Product(11L, "Product 1", "sku-1", 100.0, 10),
new Product(22L, "Product 2", "sku-2", 200.0, 2),
new Product(33L, "Product 3", "sku-3", 300.0, 3),
});

return ResponseEntity.ok(cart);
@GetMapping("/carts")
public ResponseEntity getCart() {
return ResponseEntity.ok().build();
}
}
77 changes: 77 additions & 0 deletions kbazaar/src/main/java/com/kampus/kbazaar/promotion/Promotion.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.kampus.kbazaar.promotion;

import jakarta.persistence.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity(name = "promotion")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Promotion {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "promotion_id")
private Long promotionId;

@Column(name = "code", nullable = false)
private String code;

@Column(name = "name", nullable = false)
private String name;

@Column(name = "description")
private String description;

@Column(name = "start_date", nullable = false)
private LocalDateTime startDate;

@Column(name = "end_date", nullable = false)
private LocalDateTime endDate;

@Column(name = "discount_type", nullable = false)
private String discountType;

@Column(name = "discount_amount")
private BigDecimal discountAmount;

@Column(name = "max_discount_amount")
private BigDecimal maxDiscountAmount;

@Column(name = "applicable_to", nullable = false)
private String applicableTo;

@ElementCollection
@CollectionTable(
name = "promotion_product_skus",
joinColumns = @JoinColumn(name = "promotion_id"))
@Column(name = "product_sku")
private List<String> productSkus;

@Column(name = "min_quantity")
private Integer minQuantity;

@Column(name = "free_quantity")
private Integer freeQuantity;

public PromotionResponse toResponse() {
return new PromotionResponse(
this.promotionId,
this.code,
this.name,
this.description,
this.startDate,
this.endDate,
this.discountType,
this.discountAmount,
this.maxDiscountAmount,
this.applicableTo,
this.productSkus,
this.minQuantity,
this.freeQuantity);
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,72 @@
package com.kampus.kbazaar.promotion;

public class PromotionController {}
import com.kampus.kbazaar.exceptions.NotFoundException;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import java.util.List;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/v1")
public class PromotionController {
private PromotionService promotionService;

public PromotionController(PromotionService promotionService) {
this.promotionService = promotionService;
}

@ApiResponses({
@ApiResponse(
responseCode = "200",
description = "list all promotions",
content = {
@Content(
mediaType = "application/json",
array =
@ArraySchema(
schema =
@Schema(
implementation =
PromotionResponse.class)))
}),
@ApiResponse(
responseCode = "500",
description = "internal server error",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = NotFoundException.class)))
})
@GetMapping("/promotions")
public List<PromotionResponse> getAllPromotions() {
return promotionService.getAll();
}

@ApiResponses({
@ApiResponse(
responseCode = "200",
description = "get promotion by code",
content = {
@Content(
mediaType = "application/json",
schema = @Schema(implementation = PromotionResponse.class))
}),
@ApiResponse(
responseCode = "404",
description = "promotion not found",
content = {
@Content(
mediaType = "application/json",
schema = @Schema(implementation = NotFoundException.class))
})
})
@GetMapping("/promotions/{code}")
public PromotionResponse getPromotionByCode(String code) {
return promotionService.getPromotionByCode(code);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.kampus.kbazaar.promotion;

import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface PromotionRepository extends JpaRepository<Promotion, Long> {
Optional<Promotion> findByCode(String code);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.kampus.kbazaar.promotion;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

public record PromotionResponse(
Long promotionId,
String code,
String name,
String description,
LocalDateTime startDate,
LocalDateTime endDate,
String discountType,
BigDecimal discountAmount,
BigDecimal maxDiscountAmount,
String applicableTo,
List<String> productSkus,
Integer minQuantity,
Integer freeQuantity) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.kampus.kbazaar.promotion;

import com.kampus.kbazaar.exceptions.NotFoundException;
import java.util.List;
import org.springframework.stereotype.Service;

@Service
public class PromotionService {
private PromotionRepository promotionRepository;

public PromotionService(PromotionRepository promotionRepository) {
this.promotionRepository = promotionRepository;
}

public List<PromotionResponse> getAll() {
return promotionRepository.findAll().stream().map(p -> p.toResponse()).toList();
}

public PromotionResponse getPromotionByCode(String code) {
return promotionRepository
.findByCode(code)
.map(p -> p.toResponse())
.orElseThrow(() -> new NotFoundException("Promotion not found"));
}
}
17 changes: 17 additions & 0 deletions kbazaar/src/main/resources/sql/data/promotions.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
INSERT INTO promotion (code, name, description, start_date, end_date, discount_type, discount_amount, applicable_to)
VALUES ('FIXEDAMOUNT10', 'Fixed Amount $10 Off Entire Cart', 'Get $10 off on your entire cart purchase.', '2024-03-25', '2024-04-25', 'FIXED_AMOUNT', 10.00, 'ENTIRE_CART') ON CONFLICT DO NOTHING;

INSERT INTO promotion (code, name, description, start_date, end_date, discount_type, discount_amount, applicable_to)
VALUES ('THIRTYPERCENTOFF', '30% Discount Off Entire Cart', 'Get 30% off on your entire cart purchase.', '2024-03-25', '2024-04-25', 'PERCENTAGE', 30.00, 'ENTIRE_CART') ON CONFLICT DO NOTHING;

INSERT INTO promotion (code, name, description, start_date, end_date, discount_type, discount_amount, max_discount_amount, applicable_to)
VALUES ('THIRTYPERCENTOFFLIMIT200', '30% Discount Up to 200 Baht Off Entire Cart', 'Get 30% off up to 200 Baht on your entire cart purchase.', '2024-03-25', '2024-04-25', 'PERCENTAGE', 30.00, 200.00, 'ENTIRE_CART') ON CONFLICT DO NOTHING;

INSERT INTO promotion (code, name, description, start_date, end_date, discount_type, min_quantity, free_quantity, applicable_to)
VALUES ('BUY1GET1FREE', 'Buy 1 Get 1 Free', 'Buy one product and get one free.', '2024-03-25', '2024-04-25', 'buy1_get1', 1, 1,'ENTIRE_CART') ON CONFLICT DO NOTHING;

INSERT INTO promotion (code, name, description, start_date, end_date, discount_type, min_quantity, free_quantity, applicable_to, product_skus)
VALUES ('BUY2GET1FREE', 'Buy 2 Get 1 Free', 'Buy two products and get one free.', '2024-03-25', '2024-04-25', 'buy2_get1', 2, 1, 'SPECIFIC_PRODUCTS', '{"BEV-FANTA", "BEV-RED-BULL", "BEV-7UP" }') ON CONFLICT DO NOTHING;

INSERT INTO promotion (code, name, description, start_date, end_date, discount_type, discount_amount, applicable_to, product_skus)
VALUES ('SPECIFICPRODUCT30OFF', '30% Discount on Specific Products', 'Get 30% off on specific products.', '2024-03-25', '2024-04-25', 'PERCENTAGE', 30.00, 'SPECIFIC_PRODUCTS', '{"MOBILE-APPLE-IPHONE-12-PRO", "STATIONERY-NOTEBOOK-MOLESKINE"}') ON CONFLICT DO NOTHING;
15 changes: 15 additions & 0 deletions kbazaar/src/main/resources/sql/schema/promotion.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
CREATE TABLE IF NOT EXISTS promotion (
promotion_id SERIAL PRIMARY KEY,
code VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
description TEXT,
start_date TIMESTAMP NOT NULL,
end_date TIMESTAMP NOT NULL,
discount_type VARCHAR(50) NOT NULL,
discount_amount DECIMAL(10, 2),
max_discount_amount DECIMAL(10, 2),
applicable_to VARCHAR(50) NOT NULL,
product_skus VARCHAR(255)[],
min_quantity INT,
free_quantity INT
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.kampus.kbazaar.promotion;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

import com.kampus.kbazaar.exceptions.NotFoundException;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

class PromotionServiceTest {

@Mock private PromotionRepository promotionRepository;

@InjectMocks private PromotionService promotionService;

@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}

@Test
void testGetAll() {
// Arrange
Promotion promotion1 = new Promotion();
Promotion promotion2 = new Promotion();
when(promotionRepository.findAll()).thenReturn(Arrays.asList(promotion1, promotion2));

// Act
List<PromotionResponse> promotionResponses = promotionService.getAll();

// Assert
assertEquals(2, promotionResponses.size());
}

@Test
void testGetPromotionByCode_ExistingCode_ShouldReturnPromotionResponse() {
// Arrange
String code = "BUY2GET1FREE";
Promotion promotion = new Promotion();
promotion.setCode(code);
when(promotionRepository.findByCode(code)).thenReturn(Optional.of(promotion));

// Act
PromotionResponse promotionResponse = promotionService.getPromotionByCode(code);

// Assert
assertNotNull(promotionResponse);
assertEquals(code, promotionResponse.code());
}

@Test
void testGetPromotionByCode_NonExistingCode_ShouldThrowNotFoundException() {
// Arrange
String code = "NON-EXISTING-CODE";
when(promotionRepository.findByCode(code)).thenReturn(Optional.empty());

// Act & Assert
assertThrows(NotFoundException.class, () -> promotionService.getPromotionByCode(code));
}
}

0 comments on commit 3e6ab2d

Please sign in to comment.