Skip to content

Commit 5914439

Browse files
authored
Merge branch 'develop' into refactor/#111/lessonAndCoupon
2 parents 62ba7e5 + e350c50 commit 5914439

34 files changed

+596
-168
lines changed

build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ dependencies {
4343
testAnnotationProcessor 'org.projectlombok:lombok'
4444
testImplementation 'org.springframework.boot:spring-boot-starter-test'
4545
testImplementation 'org.springframework.security:spring-security-test'
46+
testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
47+
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
4648
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
4749
}
4850

src/main/java/com/threestar/trainus/domain/coupon/user/repository/UserCouponRepository.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.time.LocalDateTime;
44
import java.util.List;
5+
import java.util.Optional;
56

67
import org.springframework.data.jpa.repository.JpaRepository;
78
import org.springframework.data.jpa.repository.Query;
@@ -13,6 +14,8 @@
1314
public interface UserCouponRepository extends JpaRepository<UserCoupon, Long> {
1415
boolean existsByUserIdAndCouponId(Long userId, Long couponId);
1516

17+
Optional<UserCoupon> findByUserIdAndCouponId(Long userId, Long couponId);
18+
1619
@Query("SELECT uc FROM UserCoupon uc JOIN FETCH uc.coupon WHERE uc.user.id = :userId")
1720
List<UserCoupon> findAllByUserIdWithCoupon(@Param("userId") Long userId);
1821

src/main/java/com/threestar/trainus/domain/coupon/user/service/CouponService.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,35 @@ public CouponPageResponseDto getCoupons(Long userId) {
9494
.coupons(dtoList)
9595
.build();
9696
}
97+
98+
@Transactional
99+
public UserCoupon getValidUserCoupon(Long userCouponId, Long userId) {
100+
return userCouponRepository.findByUserIdAndCouponId(userId, userCouponId)
101+
.filter(c -> c.getStatus() == CouponStatus.ACTIVE)
102+
.orElseThrow(() -> new BusinessException(ErrorCode.COUPON_NOT_FOUND));
103+
}
104+
105+
public int calculateDiscountedPrice(int originalPrice, UserCoupon coupon) {
106+
String discountPrice = coupon.getCoupon().getDiscountPrice();
107+
if (discountPrice.contains("%")) {
108+
int discountPercentage = Integer.parseInt(discountPrice.substring(0, discountPrice.indexOf("%")));
109+
return originalPrice * discountPercentage / 100;
110+
} else {
111+
return Integer.parseInt(discountPrice.replace("원", ""));
112+
}
113+
}
114+
115+
public void useCoupon(UserCoupon coupon) {
116+
if (coupon.getStatus() == CouponStatus.ACTIVE) {
117+
coupon.use();
118+
userCouponRepository.save(coupon);
119+
}
120+
}
121+
122+
public void restoreCoupon(UserCoupon coupon) {
123+
if (coupon.getStatus() == CouponStatus.INACTIVE) {
124+
coupon.restore();
125+
userCouponRepository.save(coupon);
126+
}
127+
}
97128
}

src/main/java/com/threestar/trainus/domain/lesson/student/service/StudentLessonService.java

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,57 @@ public LessonApplicationResponseDto applyToLesson(Long lessonId, Long userId) {
195195
}
196196
}
197197

198+
@Transactional
199+
public LessonApplicationResponseDto applyToLessonWithLock(Long lessonId, Long userId) {
200+
Lesson lesson = adminLessonService.findLessonByIdWithLock(lessonId); // 락적용 find 메서드
201+
202+
User user = userService.getUserById(userId);
203+
204+
if (lesson.getLessonLeader().equals(userId)) {
205+
throw new BusinessException(ErrorCode.LESSON_CREATOR_CANNOT_APPLY);
206+
}
207+
208+
boolean alreadyParticipated = lessonParticipantRepository.existsByLessonIdAndUserId(lessonId, userId);
209+
boolean alreadyApplied = lessonApplicationRepository.existsByLessonIdAndUserId(lessonId, userId);
210+
if (alreadyParticipated || alreadyApplied) {
211+
throw new BusinessException(ErrorCode.ALREADY_APPLIED);
212+
}
213+
214+
if (lesson.getStatus() != LessonStatus.RECRUITING) {
215+
throw new BusinessException(ErrorCode.LESSON_NOT_AVAILABLE);
216+
}
217+
218+
if (lesson.getOpenRun()) {
219+
LessonParticipant participant = LessonParticipant.builder()
220+
.lesson(lesson)
221+
.user(user)
222+
.build();
223+
lessonParticipantRepository.save(participant);
224+
lesson.incrementParticipantCount();
225+
226+
return LessonApplyMapper.toLessonApplicationResponseDto(
227+
lesson.getId(),
228+
user.getId(),
229+
ApplicationStatus.APPROVED,
230+
participant.getJoinAt()
231+
);
232+
} else {
233+
LessonApplication application = LessonApplication.builder()
234+
.lesson(lesson)
235+
.user(user)
236+
.build();
237+
lessonApplicationRepository.save(application);
238+
239+
return LessonApplyMapper.toLessonApplicationResponseDto(
240+
lesson.getId(),
241+
user.getId(),
242+
ApplicationStatus.PENDING,
243+
application.getCreatedAt()
244+
);
245+
}
246+
}
247+
248+
198249
@Transactional
199250
public void cancelLessonApplication(Long lessonId, Long userId) {
200251
// 레슨 조회
@@ -255,4 +306,24 @@ public LessonSimpleResponseDto getLessonSimple(Long lessonId) {
255306

256307
return LessonSimpleMapper.toLessonSimpleDto(lesson);
257308
}
309+
310+
@Transactional
311+
public void cancelPayment(Long lessonId, Long userId) {
312+
Lesson lesson = adminLessonService.findLessonById(lessonId);
313+
lesson.decrementParticipantCount();
314+
lessonRepository.save(lesson);
315+
316+
LessonParticipant lessonParticipant = lessonParticipantRepository.findByLessonIdAndUserId(lessonId, userId)
317+
.orElseThrow(() -> new BusinessException(ErrorCode.INVALID_LESSON_PARTICIPANT));
318+
319+
lessonParticipantRepository.delete(lessonParticipant);
320+
}
321+
322+
@Transactional
323+
public void checkValidLessonParticipant(Lesson lesson, User user) {
324+
boolean ifExists = lessonParticipantRepository.existsByLessonIdAndUserId(lesson.getId(), user.getId());
325+
if (!ifExists) {
326+
throw new BusinessException(ErrorCode.INVALID_LESSON_PARTICIPANT);
327+
}
328+
}
258329
}

