From a78caa0a7eb926d6c203d569d70804d3bb5a043e Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 8 Dec 2023 17:04:19 +0800 Subject: [PATCH 01/19] Style: change statement of HTHL error body --- .../ntou/auction/spring/controller/ShoppingcartController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ntou/auction/spring/controller/ShoppingcartController.java b/src/main/java/ntou/auction/spring/controller/ShoppingcartController.java index 37a04f0..72a9d35 100644 --- a/src/main/java/ntou/auction/spring/controller/ShoppingcartController.java +++ b/src/main/java/ntou/auction/spring/controller/ShoppingcartController.java @@ -25,7 +25,7 @@ public class ShoppingcartController { private static final Map ErrorAmountZeroMessage = Collections.singletonMap("message","商品數量不可變為負的"); - private static final Map ErrorAmountExceedMessage = Collections.singletonMap("message","商品數量過多"); + private static final Map ErrorAmountExceedMessage = Collections.singletonMap("message","加入的商品數量過多"); private final UserService userService; From 136b7b25a5de492fd0a2ec23ab5bacb9afc10d19 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 8 Dec 2023 17:06:58 +0800 Subject: [PATCH 02/19] feat: Implement product quantity check to ensure availability --- .../spring/data/entity/Shoppingcart.java | 6 ++++++ .../data/service/ShoppingcartService.java | 17 +++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/main/java/ntou/auction/spring/data/entity/Shoppingcart.java b/src/main/java/ntou/auction/spring/data/entity/Shoppingcart.java index 2bbdc59..6b61d0d 100644 --- a/src/main/java/ntou/auction/spring/data/entity/Shoppingcart.java +++ b/src/main/java/ntou/auction/spring/data/entity/Shoppingcart.java @@ -52,4 +52,10 @@ public boolean deleteProduct(Long product) { productItems.remove(product); return true; } + + public boolean checkIsEnoughAmountInProductItems(Long product, Long amount) { + if(amount.equals(0L)) return true; // this may not be happened + if(!productItems.containsKey(product)) return false; + return productItems.get(product) >= amount; + } } diff --git a/src/main/java/ntou/auction/spring/data/service/ShoppingcartService.java b/src/main/java/ntou/auction/spring/data/service/ShoppingcartService.java index c3d9e3c..665792e 100644 --- a/src/main/java/ntou/auction/spring/data/service/ShoppingcartService.java +++ b/src/main/java/ntou/auction/spring/data/service/ShoppingcartService.java @@ -78,4 +78,21 @@ public boolean deleteProductByUserId(Long userId, Long productId) { if (userShoppingcart.getProductItems().isEmpty()) repository.deleteByUserid(userId); return true; } + + public boolean checkIsEnoughAmount(Long userId, Long productId, Long amount) { + Shoppingcart userShoppingcart = getByUserId(userId); + if (userShoppingcart == null) return false; + return userShoppingcart.checkIsEnoughAmountInProductItems(productId, amount); + } + + public Long checkIsProductAllInShoppingCart(List> order, Long userid) { + // -1: format error, 0: false, 1: true + for(List product: order) { + if(product.size()!=2) return -1L; + if(!checkIsEnoughAmount(userid, product.get(0), product.get(1))) { + return 0L; + } + } + return 1L; + } } From c1ebb5e7ab0691e6ab53f30fb1fca274c3926aee Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 8 Dec 2023 17:08:26 +0800 Subject: [PATCH 03/19] feat: Introduce order system functionality. --- .../auction/spring/data/entity/Order.java | 37 +++++ .../spring/data/service/OrderRepository.java | 36 +++++ .../spring/data/service/OrderService.java | 148 ++++++++++++++++++ 3 files changed, 221 insertions(+) create mode 100644 src/main/java/ntou/auction/spring/data/entity/Order.java create mode 100644 src/main/java/ntou/auction/spring/data/service/OrderRepository.java create mode 100644 src/main/java/ntou/auction/spring/data/service/OrderService.java diff --git a/src/main/java/ntou/auction/spring/data/entity/Order.java b/src/main/java/ntou/auction/spring/data/entity/Order.java new file mode 100644 index 0000000..b293623 --- /dev/null +++ b/src/main/java/ntou/auction/spring/data/entity/Order.java @@ -0,0 +1,37 @@ +package ntou.auction.spring.data.entity; + +import ch.qos.logback.core.joran.sanity.Pair; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.persistence.*; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.util.*; + +@Entity +@Data +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "orders") +public class Order extends AbstractEntity { + @NotNull + private Long buyerid; + + @NotNull + private Long sellerid; + + private List> productAddAmountList = new ArrayList<>(); + + @NotNull + private Long status; // 0: reject, 1: waiting for submit, 2: submitted but not paid, 3: order done + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + public void addProductAddAmount(List product) { + productAddAmountList.add(product); + } +} diff --git a/src/main/java/ntou/auction/spring/data/service/OrderRepository.java b/src/main/java/ntou/auction/spring/data/service/OrderRepository.java new file mode 100644 index 0000000..83a8496 --- /dev/null +++ b/src/main/java/ntou/auction/spring/data/service/OrderRepository.java @@ -0,0 +1,36 @@ +package ntou.auction.spring.data.service; + +import jakarta.transaction.Transactional; +import ntou.auction.spring.data.entity.Order; +import ntou.auction.spring.data.entity.Shoppingcart; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; +import java.util.Optional; + +public interface OrderRepository extends JpaRepository, JpaSpecificationExecutor { + Optional findById(Long id); + @Query(value = "select * from orders o where o.buyerid = ?1", nativeQuery = true) + List findAllByBuyerid(Long buyer); + + @Query(value = "select * from orders o where o.buyerid = ?1 and o.status = 0", nativeQuery = true) + List findRejectByBuyerid(Long buyer); + + @Query(value = "select * from orders o where o.buyerid = ?1 and o.status = 1", nativeQuery = true) + List findWaitingByBuyerid(Long buyer); + + @Query(value = "select * from orders o where o.buyerid = ?1 and o.status = 2", nativeQuery = true) + List findSubmittedByBuyerid(Long buyer); + + @Query(value = "select * from orders o where o.buyerid = ?1 and o.status = 3", nativeQuery = true) + List findDoneByBuyerid(Long buyer); + + @Query(value = "select * from orders o where o.sellerid = ?1 and o.status = 1", nativeQuery = true) + List findWaitingBySellerid(Long seller); + @Modifying + @Query(value = "insert into shoppingcart(userId, productId) values (?1, ?2)", nativeQuery = true) + public void addShoppingCart(Long userId, List productId); +} diff --git a/src/main/java/ntou/auction/spring/data/service/OrderService.java b/src/main/java/ntou/auction/spring/data/service/OrderService.java new file mode 100644 index 0000000..d8101c5 --- /dev/null +++ b/src/main/java/ntou/auction/spring/data/service/OrderService.java @@ -0,0 +1,148 @@ +package ntou.auction.spring.data.service; + +import ntou.auction.spring.data.entity.Order; +import ntou.auction.spring.data.entity.OrderWithProductDetail; +import ntou.auction.spring.data.entity.ProductAddAmount; +import org.springframework.stereotype.Service; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; + +@Service +public class OrderService { + private final OrderRepository repository; + + private final ProductService productService; + + private final ShoppingcartService shoppingcartService; + + private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + public OrderService(OrderRepository repository, ProductService productService, ShoppingcartService shoppingcartService) { + this.repository = repository; + this.productService = productService; + this.shoppingcartService = shoppingcartService; + } + public Order findOrderById(Long Id) { + return repository.findById(Id).orElse(null); + } + public List findAllByBuyerId(Long buyerId) { + return repository.findAllByBuyerid(buyerId); + } + + public List findRejectByBuyerId(Long buyerId) { + return repository.findRejectByBuyerid(buyerId); + } + + public List findWaitingByBuyerId(Long buyerId) { + return repository.findWaitingByBuyerid(buyerId); + } + + public List findSubmittedByBuyerId(Long buyerId) { + return repository.findSubmittedByBuyerid(buyerId); + } + + public List findDoneByBuyerId(Long buyerId) { + return repository.findDoneByBuyerid(buyerId); + } + + public List findWaitingBySellerId(Long sellerId) { + return repository.findWaitingBySellerid(sellerId); + } + + public Long submitOrder(Long orderId, Long userId) { + // for status -> 0: reject, 1: waiting for submit, 2: submitted but not paid, 3: order done + // for return -> 0: orderNotFound, 1: statusError, 2: idError, 3: success, -1: expired + Order getorder = repository.findById(orderId).orElse(null); + if(getorder == null) return 0L; + if(!getorder.getStatus().equals(1L)) return 1L; + if(!Objects.equals(findOrderById(orderId).getSellerid(), userId)) return 2L; + getorder.setStatus(2L); + repository.save(getorder); + return 3L; + } + + public Long rejectOrder(Long orderId, Long userId) { + // 0: reject, 1: waiting for submit, 2: submitted but not paid, 3: order done + // for return -> 0: orderNotFound, 1: statusError, 2: idError, 3: success, -1: expired + Order getorder = repository.findById(orderId).orElse(null); + if(getorder == null) return 0L; + if(!getorder.getStatus().equals(1L)) return 1L; + if(!Objects.equals(findOrderById(orderId).getSellerid(), userId)) return 2L; + getorder.setStatus(0L); + repository.save(getorder); + return 3L; + } + + public Long cancelOrder(Long orderId, Long userId) { + // 0: reject, 1: waiting for submit, 2: submitted but not paid, 3: order done + // for return -> 0: orderNotFound, 1: statusError, 2: idError, 3: success, -1: expired + Order getorder = repository.findById(orderId).orElse(null); + if(getorder == null) return 0L; + if(getorder.getStatus().equals(3L) || getorder.getStatus().equals(0L)) return 1L; + if(!Objects.equals(findOrderById(orderId).getBuyerid(), userId)) return 2L; + if(Duration.between(getorder.getUpdateTime(), LocalDateTime.parse(LocalDateTime.now().format(formatter), formatter)).toSeconds()>(86400*7L)) return -1L; + getorder.setStatus(0L); + repository.save(getorder); + return 3L; + } + // make order be done + public Long doneOrder(Long orderId, Long userId) { + // 0: reject, 1: waiting for submit, 2: submitted but not paid, 3: order done + // for return -> 0: orderNotFound, 1: statusError, 2: idError, 3: success, -1: expired + Order getorder = repository.findById(orderId).orElse(null); + if(getorder == null) return 0L; + if(!getorder.getStatus().equals(2L)) return 1L; + if(!Objects.equals(findOrderById(orderId).getSellerid(), userId)) return 2L; + getorder.setStatus(3L); + repository.save(getorder); + return 3L; + } + + public boolean addOrder(Order order) { + boolean check = checkIsSameSeller(order.getProductAddAmountList()); + if(!check) return false; + repository.save(order); + return true; + } + + private boolean checkIsSameSeller(List> list) { + Set check = new HashSet<>(); + for(List productAddAmount: list) { + check.add(productService.getID(productAddAmount.get(0)).getSellerID()); + } + return check.size()==1; + } + + public List orderToOrderWithProductDetail(List getOrder) { + List result = new ArrayList<>(); + for(Order order: getOrder) { + OrderWithProductDetail addOrder = new OrderWithProductDetail(); + addOrder.setSellerid(order.getSellerid()); + addOrder.setBuyerid(order.getBuyerid()); + addOrder.setUpdateTime(order.getUpdateTime()); + addOrder.setStatus(order.getStatus()); + addOrder.setOrderid(order.getId()); + List temp = new ArrayList<>(); + for (List product : order.getProductAddAmountList()) { + temp.add(new ProductAddAmount(productService.getID(product.get(0)), product.get(1))); + } + addOrder.setProductAddAmountList(temp); + result.add(addOrder); + } + return result; + } + + public boolean addAmountToProduct(Order order) { + // (order == null) this may not be happened + if(order==null) return false; + // add product amount with amount + for(List eachProduct: order.getProductAddAmountList()) { + productService.productAmountIncrease(eachProduct.get(0), eachProduct.get(1)); + } + return true; + } + +} From 0f50d28bdead5e2861086ed62ca2155d19d3b3d1 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 8 Dec 2023 17:09:25 +0800 Subject: [PATCH 04/19] feat: Implement order controller for managing and processing orders. --- .../spring/controller/OrderController.java | 186 ++++++++++++++++++ .../spring/data/entity/AddOrderRequest.java | 18 ++ .../data/entity/OperateOrderRequest.java | 14 ++ .../data/entity/OrderWithProductDetail.java | 35 ++++ 4 files changed, 253 insertions(+) create mode 100644 src/main/java/ntou/auction/spring/controller/OrderController.java create mode 100644 src/main/java/ntou/auction/spring/data/entity/AddOrderRequest.java create mode 100644 src/main/java/ntou/auction/spring/data/entity/OperateOrderRequest.java create mode 100644 src/main/java/ntou/auction/spring/data/entity/OrderWithProductDetail.java diff --git a/src/main/java/ntou/auction/spring/controller/OrderController.java b/src/main/java/ntou/auction/spring/controller/OrderController.java new file mode 100644 index 0000000..f9f9041 --- /dev/null +++ b/src/main/java/ntou/auction/spring/controller/OrderController.java @@ -0,0 +1,186 @@ +package ntou.auction.spring.controller; + +import jakarta.validation.Valid; +import ntou.auction.spring.data.entity.*; +import ntou.auction.spring.data.service.*; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; + +@RestController +@RequestMapping(value = "/api/v1/order", produces = MediaType.APPLICATION_JSON_VALUE) +@CrossOrigin(origins = "http://localhost:3000") +public class OrderController { + private final OrderService orderService; + private final ProductService productService; + + private final ShoppingcartService shoppingcartService; + private final UserService userService; + + private final UserIdentity userIdentity; + + private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + private static final Map successMessage = Collections.singletonMap("message", "成功"); + private static final Map failMessage = Collections.singletonMap("message", "操作失敗"); + + private static final Map tooManySellerMessage = Collections.singletonMap("message", "訂單的賣家只能來自同一位"); + + private static final Map orderNotFound = Collections.singletonMap("message", "訂單不存在"); + + private static final Map statusError = Collections.singletonMap("message", "該狀態下無法進行操作"); + + private static final Map identityError = Collections.singletonMap("message", "該狀身分下無法進行操作"); + + private static final Map formatError = Collections.singletonMap("message", "格式錯誤"); + + private static final Map notFoundInShoppingCartError = Collections.singletonMap("message", "商品不在購物車中或購買數量過多"); + + public OrderController(OrderService orderService, ProductService productService, ShoppingcartService shoppingcartService, UserService userService, UserIdentity userIdentity) { + this.orderService = orderService; + this.productService = productService; + this.shoppingcartService = shoppingcartService; + this.userService = userService; + this.userIdentity = userIdentity; + } + + @GetMapping("/order/all") + List getAllByBuyer() { + Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); + List getOrder = orderService.findAllByBuyerId(userId); + return orderService.orderToOrderWithProductDetail(getOrder); + } + + @GetMapping("/order/reject") + List getRejectByBuyer() { + Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); + return orderService.orderToOrderWithProductDetail(orderService.findRejectByBuyerId(userId)); + } + + @GetMapping("/order/waiting") + List getWaitingByBuyer() { + Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); + return orderService.orderToOrderWithProductDetail(orderService.findWaitingByBuyerId(userId)); + } + + @GetMapping("/order/submit") + List getSubmitByBuyer() { + Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); + return orderService.orderToOrderWithProductDetail(orderService.findSubmittedByBuyerId(userId)); + } + + @GetMapping("/check") + List getWaitingBySeller() { + // filter Waited order with seller + Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); + return orderService.orderToOrderWithProductDetail(orderService.findWaitingBySellerId(userId)); + } + + @PostMapping("/create") + ResponseEntity> addOrder(@Valid @RequestBody AddOrderRequest request) { + Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); + List> getrequest = request.getProductList(); + // check -> -1: format error, 0: false, 1: true + Long check = shoppingcartService.checkIsProductAllInShoppingCart(getrequest, userId); + if(check.equals(-1L)) return ResponseEntity.badRequest().body(formatError); + if(check.equals(0L)) return ResponseEntity.badRequest().body(notFoundInShoppingCartError); + + // order status -> 0: reject, 1: waiting for submit, 2: submitted but not paid, 3: order done + Order order = new Order(); + order.setBuyerid(userId); + order.setUpdateTime(LocalDateTime.parse(LocalDateTime.now().format(formatter), formatter)); + order.setStatus(1L); + + for (List eachProductAddAmount : getrequest) { + Long productId = eachProductAddAmount.get(0); + Long amount = eachProductAddAmount.get(1); + Product getProduct = productService.getID(productId); + // Id error + if (getProduct == null) { + Map ErrorIdMessage = Collections.singletonMap("message", "商品(ID:" + productId + ")不存在"); + return ResponseEntity.badRequest().body(ErrorIdMessage); + } + // amount exceed + if (amount > getProduct.getProductAmount()) { + Map amountExceedReturn = Collections.singletonMap("message", "商品數量(" + getProduct.getProductName() + ")過多"); + return ResponseEntity.badRequest().body(amountExceedReturn); + } + order.setSellerid(getProduct.getSellerID()); + List input = new ArrayList<>(); + input.add(productId); + input.add(amount); + order.addProductAddAmount(input); + // decrease product's amount by amount + productService.productAmountDecrease(productId, amount); + } + // delete Product amount in Shopping cart + for (List eachProductAddAmount : getrequest) { + shoppingcartService.decreaseProductByUserId(userId, eachProductAddAmount.get(0), eachProductAddAmount.get(1)); + } + boolean result = orderService.addOrder(order); + if (!result) return ResponseEntity.badRequest().body(tooManySellerMessage); + return ResponseEntity.ok(successMessage); + } + + @PostMapping("/makesubmit") + ResponseEntity> makeSubmit(@Valid @RequestBody OperateOrderRequest request) { + Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); + Long orderId = request.getOrderId(); + if (orderId == null) return ResponseEntity.badRequest().body(failMessage); + // result -> 0: orderNotFound, 1: statusError, 2: idError, 3: success + Long result = orderService.submitOrder(orderId, userId); + if (result.equals(0L)) return ResponseEntity.badRequest().body(orderNotFound); + if (result.equals(1L)) return ResponseEntity.badRequest().body(statusError); + if (result.equals(2L)) return ResponseEntity.badRequest().body(identityError); + return ResponseEntity.ok(successMessage); + } + + @PostMapping("/makedone") + ResponseEntity> makeDone(@Valid @RequestBody OperateOrderRequest request) { + Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); + Long orderId = request.getOrderId(); + if (orderId == null) return ResponseEntity.badRequest().body(failMessage); + // result -> 0: orderNotFound, 1: statusError, 2: idError, 3: success + Long result = orderService.doneOrder(orderId, userId); + if (result.equals(0L)) return ResponseEntity.badRequest().body(orderNotFound); + if (result.equals(1L)) return ResponseEntity.badRequest().body(statusError); + if (result.equals(2L)) return ResponseEntity.badRequest().body(identityError); + return ResponseEntity.ok(successMessage); + } + + @PostMapping("/makereject") + ResponseEntity> makeReject(@Valid @RequestBody OperateOrderRequest request) { + Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); + Long orderId = request.getOrderId(); + if (orderId == null) return ResponseEntity.badRequest().body(failMessage); + // 0: orderNotFound, 1: statusError, 2: idError, 3: success + Long result = orderService.rejectOrder(orderId, userId); + if (result.equals(0L)) return ResponseEntity.badRequest().body(orderNotFound); + if (result.equals(1L)) return ResponseEntity.badRequest().body(statusError); + if (result.equals(2L)) return ResponseEntity.badRequest().body(identityError); + boolean check = orderService.addAmountToProduct(orderService.findOrderById(orderId)); + if (!check) return ResponseEntity.badRequest().body(orderNotFound); //this may not be happened + return ResponseEntity.ok(successMessage); + } + + @PostMapping("/makecancel") + ResponseEntity> makeCancel(@Valid @RequestBody OperateOrderRequest request) { + Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); + Long orderId = request.getOrderId(); + if (orderId == null) return ResponseEntity.badRequest().body(failMessage); + // 0: orderNotFound, 1: statusError, 2: idError, 3: success, -1: expired + Long result = orderService.cancelOrder(orderId, userId); + if (result.equals(0L)) return ResponseEntity.badRequest().body(orderNotFound); + if (result.equals(1L)) return ResponseEntity.badRequest().body(statusError); + if (result.equals(2L)) return ResponseEntity.badRequest().body(identityError); + Map expiredError = Collections.singletonMap("message", "超過7天無法取消訂單"); + if (result.equals(-1L)) return ResponseEntity.badRequest().body(expiredError); + Order thisOrder = orderService.findOrderById(orderId); + boolean check = orderService.addAmountToProduct(thisOrder); + if(!check) return ResponseEntity.badRequest().body(orderNotFound); // this may not be happened + return ResponseEntity.ok(successMessage); + } +} diff --git a/src/main/java/ntou/auction/spring/data/entity/AddOrderRequest.java b/src/main/java/ntou/auction/spring/data/entity/AddOrderRequest.java new file mode 100644 index 0000000..d0da843 --- /dev/null +++ b/src/main/java/ntou/auction/spring/data/entity/AddOrderRequest.java @@ -0,0 +1,18 @@ +package ntou.auction.spring.data.entity; + +import ch.qos.logback.core.joran.sanity.Pair; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class AddOrderRequest { + //List -> (productid, amount) + @NotNull + List> productList; +} diff --git a/src/main/java/ntou/auction/spring/data/entity/OperateOrderRequest.java b/src/main/java/ntou/auction/spring/data/entity/OperateOrderRequest.java new file mode 100644 index 0000000..2eaf0fb --- /dev/null +++ b/src/main/java/ntou/auction/spring/data/entity/OperateOrderRequest.java @@ -0,0 +1,14 @@ +package ntou.auction.spring.data.entity; + +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OperateOrderRequest { + @NotNull + Long orderId; +} diff --git a/src/main/java/ntou/auction/spring/data/entity/OrderWithProductDetail.java b/src/main/java/ntou/auction/spring/data/entity/OrderWithProductDetail.java new file mode 100644 index 0000000..a1f207c --- /dev/null +++ b/src/main/java/ntou/auction/spring/data/entity/OrderWithProductDetail.java @@ -0,0 +1,35 @@ +package ntou.auction.spring.data.entity; + +import ch.qos.logback.core.joran.sanity.Pair; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDateTime; +import java.util.*; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class OrderWithProductDetail { + @NotNull + private Long orderid; + + @NotNull + private Long buyerid; + + @NotNull + private Long sellerid; + + private List productAddAmountList = new ArrayList<>(); + + @NotNull + private Long status; // 0: reject, 1: waiting for submit, 2: submitted but not paid, 3: order done + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; +} From 7c784492f820f2ea4ad7000ffecfba71e4233d4a Mon Sep 17 00:00:00 2001 From: weichunnien Date: Mon, 11 Dec 2023 22:56:31 +0800 Subject: [PATCH 05/19] fix: add attribute Visible for seller to pull their product from the shelves(set visible false) --- src/main/java/ntou/auction/spring/data/entity/Product.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/ntou/auction/spring/data/entity/Product.java b/src/main/java/ntou/auction/spring/data/entity/Product.java index 1742e15..b46f191 100644 --- a/src/main/java/ntou/auction/spring/data/entity/Product.java +++ b/src/main/java/ntou/auction/spring/data/entity/Product.java @@ -57,6 +57,8 @@ public class Product extends AbstractEntity { private Boolean isAuction; //競標商品已經被加進購物車? + private Boolean visible; + @NotNull @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") private LocalDateTime updateTime; From 35858f7c5c157d770c29151d69265a03f0b77096 Mon Sep 17 00:00:00 2001 From: weichunnien Date: Mon, 11 Dec 2023 23:01:34 +0800 Subject: [PATCH 06/19] =?UTF-8?q?fix:=20=E8=AA=BF=E6=95=B4=E7=80=8F?= =?UTF-8?q?=E8=A6=BD=E8=88=87=E6=90=9C=E5=B0=8B=E6=A2=9D=E4=BB=B6=20?= =?UTF-8?q?=E5=BF=85=E9=A0=88=E7=82=BAvisible=20true?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ntou/auction/spring/data/service/ProductRepository.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/ntou/auction/spring/data/service/ProductRepository.java b/src/main/java/ntou/auction/spring/data/service/ProductRepository.java index 784419b..2913dcd 100644 --- a/src/main/java/ntou/auction/spring/data/service/ProductRepository.java +++ b/src/main/java/ntou/auction/spring/data/service/ProductRepository.java @@ -17,16 +17,17 @@ public interface ProductRepository extends JpaRepository, List findAllByIsFixedPriceFalseAndIsAuctionFalse(); + List findAllByVisibleTrue(); Product findById(long id); @Query("select p from Product p " + - "where p.productName like %?1%") //string-like + "where p.productName like %?1% and p.visible = true") //string-like List findAllByFuzzyProductName(@Param("productName") String productName); // ?1:productName List findBySellerID(long ID); - List findAllByProductType(String productType); + List findAllByProductTypeAndVisibleTrue(String productType); } From 7e8100926020bf310c07cc66ae76e42dc998ec26 Mon Sep 17 00:00:00 2001 From: weichunnien Date: Mon, 11 Dec 2023 23:06:09 +0800 Subject: [PATCH 07/19] =?UTF-8?q?feat:=20=E8=B3=A3=E5=AE=B6=E5=8F=AF?= =?UTF-8?q?=E4=BB=A5=E4=B8=8B=E6=9E=B6=E5=95=86=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spring/controller/ProductController.java | 13 +++++++++++++ .../auction/spring/data/service/ProductService.java | 13 +++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/main/java/ntou/auction/spring/controller/ProductController.java b/src/main/java/ntou/auction/spring/controller/ProductController.java index 39d1d49..1efb781 100644 --- a/src/main/java/ntou/auction/spring/controller/ProductController.java +++ b/src/main/java/ntou/auction/spring/controller/ProductController.java @@ -85,6 +85,7 @@ ResponseEntity> postProduct(@Valid @RequestBody PostFixedPric product.setBidIncrement(null); product.setProductAmount(request.getProductAmount()); product.setIsAuction(false); + product.setVisible(true); product.setSellerID(userService.findByUsername(userIdentity.getUsername()).getId()); product.setSellerName(userIdentity.getUsername()); @@ -113,6 +114,7 @@ ResponseEntity> postProduct(@Valid @RequestBody PostNonFixedP product.setBidIncrement(request.getBidIncrement()); product.setProductAmount(1L); product.setIsAuction(false); + product.setVisible(true); LocalDateTime now = LocalDateTime.now(); @@ -153,6 +155,17 @@ ResponseEntity> bidProduct(@Valid @RequestBody BidRequest req return ResponseEntity.ok(successMessage); } + @DeleteMapping("/{ID}") + ResponseEntity> deleteProduct(@PathVariable long ID){ + Map successMessage = Collections.singletonMap("message","成功刪除"); + + Product p = productService.getID(ID); + p.setVisible(false); + productService.store(p); + + return ResponseEntity.ok(successMessage); + } + @PostMapping("/buy") ResponseEntity> buyProduct(@Valid @RequestBody BuyProductRequest request){ diff --git a/src/main/java/ntou/auction/spring/data/service/ProductService.java b/src/main/java/ntou/auction/spring/data/service/ProductService.java index 107b7f4..5de58d6 100644 --- a/src/main/java/ntou/auction/spring/data/service/ProductService.java +++ b/src/main/java/ntou/auction/spring/data/service/ProductService.java @@ -34,8 +34,8 @@ public void delete(Long id) { } */ public List list() { - return repository.findAll(); - } + return repository.findAllByVisibleTrue(); + } //browse homepage public Product getID(Long id){ return repository.findById(id).orElse(null); @@ -80,18 +80,23 @@ public void productAmountIncrease(Long id,Long increment){ product.setProductAmount(productAmount + increment); this.store(product); } + public void deleteProduct(Long id){ + Product product = this.getID(id); + product.setVisible(false); + this.store(product); + } public List findByProductName(String productName) { return repository.findAllByFuzzyProductName(productName); } public List findByProductClassification(String productType){ - return repository.findAllByProductType(productType); + return repository.findAllByProductTypeAndVisibleTrue(productType); } public List findByProductNonFixed(){ return repository.findAllByIsFixedPriceFalseAndIsAuctionFalse(); } - public List findBySellerID(Long sellerID){return repository.findBySellerID(sellerID);}//賣家中心 + public List findBySellerID(Long sellerID){return repository.findBySellerIDAndVisibleTrue(sellerID);}//賣家中心 } From 3502bc321d4666982d4ead0be3279a5fc6dde193 Mon Sep 17 00:00:00 2001 From: weichunnien Date: Mon, 11 Dec 2023 23:06:43 +0800 Subject: [PATCH 08/19] =?UTF-8?q?fix:=20=E8=B3=A3=E5=AE=B6=E4=B8=AD?= =?UTF-8?q?=E5=BF=83=E4=B8=8D=E6=9C=83=E9=A1=AF=E7=A4=BA=E8=B3=A3=E5=AE=B6?= =?UTF-8?q?=E4=B8=8B=E6=9E=B6=E4=B9=8B=E5=95=86=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ntou/auction/spring/data/service/ProductRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ntou/auction/spring/data/service/ProductRepository.java b/src/main/java/ntou/auction/spring/data/service/ProductRepository.java index 2913dcd..b9281b5 100644 --- a/src/main/java/ntou/auction/spring/data/service/ProductRepository.java +++ b/src/main/java/ntou/auction/spring/data/service/ProductRepository.java @@ -25,7 +25,7 @@ public interface ProductRepository extends JpaRepository, List findAllByFuzzyProductName(@Param("productName") String productName); // ?1:productName - List findBySellerID(long ID); + List findBySellerIDAndVisibleTrue(long ID); List findAllByProductTypeAndVisibleTrue(String productType); From 9abdbcf79409a6ede3316e9037abbf0626720572 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 13 Dec 2023 21:58:11 +0800 Subject: [PATCH 09/19] style: change the statement of HTML bad request body and the url of getSubmitByBuyer --- .../java/ntou/auction/spring/controller/OrderController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ntou/auction/spring/controller/OrderController.java b/src/main/java/ntou/auction/spring/controller/OrderController.java index f9f9041..aa2fce9 100644 --- a/src/main/java/ntou/auction/spring/controller/OrderController.java +++ b/src/main/java/ntou/auction/spring/controller/OrderController.java @@ -31,7 +31,7 @@ public class OrderController { private static final Map orderNotFound = Collections.singletonMap("message", "訂單不存在"); - private static final Map statusError = Collections.singletonMap("message", "該狀態下無法進行操作"); + private static final Map statusError = Collections.singletonMap("message", "無法對目前訂單進行操作"); private static final Map identityError = Collections.singletonMap("message", "該狀身分下無法進行操作"); @@ -66,7 +66,7 @@ List getWaitingByBuyer() { return orderService.orderToOrderWithProductDetail(orderService.findWaitingByBuyerId(userId)); } - @GetMapping("/order/submit") + @GetMapping("/order/accept") List getSubmitByBuyer() { Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); return orderService.orderToOrderWithProductDetail(orderService.findSubmittedByBuyerId(userId)); From af2a89991f5fb126996284cafcf556e0bfee9b7b Mon Sep 17 00:00:00 2001 From: weichunnien Date: Fri, 15 Dec 2023 20:40:35 +0800 Subject: [PATCH 10/19] =?UTF-8?q?feat:=20=E8=B3=A3=E5=AE=B6=E4=B8=AD?= =?UTF-8?q?=E5=BF=83=E4=B9=8B=E5=95=86=E5=93=81=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spring/controller/ProductController.java | 81 ++++++++++++++++--- .../UpdateFixedPriceProductRequest.java | 41 ++++++++++ .../UpdateNonFixedPriceProductRequest.java | 48 +++++++++++ 3 files changed, 161 insertions(+), 9 deletions(-) create mode 100644 src/main/java/ntou/auction/spring/data/entity/UpdateFixedPriceProductRequest.java create mode 100644 src/main/java/ntou/auction/spring/data/entity/UpdateNonFixedPriceProductRequest.java diff --git a/src/main/java/ntou/auction/spring/controller/ProductController.java b/src/main/java/ntou/auction/spring/controller/ProductController.java index 1efb781..67f4424 100644 --- a/src/main/java/ntou/auction/spring/controller/ProductController.java +++ b/src/main/java/ntou/auction/spring/controller/ProductController.java @@ -15,6 +15,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; @RestController @@ -155,16 +156,7 @@ ResponseEntity> bidProduct(@Valid @RequestBody BidRequest req return ResponseEntity.ok(successMessage); } - @DeleteMapping("/{ID}") - ResponseEntity> deleteProduct(@PathVariable long ID){ - Map successMessage = Collections.singletonMap("message","成功刪除"); - - Product p = productService.getID(ID); - p.setVisible(false); - productService.store(p); - return ResponseEntity.ok(successMessage); - } @PostMapping("/buy") ResponseEntity> buyProduct(@Valid @RequestBody BuyProductRequest request){ @@ -219,4 +211,75 @@ List getProductInSellerCenter() { return productService.findBySellerID(userService.findByUsername(userIdentity.getUsername()).getId()); } + @DeleteMapping("/{ID}") + ResponseEntity> deleteProduct(@PathVariable long ID){ + Map successMessage = Collections.singletonMap("message","成功刪除"); + + Product p = productService.getID(ID); + p.setVisible(false); + productService.store(p); + + return ResponseEntity.ok(successMessage); + } + + @PutMapping("/fixedproduct/{ID}") + ResponseEntity> putFixedProduct(@PathVariable long ID , @Valid @RequestBody UpdateFixedPriceProductRequest request){ + + Map successMessage = Collections.singletonMap("message","成功更新不二價商品"); + + Product product = productService.getID(ID); + product.setProductName(request.getProductName()); + product.setProductDescription(request.getProductDescription()); + product.setProductImage(request.getProductImage()); + product.setProductType(request.getProductType()); + product.setCurrentPrice(request.getCurrentPrice()); + product.setProductAmount(request.getProductAmount()); + + productService.store(product); + return ResponseEntity.ok(successMessage); + } + + @PutMapping("/nonfixedproduct/{ID}") + ResponseEntity> putNonFixedProduct(@PathVariable long ID , @Valid @RequestBody UpdateNonFixedPriceProductRequest request){ + + Map successMessage = Collections.singletonMap("message","成功更新競標商品"); + Map failToPostponeAuction = Collections.singletonMap("message","延長競標截止時間失敗,因為有人得標嚕"); + Map fail = Collections.singletonMap("message","截止時間錯誤"); + Map failToSetUpsetPrice = Collections.singletonMap("message","底價不得更改,因為競標還在進行中"); + Map failToSetBidIncrement = Collections.singletonMap("message","每次增加金額不得更改,因為競標還在進行中"); + + Product product = productService.getID(ID); + + product.setProductName(request.getProductName()); + product.setProductDescription(request.getProductDescription()); + product.setProductImage(request.getProductImage()); + product.setProductType(request.getProductType()); + + + Map productMap= product.getBidInfo(); + if(!productMap.isEmpty() && !Objects.equals(request.getUpsetPrice(), product.getUpsetPrice())){ //map不為空,有人出價過了。且更改的底價 != 原本底價 + return ResponseEntity.badRequest().body(failToSetUpsetPrice); + } + product.setUpsetPrice(request.getUpsetPrice()); + + if(!productMap.isEmpty() && !Objects.equals(request.getBidIncrement(), product.getBidIncrement())){ //map不為空,有人出價過了。且被更改每口叫價 + return ResponseEntity.badRequest().body(failToSetBidIncrement); + } + product.setBidIncrement(request.getBidIncrement()); + + LocalDateTime now = LocalDateTime.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + LocalDateTime dateTime = LocalDateTime.parse(request.getFinishTime(), formatter); + if(!now.isBefore(dateTime)){ + return ResponseEntity.badRequest().body(fail); + } + if(product.getIsAuction()) { //代表競標結束且有被加入購物車 + return ResponseEntity.badRequest().body(failToPostponeAuction); + } + + product.setFinishTime(dateTime); + + productService.store(product); + return ResponseEntity.ok(successMessage); + } } diff --git a/src/main/java/ntou/auction/spring/data/entity/UpdateFixedPriceProductRequest.java b/src/main/java/ntou/auction/spring/data/entity/UpdateFixedPriceProductRequest.java new file mode 100644 index 0000000..1a9637f --- /dev/null +++ b/src/main/java/ntou/auction/spring/data/entity/UpdateFixedPriceProductRequest.java @@ -0,0 +1,41 @@ +package ntou.auction.spring.data.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Lob; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UpdateFixedPriceProductRequest { + + @NotNull + @Length(min = 1, max = 128 , message = "商品名稱至多32個中文字") + private String productName; + + @NotNull + @Min (value = 1,message = "價格須為正整數") + private Long currentPrice; + + + @Length(min = 1, max = 32) + private String productType; + + @Length(min = 1, max = 20971520,message = "商品敘述過長") + private String productDescription; + + @Lob + @Column(length = 5242880) + @Length(min = 1, max = 5242880 ,message = "圖片檔案過大,請重新上傳") + private String productImage; + + @NotNull + @Min (value = 1,message = "商品至少一個") + private Long productAmount; + +} diff --git a/src/main/java/ntou/auction/spring/data/entity/UpdateNonFixedPriceProductRequest.java b/src/main/java/ntou/auction/spring/data/entity/UpdateNonFixedPriceProductRequest.java new file mode 100644 index 0000000..b7b3ade --- /dev/null +++ b/src/main/java/ntou/auction/spring/data/entity/UpdateNonFixedPriceProductRequest.java @@ -0,0 +1,48 @@ +package ntou.auction.spring.data.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Lob; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UpdateNonFixedPriceProductRequest { + + @NotNull (message="商品名稱不得為空") + @Length(min = 1, max = 128 , message = "商品名稱至多32個中文字") + private String productName; + + @NotNull + @Min (value = 1,message = "價格須為正整數") + private Long upsetPrice; //lowest requested price + + @NotNull + @Min (value = 1,message = "每口叫價須為正整數") + private Long bidIncrement; + + @NotNull (message="商品數量不得為空") + private Long productAmount; + + @NotNull + private String finishTime; + + @Length(min = 1, max = 32) + private String productType; + + @Length(min = 1, max = 20971520,message = "商品敘述過長") + private String productDescription; + + @Lob + @Column(length = 5242880) + @Length(min = 1, max = 5242880 ,message = "圖片檔案過大,請重新上傳") + private String productImage; + + + +} From e2b01fe7cb477180df1578633eca4e9f556c874c Mon Sep 17 00:00:00 2001 From: weichunnien Date: Fri, 15 Dec 2023 20:41:13 +0800 Subject: [PATCH 11/19] =?UTF-8?q?fix:=20=E5=95=86=E5=93=81=E7=AB=B6?= =?UTF-8?q?=E6=A8=99=E7=B5=90=E6=9D=9F=E5=BE=8C=20=E5=A6=82=E6=9E=9C?= =?UTF-8?q?=E6=B2=92=E4=BA=BA=E8=B2=B7isAuction=E9=82=84=E6=98=AF=E7=82=BA?= =?UTF-8?q?false?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ntou/auction/spring/data/service/TimerTask.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/java/ntou/auction/spring/data/service/TimerTask.java b/src/main/java/ntou/auction/spring/data/service/TimerTask.java index 2a7fac3..fd307c2 100644 --- a/src/main/java/ntou/auction/spring/data/service/TimerTask.java +++ b/src/main/java/ntou/auction/spring/data/service/TimerTask.java @@ -25,7 +25,7 @@ public void execute() { for (Product product : productList) { System.out.println(product.getId()); - if (product.isExpired()) { + if (product.isExpired()) { //競標結束 Map productMap= product.getBidInfo(); @@ -36,11 +36,6 @@ public void execute() { product.setIsAuction(true); productService.store(product); } - else { - product.setIsAuction(true); - productService.store(product); - } - } } } From aaf703f1bac504cd21a27f55cc5f71311599f38b Mon Sep 17 00:00:00 2001 From: weichunnien Date: Sat, 16 Dec 2023 00:32:51 +0800 Subject: [PATCH 12/19] =?UTF-8?q?fix:=20=E6=8A=8Aapi=20=E6=90=9C=E5=B0=8B?= =?UTF-8?q?=E6=94=B9=E6=88=90pathvariable(name/classification)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spring/controller/ProductController.java | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/main/java/ntou/auction/spring/controller/ProductController.java b/src/main/java/ntou/auction/spring/controller/ProductController.java index 67f4424..77ca66b 100644 --- a/src/main/java/ntou/auction/spring/controller/ProductController.java +++ b/src/main/java/ntou/auction/spring/controller/ProductController.java @@ -36,25 +36,17 @@ public ProductController(ProductService productService, UserIdentity userIdentit } - @GetMapping("/product") + @GetMapping("/product/{name}") @ResponseBody - public ListgetProductName(@Valid @RequestBody ProductRequestGet request) { - - long type =Integer.parseInt(request.getSearchType()); - - if(type == 1) { //find by name - String pn = request.getProductName(); - return productService.findByProductName(pn); - } - - else if(type == 2){ //find by classification - String pt = request.getProductType(); - return productService.findByProductClassification(pt); - } - - return productService.list(); + public ListgetProductName(@PathVariable String name ) { + return productService.findByProductName(name); } + @GetMapping("/product/{classification}") + @ResponseBody + public ListgetProductClassification(@PathVariable String classification) { + return productService.findByProductClassification(classification); + } @GetMapping("/products") @ResponseBody From eae138e974b7489ef3acdd58fd2f0e8e1f6fe9dc Mon Sep 17 00:00:00 2001 From: weichunnien Date: Sat, 16 Dec 2023 00:39:49 +0800 Subject: [PATCH 13/19] =?UTF-8?q?fix:=20=E6=8A=8Aapi=20=E6=90=9C=E5=B0=8B?= =?UTF-8?q?=E8=AA=BF=E5=A5=BD=3D=3D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ntou/auction/spring/controller/ProductController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ntou/auction/spring/controller/ProductController.java b/src/main/java/ntou/auction/spring/controller/ProductController.java index 77ca66b..d91d21d 100644 --- a/src/main/java/ntou/auction/spring/controller/ProductController.java +++ b/src/main/java/ntou/auction/spring/controller/ProductController.java @@ -36,13 +36,13 @@ public ProductController(ProductService productService, UserIdentity userIdentit } - @GetMapping("/product/{name}") + @GetMapping("/product/name/{name}") @ResponseBody public ListgetProductName(@PathVariable String name ) { return productService.findByProductName(name); } - @GetMapping("/product/{classification}") + @GetMapping("/product/classification/{classification}") @ResponseBody public ListgetProductClassification(@PathVariable String classification) { return productService.findByProductClassification(classification); From ecb70ad31121651ab5f46ece77e9bc65c831517d Mon Sep 17 00:00:00 2001 From: weichunnien Date: Sat, 16 Dec 2023 21:35:46 +0800 Subject: [PATCH 14/19] =?UTF-8?q?fix:=20=E8=AA=8D=E8=AD=89user=E5=90=8D?= =?UTF-8?q?=E5=AD=97=E3=80=81=E5=88=AA=E9=99=A4=E6=99=82=E6=8A=8A=E5=95=86?= =?UTF-8?q?=E5=93=81=E6=95=B8=E9=87=8F=E8=A8=AD=E6=88=900?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spring/controller/ProductController.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/main/java/ntou/auction/spring/controller/ProductController.java b/src/main/java/ntou/auction/spring/controller/ProductController.java index d91d21d..0d356cc 100644 --- a/src/main/java/ntou/auction/spring/controller/ProductController.java +++ b/src/main/java/ntou/auction/spring/controller/ProductController.java @@ -206,8 +206,14 @@ List getProductInSellerCenter() { @DeleteMapping("/{ID}") ResponseEntity> deleteProduct(@PathVariable long ID){ Map successMessage = Collections.singletonMap("message","成功刪除"); + Map failMessage = Collections.singletonMap("message","刪錯商品嚕"); Product p = productService.getID(ID); + + if(!Objects.equals(userService.findByUsername(userIdentity.getUsername()).getId(), p.getSellerID())){ + return ResponseEntity.badRequest().body(failMessage); + } + p.setProductAmount(0L); p.setVisible(false); productService.store(p); @@ -218,8 +224,12 @@ ResponseEntity> deleteProduct(@PathVariable long ID){ ResponseEntity> putFixedProduct(@PathVariable long ID , @Valid @RequestBody UpdateFixedPriceProductRequest request){ Map successMessage = Collections.singletonMap("message","成功更新不二價商品"); + Map failMessage = Collections.singletonMap("message","更新錯商品嚕"); Product product = productService.getID(ID); + if(!Objects.equals(userService.findByUsername(userIdentity.getUsername()).getId(), product.getSellerID())){ + return ResponseEntity.badRequest().body(failMessage); + } product.setProductName(request.getProductName()); product.setProductDescription(request.getProductDescription()); product.setProductImage(request.getProductImage()); @@ -237,11 +247,14 @@ ResponseEntity> putNonFixedProduct(@PathVariable long ID , @V Map successMessage = Collections.singletonMap("message","成功更新競標商品"); Map failToPostponeAuction = Collections.singletonMap("message","延長競標截止時間失敗,因為有人得標嚕"); Map fail = Collections.singletonMap("message","截止時間錯誤"); - Map failToSetUpsetPrice = Collections.singletonMap("message","底價不得更改,因為競標還在進行中"); - Map failToSetBidIncrement = Collections.singletonMap("message","每次增加金額不得更改,因為競標還在進行中"); - + Map failToSetUpsetPrice = Collections.singletonMap("message","底價不得更改,因為有人出價了"); + Map failToSetBidIncrement = Collections.singletonMap("message","每次增加金額不得更改,因為有人出價了"); + Map failMessage = Collections.singletonMap("message","更新錯商品嚕阿"); Product product = productService.getID(ID); + if(!Objects.equals(userService.findByUsername(userIdentity.getUsername()).getId(), product.getSellerID())){ + return ResponseEntity.badRequest().body(failMessage); + } product.setProductName(request.getProductName()); product.setProductDescription(request.getProductDescription()); product.setProductImage(request.getProductImage()); From 6305e094f6578d37990c2b4a17ad36681b4fc92d Mon Sep 17 00:00:00 2001 From: weichunnien Date: Sun, 17 Dec 2023 22:47:10 +0800 Subject: [PATCH 15/19] =?UTF-8?q?fix:=20=E4=BF=AE=E6=AD=A3=E9=8C=AF?= =?UTF-8?q?=E8=AA=A4=E8=A8=8A=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ntou/auction/spring/controller/ProductController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ntou/auction/spring/controller/ProductController.java b/src/main/java/ntou/auction/spring/controller/ProductController.java index 0d356cc..71390b3 100644 --- a/src/main/java/ntou/auction/spring/controller/ProductController.java +++ b/src/main/java/ntou/auction/spring/controller/ProductController.java @@ -154,8 +154,8 @@ ResponseEntity> bidProduct(@Valid @RequestBody BidRequest req ResponseEntity> buyProduct(@Valid @RequestBody BuyProductRequest request){ Map successMessage = Collections.singletonMap("message","成功加入購物車"); - Map notEnoughMessage = Collections.singletonMap("message","買太多嚕"); - Map errorMessage = Collections.singletonMap("message","你只能將不二價商品加入購物車"); + Map notEnoughMessage = Collections.singletonMap("message","商品剩餘數量不足"); + Map errorMessage = Collections.singletonMap("message","只能將不二價商品加入購物車"); Map productNotExistMessage = Collections.singletonMap("message", "商品不存在或無法購買"); // 商品是否存在 From 365525f6e4c9f5e706914ec75ad550eef4c2c84e Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 18 Dec 2023 22:52:10 +0800 Subject: [PATCH 16/19] fix: resolve issue with self product purchase. --- .../spring/controller/OrderController.java | 33 +++++++++++++------ .../spring/data/service/OrderService.java | 7 ++-- .../data/service/ShoppingcartService.java | 13 +++++--- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/main/java/ntou/auction/spring/controller/OrderController.java b/src/main/java/ntou/auction/spring/controller/OrderController.java index aa2fce9..e7d02af 100644 --- a/src/main/java/ntou/auction/spring/controller/OrderController.java +++ b/src/main/java/ntou/auction/spring/controller/OrderController.java @@ -39,6 +39,8 @@ public class OrderController { private static final Map notFoundInShoppingCartError = Collections.singletonMap("message", "商品不在購物車中或購買數量過多"); + private static final Map selfBuyingError = Collections.singletonMap("message", "不可以購買自己的商品"); + public OrderController(OrderService orderService, ProductService productService, ShoppingcartService shoppingcartService, UserService userService, UserIdentity userIdentity) { this.orderService = orderService; this.productService = productService; @@ -83,10 +85,18 @@ List getWaitingBySeller() { ResponseEntity> addOrder(@Valid @RequestBody AddOrderRequest request) { Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); List> getrequest = request.getProductList(); - // check -> -1: format error, 0: false, 1: true - Long check = shoppingcartService.checkIsProductAllInShoppingCart(getrequest, userId); - if(check.equals(-1L)) return ResponseEntity.badRequest().body(formatError); - if(check.equals(0L)) return ResponseEntity.badRequest().body(notFoundInShoppingCartError); + // checkAmount -> -1: format error, 0: false, 1: true + Long checkAmount = shoppingcartService.checkIsProductAllInShoppingCart(getrequest, userId); + if(checkAmount.equals(-1L)) return ResponseEntity.badRequest().body(formatError); + if(checkAmount.equals(0L)) return ResponseEntity.badRequest().body(notFoundInShoppingCartError); + + // Same seller + boolean checkSameSeller = orderService.checkIsSameSeller(getrequest); + if(!checkSameSeller) return ResponseEntity.badRequest().body(tooManySellerMessage); + + // Self buying + boolean checkSelfBuying = shoppingcartService.checkIsViolateSelfBuying(getrequest, userId); + if(checkSelfBuying) return ResponseEntity.badRequest().body(selfBuyingError); // order status -> 0: reject, 1: waiting for submit, 2: submitted but not paid, 3: order done Order order = new Order(); @@ -113,15 +123,18 @@ ResponseEntity> addOrder(@Valid @RequestBody AddOrderRequest input.add(productId); input.add(amount); order.addProductAddAmount(input); - // decrease product's amount by amount - productService.productAmountDecrease(productId, amount); } - // delete Product amount in Shopping cart for (List eachProductAddAmount : getrequest) { - shoppingcartService.decreaseProductByUserId(userId, eachProductAddAmount.get(0), eachProductAddAmount.get(1)); + Long productId = eachProductAddAmount.get(0); + Long amount = eachProductAddAmount.get(1); + + // decrease product's amount by amount + productService.productAmountDecrease(productId, amount); + + // delete Product amount in Shopping cart + shoppingcartService.decreaseProductByUserId(userId, productId, amount); } - boolean result = orderService.addOrder(order); - if (!result) return ResponseEntity.badRequest().body(tooManySellerMessage); + orderService.addOrder(order); return ResponseEntity.ok(successMessage); } diff --git a/src/main/java/ntou/auction/spring/data/service/OrderService.java b/src/main/java/ntou/auction/spring/data/service/OrderService.java index d8101c5..344a360 100644 --- a/src/main/java/ntou/auction/spring/data/service/OrderService.java +++ b/src/main/java/ntou/auction/spring/data/service/OrderService.java @@ -101,14 +101,11 @@ public Long doneOrder(Long orderId, Long userId) { return 3L; } - public boolean addOrder(Order order) { - boolean check = checkIsSameSeller(order.getProductAddAmountList()); - if(!check) return false; + public void addOrder(Order order) { repository.save(order); - return true; } - private boolean checkIsSameSeller(List> list) { + public boolean checkIsSameSeller(List> list) { Set check = new HashSet<>(); for(List productAddAmount: list) { check.add(productService.getID(productAddAmount.get(0)).getSellerID()); diff --git a/src/main/java/ntou/auction/spring/data/service/ShoppingcartService.java b/src/main/java/ntou/auction/spring/data/service/ShoppingcartService.java index 665792e..1653e57 100644 --- a/src/main/java/ntou/auction/spring/data/service/ShoppingcartService.java +++ b/src/main/java/ntou/auction/spring/data/service/ShoppingcartService.java @@ -4,10 +4,7 @@ import ntou.auction.spring.data.entity.Shoppingcart; import org.springframework.stereotype.Service; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; @Service public class ShoppingcartService { @@ -95,4 +92,12 @@ public Long checkIsProductAllInShoppingCart(List> order, Long userid) } return 1L; } + + public boolean checkIsViolateSelfBuying(List> order, Long userid) { + for(List product: order) { + Product nowProduct = productService.getID(product.get(0)); + if(nowProduct.getSellerID().equals(userid)) return true; + } + return false; + } } From 9ae7f2441446fb6b524218e4e352a81ac3d2c9ba Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 18 Dec 2023 23:39:05 +0800 Subject: [PATCH 17/19] feat: implement View Done Order functionality in the order management system. --- .../spring/controller/OrderController.java | 48 +++++++++++++------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/src/main/java/ntou/auction/spring/controller/OrderController.java b/src/main/java/ntou/auction/spring/controller/OrderController.java index e7d02af..673562e 100644 --- a/src/main/java/ntou/auction/spring/controller/OrderController.java +++ b/src/main/java/ntou/auction/spring/controller/OrderController.java @@ -68,12 +68,18 @@ List getWaitingByBuyer() { return orderService.orderToOrderWithProductDetail(orderService.findWaitingByBuyerId(userId)); } - @GetMapping("/order/accept") + @GetMapping("/order/submitted") List getSubmitByBuyer() { Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); return orderService.orderToOrderWithProductDetail(orderService.findSubmittedByBuyerId(userId)); } + @GetMapping("/order/done") + List getDoneByBuyer() { + Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); + return orderService.orderToOrderWithProductDetail(orderService.findDoneByBuyerId(userId)); + } + @GetMapping("/check") List getWaitingBySeller() { // filter Waited order with seller @@ -85,10 +91,32 @@ List getWaitingBySeller() { ResponseEntity> addOrder(@Valid @RequestBody AddOrderRequest request) { Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); List> getrequest = request.getProductList(); - // checkAmount -> -1: format error, 0: false, 1: true - Long checkAmount = shoppingcartService.checkIsProductAllInShoppingCart(getrequest, userId); - if(checkAmount.equals(-1L)) return ResponseEntity.badRequest().body(formatError); - if(checkAmount.equals(0L)) return ResponseEntity.badRequest().body(notFoundInShoppingCartError); + + for (List eachProductAddAmount : getrequest) { + Long productId = eachProductAddAmount.get(0); + Product getProduct = productService.getID(productId); + // Id error + if (getProduct == null) { + Map ErrorIdMessage = Collections.singletonMap("message", "商品(ID:" + productId + ")不存在"); + return ResponseEntity.badRequest().body(ErrorIdMessage); + } + } + + // checkInShoppingCart -> -1: format error, 0: false, 1: true + Long checkInShoppingCart = shoppingcartService.checkIsProductAllInShoppingCart(getrequest, userId); + if(checkInShoppingCart.equals(-1L)) return ResponseEntity.badRequest().body(formatError); + if(checkInShoppingCart.equals(0L)) return ResponseEntity.badRequest().body(notFoundInShoppingCartError); + + for (List eachProductAddAmount : getrequest) { + Long productId = eachProductAddAmount.get(0); + Long amount = eachProductAddAmount.get(1); + Product getProduct = productService.getID(productId); + // amount exceed + if (amount > getProduct.getProductAmount()) { + Map amountExceedReturn = Collections.singletonMap("message", "商品數量(" + getProduct.getProductName() + ")過多"); + return ResponseEntity.badRequest().body(amountExceedReturn); + } + } // Same seller boolean checkSameSeller = orderService.checkIsSameSeller(getrequest); @@ -108,16 +136,6 @@ ResponseEntity> addOrder(@Valid @RequestBody AddOrderRequest Long productId = eachProductAddAmount.get(0); Long amount = eachProductAddAmount.get(1); Product getProduct = productService.getID(productId); - // Id error - if (getProduct == null) { - Map ErrorIdMessage = Collections.singletonMap("message", "商品(ID:" + productId + ")不存在"); - return ResponseEntity.badRequest().body(ErrorIdMessage); - } - // amount exceed - if (amount > getProduct.getProductAmount()) { - Map amountExceedReturn = Collections.singletonMap("message", "商品數量(" + getProduct.getProductName() + ")過多"); - return ResponseEntity.badRequest().body(amountExceedReturn); - } order.setSellerid(getProduct.getSellerID()); List input = new ArrayList<>(); input.add(productId); From fb78ac4b5f2b628a73e4e867c4c31286da78964f Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 20 Dec 2023 01:48:03 +0800 Subject: [PATCH 18/19] feat: implement Controller API for product status checking. --- .../spring/controller/OrderController.java | 27 ++++++++++++++++++- .../spring/data/service/OrderRepository.java | 11 ++++++++ .../spring/data/service/OrderService.java | 16 ++++++----- 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/main/java/ntou/auction/spring/controller/OrderController.java b/src/main/java/ntou/auction/spring/controller/OrderController.java index 673562e..fce9882 100644 --- a/src/main/java/ntou/auction/spring/controller/OrderController.java +++ b/src/main/java/ntou/auction/spring/controller/OrderController.java @@ -80,13 +80,38 @@ List getDoneByBuyer() { return orderService.orderToOrderWithProductDetail(orderService.findDoneByBuyerId(userId)); } - @GetMapping("/check") + @GetMapping("/check/all") + List getAllBySeller() { + Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); + return orderService.orderToOrderWithProductDetail(orderService.findAllBySellerId(userId)); + } + + @GetMapping("/check/reject") + List getRejectBySeller() { + Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); + return orderService.orderToOrderWithProductDetail(orderService.findRejectBySellerId(userId)); + } + + @GetMapping("/check/waiting") List getWaitingBySeller() { // filter Waited order with seller Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); return orderService.orderToOrderWithProductDetail(orderService.findWaitingBySellerId(userId)); } + @GetMapping("/check/submitted") + List getSubmittedBySeller() { + Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); + return orderService.orderToOrderWithProductDetail(orderService.findSubmittedBySellerId(userId)); + } + + @GetMapping("/check/done") + List getDoneBySeller() { + Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); + return orderService.orderToOrderWithProductDetail(orderService.findDoneBySellerId(userId)); + } + + @PostMapping("/create") ResponseEntity> addOrder(@Valid @RequestBody AddOrderRequest request) { Long userId = userService.findByUsername(userIdentity.getUsername()).getId(); diff --git a/src/main/java/ntou/auction/spring/data/service/OrderRepository.java b/src/main/java/ntou/auction/spring/data/service/OrderRepository.java index 83a8496..09af174 100644 --- a/src/main/java/ntou/auction/spring/data/service/OrderRepository.java +++ b/src/main/java/ntou/auction/spring/data/service/OrderRepository.java @@ -28,8 +28,19 @@ public interface OrderRepository extends JpaRepository, JpaSpecific @Query(value = "select * from orders o where o.buyerid = ?1 and o.status = 3", nativeQuery = true) List findDoneByBuyerid(Long buyer); + @Query(value = "select * from orders o where o.sellerid = ?1", nativeQuery = true) + List findAllBySellerid(Long seller); + + @Query(value = "select * from orders o where o.sellerid = ?1 and o.status = 0", nativeQuery = true) + List findRejectBySellerid(Long seller); @Query(value = "select * from orders o where o.sellerid = ?1 and o.status = 1", nativeQuery = true) List findWaitingBySellerid(Long seller); + + @Query(value = "select * from orders o where o.sellerid = ?1 and o.status = 2", nativeQuery = true) + List findSubmittedBySellerid(Long seller); + + @Query(value = "select * from orders o where o.sellerid = ?1 and o.status = 3", nativeQuery = true) + List findDoneBySellerid(Long seller); @Modifying @Query(value = "insert into shoppingcart(userId, productId) values (?1, ?2)", nativeQuery = true) public void addShoppingCart(Long userId, List productId); diff --git a/src/main/java/ntou/auction/spring/data/service/OrderService.java b/src/main/java/ntou/auction/spring/data/service/OrderService.java index 344a360..0b606e6 100644 --- a/src/main/java/ntou/auction/spring/data/service/OrderService.java +++ b/src/main/java/ntou/auction/spring/data/service/OrderService.java @@ -40,17 +40,21 @@ public List findWaitingByBuyerId(Long buyerId) { return repository.findWaitingByBuyerid(buyerId); } - public List findSubmittedByBuyerId(Long buyerId) { - return repository.findSubmittedByBuyerid(buyerId); - } + public List findSubmittedByBuyerId(Long buyerId) {return repository.findSubmittedByBuyerid(buyerId);} public List findDoneByBuyerId(Long buyerId) { return repository.findDoneByBuyerid(buyerId); } - public List findWaitingBySellerId(Long sellerId) { - return repository.findWaitingBySellerid(sellerId); - } + public List findAllBySellerId(Long sellerId) { return repository.findAllBySellerid(sellerId);} + + public List findRejectBySellerId(Long sellerId) { return repository.findRejectBySellerid(sellerId); } + + public List findWaitingBySellerId(Long sellerId) { return repository.findWaitingBySellerid(sellerId);} + + public List findSubmittedBySellerId(Long sellerId) { return repository.findSubmittedBySellerid(sellerId);} + + public List findDoneBySellerId(Long sellerId) { return repository.findDoneBySellerid(sellerId);} public Long submitOrder(Long orderId, Long userId) { // for status -> 0: reject, 1: waiting for submit, 2: submitted but not paid, 3: order done From d2be27b46149034f9d255f877b7d7f315f0c4fbc Mon Sep 17 00:00:00 2001 From: weichunnien Date: Wed, 20 Dec 2023 20:04:28 +0800 Subject: [PATCH 19/19] =?UTF-8?q?fix:=20=E4=BF=AE=E6=AD=A3=E9=8C=AF?= =?UTF-8?q?=E8=AA=A4=E8=A8=8A=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/ntou/auction/spring/data/entity/Product.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/ntou/auction/spring/data/entity/Product.java b/src/main/java/ntou/auction/spring/data/entity/Product.java index b46f191..7c66363 100644 --- a/src/main/java/ntou/auction/spring/data/entity/Product.java +++ b/src/main/java/ntou/auction/spring/data/entity/Product.java @@ -1,6 +1,7 @@ package ntou.auction.spring.data.entity; import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.*; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; @@ -44,6 +45,7 @@ public class Product extends AbstractEntity { //followings are non-isFixedPrice feature + @JsonIgnore @ElementCollection @CollectionTable(name = "bidInfo") private Map bidInfo;