From 8a1f0e5a29e668b879f998fdabaff310e2f3a067 Mon Sep 17 00:00:00 2001 From: Nong AnuchitO Date: Fri, 29 Mar 2024 22:13:58 +0700 Subject: [PATCH] update cart entity and simplify backlog --- Backlogs.md | 229 ++++++++++++++---- .../java/com/kampus/kbazaar/cart/Cart.java | 37 ++- 2 files changed, 208 insertions(+), 58 deletions(-) diff --git a/Backlogs.md b/Backlogs.md index e7870fa..259562a 100644 --- a/Backlogs.md +++ b/Backlogs.md @@ -40,6 +40,7 @@ As a Shopper, I want to view a list of available products, so that I can browse - any error should be handled and return 404 Not Found with an appropriate error message if the product doesn't exist. for example: {"message": "Product not found"} with 404 status code + # Story 2: As a Shopper, I want to view details of a specific product by its SKU, so that I can get more information about the product before making a purchase. @@ -73,9 +74,23 @@ As a Product Manager, I want to have pagination for the products, so that I can - Each product object should include id, name, description, price, sku and stock quantity. - The API should support pagination based on the query parameters. - # Story 4: +As an Admin, I want to see list of carts, so that I can manage the carts more efficiently. + +## Acceptance Criteria: +- The API retrieves a list of all carts +- Each cart object includes essential details like username, items, total price, total discount and total amount. + +## Technical Requirements: +- REST API Endpoint: GET /carts +- Response: 200 OK with a list of carts in JSON format +- Each cart object should include username, items, total price, total discount and total amount. +- any error should be handled and return 404 Not Found with an appropriate error message if the cart doesn't exist. + for example: {"message": "Cart not found"} with 404 status code + +# Story 5: + As a Shopper, I want to add a specific product to my cart, so that I can purchase the product later. ## Acceptance Criteria: @@ -93,38 +108,53 @@ As a Shopper, I want to add a specific product to my cart, so that I can purchas - any error should be handled and return 400 Bad Request with an appropriate error message if the request body is invalid. for example: {"message": "Invalid request body"} with 400 status code +## Assumption: + - BFF (Backend for frontend) will handle the stock quantity of the product as well as product information. + - User will be have a cart when they create a user account. -# Story 5: +## Out of Scope: +- The API does not validate the stock quantity of the product. +- The API does not handle the case where the product does not exist. +- The API does not handle the case where the user does not exist. +- The API does not handle the removal of a product from the cart. + + +# Story 6: -As a Shopper, I want to apply a promotion code discount to *my cart*, so that I can get a discount on my purchase. +As a Shopper, I want to apply a *promotion code discount* to *specific product* in my cart, so that I can get a discount on my purchase. ## Acceptance Criteria: -- The API applies the promotion code `FIXEDAMOUNT10` discount to the shopper cart. +- The API applies the promotion code `FIXEDAMOUNT2` discount to the specific product sku `STATIONERY-STAPLER-SWINGLINE` in the shopper cart. +- The promotion code can be applied once at a time. - Returns a 200 OK with the updated cart details if the promotion code is applied successfully. ## Technical Requirements: - REST API Endpoint: POST /carts/{username}/promotions - Path Variable: {username} - Represents the unique user identifier. - Request Body: Content Type: application/json -- Request Body Example: {"code": "FIXEDAMOUNT10"} +- Request Body Example: {"code": "FIXEDAMOUNT2", "productSkus": ["STATIONERY-STAPLER-SWINGLINE"]} -# Story 6: +# Story 7: -As a Shopper, I want to apply a promotion code discount to *specific product* in my cart, so that I can get a discount on my purchase. +As a Shopper, I want to apply a *promotion code discount* to *my cart*, so that I can get a discount on my purchase. ## Acceptance Criteria: -- The API applies the promotion code `FIXEDAMOUNT2` discount to the specific product sku `STATIONERY-STAPLER-SWINGLINE` in the shopper cart. +- The API applies the promotion code `FIXEDAMOUNT10` discount to the shopper cart. +- The promotion code can be applied once at a time. - Returns a 200 OK with the updated cart details if the promotion code is applied successfully. ## Technical Requirements: - REST API Endpoint: POST /carts/{username}/promotions - Path Variable: {username} - Represents the unique user identifier. - Request Body: Content Type: application/json -- Request Body Example: {"code": "FIXEDAMOUNT2", "productSkus": ["STATIONERY-STAPLER-SWINGLINE"]} +- Request Body Example: {"code": "FIXEDAMOUNT10"} +## Assumption: +- BFF (Backend for frontend) will handle the promotion code validation if the promotion code is valid or not. +- BFF will call the promotion endpoint only if the promotion code is valid. -# Story 7: +# Story 8: As a Product Owner, I want to limit the discount amount when shopper apply promotion code to the cart, so that I can control the discount amount. @@ -138,7 +168,7 @@ As a Product Owner, I want to limit the discount amount when shopper apply promo - Request Body: Content Type: application/json - Request Body Example: {"code": "THIRTYPERCENTOFFLIMIT200"} -# Story 8: +# Story 9: As a Shopper, I want to apply a promotional code to get free product, so that I can get a free item on my purchase. @@ -152,7 +182,7 @@ As a Shopper, I want to apply a promotional code to get free product, so that I - Request Body: Content Type: application/json - Request Body Example: {"code": "BUY2GET1FREE"} -# Story 9: +# Story 10: As a Shopper, I want to apply a promotional code to specific product to get discount, so that I can get a discount on my purchase. @@ -165,7 +195,7 @@ As a Shopper, I want to apply a promotional code to specific product to get disc - Request Body: Content Type: application/json - Request Body Example: {"code": "SPECIFICPRODUCT30OFF", "productSkus": ["MOBILE-APPLE-IPHONE-12-PRO"]} -# Story 10: +# Story 11: As a Shopper, I want to to have a promotion applied to a product automatically, so that I can get a discount on my purchase. ## Acceptance Criteria: @@ -178,7 +208,7 @@ As a Shopper, I want to to have a promotion applied to a product automatically, - Request Body: Content Type: application/json - Request Body Example: {"productSku": "MOBILE-APPLE-IPHONE-12-PRO"} -# Story 11: +# Story 12: As a Shopper, I want to earn Kpoints for every purchase, so that I can redeem them for discounts on my next purchase. @@ -197,7 +227,7 @@ As a Shopper, I want to earn Kpoints for every purchase, so that I can redeem th - any error should be handled and return 400 Bad Request with an appropriate error message if the request body is invalid. for example: {"message": "Invalid request body"} with 400 status code -# Story 12: +# Story 13: As a Shopper, I want to redeem Kpoints for a discount on my next purchase, so that I can save money on my order. @@ -216,7 +246,7 @@ As a Shopper, I want to redeem Kpoints for a discount on my next purchase, so th - any error should be handled and return 404 Not Found with an appropriate error message if the Kpoints are insufficient or invalid. for example: {"message": "Insufficient Kpoints"} with 404 status code -# Story 13: +# Story 14: As a Shopper, I want to remove a specific product from my cart, so that I can update my purchase before checking out. @@ -235,7 +265,7 @@ As a Shopper, I want to remove a specific product from my cart, so that I can up - any error should be handled and return 404 Not Found with an appropriate error message if the product doesn't exist in the cart. for example: {"message": "Product not found in the cart"} with 404 status code -# Story 14: +# Story 15: As a Shopper, I want to view my cart details, so that I can review the products and discounts before checking out. @@ -252,7 +282,7 @@ As a Shopper, I want to view my cart details, so that I can review the products - any error should be handled and return 404 Not Found with an appropriate error message if the cart doesn't exist. for example: {"message": "Cart not found"} with 404 status code -# Story 15: +# Story 16: As a Shopper, I want to place an order with the items in my cart, so that I can complete my purchase. @@ -269,7 +299,7 @@ As a Shopper, I want to place an order with the items in my cart, so that I can - any error should be handled and return 400 Bad Request with an appropriate error message if the cart is empty or the stock quantity is insufficient. for example: {"message": "Cart is empty"} with 400 status code -# Story 16: +# Story 17: As a Product Owner I want to be able to charge shopping fee for the order in next 3 months, so that I can cover the delivery cost. @@ -286,7 +316,6 @@ As a Product Owner I want to be able to charge shopping fee for the order in nex - Response: 200 OK with the updated order details if the shopping fee is applied successfully - ## Some hints to help the participants get started with the workshop.
@@ -337,16 +366,78 @@ As a Product Owner I want to be able to charge shopping fee for the order in nex } ``` +3. List Carts (GET /carts): + +```sql +CREATE TABLE IF NOT EXISTS cart ( + id SERIAL PRIMARY KEY, + username VARCHAR(255) NOT NULL, + discount DECIMAL(10, 2) default 0.00, + total_discount DECIMAL(10, 2) default 0.00, + promotion_codes VARCHAR(255) default '', -- comma-separated list of promotion codes + subtotal DECIMAL(10, 2) default 0.00, + grand_total DECIMAL(10, 2) default 0.00 +); +``` + +- Description: Retrieves a list of all carts. +- Response: +- Status Code: 200 OK +- Content Type: application/json +- Example Payload: + +```json +[ + { + "username": "TechNinja", + "items": [ + { + "id": 1, + "username": "TechNinja", + "sku": "MOBILE-APPLE-IPHONE-12-PRO", + "name": "Apple iPhone 12 Pro", + "price": 20990.25, + "quantity": 1, + "discount": 0, + "promotionCodes": "" + } + ], + "discount": 0, + "totalDiscount": 0, + "subtotal": 1, + "grandTotal": 1 + } +] +``` + 3. Add Product to Cart (POST /carts/{username}/items): +```sql +CREATE TABLE IF NOT EXISTS cart_item ( + id SERIAL PRIMARY KEY, + username VARCHAR(255) NOT NULL, + sku VARCHAR(255) NOT NULL default '', + name VARCHAR(255) NOT NULL default '', + price DECIMAL(10, 2) default 0.00, + quantity INT NOT NULL default 0, + discount DECIMAL(10, 2) default 0.00, + promotion_codes VARCHAR(255) NOT NULL default '', -- comma-separated list of promotion codes + UNIQUE (username, sku) +); +``` + - Description: Adds a specific product to the user's cart. - Request: - Content Type: application/json - Example Payload: POST /carts/TechNinja/items ```json { - "productSku": "MOBILE-APPLE-IPHONE-12-PRO", - "quantity": 1 + "sku": "MOBILE-APPLE-IPHONE-12-PRO", + "name": "Apple iPhone 12 Pro", + "price": 20990.25, + "quantity": 1, + "discount": 0, + "promotionCodes": "" } ``` @@ -362,25 +453,32 @@ As a Product Owner I want to be able to charge shopping fee for the order in nex "sku": "MOBILE-APPLE-IPHONE-12-PRO", "name": "Apple iPhone 12 Pro", "quantity": 1, - "price": 100.00, - "discount": 0.00, - "finalPrice": 100.00 + "price": 20990.25, + "discount": 0.00 } ], - "totalPrice": 100.00, + "totalPrice": 20990.25, "totalDiscount": 0.00 } ``` -4. Apply Promotion Code to Cart (POST /carts/{username}/promotions): +4. Apply Promotion Code to Specific Product in Cart (POST /carts/{username}/promotions): -- Description: Applies a promotion code discount to the user's cart. +- Description: Applies a promotion code discount to a specific product in the user's cart. - Request: - Content Type: application/json - Example Payload: POST /carts/TechNinja/promotions ```json { - "code": "FIXEDAMOUNT10" + "code": "FIXEDAMOUNT2", + "name": "Fixed Amount $2 Off Specific Products", + "description": "Get $2 off on specific products.", + "startDate": "2024-03-25T10:30:00.000Z", + "endDate": "2025-05-25T10:30:00.000Z", + "discountType": "FIXED_AMOUNT", + "discountAmount": 2.00, + "applicableTo": "SPECIFIC_PRODUCTS", + "productSkus": "STATIONERY-STAPLER-SWINGLINE,STATIONERY-PENCIL-FABER-CASTELL" } ``` @@ -391,34 +489,46 @@ As a Product Owner I want to be able to charge shopping fee for the order in nex ```json { - "username": "TechNinja", - "items": [ - { - "sku": "MOBILE-APPLE-IPHONE-12-PRO", - "name": "Apple iPhone 12 Pro", - "quantity": 1, - "price": 100.00, - "discount": 10.00, - "finalPrice": 90.00, - "promotions": ["FIXEDAMOUNT10"] - } - ], - "promotions": ["FIXED_A_MOUNT_10"], - "totalPrice": 90.00, - "totalDiscount": 10.00 + "username": "TechNinja", + "items": [ + { + "id": 1, + "username": "TechNinja", + "sku": "STATIONERY-STAPLER-SWINGLINE", + "name": "Staplers", + "price": 20.25, + "quantity": 1, + "discount": 2, + "promotionCodes": "FIXEDAMOUNT2" + } + ], + "discount": 0, + "totalDiscount": 2, + "subtotal": 20.25, + "grandTotal": 18.25, + "promotionCodes": "" } ``` -5. Earn Kpoints (POST /kpoints/{username}/earn): -- Description: Adds Kpoints to the user's account based on the amount spent. + +4. Apply Promotion Code to Cart (POST /carts/{username}/promotions): + +- Description: Applies a promotion code discount to the user's cart. - Request: - Content Type: application/json -- Example Payload: POST /kpoints/TechNinja/earn - +- Example Payload: POST /carts/TechNinja/promotions ```json { - "amount_spent": 100.00 + "code": "FIXEDAMOUNT10", + "name": "Fixed Amount $10 Off Entire Cart", + "description": "Get $10 off on your entire cart purchase.", + "startDate": "2024-03-25T10:30:00.000Z", + "endDate": "2025-05-25T10:30:00.000Z", + "discountType": "FIXED_AMOUNT", + "discountAmount": 10.00, + "applicableTo": "ENTIRE_CART", + "productSkus": "" } ``` @@ -426,10 +536,27 @@ As a Product Owner I want to be able to charge shopping fee for the order in nex - Status Code: 200 OK - Content Type: application/json - Example Payload: + ```json { - "username": "TechNinja", - "kpoints": 10 + "username": "TechNinja", + "items": [ + { + "id": 1, + "username": "TechNinja", + "sku": "MOBILE-APPLE-IPHONE-12-PRO", + "name": "Apple iPhone 12 Pro", + "price": 20990.25, + "quantity": 1, + "discount": 0, + "promotionCodes": "" + } + ], + "discount": 10, + "totalDiscount": 10, + "subtotal": 20990.25, + "grandTotal": 20980.25, + "promotionCodes": "FIXEDAMOUNT10" } ``` diff --git a/kbazaar/src/main/java/com/kampus/kbazaar/cart/Cart.java b/kbazaar/src/main/java/com/kampus/kbazaar/cart/Cart.java index 70902cb..a2f47a4 100644 --- a/kbazaar/src/main/java/com/kampus/kbazaar/cart/Cart.java +++ b/kbazaar/src/main/java/com/kampus/kbazaar/cart/Cart.java @@ -1,16 +1,39 @@ package com.kampus.kbazaar.cart; -import com.kampus.kbazaar.product.Product; +import jakarta.persistence.*; +import java.math.BigDecimal; +import jdk.jfr.Description; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; @Data +@NoArgsConstructor +@AllArgsConstructor +@Entity(name = "cart") public class Cart { - private int userID; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; - private Product[] products; + @Column(name = "username") + private String username; - public Cart(int userID, Product[] products) { - this.userID = userID; - this.products = products; - } + @Column(name = "discount") + private BigDecimal discount; + + @Column(name = "total_discount") + private BigDecimal totalDiscount; + + @Column(name = "promotion_codes") + private String promotionCodes; + + @Description("precisely reflect its pre-discount status") + @Column(name = "subtotal") + private BigDecimal subtotal; + + @Description("the final, all-inclusive amount to be paid.") + @Column(name = "grand_total") + private BigDecimal grandTotal; }