src/main/java/com/threestar/trainus/domain/lesson/teacher/controller/LocationCsvController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,4 @@ public ResponseEntity<Boolean> checkExists(
4040
boolean exists = locationCsvService.checkLocation(city, district, dong, ri);
4141
return ResponseEntity.ok(exists);
4242
}
43-
}
43+
}

src/main/java/com/threestar/trainus/domain/lesson/teacher/entity/Lesson.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,16 @@ public void incrementParticipantCount() {
132132
}
133133
}
134134

135+
// 참가자 수 감소
136+
public void decrementParticipantCount() {
137+
this.participantCount--;
138+
139+
// 정원 달성 시 -> 모집완료로 상태 변경
140+
if (this.participantCount < this.maxParticipants) {
141+
this.status = LessonStatus.RECRUITING;
142+
}
143+
}
144+
135145
//레슨 이름 수정
136146
public void updateLessonName(String lessonName) {
137147
if (lessonName != null && !lessonName.trim().isEmpty()) {

src/main/java/com/threestar/trainus/domain/lesson/teacher/entity/Location.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,4 @@ public Location(String city, String district, String dong, String ri) {
3131
this.dong = dong;
3232
this.ri = ri;
3333
}
34-
}
34+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,25 @@
11
package com.threestar.trainus.domain.lesson.teacher.repository;
22

3+
import java.util.Optional;
4+
5+
import org.springframework.data.jpa.repository.Modifying;
6+
import org.springframework.data.jpa.repository.Query;
37
import org.springframework.data.repository.CrudRepository;
48

59
import com.threestar.trainus.domain.lesson.teacher.entity.LessonParticipant;
610

11+
import jakarta.transaction.Transactional;
12+
713
public interface LessonParticipantRepository extends CrudRepository<LessonParticipant, Long> {
814

915
boolean existsByLessonIdAndUserId(Long lessonId, Long userId);
16+
17+
Optional<LessonParticipant> findByLessonIdAndUserId(Long lessonId, Long userId);
18+
19+
long countByLessonId(Long lessonId);
20+
21+
@Modifying
22+
@Transactional
23+
@Query("DELETE FROM LessonParticipant lp WHERE lp.lesson.id = :lessonId")
24+
void deleteByLessonId(Long lessonId);
1025
}

src/main/java/com/threestar/trainus/domain/lesson/teacher/repository/LocationRepository.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ public interface LocationRepository extends JpaRepository<Location, Long> {
88
boolean existsByCityAndDistrictAndDongAndRi(String city, String district, String dong, String ri);
99

1010
boolean existsByCityAndDistrictAndDong(String city, String district, String dong);
11-
}
11+
}

src/main/java/com/threestar/trainus/domain/lesson/teacher/service/AdminLessonService.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ private ApplicationStatus toApplicationStatus(String status) {
381381
}
382382
}
383383

384-
//레슨 상태 파싱
384+
//레슨 신청 상태 검증
385385
private LessonStatus toLessonStatus(String status) {
386386
try {
387387
return LessonStatus.valueOf(status);
@@ -393,7 +393,7 @@ private LessonStatus toLessonStatus(String status) {
393393
//신청 페이지 조회
394394
private Page<LessonApplication> getApplicationPage(Lesson lesson, String status,
395395
ApplicationStatus applicationStatus, Pageable pageable) {
396-
396+
397397
if ("ALL".equals(status)) {
398398
return lessonApplicationRepository.findByLesson(lesson, pageable);
399399
} else {
@@ -410,8 +410,8 @@ private Page<Lesson> getLessonPage(Long userId, String status, Pageable pageable
410410
return lessonRepository.findByLessonLeaderAndDeletedAtIsNull(userId, pageable);
411411
}
412412
}
413-
414-
//레슨 이미지 저장
413+
414+
//레슨 이미지 저장
415415
private List<LessonImage> saveLessonImages(Lesson lesson, List<String> imageUrls) {
416416
if (imageUrls == null || imageUrls.isEmpty()) {
417417
return List.of();

0 commit comments

Comments
 (0)