Skip to content

Commit 8f335b9

Browse files
authored
Merge pull request #133 from swyp-app-team-4/feat#129-point-event
Feat#129 이벤트 응모 테이블 추가했습니다.
2 parents be43442 + d9aace3 commit 8f335b9

10 files changed

Lines changed: 271 additions & 31 deletions

File tree

src/main/java/boombimapi/domain/member/domain/entity/Member.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import boombimapi.domain.congestion.entity.MemberCongestion;
77
import boombimapi.domain.favorite.entity.Favorite;
88
import boombimapi.domain.oauth2.domain.entity.SocialProvider;
9+
import boombimapi.domain.point.domain.entity.EventCampaign;
910
import boombimapi.domain.point.domain.entity.Point;
1011
import boombimapi.domain.point.domain.entity.PointHistory;
1112
import boombimapi.domain.search.domain.entity.Search;
@@ -78,6 +79,9 @@ public class Member {
7879
@OneToOne(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true)
7980
private PointHistory pointHistory;
8081

82+
// 11) 이벤트 응모
83+
@OneToOne(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true)
84+
private EventCampaign eventCampaign;
8185

8286

8387
@Column(nullable = false)

src/main/java/boombimapi/domain/member/presentation/controller/MemberController.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public class MemberController {
3838

3939
@Operation(summary = "닉네임 수정 API", description = "닉네임을 수정합니다.")
4040
@ApiResponses(value = {
41-
@ApiResponse(responseCode = "200", description = "성공"),
41+
@ApiResponse(responseCode = "200", description = "닉네임 수정 성공"),
4242
@ApiResponse(responseCode = "404", description = "유저 존재하지 않음")
4343
})
4444
@PatchMapping("/name")
@@ -66,7 +66,7 @@ public ResponseEntity<GetMemberResV1> getMember(@AuthenticationPrincipal String
6666

6767
@Operation(summary = "회원 탈퇴 API", description = "회원을 탈퇴합니다.")
6868
@ApiResponses(value = {
69-
@ApiResponse(responseCode = "200", description = "성공"),
69+
@ApiResponse(responseCode = "200", description = "회원 탈퇴 성공"),
7070
@ApiResponse(responseCode = "404", description = "유저 존재하지 않음")
7171
})
7272
@PostMapping
@@ -80,7 +80,7 @@ public ResponseEntity<BaseOKResponse<Void>> memberDelete(@AuthenticationPrincipa
8080

8181
@Operation(summary = "프로필 사진 바꾸기 API", description = "회원의 프로필 사진을 바꿉니다.")
8282
@ApiResponses(value = {
83-
@ApiResponse(responseCode = "200", description = "성공"),
83+
@ApiResponse(responseCode = "200", description = "프로필 바꾸기 성공"),
8484
@ApiResponse(responseCode = "404", description = "유저 존재하지 않음")
8585
})
8686
@PatchMapping("/profile")
@@ -90,7 +90,7 @@ public ResponseEntity<ProfileRes> updateProfile(@AuthenticationPrincipal String
9090

9191
@Operation(summary = "해당 유저 혼잡도 내역 조회 API", description = "유저가 혼잡도 작성한 내역을 반환합니다.")
9292
@ApiResponses(value = {
93-
@ApiResponse(responseCode = "200", description = "조회 성공"),
93+
@ApiResponse(responseCode = "200", description = "혼잡도 내역 조회 성공"),
9494
@ApiResponse(responseCode = "404", description = "유저 존재하지 않음")
9595
})
9696
@GetMapping("/congestion")
Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,45 @@
11
package boombimapi.domain.point.application;
22

33
import boombimapi.domain.member.domain.entity.Member;
4-
import boombimapi.domain.point.presentation.dto.res.GetPointHistoryRes;
54
import boombimapi.domain.point.presentation.dto.res.GetPointRes;
65

7-
import java.util.List;
8-
6+
/**
7+
* PointService
8+
* 포인트 관련 핵심 기능 정의 인터페이스.
9+
* <p>
10+
* - 혼잡도 작성 시 포인트 적립<br>
11+
* - 포인트 및 이력 조회<br>
12+
* - 이벤트 응모 시 포인트 차감
13+
*/
914
public interface PointService {
1015

11-
// 혼잡도 작성 추가
16+
/**
17+
* 혼잡도 작성 시 포인트 적립.
18+
* <p>
19+
* 지정된 회원의 포인트 잔액을 증가시키고, 포인트 적립 이력을 기록한다.
20+
*
21+
* @param member 포인트를 적립할 회원 엔티티
22+
* @param balance 적립할 포인트 금액
23+
*/
1224
void earnPointForCongestion(Member member, Long balance);
1325

14-
// 조회
26+
/**
27+
* 회원 포인트 및 이력 조회.
28+
* <p>
29+
* 지정된 회원 ID로 현재 포인트 잔액과 거래 내역을 조회한다.
30+
*
31+
* @param memberId 조회할 회원의 ID
32+
* @return 회원의 포인트 잔액 및 거래 이력 응답 DTO
33+
*/
1534
GetPointRes getPointHistory(String memberId);
1635

17-
// 이벤트 응모할때 20포인트 삭제
36+
/**
37+
* 이벤트 응모 시 포인트 차감.
38+
* <p>
39+
* 회원의 포인트 잔액에서 지정 금액을 차감하고, 응모 이력 및 포인트 사용 이력을 기록한다.
40+
*
41+
* @param memberId 회원 ID
42+
* @param balance 차감할 포인트 금액
43+
*/
1844
void usePointForEvent(String memberId, Long balance);
1945
}

src/main/java/boombimapi/domain/point/application/impl/PointServiceImpl.java

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,18 @@
33
import boombimapi.domain.member.domain.entity.Member;
44
import boombimapi.domain.member.domain.repository.MemberRepository;
55
import boombimapi.domain.point.application.PointService;
6+
import boombimapi.domain.point.domain.entity.EventCampaign;
67
import boombimapi.domain.point.domain.entity.Point;
78
import boombimapi.domain.point.domain.entity.PointHistory;
9+
import boombimapi.domain.point.domain.entity.type.EventCategory;
810
import boombimapi.domain.point.domain.entity.type.PointAction;
911
import boombimapi.domain.point.domain.entity.type.PointCategory;
12+
import boombimapi.domain.point.domain.repository.EventCampaignRepository;
1013
import boombimapi.domain.point.domain.repository.PointHistoryRepository;
1114
import boombimapi.domain.point.domain.repository.PointRepository;
1215
import boombimapi.domain.point.presentation.dto.res.GetPointHistoryRes;
1316
import boombimapi.domain.point.presentation.dto.res.GetPointRes;
1417
import boombimapi.global.infra.exception.error.BoombimException;
15-
import boombimapi.global.infra.exception.error.ErrorCode;
1618
import jakarta.transaction.Transactional;
1719
import lombok.RequiredArgsConstructor;
1820
import lombok.extern.slf4j.Slf4j;
@@ -23,6 +25,13 @@
2325

2426
import static boombimapi.global.infra.exception.error.ErrorCode.*;
2527

28+
/**
29+
* PointServiceImpl
30+
* 포인트 적립, 조회, 사용(이벤트 응모) 관련 비즈니스 로직을 담당한다.
31+
* - 혼잡도 작성 시 포인트 적립
32+
* - 포인트 및 이력 조회
33+
* - 이벤트 응모 시 포인트 차감 및 응모 이력 생성
34+
*/
2635
@Service
2736
@RequiredArgsConstructor
2837
@Transactional
@@ -32,15 +41,25 @@ public class PointServiceImpl implements PointService {
3241
private final PointRepository pointRepository;
3342
private final PointHistoryRepository pointHistoryRepository;
3443
private final MemberRepository memberRepository;
35-
44+
private final EventCampaignRepository eventCampaignRepository;
45+
46+
/**
47+
* [혼잡도 작성 시 포인트 적립]
48+
* - 특정 회원의 포인트 잔액을 증가시키고, 적립 이력을 저장한다.
49+
* - 포인트가 존재하지 않으면 예외 발생.
50+
*
51+
* @param member 포인트를 적립할 회원
52+
* @param balance 적립할 포인트 금액
53+
*/
3654
@Override
3755
public void earnPointForCongestion(Member member, Long balance) {
3856
Point point = pointRepository.findByMember(member)
3957
.orElseThrow(() -> new BoombimException(POINT_NOT_EXIST));
4058

41-
59+
// 포인트 적립
4260
point.addBalance(balance);
4361

62+
// 포인트 이력 생성
4463
PointHistory pointHistory = PointHistory.builder()
4564
.member(member)
4665
.amount(balance)
@@ -52,6 +71,14 @@ public void earnPointForCongestion(Member member, Long balance) {
5271
pointHistoryRepository.save(pointHistory);
5372
}
5473

74+
/**
75+
* [회원 포인트 및 이력 조회]
76+
* - 회원의 현재 포인트 잔액과 포인트 거래 이력을 조회한다.
77+
* - 회원 또는 포인트 정보가 존재하지 않으면 예외 발생.
78+
*
79+
* @param memberId 조회할 회원 ID
80+
* @return 포인트 잔액 및 거래 이력 응답 DTO
81+
*/
5582
@Override
5683
public GetPointRes getPointHistory(String memberId) {
5784
Member member = memberRepository.findById(memberId)
@@ -61,17 +88,24 @@ public GetPointRes getPointHistory(String memberId) {
6188
.orElseThrow(() -> new BoombimException(POINT_NOT_EXIST));
6289

6390
List<PointHistory> pointHistories = pointHistoryRepository.findAllByMemberOrderByCreatedAtDesc(member);
64-
6591
List<GetPointHistoryRes> result = new ArrayList<>();
6692

6793
for (PointHistory pointHistory : pointHistories) {
6894
result.add(GetPointHistoryRes.of(pointHistory));
6995
}
7096

71-
7297
return GetPointRes.of(point.getBalance(), result);
7398
}
7499

100+
/**
101+
* [이벤트 응모 시 포인트 차감]
102+
* - 회원 포인트 잔액에서 지정 금액을 차감하고, 응모 이력을 저장한다.
103+
* - 응모 횟수가 5회를 초과하면 예외 발생.
104+
* - 포인트가 부족한 경우 예외 발생.
105+
*
106+
* @param memberId 회원 ID
107+
* @param balance 차감할 포인트 금액
108+
*/
75109
@Override
76110
public void usePointForEvent(String memberId, Long balance) {
77111
Member member = memberRepository.findById(memberId)
@@ -80,17 +114,29 @@ public void usePointForEvent(String memberId, Long balance) {
80114
Point point = pointRepository.findByMember(member)
81115
.orElseThrow(() -> new BoombimException(POINT_NOT_EXIST));
82116

117+
// 포인트 잔액 부족 예외
83118
if (point.getBalance() - balance < 0) {
84119
throw new BoombimException(INSUFFICIENT_POINT_FOR_EVENT);
85120
}
86121

122+
// 이벤트 응모 제한 초과 예외
87123
if (point.getApplyEventCount() == 5) {
88124
throw new BoombimException(EVENT_PARTICIPATION_LIMIT_EXCEEDED);
89125
}
90126

127+
// 포인트 차감 및 응모 횟수 증가
91128
point.subtractBalance(balance);
92129
point.addApplyEventCnt();
93130

131+
// 이벤트 응모 이력 저장
132+
EventCampaign eventCampaign = EventCampaign.builder()
133+
.member(member)
134+
.eventCategory(EventCategory.EVENT_PARTICIPATION_TICKET)
135+
.build();
136+
137+
eventCampaignRepository.save(eventCampaign);
138+
139+
// 포인트 거래 이력 저장
94140
PointHistory pointHistory = PointHistory.builder()
95141
.member(member)
96142
.amount(balance)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package boombimapi.domain.point.domain.entity;
2+
3+
import boombimapi.domain.member.domain.entity.Member;
4+
import boombimapi.domain.point.domain.entity.type.EventCategory;
5+
import boombimapi.domain.point.domain.entity.type.PointAction;
6+
import jakarta.persistence.Column;
7+
import jakarta.persistence.Entity;
8+
import jakarta.persistence.EnumType;
9+
import jakarta.persistence.Enumerated;
10+
import jakarta.persistence.FetchType;
11+
import jakarta.persistence.GeneratedValue;
12+
import jakarta.persistence.GenerationType;
13+
import jakarta.persistence.Id;
14+
import jakarta.persistence.JoinColumn;
15+
import jakarta.persistence.OneToOne;
16+
import jakarta.persistence.Table;
17+
import java.time.LocalDateTime;
18+
import lombok.Builder;
19+
import lombok.Getter;
20+
import lombok.NoArgsConstructor;
21+
import org.hibernate.annotations.Comment;
22+
import org.hibernate.annotations.CreationTimestamp;
23+
import org.hibernate.annotations.DynamicUpdate;
24+
25+
@Getter
26+
@Entity
27+
@NoArgsConstructor
28+
@DynamicUpdate
29+
@Table(name = "event_campaign")
30+
public class EventCampaign {
31+
32+
@Id
33+
@GeneratedValue(strategy = GenerationType.IDENTITY)
34+
private Long id;
35+
36+
@OneToOne(fetch = FetchType.LAZY)
37+
@JoinColumn(name = "member_id", nullable = false)
38+
private Member member;
39+
40+
@Enumerated(EnumType.STRING)
41+
@Column(name = "event_category", nullable = false)
42+
@Comment("이벤트 타입 ex) EVENT_PARTICIPATION_TICKETE")
43+
private EventCategory eventCategory;
44+
45+
@Column(nullable = false)
46+
@CreationTimestamp
47+
private LocalDateTime createdAt;
48+
49+
@Builder
50+
public EventCampaign(Member member, EventCategory eventCategory) {
51+
this.member = member;
52+
this.eventCategory = eventCategory;
53+
}
54+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package boombimapi.domain.point.domain.entity.type;
2+
3+
import boombimapi.global.infra.exception.error.BoombimException;
4+
import boombimapi.global.infra.exception.error.ErrorCode;
5+
import com.fasterxml.jackson.annotation.JsonCreator;
6+
import java.util.Arrays;
7+
import lombok.Getter;
8+
9+
@Getter
10+
public enum EventCategory {
11+
12+
EVENT_PARTICIPATION_TICKET("이벤트 응모권");
13+
14+
private final String key;
15+
16+
EventCategory(String key) {
17+
this.key = key;
18+
}
19+
20+
public String getKey() {
21+
return key;
22+
}
23+
24+
// Enum 매핑용 메서드
25+
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
26+
public static EventCategory from(String key) {
27+
return Arrays.stream(EventCategory.values())
28+
.filter(r -> r.getKey().equalsIgnoreCase(key)) // 대소문자 구분 안함
29+
.findFirst()
30+
.orElseThrow(() -> new IllegalArgumentException("이상한 타입이네요.: " + key));
31+
}
32+
33+
public static EventCategory getByValue(String value) {
34+
for (EventCategory role : EventCategory.values()) {
35+
if (role.key.equals(value)) {
36+
return role;
37+
}
38+
}
39+
throw new BoombimException(ErrorCode.INVALID_ROLE);
40+
}
41+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package boombimapi.domain.point.domain.repository;
2+
3+
import boombimapi.domain.point.domain.entity.EventCampaign;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
import org.springframework.stereotype.Repository;
6+
7+
@Repository
8+
public interface EventCampaignRepository extends JpaRepository<EventCampaign, Long> {
9+
}

0 commit comments

Comments
 (0)