Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/main/java/com/campustable/be/domain/menu/entity/Menu.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.campustable.be.domain.category.entity.Category;
import com.campustable.be.domain.menu.dto.MenuUpdateRequest;
import com.campustable.be.global.exception.CustomException;
import com.campustable.be.global.exception.ErrorCode;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
Expand Down Expand Up @@ -84,4 +86,14 @@ public void update(MenuUpdateRequest request) {
}
}

public void decreaseStockQuantity(int quantity) {
if(this.stockQuantity - quantity < 0) {
throw new CustomException(ErrorCode.MENU_OUT_OF_STOCK);
}
else if(this.stockQuantity - quantity == 0) {
this.available = false;
}
this.stockQuantity -= quantity;
}
Comment on lines +89 to +97
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

동시성 제어 누락으로 인한 재고 오버셀링 위험

decreaseStockQuantity 메서드는 동기화 메커니즘 없이 재고를 감소시킵니다. 여러 주문이 동시에 발생하면 check-then-act 경합 상태가 발생하여 재고가 음수가 될 수 있습니다.

예시:

  • 초기 재고: 1개
  • 주문 A와 B가 동시에 발생
  • 둘 다 stockQuantity - quantity >= 0 체크 통과
  • 둘 다 감소 실행 → 최종 재고: -1개
🔎 동시성 제어 방법 제안

방법 1 (권장): 비관적 락 사용

OrderService에서 Menu 조회 시 락 적용:

@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT m FROM Menu m WHERE m.id = :id")
Optional<Menu> findByIdWithLock(@Param("id") Long id);

방법 2: 낙관적 락 사용

