From bf9b948a6439e7995a6e7452e901c9c0752c22ae Mon Sep 17 00:00:00 2001 From: 0AndWild Date: Fri, 9 May 2025 12:28:44 +0900 Subject: [PATCH 1/6] feat: add Order model --- src/main/java/kr/mayb/data/model/Order.java | 44 +++++++++++++++++++ src/main/java/kr/mayb/data/model/Product.java | 4 +- ...uctGender.java => ProductGenderPrice.java} | 2 +- ...ductDateTime.java => ProductSchedule.java} | 4 +- .../mayb/data/repository/OrderRepository.java | 7 +++ .../repository/ProductGenderRepository.java | 4 +- ...ry.java => ProductScheduleRepository.java} | 4 +- src/main/java/kr/mayb/dto/DateTimeInfo.java | 14 ------ src/main/java/kr/mayb/dto/GenderPrice.java | 7 +-- src/main/java/kr/mayb/dto/ProductDto.java | 6 +-- .../mayb/dto/ProductRegistrationRequest.java | 2 +- .../kr/mayb/dto/ProductUpdateRequest.java | 2 +- src/main/java/kr/mayb/dto/ScheduleInfo.java | 14 ++++++ .../java/kr/mayb/enums/PaymentMethod.java | 5 +++ .../java/kr/mayb/enums/PaymentStatus.java | 7 +++ .../java/kr/mayb/service/ProductService.java | 44 +++++++++---------- 16 files changed, 117 insertions(+), 53 deletions(-) create mode 100644 src/main/java/kr/mayb/data/model/Order.java rename src/main/java/kr/mayb/data/model/{ProductGender.java => ProductGenderPrice.java} (89%) rename src/main/java/kr/mayb/data/model/{ProductDateTime.java => ProductSchedule.java} (83%) create mode 100644 src/main/java/kr/mayb/data/repository/OrderRepository.java rename src/main/java/kr/mayb/data/repository/{ProductDateTimeRepository.java => ProductScheduleRepository.java} (57%) delete mode 100644 src/main/java/kr/mayb/dto/DateTimeInfo.java create mode 100644 src/main/java/kr/mayb/dto/ScheduleInfo.java create mode 100644 src/main/java/kr/mayb/enums/PaymentMethod.java create mode 100644 src/main/java/kr/mayb/enums/PaymentStatus.java diff --git a/src/main/java/kr/mayb/data/model/Order.java b/src/main/java/kr/mayb/data/model/Order.java new file mode 100644 index 0000000..9f4bb4e --- /dev/null +++ b/src/main/java/kr/mayb/data/model/Order.java @@ -0,0 +1,44 @@ +package kr.mayb.data.model; + +import jakarta.persistence.*; +import kr.mayb.enums.PaymentMethod; +import kr.mayb.enums.PaymentStatus; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Table(schema = "mayb") +@Entity +public class Order extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @Column + private int totalAmount; + + @Column + @Enumerated(EnumType.STRING) + private PaymentMethod paymentMethod; + + @Column + @Enumerated(EnumType.STRING) + private PaymentStatus paymentStatus; + + @Column(nullable = false) + private long productId; + + @Column + private long productGenderPriceId; + + @Column + private long productScheduleId; + + @Column(nullable = false) + private long memberId; + + @Column(nullable = false, columnDefinition = "BOOLEAN DEFAULT FALSE") + private boolean hasReviewed; +} diff --git a/src/main/java/kr/mayb/data/model/Product.java b/src/main/java/kr/mayb/data/model/Product.java index 2438fe4..b42086d 100644 --- a/src/main/java/kr/mayb/data/model/Product.java +++ b/src/main/java/kr/mayb/data/model/Product.java @@ -54,9 +54,9 @@ public class Product extends BaseEntity { @BatchSize(size = 20) @OneToMany(mappedBy = "product", cascade = CascadeType.ALL) - private List productGenders = new ArrayList<>(); + private List productGenderPrices = new ArrayList<>(); @BatchSize(size = 20) @OneToMany(mappedBy = "product", cascade = CascadeType.ALL) - private List productDateTimes = new ArrayList<>(); + private List productSchedules = new ArrayList<>(); } diff --git a/src/main/java/kr/mayb/data/model/ProductGender.java b/src/main/java/kr/mayb/data/model/ProductGenderPrice.java similarity index 89% rename from src/main/java/kr/mayb/data/model/ProductGender.java rename to src/main/java/kr/mayb/data/model/ProductGenderPrice.java index 26193c4..53a750b 100644 --- a/src/main/java/kr/mayb/data/model/ProductGender.java +++ b/src/main/java/kr/mayb/data/model/ProductGenderPrice.java @@ -8,7 +8,7 @@ @Setter @Table(schema = "mayb") @Entity -public class ProductGender extends BaseEntity { +public class ProductGenderPrice extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/kr/mayb/data/model/ProductDateTime.java b/src/main/java/kr/mayb/data/model/ProductSchedule.java similarity index 83% rename from src/main/java/kr/mayb/data/model/ProductDateTime.java rename to src/main/java/kr/mayb/data/model/ProductSchedule.java index 2da83f1..5296749 100644 --- a/src/main/java/kr/mayb/data/model/ProductDateTime.java +++ b/src/main/java/kr/mayb/data/model/ProductSchedule.java @@ -10,14 +10,14 @@ @Setter @Table(schema = "mayb") @Entity -public class ProductDateTime extends BaseEntity { +public class ProductSchedule extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; @Column(nullable = false) - private LocalDateTime dateTime; + private LocalDateTime timeSlot; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "product_id", nullable = false) diff --git a/src/main/java/kr/mayb/data/repository/OrderRepository.java b/src/main/java/kr/mayb/data/repository/OrderRepository.java new file mode 100644 index 0000000..a31454a --- /dev/null +++ b/src/main/java/kr/mayb/data/repository/OrderRepository.java @@ -0,0 +1,7 @@ +package kr.mayb.data.repository; + +import kr.mayb.data.model.Order; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface OrderRepository extends JpaRepository { +} diff --git a/src/main/java/kr/mayb/data/repository/ProductGenderRepository.java b/src/main/java/kr/mayb/data/repository/ProductGenderRepository.java index 993f459..33aff0d 100644 --- a/src/main/java/kr/mayb/data/repository/ProductGenderRepository.java +++ b/src/main/java/kr/mayb/data/repository/ProductGenderRepository.java @@ -1,9 +1,9 @@ package kr.mayb.data.repository; import kr.mayb.data.model.Product; -import kr.mayb.data.model.ProductGender; +import kr.mayb.data.model.ProductGenderPrice; import org.springframework.data.jpa.repository.JpaRepository; -public interface ProductGenderRepository extends JpaRepository { +public interface ProductGenderRepository extends JpaRepository { void deleteByProduct(Product product); } diff --git a/src/main/java/kr/mayb/data/repository/ProductDateTimeRepository.java b/src/main/java/kr/mayb/data/repository/ProductScheduleRepository.java similarity index 57% rename from src/main/java/kr/mayb/data/repository/ProductDateTimeRepository.java rename to src/main/java/kr/mayb/data/repository/ProductScheduleRepository.java index 49aceed..157e194 100644 --- a/src/main/java/kr/mayb/data/repository/ProductDateTimeRepository.java +++ b/src/main/java/kr/mayb/data/repository/ProductScheduleRepository.java @@ -1,9 +1,9 @@ package kr.mayb.data.repository; import kr.mayb.data.model.Product; -import kr.mayb.data.model.ProductDateTime; +import kr.mayb.data.model.ProductSchedule; import org.springframework.data.jpa.repository.JpaRepository; -public interface ProductDateTimeRepository extends JpaRepository { +public interface ProductScheduleRepository extends JpaRepository { void deleteByProduct(Product product); } diff --git a/src/main/java/kr/mayb/dto/DateTimeInfo.java b/src/main/java/kr/mayb/dto/DateTimeInfo.java deleted file mode 100644 index 2bbf552..0000000 --- a/src/main/java/kr/mayb/dto/DateTimeInfo.java +++ /dev/null @@ -1,14 +0,0 @@ -package kr.mayb.dto; - -import kr.mayb.data.model.ProductDateTime; - -import java.time.LocalDateTime; - -public record DateTimeInfo( - long id, - LocalDateTime dateTime -) { - public static DateTimeInfo of(ProductDateTime dateTime) { - return new DateTimeInfo(dateTime.getId(), dateTime.getDateTime()); - } -} diff --git a/src/main/java/kr/mayb/dto/GenderPrice.java b/src/main/java/kr/mayb/dto/GenderPrice.java index 0e72ee9..4ca9fb4 100644 --- a/src/main/java/kr/mayb/dto/GenderPrice.java +++ b/src/main/java/kr/mayb/dto/GenderPrice.java @@ -1,14 +1,15 @@ package kr.mayb.dto; import jakarta.validation.constraints.NotBlank; -import kr.mayb.data.model.ProductGender; +import kr.mayb.data.model.ProductGenderPrice; public record GenderPrice( + long id, @NotBlank String gender, int price ) { - public static GenderPrice of(ProductGender gender) { - return new GenderPrice(gender.getGender(), gender.getPrice()); + public static GenderPrice of(ProductGenderPrice gender) { + return new GenderPrice(gender.getId(), gender.getGender(), gender.getPrice()); } } diff --git a/src/main/java/kr/mayb/dto/ProductDto.java b/src/main/java/kr/mayb/dto/ProductDto.java index 069b08f..a2f82b5 100644 --- a/src/main/java/kr/mayb/dto/ProductDto.java +++ b/src/main/java/kr/mayb/dto/ProductDto.java @@ -24,7 +24,7 @@ public class ProductDto { private final List tags; private final List genderPrices; - private final List dateTimes; + private final List schedules; private final ProductStatus status; @@ -40,8 +40,8 @@ public ProductDto(Product product, boolean isAdmin) { this.originalPrice = product.getOriginalPrice(); this.salePrice = product.getSalePrice(); this.tags = product.getProductTags().stream().map(TagInfo::of).toList(); - this.genderPrices = product.getProductGenders().stream().map(GenderPrice::of).toList(); - this.dateTimes = product.getProductDateTimes().stream().map(DateTimeInfo::of).toList(); + this.genderPrices = product.getProductGenderPrices().stream().map(GenderPrice::of).toList(); + this.schedules = product.getProductSchedules().stream().map(ScheduleInfo::of).toList(); this.status = product.getStatus(); if (isAdmin) { diff --git a/src/main/java/kr/mayb/dto/ProductRegistrationRequest.java b/src/main/java/kr/mayb/dto/ProductRegistrationRequest.java index becc997..4122d7b 100644 --- a/src/main/java/kr/mayb/dto/ProductRegistrationRequest.java +++ b/src/main/java/kr/mayb/dto/ProductRegistrationRequest.java @@ -25,7 +25,7 @@ public record ProductRegistrationRequest( @NotNull @Size(min = 1) - List dateTimes, + List schedules, @Valid @NotNull diff --git a/src/main/java/kr/mayb/dto/ProductUpdateRequest.java b/src/main/java/kr/mayb/dto/ProductUpdateRequest.java index c1e98dc..9a84479 100644 --- a/src/main/java/kr/mayb/dto/ProductUpdateRequest.java +++ b/src/main/java/kr/mayb/dto/ProductUpdateRequest.java @@ -25,7 +25,7 @@ public record ProductUpdateRequest( @NotNull @Size(min = 1) - List dateTimes, + List schedules, @Valid @NotNull diff --git a/src/main/java/kr/mayb/dto/ScheduleInfo.java b/src/main/java/kr/mayb/dto/ScheduleInfo.java new file mode 100644 index 0000000..922464a --- /dev/null +++ b/src/main/java/kr/mayb/dto/ScheduleInfo.java @@ -0,0 +1,14 @@ +package kr.mayb.dto; + +import kr.mayb.data.model.ProductSchedule; + +import java.time.LocalDateTime; + +public record ScheduleInfo( + long id, + LocalDateTime time +) { + public static ScheduleInfo of(ProductSchedule schedule) { + return new ScheduleInfo(schedule.getId(), schedule.getTimeSlot()); + } +} diff --git a/src/main/java/kr/mayb/enums/PaymentMethod.java b/src/main/java/kr/mayb/enums/PaymentMethod.java new file mode 100644 index 0000000..650db79 --- /dev/null +++ b/src/main/java/kr/mayb/enums/PaymentMethod.java @@ -0,0 +1,5 @@ +package kr.mayb.enums; + +public enum PaymentMethod { + BANK_TRANSFER, +} diff --git a/src/main/java/kr/mayb/enums/PaymentStatus.java b/src/main/java/kr/mayb/enums/PaymentStatus.java new file mode 100644 index 0000000..9f994f4 --- /dev/null +++ b/src/main/java/kr/mayb/enums/PaymentStatus.java @@ -0,0 +1,7 @@ +package kr.mayb.enums; + +public enum PaymentStatus { + PENDING, + COMPLETED, + REFUNDED, +} diff --git a/src/main/java/kr/mayb/service/ProductService.java b/src/main/java/kr/mayb/service/ProductService.java index 43cac4a..b396b1c 100644 --- a/src/main/java/kr/mayb/service/ProductService.java +++ b/src/main/java/kr/mayb/service/ProductService.java @@ -3,12 +3,12 @@ import io.micrometer.common.util.StringUtils; import jakarta.transaction.Transactional; import kr.mayb.data.model.Product; -import kr.mayb.data.model.ProductDateTime; -import kr.mayb.data.model.ProductGender; +import kr.mayb.data.model.ProductGenderPrice; +import kr.mayb.data.model.ProductSchedule; import kr.mayb.data.model.ProductTag; -import kr.mayb.data.repository.ProductDateTimeRepository; import kr.mayb.data.repository.ProductGenderRepository; import kr.mayb.data.repository.ProductRepository; +import kr.mayb.data.repository.ProductScheduleRepository; import kr.mayb.data.repository.ProductTagRepository; import kr.mayb.dto.GenderPrice; import kr.mayb.dto.ProductDto; @@ -37,7 +37,7 @@ public class ProductService { private final ProductRepository productRepository; private final ProductTagRepository productTagRepository; private final ProductGenderRepository productGenderRepository; - private final ProductDateTimeRepository productDateTimeRepository; + private final ProductScheduleRepository productScheduleRepository; @Transactional public ProductDto registerProduct(ProductRegistrationRequest request, String profileUrl, String detailUrl, long creatorId) { @@ -52,13 +52,13 @@ public ProductDto registerProduct(ProductRegistrationRequest request, String pro product.setLastModifierId(creatorId); product.setStatus(ProductStatus.ACTIVE); - saveAdditionalInfo(request.tags(), request.dateTimes(), request.genderPrices(), product); + saveAdditionalInfo(request.tags(), request.schedules(), request.genderPrices(), product); Product saved = productRepository.save(product); return ProductDto.of(saved, true); } - private void saveAdditionalInfo(List tags, List dateTimes, List genderPrices, Product product) { + private void saveAdditionalInfo(List tags, List schedules, List genderPrices, Product product) { List productTags = tags.stream() .filter(StringUtils::isNotBlank) .map(tag -> { @@ -69,29 +69,29 @@ private void saveAdditionalInfo(List tags, List dateTimes }) .collect(Collectors.toList()); - List productDateTimes = dateTimes.stream() + List productSchedules = schedules.stream() .filter(Objects::nonNull) - .map(dateTime -> { - ProductDateTime productDateTime = new ProductDateTime(); - productDateTime.setDateTime(dateTime); - productDateTime.setProduct(product); - return productDateTime; + .map(time -> { + ProductSchedule productSchedule = new ProductSchedule(); + productSchedule.setTimeSlot(time); + productSchedule.setProduct(product); + return productSchedule; }) .collect(Collectors.toList()); - List productGenders = genderPrices.stream() + List productGenderPrices = genderPrices.stream() .map(genderPrice -> { - ProductGender productGender = new ProductGender(); - productGender.setGender(genderPrice.gender()); - productGender.setPrice(genderPrice.price()); - productGender.setProduct(product); - return productGender; + ProductGenderPrice productGenderPrice = new ProductGenderPrice(); + productGenderPrice.setGender(genderPrice.gender()); + productGenderPrice.setPrice(genderPrice.price()); + productGenderPrice.setProduct(product); + return productGenderPrice; }) .collect(Collectors.toList()); product.setProductTags(productTags); - product.setProductDateTimes(productDateTimes); - product.setProductGenders(productGenders); + product.setProductSchedules(productSchedules); + product.setProductGenderPrices(productGenderPrices); } public List getProducts(boolean isAdmin) { @@ -178,7 +178,7 @@ private void updateProductImage(Optional profileUrl, Optional de private void clearAndUpdateAdditionalInfo(ProductUpdateRequest request, Product product) { productTagRepository.deleteByProduct(product); productGenderRepository.deleteByProduct(product); - productDateTimeRepository.deleteByProduct(product); - saveAdditionalInfo(request.tags(), request.dateTimes(), request.genderPrices(), product); + productScheduleRepository.deleteByProduct(product); + saveAdditionalInfo(request.tags(), request.schedules(), request.genderPrices(), product); } } From 205d106ca05d20ca2f0a0277378bb51a42dc4c12 Mon Sep 17 00:00:00 2001 From: 0AndWild Date: Fri, 9 May 2025 14:15:40 +0900 Subject: [PATCH 2/6] feat: add makeOrder API --- .../kr/mayb/controller/OrderController.java | 33 +++++++++++++ .../mayb/controller/SecurityController.java | 2 + src/main/java/kr/mayb/data/model/Order.java | 4 +- src/main/java/kr/mayb/data/model/Product.java | 2 +- ...java => ProductGenderPriceRepository.java} | 6 ++- .../repository/ProductScheduleRepository.java | 4 ++ src/main/java/kr/mayb/dto/GenderPrice.java | 2 +- src/main/java/kr/mayb/dto/OrderInfo.java | 43 +++++++++++++++++ src/main/java/kr/mayb/dto/OrderRequest.java | 19 ++++++++ .../java/kr/mayb/dto/OrderedProductItem.java | 15 ++++++ src/main/java/kr/mayb/dto/ProductDto.java | 8 ++-- src/main/java/kr/mayb/dto/ScheduleInfo.java | 2 +- src/main/java/kr/mayb/dto/TagInfo.java | 2 +- src/main/java/kr/mayb/facade/OrderFacade.java | 37 +++++++++++++++ .../java/kr/mayb/service/OrderService.java | 32 +++++++++++++ .../java/kr/mayb/service/ProductService.java | 47 +++++++++++++------ 16 files changed, 232 insertions(+), 26 deletions(-) create mode 100644 src/main/java/kr/mayb/controller/OrderController.java rename src/main/java/kr/mayb/data/repository/{ProductGenderRepository.java => ProductGenderPriceRepository.java} (52%) create mode 100644 src/main/java/kr/mayb/dto/OrderInfo.java create mode 100644 src/main/java/kr/mayb/dto/OrderRequest.java create mode 100644 src/main/java/kr/mayb/dto/OrderedProductItem.java create mode 100644 src/main/java/kr/mayb/facade/OrderFacade.java create mode 100644 src/main/java/kr/mayb/service/OrderService.java diff --git a/src/main/java/kr/mayb/controller/OrderController.java b/src/main/java/kr/mayb/controller/OrderController.java new file mode 100644 index 0000000..98f8629 --- /dev/null +++ b/src/main/java/kr/mayb/controller/OrderController.java @@ -0,0 +1,33 @@ +package kr.mayb.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import kr.mayb.dto.OrderInfo; +import kr.mayb.dto.OrderRequest; +import kr.mayb.facade.OrderFacade; +import kr.mayb.security.DenyAll; +import kr.mayb.security.PermitAuthenticated; +import kr.mayb.util.response.ApiResponse; +import kr.mayb.util.response.Responses; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "Order", description = "주문 관련 API") +@DenyAll +@RestController +@RequiredArgsConstructor +public class OrderController { + + private final OrderFacade orderFacade; + + @Operation(summary = "주문하기") + @PermitAuthenticated + @PostMapping("/orders") + public ResponseEntity> makeOrder(@RequestBody OrderRequest request) { + OrderInfo response = orderFacade.makeOrder(request); + return Responses.ok(response); + } +} diff --git a/src/main/java/kr/mayb/controller/SecurityController.java b/src/main/java/kr/mayb/controller/SecurityController.java index 7d9b3b1..21865a1 100644 --- a/src/main/java/kr/mayb/controller/SecurityController.java +++ b/src/main/java/kr/mayb/controller/SecurityController.java @@ -1,6 +1,7 @@ package kr.mayb.controller; import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.tags.Tag; import kr.mayb.security.DenyAll; import kr.mayb.security.PermitAll; import kr.mayb.security.PermitAuthenticated; @@ -10,6 +11,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; +@Tag(name = "Security", description = "security 관련 Test API. Swagger 에 표시 안됨") @Hidden @DenyAll @RestController diff --git a/src/main/java/kr/mayb/data/model/Order.java b/src/main/java/kr/mayb/data/model/Order.java index 9f4bb4e..c0f5a19 100644 --- a/src/main/java/kr/mayb/data/model/Order.java +++ b/src/main/java/kr/mayb/data/model/Order.java @@ -17,7 +17,7 @@ public class Order extends BaseEntity { private long id; @Column - private int totalAmount; + private int totalPrice; @Column @Enumerated(EnumType.STRING) @@ -39,6 +39,6 @@ public class Order extends BaseEntity { @Column(nullable = false) private long memberId; - @Column(nullable = false, columnDefinition = "BOOLEAN DEFAULT FALSE") + @Column(nullable = false) private boolean hasReviewed; } diff --git a/src/main/java/kr/mayb/data/model/Product.java b/src/main/java/kr/mayb/data/model/Product.java index b42086d..a7236e5 100644 --- a/src/main/java/kr/mayb/data/model/Product.java +++ b/src/main/java/kr/mayb/data/model/Product.java @@ -27,7 +27,7 @@ public class Product extends BaseEntity { private int originalPrice; @Column - private int salePrice; + private int discountPrice; @Column private String profileImageUrl; diff --git a/src/main/java/kr/mayb/data/repository/ProductGenderRepository.java b/src/main/java/kr/mayb/data/repository/ProductGenderPriceRepository.java similarity index 52% rename from src/main/java/kr/mayb/data/repository/ProductGenderRepository.java rename to src/main/java/kr/mayb/data/repository/ProductGenderPriceRepository.java index 33aff0d..2d59874 100644 --- a/src/main/java/kr/mayb/data/repository/ProductGenderRepository.java +++ b/src/main/java/kr/mayb/data/repository/ProductGenderPriceRepository.java @@ -4,6 +4,10 @@ import kr.mayb.data.model.ProductGenderPrice; import org.springframework.data.jpa.repository.JpaRepository; -public interface ProductGenderRepository extends JpaRepository { +import java.util.Optional; + +public interface ProductGenderPriceRepository extends JpaRepository { void deleteByProduct(Product product); + + Optional findByIdAndProduct(long id, Product product); } diff --git a/src/main/java/kr/mayb/data/repository/ProductScheduleRepository.java b/src/main/java/kr/mayb/data/repository/ProductScheduleRepository.java index 157e194..a1a6c26 100644 --- a/src/main/java/kr/mayb/data/repository/ProductScheduleRepository.java +++ b/src/main/java/kr/mayb/data/repository/ProductScheduleRepository.java @@ -4,6 +4,10 @@ import kr.mayb.data.model.ProductSchedule; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; + public interface ProductScheduleRepository extends JpaRepository { void deleteByProduct(Product product); + + Optional findByIdAndProduct(long id, Product product); } diff --git a/src/main/java/kr/mayb/dto/GenderPrice.java b/src/main/java/kr/mayb/dto/GenderPrice.java index 4ca9fb4..2016e14 100644 --- a/src/main/java/kr/mayb/dto/GenderPrice.java +++ b/src/main/java/kr/mayb/dto/GenderPrice.java @@ -4,7 +4,7 @@ import kr.mayb.data.model.ProductGenderPrice; public record GenderPrice( - long id, + long priceId, @NotBlank String gender, int price diff --git a/src/main/java/kr/mayb/dto/OrderInfo.java b/src/main/java/kr/mayb/dto/OrderInfo.java new file mode 100644 index 0000000..b775566 --- /dev/null +++ b/src/main/java/kr/mayb/dto/OrderInfo.java @@ -0,0 +1,43 @@ +package kr.mayb.dto; + +import kr.mayb.data.model.Order; +import kr.mayb.enums.PaymentMethod; +import kr.mayb.enums.PaymentStatus; + +import java.time.LocalDateTime; +import java.time.OffsetDateTime; + +public record OrderInfo( + long orderId, + + int totalPrice, + PaymentMethod paymentMethod, + PaymentStatus paymentStatus, + boolean hasReviewed, + + String productName, + String productProfileImage, + + String gender, + LocalDateTime scheduledAt, + + String customerName, + + OffsetDateTime createdAt +) { + public static OrderInfo of(Order order, OrderedProductItem productItem, String customerName) { + return new OrderInfo( + order.getId(), + order.getTotalPrice(), + order.getPaymentMethod(), + order.getPaymentStatus(), + order.isHasReviewed(), + productItem.product().getName(), + productItem.product().getProfileImageUrl(), + productItem.genderPrice().getGender(), + productItem.schedule().getTimeSlot(), + customerName, + order.getCreatedAt() + ); + } +} diff --git a/src/main/java/kr/mayb/dto/OrderRequest.java b/src/main/java/kr/mayb/dto/OrderRequest.java new file mode 100644 index 0000000..1b5d843 --- /dev/null +++ b/src/main/java/kr/mayb/dto/OrderRequest.java @@ -0,0 +1,19 @@ +package kr.mayb.dto; + +import jakarta.validation.constraints.NotNull; +import kr.mayb.enums.PaymentMethod; + +public record OrderRequest( + @NotNull + long productId, + + @NotNull + long priceId, + + @NotNull + long scheduleId, + + @NotNull + PaymentMethod paymentMethod +) { +} diff --git a/src/main/java/kr/mayb/dto/OrderedProductItem.java b/src/main/java/kr/mayb/dto/OrderedProductItem.java new file mode 100644 index 0000000..25225fc --- /dev/null +++ b/src/main/java/kr/mayb/dto/OrderedProductItem.java @@ -0,0 +1,15 @@ +package kr.mayb.dto; + +import kr.mayb.data.model.Product; +import kr.mayb.data.model.ProductGenderPrice; +import kr.mayb.data.model.ProductSchedule; + +public record OrderedProductItem( + Product product, + ProductGenderPrice genderPrice, + ProductSchedule schedule +) { + public static OrderedProductItem of(Product product, ProductGenderPrice genderPrice, ProductSchedule schedule) { + return new OrderedProductItem(product, genderPrice, schedule); + } +} diff --git a/src/main/java/kr/mayb/dto/ProductDto.java b/src/main/java/kr/mayb/dto/ProductDto.java index a2f82b5..f76262d 100644 --- a/src/main/java/kr/mayb/dto/ProductDto.java +++ b/src/main/java/kr/mayb/dto/ProductDto.java @@ -20,10 +20,10 @@ public class ProductDto { private final String description; private final int originalPrice; - private final int salePrice; + private final int discountPrice; private final List tags; - private final List genderPrices; + private final List prices; private final List schedules; private final ProductStatus status; @@ -38,9 +38,9 @@ public ProductDto(Product product, boolean isAdmin) { this.detailImageUrl = product.getDetailImageUrl(); this.description = product.getDescription(); this.originalPrice = product.getOriginalPrice(); - this.salePrice = product.getSalePrice(); + this.discountPrice = product.getDiscountPrice(); this.tags = product.getProductTags().stream().map(TagInfo::of).toList(); - this.genderPrices = product.getProductGenderPrices().stream().map(GenderPrice::of).toList(); + this.prices = product.getProductGenderPrices().stream().map(GenderPrice::of).toList(); this.schedules = product.getProductSchedules().stream().map(ScheduleInfo::of).toList(); this.status = product.getStatus(); diff --git a/src/main/java/kr/mayb/dto/ScheduleInfo.java b/src/main/java/kr/mayb/dto/ScheduleInfo.java index 922464a..b7c4c56 100644 --- a/src/main/java/kr/mayb/dto/ScheduleInfo.java +++ b/src/main/java/kr/mayb/dto/ScheduleInfo.java @@ -5,7 +5,7 @@ import java.time.LocalDateTime; public record ScheduleInfo( - long id, + long scheduleId, LocalDateTime time ) { public static ScheduleInfo of(ProductSchedule schedule) { diff --git a/src/main/java/kr/mayb/dto/TagInfo.java b/src/main/java/kr/mayb/dto/TagInfo.java index da342ca..d0749d8 100644 --- a/src/main/java/kr/mayb/dto/TagInfo.java +++ b/src/main/java/kr/mayb/dto/TagInfo.java @@ -3,7 +3,7 @@ import kr.mayb.data.model.ProductTag; public record TagInfo( - long id, + long tagId, String name ) { public static TagInfo of(ProductTag tag) { diff --git a/src/main/java/kr/mayb/facade/OrderFacade.java b/src/main/java/kr/mayb/facade/OrderFacade.java new file mode 100644 index 0000000..8aebd6f --- /dev/null +++ b/src/main/java/kr/mayb/facade/OrderFacade.java @@ -0,0 +1,37 @@ +package kr.mayb.facade; + +import kr.mayb.data.model.Member; +import kr.mayb.data.model.Order; +import kr.mayb.dto.MemberDto; +import kr.mayb.dto.OrderInfo; +import kr.mayb.dto.OrderRequest; +import kr.mayb.dto.OrderedProductItem; +import kr.mayb.service.MemberService; +import kr.mayb.service.OrderService; +import kr.mayb.service.ProductService; +import kr.mayb.util.ContextUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class OrderFacade { + private final MemberService memberService; + private final OrderService orderService; + private final ProductService productService; + + public OrderInfo makeOrder(OrderRequest request) { + MemberDto member = ContextUtils.loadMember(); + OrderedProductItem productItem = productService.findOrderedProductItem(request.productId(), request.priceId(), request.scheduleId()); + + Order saved = orderService.makeOrder(productItem, request.paymentMethod(), member.getMemberId()); + return convertToOrderInfo(saved); + } + + private OrderInfo convertToOrderInfo(Order saved) { + Member member = memberService.getMember(saved.getMemberId()); + OrderedProductItem productItem = productService.findOrderedProductItem(saved.getProductId(), saved.getProductGenderPriceId(), saved.getProductScheduleId()); + + return OrderInfo.of(saved, productItem, member.getName()); + } +} diff --git a/src/main/java/kr/mayb/service/OrderService.java b/src/main/java/kr/mayb/service/OrderService.java new file mode 100644 index 0000000..80e3394 --- /dev/null +++ b/src/main/java/kr/mayb/service/OrderService.java @@ -0,0 +1,32 @@ +package kr.mayb.service; + +import jakarta.transaction.Transactional; +import kr.mayb.data.model.Order; +import kr.mayb.data.repository.OrderRepository; +import kr.mayb.dto.OrderedProductItem; +import kr.mayb.enums.PaymentMethod; +import kr.mayb.enums.PaymentStatus; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class OrderService { + + private final OrderRepository orderRepository; + + @Transactional + public Order makeOrder(OrderedProductItem productItem, PaymentMethod paymentMethod, long memberId) { + Order order = new Order(); + order.setPaymentMethod(paymentMethod); + order.setTotalPrice(productItem.genderPrice().getPrice()); + order.setPaymentStatus(PaymentStatus.PENDING); + order.setProductId(productItem.product().getId()); + order.setProductGenderPriceId(productItem.genderPrice().getId()); + order.setProductScheduleId(productItem.schedule().getId()); + order.setMemberId(memberId); + order.setHasReviewed(false); + + return orderRepository.save(order); + } +} diff --git a/src/main/java/kr/mayb/service/ProductService.java b/src/main/java/kr/mayb/service/ProductService.java index b396b1c..446ea87 100644 --- a/src/main/java/kr/mayb/service/ProductService.java +++ b/src/main/java/kr/mayb/service/ProductService.java @@ -6,14 +6,11 @@ import kr.mayb.data.model.ProductGenderPrice; import kr.mayb.data.model.ProductSchedule; import kr.mayb.data.model.ProductTag; -import kr.mayb.data.repository.ProductGenderRepository; +import kr.mayb.data.repository.ProductGenderPriceRepository; import kr.mayb.data.repository.ProductRepository; import kr.mayb.data.repository.ProductScheduleRepository; import kr.mayb.data.repository.ProductTagRepository; -import kr.mayb.dto.GenderPrice; -import kr.mayb.dto.ProductDto; -import kr.mayb.dto.ProductRegistrationRequest; -import kr.mayb.dto.ProductUpdateRequest; +import kr.mayb.dto.*; import kr.mayb.enums.GcsBucketPath; import kr.mayb.enums.ProductStatus; import kr.mayb.error.ResourceNotFoundException; @@ -36,7 +33,7 @@ public class ProductService { private final ProductRepository productRepository; private final ProductTagRepository productTagRepository; - private final ProductGenderRepository productGenderRepository; + private final ProductGenderPriceRepository productGenderPriceRepository; private final ProductScheduleRepository productScheduleRepository; @Transactional @@ -44,7 +41,7 @@ public ProductDto registerProduct(ProductRegistrationRequest request, String pro Product product = new Product(); product.setName(request.name()); product.setOriginalPrice(request.originalPrice()); - product.setSalePrice(request.salePrice()); + product.setDiscountPrice(request.salePrice()); product.setProfileImageUrl(profileUrl); product.setDetailImageUrl(detailUrl); product.setDescription(request.description()); @@ -113,8 +110,7 @@ public List getProducts(boolean isAdmin) { } public ProductDto getProduct(long productId, boolean isAdmin) { - Product product = productRepository.findById(productId) - .orElseThrow(() -> new ResourceNotFoundException("Product not found.: " + productId)); + Product product = getProduct(productId); if (isAdmin) { return ProductDto.of(product, true); @@ -129,12 +125,11 @@ public ProductDto getProduct(long productId, boolean isAdmin) { @Transactional public ProductDto updateProduct(long productId, Optional profileUrl, Optional detailUrl, ProductUpdateRequest request, long modifierId) { - Product product = productRepository.findById(productId) - .orElseThrow(() -> new ResourceNotFoundException("Product not found.: " + productId)); + Product product = getProduct(productId); product.setName(request.name()); product.setOriginalPrice(request.originalPrice()); - product.setSalePrice(request.salePrice()); + product.setDiscountPrice(request.salePrice()); product.setDescription(request.description()); updateProductImage(profileUrl, detailUrl, product); @@ -152,8 +147,7 @@ public void delete(long productId) { @Transactional public void changeStatus(long productId, boolean active, long memberId) { - Product product = productRepository.findById(productId) - .orElseThrow(() -> new ResourceNotFoundException("Product not found.: " + productId)); + Product product = getProduct(productId); if (active) { product.setStatus(ProductStatus.ACTIVE); @@ -164,6 +158,14 @@ public void changeStatus(long productId, boolean active, long memberId) { product.setLastModifierId(memberId); } + public OrderedProductItem findOrderedProductItem(long productId, long priceId, long scheduleId) { + Product product = getProduct(productId); + ProductGenderPrice genderPrice = getGenderPrice(priceId, product); + ProductSchedule schedule = getSchedule(scheduleId, product); + + return OrderedProductItem.of(product, genderPrice, schedule); + } + private void updateProductImage(Optional profileUrl, Optional detailUrl, Product product) { profileUrl.ifPresent(url -> { imageService.delete(product.getProfileImageUrl(), GcsBucketPath.PRODUCT_PROFILE); @@ -177,8 +179,23 @@ private void updateProductImage(Optional profileUrl, Optional de private void clearAndUpdateAdditionalInfo(ProductUpdateRequest request, Product product) { productTagRepository.deleteByProduct(product); - productGenderRepository.deleteByProduct(product); + productGenderPriceRepository.deleteByProduct(product); productScheduleRepository.deleteByProduct(product); saveAdditionalInfo(request.tags(), request.schedules(), request.genderPrices(), product); } + + private ProductSchedule getSchedule(long scheduleId, Product product) { + return productScheduleRepository.findByIdAndProduct(scheduleId, product) + .orElseThrow(() -> new ResourceNotFoundException("Schedule not found: " + scheduleId)); + } + + private ProductGenderPrice getGenderPrice(long priceId, Product product) { + return productGenderPriceRepository.findByIdAndProduct(priceId, product) + .orElseThrow(() -> new ResourceNotFoundException("Price not found: " + priceId)); + } + + private Product getProduct(long productId) { + return productRepository.findById(productId) + .orElseThrow(() -> new ResourceNotFoundException("Product not found: " + productId)); + } } From a6422b41efc63687b93de473498261c1ec3df771 Mon Sep 17 00:00:00 2001 From: 0AndWild Date: Fri, 9 May 2025 14:31:20 +0900 Subject: [PATCH 3/6] refactor: remove tag entity for performance --- src/main/java/kr/mayb/data/model/Product.java | 5 ++-- .../java/kr/mayb/data/model/ProductTag.java | 23 ------------------ .../data/repository/ProductTagRepository.java | 10 -------- src/main/java/kr/mayb/dto/ProductDto.java | 4 ++-- src/main/java/kr/mayb/dto/TagInfo.java | 12 ---------- .../java/kr/mayb/service/ProductService.java | 24 ++++--------------- 6 files changed, 9 insertions(+), 69 deletions(-) delete mode 100644 src/main/java/kr/mayb/data/model/ProductTag.java delete mode 100644 src/main/java/kr/mayb/data/repository/ProductTagRepository.java delete mode 100644 src/main/java/kr/mayb/dto/TagInfo.java diff --git a/src/main/java/kr/mayb/data/model/Product.java b/src/main/java/kr/mayb/data/model/Product.java index a7236e5..0908fa9 100644 --- a/src/main/java/kr/mayb/data/model/Product.java +++ b/src/main/java/kr/mayb/data/model/Product.java @@ -48,9 +48,8 @@ public class Product extends BaseEntity { @Enumerated(EnumType.STRING) private ProductStatus status; - @BatchSize(size = 20) - @OneToMany(mappedBy = "product", cascade = CascadeType.ALL) - private List productTags = new ArrayList<>(); + @Column + private String tags; @BatchSize(size = 20) @OneToMany(mappedBy = "product", cascade = CascadeType.ALL) diff --git a/src/main/java/kr/mayb/data/model/ProductTag.java b/src/main/java/kr/mayb/data/model/ProductTag.java deleted file mode 100644 index cea4c8d..0000000 --- a/src/main/java/kr/mayb/data/model/ProductTag.java +++ /dev/null @@ -1,23 +0,0 @@ -package kr.mayb.data.model; - -import jakarta.persistence.*; -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -@Table(schema = "mayb") -@Entity -public class ProductTag { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private long id; - - @Column(nullable = false) - private String name; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "product_id", nullable = false) - private Product product; -} diff --git a/src/main/java/kr/mayb/data/repository/ProductTagRepository.java b/src/main/java/kr/mayb/data/repository/ProductTagRepository.java deleted file mode 100644 index cb71a96..0000000 --- a/src/main/java/kr/mayb/data/repository/ProductTagRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package kr.mayb.data.repository; - -import kr.mayb.data.model.Product; -import kr.mayb.data.model.ProductTag; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface ProductTagRepository extends JpaRepository { - - void deleteByProduct(Product product); -} diff --git a/src/main/java/kr/mayb/dto/ProductDto.java b/src/main/java/kr/mayb/dto/ProductDto.java index f76262d..b1f868a 100644 --- a/src/main/java/kr/mayb/dto/ProductDto.java +++ b/src/main/java/kr/mayb/dto/ProductDto.java @@ -22,7 +22,7 @@ public class ProductDto { private final int originalPrice; private final int discountPrice; - private final List tags; + private final List tags; private final List prices; private final List schedules; @@ -39,7 +39,7 @@ public ProductDto(Product product, boolean isAdmin) { this.description = product.getDescription(); this.originalPrice = product.getOriginalPrice(); this.discountPrice = product.getDiscountPrice(); - this.tags = product.getProductTags().stream().map(TagInfo::of).toList(); + this.tags = List.of(product.getTags().split("\\|")); this.prices = product.getProductGenderPrices().stream().map(GenderPrice::of).toList(); this.schedules = product.getProductSchedules().stream().map(ScheduleInfo::of).toList(); this.status = product.getStatus(); diff --git a/src/main/java/kr/mayb/dto/TagInfo.java b/src/main/java/kr/mayb/dto/TagInfo.java deleted file mode 100644 index d0749d8..0000000 --- a/src/main/java/kr/mayb/dto/TagInfo.java +++ /dev/null @@ -1,12 +0,0 @@ -package kr.mayb.dto; - -import kr.mayb.data.model.ProductTag; - -public record TagInfo( - long tagId, - String name -) { - public static TagInfo of(ProductTag tag) { - return new TagInfo(tag.getId(), tag.getName()); - } -} diff --git a/src/main/java/kr/mayb/service/ProductService.java b/src/main/java/kr/mayb/service/ProductService.java index 446ea87..0e045d7 100644 --- a/src/main/java/kr/mayb/service/ProductService.java +++ b/src/main/java/kr/mayb/service/ProductService.java @@ -1,15 +1,12 @@ package kr.mayb.service; -import io.micrometer.common.util.StringUtils; import jakarta.transaction.Transactional; import kr.mayb.data.model.Product; import kr.mayb.data.model.ProductGenderPrice; import kr.mayb.data.model.ProductSchedule; -import kr.mayb.data.model.ProductTag; import kr.mayb.data.repository.ProductGenderPriceRepository; import kr.mayb.data.repository.ProductRepository; import kr.mayb.data.repository.ProductScheduleRepository; -import kr.mayb.data.repository.ProductTagRepository; import kr.mayb.dto.*; import kr.mayb.enums.GcsBucketPath; import kr.mayb.enums.ProductStatus; @@ -32,7 +29,6 @@ public class ProductService { private final ImageService imageService; private final ProductRepository productRepository; - private final ProductTagRepository productTagRepository; private final ProductGenderPriceRepository productGenderPriceRepository; private final ProductScheduleRepository productScheduleRepository; @@ -48,24 +44,15 @@ public ProductDto registerProduct(ProductRegistrationRequest request, String pro product.setCreatorId(creatorId); product.setLastModifierId(creatorId); product.setStatus(ProductStatus.ACTIVE); + product.setTags(String.join("|", request.tags())); - saveAdditionalInfo(request.tags(), request.schedules(), request.genderPrices(), product); + saveAdditionalInfo(request.schedules(), request.genderPrices(), product); Product saved = productRepository.save(product); return ProductDto.of(saved, true); } - private void saveAdditionalInfo(List tags, List schedules, List genderPrices, Product product) { - List productTags = tags.stream() - .filter(StringUtils::isNotBlank) - .map(tag -> { - ProductTag productTag = new ProductTag(); - productTag.setName(tag); - productTag.setProduct(product); - return productTag; - }) - .collect(Collectors.toList()); - + private void saveAdditionalInfo(List schedules, List genderPrices, Product product) { List productSchedules = schedules.stream() .filter(Objects::nonNull) .map(time -> { @@ -86,7 +73,6 @@ private void saveAdditionalInfo(List tags, List schedules }) .collect(Collectors.toList()); - product.setProductTags(productTags); product.setProductSchedules(productSchedules); product.setProductGenderPrices(productGenderPrices); } @@ -131,6 +117,7 @@ public ProductDto updateProduct(long productId, Optional profileUrl, Opt product.setOriginalPrice(request.originalPrice()); product.setDiscountPrice(request.salePrice()); product.setDescription(request.description()); + product.setTags(String.join("|", request.tags())); updateProductImage(profileUrl, detailUrl, product); clearAndUpdateAdditionalInfo(request, product); @@ -178,10 +165,9 @@ private void updateProductImage(Optional profileUrl, Optional de } private void clearAndUpdateAdditionalInfo(ProductUpdateRequest request, Product product) { - productTagRepository.deleteByProduct(product); productGenderPriceRepository.deleteByProduct(product); productScheduleRepository.deleteByProduct(product); - saveAdditionalInfo(request.tags(), request.schedules(), request.genderPrices(), product); + saveAdditionalInfo(request.schedules(), request.genderPrices(), product); } private ProductSchedule getSchedule(long scheduleId, Product product) { From 1db5aa9a737489da68103b3ac12659d0f58864d8 Mon Sep 17 00:00:00 2001 From: 0AndWild Date: Sun, 11 May 2025 23:07:41 +0900 Subject: [PATCH 4/6] feat: add getMyOrders API --- .../kr/mayb/controller/OrderController.java | 11 ++++++ .../data/repository/MemberRepository.java | 5 ++- .../mayb/data/repository/OrderRepository.java | 3 ++ .../ProductGenderPriceRepository.java | 4 ++ .../data/repository/ProductRepository.java | 4 ++ .../repository/ProductScheduleRepository.java | 4 ++ src/main/java/kr/mayb/dto/OrderInfo.java | 25 ++++++++++-- src/main/java/kr/mayb/enums/OrderSort.java | 18 +++++++++ src/main/java/kr/mayb/facade/OrderFacade.java | 39 +++++++++++++++++++ .../java/kr/mayb/service/MemberService.java | 10 +++++ .../java/kr/mayb/service/OrderService.java | 9 +++++ .../java/kr/mayb/service/ProductService.java | 31 +++++++++++++-- .../kr/mayb/util/request/PageRequest.java | 4 +- .../util/request/PageRequestResolver.java | 4 +- 14 files changed, 159 insertions(+), 12 deletions(-) create mode 100644 src/main/java/kr/mayb/enums/OrderSort.java diff --git a/src/main/java/kr/mayb/controller/OrderController.java b/src/main/java/kr/mayb/controller/OrderController.java index 98f8629..3868da8 100644 --- a/src/main/java/kr/mayb/controller/OrderController.java +++ b/src/main/java/kr/mayb/controller/OrderController.java @@ -7,10 +7,13 @@ import kr.mayb.facade.OrderFacade; import kr.mayb.security.DenyAll; import kr.mayb.security.PermitAuthenticated; +import kr.mayb.util.request.PageRequest; import kr.mayb.util.response.ApiResponse; +import kr.mayb.util.response.PageResponse; import kr.mayb.util.response.Responses; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @@ -30,4 +33,12 @@ public ResponseEntity> makeOrder(@RequestBody OrderReques OrderInfo response = orderFacade.makeOrder(request); return Responses.ok(response); } + + @Operation(summary = "내 주문 목록 조회") + @PermitAuthenticated + @GetMapping("/orders/me") + public ResponseEntity>> getMyOrders(PageRequest pageRequest) { + PageResponse response = orderFacade.getMyOrders(pageRequest); + return Responses.ok(response); + } } diff --git a/src/main/java/kr/mayb/data/repository/MemberRepository.java b/src/main/java/kr/mayb/data/repository/MemberRepository.java index 5f530e9..dc45fa3 100644 --- a/src/main/java/kr/mayb/data/repository/MemberRepository.java +++ b/src/main/java/kr/mayb/data/repository/MemberRepository.java @@ -4,11 +4,14 @@ import kr.mayb.data.model.Member; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Collection; +import java.util.List; import java.util.Optional; public interface MemberRepository extends JpaRepository { - boolean existsByEmail(String email); Optional findByEmail(String email); + + List findAllByIdIn(Collection memberIds); } diff --git a/src/main/java/kr/mayb/data/repository/OrderRepository.java b/src/main/java/kr/mayb/data/repository/OrderRepository.java index a31454a..2e0a1c5 100644 --- a/src/main/java/kr/mayb/data/repository/OrderRepository.java +++ b/src/main/java/kr/mayb/data/repository/OrderRepository.java @@ -1,7 +1,10 @@ package kr.mayb.data.repository; import kr.mayb.data.model.Order; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; public interface OrderRepository extends JpaRepository { + Page findAllByMemberId(long memberId, Pageable pageable); } diff --git a/src/main/java/kr/mayb/data/repository/ProductGenderPriceRepository.java b/src/main/java/kr/mayb/data/repository/ProductGenderPriceRepository.java index 2d59874..9dcba57 100644 --- a/src/main/java/kr/mayb/data/repository/ProductGenderPriceRepository.java +++ b/src/main/java/kr/mayb/data/repository/ProductGenderPriceRepository.java @@ -4,10 +4,14 @@ import kr.mayb.data.model.ProductGenderPrice; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Collection; +import java.util.List; import java.util.Optional; public interface ProductGenderPriceRepository extends JpaRepository { void deleteByProduct(Product product); Optional findByIdAndProduct(long id, Product product); + + List findAllByIdIn(Collection priceIds); } diff --git a/src/main/java/kr/mayb/data/repository/ProductRepository.java b/src/main/java/kr/mayb/data/repository/ProductRepository.java index e297cf2..40e86cd 100644 --- a/src/main/java/kr/mayb/data/repository/ProductRepository.java +++ b/src/main/java/kr/mayb/data/repository/ProductRepository.java @@ -3,5 +3,9 @@ import kr.mayb.data.model.Product; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Collection; +import java.util.List; + public interface ProductRepository extends JpaRepository { + List findAllByIdIn(Collection productIds); } diff --git a/src/main/java/kr/mayb/data/repository/ProductScheduleRepository.java b/src/main/java/kr/mayb/data/repository/ProductScheduleRepository.java index a1a6c26..3c27077 100644 --- a/src/main/java/kr/mayb/data/repository/ProductScheduleRepository.java +++ b/src/main/java/kr/mayb/data/repository/ProductScheduleRepository.java @@ -4,10 +4,14 @@ import kr.mayb.data.model.ProductSchedule; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Collection; +import java.util.List; import java.util.Optional; public interface ProductScheduleRepository extends JpaRepository { void deleteByProduct(Product product); Optional findByIdAndProduct(long id, Product product); + + List findAllByIdIn(Collection scheduleIds); } diff --git a/src/main/java/kr/mayb/dto/OrderInfo.java b/src/main/java/kr/mayb/dto/OrderInfo.java index b775566..4d9676c 100644 --- a/src/main/java/kr/mayb/dto/OrderInfo.java +++ b/src/main/java/kr/mayb/dto/OrderInfo.java @@ -1,11 +1,15 @@ package kr.mayb.dto; import kr.mayb.data.model.Order; +import kr.mayb.data.model.Product; +import kr.mayb.data.model.ProductGenderPrice; +import kr.mayb.data.model.ProductSchedule; import kr.mayb.enums.PaymentMethod; import kr.mayb.enums.PaymentStatus; import java.time.LocalDateTime; import java.time.OffsetDateTime; +import java.util.Optional; public record OrderInfo( long orderId, @@ -26,16 +30,29 @@ public record OrderInfo( OffsetDateTime createdAt ) { public static OrderInfo of(Order order, OrderedProductItem productItem, String customerName) { + String productName = Optional.ofNullable(productItem.product()) + .map(Product::getName) + .orElse(null); + String productProfileImageUrl = Optional.ofNullable(productItem.product()) + .map(Product::getProfileImageUrl) + .orElse(null); + String gender = Optional.of(productItem.genderPrice()) + .map(ProductGenderPrice::getGender) + .orElse(null); + LocalDateTime scheduledAt = Optional.ofNullable(productItem.schedule()) + .map(ProductSchedule::getTimeSlot) + .orElse(null); + return new OrderInfo( order.getId(), order.getTotalPrice(), order.getPaymentMethod(), order.getPaymentStatus(), order.isHasReviewed(), - productItem.product().getName(), - productItem.product().getProfileImageUrl(), - productItem.genderPrice().getGender(), - productItem.schedule().getTimeSlot(), + productName, + productProfileImageUrl, + gender, + scheduledAt, customerName, order.getCreatedAt() ); diff --git a/src/main/java/kr/mayb/enums/OrderSort.java b/src/main/java/kr/mayb/enums/OrderSort.java new file mode 100644 index 0000000..82339a9 --- /dev/null +++ b/src/main/java/kr/mayb/enums/OrderSort.java @@ -0,0 +1,18 @@ +package kr.mayb.enums; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Sort; + +@Getter +@RequiredArgsConstructor +public enum OrderSort { + NEWEST_FIRST("createdAt"), + ; + + private final String value; + + public Sort toSortOption() { + return Sort.by(Sort.Direction.DESC, NEWEST_FIRST.getValue()); + } +} diff --git a/src/main/java/kr/mayb/facade/OrderFacade.java b/src/main/java/kr/mayb/facade/OrderFacade.java index 8aebd6f..c73bdac 100644 --- a/src/main/java/kr/mayb/facade/OrderFacade.java +++ b/src/main/java/kr/mayb/facade/OrderFacade.java @@ -10,9 +10,19 @@ import kr.mayb.service.OrderService; import kr.mayb.service.ProductService; import kr.mayb.util.ContextUtils; +import kr.mayb.util.request.PageRequest; +import kr.mayb.util.response.PageResponse; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; import org.springframework.stereotype.Component; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + @Component @RequiredArgsConstructor public class OrderFacade { @@ -20,6 +30,8 @@ public class OrderFacade { private final OrderService orderService; private final ProductService productService; + private static final String DEFAULT_UNKNOWN_MEMBER_NAME = "탈퇴하거나 찾을 수 없는 회원입니다."; + public OrderInfo makeOrder(OrderRequest request) { MemberDto member = ContextUtils.loadMember(); OrderedProductItem productItem = productService.findOrderedProductItem(request.productId(), request.priceId(), request.scheduleId()); @@ -28,6 +40,33 @@ public OrderInfo makeOrder(OrderRequest request) { return convertToOrderInfo(saved); } + public PageResponse getMyOrders(PageRequest pageRequest) { + MemberDto member = ContextUtils.loadMember(); + Page orders = orderService.getMyOrders(member.getMemberId(), pageRequest); + + List converted = convertToOrderInfos(orders.getContent()); + return PageResponse.of(new PageImpl<>(converted, orders.getPageable(), orders.getTotalElements())); + } + + private List convertToOrderInfos(List orders) { + Map memberMap = memberService.findAllByIdIn(orders.stream().map(Order::getMemberId).collect(Collectors.toSet())); + Set productIds = orders.stream().map(Order::getProductId).collect(Collectors.toSet()); + Set priceIds = orders.stream().map(Order::getProductGenderPriceId).collect(Collectors.toSet()); + Set scheduleIds = orders.stream().map(Order::getProductScheduleId).collect(Collectors.toSet()); + + var orderedProductItemMap = productService.findOrderedProductItems(productIds, priceIds, scheduleIds, orders); + return orders.stream() + .map(order -> { + String customerName = Optional.ofNullable(memberMap.get(order.getMemberId())) + .map(Member::getName) + .orElse(DEFAULT_UNKNOWN_MEMBER_NAME); + OrderedProductItem productItem = orderedProductItemMap.get(order.getId()); + + return OrderInfo.of(order, productItem, customerName); + }) + .toList(); + } + private OrderInfo convertToOrderInfo(Order saved) { Member member = memberService.getMember(saved.getMemberId()); OrderedProductItem productItem = productService.findOrderedProductItem(saved.getProductId(), saved.getProductGenderPriceId(), saved.getProductScheduleId()); diff --git a/src/main/java/kr/mayb/service/MemberService.java b/src/main/java/kr/mayb/service/MemberService.java index f1b58b0..13cdad2 100644 --- a/src/main/java/kr/mayb/service/MemberService.java +++ b/src/main/java/kr/mayb/service/MemberService.java @@ -17,7 +17,11 @@ import org.springframework.stereotype.Service; import java.util.Collections; +import java.util.Map; import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -83,6 +87,12 @@ public MemberDto updateMember(long memberId, MemberUpdateRequest request) { return convertToMemberDto(updated); } + public Map findAllByIdIn(Set memberIds) { + return memberRepository.findAllByIdIn(memberIds) + .stream() + .collect(Collectors.toMap(Member::getId, Function.identity())); + } + private MemberDto convertToMemberDto(Member member) { String contact = aesgcmEncoder.decrypt(member.getContact()); return MemberDto.of(member, contact); diff --git a/src/main/java/kr/mayb/service/OrderService.java b/src/main/java/kr/mayb/service/OrderService.java index 80e3394..f893892 100644 --- a/src/main/java/kr/mayb/service/OrderService.java +++ b/src/main/java/kr/mayb/service/OrderService.java @@ -4,9 +4,13 @@ import kr.mayb.data.model.Order; import kr.mayb.data.repository.OrderRepository; import kr.mayb.dto.OrderedProductItem; +import kr.mayb.enums.OrderSort; import kr.mayb.enums.PaymentMethod; import kr.mayb.enums.PaymentStatus; +import kr.mayb.util.request.PageRequest; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @Service @@ -29,4 +33,9 @@ public Order makeOrder(OrderedProductItem productItem, PaymentMethod paymentMeth return orderRepository.save(order); } + + public Page getMyOrders(long memberId, PageRequest pageRequest) { + Pageable pageable = pageRequest.toPageable(OrderSort.NEWEST_FIRST.toSortOption()); + return orderRepository.findAllByMemberId(memberId, pageable); + } } diff --git a/src/main/java/kr/mayb/service/ProductService.java b/src/main/java/kr/mayb/service/ProductService.java index 0e045d7..5f02d3c 100644 --- a/src/main/java/kr/mayb/service/ProductService.java +++ b/src/main/java/kr/mayb/service/ProductService.java @@ -1,6 +1,7 @@ package kr.mayb.service; import jakarta.transaction.Transactional; +import kr.mayb.data.model.Order; import kr.mayb.data.model.Product; import kr.mayb.data.model.ProductGenderPrice; import kr.mayb.data.model.ProductSchedule; @@ -12,13 +13,13 @@ import kr.mayb.enums.ProductStatus; import kr.mayb.error.ResourceNotFoundException; import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.tuple.Pair; import org.springframework.security.access.AccessDeniedException; import org.springframework.stereotype.Service; import java.time.LocalDateTime; -import java.util.List; -import java.util.Objects; -import java.util.Optional; +import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -153,6 +154,30 @@ public OrderedProductItem findOrderedProductItem(long productId, long priceId, l return OrderedProductItem.of(product, genderPrice, schedule); } + public Map findOrderedProductItems(Set productIds, Set priceIds, Set scheduleIds, List orders) { + Map productMap = productRepository.findAllByIdIn(productIds) + .stream() + .collect(Collectors.toMap(Product::getId, Function.identity())); + Map genderPriceMap = productGenderPriceRepository.findAllByIdIn(priceIds) + .stream() + .collect(Collectors.toMap(ProductGenderPrice::getId, Function.identity())); + Map scheduleMap = productScheduleRepository.findAllByIdIn(scheduleIds) + .stream() + .collect(Collectors.toMap(ProductSchedule::getId, Function.identity())); + + return orders + .stream() + .map(order -> { + Product product = productMap.get(order.getProductId()); + ProductGenderPrice genderPrice = genderPriceMap.get(order.getProductGenderPriceId()); + ProductSchedule schedule = scheduleMap.get(order.getProductScheduleId()); + + OrderedProductItem orderedProductItem = OrderedProductItem.of(product, genderPrice, schedule); + return Pair.of(order.getId(), orderedProductItem); + }) + .collect(Collectors.toMap(Pair::getLeft, Pair::getRight)); + } + private void updateProductImage(Optional profileUrl, Optional detailUrl, Product product) { profileUrl.ifPresent(url -> { imageService.delete(product.getProfileImageUrl(), GcsBucketPath.PRODUCT_PROFILE); diff --git a/src/main/java/kr/mayb/util/request/PageRequest.java b/src/main/java/kr/mayb/util/request/PageRequest.java index a0ef9bf..db9b283 100644 --- a/src/main/java/kr/mayb/util/request/PageRequest.java +++ b/src/main/java/kr/mayb/util/request/PageRequest.java @@ -21,11 +21,11 @@ public class PageRequest { private final String sort; public static PageRequest getDefault() { - return new PageRequest(0, 10, null); + return new PageRequest(0, 5, null); } public static Pageable defaultPageable() { - return defaultPageable(10); + return defaultPageable(5); } public static Pageable defaultPageable(int size) { diff --git a/src/main/java/kr/mayb/util/request/PageRequestResolver.java b/src/main/java/kr/mayb/util/request/PageRequestResolver.java index cb73761..f5f6742 100644 --- a/src/main/java/kr/mayb/util/request/PageRequestResolver.java +++ b/src/main/java/kr/mayb/util/request/PageRequestResolver.java @@ -9,7 +9,7 @@ public class PageRequestResolver implements HandlerMethodArgumentResolver { - private static final int DEFAULT_PAGE_SIZE = 10; + private static final int DEFAULT_PAGE_SIZE = 5; private static final int DEFAULT_PAGE_NUMBER = 0; private static final int MAX_PAGE_SIZE = 100; private static final int MAX_ELEMENT_SIZE = 5000; @@ -35,7 +35,7 @@ public kr.mayb.util.request.PageRequest resolveArgument(MethodParameter paramete private int parseAndApplyBoundaries(String parameter, int defaultValue, int upper) { try { int parsed = Integer.parseInt(parameter); - return parsed < 0 ? defaultValue : parsed > upper ? upper : parsed; + return parsed < 0 ? defaultValue : Math.min(parsed, upper); } catch (NumberFormatException e) { return defaultValue; } From 76b0a6b13194ce2ef684aa4aeb753677327f81fe Mon Sep 17 00:00:00 2001 From: 0AndWild Date: Mon, 12 May 2025 00:35:18 +0900 Subject: [PATCH 5/6] feat: add getOrders API for admin --- .../kr/mayb/controller/OrderController.java | 22 +++++++++++++++---- .../mayb/data/repository/OrderRepository.java | 3 ++- .../specification/OrderSpecification.java | 18 +++++++++++++++ src/main/java/kr/mayb/dto/ProductSimple.java | 12 ++++++++++ .../java/kr/mayb/enums/PaymentStatus.java | 1 + src/main/java/kr/mayb/facade/OrderFacade.java | 21 ++++++++++++++---- .../java/kr/mayb/service/OrderService.java | 11 ++++++++++ .../java/kr/mayb/service/ProductService.java | 4 ++++ 8 files changed, 83 insertions(+), 9 deletions(-) create mode 100644 src/main/java/kr/mayb/data/repository/specification/OrderSpecification.java create mode 100644 src/main/java/kr/mayb/dto/ProductSimple.java diff --git a/src/main/java/kr/mayb/controller/OrderController.java b/src/main/java/kr/mayb/controller/OrderController.java index 3868da8..1240052 100644 --- a/src/main/java/kr/mayb/controller/OrderController.java +++ b/src/main/java/kr/mayb/controller/OrderController.java @@ -4,8 +4,11 @@ import io.swagger.v3.oas.annotations.tags.Tag; import kr.mayb.dto.OrderInfo; import kr.mayb.dto.OrderRequest; +import kr.mayb.dto.ProductSimple; +import kr.mayb.enums.PaymentStatus; import kr.mayb.facade.OrderFacade; import kr.mayb.security.DenyAll; +import kr.mayb.security.PermitAdmin; import kr.mayb.security.PermitAuthenticated; import kr.mayb.util.request.PageRequest; import kr.mayb.util.response.ApiResponse; @@ -13,10 +16,9 @@ import kr.mayb.util.response.Responses; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import java.util.List; @Tag(name = "Order", description = "주문 관련 API") @DenyAll @@ -41,4 +43,16 @@ public ResponseEntity>> getMyOrders(Pa PageResponse response = orderFacade.getMyOrders(pageRequest); return Responses.ok(response); } + + @Operation(summary = "관리자 전체 주문 목록 조회") + @PermitAdmin + @GetMapping("/orders") + public ResponseEntity>>> getOrders( + @RequestParam(value = "pid", required = false) Long productId, + @RequestParam(value = "p_status", required = false) PaymentStatus paymentStatus, + PageRequest pageRequest + ) { + var response = orderFacade.getOrders(productId, paymentStatus, pageRequest); + return Responses.ok(response); + } } diff --git a/src/main/java/kr/mayb/data/repository/OrderRepository.java b/src/main/java/kr/mayb/data/repository/OrderRepository.java index 2e0a1c5..0200480 100644 --- a/src/main/java/kr/mayb/data/repository/OrderRepository.java +++ b/src/main/java/kr/mayb/data/repository/OrderRepository.java @@ -4,7 +4,8 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; -public interface OrderRepository extends JpaRepository { +public interface OrderRepository extends JpaRepository, JpaSpecificationExecutor { Page findAllByMemberId(long memberId, Pageable pageable); } diff --git a/src/main/java/kr/mayb/data/repository/specification/OrderSpecification.java b/src/main/java/kr/mayb/data/repository/specification/OrderSpecification.java new file mode 100644 index 0000000..0c2cfea --- /dev/null +++ b/src/main/java/kr/mayb/data/repository/specification/OrderSpecification.java @@ -0,0 +1,18 @@ +package kr.mayb.data.repository.specification; + +import kr.mayb.data.model.Order; +import kr.mayb.enums.PaymentStatus; +import org.springframework.data.jpa.domain.Specification; + +public class OrderSpecification { + + public static Specification withProductId(Long productId) { + return (root, query, criteriaBuilder) -> + productId != null ? criteriaBuilder.equal(root.get("productId"), productId) : criteriaBuilder.conjunction(); + } + + public static Specification withPaymentStatus(PaymentStatus paymentStatus) { + return (root, query, criteriaBuilder) -> + paymentStatus != null ? criteriaBuilder.equal(root.get("paymentStatus"), paymentStatus) : criteriaBuilder.conjunction(); + } +} diff --git a/src/main/java/kr/mayb/dto/ProductSimple.java b/src/main/java/kr/mayb/dto/ProductSimple.java new file mode 100644 index 0000000..602af64 --- /dev/null +++ b/src/main/java/kr/mayb/dto/ProductSimple.java @@ -0,0 +1,12 @@ +package kr.mayb.dto; + +import kr.mayb.data.model.Product; + +public record ProductSimple( + long productId, + String name +) { + public static ProductSimple of(Product product) { + return new ProductSimple(product.getId(), product.getName()); + } +} diff --git a/src/main/java/kr/mayb/enums/PaymentStatus.java b/src/main/java/kr/mayb/enums/PaymentStatus.java index 9f994f4..c0b7c86 100644 --- a/src/main/java/kr/mayb/enums/PaymentStatus.java +++ b/src/main/java/kr/mayb/enums/PaymentStatus.java @@ -4,4 +4,5 @@ public enum PaymentStatus { PENDING, COMPLETED, REFUNDED, + ; } diff --git a/src/main/java/kr/mayb/facade/OrderFacade.java b/src/main/java/kr/mayb/facade/OrderFacade.java index c73bdac..dde9569 100644 --- a/src/main/java/kr/mayb/facade/OrderFacade.java +++ b/src/main/java/kr/mayb/facade/OrderFacade.java @@ -2,10 +2,8 @@ import kr.mayb.data.model.Member; import kr.mayb.data.model.Order; -import kr.mayb.dto.MemberDto; -import kr.mayb.dto.OrderInfo; -import kr.mayb.dto.OrderRequest; -import kr.mayb.dto.OrderedProductItem; +import kr.mayb.dto.*; +import kr.mayb.enums.PaymentStatus; import kr.mayb.service.MemberService; import kr.mayb.service.OrderService; import kr.mayb.service.ProductService; @@ -48,6 +46,21 @@ public PageResponse getMyOrders(PageRequest pageRequest) { return PageResponse.of(new PageImpl<>(converted, orders.getPageable(), orders.getTotalElements())); } + public PageResponse> getOrders(Long productId, PaymentStatus paymentStatus, PageRequest pageRequest) { + Page orders = orderService.getOrders(productId, paymentStatus, pageRequest); + + List converted = convertToOrderInfos(orders.getContent()); + PageImpl orderInfoPage = new PageImpl<>(converted, orders.getPageable(), orders.getTotalElements()); + return PageResponse.of(orderInfoPage, getProductMetaData()); + } + + private List getProductMetaData() { + return productService.findAll() + .stream() + .map(ProductSimple::of) + .toList(); + } + private List convertToOrderInfos(List orders) { Map memberMap = memberService.findAllByIdIn(orders.stream().map(Order::getMemberId).collect(Collectors.toSet())); Set productIds = orders.stream().map(Order::getProductId).collect(Collectors.toSet()); diff --git a/src/main/java/kr/mayb/service/OrderService.java b/src/main/java/kr/mayb/service/OrderService.java index f893892..d7909ec 100644 --- a/src/main/java/kr/mayb/service/OrderService.java +++ b/src/main/java/kr/mayb/service/OrderService.java @@ -3,6 +3,7 @@ import jakarta.transaction.Transactional; import kr.mayb.data.model.Order; import kr.mayb.data.repository.OrderRepository; +import kr.mayb.data.repository.specification.OrderSpecification; import kr.mayb.dto.OrderedProductItem; import kr.mayb.enums.OrderSort; import kr.mayb.enums.PaymentMethod; @@ -11,6 +12,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; @Service @@ -38,4 +40,13 @@ public Page getMyOrders(long memberId, PageRequest pageRequest) { Pageable pageable = pageRequest.toPageable(OrderSort.NEWEST_FIRST.toSortOption()); return orderRepository.findAllByMemberId(memberId, pageable); } + + public Page getOrders(Long productId, PaymentStatus paymentStatus, PageRequest pageRequest) { + Pageable pageable = pageRequest.toPageable(OrderSort.NEWEST_FIRST.toSortOption()); + Specification spec = Specification + .where(OrderSpecification.withProductId(productId)) + .and(OrderSpecification.withPaymentStatus(paymentStatus)); + + return orderRepository.findAll(spec, pageable); + } } diff --git a/src/main/java/kr/mayb/service/ProductService.java b/src/main/java/kr/mayb/service/ProductService.java index 5f02d3c..816c26b 100644 --- a/src/main/java/kr/mayb/service/ProductService.java +++ b/src/main/java/kr/mayb/service/ProductService.java @@ -209,4 +209,8 @@ private Product getProduct(long productId) { return productRepository.findById(productId) .orElseThrow(() -> new ResourceNotFoundException("Product not found: " + productId)); } + + public List findAll() { + return productRepository.findAll(); + } } From 46e4b8323727c3cb5d55e778077ebaba860c2a1f Mon Sep 17 00:00:00 2001 From: 0AndWild Date: Mon, 12 May 2025 01:00:55 +0900 Subject: [PATCH 6/6] feat: add updatePaymentStatus API for admin --- .../kr/mayb/controller/OrderController.java | 19 +++++++++++++++++++ .../mayb/data/repository/OrderRepository.java | 4 ++++ src/main/java/kr/mayb/facade/OrderFacade.java | 5 +++++ .../java/kr/mayb/service/OrderService.java | 11 +++++++++++ 4 files changed, 39 insertions(+) diff --git a/src/main/java/kr/mayb/controller/OrderController.java b/src/main/java/kr/mayb/controller/OrderController.java index 1240052..c8d3245 100644 --- a/src/main/java/kr/mayb/controller/OrderController.java +++ b/src/main/java/kr/mayb/controller/OrderController.java @@ -2,6 +2,8 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import kr.mayb.dto.OrderInfo; import kr.mayb.dto.OrderRequest; import kr.mayb.dto.ProductSimple; @@ -55,4 +57,21 @@ public ResponseEntity>>> var response = orderFacade.getOrders(productId, paymentStatus, pageRequest); return Responses.ok(response); } + + @Operation(summary = "관리자 결제 상태 변경") + @PermitAdmin + @PatchMapping("orders/{orderId}/members/{memberId}/payment-status") + public ResponseEntity> updatePaymentStatus(@PathVariable long orderId, + @PathVariable long memberId, + @RequestBody @Valid OrderController.PaymentStatusUpdateRequest request) { + OrderInfo response = orderFacade.updatePaymentStatus(orderId, memberId, request.status()); + return Responses.ok(response); + + } + + private record PaymentStatusUpdateRequest( + @NotNull + PaymentStatus status + ) { + } } diff --git a/src/main/java/kr/mayb/data/repository/OrderRepository.java b/src/main/java/kr/mayb/data/repository/OrderRepository.java index 0200480..cacf79e 100644 --- a/src/main/java/kr/mayb/data/repository/OrderRepository.java +++ b/src/main/java/kr/mayb/data/repository/OrderRepository.java @@ -6,6 +6,10 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import java.util.Optional; + public interface OrderRepository extends JpaRepository, JpaSpecificationExecutor { Page findAllByMemberId(long memberId, Pageable pageable); + + Optional findByIdAndMemberId(long orderId, long memberId); } diff --git a/src/main/java/kr/mayb/facade/OrderFacade.java b/src/main/java/kr/mayb/facade/OrderFacade.java index dde9569..3159610 100644 --- a/src/main/java/kr/mayb/facade/OrderFacade.java +++ b/src/main/java/kr/mayb/facade/OrderFacade.java @@ -54,6 +54,11 @@ public PageResponse> getOrders(Long productId, Pa return PageResponse.of(orderInfoPage, getProductMetaData()); } + public OrderInfo updatePaymentStatus(long orderId, long memberId, PaymentStatus status) { + Order updated = orderService.updatePaymentStatus(orderId, memberId, status); + return convertToOrderInfo(updated); + } + private List getProductMetaData() { return productService.findAll() .stream() diff --git a/src/main/java/kr/mayb/service/OrderService.java b/src/main/java/kr/mayb/service/OrderService.java index d7909ec..526f4a7 100644 --- a/src/main/java/kr/mayb/service/OrderService.java +++ b/src/main/java/kr/mayb/service/OrderService.java @@ -8,6 +8,7 @@ import kr.mayb.enums.OrderSort; import kr.mayb.enums.PaymentMethod; import kr.mayb.enums.PaymentStatus; +import kr.mayb.error.ResourceNotFoundException; import kr.mayb.util.request.PageRequest; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; @@ -49,4 +50,14 @@ public Page getOrders(Long productId, PaymentStatus paymentStatus, PageRe return orderRepository.findAll(spec, pageable); } + + @Transactional + public Order updatePaymentStatus(long orderId, long memberId, PaymentStatus paymentStatus) { + Order order = orderRepository.findByIdAndMemberId(orderId, memberId) + .orElseThrow(() -> new ResourceNotFoundException("There is no Order with orderId and memberId." + orderId + ", " + memberId)); + + order.setPaymentStatus(paymentStatus); + + return orderRepository.save(order); + } }