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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -15,13 +17,17 @@ public class ActivityResponseDto {

public ActivityResponseDto(
Long id,
String title,
String subtitle,
String description,
int point,
int sortOrder,
boolean isTodayActivity,
boolean isCustom
) {
this.id = id;
this.title = title;
this.subtitle = subtitle;
this.description = description;
this.point = point;
this.sortOrder = sortOrder;
Expand All @@ -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)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -26,12 +29,13 @@ public List<ActivityResponseDto> getAvailableActivities(
List<Long> doneActivityIds = historyService.getTodayActivityIdsByUser(userId);

// 2. 활동 전체 중 오늘 이미 한 활동 이력 체크
return activityService.getActivitiesByCategoryWithTodayFlags(categoryId, doneActivityIds);
return activityService.getActivitiesByCategoryWithTodayFlags(
categoryId,
doneActivityIds
);
}

public List<ActivityResponseDto> getAvailableTodayMissionActivities(
Long userId
) {
public List<ActivityResponseDto> getAvailableTodayMissionActivities(Long userId) {
// 1. 오늘의 활동 이력 ID 목록 조회
List<Long> doneActivityIds = historyService.getTodayActivityIdsByUser(userId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ public ActivityService(ActivityRepository activityRepository, UserRepository use
this.categoryRepository = categoryRepository;
}

public List<ActivityResponseDto> getActivitiesByCategoryWithTodayFlags(Long categoryId, List<Long> todayActivityIds) {
public List<ActivityResponseDto> getActivitiesByCategoryWithTodayFlags(
Long categoryId,
List<Long> todayActivityIds
) {
return activityRepository.findByCategoryIdAndIsDisplayedTrueOrderBySortOrderAsc(categoryId).stream()
.map(activity -> toResponseDto(activity, todayActivityIds.contains(activity.getId())))
.collect(Collectors.toList());
Expand All @@ -44,12 +47,21 @@ public List<ActivityResponseDto> getTodayMissionActivitiesWithTodayFlags(List<Lo
public ActivityResponseDto getActivity(Long activityId) {
return activityRepository.findById(activityId)
.map(this::toResponseDto)
.orElse(null);
.orElseThrow(() -> 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));
Expand All @@ -69,16 +81,23 @@ 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(),
activity.getIsCustom()
);
}

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(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,4 @@ public Response<Integer> getUserPoint(@AuthUser Long userId) {
return Response.ok(totalPoint);
}

@Operation(summary = "포인트 사용 API", description = "보유한 포인트를 사용합니다.")
@PostMapping("/my/product")
public Response<Void> usingPoint(@AuthUser Long userId, @RequestBody PointRequestDTO.buyProductReq req) {
pointService.usingPoint(userId, req);
return Response.ok();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
@Entity
@Getter
@Table(name = "Point")
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Point extends BaseEntity {

@Id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

}
Original file line number Diff line number Diff line change
@@ -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<List<ProductResponseDto>> getAvailableProducts() {
return Response.ok(productService.getAvailableProducts());
}

}
Original file line number Diff line number Diff line change
@@ -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;
}

}
Original file line number Diff line number Diff line change
@@ -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
) {}
Original file line number Diff line number Diff line change
@@ -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()
);
}
}
Original file line number Diff line number Diff line change
@@ -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<Product, Long> { }
Original file line number Diff line number Diff line change
@@ -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<ProductResponseDto> getAvailableProducts() {
return productRepository.findAll()
.stream()
.map(Product::toResponseDto)
.toList();
}

}
Loading