From 07e16622192220330cdee3f97b96c2a6058e2ad7 Mon Sep 17 00:00:00 2001 From: Desktop Date: Thu, 14 May 2026 09:22:15 +0900 Subject: [PATCH] =?UTF-8?q?fix(auth):=20=ED=9A=8C=EC=9B=90=20=EB=B3=B5?= =?UTF-8?q?=EA=B5=AC=20=EC=8B=9C=20=EB=B9=84=ED=99=9C=EC=84=B1=ED=99=94?= =?UTF-8?q?=EB=90=9C=20=EC=82=AC=EC=97=85=EC=9E=A5=20=EC=9E=AC=ED=99=9C?= =?UTF-8?q?=EC=84=B1=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - UserWithdrawService에 restoreEmployerWorkplaces() 추가 - restoreWithKakao에서 user.restore() 직후 사업장 재활성화 호출 - 탈퇴 후 복구 시 동일 사업자번호로 사업장 재등록할 수 없던 버그(#187) 해결 --- .../domain/auth/service/AuthService.java | 4 +- .../user/service/UserWithdrawService.java | 17 ++++++++ .../domain/auth/service/AuthServiceTest.java | 24 +++++++++++ .../user/service/UserWithdrawServiceTest.java | 40 +++++++++++++++++++ 4 files changed, 84 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/paycheck/domain/auth/service/AuthService.java b/src/main/java/com/example/paycheck/domain/auth/service/AuthService.java index b90baa9..2a9466d 100644 --- a/src/main/java/com/example/paycheck/domain/auth/service/AuthService.java +++ b/src/main/java/com/example/paycheck/domain/auth/service/AuthService.java @@ -139,8 +139,9 @@ private void assertWithinRecoveryPeriod(User user) { /** * 탈퇴한 카카오 계정 복구 (탈퇴 취소) * - User.deletedAt = null로 되돌림 + * - 고용주의 경우 탈퇴 시 비활성화된 사업장을 함께 복원 (사업자번호 재등록 가능) * - UserSettings는 탈퇴 시 보존되었으므로 그대로 사용 (이전 알림 설정 유지) - * - 사업장/계약/근무기록은 자동 복구하지 않음 (다른 사용자 데이터 일관성 보호) + * - 계약/근무기록은 자동 복구하지 않음 (다른 사용자 데이터 일관성 보호) * * @param kakaoAccessToken 카카오 액세스 토큰 * @return 로그인 응답 (refreshToken 포함) @@ -164,6 +165,7 @@ public AuthDto.LoginResponse restoreWithKakao(String kakaoAccessToken) { assertWithinRecoveryPeriod(user); user.restore(); + userWithdrawService.restoreEmployerWorkplaces(user); return buildLoginResponse(user); } diff --git a/src/main/java/com/example/paycheck/domain/user/service/UserWithdrawService.java b/src/main/java/com/example/paycheck/domain/user/service/UserWithdrawService.java index 89e9916..4fb710c 100644 --- a/src/main/java/com/example/paycheck/domain/user/service/UserWithdrawService.java +++ b/src/main/java/com/example/paycheck/domain/user/service/UserWithdrawService.java @@ -139,6 +139,23 @@ private void recalculateTerminationWeekAllowanceAndSalary(WorkerContract contrac }); } + /** + * 고용주 계정 복구 시 탈퇴 과정에서 비활성화된 사업장 재활성화 + * Worker 타입이거나 Employer 프로필이 없으면 아무것도 하지 않는다. + */ + public void restoreEmployerWorkplaces(User user) { + if (user.getUserType() != UserType.EMPLOYER) { + return; + } + Employer employer = employerRepository.findByUserId(user.getId()).orElse(null); + if (employer == null) { + return; + } + List deactivatedWorkplaces = + workplaceRepository.findByEmployerIdAndIsActive(employer.getId(), false); + deactivatedWorkplaces.forEach(Workplace::activate); + } + /** * 공통 데이터 정리 * UserSettings는 30일 이내 복구 시 사용자가 이전에 설정한 알림 옵션을 그대로 살리기 위해 diff --git a/src/test/java/com/example/paycheck/domain/auth/service/AuthServiceTest.java b/src/test/java/com/example/paycheck/domain/auth/service/AuthServiceTest.java index 499569a..77976b6 100644 --- a/src/test/java/com/example/paycheck/domain/auth/service/AuthServiceTest.java +++ b/src/test/java/com/example/paycheck/domain/auth/service/AuthServiceTest.java @@ -572,6 +572,30 @@ void restoreWithKakao_Success() { assertThat(response.getUserType()).isEqualTo("WORKER"); } + @Test + @DisplayName("탈퇴 계정 복구 성공 - EMPLOYER 타입은 사업장 재활성화 호출") + void restoreWithKakao_Employer_ActivatesWorkplaces() { + // given + String kakaoAccessToken = "kakao_access_token"; + User deletedEmployer = User.builder() + .id(3L) + .kakaoId("test_kakao_id") + .name("탈퇴한 고용주") + .userType(UserType.EMPLOYER) + .build(); + deletedEmployer.withdraw(); + + when(oAuthService.getKakaoUserInfo(kakaoAccessToken)).thenReturn(kakaoUserInfo); + when(userRepository.findByKakaoId(kakaoUserInfo.kakaoId())).thenReturn(Optional.of(deletedEmployer)); + when(tokenService.generateTokenPair(deletedEmployer.getId())).thenReturn(tokenPair); + + // when + authService.restoreWithKakao(kakaoAccessToken); + + // then + verify(userWithdrawService).restoreEmployerWorkplaces(deletedEmployer); + } + @Test @DisplayName("탈퇴 계정 복구 실패 - 정상 계정에 호출 시 USER_NOT_WITHDRAWN 예외") void restoreWithKakao_NotWithdrawn_ThrowsException() { diff --git a/src/test/java/com/example/paycheck/domain/user/service/UserWithdrawServiceTest.java b/src/test/java/com/example/paycheck/domain/user/service/UserWithdrawServiceTest.java index 1ec1243..c8ef533 100644 --- a/src/test/java/com/example/paycheck/domain/user/service/UserWithdrawServiceTest.java +++ b/src/test/java/com/example/paycheck/domain/user/service/UserWithdrawServiceTest.java @@ -260,6 +260,46 @@ void withdraw_onlyScheduledWorkRecordsDeleted() { any(), eq(WorkRecordStatus.COMPLETED), any()); } + @Test + @DisplayName("고용주 복구 시 비활성화된 사업장 재활성화") + void restoreEmployerWorkplaces_success() { + // given + Employer employerEntity = Employer.builder() + .id(10L) + .user(employer) + .phone("010-1234-5678") + .build(); + + Workplace deactivatedWorkplace = Workplace.builder() + .id(100L) + .employer(employerEntity) + .name("테스트 사업장") + .businessNumber("166-12-01262") + .isActive(false) + .build(); + + when(employerRepository.findByUserId(employer.getId())).thenReturn(Optional.of(employerEntity)); + when(workplaceRepository.findByEmployerIdAndIsActive(employerEntity.getId(), false)) + .thenReturn(List.of(deactivatedWorkplace)); + + // when + userWithdrawService.restoreEmployerWorkplaces(employer); + + // then + assertThat(deactivatedWorkplace.getIsActive()).isTrue(); + } + + @Test + @DisplayName("WORKER 타입 사용자 복구 시 repository 접근 없이 즉시 return") + void restoreEmployerWorkplaces_workerUser_doesNothing() { + // when + userWithdrawService.restoreEmployerWorkplaces(worker); + + // then + verify(employerRepository, never()).findByUserId(any()); + verify(workplaceRepository, never()).findByEmployerIdAndIsActive(any(), any()); + } + @Test @DisplayName("findById 결과가 비어있을 때 NotFoundException 발생") void withdraw_userNotFound_throwsNotFoundException() {