diff --git a/src/main/java/com/example/hackathon/domain/activity/dto/ActivityResponseDto.java b/src/main/java/com/example/hackathon/domain/activity/dto/ActivityResponseDto.java index 727cd86..a1013e4 100644 --- a/src/main/java/com/example/hackathon/domain/activity/dto/ActivityResponseDto.java +++ b/src/main/java/com/example/hackathon/domain/activity/dto/ActivityResponseDto.java @@ -6,6 +6,8 @@ public class ActivityResponseDto { private Long id; + private String title; + private String subtitle; private String description; private int point; private int sortOrder; @@ -15,6 +17,8 @@ public class ActivityResponseDto { public ActivityResponseDto( Long id, + String title, + String subtitle, String description, int point, int sortOrder, @@ -22,6 +26,8 @@ public ActivityResponseDto( boolean isCustom ) { this.id = id; + this.title = title; + this.subtitle = subtitle; this.description = description; this.point = point; this.sortOrder = sortOrder; @@ -31,17 +37,20 @@ public ActivityResponseDto( public ActivityResponseDto( Long id, + String title, + String subtitle, String description, int point, int sortOrder, boolean isCustom ) { this.id = id; + this.title = title; + this.subtitle = subtitle; this.description = description; this.point = point; this.sortOrder = sortOrder; this.isCustom = isCustom; } - // Getter 생략 가능 (Lombok 사용 시 @Getter) } diff --git a/src/main/java/com/example/hackathon/domain/activity/entity/Activity.java b/src/main/java/com/example/hackathon/domain/activity/entity/Activity.java index f369a39..a29d08a 100644 --- a/src/main/java/com/example/hackathon/domain/activity/entity/Activity.java +++ b/src/main/java/com/example/hackathon/domain/activity/entity/Activity.java @@ -25,6 +25,9 @@ public class Activity extends BaseEntity { @Column(name = "TITLE", nullable = false) private String title; + @Column(name = "SUBTITLE", nullable = false) + private String subtitle; + @Column(name = "DESCRIPTION", nullable = false, length = 30) private String description; @@ -36,7 +39,6 @@ public class Activity extends BaseEntity { @Column(name = "SORT_ORDER", nullable = false) private Integer sortOrder = 1; - @Enumerated(EnumType.STRING) // enum을 문자열로 저장 @Column(name="CATEGORY_TYPE") private RepeatCycle repeatCycle; diff --git a/src/main/java/com/example/hackathon/domain/activity/facade/ActivityParticipationFacade.java b/src/main/java/com/example/hackathon/domain/activity/facade/ActivityParticipationFacade.java index 4af0a7b..0f232a2 100644 --- a/src/main/java/com/example/hackathon/domain/activity/facade/ActivityParticipationFacade.java +++ b/src/main/java/com/example/hackathon/domain/activity/facade/ActivityParticipationFacade.java @@ -13,7 +13,10 @@ public class ActivityParticipationFacade { private final ActivityService activityService; private final ActivityHistoryService historyService; - public ActivityParticipationFacade(ActivityService activityService, ActivityHistoryService historyService) { + public ActivityParticipationFacade( + ActivityService activityService, + ActivityHistoryService historyService + ) { this.activityService = activityService; this.historyService = historyService; } @@ -26,12 +29,13 @@ public List getAvailableActivities( List doneActivityIds = historyService.getTodayActivityIdsByUser(userId); // 2. 활동 전체 중 오늘 이미 한 활동 이력 체크 - return activityService.getActivitiesByCategoryWithTodayFlags(categoryId, doneActivityIds); + return activityService.getActivitiesByCategoryWithTodayFlags( + categoryId, + doneActivityIds + ); } - public List getAvailableTodayMissionActivities( - Long userId - ) { + public List getAvailableTodayMissionActivities(Long userId) { // 1. 오늘의 활동 이력 ID 목록 조회 List doneActivityIds = historyService.getTodayActivityIdsByUser(userId); diff --git a/src/main/java/com/example/hackathon/domain/activity/service/ActivityService.java b/src/main/java/com/example/hackathon/domain/activity/service/ActivityService.java index a244c23..04a24dc 100644 --- a/src/main/java/com/example/hackathon/domain/activity/service/ActivityService.java +++ b/src/main/java/com/example/hackathon/domain/activity/service/ActivityService.java @@ -29,7 +29,10 @@ public ActivityService(ActivityRepository activityRepository, UserRepository use this.categoryRepository = categoryRepository; } - public List getActivitiesByCategoryWithTodayFlags(Long categoryId, List todayActivityIds) { + public List getActivitiesByCategoryWithTodayFlags( + Long categoryId, + List todayActivityIds + ) { return activityRepository.findByCategoryIdAndIsDisplayedTrueOrderBySortOrderAsc(categoryId).stream() .map(activity -> toResponseDto(activity, todayActivityIds.contains(activity.getId()))) .collect(Collectors.toList()); @@ -44,12 +47,21 @@ public List getTodayMissionActivitiesWithTodayFlags(List new BusinessException( + Code.BAD_REQUEST, + "유효하지 않은 활동 ID 입니다.") + ); } - public void addUserActivities(Long userId, ActivityNewRequestDto.AddActivity request) { + public void addUserActivities( + Long userId, + ActivityNewRequestDto.AddActivity request + ) { User user = userRepository.findByKakaoId(userId) - .orElseThrow(() -> new BusinessException(Code.USER_NOT_FOUND, "이미 오늘 참여한 활동입니다.")); + .orElseThrow(() -> new BusinessException( + Code.USER_NOT_FOUND, + "이미 오늘 참여한 활동입니다.") + ); Category category = categoryRepository.findByCategoryType(request.getCategoryType()) .orElseThrow(() -> new BusinessException(Code.CATEGORY_NOT_FOUND)); @@ -69,6 +81,8 @@ public void addUserActivities(Long userId, ActivityNewRequestDto.AddActivity req private ActivityResponseDto toResponseDto(Activity activity) { return new ActivityResponseDto( activity.getId(), + activity.getTitle(), + activity.getSubtitle(), activity.getDescription(), activity.getPoint(), activity.getSortOrder(), @@ -76,9 +90,14 @@ private ActivityResponseDto toResponseDto(Activity activity) { ); } - private ActivityResponseDto toResponseDto(Activity activity, boolean isTodayActivity) { + private ActivityResponseDto toResponseDto( + Activity activity, + boolean isTodayActivity + ) { return new ActivityResponseDto( activity.getId(), + activity.getTitle(), + activity.getSubtitle(), activity.getDescription(), activity.getPoint(), activity.getSortOrder(), diff --git a/src/main/java/com/example/hackathon/domain/activityhistory/facade/ActivityPointGrantFacade.java b/src/main/java/com/example/hackathon/domain/activityhistory/facade/ActivityPointGrantFacade.java index 8646d4c..43dfdd1 100644 --- a/src/main/java/com/example/hackathon/domain/activityhistory/facade/ActivityPointGrantFacade.java +++ b/src/main/java/com/example/hackathon/domain/activityhistory/facade/ActivityPointGrantFacade.java @@ -55,8 +55,7 @@ public void grantParticipationAndPoint( activity.getPoint() ); - // TODO 포인트 발급 연동 -// pointService.grant(user, activity.getPoint()); + pointService.updatePointBalance(userId, activity.getPoint()); } private boolean isAlreadyAttendedToday(ActivityHistoryResponseDto dto) { diff --git a/src/main/java/com/example/hackathon/domain/point/controller/PointController.java b/src/main/java/com/example/hackathon/domain/point/controller/PointController.java index ead576a..b48a2a4 100644 --- a/src/main/java/com/example/hackathon/domain/point/controller/PointController.java +++ b/src/main/java/com/example/hackathon/domain/point/controller/PointController.java @@ -27,10 +27,4 @@ public Response getUserPoint(@AuthUser Long userId) { return Response.ok(totalPoint); } - @Operation(summary = "포인트 사용 API", description = "보유한 포인트를 사용합니다.") - @PostMapping("/my/product") - public Response usingPoint(@AuthUser Long userId, @RequestBody PointRequestDTO.buyProductReq req) { - pointService.usingPoint(userId, req); - return Response.ok(); - } } diff --git a/src/main/java/com/example/hackathon/domain/point/entity/Point.java b/src/main/java/com/example/hackathon/domain/point/entity/Point.java index 85df4d2..c632e82 100644 --- a/src/main/java/com/example/hackathon/domain/point/entity/Point.java +++ b/src/main/java/com/example/hackathon/domain/point/entity/Point.java @@ -10,6 +10,9 @@ @Entity @Getter @Table(name = "Point") +@NoArgsConstructor +@AllArgsConstructor +@Builder public class Point extends BaseEntity { @Id diff --git a/src/main/java/com/example/hackathon/domain/point/service/PointService.java b/src/main/java/com/example/hackathon/domain/point/service/PointService.java index 5c8f612..b5fc585 100644 --- a/src/main/java/com/example/hackathon/domain/point/service/PointService.java +++ b/src/main/java/com/example/hackathon/domain/point/service/PointService.java @@ -29,16 +29,27 @@ public Integer getUserTotalPoint(Long userId) { } @Transactional - public void usingPoint(Long userId, PointRequestDTO.buyProductReq req){ - - Point point = pointRepository.findByUserId(userId) - .orElseThrow(() -> new BusinessException(Code.POINT_NOT_FOUND, "이미 오늘 참여한 활동입니다.")); - - int productPrice = req.getProductType().getPoint(); - int userPoints = point.getTotalPoint(); - - if (userPoints < productPrice) { throw new BusinessException(Code.POINT_NOT_ENOUGH, "이미 오늘 참여한 활동입니다.");} - - point.setTotalPoint(userPoints - productPrice); + public void updatePointBalance(Long userId, int pointDelta) { + + Point userPoint = pointRepository.findByUserId(userId).orElse(null); + + if (userPoint == null) { + if (pointDelta < 0) { + throw new BusinessException(Code.BAD_REQUEST); + } + + pointRepository.save( + Point.builder() + .user(userRepository.findById(userId) + .orElseThrow(() -> new BusinessException(Code.BAD_REQUEST))) + .totalPoint(pointDelta) + .build() + ); + } else { + int userPoints = userPoint.getTotalPoint(); + + userPoint.setTotalPoint(userPoints + pointDelta); + } } + } diff --git a/src/main/java/com/example/hackathon/domain/product/controller/ProductController.java b/src/main/java/com/example/hackathon/domain/product/controller/ProductController.java new file mode 100644 index 0000000..e0d5108 --- /dev/null +++ b/src/main/java/com/example/hackathon/domain/product/controller/ProductController.java @@ -0,0 +1,31 @@ +package com.example.hackathon.domain.product.controller; + +import com.example.hackathon.domain.product.dto.ProductResponseDto; +import com.example.hackathon.domain.product.service.ProductService; +import com.example.hackathon.global.response.Response; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequestMapping("/api/products") +@Validated +public class ProductController { + + private final ProductService productService; + + public ProductController(ProductService productService) { + this.productService = productService; + } + + @Operation(summary = "상품 조회 API", description = "포인트로 구매 가능한 상품을 조회합니다.") + @GetMapping + public Response> getAvailableProducts() { + return Response.ok(productService.getAvailableProducts()); + } + +} diff --git a/src/main/java/com/example/hackathon/domain/product/dto/ProductRequestDto.java b/src/main/java/com/example/hackathon/domain/product/dto/ProductRequestDto.java new file mode 100644 index 0000000..fc583bb --- /dev/null +++ b/src/main/java/com/example/hackathon/domain/product/dto/ProductRequestDto.java @@ -0,0 +1,18 @@ +package com.example.hackathon.domain.product.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +public class ProductRequestDto { + + private Long categoryId; + + public void setCategoryId(Long categoryId) { + this.categoryId = categoryId; + } + +} diff --git a/src/main/java/com/example/hackathon/domain/product/dto/ProductResponseDto.java b/src/main/java/com/example/hackathon/domain/product/dto/ProductResponseDto.java new file mode 100644 index 0000000..b8e4874 --- /dev/null +++ b/src/main/java/com/example/hackathon/domain/product/dto/ProductResponseDto.java @@ -0,0 +1,13 @@ +package com.example.hackathon.domain.product.dto; + +import java.time.LocalDateTime; + +public record ProductResponseDto( + Long id, + String name, + Integer price, + String imgUrl, + Integer maxPurchaseLimit, + Integer stockQty, + LocalDateTime regDt +) {} \ No newline at end of file diff --git a/src/main/java/com/example/hackathon/domain/product/entity/Product.java b/src/main/java/com/example/hackathon/domain/product/entity/Product.java new file mode 100644 index 0000000..efb922d --- /dev/null +++ b/src/main/java/com/example/hackathon/domain/product/entity/Product.java @@ -0,0 +1,55 @@ +package com.example.hackathon.domain.product.entity; + +import com.example.hackathon.domain.product.dto.ProductResponseDto; +import com.example.hackathon.global.BaseEntity; +import jakarta.persistence.*; +import lombok.*; + +@Entity +@Table(name = "PRODUCT") +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +@Builder +public class Product extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "ID", nullable = false) + private Long id; + + @Column(name = "NAME", nullable = false, length = 50) + private String name; + + @Column(name = "PRICE", nullable = false) + private Integer price; + + @Column(name = "IMG_URL", length = 500) + private String imgUrl; + + @Builder.Default + @Column(name = "MAX_PURCHASE_LIMIT", nullable = false) + private Integer maxPurchaseLimit = 1; + + @Builder.Default + @Column(name = "STOCK_QTY", nullable = false) + private Integer stockQty = 0; + + @Column(name = "REG_ID", nullable = false, length = 50) + private String regId; + + @Column(name = "UPD_ID", length = 50) + private String updId; + + public ProductResponseDto toResponseDto() { + return new ProductResponseDto( + this.id, + this.name, + this.price, + this.imgUrl, + this.maxPurchaseLimit, + this.stockQty, + this.getCreatedAt() + ); + } +} diff --git a/src/main/java/com/example/hackathon/domain/product/repository/ProductRepository.java b/src/main/java/com/example/hackathon/domain/product/repository/ProductRepository.java new file mode 100644 index 0000000..a5cd4fd --- /dev/null +++ b/src/main/java/com/example/hackathon/domain/product/repository/ProductRepository.java @@ -0,0 +1,9 @@ +package com.example.hackathon.domain.product.repository; + + +import com.example.hackathon.domain.product.entity.Product; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface ProductRepository extends JpaRepository { } diff --git a/src/main/java/com/example/hackathon/domain/product/service/ProductService.java b/src/main/java/com/example/hackathon/domain/product/service/ProductService.java new file mode 100644 index 0000000..8d95b14 --- /dev/null +++ b/src/main/java/com/example/hackathon/domain/product/service/ProductService.java @@ -0,0 +1,35 @@ +package com.example.hackathon.domain.product.service; + + +import com.example.hackathon.domain.product.dto.ProductResponseDto; +import com.example.hackathon.domain.product.entity.Product; +import com.example.hackathon.domain.product.repository.ProductRepository; +import com.example.hackathon.global.exception.BusinessException; +import com.example.hackathon.global.response.Code; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class ProductService { + + private final ProductRepository productRepository; + + public ProductService(ProductRepository productRepository) { + this.productRepository = productRepository; + } + + public ProductResponseDto getProductInfo(Long id) { + return productRepository.findById(id) + .orElseThrow(() -> new BusinessException(Code.PRODUCT_NOT_FOUND)) + .toResponseDto(); + } + + public List getAvailableProducts() { + return productRepository.findAll() + .stream() + .map(Product::toResponseDto) + .toList(); + } + +} diff --git a/src/main/java/com/example/hackathon/domain/productpurchasehistory/controller/ProductPurchaseHistoryController.java b/src/main/java/com/example/hackathon/domain/productpurchasehistory/controller/ProductPurchaseHistoryController.java new file mode 100644 index 0000000..3d3bcef --- /dev/null +++ b/src/main/java/com/example/hackathon/domain/productpurchasehistory/controller/ProductPurchaseHistoryController.java @@ -0,0 +1,35 @@ +package com.example.hackathon.domain.productpurchasehistory.controller; + +import com.example.hackathon.domain.productpurchasehistory.dto.ProductPurchaseRequestDto; +import com.example.hackathon.domain.productpurchasehistory.facade.ProductPurchaseFacade; +import com.example.hackathon.global.auth.annotation.AuthUser; +import com.example.hackathon.global.response.Response; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/products") +@Validated +public class ProductPurchaseHistoryController { + + private final ProductPurchaseFacade productPurchaseHistoryService; + + public ProductPurchaseHistoryController(ProductPurchaseFacade productPurchaseHistoryService) { + this.productPurchaseHistoryService = productPurchaseHistoryService; + } + + @Operation(summary = "상품 구매 API", description = "현재 고객 정보를 토대로 상품을 구매합니다.") + @PostMapping("/purchase") + public Response purchaseProduct( + @AuthUser Long userId, + @RequestBody ProductPurchaseRequestDto request + ) { + productPurchaseHistoryService.purchase(userId, request); + return Response.ok(); + } + +} diff --git a/src/main/java/com/example/hackathon/domain/productpurchasehistory/dto/ProductPurchaseHistoryResponseDto.java b/src/main/java/com/example/hackathon/domain/productpurchasehistory/dto/ProductPurchaseHistoryResponseDto.java new file mode 100644 index 0000000..be418a8 --- /dev/null +++ b/src/main/java/com/example/hackathon/domain/productpurchasehistory/dto/ProductPurchaseHistoryResponseDto.java @@ -0,0 +1,13 @@ +package com.example.hackathon.domain.productpurchasehistory.dto; + +import java.time.LocalDateTime; + +public record ProductPurchaseHistoryResponseDto( + Long id, + String name, + Integer price, + String imgUrl, + Integer maxPurchaseLimit, + Integer stockQty, + LocalDateTime regDt +) {} \ No newline at end of file diff --git a/src/main/java/com/example/hackathon/domain/productpurchasehistory/dto/ProductPurchaseRequestDto.java b/src/main/java/com/example/hackathon/domain/productpurchasehistory/dto/ProductPurchaseRequestDto.java new file mode 100644 index 0000000..dd7cd9f --- /dev/null +++ b/src/main/java/com/example/hackathon/domain/productpurchasehistory/dto/ProductPurchaseRequestDto.java @@ -0,0 +1,5 @@ +package com.example.hackathon.domain.productpurchasehistory.dto; + +public record ProductPurchaseRequestDto( + Long productId +) {} diff --git a/src/main/java/com/example/hackathon/domain/productpurchasehistory/entity/ProductPurchaseHistory.java b/src/main/java/com/example/hackathon/domain/productpurchasehistory/entity/ProductPurchaseHistory.java new file mode 100644 index 0000000..e8a4854 --- /dev/null +++ b/src/main/java/com/example/hackathon/domain/productpurchasehistory/entity/ProductPurchaseHistory.java @@ -0,0 +1,52 @@ +package com.example.hackathon.domain.productpurchasehistory.entity; + +import jakarta.persistence.*; +import lombok.*; + +import java.time.LocalDateTime; + +@Entity +@Table(name = "PRODUCT_PURCHASE_HISTORY") +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +@Builder +public class ProductPurchaseHistory { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "ID", nullable = false) + private Long id; + + @Column(name = "USER_ID", nullable = false) + private Long userId; + + @Column(name = "PRODUCT_ID", nullable = false) + private Long productId; + + @Column(name = "QUANTITY", nullable = false) + private Integer quantity; + + @Column(name = "PRICE_AT_TIME", nullable = false) + private Integer priceAtTime; + + @Column(name = "TOTAL_PRICE", nullable = false) + private Integer totalPrice; + + @Column(name = "PURCHASE_DT", nullable = false) + private LocalDateTime purchaseDt; + + @Column(name = "REG_DT", nullable = false) + private LocalDateTime regDt; + + @Column(name = "REG_ID", nullable = false, length = 50) + private String regId; + + @Column(name = "UPD_DT", nullable = false) + private LocalDateTime updDt; + + @Column(name = "UPD_ID", length = 50) + private String updId; + + // 필요 시 생성 메서드 등 추가 가능 +} diff --git a/src/main/java/com/example/hackathon/domain/productpurchasehistory/facade/ProductPurchaseFacade.java b/src/main/java/com/example/hackathon/domain/productpurchasehistory/facade/ProductPurchaseFacade.java new file mode 100644 index 0000000..37a5d9a --- /dev/null +++ b/src/main/java/com/example/hackathon/domain/productpurchasehistory/facade/ProductPurchaseFacade.java @@ -0,0 +1,61 @@ +package com.example.hackathon.domain.productpurchasehistory.facade; + + +import com.example.hackathon.domain.point.service.PointService; +import com.example.hackathon.domain.product.dto.ProductResponseDto; +import com.example.hackathon.domain.product.entity.Product; +import com.example.hackathon.domain.product.repository.ProductRepository; +import com.example.hackathon.domain.product.service.ProductService; +import com.example.hackathon.domain.productpurchasehistory.dto.ProductPurchaseRequestDto; +import com.example.hackathon.domain.productpurchasehistory.entity.ProductPurchaseHistory; +import com.example.hackathon.domain.productpurchasehistory.repository.ProductPurchaseHistoryRepository; +import com.example.hackathon.domain.productpurchasehistory.service.ProductPurchaseHistoryService; +import com.example.hackathon.global.exception.BusinessException; +import com.example.hackathon.global.response.Code; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; + +@Component +public class ProductPurchaseFacade { + + private final ProductService productService; + private final ProductPurchaseHistoryService productPurchaseHistoryService; + private final PointService pointService; + + public ProductPurchaseFacade(ProductService productService, ProductPurchaseHistoryService productPurchaseHistoryService, PointService pointService) { + this.productService = productService; + this.productPurchaseHistoryService = productPurchaseHistoryService; + this.pointService = pointService; + } + + /** + * 상품 구매 이력 저장 (포인트 차감 제외) + */ + @Transactional + public void purchase(Long userId, ProductPurchaseRequestDto request) { + ProductResponseDto product = productService.getProductInfo(request.productId()); + + int quantity = 1; + int price = product.price(); + int totalPrice = price * quantity; + + ProductPurchaseHistory history = ProductPurchaseHistory.builder() + .userId(userId) + .productId(product.id()) + .quantity(quantity) + .priceAtTime(price) + .totalPrice(totalPrice) + .purchaseDt(LocalDateTime.now()) + .regDt(LocalDateTime.now()) + .regId(String.valueOf(userId)) + .updDt(LocalDateTime.now()) + .build(); + + productPurchaseHistoryService.purchase(history); + +// pointService.usingPoint(); + } +} diff --git a/src/main/java/com/example/hackathon/domain/productpurchasehistory/repository/ProductPurchaseHistoryRepository.java b/src/main/java/com/example/hackathon/domain/productpurchasehistory/repository/ProductPurchaseHistoryRepository.java new file mode 100644 index 0000000..50b186c --- /dev/null +++ b/src/main/java/com/example/hackathon/domain/productpurchasehistory/repository/ProductPurchaseHistoryRepository.java @@ -0,0 +1,7 @@ +package com.example.hackathon.domain.productpurchasehistory.repository; + + +import com.example.hackathon.domain.productpurchasehistory.entity.ProductPurchaseHistory; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ProductPurchaseHistoryRepository extends JpaRepository { } diff --git a/src/main/java/com/example/hackathon/domain/productpurchasehistory/service/ProductPurchaseHistoryService.java b/src/main/java/com/example/hackathon/domain/productpurchasehistory/service/ProductPurchaseHistoryService.java new file mode 100644 index 0000000..7323f68 --- /dev/null +++ b/src/main/java/com/example/hackathon/domain/productpurchasehistory/service/ProductPurchaseHistoryService.java @@ -0,0 +1,24 @@ +package com.example.hackathon.domain.productpurchasehistory.service; + + +import com.example.hackathon.domain.productpurchasehistory.dto.ProductPurchaseHistoryResponseDto; +import com.example.hackathon.domain.productpurchasehistory.entity.ProductPurchaseHistory; +import com.example.hackathon.domain.productpurchasehistory.repository.ProductPurchaseHistoryRepository; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class ProductPurchaseHistoryService { + + private final ProductPurchaseHistoryRepository productPurchaseHistoryRepository; + + public ProductPurchaseHistoryService(ProductPurchaseHistoryRepository productPurchaseHistoryRepository) { + this.productPurchaseHistoryRepository = productPurchaseHistoryRepository; + } + + public ProductPurchaseHistory purchase(ProductPurchaseHistory productPurchaseHistory) { + return productPurchaseHistoryRepository.save(productPurchaseHistory); + } + +} diff --git a/src/main/java/com/example/hackathon/global/auth/service/KakaoOAuthService.java b/src/main/java/com/example/hackathon/global/auth/service/KakaoOAuthService.java index 903133e..9006d10 100644 --- a/src/main/java/com/example/hackathon/global/auth/service/KakaoOAuthService.java +++ b/src/main/java/com/example/hackathon/global/auth/service/KakaoOAuthService.java @@ -31,11 +31,9 @@ public KakaoOAuthService( public String loginWithKakao(String code) { // 1. 카카오로부터 토큰 발급 TokenResponseDto tokenDto = kakaoOAuthClient.getToken(code); - log.info("tokenDto : {}", tokenDto); // 2. 사용자 정보 조회 KakaoUserInfoDto userInfo = kakaoOAuthClient.getUserInfo(tokenDto.getAccessToken()); - log.info("userInfo : {}", userInfo); // 3. 회원 조회 또는 저장 User user = userRepository.findByKakaoId(userInfo.getId()) diff --git a/src/main/java/com/example/hackathon/global/config/SecurityConfig.java b/src/main/java/com/example/hackathon/global/config/SecurityConfig.java index 5d61658..2787458 100644 --- a/src/main/java/com/example/hackathon/global/config/SecurityConfig.java +++ b/src/main/java/com/example/hackathon/global/config/SecurityConfig.java @@ -34,6 +34,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti // ✅ 경로별 접근 권한 설정 .authorizeHttpRequests(auth -> auth .requestMatchers( + "/swagger-ui/index.html#/**", "/", "/swagger-ui/**", "/swagger-ui.html", diff --git a/src/main/java/com/example/hackathon/global/response/Code.java b/src/main/java/com/example/hackathon/global/response/Code.java index 80fe880..8d0820b 100644 --- a/src/main/java/com/example/hackathon/global/response/Code.java +++ b/src/main/java/com/example/hackathon/global/response/Code.java @@ -21,7 +21,8 @@ public enum Code implements BaseCode { POINT_NOT_FOUND(HttpStatus.NOT_FOUND, "COMMON404", "해당 유저는 포인트가 존재하지 않습니다."), POINT_NOT_ENOUGH(HttpStatus.INTERNAL_SERVER_ERROR, "COMMON500", "보유한 포인트가 충분하지 않습니다."), - CATEGORY_NOT_FOUND(HttpStatus.NOT_FOUND, "COMMON404", "유효한 카테고리가 없습니다.") + CATEGORY_NOT_FOUND(HttpStatus.NOT_FOUND, "COMMON404", "유효한 카테고리가 없습니다."), + PRODUCT_NOT_FOUND(HttpStatus.NOT_FOUND, "COMMON404", "유효한 상품이 없습니다.") ; private final HttpStatus status; diff --git a/src/test/java/com/example/hackathon/domain/activityhistory/service/ActivityHistoryServiceTest.java b/src/test/java/com/example/hackathon/domain/activityhistory/service/ProductPurchaseHistoryHistoryServiceTest.java similarity index 97% rename from src/test/java/com/example/hackathon/domain/activityhistory/service/ActivityHistoryServiceTest.java rename to src/test/java/com/example/hackathon/domain/activityhistory/service/ProductPurchaseHistoryHistoryServiceTest.java index 395ab76..50b2459 100644 --- a/src/test/java/com/example/hackathon/domain/activityhistory/service/ActivityHistoryServiceTest.java +++ b/src/test/java/com/example/hackathon/domain/activityhistory/service/ProductPurchaseHistoryHistoryServiceTest.java @@ -17,7 +17,7 @@ import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) -class ActivityHistoryServiceTest { +class ProductPurchaseHistoryHistoryServiceTest { @Mock private ActivityHistoryRepository activityHistoryRepository; diff --git a/src/test/java/com/example/hackathon/domain/point/service/PointServiceTest.java b/src/test/java/com/example/hackathon/domain/point/service/PointServiceTest.java index 285f2b3..33a995e 100644 --- a/src/test/java/com/example/hackathon/domain/point/service/PointServiceTest.java +++ b/src/test/java/com/example/hackathon/domain/point/service/PointServiceTest.java @@ -74,13 +74,10 @@ void getUserTotalPoint() { @Test void 포인트_사용_성공() { // given - PointRequestDTO.buyProductReq req = new PointRequestDTO.buyProductReq(); - req.builder().productType(ProductType.KEYRING).build(); // 가정: COUPON은 200포인트 필요 - when(pointRepository.findByUserId(userId)).thenReturn(Optional.of(mockPoint)); // when - pointService.usingPoint(userId, req); + pointService.updatePointBalance(userId, 200); // then assertThat(mockPoint.getTotalPoint()).isEqualTo(300); @@ -89,27 +86,11 @@ void getUserTotalPoint() { @Test void 포인트_부족_예외() { // given - PointRequestDTO.buyProductReq req = new PointRequestDTO.buyProductReq(); - req.builder().productType(ProductType.KEYRING); // 가정: GIFT는 1000포인트 필요 - when(pointRepository.findByUserId(userId)).thenReturn(Optional.of(mockPoint)); // expect - assertThatThrownBy(() -> pointService.usingPoint(userId, req)) + assertThatThrownBy(() -> pointService.updatePointBalance(userId, 1000)) .isInstanceOf(BusinessException.class) .hasMessageContaining(Code.POINT_NOT_ENOUGH.getMessage()); } - - @Test - void 포인트_엔티티_없음_예외() { - // given - PointRequestDTO.buyProductReq req = new PointRequestDTO.buyProductReq(); - - when(pointRepository.findByUserId(userId)).thenReturn(Optional.empty()); - - // expect - assertThatThrownBy(() -> pointService.usingPoint(userId, req)) - .isInstanceOf(BusinessException.class) - .hasMessageContaining(Code.POINT_NOT_FOUND.getMessage()); - } }