Menu 엔티티에 버전 필드 추가:

 public class Menu {
+  @Version
+  private Long version;

방법 3: 데이터베이스 제약 조건

ALTER TABLE menu ADD CONSTRAINT check_stock_non_negative 
CHECK (stock_quantity >= 0);

Committable suggestion skipped: line range outside the PR's diff.


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.campustable.be.domain.order.controller;


import com.campustable.be.domain.order.dto.OrderResponse;
import com.campustable.be.domain.order.service.OrderService;
import com.campustable.be.global.aop.LogMonitoringInvocation;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/orders")
public class OrderController implements OrderControllerDocs {

private final OrderService orderService;

@Override
@LogMonitoringInvocation
@PostMapping
public ResponseEntity<OrderResponse> createOrder() {
return ResponseEntity.ok(orderService.createOrder());
}

@Override
@LogMonitoringInvocation
@PatchMapping("/{orderId}/categories/{categoryId}/ready")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public ResponseEntity<Void> updateCategoryToReady(
@PathVariable Long orderId,
@PathVariable Long categoryId) {
orderService.updateCategoryToReady(orderId,categoryId);
return ResponseEntity.ok().build();
}

@Override
@LogMonitoringInvocation
@PatchMapping("/{orderId}/categories/{categoryId}/complete")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public ResponseEntity<Void> updateCategoryToComplete(
@PathVariable Long orderId,
@PathVariable Long categoryId
) {
orderService.updateCategoryToComplete(orderId,categoryId);
return ResponseEntity.ok().build();
}

@Override
@LogMonitoringInvocation
@GetMapping
public ResponseEntity<List<OrderResponse>> getMyOrders() {
return ResponseEntity.ok(orderService.getMyOrders());
}
Comment on lines +57 to +60
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

페이지네이션 누락으로 인한 성능 저하 가능성

getMyOrders 엔드포인트가 사용자의 모든 주문을 한 번에 반환합니다. 주문이 많은 사용자의 경우 메모리 사용량 증가와 응답 지연이 발생할 수 있습니다.

Pageable 파라미터를 추가하여 페이지네이션을 구현하는 것을 권장합니다.

🔎 페이지네이션 구현 제안
 @Override
 @LogMonitoringInvocation
 @GetMapping
-public ResponseEntity<List<OrderResponse>> getMyOrders() {
-  return ResponseEntity.ok(orderService.getMyOrders());
+public ResponseEntity<Page<OrderResponse>> getMyOrders(Pageable pageable) {
+  return ResponseEntity.ok(orderService.getMyOrders(pageable));
 }

OrderService와 Repository도 함께 수정 필요:

// Repository
Page<Order> findByUserUserIdOrderByCreatedAtDesc(Long userId, Pageable pageable);

// Service
Page<OrderResponse> getMyOrders(Pageable pageable) {
  // ... implementation
}

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/order/controller/OrderController.java
around lines 57-60, the getMyOrders endpoint currently returns all orders at
once which can cause memory and latency issues; update the controller to accept
a Pageable parameter (e.g., Pageable pageable) and return a paged result, then
update OrderService to expose getMyOrders(Pageable) returning a
Page<OrderResponse> and change the repository to a paged query (e.g.,
Page<Order> findByUserUserIdOrderByCreatedAtDesc(Long userId, Pageable
pageable)); ensure the controller maps the Page from the service into the
ResponseEntity and keep sorting/default page size via @PageableDefault if
needed.


@Override
@GetMapping("/users/{userId}")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public ResponseEntity<List<OrderResponse>> getOrdersByUserId(@PathVariable Long userId) {
return ResponseEntity.ok(orderService.getOrdersByUserId(userId));
}
Comment on lines +63 to +67
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

관리자 조회 엔드포인트에도 페이지네이션 필요

getOrdersByUserId도 모든 주문을 한 번에 반환하므로 getMyOrders와 동일한 성능 문제가 있습니다. 관리자가 주문이 많은 사용자를 조회할 때 특히 문제가 될 수 있습니다.

페이지네이션 적용을 권장합니다.


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.campustable.be.domain.order.controller;

import com.campustable.be.domain.order.dto.OrderResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;

@Tag(name = "Order API", description = "주문 관련 API (생성, 조회, 상태 변경)")
public interface OrderControllerDocs {

@Operation(summary = "주문 생성", description = "현재 사용자의 장바구니에 담긴 메뉴들로 주문을 생성합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "주문 생성 성공"),
@ApiResponse(responseCode = "400", description = "재고 부족"),
@ApiResponse(responseCode = "404", description = "장바구니가 비어있거나 사용자를 찾을 수 없음")
})
ResponseEntity<OrderResponse> createOrder();

@Operation(summary = "카테고리별 조리 완료 처리 (관리자)", description = "특정 주문(OrderId) 내의 특정 카테고리(CategoryId) 메뉴들을 모두 '조리 완료'로 변경합니다.")
ResponseEntity<Void> updateCategoryToReady(
@Parameter(description = "주문 ID", example = "1") @PathVariable Long orderId,
@Parameter(description = "카테고리 ID", example = "2") @PathVariable Long categoryId
);

@Operation(summary = "카테고리별 수령 완료 처리 (관리자)", description = "특정 주문(OrderId) 내의 특정 카테고리(CategoryId) 메뉴들을 모두 '수령 완료'로 변경합니다.")
ResponseEntity<Void> updateCategoryToComplete(
@Parameter(description = "주문 ID", example = "1") @PathVariable Long orderId,
@Parameter(description = "카테고리 ID", example = "2") @PathVariable Long categoryId
);

@Operation(summary = "내 주문 내역 조회", description = "사용자의 주문 내역을 조회합니다. (진행 중인 주문이 상단에 노출됨)")
@ApiResponse(responseCode = "200", description = "조회 성공")
ResponseEntity<List<OrderResponse>> getMyOrders();

@Operation(summary = "특정 유저 주문 조회 (관리자)", description = "관리자가 특정 유저(User ID)의 모든 주문 내역을 조회합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "403", description = "관리자 권한 없음"),
@ApiResponse(responseCode = "404", description = "해당 유저를 찾을 수 없음")
})
ResponseEntity<List<OrderResponse>> getOrdersByUserId(
@Parameter(description = "조회할 유저 ID", example = "5")
@PathVariable Long userId
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.campustable.be.domain.order.dto;

import com.campustable.be.domain.order.entity.OrderItem;
import com.campustable.be.domain.order.entity.OrderStatus;
import lombok.AccessLevel;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

사용되지 않는 import를 제거하세요.

AccessLevel이 import되었지만 사용되지 않습니다.

🔎 수정 제안
-import lombok.AccessLevel;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import lombok.AccessLevel;
🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/order/dto/OrderItemDto.java around
line 5, the import 'lombok.AccessLevel' is unused; remove that import line and
reformat/import-organize the file (or run your IDE's optimize imports) so only
necessary imports remain.

import lombok.Getter;

@Getter
public class OrderItemDto {

private Long orderItemId;
private Long menuId;
private String menuName;
private int orderPrice;
private int quantity;
private int subTotal;
private String menuUrl;
private OrderStatus status;
private Long categoryId;

public OrderItemDto(OrderItem orderItem) {
this.orderItemId = orderItem.getOrderItemId();
this.menuId = orderItem.getMenu().getId();
this.menuName = orderItem.getMenu().getMenuName();
this.orderPrice = orderItem.getOrderPrice(); //주문 당시가격
this.quantity = orderItem.getQuantity();
this.subTotal = orderItem.getOrderPrice() * orderItem.getQuantity();
this.menuUrl = orderItem.getMenu().getMenuUrl();
this.status = orderItem.getStatus();
this.categoryId=orderItem.getCategoryId();
}
Comment on lines +21 to +31
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "Menu.java" | head -20

Repository: CampusTable/campus-table-be

Length of output: 134


🏁 Script executed:

find . -type f -name "OrderItem.java" | head -20

Repository: CampusTable/campus-table-be

Length of output: 140


🏁 Script executed:

git ls-files | grep -E "(Menu|OrderItem)\.java$"

Repository: CampusTable/campus-table-be

Length of output: 200


🏁 Script executed:

wc -l ./src/main/java/com/campustable/be/domain/menu/entity/Menu.java

Repository: CampusTable/campus-table-be

Length of output: 137


🏁 Script executed:

cat -n ./src/main/java/com/campustable/be/domain/menu/entity/Menu.java

Repository: CampusTable/campus-table-be

Length of output: 3303


🏁 Script executed:

wc -l ./src/main/java/com/campustable/be/domain/order/entity/OrderItem.java

Repository: CampusTable/campus-table-be

Length of output: 143


🏁 Script executed:

cat -n ./src/main/java/com/campustable/be/domain/order/entity/OrderItem.java

Repository: CampusTable/campus-table-be

Length of output: 2596


OrderItem의 getTotalPrice() 메서드를 재사용하세요.

subTotal 계산에서 이미 존재하는 OrderItem.getTotalPrice() 메서드를 재사용하면 코드 중복을 제거할 수 있습니다:

-    this.subTotal = orderItem.getOrderPrice() * orderItem.getQuantity();
+    this.subTotal = orderItem.getTotalPrice();
🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/order/dto/OrderItemDto.java around
lines 21 to 31, the constructor computes subTotal by multiplying orderPrice and
quantity instead of reusing OrderItem.getTotalPrice(); replace the manual
calculation with a call to orderItem.getTotalPrice() to remove duplication and
ensure consistent logic, i.e., set this.subTotal to orderItem.getTotalPrice()
(preserving existing field types/units).


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.campustable.be.domain.order.dto;

import com.campustable.be.domain.order.entity.Order;
import java.time.LocalDateTime;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
@AllArgsConstructor // Builder와 함께 사용 시 관례적으로 추가
public class OrderResponse {

private Long orderId;
private int totalPrice;
private LocalDateTime orderDate;
private List<OrderItemDto> orderItems;

public static OrderResponse from(Order order) {
return OrderResponse.builder()
.orderId(order.getOrderId())
.totalPrice(order.getTotalPrice())
.orderDate(order.getCreatedAt()) // BaseTimeEntity의 생성일
.orderItems(order.getOrderItems().stream()
.map(OrderItemDto::new)
.toList())
.build();
}
Comment on lines +20 to +29
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find src -type f -name "OrderRepository.java" | head -5

Repository: CampusTable/campus-table-be

Length of output: 148


🏁 Script executed:

find src -type f -name "OrderItemDto.java" | head -5

Repository: CampusTable/campus-table-be

Length of output: 138


🏁 Script executed:

find src -type f -name "Order.java" -o -name "OrderItem.java" | grep -E "(Order\.java|OrderItem\.java)$" | head -10

Repository: CampusTable/campus-table-be

Length of output: 202


🏁 Script executed:

git ls-files src/main/java/com/campustable/be/domain/order | head -20

Repository: CampusTable/campus-table-be

Length of output: 801


🏁 Script executed:

cat -n src/main/java/com/campustable/be/domain/order/repository/OrderRepository.java

Repository: CampusTable/campus-table-be

Length of output: 506


🏁 Script executed:

cat -n src/main/java/com/campustable/be/domain/order/dto/OrderItemDto.java

Repository: CampusTable/campus-table-be

Length of output: 1309


🏁 Script executed:

cat -n src/main/java/com/campustable/be/domain/order/entity/Order.java

Repository: CampusTable/campus-table-be

Length of output: 2299


🏁 Script executed:

cat -n src/main/java/com/campustable/be/domain/order/entity/OrderItem.java

Repository: CampusTable/campus-table-be

Length of output: 2596


🏁 Script executed:

rg -n "OrderResponse.from\(" src/main/java/com/campustable/be --type java -B 2 -A 2

Repository: CampusTable/campus-table-be

Length of output: 1049


🏁 Script executed:

rg -n "hibernate.show_sql|show-sql|format_sql" src/main/resources -t properties -t yaml

Repository: CampusTable/campus-table-be

Length of output: 105


🏁 Script executed:

cat -n src/main/java/com/campustable/be/domain/order/service/OrderService.java

Repository: CampusTable/campus-table-be

Length of output: 4631


🏁 Script executed:

find src/main/resources -type f \( -name "application*.properties" -o -name "application*.yml" \)

Repository: CampusTable/campus-table-be

Length of output: 105


🏁 Script executed:

cat -n src/main/resources/application.yml

Repository: CampusTable/campus-table-be

Length of output: 1195


주문 조회 시 N+1 쿼리 발생 가능

OrderService.getMyOrders()getOrdersByUserId() 메서드에서 findByUserUserIdOrderByCreatedAtDesc() 호출 시, Order와 관련 OrderItem이 함께 로드되지 않으면 N+1 쿼리 문제가 발생합니다. 각 OrderItem의 Menu도 OrderItemDto 생성자에서 지연로드되므로 추가 쿼리가 발생합니다.

OrderRepository의 findByUserUserIdOrderByCreatedAtDesc() 메서드에 @entitygraph 또는 JOIN FETCH를 적용하여 필요한 데이터를 함께 로드하세요:

@EntityGraph(attributePaths = {"orderItems", "orderItems.menu"})
List<Order> findByUserUserIdOrderByCreatedAtDesc(Long userId);

또는 JPQL 사용:

@Query("SELECT o FROM Order o " +
       "JOIN FETCH o.orderItems oi " +
       "JOIN FETCH oi.menu " +
       "WHERE o.user.userId = :userId " +
       "ORDER BY o.createdAt DESC")
List<Order> findByUserUserIdOrderByCreatedAtDesc(Long userId);
🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/order/dto/OrderResponse.java around
lines 20 to 29, the Order→OrderItem→Menu relationships are being lazily loaded
which can cause N+1 queries when mapping orders to DTOs; update the
OrderRepository.findByUserUserIdOrderByCreatedAtDesc(...) to eagerly fetch
orderItems and their menu either by adding @EntityGraph(attributePaths =
{"orderItems", "orderItems.menu"}) on the repository method or replacing it with
a JPQL @Query that JOIN FETCH o.orderItems and JOIN FETCH oi.menu for the given
userId and ordered by createdAt DESC so that the DTO mapping in
OrderResponse.from uses already-loaded associations and avoids extra queries.

}
62 changes: 62 additions & 0 deletions src/main/java/com/campustable/be/domain/order/entity/Order.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.campustable.be.domain.order.entity;

import com.campustable.be.domain.user.entity.User;
import com.campustable.be.global.common.BaseTimeEntity;
import com.campustable.be.global.exception.CustomException;
import com.campustable.be.global.exception.ErrorCode;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import java.util.ArrayList;
import java.util.List;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Entity
@Getter
@Setter
@NoArgsConstructor
@Table(name="orders")
public class Order extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="order_id")
private Long orderId;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;

@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<OrderItem> orderItems = new ArrayList<>();
Comment on lines +41 to +42
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's locate and examine the Order.java file
find . -name "Order.java" -path "*/domain/order/entity/*"

Repository: CampusTable/campus-table-be

Length of output: 136


🏁 Script executed:

# Read the Order.java file to verify the cascade configuration
cat -n src/main/java/com/campustable/be/domain/order/entity/Order.java | head -60

Repository: CampusTable/campus-table-be

Length of output: 2282


🏁 Script executed:

# Check for soft delete patterns in the codebase
rg -n "deleted|DeletedDate|@SQLDelete" --type java -i

Repository: CampusTable/campus-table-be

Length of output: 53


🏁 Script executed:

# Check for audit-related annotations and listeners
rg -n "@Audited|@EntityListeners|AuditingEntityListener|@CreatedDate|@LastModifiedDate" --type java

Repository: CampusTable/campus-table-be

Length of output: 601


🏁 Script executed:

# Check CascadeType patterns in other entities
rg -n "CascadeType\.(ALL|REMOVE|PERSIST|MERGE)" --type java -B 1 -A 1

Repository: CampusTable/campus-table-be

Length of output: 1347


주문 항목 삭제 전략 재검토 필요

CascadeType.ALL은 주문 삭제 시 모든 주문 항목도 함께 삭제됩니다. Order는 BaseTimeEntity를 통해 생성/수정 시간은 기록되지만, 데이터 삭제 자체는 차단되지 않습니다. 주문 이력이 감사 및 규정 준수 목적으로 보존되어야 한다면 현재 구성은 적절하지 않습니다.

다른 엔티티들(User-Cart, Cart-CartItems)과의 일관성을 위해 orphanRemoval = true를 추가하거나, 주문은 절대 삭제되지 않아야 하는지 재검토하시기 바랍니다.

🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/order/entity/Order.java around lines
41-42, the current @OneToMany uses CascadeType.ALL which will physically delete
OrderItem rows when an Order is removed; to preserve order history you should
either remove REMOVE from the cascade (e.g., use cascade = {PERSIST, MERGE}) and
add orphanRemoval = true if you want automatic cleanup of detached items, or
alternatively forbid hard-deletes of Order by implementing a soft-delete flag
and keeping cascade limited, ensuring order items are not physically removed for
audit compliance; update the annotation accordingly and adjust delete logic to
use soft-delete if required.


private int totalPrice;


public static Order createOrder(User user, List<OrderItem> orderItems) {
Order order = new Order();
order.setUser(user);
for (OrderItem orderItem : orderItems) {
order.addOrderItem(orderItem);
}
order.setTotalPrice(orderItems.stream().mapToInt(OrderItem::getTotalPrice).sum());
return order;
}

public void addOrderItem(OrderItem orderItem) {
orderItems.add(orderItem);
orderItem.setOrder(this);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.campustable.be.domain.order.entity;


import com.campustable.be.domain.menu.entity.Menu;
import com.campustable.be.global.exception.CustomException;
import com.campustable.be.global.exception.ErrorCode;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Entity
public class OrderItem {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long orderItemId;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="order_id")
private Order order;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="menu_id")
private Menu menu;

@Enumerated(EnumType.STRING)
private OrderStatus status;

private String menuName;
private int orderPrice;
private int quantity;

private Long categoryId;

public static OrderItem createOrderItem(Menu menu, int orderPrice, int quantity) {
OrderItem orderItem = new OrderItem();
orderItem.setMenu(menu);
orderItem.setStatus(OrderStatus.PREPARING);
orderItem.setMenuName(menu.getMenuName());
orderItem.setOrderPrice(orderPrice);
orderItem.setQuantity(quantity);
orderItem.setCategoryId(menu.getCategory().getCategoryId());
return orderItem;
}

public int getTotalPrice() {
return getOrderPrice() * getQuantity();
}

public void markAsReady() {
if (this.status != OrderStatus.PREPARING) {
throw new CustomException(ErrorCode.INVALID_ORDER_STATUS);
}
this.status = OrderStatus.READY;
}

// 수령 대기 -> 주문 완료
public void markAsCompleted() {
if (this.status != OrderStatus.READY) {
throw new CustomException(ErrorCode.INVALID_ORDER_STATUS);
}
this.status = OrderStatus.COMPLETED;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.campustable.be.domain.order.entity;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum OrderStatus {

PREPARING("조리 중"),

READY("수령 대기"),

COMPLETED("주문 완료");

private final String description;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.campustable.be.domain.order.repository;

import com.campustable.be.domain.order.entity.OrderItem;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;

public interface OrderItemRepository extends JpaRepository<OrderItem, Long> {

List<OrderItem> findByOrderOrderIdAndCategoryId(Long orderId, Long categoryId);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.campustable.be.domain.order.repository;

import com.campustable.be.domain.order.entity.Order;
import java.util.Collection;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;

public interface OrderRepository extends JpaRepository<Order, Long> {

List<Order> findByUserUserIdOrderByCreatedAtDesc(Long userId);
}
Loading