diff --git a/src/main/java/com/example/sinitto/callback/controller/CallbackController.java b/src/main/java/com/example/sinitto/callback/controller/CallbackController.java index e3aeab14..30b328d8 100644 --- a/src/main/java/com/example/sinitto/callback/controller/CallbackController.java +++ b/src/main/java/com/example/sinitto/callback/controller/CallbackController.java @@ -37,7 +37,7 @@ public ResponseEntity> getWaitingCallbackList(@MemberId L public ResponseEntity pendingCompleteCallback(@MemberId Long memberId, @PathVariable Long callbackId) { - callbackService.pendingComplete(memberId, callbackId); + callbackService.changeCallbackStatusToPendingCompleteBySinitto(memberId, callbackId); return ResponseEntity.ok().build(); } @@ -55,7 +55,7 @@ public ResponseEntity completeCallback(@MemberId Long memberId, public ResponseEntity acceptCallback(@MemberId Long memberId, @PathVariable Long callbackId) { - callbackService.accept(memberId, callbackId); + callbackService.acceptCallbackBySinitto(memberId, callbackId); return ResponseEntity.ok().build(); } @@ -64,14 +64,14 @@ public ResponseEntity acceptCallback(@MemberId Long memberId, public ResponseEntity cancelCallback(@MemberId Long memberId, @PathVariable Long callbackId) { - callbackService.cancel(memberId, callbackId); + callbackService.cancelCallbackAssignmentBySinitto(memberId, callbackId); return ResponseEntity.ok().build(); } @PostMapping("/twilio") public ResponseEntity addCallCheck(@RequestParam("From") String fromNumber) { - return ResponseEntity.ok(callbackService.add(fromNumber)); + return ResponseEntity.ok(callbackService.createCallbackByCall(fromNumber)); } @Operation(summary = "시니또에게 현재 할당된 콜백 조회", description = "현재 시니또 본인에게 할당된 콜백을 조회합니다.") diff --git a/src/main/java/com/example/sinitto/callback/repository/CallbackRepository.java b/src/main/java/com/example/sinitto/callback/repository/CallbackRepository.java index eeeb617b..6d8be931 100644 --- a/src/main/java/com/example/sinitto/callback/repository/CallbackRepository.java +++ b/src/main/java/com/example/sinitto/callback/repository/CallbackRepository.java @@ -21,4 +21,6 @@ public interface CallbackRepository extends JpaRepository { Page findAllBySeniorIn(List seniors, Pageable pageable); List findAllByStatusAndPendingCompleteTimeBefore(Callback.Status status, LocalDateTime dateTime); + + boolean existsBySeniorAndStatusIn(Senior senior, List statuses); } diff --git a/src/main/java/com/example/sinitto/callback/service/CallbackService.java b/src/main/java/com/example/sinitto/callback/service/CallbackService.java index 5fcb3216..e06f144f 100644 --- a/src/main/java/com/example/sinitto/callback/service/CallbackService.java +++ b/src/main/java/com/example/sinitto/callback/service/CallbackService.java @@ -32,6 +32,7 @@ public class CallbackService { private static final String SUCCESS_MESSAGE = "감사합니다. 잠시만 기다려주세요."; private static final String FAIL_MESSAGE_NOT_ENROLLED = "등록된 사용자가 아닙니다. 서비스 이용이 불가합니다."; private static final String FAIL_MESSAGE_NOT_ENOUGH_POINT = "포인트가 부족합니다. 서비스 이용이 불가합니다."; + private static final String FAIL_MESSAGE_ALREADY_HAS_CALLBACK_IN_PROGRESS_OR_WAITING = "어르신의 요청이 이미 접수되었습니다. 잠시 기다려주시면 연락드리겠습니다."; private final CallbackRepository callbackRepository; private final MemberRepository memberRepository; private final SeniorRepository seniorRepository; @@ -56,7 +57,7 @@ public Page getWaitingCallbacks(Long memberId, Pageable pageab } @Transactional - public void accept(Long memberId, Long callbackId) { + public void acceptCallbackBySinitto(Long memberId, Long callbackId) { checkAuthorization(memberId); @@ -71,7 +72,7 @@ public void accept(Long memberId, Long callbackId) { } @Transactional - public void pendingComplete(Long memberId, Long callbackId) { + public void changeCallbackStatusToPendingCompleteBySinitto(Long memberId, Long callbackId) { checkAuthorization(memberId); @@ -125,7 +126,7 @@ public void changeOldPendingCompleteToCompleteByPolicy() { } @Transactional - public void cancel(Long memberId, Long callbackId) { + public void cancelCallbackAssignmentBySinitto(Long memberId, Long callbackId) { checkAuthorization(memberId); @@ -138,7 +139,7 @@ public void cancel(Long memberId, Long callbackId) { } @Transactional - public String add(String fromNumber) { + public String createCallbackByCall(String fromNumber) { String phoneNumber = TwilioHelper.trimPhoneNumber(fromNumber); @@ -152,6 +153,10 @@ public String add(String fromNumber) { return TwilioHelper.convertMessageToTwiML(FAIL_MESSAGE_NOT_ENOUGH_POINT); } + if (callbackRepository.existsBySeniorAndStatusIn(senior, List.of(Callback.Status.WAITING, Callback.Status.IN_PROGRESS))) { + return TwilioHelper.convertMessageToTwiML(FAIL_MESSAGE_ALREADY_HAS_CALLBACK_IN_PROGRESS_OR_WAITING); + } + point.deduct(CALLBACK_PRICE); pointLogRepository.save( diff --git a/src/main/resources/templates/point/withdraw.html b/src/main/resources/templates/point/withdraw.html index eb30738c..2300c9e9 100644 --- a/src/main/resources/templates/point/withdraw.html +++ b/src/main/resources/templates/point/withdraw.html @@ -43,7 +43,7 @@
diff --git a/src/test/java/com/example/sinitto/callback/repository/CallbackRepositoryTest.java b/src/test/java/com/example/sinitto/callback/repository/CallbackRepositoryTest.java index d5ae6833..e40c2583 100644 --- a/src/test/java/com/example/sinitto/callback/repository/CallbackRepositoryTest.java +++ b/src/test/java/com/example/sinitto/callback/repository/CallbackRepositoryTest.java @@ -220,4 +220,27 @@ void findAllByStatusAndPendingCompleteTimeBefore_success_zeroList() { assertEquals(0, result.size()); } + + @Test + @DisplayName("시니어와 상태들을 조건을 활용한 조회 테스트") + void existsBySeniorAndStatusIn() { + // given + Senior testSenior = seniorRepository.save(new Senior("senior", "01012341234", testMember)); + + callbackRepository.save(new Callback(Callback.Status.WAITING, testSenior)); + callbackRepository.save(new Callback(Callback.Status.PENDING_COMPLETE, testSenior)); + callbackRepository.save(new Callback(Callback.Status.COMPLETE, testSenior)); + + // when + boolean result1 = callbackRepository.existsBySeniorAndStatusIn(testSenior, List.of(Callback.Status.IN_PROGRESS, Callback.Status.WAITING)); + boolean result2 = callbackRepository.existsBySeniorAndStatusIn(testSenior, List.of(Callback.Status.WAITING)); + boolean result3 = callbackRepository.existsBySeniorAndStatusIn(testSenior, List.of(Callback.Status.IN_PROGRESS)); + boolean result4 = callbackRepository.existsBySeniorAndStatusIn(testSenior, List.of(Callback.Status.COMPLETE)); + + // then + assertTrue(result1); + assertTrue(result2); + assertFalse(result3); + assertTrue(result4); + } } diff --git a/src/test/java/com/example/sinitto/callback/service/CallbackServiceTest.java b/src/test/java/com/example/sinitto/callback/service/CallbackServiceTest.java index 979b6c3e..f4a0a436 100644 --- a/src/test/java/com/example/sinitto/callback/service/CallbackServiceTest.java +++ b/src/test/java/com/example/sinitto/callback/service/CallbackServiceTest.java @@ -107,7 +107,7 @@ void getCallbacks_Fail_WhenNotSinitto() { @Test @DisplayName("콜백 수락 - 성공") - void accept() { + void acceptCallbackBySinitto() { //given Long memberId = 1L; Long callbackId = 1L; @@ -120,7 +120,7 @@ void accept() { when(callbackRepository.findById(callbackId)).thenReturn(Optional.of(callback)); //when - callbackService.accept(memberId, callbackId); + callbackService.acceptCallbackBySinitto(memberId, callbackId); //then verify(callback).assignMember(memberId); @@ -144,7 +144,7 @@ void changeCallbackStatusToCompleteByGuard() { when(callback.getAssignedMemberId()).thenReturn(assignedMemberId); //when - callbackService.pendingComplete(memberId, callbackId); + callbackService.changeCallbackStatusToPendingCompleteBySinitto(memberId, callbackId); //then verify(callback).changeStatusToPendingComplete(); @@ -152,7 +152,7 @@ void changeCallbackStatusToCompleteByGuard() { @Test @DisplayName("수락한 콜백 취소 - 성공") - void cancel() { + void cancelCallbackAssignmentBySinitto() { //given Long memberId = 1L; Long callbackId = 1L; @@ -166,7 +166,7 @@ void cancel() { when(callback.getAssignedMemberId()).thenReturn(1L); //when - callbackService.cancel(memberId, callbackId); + callbackService.cancelCallbackAssignmentBySinitto(memberId, callbackId); //then verify(callback).cancelAssignment(); @@ -175,7 +175,7 @@ void cancel() { @Test @DisplayName("새로운 콜백 등록") - void addCallback() { + void createCallbackByCall() { //given String fromPhoneNumber = "+821012341234"; String trimmedPhoneNumber = TwilioHelper.trimPhoneNumber(fromPhoneNumber); @@ -189,7 +189,7 @@ void addCallback() { when(pointRepository.findByMemberIdWithWriteLock(1L)).thenReturn(Optional.of(point)); when(point.isSufficientForDeduction(anyInt())).thenReturn(true); //when - String result = callbackService.add(fromPhoneNumber); + String result = callbackService.createCallbackByCall(fromPhoneNumber); //then verify(pointLogRepository, times(1)).save(any()); @@ -199,7 +199,7 @@ void addCallback() { @Test @DisplayName("새로운 콜백 등록할 때 전화온 번호가 등록된 번호가 아닐 때") - void addCallback_fail() { + void createCallbackByCallingCallback_fail() { //given String fromPhoneNumber = "+821012341234"; String trimmedPhoneNumber = TwilioHelper.trimPhoneNumber(fromPhoneNumber); @@ -207,10 +207,61 @@ void addCallback_fail() { when(seniorRepository.findByPhoneNumber(trimmedPhoneNumber)).thenReturn(Optional.empty()); //when - String result = callbackService.add(fromPhoneNumber); + String result = callbackService.createCallbackByCall(fromPhoneNumber); //then - verify(callbackRepository, times(0)).save(any()); + verify(callbackRepository, never()).save(any()); + assertNotNull(result); + } + + @Test + @DisplayName("새로운 콜백 등록할 때 포인트가 부족할 때") + void createCallbackByCallingCallback_fail1() { + //given + String fromPhoneNumber = "+821012341234"; + String trimmedPhoneNumber = TwilioHelper.trimPhoneNumber(fromPhoneNumber); + Member member = mock(Member.class); + Senior senior = mock(Senior.class); + Point point = mock(Point.class); + + when(seniorRepository.findByPhoneNumber(trimmedPhoneNumber)).thenReturn(Optional.of(senior)); + when(senior.getMember()).thenReturn(member); + when(member.getId()).thenReturn(1L); + when(pointRepository.findByMemberIdWithWriteLock(any(Long.class))).thenReturn(Optional.of(point)); + when(point.isSufficientForDeduction(anyInt())).thenReturn(false); + + //when + String result = callbackService.createCallbackByCall(fromPhoneNumber); + + //then + verify(point, never()).deduct(anyInt()); + verify(callbackRepository, never()).save(any()); + assertNotNull(result); + } + + @Test + @DisplayName("새로운 콜백 등록할 때 이미 시니어가 신청한 진행중 or 대기중인 콜백이 존재할때") + void createCallbackByCallingCallback_fail2() { + //given + String fromPhoneNumber = "+821012341234"; + String trimmedPhoneNumber = TwilioHelper.trimPhoneNumber(fromPhoneNumber); + Member member = mock(Member.class); + Senior senior = mock(Senior.class); + Point point = mock(Point.class); + + when(seniorRepository.findByPhoneNumber(trimmedPhoneNumber)).thenReturn(Optional.of(senior)); + when(senior.getMember()).thenReturn(member); + when(member.getId()).thenReturn(1L); + when(pointRepository.findByMemberIdWithWriteLock(any(Long.class))).thenReturn(Optional.of(point)); + when(point.isSufficientForDeduction(anyInt())).thenReturn(true); + when(callbackRepository.existsBySeniorAndStatusIn(any(), any())).thenReturn(true); + + //when + String result = callbackService.createCallbackByCall(fromPhoneNumber); + + //then + verify(point, never()).deduct(anyInt()); + verify(callbackRepository, never()).save(any()); assertNotNull(result); } @@ -327,7 +378,7 @@ void changeOldPendingCompleteToCompleteByPolicy_Success_zeroList() { callbackService.changeOldPendingCompleteToCompleteByPolicy(); // Then - verify(pointLogRepository, times(0)).save(any(PointLog.class)); + verify(pointLogRepository, never()).save(any(PointLog.class)); } @Test