diff --git a/src/docs/asciidoc/appointmentMember.adoc b/src/docs/asciidoc/appointmentMember.adoc new file mode 100644 index 0000000..0520c73 --- /dev/null +++ b/src/docs/asciidoc/appointmentMember.adoc @@ -0,0 +1,85 @@ += 모임원 (AppointmentMember) +:toc: left +:toclevels: 2 + +== 모임원 추가 + +기존 모임 참여자에 새로운 모임 참여자를 추가할 수 있습니다. + +Enum + +- MANAGER: 총무 + +- PARTICIPANT: 참여자 + +=== Example + +include::{snippets}/appointment-member-controller-test/save-appointment-member/curl-request.adoc[] + +=== HTTP + +==== 요청 + +include::{snippets}/appointment-member-controller-test/save-appointment-member/http-request.adoc[] + +==== 응답 + +include::{snippets}/appointment-member-controller-test/save-appointment-member/http-response.adoc[] + +=== Body + +==== 요청 + +include::{snippets}/appointment-member-controller-test/save-appointment-member/request-body.adoc[] + +==== 응답 + +include::{snippets}/appointment-member-controller-test/save-appointment-member/response-body.adoc[] + +== 결제 상태 변경 + +모임원의 결제 상태를 변경할 수 있습니다. + +=== Example + +include::{snippets}/appointment-member-controller-test/update-payment-status/curl-request.adoc[] + +=== HTTP + +==== 요청 + +include::{snippets}/appointment-member-controller-test/update-payment-status/http-request.adoc[] + +==== 응답 + +include::{snippets}/appointment-member-controller-test/update-payment-status/http-response.adoc[] + +=== Body + +==== 요청 + +include::{snippets}/appointment-member-controller-test/update-payment-status/request-body.adoc[] + +==== 응답 + +include::{snippets}/appointment-member-controller-test/update-payment-status/response-body.adoc[] + +== 모임원 삭제 + +참여자Id를 통해 참여자를 삭제할 수 있습니다. + +- 단, 총무 참여자의 경우 삭제할 수 없습니다. + +=== Example + +include::{snippets}/appointment-member-controller-test/delete-appointment-member/curl-request.adoc[] + +=== HTTP + +==== 요청 + +include::{snippets}/appointment-member-controller-test/delete-appointment-member/http-request.adoc[] + +==== 응답 + +include::{snippets}/appointment-member-controller-test/delete-appointment-member/http-response.adoc[] diff --git a/src/docs/asciidoc/expense.adoc b/src/docs/asciidoc/expense.adoc index 251d1cc..eb04520 100644 --- a/src/docs/asciidoc/expense.adoc +++ b/src/docs/asciidoc/expense.adoc @@ -44,23 +44,23 @@ include::{snippets}/expense-controller-test/save-expenses-fail_when-member-not-f === Example -include::{snippets}/expense-controller-test/get-all-by-group-id-success/curl-request.adoc[] +include::{snippets}/expense-controller-test/get-all-by-settlement-id-success/curl-request.adoc[] === HTTP ==== 요청 -include::{snippets}/expense-controller-test/get-all-by-group-id-success/http-request.adoc[] +include::{snippets}/expense-controller-test/get-all-by-settlement-id-success/http-request.adoc[] ==== 응답 -include::{snippets}/expense-controller-test/get-all-by-group-id-success/http-response.adoc[] +include::{snippets}/expense-controller-test/get-all-by-settlement-id-success/http-response.adoc[] === Body ==== 응답 -include::{snippets}/expense-controller-test/get-all-by-group-id-success/response-body.adoc[] +include::{snippets}/expense-controller-test/get-all-by-settlement-id-success/response-body.adoc[] ==== 응답 - diff --git a/src/docs/asciidoc/group.adoc b/src/docs/asciidoc/group.adoc deleted file mode 100644 index e88a04d..0000000 --- a/src/docs/asciidoc/group.adoc +++ /dev/null @@ -1,144 +0,0 @@ -= 모임 (Group) -:toc: left -:toclevels: 2 - -== 모임 생성 - -모임을 생성할 수 있습니다. - -- 모임을 생성하는 사용자의 accessToken을 넣어준다. - -- 만들고자하는 모임의 이름과 비밀번호를 넣어준다. - -- 생성된 모임의 Id, 생성자(정산 담당자)의 Id, 생성 시간, 만료 시간, 계좌 여부를 알 수 있다. - -- 비회원이 생성한 모임은 1달 후 자동 삭제된다. - -=== Example - -include::{snippets}/group-controller-test/save-group/curl-request.adoc[] - -=== HTTP - -==== 요청 - -include::{snippets}/group-controller-test/save-group/http-request.adoc[] - -==== 응답 - -include::{snippets}/group-controller-test/save-group/http-response.adoc[] - -=== Body - -==== 요청 - -include::{snippets}/group-controller-test/save-group/request-body.adoc[] - -==== 응답 - -include::{snippets}/group-controller-test/save-group/response-body.adoc[] - -== 계좌 추가 - -은행과 계좌 정보를 추가할 수 있습니다. - -=== Example - -include::{snippets}/group-controller-test/update-account/curl-request.adoc[] - -=== HTTP - -==== 요청 - -include::{snippets}/group-controller-test/update-account/http-request.adoc[] - -==== 응답 - -include::{snippets}/group-controller-test/update-account/http-response.adoc[] - -=== Body - -==== 요청 - -include::{snippets}/group-controller-test/update-account/request-body.adoc[] - -==== 응답 - -include::{snippets}/group-controller-test/update-account/response-body.adoc[] - -== 비밀번호 검증 - -비밀번호를 검증할 수 있습니다. - -=== Example - -include::{snippets}/group-controller-test/is-password-match/curl-request.adoc[] - -=== HTTP - -==== 요청 - -include::{snippets}/group-controller-test/is-password-match/http-request.adoc[] - -==== 응답 - -include::{snippets}/group-controller-test/is-password-match/http-response.adoc[] - -=== Body - -==== 요청 - -include::{snippets}/group-controller-test/is-password-match/request-body.adoc[] - -==== 응답 - -include::{snippets}/group-controller-test/is-password-match/response-body.adoc[] - -== 모임 조회 - -모임과 참가자를 조회할 수 있습니다. - -=== Example - -include::{snippets}/group-controller-test/get-group/curl-request.adoc[] - -=== HTTP - -==== 요청 - -include::{snippets}/group-controller-test/get-group/http-request.adoc[] - -==== 응답 - -include::{snippets}/group-controller-test/get-group/http-response.adoc[] - -=== Body - -==== 응답 - -include::{snippets}/group-controller-test/get-group/response-body.adoc[] - -== 모임 상단 조회 - -지출 내역의 상단 부분을 조회할 수 있습니다. - -=== Example - -include::{snippets}/group-controller-test/get-header/curl-request.adoc[] - -=== HTTP - -==== 요청 - -include::{snippets}/group-controller-test/get-header/http-request.adoc[] - -==== 응답 - -include::{snippets}/group-controller-test/get-header/http-response.adoc[] - -=== Body - -==== 응답 - -include::{snippets}/group-controller-test/get-header/response-body.adoc[] - diff --git a/src/docs/asciidoc/groupMember.adoc b/src/docs/asciidoc/groupMember.adoc deleted file mode 100644 index 86208e5..0000000 --- a/src/docs/asciidoc/groupMember.adoc +++ /dev/null @@ -1,85 +0,0 @@ -= 모임원 (GroupMember) -:toc: left -:toclevels: 2 - -== 모임원 추가 - -기존 모임 참여자에 새로운 모임 참여자를 추가할 수 있습니다. - -Enum - -- MANAGER: 총무 - -- PARTICIPANT: 참여자 - -=== Example - -include::{snippets}/group-member-controller-test/save-group-member/curl-request.adoc[] - -=== HTTP - -==== 요청 - -include::{snippets}/group-member-controller-test/save-group-member/http-request.adoc[] - -==== 응답 - -include::{snippets}/group-member-controller-test/save-group-member/http-response.adoc[] - -=== Body - -==== 요청 - -include::{snippets}/group-member-controller-test/save-group-member/request-body.adoc[] - -==== 응답 - -include::{snippets}/group-member-controller-test/save-group-member/response-body.adoc[] - -== 결제 상태 변경 - -모임원의 결제 상태를 변경할 수 있습니다. - -=== Example - -include::{snippets}/group-member-controller-test/update-payment-status/curl-request.adoc[] - -=== HTTP - -==== 요청 - -include::{snippets}/group-member-controller-test/update-payment-status/http-request.adoc[] - -==== 응답 - -include::{snippets}/group-member-controller-test/update-payment-status/http-response.adoc[] - -=== Body - -==== 요청 - -include::{snippets}/group-member-controller-test/update-payment-status/request-body.adoc[] - -==== 응답 - -include::{snippets}/group-member-controller-test/update-payment-status/response-body.adoc[] - -== 모임원 삭제 - -참여자Id를 통해 참여자를 삭제할 수 있습니다. - -- 단, 총무 참여자의 경우 삭제할 수 없습니다. - -=== Example - -include::{snippets}/group-member-controller-test/delete-group-member/curl-request.adoc[] - -=== HTTP - -==== 요청 - -include::{snippets}/group-member-controller-test/delete-group-member/http-request.adoc[] - -==== 응답 - -include::{snippets}/group-member-controller-test/delete-group-member/http-response.adoc[] diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc index 22eb38e..6c4d0a5 100644 --- a/src/docs/asciidoc/index.adoc +++ b/src/docs/asciidoc/index.adoc @@ -14,9 +14,9 @@ include::character.adoc[] include::expense.adoc[] -include::group.adoc[] +include::settlement.adoc[] -include::groupMember.adoc[] +include::appointmentMember.adoc[] include::image.adoc[] diff --git a/src/docs/asciidoc/settlement.adoc b/src/docs/asciidoc/settlement.adoc new file mode 100644 index 0000000..3963e8c --- /dev/null +++ b/src/docs/asciidoc/settlement.adoc @@ -0,0 +1,144 @@ += 모임 (Settlement) +:toc: left +:toclevels: 2 + +== 모임 생성 + +모임을 생성할 수 있습니다. + +- 모임을 생성하는 사용자의 accessToken을 넣어준다. + +- 만들고자하는 모임의 이름과 비밀번호를 넣어준다. + +- 생성된 모임의 Id, 생성자(정산 담당자)의 Id, 생성 시간, 만료 시간, 계좌 여부를 알 수 있다. + +- 비회원이 생성한 모임은 1달 후 자동 삭제된다. + +=== Example + +include::{snippets}/settlement-controller-test/save-settlement/curl-request.adoc[] + +=== HTTP + +==== 요청 + +include::{snippets}/settlement-controller-test/save-settlement/http-request.adoc[] + +==== 응답 + +include::{snippets}/settlement-controller-test/save-settlement/http-response.adoc[] + +=== Body + +==== 요청 + +include::{snippets}/settlement-controller-test/save-settlement/request-body.adoc[] + +==== 응답 + +include::{snippets}/settlement-controller-test/save-settlement/response-body.adoc[] + +== 계좌 추가 + +은행과 계좌 정보를 추가할 수 있습니다. + +=== Example + +include::{snippets}/settlement-controller-test/update-account/curl-request.adoc[] + +=== HTTP + +==== 요청 + +include::{snippets}/settlement-controller-test/update-account/http-request.adoc[] + +==== 응답 + +include::{snippets}/settlement-controller-test/update-account/http-response.adoc[] + +=== Body + +==== 요청 + +include::{snippets}/settlement-controller-test/update-account/request-body.adoc[] + +==== 응답 + +include::{snippets}/settlement-controller-test/update-account/response-body.adoc[] + +== 비밀번호 검증 + +비밀번호를 검증할 수 있습니다. + +=== Example + +include::{snippets}/settlement-controller-test/is-password-match/curl-request.adoc[] + +=== HTTP + +==== 요청 + +include::{snippets}/settlement-controller-test/is-password-match/http-request.adoc[] + +==== 응답 + +include::{snippets}/settlement-controller-test/is-password-match/http-response.adoc[] + +=== Body + +==== 요청 + +include::{snippets}/settlement-controller-test/is-password-match/request-body.adoc[] + +==== 응답 + +include::{snippets}/settlement-controller-test/is-password-match/response-body.adoc[] + +== 모임 조회 + +모임과 참가자를 조회할 수 있습니다. + +=== Example + +include::{snippets}/settlement-controller-test/get-settlement/curl-request.adoc[] + +=== HTTP + +==== 요청 + +include::{snippets}/settlement-controller-test/get-settlement/http-request.adoc[] + +==== 응답 + +include::{snippets}/settlement-controller-test/get-settlement/http-response.adoc[] + +=== Body + +==== 응답 + +include::{snippets}/settlement-controller-test/get-settlement/response-body.adoc[] + +== 모임 상단 조회 + +지출 내역의 상단 부분을 조회할 수 있습니다. + +=== Example + +include::{snippets}/settlement-controller-test/get-header/curl-request.adoc[] + +=== HTTP + +==== 요청 + +include::{snippets}/settlement-controller-test/get-header/http-request.adoc[] + +==== 응답 + +include::{snippets}/settlement-controller-test/get-header/http-response.adoc[] + +=== Body + +==== 응답 + +include::{snippets}/settlement-controller-test/get-header/response-body.adoc[] + diff --git a/src/main/java/com/dnd/moddo/domain/appointmentMember/controller/AppointmentMemberController.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/controller/AppointmentMemberController.java new file mode 100644 index 0000000..dbc223c --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/controller/AppointmentMemberController.java @@ -0,0 +1,75 @@ +package com.dnd.moddo.domain.appointmentMember.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.dnd.moddo.domain.appointmentMember.dto.request.PaymentStatusUpdateRequest; +import com.dnd.moddo.domain.appointmentMember.dto.request.appointmentMemberSaveRequest; +import com.dnd.moddo.domain.appointmentMember.dto.response.AppointmentMemberResponse; +import com.dnd.moddo.domain.appointmentMember.dto.response.AppointmentMembersResponse; +import com.dnd.moddo.domain.appointmentMember.service.CommandAppointmentMemberService; +import com.dnd.moddo.domain.appointmentMember.service.QueryAppointmentMemberService; +import com.dnd.moddo.domain.settlement.service.QuerySettlementService; +import com.dnd.moddo.global.common.annotation.VerifyManagerPermission; +import com.dnd.moddo.global.jwt.service.JwtService; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@RequestMapping("/api/v1/group-members") +@RestController +public class AppointmentMemberController { + private final QueryAppointmentMemberService queryAppointmentMemberService; + private final CommandAppointmentMemberService commandAppointmentMemberService; + private final JwtService jwtService; + private final QuerySettlementService querySettlementService; + + @GetMapping + public ResponseEntity getAppointmentMembers( + @RequestParam("groupToken") String code + ) { + Long settlementId = querySettlementService.findIdByCode(code); + AppointmentMembersResponse response = queryAppointmentMemberService.findAll(settlementId); + return ResponseEntity.ok(response); + } + + @VerifyManagerPermission + @PutMapping + public ResponseEntity addAppointmentMember( + @RequestParam("groupToken") String code, + @Valid @RequestBody appointmentMemberSaveRequest request + ) { + Long settlementId = querySettlementService.findIdByCode(code); + AppointmentMemberResponse response = commandAppointmentMemberService.addAppointmentMember(settlementId, + request); + return ResponseEntity.ok(response); + } + + @PutMapping("/{appointmentMemberId}/payment") + public ResponseEntity updatePaymentStatus( + @RequestParam("groupToken") String code, + @PathVariable("appointmentMemberId") Long appointmentMemberId, + @RequestBody PaymentStatusUpdateRequest request) { + AppointmentMemberResponse response = commandAppointmentMemberService.updatePaymentStatus(appointmentMemberId, + request); + return ResponseEntity.ok(response); + } + + @VerifyManagerPermission + @DeleteMapping("/{appointmentMemberId}") + public ResponseEntity deleteAppointmentMember( + @PathVariable("appointmentMemberId") Long appointmentMemberId + ) { + commandAppointmentMemberService.delete(appointmentMemberId); + return ResponseEntity.noContent().build(); + } + +} diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/dto/request/PaymentStatusUpdateRequest.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/dto/request/PaymentStatusUpdateRequest.java similarity index 50% rename from src/main/java/com/dnd/moddo/domain/groupMember/dto/request/PaymentStatusUpdateRequest.java rename to src/main/java/com/dnd/moddo/domain/appointmentMember/dto/request/PaymentStatusUpdateRequest.java index e151878..c683b66 100644 --- a/src/main/java/com/dnd/moddo/domain/groupMember/dto/request/PaymentStatusUpdateRequest.java +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/dto/request/PaymentStatusUpdateRequest.java @@ -1,4 +1,4 @@ -package com.dnd.moddo.domain.groupMember.dto.request; +package com.dnd.moddo.domain.appointmentMember.dto.request; public record PaymentStatusUpdateRequest(boolean isPaid) { } diff --git a/src/main/java/com/dnd/moddo/domain/appointmentMember/dto/request/appointmentMemberSaveRequest.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/dto/request/appointmentMemberSaveRequest.java new file mode 100644 index 0000000..17d08b7 --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/dto/request/appointmentMemberSaveRequest.java @@ -0,0 +1,24 @@ +package com.dnd.moddo.domain.appointmentMember.dto.request; + +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.settlement.entity.Settlement; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; + +public record appointmentMemberSaveRequest( + @NotBlank(message = "이름은 필수 입력값 입니다.") + @Pattern(regexp = "^[가-힣a-zA-Z]{1,5}$", message = "참여자 이름은 한글과 영어만 포함하여 5자 이내여야 합니다.") + String name +) { + public AppointmentMember toEntity(Settlement settlement, Integer profileId, ExpenseRole role) { + return AppointmentMember.builder() + .name(name) + .settlement(settlement) + .role(role) + .profileId(profileId) + .isPaid(false) + .build(); + } +} diff --git a/src/main/java/com/dnd/moddo/domain/appointmentMember/dto/request/appointmentMembersSaveRequest.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/dto/request/appointmentMembersSaveRequest.java new file mode 100644 index 0000000..2935c82 --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/dto/request/appointmentMembersSaveRequest.java @@ -0,0 +1,24 @@ +package com.dnd.moddo.domain.appointmentMember.dto.request; + +import static com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole.*; + +import java.util.List; + +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.settlement.entity.Settlement; + +import jakarta.validation.Valid; + +public record appointmentMembersSaveRequest( + @Valid List members +) { + public List toEntity(Settlement settlement) { + return members.stream() + .map(m -> m.toEntity(settlement, null, PARTICIPANT)) + .toList(); + } + + public List extractNames() { + return members().stream().map(appointmentMemberSaveRequest::name).toList(); + } +} diff --git a/src/main/java/com/dnd/moddo/domain/appointmentMember/dto/response/AppointmentMemberExpenseResponse.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/dto/response/AppointmentMemberExpenseResponse.java new file mode 100644 index 0000000..609d21b --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/dto/response/AppointmentMemberExpenseResponse.java @@ -0,0 +1,35 @@ +package com.dnd.moddo.domain.appointmentMember.dto.response; + +import java.time.LocalDateTime; +import java.util.List; + +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.memberExpense.dto.response.MemberExpenseDetailResponse; + +import lombok.Builder; + +@Builder +public record AppointmentMemberExpenseResponse( + Long id, + ExpenseRole role, + String name, + Long totalAmount, + String profile, + boolean isPaid, + LocalDateTime paidAt, + List expenses +) { + public static AppointmentMemberExpenseResponse of(AppointmentMember appointmentMember, Long totalAmount, + List expenses) { + return AppointmentMemberExpenseResponse.builder() + .id(appointmentMember.getId()) + .role(appointmentMember.getRole()) + .name(appointmentMember.getName()) + .totalAmount(totalAmount) + .profile(appointmentMember.getProfileUrl()) + .isPaid(appointmentMember.isPaid()) + .paidAt(appointmentMember.getPaidAt()) + .expenses(expenses).build(); + } +} diff --git a/src/main/java/com/dnd/moddo/domain/appointmentMember/dto/response/AppointmentMemberResponse.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/dto/response/AppointmentMemberResponse.java new file mode 100644 index 0000000..2e12ad6 --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/dto/response/AppointmentMemberResponse.java @@ -0,0 +1,31 @@ +package com.dnd.moddo.domain.appointmentMember.dto.response; + +import java.time.LocalDateTime; + +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; + +import lombok.Builder; + +@Builder +public record AppointmentMemberResponse( + Long id, + ExpenseRole role, + String name, + String profile, + boolean isPaid, + LocalDateTime paidAt +) { + + public static AppointmentMemberResponse of(AppointmentMember appointmentMember) { + return AppointmentMemberResponse.builder() + .id(appointmentMember.getId()) + .name(appointmentMember.getName()) + .role(appointmentMember.getRole()) + .isPaid(appointmentMember.isPaid()) + .paidAt(appointmentMember.getPaidAt()) + .profile(appointmentMember.getProfileUrl()) + .build(); + } + +} diff --git a/src/main/java/com/dnd/moddo/domain/appointmentMember/dto/response/AppointmentMembersExpenseResponse.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/dto/response/AppointmentMembersExpenseResponse.java new file mode 100644 index 0000000..c15bb1c --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/dto/response/AppointmentMembersExpenseResponse.java @@ -0,0 +1,9 @@ +package com.dnd.moddo.domain.appointmentMember.dto.response; + +import java.util.List; + +public record AppointmentMembersExpenseResponse( + List memberExpenses +) { + +} diff --git a/src/main/java/com/dnd/moddo/domain/appointmentMember/dto/response/AppointmentMembersResponse.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/dto/response/AppointmentMembersResponse.java new file mode 100644 index 0000000..dcdda79 --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/dto/response/AppointmentMembersResponse.java @@ -0,0 +1,13 @@ +package com.dnd.moddo.domain.appointmentMember.dto.response; + +import java.util.List; + +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; + +public record AppointmentMembersResponse(List members) { + public static AppointmentMembersResponse of(List members) { + return new AppointmentMembersResponse(members.stream() + .map(AppointmentMemberResponse::of) + .toList()); + } +} diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/entity/GroupMember.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/entity/AppointmentMember.java similarity index 77% rename from src/main/java/com/dnd/moddo/domain/groupMember/entity/GroupMember.java rename to src/main/java/com/dnd/moddo/domain/appointmentMember/entity/AppointmentMember.java index 3a24f51..d6dde8c 100644 --- a/src/main/java/com/dnd/moddo/domain/groupMember/entity/GroupMember.java +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/entity/AppointmentMember.java @@ -1,9 +1,9 @@ -package com.dnd.moddo.domain.groupMember.entity; +package com.dnd.moddo.domain.appointmentMember.entity; import java.time.LocalDateTime; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.settlement.entity.Settlement; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -24,9 +24,9 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter -@Table(name = "group_members") +@Table(name = "appointment_members") @Entity -public class GroupMember { +public class AppointmentMember { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -39,8 +39,8 @@ public class GroupMember { private Integer profileId; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "group_id", nullable = false) - private Group group; + @JoinColumn(name = "settlement_id", nullable = false) + private Settlement settlement; @Column(name = "is_paid", nullable = false) private boolean isPaid; @@ -56,10 +56,10 @@ public class GroupMember { private Long version = 0L; @Builder - public GroupMember(String name, Integer profileId, Group group, boolean isPaid, ExpenseRole role) { + public AppointmentMember(String name, Integer profileId, Settlement settlement, boolean isPaid, ExpenseRole role) { this.name = name; this.profileId = profileId; - this.group = group; + this.settlement = settlement; this.isPaid = isPaid; this.role = role; } diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/entity/type/ExpenseRole.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/entity/type/ExpenseRole.java similarity index 63% rename from src/main/java/com/dnd/moddo/domain/groupMember/entity/type/ExpenseRole.java rename to src/main/java/com/dnd/moddo/domain/appointmentMember/entity/type/ExpenseRole.java index f3e31cf..d736c99 100644 --- a/src/main/java/com/dnd/moddo/domain/groupMember/entity/type/ExpenseRole.java +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/entity/type/ExpenseRole.java @@ -1,6 +1,6 @@ -package com.dnd.moddo.domain.groupMember.entity.type; +package com.dnd.moddo.domain.appointmentMember.entity.type; -import com.dnd.moddo.domain.groupMember.exception.ExpenseRoleNotFoundException; +import com.dnd.moddo.domain.appointmentMember.exception.ExpenseRoleNotFoundException; public enum ExpenseRole { MANAGER, PARTICIPANT; diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/exception/GroupMemberDuplicateNameException.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/exception/AppointmentMemberDuplicateNameException.java similarity index 51% rename from src/main/java/com/dnd/moddo/domain/groupMember/exception/GroupMemberDuplicateNameException.java rename to src/main/java/com/dnd/moddo/domain/appointmentMember/exception/AppointmentMemberDuplicateNameException.java index d0fce3b..d68a7d6 100644 --- a/src/main/java/com/dnd/moddo/domain/groupMember/exception/GroupMemberDuplicateNameException.java +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/exception/AppointmentMemberDuplicateNameException.java @@ -1,11 +1,11 @@ -package com.dnd.moddo.domain.groupMember.exception; +package com.dnd.moddo.domain.appointmentMember.exception; import org.springframework.http.HttpStatus; import com.dnd.moddo.global.exception.ModdoException; -public class GroupMemberDuplicateNameException extends ModdoException { - public GroupMemberDuplicateNameException() { +public class AppointmentMemberDuplicateNameException extends ModdoException { + public AppointmentMemberDuplicateNameException() { super(HttpStatus.CONFLICT, "중복된 참여자의 이름은 저장할 수 없습니다."); } } diff --git a/src/main/java/com/dnd/moddo/domain/appointmentMember/exception/AppointmentMemberNotFoundException.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/exception/AppointmentMemberNotFoundException.java new file mode 100644 index 0000000..93f6527 --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/exception/AppointmentMemberNotFoundException.java @@ -0,0 +1,11 @@ +package com.dnd.moddo.domain.appointmentMember.exception; + +import org.springframework.http.HttpStatus; + +import com.dnd.moddo.global.exception.ModdoException; + +public class AppointmentMemberNotFoundException extends ModdoException { + public AppointmentMemberNotFoundException(Long appointmentMemberId) { + super(HttpStatus.NOT_FOUND, "해당 참여자를 찾을 수 없습니다. (AppointmentMember ID: " + appointmentMemberId + ")"); + } +} diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/exception/ExpenseRoleNotFoundException.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/exception/ExpenseRoleNotFoundException.java similarity index 84% rename from src/main/java/com/dnd/moddo/domain/groupMember/exception/ExpenseRoleNotFoundException.java rename to src/main/java/com/dnd/moddo/domain/appointmentMember/exception/ExpenseRoleNotFoundException.java index 52931f4..26732d2 100644 --- a/src/main/java/com/dnd/moddo/domain/groupMember/exception/ExpenseRoleNotFoundException.java +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/exception/ExpenseRoleNotFoundException.java @@ -1,4 +1,4 @@ -package com.dnd.moddo.domain.groupMember.exception; +package com.dnd.moddo.domain.appointmentMember.exception; import org.springframework.http.HttpStatus; diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/exception/InvalidGroupMemberException.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/exception/InvalidAppointmentMemberException.java similarity index 56% rename from src/main/java/com/dnd/moddo/domain/groupMember/exception/InvalidGroupMemberException.java rename to src/main/java/com/dnd/moddo/domain/appointmentMember/exception/InvalidAppointmentMemberException.java index 9f31236..6d2ae91 100644 --- a/src/main/java/com/dnd/moddo/domain/groupMember/exception/InvalidGroupMemberException.java +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/exception/InvalidAppointmentMemberException.java @@ -1,11 +1,11 @@ -package com.dnd.moddo.domain.groupMember.exception; +package com.dnd.moddo.domain.appointmentMember.exception; import org.springframework.http.HttpStatus; import com.dnd.moddo.global.exception.ModdoException; -public class InvalidGroupMemberException extends ModdoException { - public InvalidGroupMemberException(Long id) { +public class InvalidAppointmentMemberException extends ModdoException { + public InvalidAppointmentMemberException(Long id) { super(HttpStatus.BAD_REQUEST, "해당 모임에 속하지 않은 참여자가 포함되어 있습니다 (Member ID: " + id + ")"); } } diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/exception/InvalidExpenseParticipantsException.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/exception/InvalidExpenseParticipantsException.java similarity index 84% rename from src/main/java/com/dnd/moddo/domain/groupMember/exception/InvalidExpenseParticipantsException.java rename to src/main/java/com/dnd/moddo/domain/appointmentMember/exception/InvalidExpenseParticipantsException.java index 4aca8e5..56f0427 100644 --- a/src/main/java/com/dnd/moddo/domain/groupMember/exception/InvalidExpenseParticipantsException.java +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/exception/InvalidExpenseParticipantsException.java @@ -1,4 +1,4 @@ -package com.dnd.moddo.domain.groupMember.exception; +package com.dnd.moddo.domain.appointmentMember.exception; import org.springframework.http.HttpStatus; diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/exception/ManagerCannotDeleteException.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/exception/ManagerCannotDeleteException.java similarity index 56% rename from src/main/java/com/dnd/moddo/domain/groupMember/exception/ManagerCannotDeleteException.java rename to src/main/java/com/dnd/moddo/domain/appointmentMember/exception/ManagerCannotDeleteException.java index 0dc5f25..92e3ff0 100644 --- a/src/main/java/com/dnd/moddo/domain/groupMember/exception/ManagerCannotDeleteException.java +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/exception/ManagerCannotDeleteException.java @@ -1,11 +1,11 @@ -package com.dnd.moddo.domain.groupMember.exception; +package com.dnd.moddo.domain.appointmentMember.exception; import org.springframework.http.HttpStatus; import com.dnd.moddo.global.exception.ModdoException; public class ManagerCannotDeleteException extends ModdoException { - public ManagerCannotDeleteException(Long groupMemberId) { - super(HttpStatus.BAD_REQUEST, "총무(MANAGER)는 삭제할 수 없습니다. (Member ID: " + groupMemberId + ")"); + public ManagerCannotDeleteException(Long appointmentMemberId) { + super(HttpStatus.BAD_REQUEST, "총무(MANAGER)는 삭제할 수 없습니다. (Member ID: " + appointmentMemberId + ")"); } } diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/exception/PaymentConcurrencyException.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/exception/PaymentConcurrencyException.java similarity index 83% rename from src/main/java/com/dnd/moddo/domain/groupMember/exception/PaymentConcurrencyException.java rename to src/main/java/com/dnd/moddo/domain/appointmentMember/exception/PaymentConcurrencyException.java index d6a1a08..525edf8 100644 --- a/src/main/java/com/dnd/moddo/domain/groupMember/exception/PaymentConcurrencyException.java +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/exception/PaymentConcurrencyException.java @@ -1,4 +1,4 @@ -package com.dnd.moddo.domain.groupMember.exception; +package com.dnd.moddo.domain.appointmentMember.exception; import org.springframework.http.HttpStatus; diff --git a/src/main/java/com/dnd/moddo/domain/appointmentMember/repository/AppointmentMemberRepository.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/repository/AppointmentMemberRepository.java new file mode 100644 index 0000000..a9a47f4 --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/repository/AppointmentMemberRepository.java @@ -0,0 +1,28 @@ +package com.dnd.moddo.domain.appointmentMember.repository; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.exception.AppointmentMemberNotFoundException; + +public interface AppointmentMemberRepository extends JpaRepository { + + @Query("select gm from AppointmentMember gm where gm.settlement.id = :settlementId order by " + + "case when gm.role = 'MANAGER' then 1 else 2 end, " + + "case when gm.paidAt is null then 1 else 0 end, " + + "gm.paidAt asc, " + + "gm.name asc") + List findBySettlementId(@Param("settlementId") Long settlementId); + + @Query("select gm.id from AppointmentMember gm where gm.settlement.id = :settlementId") + List findAppointmentMemberIdsBySettlementId(@Param("settlementId") Long settlementId); + + default AppointmentMember getById(Long id) { + return findById(id) + .orElseThrow(() -> new AppointmentMemberNotFoundException(id)); + } +} diff --git a/src/main/java/com/dnd/moddo/domain/appointmentMember/service/CommandAppointmentMemberService.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/service/CommandAppointmentMemberService.java new file mode 100644 index 0000000..615a6ac --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/service/CommandAppointmentMemberService.java @@ -0,0 +1,43 @@ +package com.dnd.moddo.domain.appointmentMember.service; + +import org.springframework.stereotype.Service; + +import com.dnd.moddo.domain.appointmentMember.dto.request.PaymentStatusUpdateRequest; +import com.dnd.moddo.domain.appointmentMember.dto.request.appointmentMemberSaveRequest; +import com.dnd.moddo.domain.appointmentMember.dto.response.AppointmentMemberResponse; +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.service.implementation.AppointmentMemberCreator; +import com.dnd.moddo.domain.appointmentMember.service.implementation.AppointmentMemberDeleter; +import com.dnd.moddo.domain.appointmentMember.service.implementation.AppointmentMemberUpdater; +import com.dnd.moddo.domain.settlement.entity.Settlement; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Service +public class CommandAppointmentMemberService { + private final AppointmentMemberCreator appointmentMemberCreator; + private final AppointmentMemberUpdater appointmentMemberUpdater; + private final AppointmentMemberDeleter appointmentMemberDeleter; + + public AppointmentMemberResponse createManager(Settlement settlement, Long userId) { + AppointmentMember appointmentMember = appointmentMemberCreator.createManagerForSettlement(settlement, userId); + return AppointmentMemberResponse.of(appointmentMember); + } + + public AppointmentMemberResponse addAppointmentMember(Long settlementId, appointmentMemberSaveRequest request) { + AppointmentMember appointmentMember = appointmentMemberUpdater.addToSettlement(settlementId, request); + return AppointmentMemberResponse.of(appointmentMember); + } + + public AppointmentMemberResponse updatePaymentStatus(Long appointmentMemberId, PaymentStatusUpdateRequest request) { + AppointmentMember appointmentMember = appointmentMemberUpdater.updatePaymentStatus(appointmentMemberId, + request); + return AppointmentMemberResponse.of(appointmentMember); + } + + public void delete(Long appointmentMemberId) { + appointmentMemberDeleter.delete(appointmentMemberId); + } + +} diff --git a/src/main/java/com/dnd/moddo/domain/appointmentMember/service/QueryAppointmentMemberService.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/service/QueryAppointmentMemberService.java new file mode 100644 index 0000000..53fc682 --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/service/QueryAppointmentMemberService.java @@ -0,0 +1,22 @@ +package com.dnd.moddo.domain.appointmentMember.service; + +import java.util.List; + +import org.springframework.stereotype.Service; + +import com.dnd.moddo.domain.appointmentMember.dto.response.AppointmentMembersResponse; +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.service.implementation.AppointmentMemberReader; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Service +public class QueryAppointmentMemberService { + private final AppointmentMemberReader appointmentMemberReader; + + public AppointmentMembersResponse findAll(Long settlementId) { + List members = appointmentMemberReader.findAllBySettlementId(settlementId); + return AppointmentMembersResponse.of(members); + } +} diff --git a/src/main/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberCreator.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberCreator.java new file mode 100644 index 0000000..91c8ebd --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberCreator.java @@ -0,0 +1,39 @@ +package com.dnd.moddo.domain.appointmentMember.service.implementation; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.appointmentMember.repository.AppointmentMemberRepository; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.user.entity.User; +import com.dnd.moddo.domain.user.repository.UserRepository; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Service +@Transactional +public class AppointmentMemberCreator { + private final AppointmentMemberRepository appointmentMemberRepository; + private final UserRepository userRepository; + + public AppointmentMember createManagerForSettlement(Settlement settlement, Long userId) { + User user = userRepository.getById(userId); + + String name = user.getIsMember() ? user.getName() : "김모또"; + + AppointmentMember appointmentMember = AppointmentMember.builder() + .name(name) + .settlement(settlement) + .profileId(null) + .profileId(0) + .role(ExpenseRole.MANAGER) + .build(); + + appointmentMember.updatePaymentStatus(true); + + return appointmentMemberRepository.save(appointmentMember); + } +} diff --git a/src/main/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberDeleter.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberDeleter.java new file mode 100644 index 0000000..ea039e8 --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberDeleter.java @@ -0,0 +1,26 @@ +package com.dnd.moddo.domain.appointmentMember.service.implementation; + +import org.springframework.stereotype.Service; + +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.exception.ManagerCannotDeleteException; +import com.dnd.moddo.domain.appointmentMember.repository.AppointmentMemberRepository; + +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +@Transactional +public class AppointmentMemberDeleter { + private final AppointmentMemberRepository appointmentMemberRepository; + private final AppointmentMemberReader appointmentMemberReader; + + public void delete(Long appointmentMemberId) { + AppointmentMember appointmentMember = appointmentMemberReader.findByAppointmentMemberId(appointmentMemberId); + if (appointmentMember.isManager()) { + throw new ManagerCannotDeleteException(appointmentMemberId); + } + appointmentMemberRepository.delete(appointmentMember); + } +} diff --git a/src/main/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberReader.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberReader.java new file mode 100644 index 0000000..a3eef63 --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberReader.java @@ -0,0 +1,31 @@ +package com.dnd.moddo.domain.appointmentMember.service.implementation; + +import java.util.List; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.repository.AppointmentMemberRepository; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class AppointmentMemberReader { + private final AppointmentMemberRepository appointmentMemberRepository; + + public List findAllBySettlementId(Long settlementId) { + return appointmentMemberRepository.findBySettlementId(settlementId); + } + + public AppointmentMember findByAppointmentMemberId(Long appointmentMemberId) { + return appointmentMemberRepository.getById(appointmentMemberId); + } + + public List findIdsBySettlementId(Long settlementId) { + return appointmentMemberRepository.findAppointmentMemberIdsBySettlementId(settlementId); + } + +} diff --git a/src/main/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberUpdater.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberUpdater.java new file mode 100644 index 0000000..6054d98 --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberUpdater.java @@ -0,0 +1,80 @@ +package com.dnd.moddo.domain.appointmentMember.service.implementation; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.dao.OptimisticLockingFailureException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; + +import com.dnd.moddo.domain.appointmentMember.dto.request.PaymentStatusUpdateRequest; +import com.dnd.moddo.domain.appointmentMember.dto.request.appointmentMemberSaveRequest; +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.appointmentMember.exception.PaymentConcurrencyException; +import com.dnd.moddo.domain.appointmentMember.repository.AppointmentMemberRepository; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementReader; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class AppointmentMemberUpdater { + private final AppointmentMemberRepository appointmentMemberRepository; + private final AppointmentMemberReader appointmentMemberReader; + private final AppointmentMemberValidator appointmentMemberValidator; + private final SettlementReader settlementReader; + + @Transactional + public AppointmentMember addToSettlement(Long settlementId, appointmentMemberSaveRequest request) { + Settlement settlement = settlementReader.read(settlementId); + List appointmentMembers = appointmentMemberReader.findAllBySettlementId(settlementId); + + List existingNames = new ArrayList<>( + appointmentMembers.stream().map(AppointmentMember::getName).toList()); + existingNames.add(request.name()); + + appointmentMemberValidator.validateMemberNamesNotDuplicate(existingNames); + + List usedProfiles = appointmentMembers.stream() + .filter(member -> !member.isManager()) + .map(AppointmentMember::getProfileId) + .toList(); + + Integer newProfileId = findAvailableProfileId(usedProfiles); + + AppointmentMember newMember = request.toEntity(settlement, newProfileId, ExpenseRole.PARTICIPANT); + newMember = appointmentMemberRepository.save(newMember); + + return newMember; + } + + @Transactional(isolation = Isolation.READ_COMMITTED) + public AppointmentMember updatePaymentStatus(Long appointmentMemberId, PaymentStatusUpdateRequest request) { + try { + AppointmentMember appointmentMember = appointmentMemberRepository.getById(appointmentMemberId); + if (appointmentMember.isPaid() != request.isPaid()) { + appointmentMember.updatePaymentStatus(request.isPaid()); + appointmentMemberRepository.save(appointmentMember); + } + return appointmentMember; + } catch (OptimisticLockingFailureException e) { + throw new PaymentConcurrencyException(); + } + } + + private Integer findAvailableProfileId(List usedProfiles) { + for (int i = 1; i <= 8; i++) { + if (!usedProfiles.contains(i)) { + return i; + } + } + + return (usedProfiles.size() % 8) + 1; + } +} + + + diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberValidator.java b/src/main/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberValidator.java similarity index 64% rename from src/main/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberValidator.java rename to src/main/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberValidator.java index 8d693fa..443478c 100644 --- a/src/main/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberValidator.java +++ b/src/main/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberValidator.java @@ -1,4 +1,4 @@ -package com.dnd.moddo.domain.groupMember.service.implementation; +package com.dnd.moddo.domain.appointmentMember.service.implementation; import java.util.HashSet; import java.util.List; @@ -6,17 +6,17 @@ import org.springframework.stereotype.Service; -import com.dnd.moddo.domain.groupMember.exception.GroupMemberDuplicateNameException; +import com.dnd.moddo.domain.appointmentMember.exception.AppointmentMemberDuplicateNameException; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @Service -public class GroupMemberValidator { +public class AppointmentMemberValidator { public void validateMemberNamesNotDuplicate(List names) { if (hasDuplicateMemberName(names)) { - throw new GroupMemberDuplicateNameException(); + throw new AppointmentMemberDuplicateNameException(); } } @@ -24,5 +24,5 @@ private boolean hasDuplicateMemberName(List names) { Set uniqueNames = new HashSet<>(names); return uniqueNames.size() != names.size(); } - + } diff --git a/src/main/java/com/dnd/moddo/domain/character/controller/CharacterController.java b/src/main/java/com/dnd/moddo/domain/character/controller/CharacterController.java index 4044355..a50255e 100644 --- a/src/main/java/com/dnd/moddo/domain/character/controller/CharacterController.java +++ b/src/main/java/com/dnd/moddo/domain/character/controller/CharacterController.java @@ -7,7 +7,7 @@ import org.springframework.web.bind.annotation.RestController; import com.dnd.moddo.domain.character.service.QueryCharacterService; -import com.dnd.moddo.domain.group.service.QueryGroupService; +import com.dnd.moddo.domain.settlement.service.QuerySettlementService; import com.dnd.moddo.domain.image.dto.CharacterResponse; import com.dnd.moddo.global.jwt.service.JwtService; @@ -20,13 +20,13 @@ public class CharacterController { private final JwtService jwtService; private final QueryCharacterService queryCharacterService; - private final QueryGroupService queryGroupService; + private final QuerySettlementService querySettlementService; @GetMapping() public ResponseEntity getCharacter( @RequestParam("groupToken") String code ) { - Long groupId = queryGroupService.findIdByCode(code); + Long groupId = querySettlementService.findIdByCode(code); CharacterResponse response = queryCharacterService.findCharacterByGroupId(groupId); return ResponseEntity.ok(response); diff --git a/src/main/java/com/dnd/moddo/domain/character/entity/Character.java b/src/main/java/com/dnd/moddo/domain/character/entity/Character.java index 6bbef03..aaf7b4b 100644 --- a/src/main/java/com/dnd/moddo/domain/character/entity/Character.java +++ b/src/main/java/com/dnd/moddo/domain/character/entity/Character.java @@ -1,6 +1,6 @@ package com.dnd.moddo.domain.character.entity; -import com.dnd.moddo.domain.group.entity.Group; +import com.dnd.moddo.domain.settlement.entity.Settlement; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; @@ -27,7 +27,7 @@ public class Character { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "group_id", nullable = false) - private Group group; + private Settlement settlement; private String name; private String rarity; @@ -35,8 +35,8 @@ public class Character { private String imageBigUrl; @Builder - public Character(Group group, String name, String rarity, String imageUrl, String imageBigUrl) { - this.group = group; + public Character(Settlement settlement, String name, String rarity, String imageUrl, String imageBigUrl) { + this.settlement = settlement; this.name = name; this.rarity = rarity; this.imageUrl = imageUrl; diff --git a/src/main/java/com/dnd/moddo/domain/character/repository/CharacterRepository.java b/src/main/java/com/dnd/moddo/domain/character/repository/CharacterRepository.java index 6d8f004..0439261 100644 --- a/src/main/java/com/dnd/moddo/domain/character/repository/CharacterRepository.java +++ b/src/main/java/com/dnd/moddo/domain/character/repository/CharacterRepository.java @@ -12,5 +12,5 @@ default Character getById(Long characterId) { return findById(characterId).orElseThrow(() -> new CharacterNotFoundException()); } - Optional findByGroupId(Long groupId); + Optional findBySettlementId(Long settlementId); } \ No newline at end of file diff --git a/src/main/java/com/dnd/moddo/domain/character/service/implementation/CharacterReader.java b/src/main/java/com/dnd/moddo/domain/character/service/implementation/CharacterReader.java index 81879cf..f43d7c9 100644 --- a/src/main/java/com/dnd/moddo/domain/character/service/implementation/CharacterReader.java +++ b/src/main/java/com/dnd/moddo/domain/character/service/implementation/CharacterReader.java @@ -15,7 +15,7 @@ public class CharacterReader { private final CharacterRepository characterRepository; public CharacterResponse getCharacterByGroupId(Long groupId) { - Character character = characterRepository.findByGroupId(groupId) + Character character = characterRepository.findBySettlementId(groupId) .orElseThrow(CharacterNotFoundException::new); return CharacterResponse.from(character); diff --git a/src/main/java/com/dnd/moddo/domain/expense/controller/ExpenseController.java b/src/main/java/com/dnd/moddo/domain/expense/controller/ExpenseController.java index 7176c5e..430d8bb 100644 --- a/src/main/java/com/dnd/moddo/domain/expense/controller/ExpenseController.java +++ b/src/main/java/com/dnd/moddo/domain/expense/controller/ExpenseController.java @@ -19,7 +19,7 @@ import com.dnd.moddo.domain.expense.dto.response.ExpensesResponse; import com.dnd.moddo.domain.expense.service.CommandExpenseService; import com.dnd.moddo.domain.expense.service.QueryExpenseService; -import com.dnd.moddo.domain.group.service.QueryGroupService; +import com.dnd.moddo.domain.settlement.service.QuerySettlementService; import com.dnd.moddo.global.common.annotation.VerifyManagerPermission; import com.dnd.moddo.global.jwt.service.JwtService; @@ -35,21 +35,21 @@ public class ExpenseController { private final CommandExpenseService commandExpenseService; private final QueryExpenseService queryExpenseService; private final JwtService jwtService; - private final QueryGroupService queryGroupService; + private final QuerySettlementService querySettlementService; @PostMapping public ResponseEntity saveExpenses( @RequestParam("groupToken") String code, @Valid @RequestBody ExpensesRequest request) { - Long groupId = queryGroupService.findIdByCode(code); - ExpensesResponse response = commandExpenseService.createExpenses(groupId, request); + Long settlementId = querySettlementService.findIdByCode(code); + ExpensesResponse response = commandExpenseService.createExpenses(settlementId, request); return ResponseEntity.ok(response); } @GetMapping - public ResponseEntity getAllByGroupId(@RequestParam("groupToken") String code) { - Long groupId = queryGroupService.findIdByCode(code); - ExpensesResponse response = queryExpenseService.findAllByGroupId(groupId); + public ResponseEntity getAllBySettlementId(@RequestParam("groupToken") String code) { + Long settlementId = querySettlementService.findIdByCode(code); + ExpensesResponse response = queryExpenseService.findAllBySettlementId(settlementId); return ResponseEntity.ok(response); } @@ -61,10 +61,10 @@ public ResponseEntity getByExpenseId(@PathVariable("expenseId") } @GetMapping("/details") - public ResponseEntity getExpenseDetailsByGroupId( + public ResponseEntity getExpenseDetailsBySettlementId( @RequestParam("groupToken") String code) { - Long groupId = queryGroupService.findIdByCode(code); - ExpenseDetailsResponse response = queryExpenseService.findAllExpenseDetailsByGroupId(groupId); + Long settlementId = querySettlementService.findIdByCode(code); + ExpenseDetailsResponse response = queryExpenseService.findAllExpenseDetailsBySettlementId(settlementId); return ResponseEntity.ok(response); } @@ -90,7 +90,7 @@ public void updateImgUrl(HttpServletRequest request, @PathVariable("expenseId") Long expenseId, @RequestBody ExpenseImageRequest expenseImageRequest) { Long userId = jwtService.getUserId(request); - Long groupId = queryGroupService.findIdByCode(code); - commandExpenseService.updateImgUrl(userId, groupId, expenseId, expenseImageRequest); + Long settlementId = querySettlementService.findIdByCode(code); + commandExpenseService.updateImgUrl(userId, settlementId, expenseId, expenseImageRequest); } } diff --git a/src/main/java/com/dnd/moddo/domain/expense/dto/request/ExpenseRequest.java b/src/main/java/com/dnd/moddo/domain/expense/dto/request/ExpenseRequest.java index f204ba4..cae772a 100644 --- a/src/main/java/com/dnd/moddo/domain/expense/dto/request/ExpenseRequest.java +++ b/src/main/java/com/dnd/moddo/domain/expense/dto/request/ExpenseRequest.java @@ -4,7 +4,7 @@ import java.util.List; import com.dnd.moddo.domain.expense.entity.Expense; -import com.dnd.moddo.domain.group.entity.Group; +import com.dnd.moddo.domain.settlement.entity.Settlement; import com.dnd.moddo.domain.memberExpense.dto.request.MemberExpenseRequest; import com.fasterxml.jackson.annotation.JsonFormat; @@ -26,7 +26,7 @@ public record ExpenseRequest( ) { - public Expense toEntity(Group group) { - return new Expense(group, amount(), content(), date()); + public Expense toEntity(Settlement settlement) { + return new Expense(settlement, amount(), content(), date()); } } diff --git a/src/main/java/com/dnd/moddo/domain/expense/dto/request/ExpensesRequest.java b/src/main/java/com/dnd/moddo/domain/expense/dto/request/ExpensesRequest.java index be36b98..f526252 100644 --- a/src/main/java/com/dnd/moddo/domain/expense/dto/request/ExpensesRequest.java +++ b/src/main/java/com/dnd/moddo/domain/expense/dto/request/ExpensesRequest.java @@ -3,16 +3,16 @@ import java.util.List; import com.dnd.moddo.domain.expense.entity.Expense; -import com.dnd.moddo.domain.group.entity.Group; +import com.dnd.moddo.domain.settlement.entity.Settlement; import jakarta.validation.Valid; public record ExpensesRequest( @Valid List expenses ) { - public List toEntity(Group group) { + public List toEntity(Settlement settlement) { return expenses.stream() - .map(e -> e.toEntity(group)) + .map(e -> e.toEntity(settlement)) .toList(); } } diff --git a/src/main/java/com/dnd/moddo/domain/expense/entity/Expense.java b/src/main/java/com/dnd/moddo/domain/expense/entity/Expense.java index 60c3ac2..5cd56ba 100644 --- a/src/main/java/com/dnd/moddo/domain/expense/entity/Expense.java +++ b/src/main/java/com/dnd/moddo/domain/expense/entity/Expense.java @@ -3,13 +3,19 @@ import java.time.LocalDate; import java.util.List; -import ch.qos.logback.core.testUtil.StringListAppender; -import com.dnd.moddo.domain.expense.dto.request.ExpenseImageRequest; -import com.dnd.moddo.domain.group.entity.Group; +import com.dnd.moddo.domain.settlement.entity.Settlement; import com.dnd.moddo.global.converter.StringListConverter; import com.fasterxml.jackson.annotation.JsonFormat; -import jakarta.persistence.*; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -25,8 +31,8 @@ public class Expense { private Long id; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "group_id") - private Group group; + @JoinColumn(name = "settlement_id") + private Settlement settlement; private Long amount; @@ -38,13 +44,13 @@ public class Expense { @Convert(converter = StringListConverter.class) private List images; - public Expense(Group group, Long amount, String content, LocalDate date) { - this(group, amount, content, date, null); + public Expense(Settlement settlement, Long amount, String content, LocalDate date) { + this(settlement, amount, content, date, null); } @Builder - public Expense(Group group, Long amount, String content, LocalDate date, List images) { - this.group = group; + public Expense(Settlement settlement, Long amount, String content, LocalDate date, List images) { + this.settlement = settlement; this.amount = amount; this.content = content; this.date = date; diff --git a/src/main/java/com/dnd/moddo/domain/expense/repository/ExpenseRepository.java b/src/main/java/com/dnd/moddo/domain/expense/repository/ExpenseRepository.java index 35137b0..0be37a8 100644 --- a/src/main/java/com/dnd/moddo/domain/expense/repository/ExpenseRepository.java +++ b/src/main/java/com/dnd/moddo/domain/expense/repository/ExpenseRepository.java @@ -2,21 +2,21 @@ import java.util.List; -import com.dnd.moddo.domain.group.entity.Group; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import com.dnd.moddo.domain.expense.entity.Expense; import com.dnd.moddo.domain.expense.exception.ExpenseNotFoundException; -import org.springframework.data.jpa.repository.Query; +import com.dnd.moddo.domain.settlement.entity.Settlement; public interface ExpenseRepository extends JpaRepository { - List findByGroupId(Long groupId); + List findBySettlementId(Long settlementId); + + List findBySettlementIdOrderByDateAsc(Long id); - List findByGroupIdOrderByDateAsc(Long id); + @Query("SELECT SUM(e.amount) FROM Expense e WHERE e.settlement = :settlement") + Long sumAmountBySettlement(Settlement settlement); - @Query("SELECT SUM(e.amount) FROM Expense e WHERE e.group = :group") - Long sumAmountByGroup(Group group); - default Expense getById(Long id) { return findById(id) .orElseThrow(() -> new ExpenseNotFoundException(id)); diff --git a/src/main/java/com/dnd/moddo/domain/expense/service/CommandExpenseService.java b/src/main/java/com/dnd/moddo/domain/expense/service/CommandExpenseService.java index 0afd53e..db129f0 100644 --- a/src/main/java/com/dnd/moddo/domain/expense/service/CommandExpenseService.java +++ b/src/main/java/com/dnd/moddo/domain/expense/service/CommandExpenseService.java @@ -2,12 +2,9 @@ import java.util.List; -import com.dnd.moddo.domain.expense.dto.request.ExpenseImageRequest; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.service.implementation.GroupReader; -import com.dnd.moddo.domain.group.service.implementation.GroupValidator; import org.springframework.stereotype.Service; +import com.dnd.moddo.domain.expense.dto.request.ExpenseImageRequest; import com.dnd.moddo.domain.expense.dto.request.ExpenseRequest; import com.dnd.moddo.domain.expense.dto.request.ExpensesRequest; import com.dnd.moddo.domain.expense.dto.response.ExpenseResponse; @@ -19,6 +16,9 @@ import com.dnd.moddo.domain.expense.service.implementation.ExpenseUpdater; import com.dnd.moddo.domain.memberExpense.dto.response.MemberExpenseResponse; import com.dnd.moddo.domain.memberExpense.service.CommandMemberExpenseService; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementReader; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementValidator; import lombok.RequiredArgsConstructor; @@ -30,8 +30,8 @@ public class CommandExpenseService { private final ExpenseUpdater expenseUpdater; private final ExpenseDeleter expenseDeleter; private final CommandMemberExpenseService commandMemberExpenseService; - private final GroupReader groupReader; - private final GroupValidator groupValidator; + private final SettlementReader settlementReader; + private final SettlementValidator settlementValidator; public ExpensesResponse createExpenses(Long groupId, ExpensesRequest request) { List expenses = request.expenses() @@ -58,12 +58,11 @@ public ExpenseResponse update(Long expenseId, ExpenseRequest request) { } public void updateImgUrl(Long userId, Long groupId, Long expenseId, ExpenseImageRequest request) { - Group group = groupReader.read(groupId); - groupValidator.checkGroupAuthor(group, userId); + Settlement settlement = settlementReader.read(groupId); + settlementValidator.checkSettlementAuthor(settlement, userId); expenseUpdater.updateImgUrl(expenseId, request); } - public void delete(Long expenseId) { Expense expense = expenseReader.findByExpenseId(expenseId); //TODO 삭제하는 사람이 정산자인지 확인 로직 필요 diff --git a/src/main/java/com/dnd/moddo/domain/expense/service/QueryExpenseService.java b/src/main/java/com/dnd/moddo/domain/expense/service/QueryExpenseService.java index 0e6ee02..5d39d34 100644 --- a/src/main/java/com/dnd/moddo/domain/expense/service/QueryExpenseService.java +++ b/src/main/java/com/dnd/moddo/domain/expense/service/QueryExpenseService.java @@ -21,8 +21,8 @@ public class QueryExpenseService { private final ExpenseReader expenseReader; private final QueryMemberExpenseService queryMemberExpenseService; - public ExpensesResponse findAllByGroupId(Long groupId) { - List expenses = expenseReader.findAllByGroupId(groupId); + public ExpensesResponse findAllBySettlementId(Long settlementId) { + List expenses = expenseReader.findAllBySettlementId(settlementId); return new ExpensesResponse( expenses.stream() .map(expense -> @@ -36,9 +36,9 @@ public ExpenseResponse findOneByExpenseId(Long expenseId) { return ExpenseResponse.of(expense); } - public ExpenseDetailsResponse findAllExpenseDetailsByGroupId(Long groupId) { + public ExpenseDetailsResponse findAllExpenseDetailsBySettlementId(Long settlementId) { - List expenses = expenseReader.findAllByGroupId(groupId); + List expenses = expenseReader.findAllBySettlementId(settlementId); List expenseIds = expenses.stream().map(Expense::getId).toList(); Map> memberNameByExpenseId = queryMemberExpenseService.getMemberNamesByExpenseIds( diff --git a/src/main/java/com/dnd/moddo/domain/expense/service/implementation/ExpenseCreator.java b/src/main/java/com/dnd/moddo/domain/expense/service/implementation/ExpenseCreator.java index 16eb484..96dc07e 100644 --- a/src/main/java/com/dnd/moddo/domain/expense/service/implementation/ExpenseCreator.java +++ b/src/main/java/com/dnd/moddo/domain/expense/service/implementation/ExpenseCreator.java @@ -6,9 +6,9 @@ import com.dnd.moddo.domain.expense.dto.request.ExpenseRequest; import com.dnd.moddo.domain.expense.entity.Expense; import com.dnd.moddo.domain.expense.repository.ExpenseRepository; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.repository.GroupRepository; import com.dnd.moddo.domain.memberExpense.service.implementation.MemberExpenseValidator; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.repository.SettlementRepository; import lombok.RequiredArgsConstructor; @@ -18,14 +18,14 @@ public class ExpenseCreator { private final ExpenseRepository expenseRepository; private final MemberExpenseValidator memberExpenseValidator; - private final GroupRepository groupRepository; + private final SettlementRepository settlementRepository; - public Expense create(Long groupId, ExpenseRequest request) { - Group group = groupRepository.getById(groupId); + public Expense create(Long settlementId, ExpenseRequest request) { + Settlement settlement = settlementRepository.getById(settlementId); - memberExpenseValidator.validateMembersArePartOfGroup(groupId, request.memberExpenses()); + memberExpenseValidator.validateMembersArePartOfSettlement(settlementId, request.memberExpenses()); - Expense expense = request.toEntity(group); + Expense expense = request.toEntity(settlement); return expenseRepository.save(expense); } diff --git a/src/main/java/com/dnd/moddo/domain/expense/service/implementation/ExpenseReader.java b/src/main/java/com/dnd/moddo/domain/expense/service/implementation/ExpenseReader.java index 7154d70..b265027 100644 --- a/src/main/java/com/dnd/moddo/domain/expense/service/implementation/ExpenseReader.java +++ b/src/main/java/com/dnd/moddo/domain/expense/service/implementation/ExpenseReader.java @@ -16,8 +16,8 @@ public class ExpenseReader { private final ExpenseRepository expenseRepository; - public List findAllByGroupId(Long groupId) { - return expenseRepository.findByGroupIdOrderByDateAsc(groupId); + public List findAllBySettlementId(Long settlementId) { + return expenseRepository.findBySettlementIdOrderByDateAsc(settlementId); } public Expense findByExpenseId(Long expenseId) { diff --git a/src/main/java/com/dnd/moddo/domain/group/controller/GroupController.java b/src/main/java/com/dnd/moddo/domain/group/controller/GroupController.java deleted file mode 100644 index 52c4a97..0000000 --- a/src/main/java/com/dnd/moddo/domain/group/controller/GroupController.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.dnd.moddo.domain.group.controller; - -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import com.dnd.moddo.domain.group.dto.request.GroupAccountRequest; -import com.dnd.moddo.domain.group.dto.request.GroupPasswordRequest; -import com.dnd.moddo.domain.group.dto.request.GroupRequest; -import com.dnd.moddo.domain.group.dto.response.GroupDetailResponse; -import com.dnd.moddo.domain.group.dto.response.GroupHeaderResponse; -import com.dnd.moddo.domain.group.dto.response.GroupPasswordResponse; -import com.dnd.moddo.domain.group.dto.response.GroupResponse; -import com.dnd.moddo.domain.group.dto.response.GroupSaveResponse; -import com.dnd.moddo.domain.group.service.CommandGroupService; -import com.dnd.moddo.domain.group.service.QueryGroupService; -import com.dnd.moddo.global.jwt.service.JwtService; - -import jakarta.servlet.http.HttpServletRequest; -import lombok.RequiredArgsConstructor; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/api/v1/group") -public class GroupController { - private final CommandGroupService commandGroupService; - private final JwtService jwtService; - private final QueryGroupService queryGroupService; - - @PostMapping - public ResponseEntity saveGroup(HttpServletRequest request, - @RequestBody GroupRequest groupRequest) { - Long userId = jwtService.getUserId(request); - GroupSaveResponse response = commandGroupService.createGroup(groupRequest, userId); - return ResponseEntity.ok(response); - } - - @PutMapping("/account") - public ResponseEntity updateAccount( - HttpServletRequest request, - @RequestParam("groupToken") String code, - @RequestBody GroupAccountRequest groupAccountRequest) { - Long userId = jwtService.getUserId(request); - Long groupId = queryGroupService.findIdByCode(code); - - GroupResponse response = commandGroupService.updateAccount(groupAccountRequest, userId, groupId); - return ResponseEntity.ok(response); - } - - @GetMapping - public ResponseEntity getGroup( - HttpServletRequest request, - @RequestParam("groupToken") String code) { - Long userId = jwtService.getUserId(request); - Long groupId = queryGroupService.findIdByCode(code); - - GroupDetailResponse response = queryGroupService.findOne(groupId, userId); - return ResponseEntity.ok(response); - } - - @PostMapping("/password") - public ResponseEntity isPasswordMatch( - HttpServletRequest request, - @RequestParam("groupToken") String code, - @RequestBody GroupPasswordRequest groupPasswordRequest) { - Long userId = jwtService.getUserId(request); - Long groupId = queryGroupService.findIdByCode(code); - - GroupPasswordResponse response = commandGroupService.isPasswordMatch(groupId, userId, groupPasswordRequest); - return ResponseEntity.ok(response); - } - - @GetMapping("/header") - public ResponseEntity getHeader( - @RequestParam("groupToken") String code) { - Long groupId = queryGroupService.findIdByCode(code); - - GroupHeaderResponse response = queryGroupService.findByGroupHeader(groupId); - return ResponseEntity.ok(response); - } - - @GetMapping("/header/no-cache") - public ResponseEntity getHeaderNoCache( - @RequestParam("groupToken") String code) { - Long groupId = queryGroupService.findIdByCodeNoCache(code); - - GroupHeaderResponse response = queryGroupService.findByGroupHeader(groupId); - return ResponseEntity.ok(response); - } -} diff --git a/src/main/java/com/dnd/moddo/domain/group/dto/request/GroupAccountRequest.java b/src/main/java/com/dnd/moddo/domain/group/dto/request/GroupAccountRequest.java deleted file mode 100644 index 272de19..0000000 --- a/src/main/java/com/dnd/moddo/domain/group/dto/request/GroupAccountRequest.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.dnd.moddo.domain.group.dto.request; - -public record GroupAccountRequest( - String bank, - - String accountNumber -) { -} diff --git a/src/main/java/com/dnd/moddo/domain/group/dto/request/GroupPasswordRequest.java b/src/main/java/com/dnd/moddo/domain/group/dto/request/GroupPasswordRequest.java deleted file mode 100644 index 0f97bf7..0000000 --- a/src/main/java/com/dnd/moddo/domain/group/dto/request/GroupPasswordRequest.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.dnd.moddo.domain.group.dto.request; - -public record GroupPasswordRequest( - String password -) { -} diff --git a/src/main/java/com/dnd/moddo/domain/group/dto/response/GroupDetailResponse.java b/src/main/java/com/dnd/moddo/domain/group/dto/response/GroupDetailResponse.java deleted file mode 100644 index ec8bad6..0000000 --- a/src/main/java/com/dnd/moddo/domain/group/dto/response/GroupDetailResponse.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.dnd.moddo.domain.group.dto.response; - -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.groupMember.dto.response.GroupMemberResponse; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; - -import java.util.List; -import java.util.stream.Collectors; - -public record GroupDetailResponse( - Long id, - String groupName, - List members -) { - public static GroupDetailResponse of(Group group, List members) { - List memberResponses = members.stream() - .map(GroupMemberResponse::of) - .collect(Collectors.toList()); - return new GroupDetailResponse( - group.getId(), - group.getName(), - memberResponses - ); - } -} diff --git a/src/main/java/com/dnd/moddo/domain/group/dto/response/GroupHeaderResponse.java b/src/main/java/com/dnd/moddo/domain/group/dto/response/GroupHeaderResponse.java deleted file mode 100644 index ac9a5ad..0000000 --- a/src/main/java/com/dnd/moddo/domain/group/dto/response/GroupHeaderResponse.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.dnd.moddo.domain.group.dto.response; - -import java.time.LocalDateTime; - -public record GroupHeaderResponse( - String groupName, - Long totalAmount, - LocalDateTime deadline, - String bank, - String accountNumber -) { - public static GroupHeaderResponse of(String groupName, Long totalAmount, LocalDateTime deadline, String bank, String accountNumber) { - return new GroupHeaderResponse(groupName, totalAmount, deadline, bank, accountNumber); - } -} diff --git a/src/main/java/com/dnd/moddo/domain/group/dto/response/GroupPasswordResponse.java b/src/main/java/com/dnd/moddo/domain/group/dto/response/GroupPasswordResponse.java deleted file mode 100644 index 0eb976e..0000000 --- a/src/main/java/com/dnd/moddo/domain/group/dto/response/GroupPasswordResponse.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.dnd.moddo.domain.group.dto.response; - -public record GroupPasswordResponse( - String status -) { - public static GroupPasswordResponse from(String status) { - return new GroupPasswordResponse(status); - } -} diff --git a/src/main/java/com/dnd/moddo/domain/group/dto/response/GroupResponse.java b/src/main/java/com/dnd/moddo/domain/group/dto/response/GroupResponse.java deleted file mode 100644 index 9287db4..0000000 --- a/src/main/java/com/dnd/moddo/domain/group/dto/response/GroupResponse.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.dnd.moddo.domain.group.dto.response; - -import java.time.LocalDateTime; - -import com.dnd.moddo.domain.group.entity.Group; - -public record GroupResponse( - Long id, - Long writer, - LocalDateTime createdAt, - LocalDateTime expiredAt, - String bank, - String accountNumber, - LocalDateTime deadline -) { - public static GroupResponse of(Group group) { - return new GroupResponse( - group.getId(), - group.getWriter(), - group.getCreatedAt(), - group.getExpiredAt(), - group.getBank(), - group.getAccountNumber(), - group.getDeadline() - ); - } -} diff --git a/src/main/java/com/dnd/moddo/domain/group/dto/response/GroupSaveResponse.java b/src/main/java/com/dnd/moddo/domain/group/dto/response/GroupSaveResponse.java deleted file mode 100644 index 2333207..0000000 --- a/src/main/java/com/dnd/moddo/domain/group/dto/response/GroupSaveResponse.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.dnd.moddo.domain.group.dto.response; - -import com.dnd.moddo.domain.groupMember.dto.response.GroupMemberResponse; - -public record GroupSaveResponse( - String groupToken, - GroupMemberResponse manager -) { -} diff --git a/src/main/java/com/dnd/moddo/domain/group/exception/GroupNotAuthorException.java b/src/main/java/com/dnd/moddo/domain/group/exception/GroupNotAuthorException.java deleted file mode 100644 index b449716..0000000 --- a/src/main/java/com/dnd/moddo/domain/group/exception/GroupNotAuthorException.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.dnd.moddo.domain.group.exception; - -import com.dnd.moddo.global.exception.ModdoException; -import org.springframework.http.HttpStatus; - -public class GroupNotAuthorException extends ModdoException { - public GroupNotAuthorException() { - super(HttpStatus.FORBIDDEN, "모임 작성자가 아닙니다."); - } -} diff --git a/src/main/java/com/dnd/moddo/domain/group/exception/InvalidPasswordException.java b/src/main/java/com/dnd/moddo/domain/group/exception/InvalidPasswordException.java deleted file mode 100644 index 850711b..0000000 --- a/src/main/java/com/dnd/moddo/domain/group/exception/InvalidPasswordException.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.dnd.moddo.domain.group.exception; - -import com.dnd.moddo.global.exception.ModdoException; -import org.springframework.http.HttpStatus; - -public class InvalidPasswordException extends ModdoException { - public InvalidPasswordException() { - super(HttpStatus.BAD_REQUEST, "비밀번호가 틀렸습니다."); - } -} diff --git a/src/main/java/com/dnd/moddo/domain/group/service/CommandGroupService.java b/src/main/java/com/dnd/moddo/domain/group/service/CommandGroupService.java deleted file mode 100644 index ac7ff9d..0000000 --- a/src/main/java/com/dnd/moddo/domain/group/service/CommandGroupService.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.dnd.moddo.domain.group.service; - -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import com.dnd.moddo.domain.group.dto.request.GroupAccountRequest; -import com.dnd.moddo.domain.group.dto.request.GroupPasswordRequest; -import com.dnd.moddo.domain.group.dto.request.GroupRequest; -import com.dnd.moddo.domain.group.dto.response.GroupPasswordResponse; -import com.dnd.moddo.domain.group.dto.response.GroupResponse; -import com.dnd.moddo.domain.group.dto.response.GroupSaveResponse; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.service.implementation.GroupCreator; -import com.dnd.moddo.domain.group.service.implementation.GroupReader; -import com.dnd.moddo.domain.group.service.implementation.GroupUpdater; -import com.dnd.moddo.domain.group.service.implementation.GroupValidator; -import com.dnd.moddo.domain.groupMember.dto.response.GroupMemberResponse; -import com.dnd.moddo.domain.groupMember.service.CommandGroupMemberService; -import com.dnd.moddo.global.jwt.utill.JwtProvider; - -import lombok.RequiredArgsConstructor; - -@Service -@RequiredArgsConstructor -@Transactional -public class CommandGroupService { - private final GroupCreator groupCreator; - private final GroupUpdater groupUpdater; - private final GroupValidator groupValidator; - private final GroupReader groupReader; - private final JwtProvider jwtProvider; - private final CommandGroupMemberService commandGroupMemberService; - - public GroupSaveResponse createGroup(GroupRequest request, Long userId) { - Group group = groupCreator.createGroup(request, userId); - GroupMemberResponse manager = commandGroupMemberService.createManager(group, userId); - return new GroupSaveResponse(group.getCode(), manager); - } - - public GroupResponse updateAccount(GroupAccountRequest request, Long userId, Long groupId) { - Group group = groupReader.read(groupId); - groupValidator.checkGroupAuthor(group, userId); - group = groupUpdater.updateAccount(request, group.getId()); - return GroupResponse.of(group); - } - - public GroupPasswordResponse isPasswordMatch(Long groupId, Long userId, GroupPasswordRequest request) { - Group group = groupReader.read(groupId); - groupValidator.checkGroupAuthor(group, userId); - GroupPasswordResponse response = groupValidator.checkGroupPassword(request, group.getPassword()); - return response; - } -} diff --git a/src/main/java/com/dnd/moddo/domain/group/service/QueryGroupService.java b/src/main/java/com/dnd/moddo/domain/group/service/QueryGroupService.java deleted file mode 100644 index f0d7d83..0000000 --- a/src/main/java/com/dnd/moddo/domain/group/service/QueryGroupService.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.dnd.moddo.domain.group.service; - -import java.util.List; - -import org.springframework.cache.annotation.Cacheable; -import org.springframework.stereotype.Service; - -import com.dnd.moddo.domain.group.dto.response.GroupDetailResponse; -import com.dnd.moddo.domain.group.dto.response.GroupHeaderResponse; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.service.implementation.GroupReader; -import com.dnd.moddo.domain.group.service.implementation.GroupValidator; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; - -import lombok.RequiredArgsConstructor; - -@Service -@RequiredArgsConstructor -public class QueryGroupService { - private final GroupReader groupReader; - private final GroupValidator groupValidator; - - public GroupDetailResponse findOne(Long groupId, Long userId) { - Group group = groupReader.read(groupId); - groupValidator.checkGroupAuthor(group, userId); - List members = groupReader.findByGroup(groupId); - return GroupDetailResponse.of(group, members); - } - - public GroupHeaderResponse findByGroupHeader(Long groupId) { - return groupReader.findByHeader(groupId); - } - - @Cacheable(cacheNames = "groups", key = "#code") - public Long findIdByCode(String code) { - return groupReader.findIdByGroupCode(code); - } - - public Long findIdByCodeNoCache(String code) { - return groupReader.findIdByGroupCode(code); - } -} diff --git a/src/main/java/com/dnd/moddo/domain/group/service/implementation/GroupReader.java b/src/main/java/com/dnd/moddo/domain/group/service/implementation/GroupReader.java deleted file mode 100644 index 13b9727..0000000 --- a/src/main/java/com/dnd/moddo/domain/group/service/implementation/GroupReader.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.dnd.moddo.domain.group.service.implementation; - -import java.util.List; - -import org.springframework.stereotype.Service; - -import com.dnd.moddo.domain.expense.repository.ExpenseRepository; -import com.dnd.moddo.domain.group.dto.response.GroupHeaderResponse; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.repository.GroupRepository; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.repository.GroupMemberRepository; - -import lombok.RequiredArgsConstructor; - -@Service -@RequiredArgsConstructor -public class GroupReader { - private final GroupRepository groupRepository; - private final GroupMemberRepository groupMemberRepository; - private final ExpenseRepository expenseRepository; - - public Group read(Long groupId) { - return groupRepository.getById(groupId); - } - - public List findByGroup(Long groupId) { - return groupMemberRepository.findByGroupId(groupId); - } - - public GroupHeaderResponse findByHeader(Long groupId) { - Group group = groupRepository.getById(groupId); - Long totalAmount = expenseRepository.sumAmountByGroup(group); - - return GroupHeaderResponse.of(group.getName(), totalAmount, group.getDeadline(), group.getBank(), - group.getAccountNumber()); - } - - public Long findIdByGroupCode(String code) { - return groupRepository.getIdByCode(code); - } -} diff --git a/src/main/java/com/dnd/moddo/domain/group/service/implementation/GroupUpdater.java b/src/main/java/com/dnd/moddo/domain/group/service/implementation/GroupUpdater.java deleted file mode 100644 index 70714dc..0000000 --- a/src/main/java/com/dnd/moddo/domain/group/service/implementation/GroupUpdater.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.dnd.moddo.domain.group.service.implementation; - -import com.dnd.moddo.domain.group.dto.request.GroupAccountRequest; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.repository.GroupRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional -@RequiredArgsConstructor -public class GroupUpdater { - private final GroupRepository groupRepository; - - public Group updateAccount(GroupAccountRequest request, Long groupId) { - Group group = groupRepository.getById(groupId); - group.updateAccount(request); - return group; - } -} diff --git a/src/main/java/com/dnd/moddo/domain/group/service/implementation/GroupValidator.java b/src/main/java/com/dnd/moddo/domain/group/service/implementation/GroupValidator.java deleted file mode 100644 index 69069b9..0000000 --- a/src/main/java/com/dnd/moddo/domain/group/service/implementation/GroupValidator.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.dnd.moddo.domain.group.service.implementation; - -import com.dnd.moddo.domain.group.dto.request.GroupPasswordRequest; -import com.dnd.moddo.domain.group.dto.response.GroupPasswordResponse; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.exception.GroupNotAuthorException; -import com.dnd.moddo.domain.group.exception.InvalidPasswordException; -import com.dnd.moddo.domain.group.repository.GroupRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class GroupValidator { - - private final PasswordEncoder passwordEncoder; - - private final GroupRepository groupRepository; - - public void checkGroupAuthor(Group group, Long userId) { - if (!group.isWriter(userId)) { - throw new GroupNotAuthorException(); - } - } - - public GroupPasswordResponse checkGroupPassword(GroupPasswordRequest groupPasswordRequest, String getPassword) { - boolean isMatch = passwordEncoder.matches(groupPasswordRequest.password(), getPassword); - - if (!isMatch) { - throw new InvalidPasswordException(); - } - - return GroupPasswordResponse.from("확인되었습니다."); - } -} diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/controller/GroupMemberController.java b/src/main/java/com/dnd/moddo/domain/groupMember/controller/GroupMemberController.java deleted file mode 100644 index c735ed4..0000000 --- a/src/main/java/com/dnd/moddo/domain/groupMember/controller/GroupMemberController.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.dnd.moddo.domain.groupMember.controller; - -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import com.dnd.moddo.domain.group.service.QueryGroupService; -import com.dnd.moddo.domain.groupMember.dto.request.GroupMemberSaveRequest; -import com.dnd.moddo.domain.groupMember.dto.request.PaymentStatusUpdateRequest; -import com.dnd.moddo.domain.groupMember.dto.response.GroupMemberResponse; -import com.dnd.moddo.domain.groupMember.dto.response.GroupMembersResponse; -import com.dnd.moddo.domain.groupMember.service.CommandGroupMemberService; -import com.dnd.moddo.domain.groupMember.service.QueryGroupMemberService; -import com.dnd.moddo.global.common.annotation.VerifyManagerPermission; -import com.dnd.moddo.global.jwt.service.JwtService; - -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@RequestMapping("/api/v1/group-members") -@RestController -public class GroupMemberController { - private final QueryGroupMemberService queryGroupMemberService; - private final CommandGroupMemberService commandGroupMemberService; - private final JwtService jwtService; - private final QueryGroupService queryGroupService; - - @GetMapping - public ResponseEntity getGroupMembers( - @RequestParam("groupToken") String code - ) { - Long groupId = queryGroupService.findIdByCode(code); - GroupMembersResponse response = queryGroupMemberService.findAll(groupId); - return ResponseEntity.ok(response); - } - - @VerifyManagerPermission - @PutMapping - public ResponseEntity addGroupMember( - @RequestParam("groupToken") String code, - @Valid @RequestBody GroupMemberSaveRequest request - ) { - Long groupId = queryGroupService.findIdByCode(code); - GroupMemberResponse response = commandGroupMemberService.addGroupMember(groupId, request); - return ResponseEntity.ok(response); - } - - @PutMapping("/{groupMemberId}/payment") - public ResponseEntity updatePaymentStatus( - @RequestParam("groupToken") String code, - @PathVariable("groupMemberId") Long groupMemberId, - @RequestBody PaymentStatusUpdateRequest request) { - GroupMemberResponse response = commandGroupMemberService.updatePaymentStatus(groupMemberId, request); - return ResponseEntity.ok(response); - } - - @VerifyManagerPermission - @DeleteMapping("/{groupMemberId}") - public ResponseEntity deleteGroupMember( - @PathVariable("groupMemberId") Long groupMemberId - ) { - commandGroupMemberService.delete(groupMemberId); - return ResponseEntity.noContent().build(); - } - -} diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/dto/request/GroupMemberSaveRequest.java b/src/main/java/com/dnd/moddo/domain/groupMember/dto/request/GroupMemberSaveRequest.java deleted file mode 100644 index 101eada..0000000 --- a/src/main/java/com/dnd/moddo/domain/groupMember/dto/request/GroupMemberSaveRequest.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.dnd.moddo.domain.groupMember.dto.request; - -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Pattern; - -public record GroupMemberSaveRequest( - @NotBlank(message = "이름은 필수 입력값 입니다.") - @Pattern(regexp = "^[가-힣a-zA-Z]{1,5}$", message = "참여자 이름은 한글과 영어만 포함하여 5자 이내여야 합니다.") - String name -) { - public GroupMember toEntity(Group group, Integer profileId, ExpenseRole role) { - return GroupMember.builder() - .name(name) - .group(group) - .role(role) - .profileId(profileId) - .isPaid(false) - .build(); - } -} diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/dto/request/GroupMembersSaveRequest.java b/src/main/java/com/dnd/moddo/domain/groupMember/dto/request/GroupMembersSaveRequest.java deleted file mode 100644 index 12ce8e7..0000000 --- a/src/main/java/com/dnd/moddo/domain/groupMember/dto/request/GroupMembersSaveRequest.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.dnd.moddo.domain.groupMember.dto.request; - -import static com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole.*; - -import java.util.List; - -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; - -import jakarta.validation.Valid; - -public record GroupMembersSaveRequest( - @Valid List members -) { - public List toEntity(Group group) { - return members.stream() - .map(m -> m.toEntity(group, null, PARTICIPANT)) - .toList(); - } - - public List extractNames() { - return members().stream().map(GroupMemberSaveRequest::name).toList(); - } -} diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/dto/response/GroupMemberExpenseResponse.java b/src/main/java/com/dnd/moddo/domain/groupMember/dto/response/GroupMemberExpenseResponse.java deleted file mode 100644 index 434c968..0000000 --- a/src/main/java/com/dnd/moddo/domain/groupMember/dto/response/GroupMemberExpenseResponse.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.dnd.moddo.domain.groupMember.dto.response; - -import java.time.LocalDateTime; -import java.util.List; - -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; -import com.dnd.moddo.domain.memberExpense.dto.response.MemberExpenseDetailResponse; - -import lombok.Builder; - -@Builder -public record GroupMemberExpenseResponse( - Long id, - ExpenseRole role, - String name, - Long totalAmount, - String profile, - boolean isPaid, - LocalDateTime paidAt, - List expenses -) { - public static GroupMemberExpenseResponse of(GroupMember groupMember, Long totalAmount, - List expenses) { - return GroupMemberExpenseResponse.builder() - .id(groupMember.getId()) - .role(groupMember.getRole()) - .name(groupMember.getName()) - .totalAmount(totalAmount) - .profile(groupMember.getProfileUrl()) - .isPaid(groupMember.isPaid()) - .paidAt(groupMember.getPaidAt()) - .expenses(expenses).build(); - } -} diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/dto/response/GroupMemberResponse.java b/src/main/java/com/dnd/moddo/domain/groupMember/dto/response/GroupMemberResponse.java deleted file mode 100644 index 6916b60..0000000 --- a/src/main/java/com/dnd/moddo/domain/groupMember/dto/response/GroupMemberResponse.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.dnd.moddo.domain.groupMember.dto.response; - -import java.time.LocalDateTime; - -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; - -import lombok.Builder; - -@Builder -public record GroupMemberResponse( - Long id, - ExpenseRole role, - String name, - String profile, - boolean isPaid, - LocalDateTime paidAt -) { - - public static GroupMemberResponse of(GroupMember groupMember) { - return GroupMemberResponse.builder() - .id(groupMember.getId()) - .name(groupMember.getName()) - .role(groupMember.getRole()) - .isPaid(groupMember.isPaid()) - .paidAt(groupMember.getPaidAt()) - .profile(groupMember.getProfileUrl()) - .build(); - } - -} diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/dto/response/GroupMembersExpenseResponse.java b/src/main/java/com/dnd/moddo/domain/groupMember/dto/response/GroupMembersExpenseResponse.java deleted file mode 100644 index 9635334..0000000 --- a/src/main/java/com/dnd/moddo/domain/groupMember/dto/response/GroupMembersExpenseResponse.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.dnd.moddo.domain.groupMember.dto.response; - -import java.util.List; - -public record GroupMembersExpenseResponse( - List memberExpenses -) { - -} diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/dto/response/GroupMembersResponse.java b/src/main/java/com/dnd/moddo/domain/groupMember/dto/response/GroupMembersResponse.java deleted file mode 100644 index f992f05..0000000 --- a/src/main/java/com/dnd/moddo/domain/groupMember/dto/response/GroupMembersResponse.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.dnd.moddo.domain.groupMember.dto.response; - -import java.util.List; - -import com.dnd.moddo.domain.groupMember.entity.GroupMember; - -public record GroupMembersResponse(List members) { - public static GroupMembersResponse of(List members) { - return new GroupMembersResponse(members.stream() - .map(GroupMemberResponse::of) - .toList()); - } -} diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/exception/GroupMemberNotFoundException.java b/src/main/java/com/dnd/moddo/domain/groupMember/exception/GroupMemberNotFoundException.java deleted file mode 100644 index 803f8fc..0000000 --- a/src/main/java/com/dnd/moddo/domain/groupMember/exception/GroupMemberNotFoundException.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.dnd.moddo.domain.groupMember.exception; - -import org.springframework.http.HttpStatus; - -import com.dnd.moddo.global.exception.ModdoException; - -public class GroupMemberNotFoundException extends ModdoException { - public GroupMemberNotFoundException(Long groupMemberId) { - super(HttpStatus.NOT_FOUND, "해당 참여자를 찾을 수 없습니다. (GroupMember ID: " + groupMemberId + ")"); - } -} diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/repository/GroupMemberRepository.java b/src/main/java/com/dnd/moddo/domain/groupMember/repository/GroupMemberRepository.java deleted file mode 100644 index d12534d..0000000 --- a/src/main/java/com/dnd/moddo/domain/groupMember/repository/GroupMemberRepository.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.dnd.moddo.domain.groupMember.repository; - -import java.util.List; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; - -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.exception.GroupMemberNotFoundException; - -public interface GroupMemberRepository extends JpaRepository { - - @Query("select gm from GroupMember gm where gm.group.id = :groupId order by " - + "case when gm.role = 'MANAGER' then 1 else 2 end, " - + "case when gm.paidAt is null then 1 else 0 end, " - + "gm.paidAt asc, " - + "gm.name asc") - List findByGroupId(@Param("groupId") Long groupId); - - @Query("select gm.id from GroupMember gm where gm.group.id = :groupId") - List findGroupMemberIdsByGroupId(@Param("groupId") Long groupId); - - default GroupMember getById(Long id) { - return findById(id) - .orElseThrow(() -> new GroupMemberNotFoundException(id)); - } -} diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/service/CommandGroupMemberService.java b/src/main/java/com/dnd/moddo/domain/groupMember/service/CommandGroupMemberService.java deleted file mode 100644 index 948580b..0000000 --- a/src/main/java/com/dnd/moddo/domain/groupMember/service/CommandGroupMemberService.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.dnd.moddo.domain.groupMember.service; - -import org.springframework.stereotype.Service; - -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.groupMember.dto.request.GroupMemberSaveRequest; -import com.dnd.moddo.domain.groupMember.dto.request.PaymentStatusUpdateRequest; -import com.dnd.moddo.domain.groupMember.dto.response.GroupMemberResponse; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.service.implementation.GroupMemberCreator; -import com.dnd.moddo.domain.groupMember.service.implementation.GroupMemberDeleter; -import com.dnd.moddo.domain.groupMember.service.implementation.GroupMemberUpdater; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Service -public class CommandGroupMemberService { - private final GroupMemberCreator groupMemberCreator; - private final GroupMemberUpdater groupMemberUpdater; - private final GroupMemberDeleter groupMemberDeleter; - - public GroupMemberResponse createManager(Group group, Long userId) { - GroupMember groupMember = groupMemberCreator.createManagerForGroup(group, userId); - return GroupMemberResponse.of(groupMember); - } - - public GroupMemberResponse addGroupMember(Long groupId, GroupMemberSaveRequest request) { - GroupMember groupMember = groupMemberUpdater.addToGroup(groupId, request); - return GroupMemberResponse.of(groupMember); - } - - public GroupMemberResponse updatePaymentStatus(Long groupMemberId, PaymentStatusUpdateRequest request) { - GroupMember groupMember = groupMemberUpdater.updatePaymentStatus(groupMemberId, request); - return GroupMemberResponse.of(groupMember); - } - - public void delete(Long groupMemberId) { - groupMemberDeleter.delete(groupMemberId); - } - -} diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/service/QueryGroupMemberService.java b/src/main/java/com/dnd/moddo/domain/groupMember/service/QueryGroupMemberService.java deleted file mode 100644 index 1b3d381..0000000 --- a/src/main/java/com/dnd/moddo/domain/groupMember/service/QueryGroupMemberService.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.dnd.moddo.domain.groupMember.service; - -import java.util.List; - -import org.springframework.stereotype.Service; - -import com.dnd.moddo.domain.groupMember.dto.response.GroupMembersResponse; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.service.implementation.GroupMemberReader; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Service -public class QueryGroupMemberService { - private final GroupMemberReader groupMemberReader; - - public GroupMembersResponse findAll(Long groupId) { - List members = groupMemberReader.findAllByGroupId(groupId); - return GroupMembersResponse.of(members); - } -} diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberCreator.java b/src/main/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberCreator.java deleted file mode 100644 index 8f22540..0000000 --- a/src/main/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberCreator.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.dnd.moddo.domain.groupMember.service.implementation; - -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; -import com.dnd.moddo.domain.groupMember.repository.GroupMemberRepository; -import com.dnd.moddo.domain.user.entity.User; -import com.dnd.moddo.domain.user.repository.UserRepository; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Service -@Transactional -public class GroupMemberCreator { - private final GroupMemberRepository groupMemberRepository; - private final UserRepository userRepository; - - public GroupMember createManagerForGroup(Group group, Long userId) { - User user = userRepository.getById(userId); - - String name = user.getIsMember() ? user.getName() : "김모또"; - - GroupMember groupMember = GroupMember.builder() - .name(name) - .group(group) - .profileId(null) - .profileId(0) - .role(ExpenseRole.MANAGER) - .build(); - - groupMember.updatePaymentStatus(true); - - return groupMemberRepository.save(groupMember); - } -} diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberDeleter.java b/src/main/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberDeleter.java deleted file mode 100644 index c2db2bc..0000000 --- a/src/main/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberDeleter.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.dnd.moddo.domain.groupMember.service.implementation; - -import org.springframework.stereotype.Service; - -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.exception.ManagerCannotDeleteException; -import com.dnd.moddo.domain.groupMember.repository.GroupMemberRepository; - -import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; - -@Service -@RequiredArgsConstructor -@Transactional -public class GroupMemberDeleter { - private final GroupMemberRepository groupMemberRepository; - private final GroupMemberReader groupMemberReader; - - public void delete(Long groupMemberId) { - GroupMember groupMember = groupMemberReader.findByGroupMemberId(groupMemberId); - if (groupMember.isManager()) { - throw new ManagerCannotDeleteException(groupMemberId); - } - groupMemberRepository.delete(groupMember); - } -} diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberReader.java b/src/main/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberReader.java deleted file mode 100644 index b82a70a..0000000 --- a/src/main/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberReader.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.dnd.moddo.domain.groupMember.service.implementation; - -import java.util.List; - -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.repository.GroupMemberRepository; - -import lombok.RequiredArgsConstructor; - -@Service -@RequiredArgsConstructor -@Transactional(readOnly = true) -public class GroupMemberReader { - private final GroupMemberRepository groupMemberRepository; - - public List findAllByGroupId(Long groupId) { - return groupMemberRepository.findByGroupId(groupId); - } - - public GroupMember findByGroupMemberId(Long groupMemberId) { - return groupMemberRepository.getById(groupMemberId); - } - - public List findIdsByGroupId(Long groupId) { - return groupMemberRepository.findGroupMemberIdsByGroupId(groupId); - } - -} diff --git a/src/main/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberUpdater.java b/src/main/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberUpdater.java deleted file mode 100644 index bd94f9c..0000000 --- a/src/main/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberUpdater.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.dnd.moddo.domain.groupMember.service.implementation; - -import java.util.ArrayList; -import java.util.List; - -import org.springframework.dao.OptimisticLockingFailureException; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Isolation; -import org.springframework.transaction.annotation.Transactional; - -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.service.implementation.GroupReader; -import com.dnd.moddo.domain.groupMember.dto.request.GroupMemberSaveRequest; -import com.dnd.moddo.domain.groupMember.dto.request.PaymentStatusUpdateRequest; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; -import com.dnd.moddo.domain.groupMember.exception.PaymentConcurrencyException; -import com.dnd.moddo.domain.groupMember.repository.GroupMemberRepository; - -import lombok.RequiredArgsConstructor; - -@Service -@RequiredArgsConstructor -public class GroupMemberUpdater { - private final GroupMemberRepository groupMemberRepository; - private final GroupMemberReader groupMemberReader; - private final GroupMemberValidator groupMemberValidator; - private final GroupReader groupReader; - - @Transactional - public GroupMember addToGroup(Long groupId, GroupMemberSaveRequest request) { - Group group = groupReader.read(groupId); - List groupMembers = groupMemberReader.findAllByGroupId(groupId); - - List existingNames = new ArrayList<>(groupMembers.stream().map(GroupMember::getName).toList()); - existingNames.add(request.name()); - - groupMemberValidator.validateMemberNamesNotDuplicate(existingNames); - - List usedProfiles = groupMembers.stream() - .filter(member -> !member.isManager()) - .map(GroupMember::getProfileId) - .toList(); - - Integer newProfileId = findAvailableProfileId(usedProfiles); - - GroupMember newMember = request.toEntity(group, newProfileId, ExpenseRole.PARTICIPANT); - newMember = groupMemberRepository.save(newMember); - - return newMember; - } - - @Transactional(isolation = Isolation.READ_COMMITTED) - public GroupMember updatePaymentStatus(Long groupMemberId, PaymentStatusUpdateRequest request) { - try { - GroupMember groupMember = groupMemberRepository.getById(groupMemberId); - if (groupMember.isPaid() != request.isPaid()) { - groupMember.updatePaymentStatus(request.isPaid()); - groupMemberRepository.save(groupMember); - } - return groupMember; - } catch (OptimisticLockingFailureException e) { - throw new PaymentConcurrencyException(); - } - } - - private Integer findAvailableProfileId(List usedProfiles) { - for (int i = 1; i <= 8; i++) { - if (!usedProfiles.contains(i)) { - return i; - } - } - - return (usedProfiles.size() % 8) + 1; - } -} - - - diff --git a/src/main/java/com/dnd/moddo/domain/image/service/implementation/ImageReader.java b/src/main/java/com/dnd/moddo/domain/image/service/implementation/ImageReader.java index b9aa8a3..9dcd0a0 100644 --- a/src/main/java/com/dnd/moddo/domain/image/service/implementation/ImageReader.java +++ b/src/main/java/com/dnd/moddo/domain/image/service/implementation/ImageReader.java @@ -5,7 +5,7 @@ import org.springframework.stereotype.Service; -import com.dnd.moddo.domain.group.repository.GroupRepository; +import com.dnd.moddo.domain.settlement.repository.SettlementRepository; import com.dnd.moddo.domain.image.dto.CharacterResponse; import com.dnd.moddo.domain.image.entity.type.Characters; import com.dnd.moddo.domain.image.exception.CharacterNotFoundException; @@ -18,7 +18,7 @@ public class ImageReader { private final S3Bucket s3Bucket; - private final GroupRepository groupRepository; + private final SettlementRepository settlementRepository; public CharacterResponse getRandomCharacter() { int rarity = getRandomRarity(); diff --git a/src/main/java/com/dnd/moddo/domain/memberExpense/controller/MemberExpenseController.java b/src/main/java/com/dnd/moddo/domain/memberExpense/controller/MemberExpenseController.java index 21ff268..85dcfc0 100644 --- a/src/main/java/com/dnd/moddo/domain/memberExpense/controller/MemberExpenseController.java +++ b/src/main/java/com/dnd/moddo/domain/memberExpense/controller/MemberExpenseController.java @@ -6,9 +6,9 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import com.dnd.moddo.domain.group.service.QueryGroupService; -import com.dnd.moddo.domain.groupMember.dto.response.GroupMembersExpenseResponse; +import com.dnd.moddo.domain.appointmentMember.dto.response.AppointmentMembersExpenseResponse; import com.dnd.moddo.domain.memberExpense.service.QueryMemberExpenseService; +import com.dnd.moddo.domain.settlement.service.QuerySettlementService; import com.dnd.moddo.global.jwt.service.JwtService; import lombok.RequiredArgsConstructor; @@ -19,14 +19,15 @@ public class MemberExpenseController { private final QueryMemberExpenseService queryMemberExpenseService; private final JwtService jwtService; - private final QueryGroupService queryGroupService; + private final QuerySettlementService querySettlementService; @GetMapping - public ResponseEntity getMemberExpensesDetails( + public ResponseEntity getMemberExpensesDetails( @RequestParam("groupToken") String code ) { - Long groupId = queryGroupService.findIdByCode(code); - GroupMembersExpenseResponse response = queryMemberExpenseService.findMemberExpenseDetailsByGroupId(groupId); + Long settlementId = querySettlementService.findIdByCode(code); + AppointmentMembersExpenseResponse response = queryMemberExpenseService.findMemberExpenseDetailsBySettlementId( + settlementId); return ResponseEntity.ok(response); } } diff --git a/src/main/java/com/dnd/moddo/domain/memberExpense/dto/request/MemberExpenseRequest.java b/src/main/java/com/dnd/moddo/domain/memberExpense/dto/request/MemberExpenseRequest.java index 254a07a..af087e6 100644 --- a/src/main/java/com/dnd/moddo/domain/memberExpense/dto/request/MemberExpenseRequest.java +++ b/src/main/java/com/dnd/moddo/domain/memberExpense/dto/request/MemberExpenseRequest.java @@ -1,6 +1,6 @@ package com.dnd.moddo.domain.memberExpense.dto.request; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; import com.dnd.moddo.domain.memberExpense.entity.MemberExpense; import jakarta.validation.constraints.Max; @@ -15,10 +15,10 @@ public record MemberExpenseRequest( @Positive(message = "지출내역 값은 양수여야 합니다.") @Max(value = 5_000_000, message = "지출내역 값은 최대 500만원까지 입력할 수 있습니다.") Long amount) { - public MemberExpense toEntity(Long expenseId, GroupMember groupMember) { + public MemberExpense toEntity(Long expenseId, AppointmentMember appointmentMember) { return MemberExpense.builder() .expenseId(expenseId) - .groupMember(groupMember) + .appointmentMember(appointmentMember) .amount(amount()) .build(); } diff --git a/src/main/java/com/dnd/moddo/domain/memberExpense/dto/response/MemberExpenseResponse.java b/src/main/java/com/dnd/moddo/domain/memberExpense/dto/response/MemberExpenseResponse.java index ac587dd..262f46a 100644 --- a/src/main/java/com/dnd/moddo/domain/memberExpense/dto/response/MemberExpenseResponse.java +++ b/src/main/java/com/dnd/moddo/domain/memberExpense/dto/response/MemberExpenseResponse.java @@ -1,6 +1,6 @@ package com.dnd.moddo.domain.memberExpense.dto.response; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; import com.dnd.moddo.domain.memberExpense.entity.MemberExpense; import lombok.Builder; @@ -15,10 +15,10 @@ public record MemberExpenseResponse( ) { public static MemberExpenseResponse of(MemberExpense memberExpense) { return MemberExpenseResponse.builder() - .id(memberExpense.getGroupMember().getId()) - .name(memberExpense.getGroupMember().getName()) - .role(memberExpense.getGroupMember().getRole()) - .profile(memberExpense.getGroupMember().getProfileUrl()) + .id(memberExpense.getAppointmentMember().getId()) + .name(memberExpense.getAppointmentMember().getName()) + .role(memberExpense.getAppointmentMember().getRole()) + .profile(memberExpense.getAppointmentMember().getProfileUrl()) .amount(memberExpense.getAmount()) .build(); } diff --git a/src/main/java/com/dnd/moddo/domain/memberExpense/entity/MemberExpense.java b/src/main/java/com/dnd/moddo/domain/memberExpense/entity/MemberExpense.java index 8b6f343..0137436 100644 --- a/src/main/java/com/dnd/moddo/domain/memberExpense/entity/MemberExpense.java +++ b/src/main/java/com/dnd/moddo/domain/memberExpense/entity/MemberExpense.java @@ -1,6 +1,6 @@ package com.dnd.moddo.domain.memberExpense.entity; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -29,15 +29,15 @@ public class MemberExpense { private Long expenseId; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "group_member_id") - private GroupMember groupMember; + @JoinColumn(name = "appointment_member_id") + private AppointmentMember appointmentMember; private Long amount; @Builder - public MemberExpense(Long expenseId, GroupMember groupMember, Long amount) { + public MemberExpense(Long expenseId, AppointmentMember appointmentMember, Long amount) { this.expenseId = expenseId; - this.groupMember = groupMember; + this.appointmentMember = appointmentMember; this.amount = amount; } diff --git a/src/main/java/com/dnd/moddo/domain/memberExpense/repotiroy/MemberExpenseRepository.java b/src/main/java/com/dnd/moddo/domain/memberExpense/repotiroy/MemberExpenseRepository.java index f1c8003..19f48b5 100644 --- a/src/main/java/com/dnd/moddo/domain/memberExpense/repotiroy/MemberExpenseRepository.java +++ b/src/main/java/com/dnd/moddo/domain/memberExpense/repotiroy/MemberExpenseRepository.java @@ -15,6 +15,6 @@ public interface MemberExpenseRepository extends JpaRepository findAllByExpenseIds(@Param("expenseIds") List expenseIds); - @Query("select me from MemberExpense me where me.groupMember.id in :groupMemberIds") - List findAllByGroupMemberIds(@Param("groupMemberIds") List groupMemberIds); + @Query("select me from MemberExpense me where me.appointmentMember.id in :appointmentMemberIds") + List findAllByAppointmentMemberIds(@Param("appointmentMemberIds") List appointmentMemberIds); } diff --git a/src/main/java/com/dnd/moddo/domain/memberExpense/service/CommandMemberExpenseService.java b/src/main/java/com/dnd/moddo/domain/memberExpense/service/CommandMemberExpenseService.java index f7c8364..6c2a11e 100644 --- a/src/main/java/com/dnd/moddo/domain/memberExpense/service/CommandMemberExpenseService.java +++ b/src/main/java/com/dnd/moddo/domain/memberExpense/service/CommandMemberExpenseService.java @@ -7,8 +7,8 @@ import org.springframework.stereotype.Service; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.service.implementation.GroupMemberReader; +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.service.implementation.AppointmentMemberReader; import com.dnd.moddo.domain.memberExpense.dto.request.MemberExpenseRequest; import com.dnd.moddo.domain.memberExpense.dto.response.MemberExpenseResponse; import com.dnd.moddo.domain.memberExpense.entity.MemberExpense; @@ -22,7 +22,7 @@ @Service @RequiredArgsConstructor public class CommandMemberExpenseService { - private final GroupMemberReader groupMemberReader; + private final AppointmentMemberReader appointmentMemberReader; private final MemberExpenseCreator memberExpenseCreator; private final MemberExpenseReader memberExpenseReader; private final MemberExpenseUpdater memberExpenseUpdater; @@ -31,8 +31,8 @@ public class CommandMemberExpenseService { public List create(Long expenseId, List request) { return request.stream() .map(m -> { - GroupMember groupMember = groupMemberReader.findByGroupMemberId(m.id()); - return MemberExpenseResponse.of(memberExpenseCreator.create(expenseId, groupMember, m)); + AppointmentMember appointmentMember = appointmentMemberReader.findByAppointmentMemberId(m.id()); + return MemberExpenseResponse.of(memberExpenseCreator.create(expenseId, appointmentMember, m)); }).toList(); } @@ -42,7 +42,7 @@ public List update(Long expenseId, List memberExpenses = memberExpenseReader.findAllByExpenseId(expenseId); Map existingMemberExpenses = memberExpenses.stream() - .collect(Collectors.toMap(me -> me.getGroupMember().getId(), me -> me)); + .collect(Collectors.toMap(me -> me.getAppointmentMember().getId(), me -> me)); //2. 기존에 있던 멤버가 요청에 없는 경우 삭제한다. deleteNonIncludedMemberExpenses(requests, memberExpenses); @@ -57,18 +57,19 @@ private MemberExpenseResponse handleMemberExpenseUpdateOrCreate(Long expenseId, Map existingMemberExpenses, MemberExpenseRequest request) { - Long groupMemberId = request.id(); + Long appointmentMemberId = request.id(); MemberExpenseResponse response; - if (existingMemberExpenses.containsKey(groupMemberId)) { + if (existingMemberExpenses.containsKey(appointmentMemberId)) { // 1. 기존 멤버가 있으면 업데이트 - MemberExpense existingMemberExpense = existingMemberExpenses.get(groupMemberId); + MemberExpense existingMemberExpense = existingMemberExpenses.get(appointmentMemberId); memberExpenseUpdater.update(existingMemberExpense, request); response = MemberExpenseResponse.of(existingMemberExpense); } else { // 2. 없는 멤버면 추가 - GroupMember groupMember = groupMemberReader.findByGroupMemberId(groupMemberId); - MemberExpense newMemberExpense = memberExpenseCreator.create(expenseId, groupMember, request); + AppointmentMember appointmentMember = appointmentMemberReader.findByAppointmentMemberId( + appointmentMemberId); + MemberExpense newMemberExpense = memberExpenseCreator.create(expenseId, appointmentMember, request); response = MemberExpenseResponse.of(newMemberExpense); } @@ -84,7 +85,7 @@ private void deleteNonIncludedMemberExpenses(List requests //2. 멤버별 지출내역중 요청된 멤버 id에 포함되지 않는 지출내역을 찾는다. List deleteMemberExpenses = memberExpenses.stream() - .filter(me -> !requestMemberIds.contains(me.getGroupMember().getId())) + .filter(me -> !requestMemberIds.contains(me.getAppointmentMember().getId())) .toList(); memberExpenseDeleter.deleteByMemberExpenses(deleteMemberExpenses); diff --git a/src/main/java/com/dnd/moddo/domain/memberExpense/service/QueryMemberExpenseService.java b/src/main/java/com/dnd/moddo/domain/memberExpense/service/QueryMemberExpenseService.java index 8c7fbf1..146ea58 100644 --- a/src/main/java/com/dnd/moddo/domain/memberExpense/service/QueryMemberExpenseService.java +++ b/src/main/java/com/dnd/moddo/domain/memberExpense/service/QueryMemberExpenseService.java @@ -9,12 +9,12 @@ import org.springframework.stereotype.Service; +import com.dnd.moddo.domain.appointmentMember.dto.response.AppointmentMemberExpenseResponse; +import com.dnd.moddo.domain.appointmentMember.dto.response.AppointmentMembersExpenseResponse; +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.service.implementation.AppointmentMemberReader; import com.dnd.moddo.domain.expense.entity.Expense; import com.dnd.moddo.domain.expense.service.implementation.ExpenseReader; -import com.dnd.moddo.domain.groupMember.dto.response.GroupMemberExpenseResponse; -import com.dnd.moddo.domain.groupMember.dto.response.GroupMembersExpenseResponse; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.service.implementation.GroupMemberReader; import com.dnd.moddo.domain.memberExpense.dto.response.MemberExpenseDetailResponse; import com.dnd.moddo.domain.memberExpense.dto.response.MemberExpenseResponse; import com.dnd.moddo.domain.memberExpense.entity.MemberExpense; @@ -26,7 +26,7 @@ @RequiredArgsConstructor public class QueryMemberExpenseService { private final MemberExpenseReader memberExpenseReader; - private final GroupMemberReader groupMemberReader; + private final AppointmentMemberReader appointmentMemberReader; private final ExpenseReader expenseReader; public List findAllByExpenseId(Long expenseId) { @@ -36,49 +36,51 @@ public List findAllByExpenseId(Long expenseId) { .toList(); } - public GroupMembersExpenseResponse findMemberExpenseDetailsByGroupId(Long groupId) { - List groupMembers = groupMemberReader.findAllByGroupId(groupId); + public AppointmentMembersExpenseResponse findMemberExpenseDetailsBySettlementId(Long settlementId) { + List appointmentMembers = appointmentMemberReader.findAllBySettlementId(settlementId); - Map groupMemberById = convertGroupMembersToMap(groupMembers); + Map appointmentMemberById = convertAppointmentMembersToMap(appointmentMembers); - Map> memberExpenses = memberExpenseReader.findAllByGroupMemberIds( - groupMemberById.keySet().stream().toList()) + Map> memberExpenses = memberExpenseReader.findAllByAppointMemberIds( + appointmentMemberById.keySet().stream().toList()) .stream() - .collect(Collectors.groupingBy(me -> me.getGroupMember().getId())); + .collect(Collectors.groupingBy(me -> me.getAppointmentMember().getId())); ; - List expenses = expenseReader.findAllByGroupId(groupId); + List expenses = expenseReader.findAllBySettlementId(settlementId); - List responses = groupMemberById.keySet() + List responses = appointmentMemberById.keySet() .stream() .map( - key -> findMemberExpenseDetailByGroupMember(groupMemberById.get(key), memberExpenses.get(key), expenses) + key -> findMemberExpenseDetailByAppointmentMember(appointmentMemberById.get(key), + memberExpenses.get(key), + expenses) ) .filter(Objects::nonNull) .toList(); - return new GroupMembersExpenseResponse(responses); + return new AppointmentMembersExpenseResponse(responses); } - private Map convertGroupMembersToMap(List groupMembers) { - return groupMembers.stream() - .collect(Collectors.toMap(GroupMember::getId, groupMember -> groupMember, + private Map convertAppointmentMembersToMap(List appointmentMembers) { + return appointmentMembers.stream() + .collect(Collectors.toMap(AppointmentMember::getId, appointmentMember -> appointmentMember, (existing, replacement) -> existing, LinkedHashMap::new) ); } - private GroupMemberExpenseResponse findMemberExpenseDetailByGroupMember( - GroupMember groupMember, List memberExpenses, List expenses) { + private AppointmentMemberExpenseResponse findMemberExpenseDetailByAppointmentMember( + AppointmentMember appointmentMember, List memberExpenses, List expenses) { if (memberExpenses == null) { - return GroupMemberExpenseResponse.of(groupMember, 0L, new ArrayList<>()); + return AppointmentMemberExpenseResponse.of(appointmentMember, 0L, new ArrayList<>()); } List memberExpenseDetails = mapToMemberExpenseDetails(memberExpenses, expenses); Long totalAmount = calculateTotalAmount(memberExpenses); - return GroupMemberExpenseResponse.of(groupMember, totalAmount, memberExpenseDetails); + return AppointmentMemberExpenseResponse.of(appointmentMember, totalAmount, memberExpenseDetails); } private Long calculateTotalAmount(List memberExpenses) { @@ -113,7 +115,7 @@ public Map> getMemberNamesByExpenseIds(List expenseIds) } private String formatMemberName(MemberExpense me) { - String name = me.getGroupMember().getName(); - return me.getGroupMember().isManager() ? name + "(총무)" : name; + String name = me.getAppointmentMember().getName(); + return me.getAppointmentMember().isManager() ? name + "(총무)" : name; } } diff --git a/src/main/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseCreator.java b/src/main/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseCreator.java index 19422a9..4ed0507 100644 --- a/src/main/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseCreator.java +++ b/src/main/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseCreator.java @@ -3,7 +3,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; import com.dnd.moddo.domain.memberExpense.dto.request.MemberExpenseRequest; import com.dnd.moddo.domain.memberExpense.entity.MemberExpense; import com.dnd.moddo.domain.memberExpense.repotiroy.MemberExpenseRepository; @@ -16,8 +16,9 @@ public class MemberExpenseCreator { private final MemberExpenseRepository memberExpenseRepository; - public MemberExpense create(Long expenseId, GroupMember groupMember, MemberExpenseRequest memberExpenseRequest) { - MemberExpense memberExpense = memberExpenseRequest.toEntity(expenseId, groupMember); + public MemberExpense create(Long expenseId, AppointmentMember appointmentMember, + MemberExpenseRequest memberExpenseRequest) { + MemberExpense memberExpense = memberExpenseRequest.toEntity(expenseId, appointmentMember); return memberExpenseRepository.save(memberExpense); } } diff --git a/src/main/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseReader.java b/src/main/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseReader.java index 3d43748..7760765 100644 --- a/src/main/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseReader.java +++ b/src/main/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseReader.java @@ -20,8 +20,8 @@ public List findAllByExpenseId(Long expenseId) { return memberExpenseRepository.findByExpenseId(expenseId); } - public List findAllByGroupMemberIds(List groupMemberIds) { - return memberExpenseRepository.findAllByGroupMemberIds(groupMemberIds); + public List findAllByAppointMemberIds(List appointMemberIds) { + return memberExpenseRepository.findAllByAppointmentMemberIds(appointMemberIds); } public List findAllByExpenseIds(List expenseIds) { diff --git a/src/main/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseValidator.java b/src/main/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseValidator.java index ba6479d..887807d 100644 --- a/src/main/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseValidator.java +++ b/src/main/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseValidator.java @@ -6,8 +6,8 @@ import org.springframework.stereotype.Component; -import com.dnd.moddo.domain.groupMember.exception.InvalidGroupMemberException; -import com.dnd.moddo.domain.groupMember.service.implementation.GroupMemberReader; +import com.dnd.moddo.domain.appointmentMember.exception.InvalidAppointmentMemberException; +import com.dnd.moddo.domain.appointmentMember.service.implementation.AppointmentMemberReader; import com.dnd.moddo.domain.memberExpense.dto.request.MemberExpenseRequest; import lombok.RequiredArgsConstructor; @@ -15,17 +15,18 @@ @RequiredArgsConstructor @Component public class MemberExpenseValidator { - private final GroupMemberReader groupMemberReader; + private final AppointmentMemberReader appointmentMemberReader; - public void validateMembersArePartOfGroup(Long groupId, List requests) { - Set validGroupMemberIds = new HashSet<>(groupMemberReader.findIdsByGroupId(groupId)); - List requestedGroupMemberIds = requests.stream() + public void validateMembersArePartOfSettlement(Long settlementId, List requests) { + Set validAppointmentMemberIds = new HashSet<>( + appointmentMemberReader.findIdsBySettlementId(settlementId)); + List requestedAppointmentMemberIds = requests.stream() .map(MemberExpenseRequest::id) .toList(); - requestedGroupMemberIds.forEach(id -> { - if (!validGroupMemberIds.contains(id)) { - throw new InvalidGroupMemberException(id); + requestedAppointmentMemberIds.forEach(id -> { + if (!validAppointmentMemberIds.contains(id)) { + throw new InvalidAppointmentMemberException(id); } }); diff --git a/src/main/java/com/dnd/moddo/domain/settlement/controller/SettlementController.java b/src/main/java/com/dnd/moddo/domain/settlement/controller/SettlementController.java new file mode 100644 index 0000000..5e56d4e --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/settlement/controller/SettlementController.java @@ -0,0 +1,97 @@ +package com.dnd.moddo.domain.settlement.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.dnd.moddo.domain.settlement.dto.request.SettlementAccountRequest; +import com.dnd.moddo.domain.settlement.dto.request.SettlementPasswordRequest; +import com.dnd.moddo.domain.settlement.dto.request.SettlementRequest; +import com.dnd.moddo.domain.settlement.dto.response.SettlementDetailResponse; +import com.dnd.moddo.domain.settlement.dto.response.SettlementHeaderResponse; +import com.dnd.moddo.domain.settlement.dto.response.SettlementPasswordResponse; +import com.dnd.moddo.domain.settlement.dto.response.SettlementResponse; +import com.dnd.moddo.domain.settlement.dto.response.SettlementSaveResponse; +import com.dnd.moddo.domain.settlement.service.CommandSettlementService; +import com.dnd.moddo.domain.settlement.service.QuerySettlementService; +import com.dnd.moddo.global.jwt.service.JwtService; + +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1/group") +public class SettlementController { + private final CommandSettlementService commandSettlementService; + private final JwtService jwtService; + private final QuerySettlementService querySettlementService; + + @PostMapping + public ResponseEntity saveSettlement(HttpServletRequest request, + @RequestBody SettlementRequest settlementRequest) { + Long userId = jwtService.getUserId(request); + SettlementSaveResponse response = commandSettlementService.createSettlement(settlementRequest, userId); + return ResponseEntity.ok(response); + } + + @PutMapping("/account") + public ResponseEntity updateAccount( + HttpServletRequest request, + @RequestParam("groupToken") String code, + @RequestBody SettlementAccountRequest settlementAccountRequest) { + Long userId = jwtService.getUserId(request); + Long settlementId = querySettlementService.findIdByCode(code); + + SettlementResponse response = commandSettlementService.updateAccount(settlementAccountRequest, userId, + settlementId); + return ResponseEntity.ok(response); + } + + @GetMapping + public ResponseEntity getSettlement( + HttpServletRequest request, + @RequestParam("groupToken") String code) { + Long userId = jwtService.getUserId(request); + Long settlementId = querySettlementService.findIdByCode(code); + + SettlementDetailResponse response = querySettlementService.findOne(settlementId, userId); + return ResponseEntity.ok(response); + } + + @PostMapping("/password") + public ResponseEntity isPasswordMatch( + HttpServletRequest request, + @RequestParam("groupToken") String code, + @RequestBody SettlementPasswordRequest settlementPasswordRequest) { + Long userId = jwtService.getUserId(request); + Long settlementId = querySettlementService.findIdByCode(code); + + SettlementPasswordResponse response = commandSettlementService.isPasswordMatch(settlementId, userId, + settlementPasswordRequest); + return ResponseEntity.ok(response); + } + + @GetMapping("/header") + public ResponseEntity getHeader( + @RequestParam("groupToken") String code) { + Long settlementId = querySettlementService.findIdByCode(code); + + SettlementHeaderResponse response = querySettlementService.findBySettlementHeader(settlementId); + return ResponseEntity.ok(response); + } + + @GetMapping("/header/no-cache") + public ResponseEntity getHeaderNoCache( + @RequestParam("groupToken") String code) { + Long settlementId = querySettlementService.findIdByCodeNoCache(code); + + SettlementHeaderResponse response = querySettlementService.findBySettlementHeader(settlementId); + return ResponseEntity.ok(response); + } +} diff --git a/src/main/java/com/dnd/moddo/domain/settlement/dto/request/SettlementAccountRequest.java b/src/main/java/com/dnd/moddo/domain/settlement/dto/request/SettlementAccountRequest.java new file mode 100644 index 0000000..6622a1f --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/settlement/dto/request/SettlementAccountRequest.java @@ -0,0 +1,8 @@ +package com.dnd.moddo.domain.settlement.dto.request; + +public record SettlementAccountRequest( + String bank, + + String accountNumber +) { +} diff --git a/src/main/java/com/dnd/moddo/domain/settlement/dto/request/SettlementPasswordRequest.java b/src/main/java/com/dnd/moddo/domain/settlement/dto/request/SettlementPasswordRequest.java new file mode 100644 index 0000000..e19d6bf --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/settlement/dto/request/SettlementPasswordRequest.java @@ -0,0 +1,6 @@ +package com.dnd.moddo.domain.settlement.dto.request; + +public record SettlementPasswordRequest( + String password +) { +} diff --git a/src/main/java/com/dnd/moddo/domain/group/dto/request/GroupRequest.java b/src/main/java/com/dnd/moddo/domain/settlement/dto/request/SettlementRequest.java similarity index 62% rename from src/main/java/com/dnd/moddo/domain/group/dto/request/GroupRequest.java rename to src/main/java/com/dnd/moddo/domain/settlement/dto/request/SettlementRequest.java index 17e9e0f..b4d7419 100644 --- a/src/main/java/com/dnd/moddo/domain/group/dto/request/GroupRequest.java +++ b/src/main/java/com/dnd/moddo/domain/settlement/dto/request/SettlementRequest.java @@ -1,8 +1,8 @@ -package com.dnd.moddo.domain.group.dto.request; +package com.dnd.moddo.domain.settlement.dto.request; import jakarta.validation.constraints.NotBlank; -public record GroupRequest( +public record SettlementRequest( @NotBlank(message = "모임 이름은 필수입니다.") String name, diff --git a/src/main/java/com/dnd/moddo/domain/settlement/dto/response/SettlementDetailResponse.java b/src/main/java/com/dnd/moddo/domain/settlement/dto/response/SettlementDetailResponse.java new file mode 100644 index 0000000..1b58a3e --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/settlement/dto/response/SettlementDetailResponse.java @@ -0,0 +1,25 @@ +package com.dnd.moddo.domain.settlement.dto.response; + +import java.util.List; +import java.util.stream.Collectors; + +import com.dnd.moddo.domain.appointmentMember.dto.response.AppointmentMemberResponse; +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.settlement.entity.Settlement; + +public record SettlementDetailResponse( + Long id, + String groupName, + List members +) { + public static SettlementDetailResponse of(Settlement settlement, List members) { + List memberResponses = members.stream() + .map(AppointmentMemberResponse::of) + .collect(Collectors.toList()); + return new SettlementDetailResponse( + settlement.getId(), + settlement.getName(), + memberResponses + ); + } +} diff --git a/src/main/java/com/dnd/moddo/domain/settlement/dto/response/SettlementHeaderResponse.java b/src/main/java/com/dnd/moddo/domain/settlement/dto/response/SettlementHeaderResponse.java new file mode 100644 index 0000000..cb98fa4 --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/settlement/dto/response/SettlementHeaderResponse.java @@ -0,0 +1,16 @@ +package com.dnd.moddo.domain.settlement.dto.response; + +import java.time.LocalDateTime; + +public record SettlementHeaderResponse( + String groupName, + Long totalAmount, + LocalDateTime deadline, + String bank, + String accountNumber +) { + public static SettlementHeaderResponse of(String groupName, Long totalAmount, LocalDateTime deadline, String bank, + String accountNumber) { + return new SettlementHeaderResponse(groupName, totalAmount, deadline, bank, accountNumber); + } +} diff --git a/src/main/java/com/dnd/moddo/domain/settlement/dto/response/SettlementPasswordResponse.java b/src/main/java/com/dnd/moddo/domain/settlement/dto/response/SettlementPasswordResponse.java new file mode 100644 index 0000000..7442bea --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/settlement/dto/response/SettlementPasswordResponse.java @@ -0,0 +1,9 @@ +package com.dnd.moddo.domain.settlement.dto.response; + +public record SettlementPasswordResponse( + String status +) { + public static SettlementPasswordResponse from(String status) { + return new SettlementPasswordResponse(status); + } +} diff --git a/src/main/java/com/dnd/moddo/domain/settlement/dto/response/SettlementResponse.java b/src/main/java/com/dnd/moddo/domain/settlement/dto/response/SettlementResponse.java new file mode 100644 index 0000000..4a85025 --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/settlement/dto/response/SettlementResponse.java @@ -0,0 +1,27 @@ +package com.dnd.moddo.domain.settlement.dto.response; + +import java.time.LocalDateTime; + +import com.dnd.moddo.domain.settlement.entity.Settlement; + +public record SettlementResponse( + Long id, + Long writer, + LocalDateTime createdAt, + LocalDateTime expiredAt, + String bank, + String accountNumber, + LocalDateTime deadline +) { + public static SettlementResponse of(Settlement settlement) { + return new SettlementResponse( + settlement.getId(), + settlement.getWriter(), + settlement.getCreatedAt(), + settlement.getExpiredAt(), + settlement.getBank(), + settlement.getAccountNumber(), + settlement.getDeadline() + ); + } +} diff --git a/src/main/java/com/dnd/moddo/domain/settlement/dto/response/SettlementSaveResponse.java b/src/main/java/com/dnd/moddo/domain/settlement/dto/response/SettlementSaveResponse.java new file mode 100644 index 0000000..6198ae1 --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/settlement/dto/response/SettlementSaveResponse.java @@ -0,0 +1,9 @@ +package com.dnd.moddo.domain.settlement.dto.response; + +import com.dnd.moddo.domain.appointmentMember.dto.response.AppointmentMemberResponse; + +public record SettlementSaveResponse( + String groupToken, + AppointmentMemberResponse manager +) { +} diff --git a/src/main/java/com/dnd/moddo/domain/group/entity/Group.java b/src/main/java/com/dnd/moddo/domain/settlement/entity/Settlement.java similarity index 81% rename from src/main/java/com/dnd/moddo/domain/group/entity/Group.java rename to src/main/java/com/dnd/moddo/domain/settlement/entity/Settlement.java index 3162e3a..df528f1 100644 --- a/src/main/java/com/dnd/moddo/domain/group/entity/Group.java +++ b/src/main/java/com/dnd/moddo/domain/settlement/entity/Settlement.java @@ -1,8 +1,8 @@ -package com.dnd.moddo.domain.group.entity; +package com.dnd.moddo.domain.settlement.entity; import java.time.LocalDateTime; -import com.dnd.moddo.domain.group.dto.request.GroupAccountRequest; +import com.dnd.moddo.domain.settlement.dto.request.SettlementAccountRequest; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -20,8 +20,8 @@ @Getter @AllArgsConstructor @NoArgsConstructor(access = AccessLevel.PROTECTED) -@Table(name = "`groups`") -public class Group { +@Table(name = "`settlement`") +public class Settlement { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -48,7 +48,7 @@ public class Group { private String code; @Builder - public Group(String name, Long writer, String password, LocalDateTime createdAt, + public Settlement(String name, Long writer, String password, LocalDateTime createdAt, String bank, String accountNumber, String code, LocalDateTime deadline) { this.name = name; this.writer = writer; @@ -61,7 +61,7 @@ public Group(String name, Long writer, String password, LocalDateTime createdAt, this.deadline = deadline; } - public void updateAccount(GroupAccountRequest request) { + public void updateAccount(SettlementAccountRequest request) { this.bank = request.bank(); this.accountNumber = request.accountNumber(); this.deadline = LocalDateTime.now().plusDays(1); diff --git a/src/main/java/com/dnd/moddo/domain/settlement/exception/GroupNotAuthorException.java b/src/main/java/com/dnd/moddo/domain/settlement/exception/GroupNotAuthorException.java new file mode 100644 index 0000000..8aa894f --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/settlement/exception/GroupNotAuthorException.java @@ -0,0 +1,11 @@ +package com.dnd.moddo.domain.settlement.exception; + +import com.dnd.moddo.global.exception.ModdoException; + +import org.springframework.http.HttpStatus; + +public class GroupNotAuthorException extends ModdoException { + public GroupNotAuthorException() { + super(HttpStatus.FORBIDDEN, "모임 작성자가 아닙니다."); + } +} diff --git a/src/main/java/com/dnd/moddo/domain/group/exception/GroupNotFoundException.java b/src/main/java/com/dnd/moddo/domain/settlement/exception/GroupNotFoundException.java similarity index 90% rename from src/main/java/com/dnd/moddo/domain/group/exception/GroupNotFoundException.java rename to src/main/java/com/dnd/moddo/domain/settlement/exception/GroupNotFoundException.java index 528bbeb..3a7733f 100644 --- a/src/main/java/com/dnd/moddo/domain/group/exception/GroupNotFoundException.java +++ b/src/main/java/com/dnd/moddo/domain/settlement/exception/GroupNotFoundException.java @@ -1,4 +1,4 @@ -package com.dnd.moddo.domain.group.exception; +package com.dnd.moddo.domain.settlement.exception; import org.springframework.http.HttpStatus; diff --git a/src/main/java/com/dnd/moddo/domain/settlement/exception/InvalidPasswordException.java b/src/main/java/com/dnd/moddo/domain/settlement/exception/InvalidPasswordException.java new file mode 100644 index 0000000..89e5d7e --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/settlement/exception/InvalidPasswordException.java @@ -0,0 +1,11 @@ +package com.dnd.moddo.domain.settlement.exception; + +import com.dnd.moddo.global.exception.ModdoException; + +import org.springframework.http.HttpStatus; + +public class InvalidPasswordException extends ModdoException { + public InvalidPasswordException() { + super(HttpStatus.BAD_REQUEST, "비밀번호가 틀렸습니다."); + } +} diff --git a/src/main/java/com/dnd/moddo/domain/group/repository/GroupRepository.java b/src/main/java/com/dnd/moddo/domain/settlement/repository/SettlementRepository.java similarity index 58% rename from src/main/java/com/dnd/moddo/domain/group/repository/GroupRepository.java rename to src/main/java/com/dnd/moddo/domain/settlement/repository/SettlementRepository.java index 06eec18..24ae90f 100644 --- a/src/main/java/com/dnd/moddo/domain/group/repository/GroupRepository.java +++ b/src/main/java/com/dnd/moddo/domain/settlement/repository/SettlementRepository.java @@ -1,4 +1,4 @@ -package com.dnd.moddo.domain.group.repository; +package com.dnd.moddo.domain.settlement.repository; import java.util.Optional; @@ -6,17 +6,17 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.exception.GroupNotFoundException; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.exception.GroupNotFoundException; -public interface GroupRepository extends JpaRepository { - default Group getById(Long groupId) { +public interface SettlementRepository extends JpaRepository { + default Settlement getById(Long groupId) { return findById(groupId).orElseThrow(() -> new GroupNotFoundException(groupId)); } boolean existsByCode(String code); - @Query("SELECT g.id FROM Group g WHERE g.code = :code") + @Query("SELECT g.id FROM Settlement g WHERE g.code = :code") Optional findIdByCode(@Param("code") String code); default Long getIdByCode(String code) { diff --git a/src/main/java/com/dnd/moddo/domain/settlement/service/CommandSettlementService.java b/src/main/java/com/dnd/moddo/domain/settlement/service/CommandSettlementService.java new file mode 100644 index 0000000..37d0624 --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/settlement/service/CommandSettlementService.java @@ -0,0 +1,55 @@ +package com.dnd.moddo.domain.settlement.service; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.dnd.moddo.domain.appointmentMember.dto.response.AppointmentMemberResponse; +import com.dnd.moddo.domain.appointmentMember.service.CommandAppointmentMemberService; +import com.dnd.moddo.domain.settlement.dto.request.SettlementAccountRequest; +import com.dnd.moddo.domain.settlement.dto.request.SettlementPasswordRequest; +import com.dnd.moddo.domain.settlement.dto.request.SettlementRequest; +import com.dnd.moddo.domain.settlement.dto.response.SettlementPasswordResponse; +import com.dnd.moddo.domain.settlement.dto.response.SettlementResponse; +import com.dnd.moddo.domain.settlement.dto.response.SettlementSaveResponse; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementCreator; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementReader; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementUpdater; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementValidator; +import com.dnd.moddo.global.jwt.utill.JwtProvider; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +@Transactional +public class CommandSettlementService { + private final SettlementCreator settlementCreator; + private final SettlementUpdater settlementUpdater; + private final SettlementValidator settlementValidator; + private final SettlementReader settlementReader; + private final JwtProvider jwtProvider; + private final CommandAppointmentMemberService commandAppointmentMemberService; + + public SettlementSaveResponse createSettlement(SettlementRequest request, Long userId) { + Settlement settlement = settlementCreator.createSettlement(request, userId); + AppointmentMemberResponse manager = commandAppointmentMemberService.createManager(settlement, userId); + return new SettlementSaveResponse(settlement.getCode(), manager); + } + + public SettlementResponse updateAccount(SettlementAccountRequest request, Long userId, Long settlementId) { + Settlement settlement = settlementReader.read(settlementId); + settlementValidator.checkSettlementAuthor(settlement, userId); + settlement = settlementUpdater.updateAccount(request, settlement.getId()); + return SettlementResponse.of(settlement); + } + + public SettlementPasswordResponse isPasswordMatch(Long settlementId, Long userId, + SettlementPasswordRequest request) { + Settlement settlement = settlementReader.read(settlementId); + settlementValidator.checkSettlementAuthor(settlement, userId); + SettlementPasswordResponse response = settlementValidator.checkSettlementPassword(request, + settlement.getPassword()); + return response; + } +} diff --git a/src/main/java/com/dnd/moddo/domain/settlement/service/QuerySettlementService.java b/src/main/java/com/dnd/moddo/domain/settlement/service/QuerySettlementService.java new file mode 100644 index 0000000..90b59d1 --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/settlement/service/QuerySettlementService.java @@ -0,0 +1,42 @@ +package com.dnd.moddo.domain.settlement.service; + +import java.util.List; + +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.settlement.dto.response.SettlementDetailResponse; +import com.dnd.moddo.domain.settlement.dto.response.SettlementHeaderResponse; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementReader; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementValidator; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class QuerySettlementService { + private final SettlementReader settlementReader; + private final SettlementValidator settlementValidator; + + public SettlementDetailResponse findOne(Long settlementId, Long userId) { + Settlement settlement = settlementReader.read(settlementId); + settlementValidator.checkSettlementAuthor(settlement, userId); + List members = settlementReader.findBySettlement(settlementId); + return SettlementDetailResponse.of(settlement, members); + } + + public SettlementHeaderResponse findBySettlementHeader(Long settlementId) { + return settlementReader.findByHeader(settlementId); + } + + @Cacheable(cacheNames = "settlements", key = "#code") + public Long findIdByCode(String code) { + return settlementReader.findIdByGroupCode(code); + } + + public Long findIdByCodeNoCache(String code) { + return settlementReader.findIdByGroupCode(code); + } +} diff --git a/src/main/java/com/dnd/moddo/domain/group/service/implementation/GroupCreator.java b/src/main/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementCreator.java similarity index 73% rename from src/main/java/com/dnd/moddo/domain/group/service/implementation/GroupCreator.java rename to src/main/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementCreator.java index 37489fc..2ad53f1 100644 --- a/src/main/java/com/dnd/moddo/domain/group/service/implementation/GroupCreator.java +++ b/src/main/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementCreator.java @@ -1,4 +1,4 @@ -package com.dnd.moddo.domain.group.service.implementation; +package com.dnd.moddo.domain.settlement.service.implementation; import java.time.LocalDateTime; import java.util.UUID; @@ -8,11 +8,11 @@ import com.dnd.moddo.domain.character.entity.Character; import com.dnd.moddo.domain.character.repository.CharacterRepository; -import com.dnd.moddo.domain.group.dto.request.GroupRequest; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.repository.GroupRepository; import com.dnd.moddo.domain.image.dto.CharacterResponse; import com.dnd.moddo.domain.image.service.implementation.ImageReader; +import com.dnd.moddo.domain.settlement.dto.request.SettlementRequest; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.repository.SettlementRepository; import com.dnd.moddo.domain.user.entity.User; import com.dnd.moddo.domain.user.repository.UserRepository; import com.dnd.moddo.global.util.ShortUUIDGenerator; @@ -21,19 +21,19 @@ @Service @RequiredArgsConstructor -public class GroupCreator { +public class SettlementCreator { - private final GroupRepository groupRepository; + private final SettlementRepository settlementRepository; private final UserRepository userRepository; private final BCryptPasswordEncoder passwordEncoder; private final ImageReader imageReader; private final CharacterRepository characterRepository; - public Group createGroup(GroupRequest request, Long userId) { + public Settlement createSettlement(SettlementRequest request, Long userId) { User user = userRepository.getById(userId); String encryptedPassword = passwordEncoder.encode(request.password()); - Group group = Group.builder() + Settlement settlement = Settlement.builder() .writer(user.getId()) .name(request.name()) .password(encryptedPassword) @@ -41,12 +41,12 @@ public Group createGroup(GroupRequest request, Long userId) { .code(generateUniqueGroupCode()) .build(); - group = groupRepository.save(group); + settlement = settlementRepository.save(settlement); CharacterResponse characterResponse = imageReader.getRandomCharacter(); Character character = Character.builder() - .group(group) + .settlement(settlement) .name(characterResponse.name()) .rarity(characterResponse.rarity()) .imageUrl(characterResponse.imageUrl()) @@ -55,14 +55,14 @@ public Group createGroup(GroupRequest request, Long userId) { characterRepository.save(character); - return group; + return settlement; } private String generateUniqueGroupCode() { for (int i = 0; i < 5; i++) { String uuid = UUID.randomUUID().toString(); String code = ShortUUIDGenerator.shortenUUID(uuid); - if (!groupRepository.existsByCode(code)) { + if (!settlementRepository.existsByCode(code)) { return code; } } diff --git a/src/main/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementReader.java b/src/main/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementReader.java new file mode 100644 index 0000000..204af69 --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementReader.java @@ -0,0 +1,43 @@ +package com.dnd.moddo.domain.settlement.service.implementation; + +import java.util.List; + +import org.springframework.stereotype.Service; + +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.repository.AppointmentMemberRepository; +import com.dnd.moddo.domain.expense.repository.ExpenseRepository; +import com.dnd.moddo.domain.settlement.dto.response.SettlementHeaderResponse; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.repository.SettlementRepository; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class SettlementReader { + private final SettlementRepository settlementRepository; + private final AppointmentMemberRepository appointmentMemberRepository; + private final ExpenseRepository expenseRepository; + + public Settlement read(Long settlementId) { + return settlementRepository.getById(settlementId); + } + + public List findBySettlement(Long settlementId) { + return appointmentMemberRepository.findBySettlementId(settlementId); + } + + public SettlementHeaderResponse findByHeader(Long settlementId) { + Settlement settlement = settlementRepository.getById(settlementId); + Long totalAmount = expenseRepository.sumAmountBySettlement(settlement); + + return SettlementHeaderResponse.of(settlement.getName(), totalAmount, settlement.getDeadline(), + settlement.getBank(), + settlement.getAccountNumber()); + } + + public Long findIdByGroupCode(String code) { + return settlementRepository.getIdByCode(code); + } +} diff --git a/src/main/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementUpdater.java b/src/main/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementUpdater.java new file mode 100644 index 0000000..7cb9c21 --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementUpdater.java @@ -0,0 +1,23 @@ +package com.dnd.moddo.domain.settlement.service.implementation; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.dnd.moddo.domain.settlement.dto.request.SettlementAccountRequest; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.repository.SettlementRepository; + +import lombok.RequiredArgsConstructor; + +@Service +@Transactional +@RequiredArgsConstructor +public class SettlementUpdater { + private final SettlementRepository settlementRepository; + + public Settlement updateAccount(SettlementAccountRequest request, Long settlementId) { + Settlement settlement = settlementRepository.getById(settlementId); + settlement.updateAccount(request); + return settlement; + } +} diff --git a/src/main/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementValidator.java b/src/main/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementValidator.java new file mode 100644 index 0000000..6213759 --- /dev/null +++ b/src/main/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementValidator.java @@ -0,0 +1,39 @@ +package com.dnd.moddo.domain.settlement.service.implementation; + +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +import com.dnd.moddo.domain.settlement.dto.request.SettlementPasswordRequest; +import com.dnd.moddo.domain.settlement.dto.response.SettlementPasswordResponse; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.exception.GroupNotAuthorException; +import com.dnd.moddo.domain.settlement.exception.InvalidPasswordException; +import com.dnd.moddo.domain.settlement.repository.SettlementRepository; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class SettlementValidator { + + private final PasswordEncoder passwordEncoder; + + private final SettlementRepository settlementRepository; + + public void checkSettlementAuthor(Settlement settlement, Long userId) { + if (!settlement.isWriter(userId)) { + throw new GroupNotAuthorException(); + } + } + + public SettlementPasswordResponse checkSettlementPassword(SettlementPasswordRequest settlementPasswordRequest, + String getPassword) { + boolean isMatch = passwordEncoder.matches(settlementPasswordRequest.password(), getPassword); + + if (!isMatch) { + throw new InvalidPasswordException(); + } + + return SettlementPasswordResponse.from("확인되었습니다."); + } +} diff --git a/src/main/java/com/dnd/moddo/global/common/aop/GroupPermissionAspect.java b/src/main/java/com/dnd/moddo/global/common/aop/GroupPermissionAspect.java index 971b281..5f47679 100644 --- a/src/main/java/com/dnd/moddo/global/common/aop/GroupPermissionAspect.java +++ b/src/main/java/com/dnd/moddo/global/common/aop/GroupPermissionAspect.java @@ -7,9 +7,9 @@ import com.dnd.moddo.domain.auth.exception.TokenNotFoundException; import com.dnd.moddo.domain.auth.exception.UserPermissionException; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.service.QueryGroupService; -import com.dnd.moddo.domain.group.service.implementation.GroupReader; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.service.QuerySettlementService; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementReader; import com.dnd.moddo.global.common.annotation.VerifyManagerPermission; import com.dnd.moddo.global.jwt.service.JwtService; @@ -21,9 +21,9 @@ @Component public class GroupPermissionAspect { private final JwtService jwtService; - private final QueryGroupService queryGroupService; + private final QuerySettlementService querySettlementService; private final HttpServletRequest request; - private final GroupReader groupReader; + private final SettlementReader settlementReader; @Before("@annotation(verifyManagerPermission)") public void checkPermission(JoinPoint joinPoint, VerifyManagerPermission verifyManagerPermission) { @@ -42,16 +42,16 @@ public void checkPermission(JoinPoint joinPoint, VerifyManagerPermission verifyM throw new TokenNotFoundException("group token"); } - Long groupId = queryGroupService.findIdByCode(code); + Long settlementId = querySettlementService.findIdByCode(code); // 사용자 검증 - if (!isAuthorized(userId, groupId)) { + if (!isAuthorized(userId, settlementId)) { throw new UserPermissionException(); } } - private boolean isAuthorized(Long userId, Long groupId) { - Group group = groupReader.read(groupId); - return group.isWriter(userId); + private boolean isAuthorized(Long userId, Long settlementId) { + Settlement settlement = settlementReader.read(settlementId); + return settlement.isWriter(userId); } } diff --git a/src/main/java/com/dnd/moddo/global/security/auth/AuthDetailsService.java b/src/main/java/com/dnd/moddo/global/security/auth/AuthDetailsService.java index a270b86..45536de 100644 --- a/src/main/java/com/dnd/moddo/global/security/auth/AuthDetailsService.java +++ b/src/main/java/com/dnd/moddo/global/security/auth/AuthDetailsService.java @@ -20,7 +20,16 @@ public class AuthDetailsService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String id) throws UsernameNotFoundException { - return userRepository.findById(Long.parseLong(id)) + if (id == null) { + throw new UsernameNotFoundException("id is null"); + } + final Long userId; + try { + userId = Long.parseLong(id); + } catch (NumberFormatException e) { + throw new UsernameNotFoundException("invalid id: " + id); + } + return userRepository.findById(userId) .map(AuthDetails::new) .orElseThrow(() -> new UserNotFoundException(id)); } diff --git a/src/test/java/com/dnd/moddo/domain/groupMember/controller/GroupMemberControllerTest.java b/src/test/java/com/dnd/moddo/domain/appointmentMember/controller/AppointmentMemberControllerTest.java similarity index 57% rename from src/test/java/com/dnd/moddo/domain/groupMember/controller/GroupMemberControllerTest.java rename to src/test/java/com/dnd/moddo/domain/appointmentMember/controller/AppointmentMemberControllerTest.java index b1c78f5..6a5bbf9 100644 --- a/src/test/java/com/dnd/moddo/domain/groupMember/controller/GroupMemberControllerTest.java +++ b/src/test/java/com/dnd/moddo/domain/appointmentMember/controller/AppointmentMemberControllerTest.java @@ -1,6 +1,6 @@ -package com.dnd.moddo.domain.groupMember.controller; +package com.dnd.moddo.domain.appointmentMember.controller; -import static com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole.*; +import static com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole.*; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @@ -12,25 +12,25 @@ import org.springframework.http.MediaType; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import com.dnd.moddo.domain.groupMember.dto.request.GroupMemberSaveRequest; -import com.dnd.moddo.domain.groupMember.dto.request.PaymentStatusUpdateRequest; -import com.dnd.moddo.domain.groupMember.dto.response.GroupMemberResponse; -import com.dnd.moddo.domain.groupMember.dto.response.GroupMembersResponse; +import com.dnd.moddo.domain.appointmentMember.dto.request.PaymentStatusUpdateRequest; +import com.dnd.moddo.domain.appointmentMember.dto.request.appointmentMemberSaveRequest; +import com.dnd.moddo.domain.appointmentMember.dto.response.AppointmentMemberResponse; +import com.dnd.moddo.domain.appointmentMember.dto.response.AppointmentMembersResponse; import com.dnd.moddo.global.util.RestDocsTestSupport; -public class GroupMemberControllerTest extends RestDocsTestSupport { +public class AppointmentMemberControllerTest extends RestDocsTestSupport { @Test @DisplayName("모임원을 성공적으로 조회한다.") - void getGroupMembers() throws Exception { + void getAppointmentMembers() throws Exception { // given String groupToken = "groupToken"; Long groupId = 1L; - GroupMembersResponse mockResponse = GroupMembersResponse.of(Collections.emptyList()); + AppointmentMembersResponse mockResponse = AppointmentMembersResponse.of(Collections.emptyList()); - when(queryGroupService.findIdByCode(groupToken)).thenReturn(groupId); - when(queryGroupMemberService.findAll(groupId)).thenReturn(mockResponse); + when(querySettlementService.findIdByCode(groupToken)).thenReturn(groupId); + when(queryAppointmentMemberService.findAll(groupId)).thenReturn(mockResponse); // when & then mockMvc.perform(MockMvcRequestBuilders.get("/api/v1/group-members") @@ -38,23 +38,23 @@ void getGroupMembers() throws Exception { .andExpect(status().isOk()) .andExpect(jsonPath("$.members").isArray()); - verify(queryGroupService).findIdByCode(groupToken); - verify(queryGroupMemberService).findAll(groupId); + verify(querySettlementService).findIdByCode(groupToken); + verify(queryAppointmentMemberService).findAll(groupId); } @Test @DisplayName("모임원을 성공적으로 추가한다.") - void saveGroupMember() throws Exception { + void saveAppointmentMember() throws Exception { // given String groupToken = "groupToken"; Long groupId = 1L; - GroupMemberSaveRequest request = new GroupMemberSaveRequest("김반숙"); - GroupMemberResponse response = new GroupMemberResponse(1L, PARTICIPANT, "김반숙", + appointmentMemberSaveRequest request = new appointmentMemberSaveRequest("김반숙"); + AppointmentMemberResponse response = new AppointmentMemberResponse(1L, PARTICIPANT, "김반숙", "https://moddo-s3.s3.amazonaws.com/profile/1.png", false, null); - when(queryGroupService.findIdByCode(groupToken)).thenReturn(groupId); - when(commandGroupMemberService.addGroupMember(groupId, request)).thenReturn(response); + when(querySettlementService.findIdByCode(groupToken)).thenReturn(groupId); + when(commandAppointmentMemberService.addAppointmentMember(groupId, request)).thenReturn(response); // when & then mockMvc.perform(MockMvcRequestBuilders.put("/api/v1/group-members") @@ -74,10 +74,10 @@ void updatePaymentStatus() throws Exception { Long groupMemberId = 1L; PaymentStatusUpdateRequest request = new PaymentStatusUpdateRequest(true); - GroupMemberResponse response = new GroupMemberResponse(1L, PARTICIPANT, "김반숙", + AppointmentMemberResponse response = new AppointmentMemberResponse(1L, PARTICIPANT, "김반숙", "https://moddo-s3.s3.amazonaws.com/profile/1.png", true, LocalDateTime.now()); - when(commandGroupMemberService.updatePaymentStatus(groupMemberId, request)).thenReturn(response); + when(commandAppointmentMemberService.updatePaymentStatus(groupMemberId, request)).thenReturn(response); // when & then mockMvc.perform(MockMvcRequestBuilders.put("/api/v1/group-members/{groupMemberId}/payment", groupMemberId) @@ -90,7 +90,7 @@ void updatePaymentStatus() throws Exception { @Test @DisplayName("모임원을 성공적으로 삭제한다.") - void deleteGroupMember() throws Exception { + void deleteAppointmentMember() throws Exception { // given Long groupMemberId = 1L; @@ -98,7 +98,7 @@ void deleteGroupMember() throws Exception { .andExpect(status().isNoContent()); // when & then - verify(commandGroupMemberService).delete(groupMemberId); + verify(commandAppointmentMemberService).delete(groupMemberId); } } diff --git a/src/test/java/com/dnd/moddo/domain/groupMember/entity/GroupMemberTest.java b/src/test/java/com/dnd/moddo/domain/appointmentMember/entity/AppointmentMemberTest.java similarity index 55% rename from src/test/java/com/dnd/moddo/domain/groupMember/entity/GroupMemberTest.java rename to src/test/java/com/dnd/moddo/domain/appointmentMember/entity/AppointmentMemberTest.java index 521504a..885085a 100644 --- a/src/test/java/com/dnd/moddo/domain/groupMember/entity/GroupMemberTest.java +++ b/src/test/java/com/dnd/moddo/domain/appointmentMember/entity/AppointmentMemberTest.java @@ -1,4 +1,4 @@ -package com.dnd.moddo.domain.groupMember.entity; +package com.dnd.moddo.domain.appointmentMember.entity; import static org.assertj.core.api.Assertions.*; @@ -6,32 +6,32 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.settlement.entity.Settlement; import com.dnd.moddo.global.support.GroupTestFactory; -class GroupMemberTest { +class AppointmentMemberTest { - private Group mockGroup; + private Settlement mockSettlement; @BeforeEach void setUp() { - mockGroup = GroupTestFactory.createDefault(); + mockSettlement = GroupTestFactory.createDefault(); } @DisplayName("참여자의 역할이 총무인 경우 true를 반환한다.") @Test void testIsManager_whenRoleIsManager() { // given - GroupMember groupMember = GroupMember.builder() + AppointmentMember appointmentMember = AppointmentMember.builder() .name("김모또") - .group(mockGroup) + .settlement(mockSettlement) .role(ExpenseRole.MANAGER) .isPaid(true) .build(); // when - boolean isManager = groupMember.isManager(); + boolean isManager = appointmentMember.isManager(); // then assertThat(isManager).isTrue(); @@ -41,15 +41,15 @@ void testIsManager_whenRoleIsManager() { @Test void testIsManager_whenRoleIsNotManager() { // given - GroupMember groupMember = GroupMember.builder() + AppointmentMember appointmentMember = AppointmentMember.builder() .name("김모또") - .group(mockGroup) + .settlement(mockSettlement) .role(ExpenseRole.PARTICIPANT) .isPaid(true) .build(); // when - boolean isManager = groupMember.isManager(); + boolean isManager = appointmentMember.isManager(); // then assertThat(isManager).isFalse(); @@ -59,18 +59,18 @@ void testIsManager_whenRoleIsNotManager() { @Test void testUpdatePaymentStatus() { // given - GroupMember groupMember = GroupMember.builder() + AppointmentMember appointmentMember = AppointmentMember.builder() .name("김모또") - .group(mockGroup) + .settlement(mockSettlement) .role(ExpenseRole.PARTICIPANT) .isPaid(false) .build(); // when - groupMember.updatePaymentStatus(true); + appointmentMember.updatePaymentStatus(true); // then - assertThat(groupMember.isPaid()).isTrue(); - assertThat(groupMember.getPaidAt()).isNotNull(); + assertThat(appointmentMember.isPaid()).isTrue(); + assertThat(appointmentMember.getPaidAt()).isNotNull(); } } diff --git a/src/test/java/com/dnd/moddo/domain/appointmentMember/service/CommandAppointmentMemberServiceTest.java b/src/test/java/com/dnd/moddo/domain/appointmentMember/service/CommandAppointmentMemberServiceTest.java new file mode 100644 index 0000000..4cff39b --- /dev/null +++ b/src/test/java/com/dnd/moddo/domain/appointmentMember/service/CommandAppointmentMemberServiceTest.java @@ -0,0 +1,116 @@ +package com.dnd.moddo.domain.appointmentMember.service; + +import static org.assertj.core.api.BDDAssertions.*; +import static org.mockito.Mockito.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.dnd.moddo.domain.appointmentMember.dto.request.PaymentStatusUpdateRequest; +import com.dnd.moddo.domain.appointmentMember.dto.request.appointmentMemberSaveRequest; +import com.dnd.moddo.domain.appointmentMember.dto.response.AppointmentMemberResponse; +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.appointmentMember.service.implementation.AppointmentMemberCreator; +import com.dnd.moddo.domain.appointmentMember.service.implementation.AppointmentMemberUpdater; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.global.support.GroupTestFactory; + +@ExtendWith(MockitoExtension.class) +public class CommandAppointmentMemberServiceTest { + @Mock + private AppointmentMemberCreator appointmentMemberCreator; + @Mock + private AppointmentMemberUpdater appointmentMemberUpdater; + @InjectMocks + private CommandAppointmentMemberService commandAppointmentMemberService; + + private Settlement mockSettlement; + + @BeforeEach + void setUp() { + mockSettlement = GroupTestFactory.createDefault(); + } + + @DisplayName("모든 정보가 유효할때 총무 생성에 성공한다.") + @Test + void whenValidInfo_thenCreateSuccess() { + //given + Long userId = 1L; + AppointmentMember expectedMembers = AppointmentMember.builder() + .name("김모또") + .settlement(this.mockSettlement) + .profileId(0) + .role(ExpenseRole.MANAGER) + .build(); + Settlement mockSettlement = mock(Settlement.class); + when(appointmentMemberCreator.createManagerForSettlement(any(Settlement.class), eq(userId))).thenReturn( + expectedMembers); + + // when + AppointmentMemberResponse response = commandAppointmentMemberService.createManager(mockSettlement, userId); + + //then + assertThat(response).isNotNull(); + assertThat(response.name()).isEqualTo("김모또"); + assertThat(response.role()).isEqualTo(ExpenseRole.MANAGER); + verify(appointmentMemberCreator, times(1)).createManagerForSettlement(any(Settlement.class), any()); + } + + @DisplayName("모든 정보가 유효할때 기존 모임의 참여자 추가가 성공한다.") + @Test + void whenValidInfo_thenAddAppointmentMemberSuccess() { + //given + Long groupId = mockSettlement.getId(); + appointmentMemberSaveRequest request = mock(appointmentMemberSaveRequest.class); + AppointmentMember expectedMember = AppointmentMember.builder() + .name("김반숙") + .settlement(mockSettlement) + .profileId(1) + .role(ExpenseRole.PARTICIPANT) + .build(); + + when(appointmentMemberUpdater.addToSettlement(eq(groupId), any(appointmentMemberSaveRequest.class))).thenReturn( + expectedMember); + + //when + AppointmentMemberResponse response = commandAppointmentMemberService.addAppointmentMember(groupId, request); + + //then + assertThat(response).isNotNull(); + assertThat(response.name()).isEqualTo("김반숙"); + verify(appointmentMemberUpdater, times(1)).addToSettlement(eq(groupId), + any(appointmentMemberSaveRequest.class)); + } + + @DisplayName("참여자 입금 내역을 업데이트 할 수 있다.") + @Test + void whenUpdatePaymentStatus_thenSuccess() { + //given + AppointmentMember expectedAppointmentMember = AppointmentMember.builder() + .name("김반숙") + .settlement(mockSettlement) + .isPaid(true) + .profileId(1) + .role(ExpenseRole.PARTICIPANT) + .build(); + PaymentStatusUpdateRequest request = new PaymentStatusUpdateRequest(true); + when(appointmentMemberUpdater.updatePaymentStatus(any(), eq(request))).thenReturn(expectedAppointmentMember); + + //then + AppointmentMemberResponse response = commandAppointmentMemberService.updatePaymentStatus(1L, request); + + //then + assertThat(response).isNotNull(); + assertThat(response.name()).isEqualTo("김반숙"); + assertThat(response.role()).isEqualTo(ExpenseRole.PARTICIPANT); + assertThat(response.isPaid()).isTrue(); + + verify(appointmentMemberUpdater, times(1)).updatePaymentStatus(any(), eq(request)); + } +} diff --git a/src/test/java/com/dnd/moddo/domain/groupMember/service/PaymentConcurrencyTest.java b/src/test/java/com/dnd/moddo/domain/appointmentMember/service/PaymentConcurrencyTest.java similarity index 53% rename from src/test/java/com/dnd/moddo/domain/groupMember/service/PaymentConcurrencyTest.java rename to src/test/java/com/dnd/moddo/domain/appointmentMember/service/PaymentConcurrencyTest.java index 4037916..e80f56e 100644 --- a/src/test/java/com/dnd/moddo/domain/groupMember/service/PaymentConcurrencyTest.java +++ b/src/test/java/com/dnd/moddo/domain/appointmentMember/service/PaymentConcurrencyTest.java @@ -1,4 +1,4 @@ -package com.dnd.moddo.domain.groupMember.service; +package com.dnd.moddo.domain.appointmentMember.service; import static org.assertj.core.api.AssertionsForClassTypes.*; @@ -15,46 +15,46 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import com.dnd.moddo.ModdoApplication; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.repository.GroupRepository; -import com.dnd.moddo.domain.group.service.implementation.GroupReader; -import com.dnd.moddo.domain.groupMember.dto.request.PaymentStatusUpdateRequest; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; -import com.dnd.moddo.domain.groupMember.repository.GroupMemberRepository; -import com.dnd.moddo.domain.groupMember.service.implementation.GroupMemberReader; -import com.dnd.moddo.domain.groupMember.service.implementation.GroupMemberUpdater; -import com.dnd.moddo.domain.groupMember.service.implementation.GroupMemberValidator; +import com.dnd.moddo.domain.appointmentMember.dto.request.PaymentStatusUpdateRequest; +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.appointmentMember.repository.AppointmentMemberRepository; +import com.dnd.moddo.domain.appointmentMember.service.implementation.AppointmentMemberReader; +import com.dnd.moddo.domain.appointmentMember.service.implementation.AppointmentMemberUpdater; +import com.dnd.moddo.domain.appointmentMember.service.implementation.AppointmentMemberValidator; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.repository.SettlementRepository; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementReader; import com.dnd.moddo.global.support.GroupTestFactory; @ExtendWith(SpringExtension.class) @SpringBootTest(classes = ModdoApplication.class) // 명시적으로 설정 클래스를 지정 public class PaymentConcurrencyTest { @Autowired - private GroupMemberUpdater groupMemberUpdater; + private AppointmentMemberUpdater appointmentMemberUpdater; @Autowired - private GroupMemberRepository groupMemberRepository; + private AppointmentMemberRepository appointmentMemberRepository; @Autowired - private GroupRepository groupRepository; + private SettlementRepository settlementRepository; @Autowired - private GroupMemberValidator groupMemberValidator; + private AppointmentMemberValidator appointmentMemberValidator; @Autowired - private GroupMemberReader groupMemberReader; + private AppointmentMemberReader appointmentMemberReader; @Autowired - private GroupReader groupReader; + private SettlementReader settlementReader; - private GroupMember groupMember; + private AppointmentMember appointmentMember; @BeforeEach void setUp() { - Group mockGroup = GroupTestFactory.createDefault(); + Settlement mockSettlement = GroupTestFactory.createDefault(); - groupRepository.save(mockGroup); + settlementRepository.save(mockSettlement); - groupMember = groupMemberRepository.save( - GroupMember.builder() + appointmentMember = appointmentMemberRepository.save( + AppointmentMember.builder() .name("김반숙") - .group(mockGroup) + .settlement(mockSettlement) .profileId(1) .role(ExpenseRole.PARTICIPANT) .build()); @@ -64,7 +64,7 @@ void setUp() { @Test void optimisticLock_shouldThrowExceptionOnConflict() throws InterruptedException { //given - Long groupMemberId = groupMember.getId(); + Long groupMemberId = appointmentMember.getId(); int threadCount = 10; CountDownLatch latch = new CountDownLatch(threadCount); @@ -75,7 +75,7 @@ void optimisticLock_shouldThrowExceptionOnConflict() throws InterruptedException for (int i = 0; i < threadCount; i++) { new Thread(() -> { try { - groupMemberUpdater.updatePaymentStatus(groupMemberId, new PaymentStatusUpdateRequest(true)); + appointmentMemberUpdater.updatePaymentStatus(groupMemberId, new PaymentStatusUpdateRequest(true)); successCount.incrementAndGet(); } catch (OptimisticLockingFailureException e) { failureCount.incrementAndGet(); // 동시 수정 충돌 발생 @@ -89,7 +89,7 @@ void optimisticLock_shouldThrowExceptionOnConflict() throws InterruptedException //then - GroupMember result = groupMemberRepository.getById(groupMemberId); + AppointmentMember result = appointmentMemberRepository.getById(groupMemberId); assertThat(result.isPaid()).isTrue(); assertThat(successCount.get()).isGreaterThan(0); diff --git a/src/test/java/com/dnd/moddo/domain/appointmentMember/service/QueryAppointmentMemberServiceTest.java b/src/test/java/com/dnd/moddo/domain/appointmentMember/service/QueryAppointmentMemberServiceTest.java new file mode 100644 index 0000000..2e36ab6 --- /dev/null +++ b/src/test/java/com/dnd/moddo/domain/appointmentMember/service/QueryAppointmentMemberServiceTest.java @@ -0,0 +1,71 @@ +package com.dnd.moddo.domain.appointmentMember.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.dnd.moddo.domain.appointmentMember.dto.response.AppointmentMembersResponse; +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.appointmentMember.service.implementation.AppointmentMemberReader; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.global.support.GroupTestFactory; + +@ExtendWith(MockitoExtension.class) +public class QueryAppointmentMemberServiceTest { + + @Mock + private AppointmentMemberReader appointmentMemberReader; + @InjectMocks + private QueryAppointmentMemberService queryAppointmentMemberService; + + private Settlement mockSettlement; + private List mockMembers; + + @BeforeEach + void setUp() { + mockSettlement = GroupTestFactory.createDefault(); + + mockMembers = List.of( + AppointmentMember.builder() + .name("김모또") + .settlement(mockSettlement) + .profileId(0) + .role(ExpenseRole.MANAGER) + .build(), + AppointmentMember.builder() + .name("김반숙") + .profileId(1) + .settlement(mockSettlement) + .role(ExpenseRole.PARTICIPANT) + .build() + ); + } + + @DisplayName("모임이 존재하면 모임의 모든 참여자를 조회할 수 있다.") + @Test + void findAll() { + //given + Long groupId = mockSettlement.getId(); + + when(appointmentMemberReader.findAllBySettlementId(eq(groupId))).thenReturn(mockMembers); + + //when + AppointmentMembersResponse response = queryAppointmentMemberService.findAll(groupId); + + //then + assertThat(response).isNotNull(); + assertThat(response.members().size()).isEqualTo(2); + assertThat(response.members().get(0).name()).isEqualTo("김모또"); + verify(appointmentMemberReader, times(1)).findAllBySettlementId(eq(groupId)); + } +} diff --git a/src/test/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberCreatorTest.java b/src/test/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberCreatorTest.java similarity index 62% rename from src/test/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberCreatorTest.java rename to src/test/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberCreatorTest.java index 6240a39..821e516 100644 --- a/src/test/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberCreatorTest.java +++ b/src/test/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberCreatorTest.java @@ -1,4 +1,4 @@ -package com.dnd.moddo.domain.groupMember.service.implementation; +package com.dnd.moddo.domain.appointmentMember.service.implementation; import static org.assertj.core.api.BDDAssertions.*; import static org.mockito.ArgumentMatchers.*; @@ -12,30 +12,30 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; -import com.dnd.moddo.domain.groupMember.repository.GroupMemberRepository; +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.appointmentMember.repository.AppointmentMemberRepository; +import com.dnd.moddo.domain.settlement.entity.Settlement; import com.dnd.moddo.domain.user.entity.User; import com.dnd.moddo.domain.user.repository.UserRepository; @ExtendWith(MockitoExtension.class) -public class GroupMemberCreatorTest { +public class AppointmentMemberCreatorTest { @Mock - private GroupMemberRepository groupMemberRepository; + private AppointmentMemberRepository appointmentMemberRepository; @Mock private UserRepository userRepository; @InjectMocks - private GroupMemberCreator groupMemberCreator; + private AppointmentMemberCreator appointmentMemberCreator; - private Group mockGroup; + private Settlement mockSettlement; @BeforeEach void setUp() { - mockGroup = mock(Group.class); + mockSettlement = mock(Settlement.class); } @DisplayName("사용자가 비회원인 경우, 총무의 이름은 '김모또'로 생성되고 프로필 ID가 0으로 설정된다.") @@ -48,17 +48,17 @@ void create_Success_WithGuestMember() { when(userRepository.getById(eq(userId))).thenReturn(mockUser); when(mockUser.getIsMember()).thenReturn(false); - GroupMember expectedMember = GroupMember.builder() + AppointmentMember expectedMember = AppointmentMember.builder() .name("김모또") - .group(mockGroup) + .settlement(mockSettlement) .profileId(0) .role(ExpenseRole.MANAGER) .build(); - when(groupMemberRepository.save(any(GroupMember.class))).thenReturn(expectedMember); + when(appointmentMemberRepository.save(any(AppointmentMember.class))).thenReturn(expectedMember); // when - GroupMember savedMember = groupMemberCreator.createManagerForGroup(mockGroup, userId); + AppointmentMember savedMember = appointmentMemberCreator.createManagerForSettlement(mockSettlement, userId); // then assertThat(savedMember).isNotNull(); @@ -67,7 +67,7 @@ void create_Success_WithGuestMember() { assertThat(savedMember.getProfileId()).isEqualTo(0); // profileId 검증 verify(userRepository, times(1)).getById(eq(userId)); - verify(groupMemberRepository, times(1)).save(any(GroupMember.class)); + verify(appointmentMemberRepository, times(1)).save(any(AppointmentMember.class)); } @DisplayName("사용자가 회원인 경우, 총무의 이름은 회원의 이름으로 생성되고 프로필 ID가 0으로 설정된다.") @@ -81,17 +81,17 @@ void create_Success_WithMember() { when(mockUser.getIsMember()).thenReturn(true); when(mockUser.getName()).thenReturn("연노른자"); - GroupMember expectedMember = GroupMember.builder() + AppointmentMember expectedMember = AppointmentMember.builder() .name("연노른자") - .group(mockGroup) + .settlement(mockSettlement) .profileId(0) .role(ExpenseRole.MANAGER) .build(); - when(groupMemberRepository.save(any(GroupMember.class))).thenReturn(expectedMember); + when(appointmentMemberRepository.save(any(AppointmentMember.class))).thenReturn(expectedMember); // when - GroupMember savedMember = groupMemberCreator.createManagerForGroup(mockGroup, userId); + AppointmentMember savedMember = appointmentMemberCreator.createManagerForSettlement(mockSettlement, userId); // then assertThat(savedMember).isNotNull(); @@ -100,6 +100,6 @@ void create_Success_WithMember() { assertThat(savedMember.getProfileId()).isEqualTo(0); verify(userRepository, times(1)).getById(eq(userId)); - verify(groupMemberRepository, times(1)).save(any(GroupMember.class)); + verify(appointmentMemberRepository, times(1)).save(any(AppointmentMember.class)); } } diff --git a/src/test/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberDeleterTest.java b/src/test/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberDeleterTest.java new file mode 100644 index 0000000..7ffdd54 --- /dev/null +++ b/src/test/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberDeleterTest.java @@ -0,0 +1,94 @@ +package com.dnd.moddo.domain.appointmentMember.service.implementation; + +import static org.assertj.core.api.AssertionsForClassTypes.*; +import static org.mockito.Mockito.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.appointmentMember.exception.AppointmentMemberNotFoundException; +import com.dnd.moddo.domain.appointmentMember.repository.AppointmentMemberRepository; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.global.support.GroupTestFactory; + +@ExtendWith(MockitoExtension.class) +class AppointmentMemberDeleterTest { + + @Mock + private AppointmentMemberRepository appointmentMemberRepository; + @Mock + private AppointmentMemberReader appointmentMemberReader; + @InjectMocks + private AppointmentMemberDeleter appointmentMemberDeleter; + + private Settlement mockSettlement; + + @BeforeEach + void setUp() { + mockSettlement = GroupTestFactory.createDefault(); + } + + @DisplayName("유효한 참여자 id로 삭제를 요청하면 성공적으로 삭제된다.") + @Test + void delete_Success_ValidGroupMemberId() { + //given + Long groupMemberId = 1L; + AppointmentMember expectedMember = AppointmentMember.builder() + .name("김반숙") + .settlement(mockSettlement) + .role(ExpenseRole.PARTICIPANT) + .isPaid(false) + .build(); + + when(appointmentMemberReader.findByAppointmentMemberId(eq(groupMemberId))).thenReturn(expectedMember); + doNothing().when(appointmentMemberRepository).delete(any(AppointmentMember.class)); + + //when + appointmentMemberDeleter.delete(groupMemberId); + + //then + verify(appointmentMemberRepository, times(1)).delete(any(AppointmentMember.class)); + } + + @DisplayName("유효하지 않은 참여자 id로 삭제를 요청하면 예외가 발생한다.") + @Test + void delete_ThrowException_WithInvalidExpenseId() { + //given + Long appointmentMember = 1L; + + doThrow(new AppointmentMemberNotFoundException(appointmentMember)).when(appointmentMemberReader) + .findByAppointmentMemberId(eq(appointmentMember)); + + //when & then + assertThatThrownBy(() -> { + appointmentMemberDeleter.delete(appointmentMember); + }).hasMessage("해당 참여자를 찾을 수 없습니다. (AppointmentMember ID: " + appointmentMember + ")"); + } + + @DisplayName("유효한 참여자 id로 삭제를 요청하면 성공적으로 삭제된다.") + @Test + void delete_ThrowException_WhenRoleIsManager() { + //given + Long appointmentMember = 1L; + AppointmentMember expectedMember = AppointmentMember.builder() + .name("김모또") + .settlement(mockSettlement) + .role(ExpenseRole.MANAGER) + .isPaid(false) + .build(); + + when(appointmentMemberReader.findByAppointmentMemberId(eq(appointmentMember))).thenReturn(expectedMember); + + //when & then + assertThatThrownBy(() -> { + appointmentMemberDeleter.delete(appointmentMember); + }).hasMessage("총무(MANAGER)는 삭제할 수 없습니다. (Member ID: " + appointmentMember + ")"); + } +} diff --git a/src/test/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberReaderTest.java b/src/test/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberReaderTest.java new file mode 100644 index 0000000..20f8e5a --- /dev/null +++ b/src/test/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberReaderTest.java @@ -0,0 +1,109 @@ +package com.dnd.moddo.domain.appointmentMember.service.implementation; + +import static org.assertj.core.api.AssertionsForClassTypes.*; +import static org.mockito.Mockito.*; + +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.appointmentMember.exception.AppointmentMemberNotFoundException; +import com.dnd.moddo.domain.appointmentMember.repository.AppointmentMemberRepository; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.global.support.GroupTestFactory; + +@ExtendWith(MockitoExtension.class) +public class AppointmentMemberReaderTest { + @Mock + private AppointmentMemberRepository appointmentMemberRepository; + @InjectMocks + private AppointmentMemberReader appointmentMemberReader; + + private Settlement mockSettlement; + + @BeforeEach + void setUp() { + mockSettlement = GroupTestFactory.createDefault(); + } + + @DisplayName("모임이 존재할때 모임의 모든 참여자를 조회에 성공한다.") + @Test + void findAllBySettlementIdSuccess() { + //given + Long groupId = mockSettlement.getId(); + List expectedMembers = List.of( + AppointmentMember.builder() + .name("김모또") + .settlement(mockSettlement) + .role(ExpenseRole.MANAGER) + .isPaid(false) + .build(), + AppointmentMember.builder() + .name("김반숙") + .settlement(mockSettlement) + .role(ExpenseRole.PARTICIPANT) + .isPaid(false) + .build() + ); + + when(appointmentMemberRepository.findBySettlementId(eq(groupId))).thenReturn(expectedMembers); + + //when + List result = appointmentMemberReader.findAllBySettlementId(groupId); + + //then + assertThat(result).isNotNull(); + assertThat(result.size()).isEqualTo(2); + assertThat(result.get(0).getName()).isEqualTo("김모또"); + assertThat(result.get(0).getRole()).isEqualTo(ExpenseRole.MANAGER); + verify(appointmentMemberRepository, times(1)).findBySettlementId(groupId); + } + + @DisplayName("참여자가 존재할때 참여자 id를 사용해 참여자 정보 조회에 성공한다.") + @Test + void findByGroupMemberIdSuccess() { + //given + Long groupMemberId = 1L; + AppointmentMember expectedMember = AppointmentMember.builder() + .name("김반숙") + .settlement(mockSettlement) + .role(ExpenseRole.PARTICIPANT) + .isPaid(false) + .build(); + + when(appointmentMemberRepository.getById(eq(groupMemberId))).thenReturn(expectedMember); + + //when + AppointmentMember result = appointmentMemberReader.findByAppointmentMemberId(groupMemberId); + + //then + assertThat(result).isNotNull(); + assertThat(result.getSettlement()).isEqualTo(mockSettlement); + assertThat(result.getName()).isEqualTo("김반숙"); + verify(appointmentMemberRepository, times(1)).getById(eq(groupMemberId)); + + } + + @DisplayName("참여자가 존재하지 않을때 참여자 id를 사용해 조회하려고 하면 예외가 발생한다.") + @Test + void findByGroupMemberIdFail() { + //given + Long appointmentMember = 1L; + doThrow(new AppointmentMemberNotFoundException(appointmentMember)).when(appointmentMemberRepository) + .getById(eq(appointmentMember)); + + //when & then + assertThatThrownBy(() -> { + appointmentMemberReader.findByAppointmentMemberId(appointmentMember); + }).hasMessage("해당 참여자를 찾을 수 없습니다. (AppointmentMember ID: " + appointmentMember + ")"); + } + +} diff --git a/src/test/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberUpdaterTest.java b/src/test/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberUpdaterTest.java new file mode 100644 index 0000000..a693454 --- /dev/null +++ b/src/test/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberUpdaterTest.java @@ -0,0 +1,177 @@ +package com.dnd.moddo.domain.appointmentMember.service.implementation; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.dnd.moddo.domain.appointmentMember.dto.request.PaymentStatusUpdateRequest; +import com.dnd.moddo.domain.appointmentMember.dto.request.appointmentMemberSaveRequest; +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.appointmentMember.exception.AppointmentMemberDuplicateNameException; +import com.dnd.moddo.domain.appointmentMember.repository.AppointmentMemberRepository; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementReader; +import com.dnd.moddo.global.config.S3Bucket; + +@ExtendWith(MockitoExtension.class) +class AppointmentMemberUpdaterTest { + @Mock + private AppointmentMemberRepository appointmentMemberRepository; + @Mock + private AppointmentMemberReader appointmentMemberReader; + @Mock + private AppointmentMemberValidator appointmentMemberValidator; + @Mock + private SettlementReader settlementReader; + @Mock + private S3Bucket s3Bucket; + @InjectMocks + private AppointmentMemberUpdater appointmentMemberUpdater; + + private Settlement mockSettlement; + + @BeforeEach + void setup() { + mockSettlement = mock(Settlement.class); + } + + @DisplayName("추가하려는 참여자의 이름이 기존 참여자의 이름과 중복되지 않을 경우 참여자 추가에 성공한다.") + @Test + void addToSettlementSuccess() { + // given + Long groupId = 1L; + appointmentMemberSaveRequest request = mock(appointmentMemberSaveRequest.class); + String newMemberName = "김반숙"; + + when(request.name()).thenReturn(newMemberName); + when(settlementReader.read(eq(groupId))).thenReturn(mockSettlement); + + List mockAppointmentMembers = new ArrayList<>(); + when(appointmentMemberReader.findAllBySettlementId(eq(groupId))).thenReturn(mockAppointmentMembers); + + doNothing().when(appointmentMemberValidator).validateMemberNamesNotDuplicate(any()); + + AppointmentMember expectedAppointmentMember = AppointmentMember.builder() + .name(newMemberName) + .settlement(mockSettlement) + .role(ExpenseRole.PARTICIPANT) + .profileId(1) + .build(); + when(appointmentMemberRepository.save(any())).thenReturn(expectedAppointmentMember); + + // when + AppointmentMember result = appointmentMemberUpdater.addToSettlement(groupId, request); + + // then + assertThat(result).isNotNull(); + assertThat(result.getSettlement()).isEqualTo(mockSettlement); + assertThat(result.getName()).isEqualTo(newMemberName); + assertThat(result.getProfileId()).isEqualTo(1); + + verify(appointmentMemberRepository, times(1)).save(any()); + } + + @DisplayName("추가하려는 참여자의 이름이 기존 참여자의 이름과 중복되는 경우 예외가 발생한다.") + @Test + void addToSettlementDuplicatedName() { + // given + Long groupId = 1L; + appointmentMemberSaveRequest request = mock(appointmentMemberSaveRequest.class); + String duplicatedName = "김반숙"; + + when(request.name()).thenReturn(duplicatedName); + when(settlementReader.read(eq(groupId))).thenReturn(mockSettlement); + + List mockAppointmentMembers = new ArrayList<>(); + AppointmentMember existingMember = AppointmentMember.builder().name(duplicatedName).build(); + mockAppointmentMembers.add(existingMember); + when(appointmentMemberReader.findAllBySettlementId(eq(groupId))).thenReturn(mockAppointmentMembers); + + doThrow(new AppointmentMemberDuplicateNameException()).when(appointmentMemberValidator) + .validateMemberNamesNotDuplicate(any()); + + // when & then + assertThatThrownBy(() -> { + appointmentMemberUpdater.addToSettlement(groupId, request); + }).hasMessage("중복된 참여자의 이름은 저장할 수 없습니다."); + } + + @DisplayName("참여자가 유효할 때 참여자의 입금 상태를 변경할 수 있다.") + @Test + void updatePaymentStatus_Success() { + // given + AppointmentMember appointmentMember = AppointmentMember.builder() + .name("김반숙") + .settlement(mockSettlement) + .role(ExpenseRole.PARTICIPANT) + .build(); + PaymentStatusUpdateRequest request = new PaymentStatusUpdateRequest(true); + + when(appointmentMemberRepository.getById(any())).thenReturn(appointmentMember); + + // when + AppointmentMember result = appointmentMemberUpdater.updatePaymentStatus(1L, request); + + // then + assertThat(result).isNotNull(); + assertThat(result.isPaid()).isTrue(); + } + + @DisplayName("9번째 이상의 참여자가 추가될 때 프로필 ID가 올바르게 순환된다.") + @Test + void addToSettlementProfileRotationSuccess() { + // given + Long groupId = 1L; + appointmentMemberSaveRequest request = mock(appointmentMemberSaveRequest.class); + String newMemberName = "김철수"; + + when(request.name()).thenReturn(newMemberName); + when(settlementReader.read(eq(groupId))).thenReturn(mockSettlement); + + // 기존 멤버 8명 설정 + List mockAppointmentMembers = new ArrayList<>(); + for (int i = 1; i <= 8; i++) { + mockAppointmentMembers.add( + AppointmentMember.builder() + .name("멤버" + i) + .settlement(mockSettlement) + .profileId(i) + .role(ExpenseRole.PARTICIPANT) + .build() + ); + } + when(appointmentMemberReader.findAllBySettlementId(eq(groupId))).thenReturn(mockAppointmentMembers); + + doNothing().when(appointmentMemberValidator).validateMemberNamesNotDuplicate(any()); + + AppointmentMember expectedAppointmentMember = AppointmentMember.builder() + .name(newMemberName) + .settlement(mockSettlement) + .role(ExpenseRole.PARTICIPANT) + .profileId(1) + .build(); + when(appointmentMemberRepository.save(any())).thenReturn(expectedAppointmentMember); + + // when + AppointmentMember result = appointmentMemberUpdater.addToSettlement(groupId, request); + + // then + assertThat(result).isNotNull(); + assertThat(result.getSettlement()).isEqualTo(mockSettlement); + assertThat(result.getName()).isEqualTo(newMemberName); + assertThat(result.getProfileId()).isEqualTo(1); + + verify(appointmentMemberRepository, times(1)).save(any()); + } +} diff --git a/src/test/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberValidatorTest.java b/src/test/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberValidatorTest.java similarity index 68% rename from src/test/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberValidatorTest.java rename to src/test/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberValidatorTest.java index c18100b..23077d9 100644 --- a/src/test/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberValidatorTest.java +++ b/src/test/java/com/dnd/moddo/domain/appointmentMember/service/implementation/AppointmentMemberValidatorTest.java @@ -1,4 +1,4 @@ -package com.dnd.moddo.domain.groupMember.service.implementation; +package com.dnd.moddo.domain.appointmentMember.service.implementation; import static org.assertj.core.api.AssertionsForClassTypes.*; @@ -7,8 +7,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -class GroupMemberValidatorTest { - private final GroupMemberValidator groupMemberValidator = new GroupMemberValidator(); +class AppointmentMemberValidatorTest { + private final AppointmentMemberValidator appointmentMemberValidator = new AppointmentMemberValidator(); @DisplayName("중복된 이름이 없는 경우 검증에 성공한다.") @Test @@ -16,7 +16,7 @@ void validateGroupMemberNamesNotDuplicate() { List names = List.of("김반숙", "이계란", "박완숙"); assertThatCode(() -> { - groupMemberValidator.validateMemberNamesNotDuplicate(names); + appointmentMemberValidator.validateMemberNamesNotDuplicate(names); }).doesNotThrowAnyException(); } @@ -26,8 +26,8 @@ void validateGroupMemberNamesIsDuplicate() { List names = List.of("김반숙", "이계란", "김반숙"); assertThatThrownBy(() -> { - groupMemberValidator.validateMemberNamesNotDuplicate(names); + appointmentMemberValidator.validateMemberNamesNotDuplicate(names); }).hasMessage("중복된 참여자의 이름은 저장할 수 없습니다."); } - + } \ No newline at end of file diff --git a/src/test/java/com/dnd/moddo/domain/character/controller/CharacterControllerTest.java b/src/test/java/com/dnd/moddo/domain/character/controller/CharacterControllerTest.java index a70d3c7..b64c22a 100644 --- a/src/test/java/com/dnd/moddo/domain/character/controller/CharacterControllerTest.java +++ b/src/test/java/com/dnd/moddo/domain/character/controller/CharacterControllerTest.java @@ -29,7 +29,7 @@ void getCharacterSuccess() throws Exception { "https://moddo-s3.s3.amazonaws.com/character/천사 모또-2-big.png" ); - Mockito.when(queryGroupService.findIdByCode(groupToken)).thenReturn(groupId); + Mockito.when(querySettlementService.findIdByCode(groupToken)).thenReturn(groupId); Mockito.when(queryCharacterService.findCharacterByGroupId(eq(groupId))).thenReturn(mockResponse); // when & then @@ -43,7 +43,7 @@ void getCharacterSuccess() throws Exception { .andExpect(jsonPath("$.imageBigUrl").value("https://moddo-s3.s3.amazonaws.com/character/천사 모또-2-big.png")) .andDo(print()); - verify(queryGroupService).findIdByCode(groupToken); + verify(querySettlementService).findIdByCode(groupToken); verify(queryCharacterService).findCharacterByGroupId(groupId); } @@ -52,7 +52,7 @@ void getCharacterSuccess() throws Exception { void getCharacterInvalidToken() throws Exception { // given String groupToken = "invalid.groupToken"; - when(queryGroupService.findIdByCode(groupToken)).thenThrow(new TokenInvalidException()); + when(querySettlementService.findIdByCode(groupToken)).thenThrow(new TokenInvalidException()); // when & then mockMvc.perform(get("/api/v1/character") @@ -60,7 +60,7 @@ void getCharacterInvalidToken() throws Exception { .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isUnauthorized()); - verify(queryGroupService).findIdByCode(groupToken); + verify(querySettlementService).findIdByCode(groupToken); verify(queryCharacterService, never()).findCharacterByGroupId(any()); } @@ -69,7 +69,7 @@ void getCharacterInvalidToken() throws Exception { void getCharacterMissingToken() throws Exception { // when String groupToken = ""; - when(queryGroupService.findIdByCode(groupToken)).thenThrow(new MissingTokenException()); + when(querySettlementService.findIdByCode(groupToken)).thenThrow(new MissingTokenException()); // then mockMvc.perform(get("/api/v1/character") @@ -77,7 +77,7 @@ void getCharacterMissingToken() throws Exception { .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isUnauthorized()); - verify(queryGroupService).findIdByCode(groupToken); + verify(querySettlementService).findIdByCode(groupToken); verify(queryCharacterService, never()).findCharacterByGroupId(any()); } } diff --git a/src/test/java/com/dnd/moddo/domain/character/entity/CharacterTest.java b/src/test/java/com/dnd/moddo/domain/character/entity/CharacterTest.java index eee6769..7518224 100644 --- a/src/test/java/com/dnd/moddo/domain/character/entity/CharacterTest.java +++ b/src/test/java/com/dnd/moddo/domain/character/entity/CharacterTest.java @@ -8,7 +8,7 @@ import org.junit.jupiter.api.Test; import com.dnd.moddo.domain.character.entity.Character; -import com.dnd.moddo.domain.group.entity.Group; +import com.dnd.moddo.domain.settlement.entity.Settlement; class CharacterTest { @@ -16,7 +16,7 @@ class CharacterTest { @Test void characterEntityCreationTest() { // given - Group group = Group.builder() + Settlement settlement = Settlement.builder() .writer(1L) .name("Test Group") .password("testPassword") @@ -25,7 +25,7 @@ void characterEntityCreationTest() { // when Character character = Character.builder() - .group(group) + .settlement(settlement) .name("러키 모또") .rarity("1") .imageUrl("https://moddo-s3.s3.amazonaws.com/character/lucky-1.png") @@ -34,7 +34,7 @@ void characterEntityCreationTest() { // then assertThat(character).isNotNull(); - assertThat(character.getGroup()).isEqualTo(group); + assertThat(character.getSettlement()).isEqualTo(settlement); assertThat(character.getName()).isEqualTo("러키 모또"); assertThat(character.getRarity()).isEqualTo("1"); assertThat(character.getImageUrl()).isEqualTo("https://moddo-s3.s3.amazonaws.com/character/lucky-1.png"); diff --git a/src/test/java/com/dnd/moddo/domain/character/service/implementation/CharacterReaderTest.java b/src/test/java/com/dnd/moddo/domain/character/service/implementation/CharacterReaderTest.java index fcdf4c1..84b3e9f 100644 --- a/src/test/java/com/dnd/moddo/domain/character/service/implementation/CharacterReaderTest.java +++ b/src/test/java/com/dnd/moddo/domain/character/service/implementation/CharacterReaderTest.java @@ -17,9 +17,9 @@ import com.dnd.moddo.domain.character.entity.Character; import com.dnd.moddo.domain.character.repository.CharacterRepository; import com.dnd.moddo.domain.character.service.implementation.CharacterReader; -import com.dnd.moddo.domain.group.entity.Group; import com.dnd.moddo.domain.image.dto.CharacterResponse; import com.dnd.moddo.domain.image.exception.CharacterNotFoundException; +import com.dnd.moddo.domain.settlement.entity.Settlement; @ExtendWith(MockitoExtension.class) class CharacterReaderTest { @@ -36,14 +36,14 @@ class CharacterReaderTest { @BeforeEach void setUp() { groupId = 1L; - Group mockGroup = Group.builder() + Settlement mockSettlement = Settlement.builder() .writer(1L) .name("Test Group") .password("testPassword") .build(); mockCharacter = Character.builder() - .group(mockGroup) + .settlement(mockSettlement) .name("러키 모또") .rarity("1") .imageUrl("https://moddo-s3.s3.amazonaws.com/character/lucky-1.png") @@ -55,7 +55,7 @@ void setUp() { @Test void getCharacterByGroupIdSuccess() { // given - when(characterRepository.findByGroupId(groupId)).thenReturn(Optional.of(mockCharacter)); + when(characterRepository.findBySettlementId(groupId)).thenReturn(Optional.of(mockCharacter)); // when CharacterResponse response = characterReader.getCharacterByGroupId(groupId); @@ -67,18 +67,18 @@ void getCharacterByGroupIdSuccess() { assertThat(response.imageUrl()).isEqualTo(mockCharacter.getImageUrl()); assertThat(response.imageBigUrl()).isEqualTo(mockCharacter.getImageBigUrl()); - verify(characterRepository, times(1)).findByGroupId(groupId); + verify(characterRepository, times(1)).findBySettlementId(groupId); } @DisplayName("존재하지 않는 groupId로 캐릭터를 조회하면 예외가 발생한다.") @Test void getCharacterByGroupIdNotFound() { // given - when(characterRepository.findByGroupId(groupId)).thenReturn(Optional.empty()); + when(characterRepository.findBySettlementId(groupId)).thenReturn(Optional.empty()); // when & then assertThrows(CharacterNotFoundException.class, () -> characterReader.getCharacterByGroupId(groupId)); - verify(characterRepository, times(1)).findByGroupId(groupId); + verify(characterRepository, times(1)).findBySettlementId(groupId); } } diff --git a/src/test/java/com/dnd/moddo/domain/expense/controller/ExpenseControllerTest.java b/src/test/java/com/dnd/moddo/domain/expense/controller/ExpenseControllerTest.java index 1eb3e28..aaf3d96 100644 --- a/src/test/java/com/dnd/moddo/domain/expense/controller/ExpenseControllerTest.java +++ b/src/test/java/com/dnd/moddo/domain/expense/controller/ExpenseControllerTest.java @@ -1,6 +1,6 @@ package com.dnd.moddo.domain.expense.controller; -import static com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole.*; +import static com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole.*; import static org.hamcrest.Matchers.*; import static org.mockito.BDDMockito.any; import static org.mockito.BDDMockito.*; @@ -18,6 +18,7 @@ import org.springframework.http.MediaType; import org.springframework.restdocs.payload.JsonFieldType; +import com.dnd.moddo.domain.appointmentMember.exception.AppointmentMemberNotFoundException; import com.dnd.moddo.domain.expense.dto.request.ExpenseImageRequest; import com.dnd.moddo.domain.expense.dto.request.ExpenseRequest; import com.dnd.moddo.domain.expense.dto.request.ExpensesRequest; @@ -26,7 +27,6 @@ import com.dnd.moddo.domain.expense.dto.response.ExpenseResponse; import com.dnd.moddo.domain.expense.dto.response.ExpensesResponse; import com.dnd.moddo.domain.expense.exception.ExpenseNotFoundException; -import com.dnd.moddo.domain.groupMember.exception.GroupMemberNotFoundException; import com.dnd.moddo.domain.memberExpense.dto.request.MemberExpenseRequest; import com.dnd.moddo.domain.memberExpense.dto.response.MemberExpenseResponse; import com.dnd.moddo.global.util.RestDocsTestSupport; @@ -71,7 +71,7 @@ void saveExpensesSuccess() throws Exception { ) )); - when(queryGroupService.findIdByCode(groupToken)).thenReturn(groupId); + when(querySettlementService.findIdByCode(groupToken)).thenReturn(groupId); when(commandExpenseService.createExpenses(eq(groupId), any())).thenReturn(response); mockMvc.perform(post("/api/v1/expenses") @@ -97,7 +97,7 @@ void saveExpensesSuccess() throws Exception { @Test @DisplayName("전체 지출 목록을 정상적으로 조회한다.") - void getAllByGroupIdSuccess() throws Exception { + void getAllBySettlementIdSuccess() throws Exception { // given List expenseResponses = List.of( new ExpenseResponse(1L, 100000L, "지출", LocalDate.of(2025, 2, 3), List.of( @@ -132,8 +132,8 @@ void getAllByGroupIdSuccess() throws Exception { ExpensesResponse response = new ExpensesResponse(expenseResponses); - when(queryGroupService.findIdByCode(groupToken)).thenReturn(groupId); - when(queryExpenseService.findAllByGroupId(groupId)).thenReturn(response); + when(querySettlementService.findIdByCode(groupToken)).thenReturn(groupId); + when(queryExpenseService.findAllBySettlementId(groupId)).thenReturn(response); // when & then mockMvc.perform(get("/api/v1/expenses") @@ -195,8 +195,8 @@ void getExpenseDetailsSuccess() throws Exception { ); ExpenseDetailsResponse response = new ExpenseDetailsResponse(expenseDetail); - given(queryGroupService.findIdByCode(groupToken)).willReturn(groupId); - given(queryExpenseService.findAllExpenseDetailsByGroupId(groupId)).willReturn(response); + given(querySettlementService.findIdByCode(groupToken)).willReturn(groupId); + given(queryExpenseService.findAllExpenseDetailsBySettlementId(groupId)).willReturn(response); // when & then mockMvc.perform(get("/api/v1/expenses/details") @@ -277,9 +277,9 @@ void saveExpensesFail_whenMemberNotFound() throws Exception { ExpensesRequest request = new ExpensesRequest( List.of(new ExpenseRequest(100000L, "지출", LocalDate.now(), List.of()))); - when(queryGroupService.findIdByCode(groupToken)).thenReturn(groupId); + when(querySettlementService.findIdByCode(groupToken)).thenReturn(groupId); when(commandExpenseService.createExpenses(eq(groupId), any())) - .thenThrow(new GroupMemberNotFoundException(1L)); + .thenThrow(new AppointmentMemberNotFoundException(1L)); mockMvc.perform(post("/api/v1/expenses") .param("groupToken", groupToken) diff --git a/src/test/java/com/dnd/moddo/domain/expense/entity/ExpenseTest.java b/src/test/java/com/dnd/moddo/domain/expense/entity/ExpenseTest.java index cde2377..6b501fa 100644 --- a/src/test/java/com/dnd/moddo/domain/expense/entity/ExpenseTest.java +++ b/src/test/java/com/dnd/moddo/domain/expense/entity/ExpenseTest.java @@ -8,16 +8,16 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import com.dnd.moddo.domain.group.entity.Group; +import com.dnd.moddo.domain.settlement.entity.Settlement; import com.dnd.moddo.global.support.GroupTestFactory; class ExpenseTest { - private Group mockGroup; + private Settlement mockSettlement; @BeforeEach void setUp() { - mockGroup = GroupTestFactory.createDefault(); + mockSettlement = GroupTestFactory.createDefault(); } @Test @@ -26,7 +26,7 @@ void update() { Long initAmount = 20000L; String initContent = "old content"; LocalDate initDate = LocalDate.of(2025, 02, 03); - Expense expense = new Expense(mockGroup, initAmount, initContent, initDate); + Expense expense = new Expense(mockSettlement, initAmount, initContent, initDate); // when Long newAmount = 30000L; @@ -47,7 +47,7 @@ void updateImgUrl() { Long initAmount = 20000L; String initContent = "old content"; LocalDate initDate = LocalDate.of(2025, 02, 03); - Expense expense = new Expense(mockGroup, initAmount, initContent, initDate); + Expense expense = new Expense(mockSettlement, initAmount, initContent, initDate); List images = List.of("image1.jpg", "image2.jpg"); expense.updateImgUrl(images); diff --git a/src/test/java/com/dnd/moddo/domain/expense/service/CommandExpenseServiceTest.java b/src/test/java/com/dnd/moddo/domain/expense/service/CommandExpenseServiceTest.java index 42184be..3c026d4 100644 --- a/src/test/java/com/dnd/moddo/domain/expense/service/CommandExpenseServiceTest.java +++ b/src/test/java/com/dnd/moddo/domain/expense/service/CommandExpenseServiceTest.java @@ -26,11 +26,11 @@ import com.dnd.moddo.domain.expense.service.implementation.ExpenseDeleter; import com.dnd.moddo.domain.expense.service.implementation.ExpenseReader; import com.dnd.moddo.domain.expense.service.implementation.ExpenseUpdater; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.service.implementation.GroupReader; -import com.dnd.moddo.domain.group.service.implementation.GroupValidator; import com.dnd.moddo.domain.memberExpense.dto.response.MemberExpenseResponse; import com.dnd.moddo.domain.memberExpense.service.CommandMemberExpenseService; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementReader; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementValidator; import com.dnd.moddo.global.support.GroupTestFactory; @ExtendWith(MockitoExtension.class) @@ -45,26 +45,26 @@ class CommandExpenseServiceTest { @Mock private ExpenseDeleter expenseDeleter; @Mock - private GroupReader groupReader; + private SettlementReader settlementReader; @Mock - private GroupValidator groupValidator; + private SettlementValidator settlementValidator; @Mock private CommandMemberExpenseService commandMemberExpenseService; @InjectMocks private CommandExpenseService commandExpenseService; - private Group mockGroup; + private Settlement mockSettlement; @BeforeEach void setUp() { - mockGroup = GroupTestFactory.createDefault(); + mockSettlement = GroupTestFactory.createDefault(); } @DisplayName("모임이 존재할 때 여러 지출 내역 생성에 성공한다.") @Test void createExpense() { //given - Long groupId = mockGroup.getId(); + Long groupId = mockSettlement.getId(); ExpenseRequest expenseRequest1 = new ExpenseRequest(20000L, "투썸플레이스", LocalDate.of(2025, 02, 03), new ArrayList<>()); @@ -73,8 +73,8 @@ void createExpense() { ExpensesRequest request = new ExpensesRequest(List.of(expenseRequest1, expenseRequest2)); - Expense expense1 = new Expense(mockGroup, 20000L, "투썸플레이스", LocalDate.of(2025, 02, 03)); - Expense expense2 = new Expense(mockGroup, 100000L, "하이디라오", LocalDate.of(2025, 02, 03)); + Expense expense1 = new Expense(mockSettlement, 20000L, "투썸플레이스", LocalDate.of(2025, 02, 03)); + Expense expense2 = new Expense(mockSettlement, 100000L, "하이디라오", LocalDate.of(2025, 02, 03)); when(expenseCreator.create(eq(groupId), any(ExpenseRequest.class))) .thenReturn(expense1) .thenReturn(expense2); @@ -93,8 +93,8 @@ void createExpense() { @Test void updateSuccess() { //given - Long groupId = mockGroup.getId(), expenseId = 1L; - Expense mockExpense = new Expense(mockGroup, 20000L, "투썸플레이스", LocalDate.of(2025, 02, 03)); + Long groupId = mockSettlement.getId(), expenseId = 1L; + Expense mockExpense = new Expense(mockSettlement, 20000L, "투썸플레이스", LocalDate.of(2025, 02, 03)); ExpenseRequest expenseRequest = mock(ExpenseRequest.class); ExpenseResponse expectedResponse = ExpenseResponse.of(mockExpense); @@ -167,19 +167,19 @@ void deleteNotFound() { @Test void updateImgUrlSuccess() { // given - Long userId = mockGroup.getWriter(), groupId = mockGroup.getId(), expenseId = 1L; + Long userId = this.mockSettlement.getWriter(), groupId = this.mockSettlement.getId(), expenseId = 1L; ExpenseImageRequest request = mock(ExpenseImageRequest.class); - Group mockGroup = mock(Group.class); + Settlement mockSettlement = mock(Settlement.class); - when(groupReader.read(groupId)).thenReturn(mockGroup); - doNothing().when(groupValidator).checkGroupAuthor(mockGroup, userId); + when(settlementReader.read(groupId)).thenReturn(mockSettlement); + doNothing().when(settlementValidator).checkSettlementAuthor(mockSettlement, userId); // when commandExpenseService.updateImgUrl(userId, groupId, expenseId, request); // then - verify(groupReader, times(1)).read(groupId); - verify(groupValidator, times(1)).checkGroupAuthor(mockGroup, userId); + verify(settlementReader, times(1)).read(groupId); + verify(settlementValidator, times(1)).checkSettlementAuthor(mockSettlement, userId); verify(expenseUpdater, times(1)).updateImgUrl(expenseId, request); } diff --git a/src/test/java/com/dnd/moddo/domain/expense/service/QueryExpenseServiceTest.java b/src/test/java/com/dnd/moddo/domain/expense/service/QueryExpenseServiceTest.java index 9499758..fa1e530 100644 --- a/src/test/java/com/dnd/moddo/domain/expense/service/QueryExpenseServiceTest.java +++ b/src/test/java/com/dnd/moddo/domain/expense/service/QueryExpenseServiceTest.java @@ -15,16 +15,16 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; import com.dnd.moddo.domain.expense.dto.response.ExpenseDetailsResponse; import com.dnd.moddo.domain.expense.dto.response.ExpenseResponse; import com.dnd.moddo.domain.expense.dto.response.ExpensesResponse; import com.dnd.moddo.domain.expense.entity.Expense; import com.dnd.moddo.domain.expense.exception.ExpenseNotFoundException; import com.dnd.moddo.domain.expense.service.implementation.ExpenseReader; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; import com.dnd.moddo.domain.memberExpense.dto.response.MemberExpenseResponse; import com.dnd.moddo.domain.memberExpense.service.QueryMemberExpenseService; +import com.dnd.moddo.domain.settlement.entity.Settlement; import com.dnd.moddo.global.support.GroupTestFactory; @ExtendWith(MockitoExtension.class) @@ -37,24 +37,24 @@ class QueryExpenseServiceTest { @InjectMocks private QueryExpenseService queryExpenseService; - private Group mockGroup; + private Settlement mockSettlement; @BeforeEach void setUp() { - mockGroup = GroupTestFactory.createDefault(); + mockSettlement = GroupTestFactory.createDefault(); } @DisplayName("모임이 존재하면 모임의 모든 지출내역을 조회할 수 있다.") @Test - void findAllByGroupId() { + void findAllBySettlementId() { //given - Long groupId = mockGroup.getId(); + Long groupId = mockSettlement.getId(); List mockExpenses = List.of( - new Expense(mockGroup, 20000L, "투썸플레이스", LocalDate.of(2025, 02, 03)), - new Expense(mockGroup, 35000L, "보드게임카페", LocalDate.of(2025, 02, 03)) + new Expense(mockSettlement, 20000L, "투썸플레이스", LocalDate.of(2025, 02, 03)), + new Expense(mockSettlement, 35000L, "보드게임카페", LocalDate.of(2025, 02, 03)) ); - when(expenseReader.findAllByGroupId(eq(groupId))).thenReturn(mockExpenses); + when(expenseReader.findAllBySettlementId(eq(groupId))).thenReturn(mockExpenses); Long expenseId1 = 1L, expenseId2 = 2L; List responses1 = List.of( @@ -69,14 +69,14 @@ void findAllByGroupId() { .thenReturn(responses2); //when - ExpensesResponse response = queryExpenseService.findAllByGroupId(groupId); + ExpensesResponse response = queryExpenseService.findAllBySettlementId(groupId); //then assertThat(response).isNotNull(); assertThat(response.expenses().size()).isEqualTo(mockExpenses.size()); assertThat(response.expenses().get(0).content()).isEqualTo("투썸플레이스"); - verify(expenseReader, times(1)).findAllByGroupId(eq(groupId)); + verify(expenseReader, times(1)).findAllBySettlementId(eq(groupId)); } @@ -84,8 +84,8 @@ void findAllByGroupId() { @Test void findOneByExpenseIdSuccess() { //given - Long groupId = mockGroup.getId(), expenseId = 1L; - Expense mockExpense = new Expense(mockGroup, 20000L, "투썸플레이스", LocalDate.of(2025, 02, 03)); + Long groupId = mockSettlement.getId(), expenseId = 1L; + Expense mockExpense = new Expense(mockSettlement, 20000L, "투썸플레이스", LocalDate.of(2025, 02, 03)); when(expenseReader.findByExpenseId(eq(expenseId))).thenReturn(mockExpense); @@ -117,7 +117,7 @@ void findOneByExpenseIdNotFound() { @DisplayName("모임 id가 유효하면 모임에 속한 전체 지출내역을 조회할 수 있다.") @Test - void findAllExpenseDetailsByGroupId_Success() { + void findAllExpenseDetailsBySettlementId_Success() { //given Long groupId = 1L; Expense expense1 = mock(Expense.class); @@ -130,7 +130,7 @@ void findAllExpenseDetailsByGroupId_Success() { List mockExpense = List.of(expense1, expense2, expense3); - when(expenseReader.findAllByGroupId(eq(groupId))).thenReturn(mockExpense); + when(expenseReader.findAllBySettlementId(eq(groupId))).thenReturn(mockExpense); when(queryMemberExpenseService.getMemberNamesByExpenseIds(eq(List.of(1L, 2L, 3L)))).thenReturn(Map.of( 1L, List.of("김모또", "김반숙"), @@ -139,14 +139,14 @@ void findAllExpenseDetailsByGroupId_Success() { )); //when - ExpenseDetailsResponse response = queryExpenseService.findAllExpenseDetailsByGroupId(groupId); + ExpenseDetailsResponse response = queryExpenseService.findAllExpenseDetailsBySettlementId(groupId); //then assertThat(response).isNotNull(); assertThat(response.expenses()).hasSize(3); assertThat(response.expenses().get(0).groupMembers()).hasSize(2); - verify(expenseReader, times(1)).findAllByGroupId(eq(groupId)); + verify(expenseReader, times(1)).findAllBySettlementId(eq(groupId)); verify(queryMemberExpenseService, times(1)).getMemberNamesByExpenseIds(any()); } } \ No newline at end of file diff --git a/src/test/java/com/dnd/moddo/domain/expense/service/implementation/ExpenseCreatorTest.java b/src/test/java/com/dnd/moddo/domain/expense/service/implementation/ExpenseCreatorTest.java index 58d4043..91428ef 100644 --- a/src/test/java/com/dnd/moddo/domain/expense/service/implementation/ExpenseCreatorTest.java +++ b/src/test/java/com/dnd/moddo/domain/expense/service/implementation/ExpenseCreatorTest.java @@ -17,9 +17,9 @@ import com.dnd.moddo.domain.expense.dto.request.ExpenseRequest; import com.dnd.moddo.domain.expense.entity.Expense; import com.dnd.moddo.domain.expense.repository.ExpenseRepository; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.repository.GroupRepository; import com.dnd.moddo.domain.memberExpense.service.implementation.MemberExpenseValidator; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.repository.SettlementRepository; import com.dnd.moddo.global.support.GroupTestFactory; @ExtendWith(MockitoExtension.class) @@ -27,30 +27,30 @@ class ExpenseCreatorTest { @Mock private ExpenseRepository expenseRepository; @Mock - private GroupRepository groupRepository; + private SettlementRepository settlementRepository; @Mock private MemberExpenseValidator memberExpenseValidator; @InjectMocks private ExpenseCreator expenseCreator; - private Group mockGroup; + private Settlement mockSettlement; @BeforeEach void setUp() { - mockGroup = GroupTestFactory.createDefault(); + mockSettlement = GroupTestFactory.createDefault(); } @DisplayName("모임이 존재하면 지출내역을 생성에 성공한다.") @Test void createSuccess() { //given - Long groupId = mockGroup.getId(); - when(groupRepository.getById(eq(groupId))).thenReturn(mockGroup); + Long groupId = mockSettlement.getId(); + when(settlementRepository.getById(eq(groupId))).thenReturn(mockSettlement); ExpenseRequest request = mock(ExpenseRequest.class); - Expense mockExpense = new Expense(mockGroup, 20000L, "투썸플레이스", LocalDate.of(2025, 02, 03)); + Expense mockExpense = new Expense(mockSettlement, 20000L, "투썸플레이스", LocalDate.of(2025, 02, 03)); when(expenseRepository.save(any())).thenReturn(mockExpense); - doNothing().when(memberExpenseValidator).validateMembersArePartOfGroup(groupId, new ArrayList<>()); + doNothing().when(memberExpenseValidator).validateMembersArePartOfSettlement(groupId, new ArrayList<>()); //when Expense result = expenseCreator.create(groupId, request); diff --git a/src/test/java/com/dnd/moddo/domain/expense/service/implementation/ExpenseReaderTest.java b/src/test/java/com/dnd/moddo/domain/expense/service/implementation/ExpenseReaderTest.java index 28bb9b9..e293e98 100644 --- a/src/test/java/com/dnd/moddo/domain/expense/service/implementation/ExpenseReaderTest.java +++ b/src/test/java/com/dnd/moddo/domain/expense/service/implementation/ExpenseReaderTest.java @@ -17,7 +17,7 @@ import com.dnd.moddo.domain.expense.entity.Expense; import com.dnd.moddo.domain.expense.exception.ExpenseNotFoundException; import com.dnd.moddo.domain.expense.repository.ExpenseRepository; -import com.dnd.moddo.domain.group.entity.Group; +import com.dnd.moddo.domain.settlement.entity.Settlement; import com.dnd.moddo.global.support.GroupTestFactory; @ExtendWith(MockitoExtension.class) @@ -28,34 +28,34 @@ class ExpenseReaderTest { @InjectMocks private ExpenseReader expenseReader; - private Group mockGroup; + private Settlement mockSettlement; @BeforeEach void setUp() { - mockGroup = GroupTestFactory.createDefault(); + mockSettlement = GroupTestFactory.createDefault(); } @DisplayName("모임이 존재하면 모임에 해당하는 지출내역을 모두 조회할 수 있다.") @Test - void findAllByGroupId() { + void findAllBySettlementId() { //given - Long groupId = mockGroup.getId(); + Long groupId = mockSettlement.getId(); List mockExpenses = List.of( - new Expense(mockGroup, 20000L, "투썸플레이스", LocalDate.of(2025, 02, 03)), - new Expense(mockGroup, 35000L, "보드게임카페", LocalDate.of(2025, 02, 03)) + new Expense(mockSettlement, 20000L, "투썸플레이스", LocalDate.of(2025, 02, 03)), + new Expense(mockSettlement, 35000L, "보드게임카페", LocalDate.of(2025, 02, 03)) ); - when(expenseRepository.findByGroupIdOrderByDateAsc(eq(groupId))).thenReturn(mockExpenses); + when(expenseRepository.findBySettlementIdOrderByDateAsc(eq(groupId))).thenReturn(mockExpenses); //when - List result = expenseReader.findAllByGroupId(groupId); + List result = expenseReader.findAllBySettlementId(groupId); assertThat(result).isNotNull(); assertThat(result.size()).isEqualTo(mockExpenses.size()); assertThat(result.get(0).getContent()).isEqualTo("투썸플레이스"); //then - verify(expenseRepository, times(1)).findByGroupIdOrderByDateAsc(eq(groupId)); + verify(expenseRepository, times(1)).findBySettlementIdOrderByDateAsc(eq(groupId)); } @DisplayName("지출내역이 존재하면 해당 지출내역을 조회할 수 있다.") @@ -63,7 +63,7 @@ void findAllByGroupId() { void findByExpenseIdSuccess() { //given Long expenseId = 1L; - Expense mockExpense = new Expense(mockGroup, 20000L, "투썸플레이스", LocalDate.of(2025, 02, 03)); + Expense mockExpense = new Expense(mockSettlement, 20000L, "투썸플레이스", LocalDate.of(2025, 02, 03)); when(expenseRepository.getById(eq(expenseId))).thenReturn(mockExpense); //when diff --git a/src/test/java/com/dnd/moddo/domain/group/service/CommandGroupServiceTest.java b/src/test/java/com/dnd/moddo/domain/group/service/CommandGroupServiceTest.java deleted file mode 100644 index f06fd7f..0000000 --- a/src/test/java/com/dnd/moddo/domain/group/service/CommandGroupServiceTest.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.dnd.moddo.domain.group.service; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; - -import java.time.LocalDateTime; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.dnd.moddo.domain.group.dto.request.GroupAccountRequest; -import com.dnd.moddo.domain.group.dto.request.GroupPasswordRequest; -import com.dnd.moddo.domain.group.dto.request.GroupRequest; -import com.dnd.moddo.domain.group.dto.response.GroupPasswordResponse; -import com.dnd.moddo.domain.group.dto.response.GroupResponse; -import com.dnd.moddo.domain.group.dto.response.GroupSaveResponse; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.service.implementation.GroupCreator; -import com.dnd.moddo.domain.group.service.implementation.GroupReader; -import com.dnd.moddo.domain.group.service.implementation.GroupUpdater; -import com.dnd.moddo.domain.group.service.implementation.GroupValidator; -import com.dnd.moddo.domain.groupMember.dto.response.GroupMemberResponse; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; -import com.dnd.moddo.domain.groupMember.service.CommandGroupMemberService; -import com.dnd.moddo.global.jwt.utill.JwtProvider; - -@ExtendWith(MockitoExtension.class) -class CommandGroupServiceTest { - - @Mock - private GroupCreator groupCreator; - - @Mock - private GroupUpdater groupUpdater; // 추가 - - @Mock - private GroupReader groupReader; - - @Mock - private GroupValidator groupValidator; - @Mock - private JwtProvider jwtProvider; - @Mock - private CommandGroupMemberService commandGroupMemberService; - @InjectMocks - private CommandGroupService commandGroupService; - - private GroupRequest groupRequest; - private GroupAccountRequest groupAccountRequest; - private Group group; - private GroupResponse groupResponse; - private GroupSaveResponse expectedResponse; - - @BeforeEach - void setUp() { - groupRequest = new GroupRequest("GroupName", "password123"); - groupResponse = new GroupResponse(1L, 1L, LocalDateTime.now(), LocalDateTime.now().plusDays(1), "bank", - "1234-1234", LocalDateTime.now().plusDays(1)); - groupAccountRequest = new GroupAccountRequest("newBank", "5678-5678"); - expectedResponse = new GroupSaveResponse("groupToken", mock(GroupMemberResponse.class)); - group = mock(Group.class); - } - - @Test - @DisplayName("그룹과 총무를 생성할 수 있다.") - void createGroup() { - // Given - GroupMemberResponse groupMemberResponse = new GroupMemberResponse(1L, ExpenseRole.MANAGER, "김모또", null, true, - LocalDateTime.now()); - - when(groupCreator.createGroup(any(GroupRequest.class), anyLong())).thenReturn(group); - when(group.getCode()).thenReturn("code"); - when(commandGroupMemberService.createManager(any(), any())).thenReturn(groupMemberResponse); - - // When - GroupSaveResponse response = commandGroupService.createGroup(groupRequest, 1L); - - // Then - assertThat(response).isNotNull(); - assertThat(response.groupToken()).isEqualTo("code"); - assertThat(response.manager().role()).isEqualTo(ExpenseRole.MANAGER); - - verify(groupCreator, times(1)).createGroup(any(GroupRequest.class), anyLong()); - verify(commandGroupMemberService, times(1)).createManager(any(), any()); - } - - @Test - @DisplayName("그룹의 계좌 정보를 업데이트할 수 있다.") - void updateGroupAccount() { - // Given - when(groupReader.read(anyLong())).thenReturn(group); - when(groupUpdater.updateAccount(any(GroupAccountRequest.class), anyLong())).thenReturn(group); - doNothing().when(groupValidator).checkGroupAuthor(any(Group.class), anyLong()); - - // When - GroupResponse result = commandGroupService.updateAccount(groupAccountRequest, group.getWriter(), group.getId()); - - // Then - assertThat(result).isNotNull(); - verify(groupReader, times(1)).read(anyLong()); - verify(groupValidator, times(1)).checkGroupAuthor(any(Group.class), anyLong()); - verify(groupUpdater, times(1)).updateAccount(any(GroupAccountRequest.class), anyLong()); - } - - @Test - @DisplayName("올바른 비밀번호를 입력하면 확인 메시지를 반환한다.") - void VerifyPassword_Success() { - // Given - GroupPasswordRequest request = new GroupPasswordRequest("correctPassword"); - GroupPasswordResponse expectedResponse = GroupPasswordResponse.from("확인되었습니다."); - - when(groupReader.read(group.getId())).thenReturn(group); - doNothing().when(groupValidator).checkGroupAuthor(group, 1L); - when(groupValidator.checkGroupPassword(request, group.getPassword())).thenReturn(expectedResponse); - - // When - GroupPasswordResponse response = commandGroupService.isPasswordMatch(group.getId(), 1L, request); - - // Then - assertThat(response).isNotNull(); - assertThat(response.status()).isEqualTo("확인되었습니다."); - - verify(groupReader, times(1)).read(group.getId()); - verify(groupValidator, times(1)).checkGroupAuthor(group, 1L); - verify(groupValidator, times(1)).checkGroupPassword(request, group.getPassword()); - } - - @Test - @DisplayName("잘못된 비밀번호를 입력하면 예외가 발생한다.") - void VerifyPassword_Fail_WrongPassword() { - // Given - GroupPasswordRequest request = new GroupPasswordRequest("wrongPassword"); - String storedPassword = "correctPassword"; - - when(groupReader.read(group.getId())).thenReturn(group); - doNothing().when(groupValidator).checkGroupAuthor(group, 1L); - when(group.getPassword()).thenReturn(storedPassword); - - doThrow(new RuntimeException("비밀번호가 일치하지 않습니다.")) - .when(groupValidator).checkGroupPassword(request, storedPassword); - - // When & Then - assertThatThrownBy(() -> commandGroupService.isPasswordMatch(group.getId(), 1L, request)) - .isInstanceOf(RuntimeException.class) - .hasMessageContaining("비밀번호가 일치하지 않습니다."); - - verify(groupReader, times(1)).read(group.getId()); - verify(groupValidator, times(1)).checkGroupAuthor(group, 1L); - verify(groupValidator, times(1)).checkGroupPassword(request, storedPassword); - } -} diff --git a/src/test/java/com/dnd/moddo/domain/group/service/QueryGroupServiceTest.java b/src/test/java/com/dnd/moddo/domain/group/service/QueryGroupServiceTest.java deleted file mode 100644 index bcbd6be..0000000 --- a/src/test/java/com/dnd/moddo/domain/group/service/QueryGroupServiceTest.java +++ /dev/null @@ -1,190 +0,0 @@ -package com.dnd.moddo.domain.group.service; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; -import static org.springframework.test.util.ReflectionTestUtils.*; - -import java.time.LocalDateTime; -import java.util.List; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.dnd.moddo.domain.group.dto.response.GroupDetailResponse; -import com.dnd.moddo.domain.group.dto.response.GroupHeaderResponse; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.exception.GroupNotFoundException; -import com.dnd.moddo.domain.group.service.implementation.GroupReader; -import com.dnd.moddo.domain.group.service.implementation.GroupValidator; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; -import com.dnd.moddo.global.support.GroupTestFactory; - -@ExtendWith(MockitoExtension.class) -class QueryGroupServiceTest { - - @InjectMocks - private QueryGroupService queryGroupService; - - @Mock - private GroupReader groupReader; - - @Mock - private GroupValidator groupValidator; - - private Group group; - private GroupMember groupMember; - - @BeforeEach - void setUp() { - group = GroupTestFactory.createDefault(); - groupMember = new GroupMember("김완숙", 1, group, false, ExpenseRole.MANAGER); - - setField(group, "id", 1L); - } - - @Test - @DisplayName("그룹 상세 정보를 정상적으로 조회할 수 있다.") - void FindOne_Success() { - // Given - when(groupReader.read(anyLong())).thenReturn(group); - when(groupReader.findByGroup(group.getId())).thenReturn(List.of(groupMember)); - doNothing().when(groupValidator).checkGroupAuthor(group, 1L); - - // When - GroupDetailResponse response = queryGroupService.findOne(group.getId(), 1L); - - // Then - assertThat(response).isNotNull(); - assertThat(response.id()).isEqualTo(group.getId()); - assertThat(response.groupName()).isEqualTo(group.getName()); - assertThat(response.members()).hasSize(1); - assertThat(response.members().get(0).name()).isEqualTo(groupMember.getName()); - - verify(groupReader, times(1)).read(1L); - verify(groupReader, times(1)).findByGroup(group.getId()); - verify(groupValidator, times(1)).checkGroupAuthor(group, 1L); - } - - @Test - @DisplayName("그룹 작성자가 아닐 경우 예외가 발생한다.") - void FindOne_Failure_WhenNotGroupAuthor() { - // Given - when(groupReader.read(anyLong())).thenReturn(group); - doThrow(new RuntimeException("Not an author")).when(groupValidator).checkGroupAuthor(group, 2L); - - // When & Then - assertThatThrownBy(() -> queryGroupService.findOne(1L, 2L)) - .isInstanceOf(RuntimeException.class) - .hasMessageContaining("Not an author"); - - verify(groupReader, times(1)).read(1L); - verify(groupValidator, times(1)).checkGroupAuthor(group, 2L); - } - - @Test - @DisplayName("그룹을 찾을 수 없을 경우 예외가 발생한다.") - void FindOne_Failure_WhenGroupNotFound() { - // Given - when(groupReader.read(anyLong())).thenThrow(new RuntimeException("Group not found")); - - // When & Then - assertThatThrownBy(() -> queryGroupService.findOne(1L, 1L)) - .isInstanceOf(RuntimeException.class) - .hasMessageContaining("Group not found"); - - verify(groupReader, times(1)).read(1L); - } - - @Test - @DisplayName("그룹 헤더를 정상적으로 조회할 수 있다.") - void FindByGroupHeader_Success() { - // Given - GroupHeaderResponse expectedResponse = new GroupHeaderResponse(group.getName(), 1000L, - LocalDateTime.now().plusDays(1), group.getBank(), group.getAccountNumber()); - when(groupReader.findByHeader(group.getId())).thenReturn(expectedResponse); - - // When - GroupHeaderResponse response = queryGroupService.findByGroupHeader(group.getId()); - - // Then - assertThat(response).isNotNull(); - assertThat(response.groupName()).isEqualTo(group.getName()); - assertThat(response.bank()).isEqualTo(group.getBank()); - assertThat(response.accountNumber()).isEqualTo(group.getAccountNumber()); - - verify(groupReader, times(1)).findByHeader(group.getId()); - } - - @Test - @DisplayName("그룹 헤더를 찾을 수 없을 경우 예외가 발생한다.") - void FindByGroupHeader_Failure_WhenHeaderNotFound() { - // Given - when(groupReader.findByHeader(anyLong())).thenThrow(new RuntimeException("Header not found")); - - // When & Then - assertThatThrownBy(() -> queryGroupService.findByGroupHeader(1L)) - .isInstanceOf(RuntimeException.class) - .hasMessageContaining("Header not found"); - - verify(groupReader, times(1)).findByHeader(1L); - } - - @DisplayName("group code가 유효할 때 group Id를 찾을 수 있다.") - @Test - void FindByGroupId_Success() { - //given - Long expected = 1L; - when(groupReader.findIdByGroupCode(anyString())).thenReturn(expected); - //when - Long result = queryGroupService.findIdByCode("code"); - //then - assertThat(result).isEqualTo(expected); - verify(groupReader, times(1)).findIdByGroupCode(anyString()); - } - - @DisplayName("group code가 존재하지 않을때 예외가 발생한다..") - @Test - void FindByGroupId_ThrowException_WhenCodeNotFound() { - //given - when(groupReader.findIdByGroupCode(anyString())).thenThrow(new GroupNotFoundException("code")); - //when & then - assertThatThrownBy(() -> queryGroupService.findIdByCode("code")) - .isInstanceOf(RuntimeException.class) - .hasMessageContaining("code"); - - verify(groupReader, times(1)).findIdByGroupCode(anyString()); - } - - @DisplayName("group code가 유효할 때 group Id를 찾을 수 있다.") - @Test - void FindByGroupIdNoCache_Success() { - //given - Long expected = 1L; - when(groupReader.findIdByGroupCode(anyString())).thenReturn(expected); - //when - Long result = queryGroupService.findIdByCodeNoCache("code"); - //then - assertThat(result).isEqualTo(expected); - verify(groupReader, times(1)).findIdByGroupCode(anyString()); - } - - @DisplayName("group code가 존재하지 않을때 예외가 발생한다..") - @Test - void FindByGroupIdNoCache_ThrowException_WhenCodeNotFound() { - //given - when(groupReader.findIdByGroupCode(anyString())).thenThrow(new GroupNotFoundException("code")); - //when & then - assertThatThrownBy(() -> queryGroupService.findIdByCodeNoCache("code")) - .isInstanceOf(RuntimeException.class) - .hasMessageContaining("code"); - - verify(groupReader, times(1)).findIdByGroupCode(anyString()); - } -} diff --git a/src/test/java/com/dnd/moddo/domain/group/service/implementation/GroupReaderTest.java b/src/test/java/com/dnd/moddo/domain/group/service/implementation/GroupReaderTest.java deleted file mode 100644 index d52712a..0000000 --- a/src/test/java/com/dnd/moddo/domain/group/service/implementation/GroupReaderTest.java +++ /dev/null @@ -1,127 +0,0 @@ -package com.dnd.moddo.domain.group.service.implementation; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.*; - -import java.util.List; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.dnd.moddo.domain.expense.repository.ExpenseRepository; -import com.dnd.moddo.domain.group.dto.response.GroupHeaderResponse; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.exception.GroupNotFoundException; -import com.dnd.moddo.domain.group.repository.GroupRepository; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.repository.GroupMemberRepository; - -@ExtendWith(MockitoExtension.class) -class GroupReaderTest { - - @Mock - private GroupRepository groupRepository; - - @Mock - private ExpenseRepository expenseRepository; - - @Mock - private GroupMemberRepository groupMemberRepository; - - @InjectMocks - private GroupReader groupReader; - - @Test - @DisplayName("그룹 ID를 통해 그룹을 정상적으로 조회할 수 있다.") - void readGroup_Success() { - // Given - Long groupId = 1L; - Group mockGroup = mock(Group.class); - - when(groupRepository.getById(anyLong())).thenReturn(mockGroup); - - // When - Group result = groupReader.read(groupId); - - // Then - assertThat(result).isNotNull(); - verify(groupRepository, times(1)).getById(groupId); - } - - @Test - @DisplayName("그룹을 통해 그룹 멤버 목록을 정상적으로 조회할 수 있다.") - void findByGroup_Success() { - // Given - Group mockGroup = mock(Group.class); - when(mockGroup.getId()).thenReturn(1L); - List mockMembers = List.of(mock(GroupMember.class), mock(GroupMember.class)); - - when(groupMemberRepository.findByGroupId(anyLong())).thenReturn(mockMembers); - - // When - List result = groupReader.findByGroup(mockGroup.getId()); - - // Then - assertThat(result).hasSize(2); - verify(groupMemberRepository, times(1)).findByGroupId(mockGroup.getId()); - } - - @Test - @DisplayName("그룹 ID를 통해 그룹 헤더 정보를 정상적으로 조회할 수 있다.") - void findByHeader_Success() { - // Given - Long groupId = 1L; - Group mockGroup = mock(Group.class); - when(mockGroup.getName()).thenReturn("모임 이름"); - when(mockGroup.getBank()).thenReturn("은행"); - when(mockGroup.getAccountNumber()).thenReturn("1234-1234"); - when(groupRepository.getById(anyLong())).thenReturn(mockGroup); - - Long totalAmount = 1000L; - when(expenseRepository.sumAmountByGroup(any(Group.class))).thenReturn(totalAmount); - - // When - GroupHeaderResponse result = groupReader.findByHeader(groupId); - - // Then - assertThat(result).isNotNull(); - assertThat(result.groupName()).isEqualTo("모임 이름"); - assertThat(result.totalAmount()).isEqualTo(1000L); - assertThat(result.bank()).isEqualTo("은행"); - assertThat(result.accountNumber()).isEqualTo("1234-1234"); - verify(groupRepository, times(1)).getById(groupId); - verify(expenseRepository, times(1)).sumAmountByGroup(mockGroup); - } - - @DisplayName("group code로 group Id를 찾을 수 있다.") - @Test - void whenValidGroupCode_thenReturnsGroupId() { - //given - Long expected = 1L; - when(groupRepository.getIdByCode(anyString())).thenReturn(expected); - //when - Long result = groupReader.findIdByGroupCode("code"); - //then - assertThat(result).isEqualTo(expected); - verify(groupRepository, times(1)).getIdByCode(anyString()); - } - - @DisplayName("group code로 group id를 찾을 수 없을때 예외가 발생한다.") - @Test - void whenInvalidGroupCode_thenThrowsException() { - //given - when(groupRepository.getIdByCode(anyString())).thenThrow(new GroupNotFoundException("code")); - //when & then - assertThatThrownBy(() -> groupReader.findIdByGroupCode("code")) - .isInstanceOf(GroupNotFoundException.class) - .hasMessageContaining("code"); - - verify(groupRepository, times(1)).getIdByCode(anyString()); - } -} diff --git a/src/test/java/com/dnd/moddo/domain/group/service/implementation/GroupUpdaterTest.java b/src/test/java/com/dnd/moddo/domain/group/service/implementation/GroupUpdaterTest.java deleted file mode 100644 index 0c5a3dc..0000000 --- a/src/test/java/com/dnd/moddo/domain/group/service/implementation/GroupUpdaterTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.dnd.moddo.domain.group.service.implementation; - -import static org.assertj.core.api.AssertionsForClassTypes.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.dnd.moddo.domain.group.dto.request.GroupAccountRequest; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.exception.GroupNotFoundException; -import com.dnd.moddo.domain.group.repository.GroupRepository; - -@ExtendWith(MockitoExtension.class) -class GroupUpdaterTest { - @Mock - private GroupRepository groupRepository; - @InjectMocks - private GroupUpdater groupUpdater; - - @DisplayName("그룹이 존재하면 계좌 정보를 수정할 수 있다.") - @Test - void updateAccountSuccess() { - // given - Long groupId = 1L; - Group mockGroup = mock(Group.class); - GroupAccountRequest request = mock(GroupAccountRequest.class); - - when(groupRepository.getById(eq(groupId))).thenReturn(mockGroup); - - // when - Group updatedGroup = groupUpdater.updateAccount(request, groupId); - - // then - verify(mockGroup, times(1)).updateAccount(any()); - assertThat(updatedGroup).isEqualTo(mockGroup); - } - - @DisplayName("그룹이 존재하지 않으면 계좌 정보를 수정할 때 예외가 발생한다.") - @Test - void updateAccountNotFoundGroup() { - // given - Long groupId = 1L; - GroupAccountRequest request = mock(GroupAccountRequest.class); - - doThrow(new GroupNotFoundException(groupId)).when(groupRepository).getById(groupId); - - // when & then - assertThatThrownBy(() -> groupUpdater.updateAccount(request, groupId)) - .isInstanceOf(GroupNotFoundException.class); - } - -} diff --git a/src/test/java/com/dnd/moddo/domain/group/service/implementation/GroupValidatorTest.java b/src/test/java/com/dnd/moddo/domain/group/service/implementation/GroupValidatorTest.java deleted file mode 100644 index b10447b..0000000 --- a/src/test/java/com/dnd/moddo/domain/group/service/implementation/GroupValidatorTest.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.dnd.moddo.domain.group.service.implementation; - -import com.dnd.moddo.domain.group.dto.request.GroupPasswordRequest; -import com.dnd.moddo.domain.group.dto.response.GroupPasswordResponse; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.exception.GroupNotAuthorException; -import com.dnd.moddo.domain.group.exception.InvalidPasswordException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.springframework.security.crypto.password.PasswordEncoder; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -class GroupValidatorTest { - - private GroupValidator groupValidator; - - @Mock - private PasswordEncoder passwordEncoder; - - @BeforeEach - void setUp() { - MockitoAnnotations.openMocks(this); - groupValidator = new GroupValidator(passwordEncoder, null); // GroupRepository는 필요 없으면 null 처리 - } - - @Test - @DisplayName("그룹 작성자와 요청 사용자가 같으면 예외가 발생하지 않는다.") - void checkGroupAuthor_Success() { - // Given - Group group = mock(Group.class); - Long writer = 1L; - when(group.isWriter(writer)).thenReturn(true); - - // When & Then - groupValidator.checkGroupAuthor(group, writer); - } - - @Test - @DisplayName("그룹 작성자와 요청 사용자가 다르면 GroupNotAuthorException 예외가 발생한다.") - void checkGroupAuthor_Fail() { - Group group = mock(Group.class); - Long writer = 1L; - when(group.isWriter(writer)).thenReturn(false); - - // When & Then - assertThatThrownBy(() -> groupValidator.checkGroupAuthor(group, writer)) - .isInstanceOf(GroupNotAuthorException.class); - } - - @Test - @DisplayName("올바른 비밀번호를 입력하면 확인 메시지를 반환한다.") - void checkGroupPassword_Success() { - // Given - String rawPassword = "correctPassword"; - String encodedPassword = "$2a$10$WzHqXjA4oH8lTxH9m6Q7se1k2dG0B1h7U4Fv0t5y8LdHwWx7uy6MS"; - GroupPasswordRequest request = new GroupPasswordRequest(rawPassword); - - when(passwordEncoder.matches(rawPassword, encodedPassword)).thenReturn(true); - - // When - GroupPasswordResponse response = groupValidator.checkGroupPassword(request, encodedPassword); - - // Then - assertThat(response.status()).isEqualTo("확인되었습니다."); - } - - @Test - @DisplayName("잘못된 비밀번호를 입력하면 InvalidPasswordException 예외가 발생한다.") - void checkGroupPassword_Fail() { - // Given - String rawPassword = "wrongPassword"; - String encodedPassword = "$2a$10$WzHqXjA4oH8lTxH9m6Q7se1k2dG0B1h7U4Fv0t5y8LdHwWx7uy6MS"; - GroupPasswordRequest request = new GroupPasswordRequest(rawPassword); - - when(passwordEncoder.matches(rawPassword, encodedPassword)).thenReturn(false); - - // When & Then - assertThatThrownBy(() -> groupValidator.checkGroupPassword(request, encodedPassword)) - .isInstanceOf(InvalidPasswordException.class); - } -} diff --git a/src/test/java/com/dnd/moddo/domain/groupMember/service/CommandGroupMemberServiceTest.java b/src/test/java/com/dnd/moddo/domain/groupMember/service/CommandGroupMemberServiceTest.java deleted file mode 100644 index 4c67b74..0000000 --- a/src/test/java/com/dnd/moddo/domain/groupMember/service/CommandGroupMemberServiceTest.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.dnd.moddo.domain.groupMember.service; - -import static org.assertj.core.api.BDDAssertions.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.groupMember.dto.request.GroupMemberSaveRequest; -import com.dnd.moddo.domain.groupMember.dto.request.PaymentStatusUpdateRequest; -import com.dnd.moddo.domain.groupMember.dto.response.GroupMemberResponse; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; -import com.dnd.moddo.domain.groupMember.service.implementation.GroupMemberCreator; -import com.dnd.moddo.domain.groupMember.service.implementation.GroupMemberUpdater; -import com.dnd.moddo.global.support.GroupTestFactory; - -@ExtendWith(MockitoExtension.class) -public class CommandGroupMemberServiceTest { - @Mock - private GroupMemberCreator groupMemberCreator; - @Mock - private GroupMemberUpdater groupMemberUpdater; - @InjectMocks - private CommandGroupMemberService commandGroupMemberService; - - private Group mockGroup; - - @BeforeEach - void setUp() { - mockGroup = GroupTestFactory.createDefault(); - } - - @DisplayName("모든 정보가 유효할때 총무 생성에 성공한다.") - @Test - void whenValidInfo_thenCreateSuccess() { - //given - Long userId = 1L; - GroupMember expectedMembers = GroupMember.builder() - .name("김모또") - .group(mockGroup) - .profileId(0) - .role(ExpenseRole.MANAGER) - .build(); - Group mockGroup = mock(Group.class); - when(groupMemberCreator.createManagerForGroup(any(Group.class), eq(userId))).thenReturn(expectedMembers); - - // when - GroupMemberResponse response = commandGroupMemberService.createManager(mockGroup, userId); - - //then - assertThat(response).isNotNull(); - assertThat(response.name()).isEqualTo("김모또"); - assertThat(response.role()).isEqualTo(ExpenseRole.MANAGER); - verify(groupMemberCreator, times(1)).createManagerForGroup(any(Group.class), any()); - } - - @DisplayName("모든 정보가 유효할때 기존 모임의 참여자 추가가 성공한다.") - @Test - void whenValidInfo_thenAddGroupMemberSuccess() { - //given - Long groupId = mockGroup.getId(); - GroupMemberSaveRequest request = mock(GroupMemberSaveRequest.class); - GroupMember expectedMember = GroupMember.builder() - .name("김반숙") - .group(mockGroup) - .profileId(1) - .role(ExpenseRole.PARTICIPANT) - .build(); - - when(groupMemberUpdater.addToGroup(eq(groupId), any(GroupMemberSaveRequest.class))).thenReturn(expectedMember); - - //when - GroupMemberResponse response = commandGroupMemberService.addGroupMember(groupId, request); - - //then - assertThat(response).isNotNull(); - assertThat(response.name()).isEqualTo("김반숙"); - verify(groupMemberUpdater, times(1)).addToGroup(eq(groupId), any(GroupMemberSaveRequest.class)); - } - - @DisplayName("참여자 입금 내역을 업데이트 할 수 있다.") - @Test - void whenUpdatePaymentStatus_thenSuccess() { - //given - GroupMember expectedGroupMember = GroupMember.builder() - .name("김반숙") - .group(mockGroup) - .isPaid(true) - .profileId(1) - .role(ExpenseRole.PARTICIPANT) - .build(); - PaymentStatusUpdateRequest request = new PaymentStatusUpdateRequest(true); - when(groupMemberUpdater.updatePaymentStatus(any(), eq(request))).thenReturn(expectedGroupMember); - - //then - GroupMemberResponse response = commandGroupMemberService.updatePaymentStatus(1L, request); - - //then - assertThat(response).isNotNull(); - assertThat(response.name()).isEqualTo("김반숙"); - assertThat(response.role()).isEqualTo(ExpenseRole.PARTICIPANT); - assertThat(response.isPaid()).isTrue(); - - verify(groupMemberUpdater, times(1)).updatePaymentStatus(any(), eq(request)); - } -} diff --git a/src/test/java/com/dnd/moddo/domain/groupMember/service/QueryGroupMemberServiceTest.java b/src/test/java/com/dnd/moddo/domain/groupMember/service/QueryGroupMemberServiceTest.java deleted file mode 100644 index 8c01370..0000000 --- a/src/test/java/com/dnd/moddo/domain/groupMember/service/QueryGroupMemberServiceTest.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.dnd.moddo.domain.groupMember.service; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.List; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.groupMember.dto.response.GroupMembersResponse; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; -import com.dnd.moddo.domain.groupMember.service.implementation.GroupMemberReader; -import com.dnd.moddo.global.support.GroupTestFactory; - -@ExtendWith(MockitoExtension.class) -public class QueryGroupMemberServiceTest { - - @Mock - private GroupMemberReader groupMemberReader; - @InjectMocks - private QueryGroupMemberService queryGroupMemberService; - - private Group mockGroup; - private List mockMembers; - - @BeforeEach - void setUp() { - mockGroup = GroupTestFactory.createDefault(); - - mockMembers = List.of( - GroupMember.builder() - .name("김모또") - .group(mockGroup) - .profileId(0) - .role(ExpenseRole.MANAGER) - .build(), - GroupMember.builder() - .name("김반숙") - .profileId(1) - .group(mockGroup) - .role(ExpenseRole.PARTICIPANT) - .build() - ); - } - - @DisplayName("모임이 존재하면 모임의 모든 참여자를 조회할 수 있다.") - @Test - void findAll() { - //given - Long groupId = mockGroup.getId(); - - when(groupMemberReader.findAllByGroupId(eq(groupId))).thenReturn(mockMembers); - - //when - GroupMembersResponse response = queryGroupMemberService.findAll(groupId); - - //then - assertThat(response).isNotNull(); - assertThat(response.members().size()).isEqualTo(2); - assertThat(response.members().get(0).name()).isEqualTo("김모또"); - verify(groupMemberReader, times(1)).findAllByGroupId(eq(groupId)); - } -} diff --git a/src/test/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberDeleterTest.java b/src/test/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberDeleterTest.java deleted file mode 100644 index 622f4ff..0000000 --- a/src/test/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberDeleterTest.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.dnd.moddo.domain.groupMember.service.implementation; - -import static org.assertj.core.api.AssertionsForClassTypes.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; -import com.dnd.moddo.domain.groupMember.exception.GroupMemberNotFoundException; -import com.dnd.moddo.domain.groupMember.repository.GroupMemberRepository; -import com.dnd.moddo.global.support.GroupTestFactory; - -@ExtendWith(MockitoExtension.class) -class GroupMemberDeleterTest { - - @Mock - private GroupMemberRepository groupMemberRepository; - @Mock - private GroupMemberReader groupMemberReader; - @InjectMocks - private GroupMemberDeleter groupMemberDeleter; - - private Group mockGroup; - - @BeforeEach - void setUp() { - mockGroup = GroupTestFactory.createDefault(); - } - - @DisplayName("유효한 참여자 id로 삭제를 요청하면 성공적으로 삭제된다.") - @Test - void delete_Success_ValidGroupMemberId() { - //given - Long groupMemberId = 1L; - GroupMember expectedMember = GroupMember.builder() - .name("김반숙") - .group(mockGroup) - .role(ExpenseRole.PARTICIPANT) - .isPaid(false) - .build(); - - when(groupMemberReader.findByGroupMemberId(eq(groupMemberId))).thenReturn(expectedMember); - doNothing().when(groupMemberRepository).delete(any(GroupMember.class)); - - //when - groupMemberDeleter.delete(groupMemberId); - - //then - verify(groupMemberRepository, times(1)).delete(any(GroupMember.class)); - } - - @DisplayName("유효하지 않은 참여자 id로 삭제를 요청하면 예외가 발생한다.") - @Test - void delete_ThrowException_WithInvalidExpenseId() { - //given - Long groupMemberId = 1L; - - doThrow(new GroupMemberNotFoundException(groupMemberId)).when(groupMemberReader) - .findByGroupMemberId(eq(groupMemberId)); - - //when & then - assertThatThrownBy(() -> { - groupMemberDeleter.delete(groupMemberId); - }).hasMessage("해당 참여자를 찾을 수 없습니다. (GroupMember ID: " + groupMemberId + ")"); - } - - @DisplayName("유효한 참여자 id로 삭제를 요청하면 성공적으로 삭제된다.") - @Test - void delete_ThrowException_WhenRoleIsManager() { - //given - Long groupMemberId = 1L; - GroupMember expectedMember = GroupMember.builder() - .name("김모또") - .group(mockGroup) - .role(ExpenseRole.MANAGER) - .isPaid(false) - .build(); - - when(groupMemberReader.findByGroupMemberId(eq(groupMemberId))).thenReturn(expectedMember); - - //when & then - assertThatThrownBy(() -> { - groupMemberDeleter.delete(groupMemberId); - }).hasMessage("총무(MANAGER)는 삭제할 수 없습니다. (Member ID: " + groupMemberId + ")"); - } -} diff --git a/src/test/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberReaderTest.java b/src/test/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberReaderTest.java deleted file mode 100644 index b0dade2..0000000 --- a/src/test/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberReaderTest.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.dnd.moddo.domain.groupMember.service.implementation; - -import static org.assertj.core.api.AssertionsForClassTypes.*; -import static org.mockito.Mockito.*; - -import java.util.List; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; -import com.dnd.moddo.domain.groupMember.exception.GroupMemberNotFoundException; -import com.dnd.moddo.domain.groupMember.repository.GroupMemberRepository; -import com.dnd.moddo.global.support.GroupTestFactory; - -@ExtendWith(MockitoExtension.class) -public class GroupMemberReaderTest { - @Mock - private GroupMemberRepository groupMemberRepository; - @InjectMocks - private GroupMemberReader groupMemberReader; - - private Group mockGroup; - - @BeforeEach - void setUp() { - mockGroup = GroupTestFactory.createDefault(); - } - - @DisplayName("모임이 존재할때 모임의 모든 참여자를 조회에 성공한다.") - @Test - void findAllByGroupIdSuccess() { - //given - Long groupId = mockGroup.getId(); - List expectedMembers = List.of( - GroupMember.builder() - .name("김모또") - .group(mockGroup) - .role(ExpenseRole.MANAGER) - .isPaid(false) - .build(), - GroupMember.builder() - .name("김반숙") - .group(mockGroup) - .role(ExpenseRole.PARTICIPANT) - .isPaid(false) - .build() - ); - - when(groupMemberRepository.findByGroupId(eq(groupId))).thenReturn(expectedMembers); - - //when - List result = groupMemberReader.findAllByGroupId(groupId); - - //then - assertThat(result).isNotNull(); - assertThat(result.size()).isEqualTo(2); - assertThat(result.get(0).getName()).isEqualTo("김모또"); - assertThat(result.get(0).getRole()).isEqualTo(ExpenseRole.MANAGER); - verify(groupMemberRepository, times(1)).findByGroupId(groupId); - } - - @DisplayName("참여자가 존재할때 참여자 id를 사용해 참여자 정보 조회에 성공한다.") - @Test - void findByGroupMemberIdSuccess() { - //given - Long groupMemberId = 1L; - GroupMember expectedMember = GroupMember.builder() - .name("김반숙") - .group(mockGroup) - .role(ExpenseRole.PARTICIPANT) - .isPaid(false) - .build(); - - when(groupMemberRepository.getById(eq(groupMemberId))).thenReturn(expectedMember); - - //when - GroupMember result = groupMemberReader.findByGroupMemberId(groupMemberId); - - //then - assertThat(result).isNotNull(); - assertThat(result.getGroup()).isEqualTo(mockGroup); - assertThat(result.getName()).isEqualTo("김반숙"); - verify(groupMemberRepository, times(1)).getById(eq(groupMemberId)); - - } - - @DisplayName("참여자가 존재하지 않을때 참여자 id를 사용해 조회하려고 하면 예외가 발생한다.") - @Test - void findByGroupMemberIdFail() { - //given - Long groupMemberId = 1L; - doThrow(new GroupMemberNotFoundException(groupMemberId)).when(groupMemberRepository).getById(eq(groupMemberId)); - - //when & then - assertThatThrownBy(() -> { - groupMemberReader.findByGroupMemberId(groupMemberId); - }).hasMessage("해당 참여자를 찾을 수 없습니다. (GroupMember ID: " + groupMemberId + ")"); - } - -} diff --git a/src/test/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberUpdaterTest.java b/src/test/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberUpdaterTest.java deleted file mode 100644 index 89da3eb..0000000 --- a/src/test/java/com/dnd/moddo/domain/groupMember/service/implementation/GroupMemberUpdaterTest.java +++ /dev/null @@ -1,177 +0,0 @@ -package com.dnd.moddo.domain.groupMember.service.implementation; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.ArrayList; -import java.util.List; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.service.implementation.GroupReader; -import com.dnd.moddo.domain.groupMember.dto.request.GroupMemberSaveRequest; -import com.dnd.moddo.domain.groupMember.dto.request.PaymentStatusUpdateRequest; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; -import com.dnd.moddo.domain.groupMember.exception.GroupMemberDuplicateNameException; -import com.dnd.moddo.domain.groupMember.repository.GroupMemberRepository; -import com.dnd.moddo.global.config.S3Bucket; - -@ExtendWith(MockitoExtension.class) -class GroupMemberUpdaterTest { - @Mock - private GroupMemberRepository groupMemberRepository; - @Mock - private GroupMemberReader groupMemberReader; - @Mock - private GroupMemberValidator groupMemberValidator; - @Mock - private GroupReader groupReader; - @Mock - private S3Bucket s3Bucket; - @InjectMocks - private GroupMemberUpdater groupMemberUpdater; - - private Group mockGroup; - - @BeforeEach - void setup() { - mockGroup = mock(Group.class); - } - - @DisplayName("추가하려는 참여자의 이름이 기존 참여자의 이름과 중복되지 않을 경우 참여자 추가에 성공한다.") - @Test - void addToGroupSuccess() { - // given - Long groupId = 1L; - GroupMemberSaveRequest request = mock(GroupMemberSaveRequest.class); - String newMemberName = "김반숙"; - - when(request.name()).thenReturn(newMemberName); - when(groupReader.read(eq(groupId))).thenReturn(mockGroup); - - List mockGroupMembers = new ArrayList<>(); - when(groupMemberReader.findAllByGroupId(eq(groupId))).thenReturn(mockGroupMembers); - - doNothing().when(groupMemberValidator).validateMemberNamesNotDuplicate(any()); - - GroupMember expectedGroupMember = GroupMember.builder() - .name(newMemberName) - .group(mockGroup) - .role(ExpenseRole.PARTICIPANT) - .profileId(1) - .build(); - when(groupMemberRepository.save(any())).thenReturn(expectedGroupMember); - - // when - GroupMember result = groupMemberUpdater.addToGroup(groupId, request); - - // then - assertThat(result).isNotNull(); - assertThat(result.getGroup()).isEqualTo(mockGroup); - assertThat(result.getName()).isEqualTo(newMemberName); - assertThat(result.getProfileId()).isEqualTo(1); - - verify(groupMemberRepository, times(1)).save(any()); - } - - @DisplayName("추가하려는 참여자의 이름이 기존 참여자의 이름과 중복되는 경우 예외가 발생한다.") - @Test - void addToGroupDuplicatedName() { - // given - Long groupId = 1L; - GroupMemberSaveRequest request = mock(GroupMemberSaveRequest.class); - String duplicatedName = "김반숙"; - - when(request.name()).thenReturn(duplicatedName); - when(groupReader.read(eq(groupId))).thenReturn(mockGroup); - - List mockGroupMembers = new ArrayList<>(); - GroupMember existingMember = GroupMember.builder().name(duplicatedName).build(); - mockGroupMembers.add(existingMember); - when(groupMemberReader.findAllByGroupId(eq(groupId))).thenReturn(mockGroupMembers); - - doThrow(new GroupMemberDuplicateNameException()).when(groupMemberValidator) - .validateMemberNamesNotDuplicate(any()); - - // when & then - assertThatThrownBy(() -> { - groupMemberUpdater.addToGroup(groupId, request); - }).hasMessage("중복된 참여자의 이름은 저장할 수 없습니다."); - } - - @DisplayName("참여자가 유효할 때 참여자의 입금 상태를 변경할 수 있다.") - @Test - void updatePaymentStatus_Success() { - // given - GroupMember groupMember = GroupMember.builder() - .name("김반숙") - .group(mockGroup) - .role(ExpenseRole.PARTICIPANT) - .build(); - PaymentStatusUpdateRequest request = new PaymentStatusUpdateRequest(true); - - when(groupMemberRepository.getById(any())).thenReturn(groupMember); - - // when - GroupMember result = groupMemberUpdater.updatePaymentStatus(1L, request); - - // then - assertThat(result).isNotNull(); - assertThat(result.isPaid()).isTrue(); - } - - @DisplayName("9번째 이상의 참여자가 추가될 때 프로필 ID가 올바르게 순환된다.") - @Test - void addToGroupProfileRotationSuccess() { - // given - Long groupId = 1L; - GroupMemberSaveRequest request = mock(GroupMemberSaveRequest.class); - String newMemberName = "김철수"; - - when(request.name()).thenReturn(newMemberName); - when(groupReader.read(eq(groupId))).thenReturn(mockGroup); - - // 기존 멤버 8명 설정 - List mockGroupMembers = new ArrayList<>(); - for (int i = 1; i <= 8; i++) { - mockGroupMembers.add( - GroupMember.builder() - .name("멤버" + i) - .group(mockGroup) - .profileId(i) - .role(ExpenseRole.PARTICIPANT) - .build() - ); - } - when(groupMemberReader.findAllByGroupId(eq(groupId))).thenReturn(mockGroupMembers); - - doNothing().when(groupMemberValidator).validateMemberNamesNotDuplicate(any()); - - GroupMember expectedGroupMember = GroupMember.builder() - .name(newMemberName) - .group(mockGroup) - .role(ExpenseRole.PARTICIPANT) - .profileId(1) - .build(); - when(groupMemberRepository.save(any())).thenReturn(expectedGroupMember); - - // when - GroupMember result = groupMemberUpdater.addToGroup(groupId, request); - - // then - assertThat(result).isNotNull(); - assertThat(result.getGroup()).isEqualTo(mockGroup); - assertThat(result.getName()).isEqualTo(newMemberName); - assertThat(result.getProfileId()).isEqualTo(1); - - verify(groupMemberRepository, times(1)).save(any()); - } -} diff --git a/src/test/java/com/dnd/moddo/domain/memberExpense/controller/MemberExpenseControllerTest.java b/src/test/java/com/dnd/moddo/domain/memberExpense/controller/MemberExpenseControllerTest.java index ea9f378..f100bd1 100644 --- a/src/test/java/com/dnd/moddo/domain/memberExpense/controller/MemberExpenseControllerTest.java +++ b/src/test/java/com/dnd/moddo/domain/memberExpense/controller/MemberExpenseControllerTest.java @@ -1,6 +1,6 @@ package com.dnd.moddo.domain.memberExpense.controller; -import static com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole.*; +import static com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole.*; import static org.mockito.Mockito.*; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @@ -12,8 +12,8 @@ import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; -import com.dnd.moddo.domain.groupMember.dto.response.GroupMemberExpenseResponse; -import com.dnd.moddo.domain.groupMember.dto.response.GroupMembersExpenseResponse; +import com.dnd.moddo.domain.appointmentMember.dto.response.AppointmentMemberExpenseResponse; +import com.dnd.moddo.domain.appointmentMember.dto.response.AppointmentMembersExpenseResponse; import com.dnd.moddo.domain.memberExpense.dto.response.MemberExpenseDetailResponse; import com.dnd.moddo.global.util.RestDocsTestSupport; @@ -26,22 +26,22 @@ void getMemberExpensesDetailsSuccess() throws Exception { String groupToken = "mockedGroupToken"; Long groupId = 1L; - GroupMembersExpenseResponse groupMembersExpenseResponse = new GroupMembersExpenseResponse( + AppointmentMembersExpenseResponse appointmentMembersExpenseResponse = new AppointmentMembersExpenseResponse( List.of( - new GroupMemberExpenseResponse(1L, MANAGER, "김모또", 10000L, + new AppointmentMemberExpenseResponse(1L, MANAGER, "김모또", 10000L, "https://moddo-s3.s3.amazonaws.com/profile/MODDO.png", true, LocalDateTime.now(), List.of(new MemberExpenseDetailResponse("카페", 10000L)) ), - new GroupMemberExpenseResponse(2L, PARTICIPANT, "군계란", 10000L, + new AppointmentMemberExpenseResponse(2L, PARTICIPANT, "군계란", 10000L, "https://moddo-s3.s3.amazonaws.com/profile/1.png", false, null, List.of(new MemberExpenseDetailResponse("카페", 10000L)) ) ) ); - when(queryGroupService.findIdByCode(groupToken)).thenReturn(groupId); - when(queryMemberExpenseService.findMemberExpenseDetailsByGroupId(groupId)).thenReturn( - groupMembersExpenseResponse); + when(querySettlementService.findIdByCode(groupToken)).thenReturn(groupId); + when(queryMemberExpenseService.findMemberExpenseDetailsBySettlementId(groupId)).thenReturn( + appointmentMembersExpenseResponse); // when & then mockMvc.perform(get("/api/v1/member-expenses") @@ -50,7 +50,7 @@ void getMemberExpensesDetailsSuccess() throws Exception { .andExpect(status().isOk()) .andExpect(jsonPath("$.memberExpenses").isArray()); - verify(queryGroupService, times(1)).findIdByCode(groupToken); - verify(queryMemberExpenseService, times(1)).findMemberExpenseDetailsByGroupId(groupId); + verify(querySettlementService, times(1)).findIdByCode(groupToken); + verify(queryMemberExpenseService, times(1)).findMemberExpenseDetailsBySettlementId(groupId); } } diff --git a/src/test/java/com/dnd/moddo/domain/memberExpense/service/CommandMemberExpenseServiceTest.java b/src/test/java/com/dnd/moddo/domain/memberExpense/service/CommandMemberExpenseServiceTest.java index f398adb..cfa816c 100644 --- a/src/test/java/com/dnd/moddo/domain/memberExpense/service/CommandMemberExpenseServiceTest.java +++ b/src/test/java/com/dnd/moddo/domain/memberExpense/service/CommandMemberExpenseServiceTest.java @@ -12,9 +12,8 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.service.implementation.GroupMemberReader; +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.service.implementation.AppointmentMemberReader; import com.dnd.moddo.domain.memberExpense.dto.request.MemberExpenseRequest; import com.dnd.moddo.domain.memberExpense.dto.response.MemberExpenseResponse; import com.dnd.moddo.domain.memberExpense.entity.MemberExpense; @@ -22,11 +21,12 @@ import com.dnd.moddo.domain.memberExpense.service.implementation.MemberExpenseDeleter; import com.dnd.moddo.domain.memberExpense.service.implementation.MemberExpenseReader; import com.dnd.moddo.domain.memberExpense.service.implementation.MemberExpenseUpdater; +import com.dnd.moddo.domain.settlement.entity.Settlement; @ExtendWith(MockitoExtension.class) class CommandMemberExpenseServiceTest { @Mock - private GroupMemberReader groupMemberReader; + private AppointmentMemberReader appointmentMemberReader; @Mock private MemberExpenseCreator memberExpenseCreator; @Mock @@ -38,7 +38,7 @@ class CommandMemberExpenseServiceTest { @InjectMocks private CommandMemberExpenseService commandMemberExpenseService; - private Group mockGroup = mock(Group.class); + private Settlement mockSettlement = mock(Settlement.class); @DisplayName("참여자별 지출내역으르 생성할 때 모든 정보가 유효할 때 참여자별 지출내역 생성에 성공한다.") @Test @@ -49,25 +49,25 @@ void create_Success_MemberExpenses() { MemberExpenseRequest request2 = new MemberExpenseRequest(2L, 10000L); List requests = List.of(request1, request2); - GroupMember groupMember1 = mock(GroupMember.class); - GroupMember groupMember2 = mock(GroupMember.class); + AppointmentMember appointmentMember1 = mock(AppointmentMember.class); + AppointmentMember appointmentMember2 = mock(AppointmentMember.class); - when(groupMember1.getId()).thenReturn(1L); - when(groupMember2.getId()).thenReturn(2L); + when(appointmentMember1.getId()).thenReturn(1L); + when(appointmentMember2.getId()).thenReturn(2L); - when(groupMemberReader.findByGroupMemberId(any())) - .thenReturn(groupMember1) - .thenReturn(groupMember2); + when(appointmentMemberReader.findByAppointmentMemberId(any())) + .thenReturn(appointmentMember1) + .thenReturn(appointmentMember2); MemberExpense memberExpense1 = mock(MemberExpense.class); MemberExpense memberExpense2 = mock(MemberExpense.class); - when(memberExpense1.getGroupMember()).thenReturn(groupMember1); - when(memberExpense2.getGroupMember()).thenReturn(groupMember2); + when(memberExpense1.getAppointmentMember()).thenReturn(appointmentMember1); + when(memberExpense2.getAppointmentMember()).thenReturn(appointmentMember2); - when(memberExpenseCreator.create(eq(expenseId), eq(groupMember1), eq(request1))) + when(memberExpenseCreator.create(eq(expenseId), eq(appointmentMember1), eq(request1))) .thenReturn(memberExpense1); - when(memberExpenseCreator.create(eq(expenseId), eq(groupMember2), eq(request2))) + when(memberExpenseCreator.create(eq(expenseId), eq(appointmentMember2), eq(request2))) .thenReturn(memberExpense2); //when @@ -77,7 +77,7 @@ void create_Success_MemberExpenses() { assertThat(responses).isNotEmpty(); assertThat(responses).hasSize(2); - verify(memberExpenseCreator, times(2)).create(eq(expenseId), any(GroupMember.class), + verify(memberExpenseCreator, times(2)).create(eq(expenseId), any(AppointmentMember.class), any(MemberExpenseRequest.class)); } @@ -90,17 +90,17 @@ void update_Success_MemberExpenses() { MemberExpenseRequest request2 = new MemberExpenseRequest(2L, 30000L); List requests = List.of(request1, request2); - GroupMember groupMember1 = mock(GroupMember.class); - GroupMember groupMember2 = mock(GroupMember.class); + AppointmentMember appointmentMember1 = mock(AppointmentMember.class); + AppointmentMember appointmentMember2 = mock(AppointmentMember.class); - when(groupMember1.getId()).thenReturn(1L); - when(groupMember2.getId()).thenReturn(2L); + when(appointmentMember1.getId()).thenReturn(1L); + when(appointmentMember2.getId()).thenReturn(2L); MemberExpense existingMemberExpense1 = mock(MemberExpense.class); MemberExpense existingMemberExpense2 = mock(MemberExpense.class); - when(existingMemberExpense1.getGroupMember()).thenReturn(groupMember1); - when(existingMemberExpense2.getGroupMember()).thenReturn(groupMember2); + when(existingMemberExpense1.getAppointmentMember()).thenReturn(appointmentMember1); + when(existingMemberExpense2.getAppointmentMember()).thenReturn(appointmentMember2); List exisitingMemberExpenses = List.of(existingMemberExpense1, existingMemberExpense2); @@ -130,29 +130,29 @@ void addAndUpdate_Success_eMemberExpenses() { MemberExpenseRequest request3 = new MemberExpenseRequest(3L, 30000L); List requests = List.of(request1, request2, request3); - GroupMember groupMember1 = mock(GroupMember.class); - GroupMember groupMember2 = mock(GroupMember.class); - GroupMember expectedGroupMember = mock(GroupMember.class); + AppointmentMember appointmentMember1 = mock(AppointmentMember.class); + AppointmentMember appointmentMember2 = mock(AppointmentMember.class); + AppointmentMember expectedAppointmentMember = mock(AppointmentMember.class); - when(groupMember1.getId()).thenReturn(1L); - when(groupMember2.getId()).thenReturn(2L); - when(expectedGroupMember.getId()).thenReturn(3L); + when(appointmentMember1.getId()).thenReturn(1L); + when(appointmentMember2.getId()).thenReturn(2L); + when(expectedAppointmentMember.getId()).thenReturn(3L); MemberExpense existingMemberExpense1 = mock(MemberExpense.class); MemberExpense existingMemberExpense2 = mock(MemberExpense.class); - when(existingMemberExpense1.getGroupMember()).thenReturn(groupMember1); - when(existingMemberExpense2.getGroupMember()).thenReturn(groupMember2); + when(existingMemberExpense1.getAppointmentMember()).thenReturn(appointmentMember1); + when(existingMemberExpense2.getAppointmentMember()).thenReturn(appointmentMember2); - MemberExpense expectedMemberExpense = new MemberExpense(expenseId, expectedGroupMember, 30000L); + MemberExpense expectedMemberExpense = new MemberExpense(expenseId, expectedAppointmentMember, 30000L); when(memberExpenseReader.findAllByExpenseId(eq(expenseId))).thenReturn( List.of(existingMemberExpense1, existingMemberExpense2)); - when(groupMemberReader.findByGroupMemberId(3L)).thenReturn(expectedGroupMember); + when(appointmentMemberReader.findByAppointmentMemberId(3L)).thenReturn(expectedAppointmentMember); doNothing().when(memberExpenseUpdater).update(existingMemberExpense1, request1); doNothing().when(memberExpenseUpdater).update(existingMemberExpense2, request2); - when(memberExpenseCreator.create(eq(expenseId), any(GroupMember.class), eq(request3))).thenReturn( + when(memberExpenseCreator.create(eq(expenseId), any(AppointmentMember.class), eq(request3))).thenReturn( expectedMemberExpense); // when @@ -163,7 +163,7 @@ void addAndUpdate_Success_eMemberExpenses() { assertThat(responses).hasSize(3); verify(memberExpenseUpdater, times(2)).update(any(MemberExpense.class), any(MemberExpenseRequest.class)); - verify(memberExpenseCreator, times(1)).create(eq(expenseId), any(GroupMember.class), + verify(memberExpenseCreator, times(1)).create(eq(expenseId), any(AppointmentMember.class), any(MemberExpenseRequest.class)); } @@ -175,17 +175,17 @@ void deleteAndUpdate_Success_MemberExpenses() { MemberExpenseRequest request1 = new MemberExpenseRequest(1L, 20000L); List requests = List.of(request1); - GroupMember groupMember1 = mock(GroupMember.class); - GroupMember groupMember2 = mock(GroupMember.class); + AppointmentMember appointmentMember1 = mock(AppointmentMember.class); + AppointmentMember appointmentMember2 = mock(AppointmentMember.class); - when(groupMember1.getId()).thenReturn(1L); - when(groupMember2.getId()).thenReturn(2L); + when(appointmentMember1.getId()).thenReturn(1L); + when(appointmentMember2.getId()).thenReturn(2L); MemberExpense existingMemberExpense1 = mock(MemberExpense.class); MemberExpense existingMemberExpense2 = mock(MemberExpense.class); - when(existingMemberExpense1.getGroupMember()).thenReturn(groupMember1); - when(existingMemberExpense2.getGroupMember()).thenReturn(groupMember2); + when(existingMemberExpense1.getAppointmentMember()).thenReturn(appointmentMember1); + when(existingMemberExpense2.getAppointmentMember()).thenReturn(appointmentMember2); when(existingMemberExpense1.getAmount()).thenReturn(5000L); when(memberExpenseReader.findAllByExpenseId(eq(expenseId))).thenReturn( diff --git a/src/test/java/com/dnd/moddo/domain/memberExpense/service/QueryMemberExpenseServiceTest.java b/src/test/java/com/dnd/moddo/domain/memberExpense/service/QueryMemberExpenseServiceTest.java index 0ee65cf..f03e953 100644 --- a/src/test/java/com/dnd/moddo/domain/memberExpense/service/QueryMemberExpenseServiceTest.java +++ b/src/test/java/com/dnd/moddo/domain/memberExpense/service/QueryMemberExpenseServiceTest.java @@ -14,16 +14,16 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import com.dnd.moddo.domain.appointmentMember.dto.response.AppointmentMembersExpenseResponse; +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.appointmentMember.service.implementation.AppointmentMemberReader; import com.dnd.moddo.domain.expense.entity.Expense; import com.dnd.moddo.domain.expense.service.implementation.ExpenseReader; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.groupMember.dto.response.GroupMembersExpenseResponse; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; -import com.dnd.moddo.domain.groupMember.service.implementation.GroupMemberReader; import com.dnd.moddo.domain.memberExpense.dto.response.MemberExpenseResponse; import com.dnd.moddo.domain.memberExpense.entity.MemberExpense; import com.dnd.moddo.domain.memberExpense.service.implementation.MemberExpenseReader; +import com.dnd.moddo.domain.settlement.entity.Settlement; import com.dnd.moddo.global.support.GroupTestFactory; @ExtendWith(MockitoExtension.class) @@ -33,29 +33,29 @@ class QueryMemberExpenseServiceTest { @Mock private ExpenseReader expenseReader; @Mock - private GroupMemberReader groupMemberReader; + private AppointmentMemberReader appointmentMemberReader; @InjectMocks private QueryMemberExpenseService queryMemberExpenseService; - private Group mockGroup; - private GroupMember mockGroupMember1; - private GroupMember mockGroupMember2; + private Settlement mockSettlement; + private AppointmentMember mockAppointmentMember1; + private AppointmentMember mockAppointmentMember2; @BeforeEach void setUp() { - mockGroup = GroupTestFactory.createDefault(); + mockSettlement = GroupTestFactory.createDefault(); - mockGroupMember1 = GroupMember.builder() + mockAppointmentMember1 = AppointmentMember.builder() .name("김모또") - .group(mockGroup) + .settlement(mockSettlement) .isPaid(true) .profileId(0) .role(ExpenseRole.MANAGER) .build(); - mockGroupMember2 = GroupMember.builder() + mockAppointmentMember2 = AppointmentMember.builder() .name("박완숙") - .group(mockGroup) + .settlement(mockSettlement) .isPaid(false) .profileId(1) .role(ExpenseRole.PARTICIPANT) @@ -69,8 +69,8 @@ void findAllByExpenseId() { Long expenseId = 1L; List expectedMemberExpense = List.of( - new MemberExpense(expenseId, mockGroupMember1, 15000L), - new MemberExpense(expenseId, mockGroupMember2, 5000L) + new MemberExpense(expenseId, mockAppointmentMember1, 15000L), + new MemberExpense(expenseId, mockAppointmentMember2, 5000L) ); when(memberExpenseReader.findAllByExpenseId(eq(expenseId))).thenReturn(expectedMemberExpense); @@ -87,68 +87,69 @@ void findAllByExpenseId() { @DisplayName("모임이 유효할 때 참여자별 정산내역 조회에 성공한다.") @Test - void findMemberExpenseDetailsByGroupId_Success() { + void findMemberExpenseDetailsBySettlementId_Success() { //given Long groupId = 1L; - GroupMember groupMember1 = mock(GroupMember.class); - GroupMember groupMember2 = mock(GroupMember.class); + AppointmentMember appointmentMember1 = mock(AppointmentMember.class); + AppointmentMember appointmentMember2 = mock(AppointmentMember.class); - when(groupMember1.getId()).thenReturn(1L); - when(groupMember2.getId()).thenReturn(2L); + when(appointmentMember1.getId()).thenReturn(1L); + when(appointmentMember2.getId()).thenReturn(2L); - List groupMembers = List.of(groupMember1, groupMember2); + List appointmentMembers = List.of(appointmentMember1, appointmentMember2); MemberExpense memberExpense1 = mock(MemberExpense.class); MemberExpense memberExpense2 = mock(MemberExpense.class); when(memberExpense1.getExpenseId()).thenReturn(1L); when(memberExpense1.getAmount()).thenReturn(10000L); - when(memberExpense1.getGroupMember()).thenReturn(groupMember1); + when(memberExpense1.getAppointmentMember()).thenReturn(appointmentMember1); when(memberExpense2.getExpenseId()).thenReturn(2L); when(memberExpense2.getAmount()).thenReturn(15000L); - when(memberExpense2.getGroupMember()).thenReturn(groupMember2); + when(memberExpense2.getAppointmentMember()).thenReturn(appointmentMember2); Expense expense1 = mock(Expense.class); Expense expense2 = mock(Expense.class); when(expense1.getId()).thenReturn(1L); when(expense2.getId()).thenReturn(2L); - when(groupMemberReader.findAllByGroupId(eq(groupId))).thenReturn(groupMembers); - when(memberExpenseReader.findAllByGroupMemberIds(List.of(1L, 2L))) + when(appointmentMemberReader.findAllBySettlementId(eq(groupId))).thenReturn(appointmentMembers); + when(memberExpenseReader.findAllByAppointMemberIds(List.of(1L, 2L))) .thenReturn(List.of(memberExpense1, memberExpense2)); - when(expenseReader.findAllByGroupId(any())).thenReturn(List.of(expense1, expense2)); + when(expenseReader.findAllBySettlementId(any())).thenReturn(List.of(expense1, expense2)); // when - GroupMembersExpenseResponse response = queryMemberExpenseService.findMemberExpenseDetailsByGroupId(groupId); + AppointmentMembersExpenseResponse response = queryMemberExpenseService.findMemberExpenseDetailsBySettlementId( + groupId); // then assertThat(response).isNotNull(); assertThat(response.memberExpenses()).hasSize(2); - verify(groupMemberReader, times(1)).findAllByGroupId(groupId); - verify(memberExpenseReader, times(1)).findAllByGroupMemberIds(anyList()); - verify(expenseReader, times(1)).findAllByGroupId(groupId); + verify(appointmentMemberReader, times(1)).findAllBySettlementId(groupId); + verify(memberExpenseReader, times(1)).findAllByAppointMemberIds(anyList()); + verify(expenseReader, times(1)).findAllBySettlementId(groupId); } @DisplayName("지출내역 id를 통해 참여자 지출내역을 찾아 지출내역 id에 해당하는 참여자 이름들을 map으로 조회할 수 있다.") @Test void getMemberNamesByExpenseIds_Success() { //given - GroupMember groupMember1 = mock(GroupMember.class); - GroupMember groupMember2 = mock(GroupMember.class); + AppointmentMember appointmentMember1 = mock(AppointmentMember.class); + AppointmentMember appointmentMember2 = mock(AppointmentMember.class); - when(groupMember1.getName()).thenReturn("김모또"); - when(groupMember2.getName()).thenReturn("김반숙"); + when(appointmentMember1.getName()).thenReturn("김모또"); + when(appointmentMember2.getName()).thenReturn("김반숙"); - when(groupMember1.isManager()).thenReturn(true); - when(groupMember2.isManager()).thenReturn(false); + when(appointmentMember1.isManager()).thenReturn(true); + when(appointmentMember2.isManager()).thenReturn(false); List expenseIds = List.of(1L, 2L); List mockExpenses = List.of( - new MemberExpense(1L, groupMember1, 1000L), - new MemberExpense(2L, groupMember1, 2000L), - new MemberExpense(1L, groupMember2, 3000L) + new MemberExpense(1L, appointmentMember1, 1000L), + new MemberExpense(2L, appointmentMember1, 2000L), + new MemberExpense(1L, appointmentMember2, 3000L) ); when(memberExpenseReader.findAllByExpenseIds(eq(expenseIds))).thenReturn(mockExpenses); diff --git a/src/test/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseCreatorTest.java b/src/test/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseCreatorTest.java index 49f20e4..1b312a2 100644 --- a/src/test/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseCreatorTest.java +++ b/src/test/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseCreatorTest.java @@ -11,12 +11,12 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; import com.dnd.moddo.domain.memberExpense.dto.request.MemberExpenseRequest; import com.dnd.moddo.domain.memberExpense.entity.MemberExpense; import com.dnd.moddo.domain.memberExpense.repotiroy.MemberExpenseRepository; +import com.dnd.moddo.domain.settlement.entity.Settlement; import com.dnd.moddo.global.support.GroupTestFactory; @ExtendWith(MockitoExtension.class) @@ -26,17 +26,17 @@ class MemberExpenseCreatorTest { @InjectMocks private MemberExpenseCreator memberExpenseCreator; - private Group mockGroup; - private GroupMember mockGroupMember; + private Settlement mockSettlement; + private AppointmentMember mockAppointmentMember; private MemberExpenseRequest mockMemberExpenseRequest; @BeforeEach void setUp() { - mockGroup = GroupTestFactory.createDefault(); + mockSettlement = GroupTestFactory.createDefault(); - mockGroupMember = GroupMember.builder() + mockAppointmentMember = AppointmentMember.builder() .name("박완수") - .group(mockGroup) + .settlement(mockSettlement) .role(ExpenseRole.MANAGER) .isPaid(true) .build(); @@ -49,19 +49,19 @@ void setUp() { void createMemberExpenseSuccess() { //given Long expenseId = 1L; - MemberExpense mockMemberExpense = new MemberExpense(expenseId, mockGroupMember, 10000L); + MemberExpense mockMemberExpense = new MemberExpense(expenseId, mockAppointmentMember, 10000L); - when(mockMemberExpenseRequest.toEntity(expenseId, mockGroupMember)).thenReturn(mockMemberExpense); + when(mockMemberExpenseRequest.toEntity(expenseId, mockAppointmentMember)).thenReturn(mockMemberExpense); when(memberExpenseRepository.save(any(MemberExpense.class))).thenReturn(mockMemberExpense); //when - MemberExpense result = memberExpenseCreator.create(expenseId, mockGroupMember, mockMemberExpenseRequest); + MemberExpense result = memberExpenseCreator.create(expenseId, mockAppointmentMember, mockMemberExpenseRequest); //then assertThat(result).isNotNull(); assertThat(result).isEqualTo(mockMemberExpense); assertThat(result.getAmount()).isEqualTo(10000L); - assertThat(result.getGroupMember()).isEqualTo(mockGroupMember); + assertThat(result.getAppointmentMember()).isEqualTo(mockAppointmentMember); verify(memberExpenseRepository, times(1)).save(any(MemberExpense.class)); } diff --git a/src/test/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseReaderTest.java b/src/test/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseReaderTest.java index d40c30d..278b40d 100644 --- a/src/test/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseReaderTest.java +++ b/src/test/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseReaderTest.java @@ -13,11 +13,11 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; -import com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; import com.dnd.moddo.domain.memberExpense.entity.MemberExpense; import com.dnd.moddo.domain.memberExpense.repotiroy.MemberExpenseRepository; +import com.dnd.moddo.domain.settlement.entity.Settlement; import com.dnd.moddo.global.support.GroupTestFactory; @ExtendWith(MockitoExtension.class) @@ -27,16 +27,16 @@ class MemberExpenseReaderTest { @InjectMocks private MemberExpenseReader memberExpenseReader; - private Group mockGroup; - private GroupMember mockGroupMember; + private Settlement mockSettlement; + private AppointmentMember mockAppointmentMember; @BeforeEach void setUp() { - mockGroup = GroupTestFactory.createDefault(); + mockSettlement = GroupTestFactory.createDefault(); - mockGroupMember = GroupMember.builder() + mockAppointmentMember = AppointmentMember.builder() .name("박완숙") - .group(mockGroup) + .settlement(mockSettlement) .role(ExpenseRole.MANAGER) .isPaid(true) .build(); @@ -49,7 +49,7 @@ void findAllByExpenseId_Success() { Long expenseId = 1L; // Mock 데이터 준비 List expectedMemberExpense = List.of( - new MemberExpense(expenseId, mockGroupMember, 15000L) + new MemberExpense(expenseId, mockAppointmentMember, 15000L) ); when(memberExpenseRepository.findByExpenseId(eq(expenseId))).thenReturn(expectedMemberExpense); @@ -60,57 +60,65 @@ void findAllByExpenseId_Success() { // then assertThat(result).isNotEmpty(); assertThat(result.get(0).getAmount()).isEqualTo(15000L); - assertThat(result.get(0).getGroupMember()).isEqualTo(mockGroupMember); + assertThat(result.get(0).getAppointmentMember()).isEqualTo(mockAppointmentMember); verify(memberExpenseRepository, times(1)).findByExpenseId(eq(expenseId)); } @DisplayName("참여자별 지출내역을 참여자 id, 지출내역 map으로 변환하여 조회할 수 있다.") @Test - void findAllByGroupMemberIds_Success() { + void findAllByAppointMemberIds_Success() { // given - GroupMember groupMember1 = GroupMember.builder() + AppointmentMember appointmentMember1 = AppointmentMember.builder() .name("김모또") - .group(mockGroup) + .settlement(mockSettlement) .role(ExpenseRole.PARTICIPANT) .build(); - GroupMember groupMember2 = GroupMember.builder().name("박완숙").group(mockGroup).role(ExpenseRole.MANAGER).build(); + AppointmentMember appointmentMember2 = AppointmentMember.builder() + .name("박완숙") + .settlement(mockSettlement) + .role(ExpenseRole.MANAGER) + .build(); List mockExpenses = List.of( - new MemberExpense(1L, groupMember1, 1000L), - new MemberExpense(2L, groupMember1, 2000L), - new MemberExpense(1L, groupMember2, 3000L) + new MemberExpense(1L, appointmentMember1, 1000L), + new MemberExpense(2L, appointmentMember1, 2000L), + new MemberExpense(1L, appointmentMember2, 3000L) ); List groupMemberIds = List.of(1L, 2L); - when(memberExpenseRepository.findAllByGroupMemberIds(groupMemberIds)).thenReturn(mockExpenses); + when(memberExpenseRepository.findAllByAppointmentMemberIds(groupMemberIds)).thenReturn(mockExpenses); // when - List result = memberExpenseReader.findAllByGroupMemberIds(groupMemberIds); + List result = memberExpenseReader.findAllByAppointMemberIds(groupMemberIds); // then assertThat(result).isNotEmpty(); assertThat(result).hasSize(mockExpenses.size()); - verify(memberExpenseRepository, times(1)).findAllByGroupMemberIds(groupMemberIds); + verify(memberExpenseRepository, times(1)).findAllByAppointmentMemberIds(groupMemberIds); } @DisplayName("지출내역 id들로 모든 참여자별 지출내역을 조회할 수 있다.") @Test void findAllByExpenseIds_Success() { // given - GroupMember groupMember1 = GroupMember.builder() + AppointmentMember appointmentMember1 = AppointmentMember.builder() .name("김모또") - .group(mockGroup) + .settlement(mockSettlement) .role(ExpenseRole.PARTICIPANT) .build(); - GroupMember groupMember2 = GroupMember.builder().name("박완숙").group(mockGroup).role(ExpenseRole.MANAGER).build(); + AppointmentMember appointmentMember2 = AppointmentMember.builder() + .name("박완숙") + .settlement(mockSettlement) + .role(ExpenseRole.MANAGER) + .build(); List mockExpenses = List.of( - new MemberExpense(1L, groupMember1, 1000L), - new MemberExpense(2L, groupMember1, 2000L), - new MemberExpense(1L, groupMember2, 3000L) + new MemberExpense(1L, appointmentMember1, 1000L), + new MemberExpense(2L, appointmentMember1, 2000L), + new MemberExpense(1L, appointmentMember2, 3000L) ); List expenseIds = List.of(1L, 2L); diff --git a/src/test/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseUpdaterTest.java b/src/test/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseUpdaterTest.java index 32b6a0f..6ef6412 100644 --- a/src/test/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseUpdaterTest.java +++ b/src/test/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseUpdaterTest.java @@ -10,7 +10,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import com.dnd.moddo.domain.groupMember.entity.GroupMember; +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; import com.dnd.moddo.domain.memberExpense.dto.request.MemberExpenseRequest; import com.dnd.moddo.domain.memberExpense.entity.MemberExpense; import com.dnd.moddo.domain.memberExpense.repotiroy.MemberExpenseRepository; @@ -28,7 +28,7 @@ void update_Success() { //given Long expectedAmount = 5000L; - MemberExpense memberExpense = new MemberExpense(1L, mock(GroupMember.class), 15000L); + MemberExpense memberExpense = new MemberExpense(1L, mock(AppointmentMember.class), 15000L); MemberExpenseRequest request = new MemberExpenseRequest(1L, expectedAmount); when(memberExpenseRepository.save(memberExpense)).thenReturn(any(MemberExpense.class)); diff --git a/src/test/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseValidatorTest.java b/src/test/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseValidatorTest.java index e85baa9..e70b5c6 100644 --- a/src/test/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseValidatorTest.java +++ b/src/test/java/com/dnd/moddo/domain/memberExpense/service/implementation/MemberExpenseValidatorTest.java @@ -12,19 +12,19 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import com.dnd.moddo.domain.groupMember.service.implementation.GroupMemberReader; +import com.dnd.moddo.domain.appointmentMember.service.implementation.AppointmentMemberReader; import com.dnd.moddo.domain.memberExpense.dto.request.MemberExpenseRequest; @ExtendWith(MockitoExtension.class) class MemberExpenseValidatorTest { @Mock - private GroupMemberReader groupMemberReader; + private AppointmentMemberReader appointmentMemberReader; @InjectMocks private MemberExpenseValidator memberExpenseValidator; @DisplayName("해당 모임에 참여자 id가 존재하면 검증에 성공한다.") @Test - void validateMembersArePartOfGroupSuccess() { + void validateMembersArePartOfSettlementSuccess() { //given Long groupId = 1L; List requests = List.of(new MemberExpenseRequest(1L, 15000L), @@ -32,28 +32,28 @@ void validateMembersArePartOfGroupSuccess() { List mockGroupMemberIds = List.of(1L, 2L); - when(groupMemberReader.findIdsByGroupId(eq(groupId))).thenReturn(mockGroupMemberIds); + when(appointmentMemberReader.findIdsBySettlementId(eq(groupId))).thenReturn(mockGroupMemberIds); //when & when assertThatCode(() -> { - memberExpenseValidator.validateMembersArePartOfGroup(groupId, requests); + memberExpenseValidator.validateMembersArePartOfSettlement(groupId, requests); }).doesNotThrowAnyException(); } @DisplayName("해당 모임에 참여자 id가 존재하지 않으면 예외가 발생한다.") @Test - void validateMembersArePartOfGroupFail() { + void validateMembersArePartOfSettlementFail() { //given Long groupId = 1L, invalidMemberId = 3L; List requests = List.of(new MemberExpenseRequest(1L, 15000L), new MemberExpenseRequest(invalidMemberId, 5000L)); List mockGroupMemberIds = List.of(1L, 2L); - when(groupMemberReader.findIdsByGroupId(eq(groupId))).thenReturn(mockGroupMemberIds); + when(appointmentMemberReader.findIdsBySettlementId(eq(groupId))).thenReturn(mockGroupMemberIds); //when & then assertThatThrownBy(() -> { - memberExpenseValidator.validateMembersArePartOfGroup(groupId, requests); + memberExpenseValidator.validateMembersArePartOfSettlement(groupId, requests); }).hasMessage("해당 모임에 속하지 않은 참여자가 포함되어 있습니다 (Member ID: " + invalidMemberId + ")"); } diff --git a/src/test/java/com/dnd/moddo/domain/group/controller/GroupControllerTest.java b/src/test/java/com/dnd/moddo/domain/settlement/controller/SettlementControllerTest.java similarity index 51% rename from src/test/java/com/dnd/moddo/domain/group/controller/GroupControllerTest.java rename to src/test/java/com/dnd/moddo/domain/settlement/controller/SettlementControllerTest.java index 21c6be0..b212906 100644 --- a/src/test/java/com/dnd/moddo/domain/group/controller/GroupControllerTest.java +++ b/src/test/java/com/dnd/moddo/domain/settlement/controller/SettlementControllerTest.java @@ -1,6 +1,6 @@ -package com.dnd.moddo.domain.group.controller; +package com.dnd.moddo.domain.settlement.controller; -import static com.dnd.moddo.domain.groupMember.entity.type.ExpenseRole.*; +import static com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole.*; import static org.mockito.BDDMockito.*; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @@ -12,32 +12,32 @@ import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; -import com.dnd.moddo.domain.group.dto.request.GroupAccountRequest; -import com.dnd.moddo.domain.group.dto.request.GroupPasswordRequest; -import com.dnd.moddo.domain.group.dto.request.GroupRequest; -import com.dnd.moddo.domain.group.dto.response.GroupDetailResponse; -import com.dnd.moddo.domain.group.dto.response.GroupHeaderResponse; -import com.dnd.moddo.domain.group.dto.response.GroupPasswordResponse; -import com.dnd.moddo.domain.group.dto.response.GroupResponse; -import com.dnd.moddo.domain.group.dto.response.GroupSaveResponse; -import com.dnd.moddo.domain.groupMember.dto.response.GroupMemberResponse; +import com.dnd.moddo.domain.appointmentMember.dto.response.AppointmentMemberResponse; +import com.dnd.moddo.domain.settlement.dto.request.SettlementAccountRequest; +import com.dnd.moddo.domain.settlement.dto.request.SettlementPasswordRequest; +import com.dnd.moddo.domain.settlement.dto.request.SettlementRequest; +import com.dnd.moddo.domain.settlement.dto.response.SettlementDetailResponse; +import com.dnd.moddo.domain.settlement.dto.response.SettlementHeaderResponse; +import com.dnd.moddo.domain.settlement.dto.response.SettlementPasswordResponse; +import com.dnd.moddo.domain.settlement.dto.response.SettlementResponse; +import com.dnd.moddo.domain.settlement.dto.response.SettlementSaveResponse; import com.dnd.moddo.global.util.RestDocsTestSupport; import jakarta.servlet.http.HttpServletRequest; -public class GroupControllerTest extends RestDocsTestSupport { +public class SettlementControllerTest extends RestDocsTestSupport { @Test @DisplayName("모임을 성공적으로 생성한다.") - void saveGroup() throws Exception { + void saveSettlement() throws Exception { // given - GroupRequest request = new GroupRequest("모또 모임", "1234"); - GroupSaveResponse response = new GroupSaveResponse("groupToken", new GroupMemberResponse( + SettlementRequest request = new SettlementRequest("모또 모임", "1234"); + SettlementSaveResponse response = new SettlementSaveResponse("groupToken", new AppointmentMemberResponse( 1L, MANAGER, "김모또", "https://moddo-s3.s3.amazonaws.com/profile/MODDO.png", true, LocalDateTime.now() )); given(jwtService.getUserId(any(HttpServletRequest.class))).willReturn(1L); - given(commandGroupService.createGroup(any(), eq(1L))).willReturn(response); + given(commandSettlementService.createSettlement(any(), eq(1L))).willReturn(response); // when & then mockMvc.perform(post("/api/v1/group") @@ -51,15 +51,15 @@ void saveGroup() throws Exception { @DisplayName("계좌 정보를 성공적으로 수정한다.") void updateAccount() throws Exception { // given - GroupAccountRequest accountRequest = new GroupAccountRequest("우리은행", "1111-1111"); - GroupResponse response = new GroupResponse( + SettlementAccountRequest accountRequest = new SettlementAccountRequest("우리은행", "1111-1111"); + SettlementResponse response = new SettlementResponse( 1L, 1L, LocalDateTime.now(), LocalDateTime.now().plusMonths(1), "우리은행", "1111-1111", LocalDateTime.now().plusDays(1) ); given(jwtService.getUserId(any(HttpServletRequest.class))).willReturn(1L); - given(queryGroupService.findIdByCode(anyString())).willReturn(100L); - given(commandGroupService.updateAccount(any(), eq(1L), eq(100L))).willReturn(response); + given(querySettlementService.findIdByCode(anyString())).willReturn(100L); + given(commandSettlementService.updateAccount(any(), eq(1L), eq(100L))).willReturn(response); // when & then mockMvc.perform(put("/api/v1/group/account") @@ -71,16 +71,17 @@ void updateAccount() throws Exception { @Test @DisplayName("모임을 성공적으로 조회한다.") - void getGroup() throws Exception { + void getSettlement() throws Exception { // given - GroupDetailResponse response = new GroupDetailResponse(1L, "모또 모임", List.of( - new GroupMemberResponse(1L, MANAGER, "김모또", "https://moddo-s3.s3.amazonaws.com/profile/MODDO.png", true, + SettlementDetailResponse response = new SettlementDetailResponse(1L, "모또 모임", List.of( + new AppointmentMemberResponse(1L, MANAGER, "김모또", "https://moddo-s3.s3.amazonaws.com/profile/MODDO.png", + true, LocalDateTime.now()) )); given(jwtService.getUserId(any(HttpServletRequest.class))).willReturn(1L); - given(queryGroupService.findIdByCode(anyString())).willReturn(100L); - given(queryGroupService.findOne(100L, 1L)).willReturn(response); + given(querySettlementService.findIdByCode(anyString())).willReturn(100L); + given(querySettlementService.findOne(100L, 1L)).willReturn(response); // when & then mockMvc.perform(get("/api/v1/group") @@ -92,12 +93,12 @@ void getGroup() throws Exception { @DisplayName("비밀번호를 성공적으로 검증한다.") void isPasswordMatch() throws Exception { // given - GroupPasswordRequest request = new GroupPasswordRequest("1234"); - GroupPasswordResponse response = GroupPasswordResponse.from("확인되었습니다."); + SettlementPasswordRequest request = new SettlementPasswordRequest("1234"); + SettlementPasswordResponse response = SettlementPasswordResponse.from("확인되었습니다."); given(jwtService.getUserId(any(HttpServletRequest.class))).willReturn(1L); - given(queryGroupService.findIdByCode(anyString())).willReturn(100L); - given(commandGroupService.isPasswordMatch(100L, 1L, request)).willReturn(response); + given(querySettlementService.findIdByCode(anyString())).willReturn(100L); + given(commandSettlementService.isPasswordMatch(100L, 1L, request)).willReturn(response); // when & then mockMvc.perform(post("/api/v1/group/password") @@ -112,11 +113,12 @@ void isPasswordMatch() throws Exception { @DisplayName("모임의 헤더를 성공적으로 조회한다.") void getHeader() throws Exception { // given - GroupHeaderResponse response = GroupHeaderResponse.of("모또 모임", 10000L, LocalDateTime.now().plusDays(1), "우리은행", + SettlementHeaderResponse response = SettlementHeaderResponse.of("모또 모임", 10000L, + LocalDateTime.now().plusDays(1), "우리은행", "1111-1111"); - given(queryGroupService.findIdByCode("groupToken")).willReturn(100L); - given(queryGroupService.findByGroupHeader(100L)).willReturn(response); + given(querySettlementService.findIdByCode("groupToken")).willReturn(100L); + given(querySettlementService.findBySettlementHeader(100L)).willReturn(response); // when & then mockMvc.perform(get("/api/v1/group/header") diff --git a/src/test/java/com/dnd/moddo/domain/group/entity/GroupTest.java b/src/test/java/com/dnd/moddo/domain/settlement/entity/SettlementTest.java similarity index 58% rename from src/test/java/com/dnd/moddo/domain/group/entity/GroupTest.java rename to src/test/java/com/dnd/moddo/domain/settlement/entity/SettlementTest.java index 932824c..e81cdd2 100644 --- a/src/test/java/com/dnd/moddo/domain/group/entity/GroupTest.java +++ b/src/test/java/com/dnd/moddo/domain/settlement/entity/SettlementTest.java @@ -1,4 +1,4 @@ -package com.dnd.moddo.domain.group.entity; +package com.dnd.moddo.domain.settlement.entity; import static org.assertj.core.api.Assertions.*; @@ -8,16 +8,16 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import com.dnd.moddo.domain.group.dto.request.GroupAccountRequest; +import com.dnd.moddo.domain.settlement.dto.request.SettlementAccountRequest; import com.dnd.moddo.global.support.GroupTestFactory; -class GroupTest { +class SettlementTest { - private Group mockGroup; + private Settlement mockSettlement; @BeforeEach void setUp() { - mockGroup = GroupTestFactory.createDefault(); + mockSettlement = GroupTestFactory.createDefault(); } @DisplayName("그룹의 작성자(userId)가 해당 그룹의 작성자인지 확인한다.") @@ -27,7 +27,7 @@ void testIsWriter_whenUserIsWriter() { Long userId = 1L; // when - boolean isWriter = mockGroup.isWriter(userId); + boolean isWriter = mockSettlement.isWriter(userId); // then assertThat(isWriter).isTrue(); @@ -40,7 +40,7 @@ void testIsWriter_whenUserIsNotWriter() { Long userId = 2L; // when - boolean isWriter = mockGroup.isWriter(userId); + boolean isWriter = mockSettlement.isWriter(userId); // then assertThat(isWriter).isFalse(); @@ -50,15 +50,15 @@ void testIsWriter_whenUserIsNotWriter() { @Test void testUpdateAccount() { // given - GroupAccountRequest request = new GroupAccountRequest("새로운 은행", "새로운 계좌"); + SettlementAccountRequest request = new SettlementAccountRequest("새로운 은행", "새로운 계좌"); // when - mockGroup.updateAccount(request); + mockSettlement.updateAccount(request); // then - assertThat(mockGroup.getBank()).isEqualTo("새로운 은행"); - assertThat(mockGroup.getAccountNumber()).isEqualTo("새로운 계좌"); - assertThat(mockGroup.getDeadline()).isAfter(LocalDateTime.now()); + assertThat(mockSettlement.getBank()).isEqualTo("새로운 은행"); + assertThat(mockSettlement.getAccountNumber()).isEqualTo("새로운 계좌"); + assertThat(mockSettlement.getDeadline()).isAfter(LocalDateTime.now()); } @DisplayName("그룹의 작성자를 확인할 수 있다.") @@ -68,7 +68,7 @@ void testGroupWriter() { Long writerId = 1L; // when - Long actualWriterId = mockGroup.getWriter(); + Long actualWriterId = mockSettlement.getWriter(); // then assertThat(actualWriterId).isEqualTo(writerId); diff --git a/src/test/java/com/dnd/moddo/domain/settlement/service/CommandSettlementServiceTest.java b/src/test/java/com/dnd/moddo/domain/settlement/service/CommandSettlementServiceTest.java new file mode 100644 index 0000000..639afa2 --- /dev/null +++ b/src/test/java/com/dnd/moddo/domain/settlement/service/CommandSettlementServiceTest.java @@ -0,0 +1,162 @@ +package com.dnd.moddo.domain.settlement.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.time.LocalDateTime; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.dnd.moddo.domain.appointmentMember.dto.response.AppointmentMemberResponse; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.appointmentMember.service.CommandAppointmentMemberService; +import com.dnd.moddo.domain.settlement.dto.request.SettlementAccountRequest; +import com.dnd.moddo.domain.settlement.dto.request.SettlementPasswordRequest; +import com.dnd.moddo.domain.settlement.dto.request.SettlementRequest; +import com.dnd.moddo.domain.settlement.dto.response.SettlementPasswordResponse; +import com.dnd.moddo.domain.settlement.dto.response.SettlementResponse; +import com.dnd.moddo.domain.settlement.dto.response.SettlementSaveResponse; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementCreator; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementReader; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementUpdater; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementValidator; +import com.dnd.moddo.global.jwt.utill.JwtProvider; + +@ExtendWith(MockitoExtension.class) +class CommandSettlementServiceTest { + + @Mock + private SettlementCreator settlementCreator; + + @Mock + private SettlementUpdater settlementUpdater; // 추가 + + @Mock + private SettlementReader settlementReader; + + @Mock + private SettlementValidator settlementValidator; + @Mock + private JwtProvider jwtProvider; + @Mock + private CommandAppointmentMemberService commandAppointmentMemberService; + @InjectMocks + private CommandSettlementService commandSettlementService; + + private SettlementRequest settlementRequest; + private SettlementAccountRequest settlementAccountRequest; + private Settlement settlement; + private SettlementResponse settlementResponse; + private SettlementSaveResponse expectedResponse; + + @BeforeEach + void setUp() { + settlementRequest = new SettlementRequest("GroupName", "password123"); + settlementResponse = new SettlementResponse(1L, 1L, LocalDateTime.now(), LocalDateTime.now().plusDays(1), + "bank", + "1234-1234", LocalDateTime.now().plusDays(1)); + settlementAccountRequest = new SettlementAccountRequest("newBank", "5678-5678"); + expectedResponse = new SettlementSaveResponse("groupToken", mock(AppointmentMemberResponse.class)); + settlement = mock(Settlement.class); + } + + @Test + @DisplayName("그룹과 총무를 생성할 수 있다.") + void createSettlement() { + // Given + AppointmentMemberResponse appointmentMemberResponse = new AppointmentMemberResponse(1L, ExpenseRole.MANAGER, + "김모또", null, true, + LocalDateTime.now()); + + when(settlementCreator.createSettlement(any(SettlementRequest.class), anyLong())).thenReturn(settlement); + when(settlement.getCode()).thenReturn("code"); + when(commandAppointmentMemberService.createManager(any(), any())).thenReturn(appointmentMemberResponse); + + // When + SettlementSaveResponse response = commandSettlementService.createSettlement(settlementRequest, 1L); + + // Then + assertThat(response).isNotNull(); + assertThat(response.groupToken()).isEqualTo("code"); + assertThat(response.manager().role()).isEqualTo(ExpenseRole.MANAGER); + + verify(settlementCreator, times(1)).createSettlement(any(SettlementRequest.class), anyLong()); + verify(commandAppointmentMemberService, times(1)).createManager(any(), any()); + } + + @Test + @DisplayName("그룹의 계좌 정보를 업데이트할 수 있다.") + void updateGroupAccount() { + // Given + when(settlementReader.read(anyLong())).thenReturn(settlement); + when(settlementUpdater.updateAccount(any(SettlementAccountRequest.class), anyLong())).thenReturn(settlement); + doNothing().when(settlementValidator).checkSettlementAuthor(any(Settlement.class), anyLong()); + + // When + SettlementResponse result = commandSettlementService.updateAccount(settlementAccountRequest, + settlement.getWriter(), + settlement.getId()); + + // Then + assertThat(result).isNotNull(); + verify(settlementReader, times(1)).read(anyLong()); + verify(settlementValidator, times(1)).checkSettlementAuthor(any(Settlement.class), anyLong()); + verify(settlementUpdater, times(1)).updateAccount(any(SettlementAccountRequest.class), anyLong()); + } + + @Test + @DisplayName("올바른 비밀번호를 입력하면 확인 메시지를 반환한다.") + void VerifyPassword_Success() { + // Given + SettlementPasswordRequest request = new SettlementPasswordRequest("correctPassword"); + SettlementPasswordResponse expectedResponse = SettlementPasswordResponse.from("확인되었습니다."); + + when(settlementReader.read(settlement.getId())).thenReturn(settlement); + doNothing().when(settlementValidator).checkSettlementAuthor(settlement, 1L); + when(settlementValidator.checkSettlementPassword(request, settlement.getPassword())).thenReturn( + expectedResponse); + + // When + SettlementPasswordResponse response = commandSettlementService.isPasswordMatch(settlement.getId(), 1L, request); + + // Then + assertThat(response).isNotNull(); + assertThat(response.status()).isEqualTo("확인되었습니다."); + + verify(settlementReader, times(1)).read(settlement.getId()); + verify(settlementValidator, times(1)).checkSettlementAuthor(settlement, 1L); + verify(settlementValidator, times(1)).checkSettlementPassword(request, settlement.getPassword()); + } + + @Test + @DisplayName("잘못된 비밀번호를 입력하면 예외가 발생한다.") + void VerifyPassword_Fail_WrongPassword() { + // Given + SettlementPasswordRequest request = new SettlementPasswordRequest("wrongPassword"); + String storedPassword = "correctPassword"; + + when(settlementReader.read(settlement.getId())).thenReturn(settlement); + doNothing().when(settlementValidator).checkSettlementAuthor(settlement, 1L); + when(settlement.getPassword()).thenReturn(storedPassword); + + doThrow(new RuntimeException("비밀번호가 일치하지 않습니다.")) + .when(settlementValidator).checkSettlementPassword(request, storedPassword); + + // When & Then + assertThatThrownBy(() -> commandSettlementService.isPasswordMatch(settlement.getId(), 1L, request)) + .isInstanceOf(RuntimeException.class) + .hasMessageContaining("비밀번호가 일치하지 않습니다."); + + verify(settlementReader, times(1)).read(settlement.getId()); + verify(settlementValidator, times(1)).checkSettlementAuthor(settlement, 1L); + verify(settlementValidator, times(1)).checkSettlementPassword(request, storedPassword); + } +} diff --git a/src/test/java/com/dnd/moddo/domain/settlement/service/QuerySettlementServiceTest.java b/src/test/java/com/dnd/moddo/domain/settlement/service/QuerySettlementServiceTest.java new file mode 100644 index 0000000..1202970 --- /dev/null +++ b/src/test/java/com/dnd/moddo/domain/settlement/service/QuerySettlementServiceTest.java @@ -0,0 +1,190 @@ +package com.dnd.moddo.domain.settlement.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; +import static org.springframework.test.util.ReflectionTestUtils.*; + +import java.time.LocalDateTime; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.entity.type.ExpenseRole; +import com.dnd.moddo.domain.settlement.dto.response.SettlementDetailResponse; +import com.dnd.moddo.domain.settlement.dto.response.SettlementHeaderResponse; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.exception.GroupNotFoundException; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementReader; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementValidator; +import com.dnd.moddo.global.support.GroupTestFactory; + +@ExtendWith(MockitoExtension.class) +class QuerySettlementServiceTest { + + @InjectMocks + private QuerySettlementService querySettlementService; + + @Mock + private SettlementReader settlementReader; + + @Mock + private SettlementValidator settlementValidator; + + private Settlement settlement; + private AppointmentMember appointmentMember; + + @BeforeEach + void setUp() { + settlement = GroupTestFactory.createDefault(); + appointmentMember = new AppointmentMember("김완숙", 1, settlement, false, ExpenseRole.MANAGER); + + setField(settlement, "id", 1L); + } + + @Test + @DisplayName("그룹 상세 정보를 정상적으로 조회할 수 있다.") + void FindOne_Success() { + // Given + when(settlementReader.read(anyLong())).thenReturn(settlement); + when(settlementReader.findBySettlement(settlement.getId())).thenReturn(List.of(appointmentMember)); + doNothing().when(settlementValidator).checkSettlementAuthor(settlement, 1L); + + // When + SettlementDetailResponse response = querySettlementService.findOne(settlement.getId(), 1L); + + // Then + assertThat(response).isNotNull(); + assertThat(response.id()).isEqualTo(settlement.getId()); + assertThat(response.groupName()).isEqualTo(settlement.getName()); + assertThat(response.members()).hasSize(1); + assertThat(response.members().get(0).name()).isEqualTo(appointmentMember.getName()); + + verify(settlementReader, times(1)).read(1L); + verify(settlementReader, times(1)).findBySettlement(settlement.getId()); + verify(settlementValidator, times(1)).checkSettlementAuthor(settlement, 1L); + } + + @Test + @DisplayName("그룹 작성자가 아닐 경우 예외가 발생한다.") + void FindOne_Failure_WhenNotGroupAuthor() { + // Given + when(settlementReader.read(anyLong())).thenReturn(settlement); + doThrow(new RuntimeException("Not an author")).when(settlementValidator).checkSettlementAuthor(settlement, 2L); + + // When & Then + assertThatThrownBy(() -> querySettlementService.findOne(1L, 2L)) + .isInstanceOf(RuntimeException.class) + .hasMessageContaining("Not an author"); + + verify(settlementReader, times(1)).read(1L); + verify(settlementValidator, times(1)).checkSettlementAuthor(settlement, 2L); + } + + @Test + @DisplayName("그룹을 찾을 수 없을 경우 예외가 발생한다.") + void FindOne_Failure_WhenGroupNotFound() { + // Given + when(settlementReader.read(anyLong())).thenThrow(new RuntimeException("Group not found")); + + // When & Then + assertThatThrownBy(() -> querySettlementService.findOne(1L, 1L)) + .isInstanceOf(RuntimeException.class) + .hasMessageContaining("Group not found"); + + verify(settlementReader, times(1)).read(1L); + } + + @Test + @DisplayName("그룹 헤더를 정상적으로 조회할 수 있다.") + void FindBySettlementHeader_Success() { + // Given + SettlementHeaderResponse expectedResponse = new SettlementHeaderResponse(settlement.getName(), 1000L, + LocalDateTime.now().plusDays(1), settlement.getBank(), settlement.getAccountNumber()); + when(settlementReader.findByHeader(settlement.getId())).thenReturn(expectedResponse); + + // When + SettlementHeaderResponse response = querySettlementService.findBySettlementHeader(settlement.getId()); + + // Then + assertThat(response).isNotNull(); + assertThat(response.groupName()).isEqualTo(settlement.getName()); + assertThat(response.bank()).isEqualTo(settlement.getBank()); + assertThat(response.accountNumber()).isEqualTo(settlement.getAccountNumber()); + + verify(settlementReader, times(1)).findByHeader(settlement.getId()); + } + + @Test + @DisplayName("그룹 헤더를 찾을 수 없을 경우 예외가 발생한다.") + void FindBySettlementHeader_Failure_WhenHeaderNotFound() { + // Given + when(settlementReader.findByHeader(anyLong())).thenThrow(new RuntimeException("Header not found")); + + // When & Then + assertThatThrownBy(() -> querySettlementService.findBySettlementHeader(1L)) + .isInstanceOf(RuntimeException.class) + .hasMessageContaining("Header not found"); + + verify(settlementReader, times(1)).findByHeader(1L); + } + + @DisplayName("group code가 유효할 때 group Id를 찾을 수 있다.") + @Test + void FindByGroupId_Success() { + //given + Long expected = 1L; + when(settlementReader.findIdByGroupCode(anyString())).thenReturn(expected); + //when + Long result = querySettlementService.findIdByCode("code"); + //then + assertThat(result).isEqualTo(expected); + verify(settlementReader, times(1)).findIdByGroupCode(anyString()); + } + + @DisplayName("group code가 존재하지 않을때 예외가 발생한다..") + @Test + void FindByGroupId_ThrowException_WhenCodeNotFound() { + //given + when(settlementReader.findIdByGroupCode(anyString())).thenThrow(new GroupNotFoundException("code")); + //when & then + assertThatThrownBy(() -> querySettlementService.findIdByCode("code")) + .isInstanceOf(RuntimeException.class) + .hasMessageContaining("code"); + + verify(settlementReader, times(1)).findIdByGroupCode(anyString()); + } + + @DisplayName("group code가 유효할 때 group Id를 찾을 수 있다.") + @Test + void FindByGroupIdNoCache_Success() { + //given + Long expected = 1L; + when(settlementReader.findIdByGroupCode(anyString())).thenReturn(expected); + //when + Long result = querySettlementService.findIdByCodeNoCache("code"); + //then + assertThat(result).isEqualTo(expected); + verify(settlementReader, times(1)).findIdByGroupCode(anyString()); + } + + @DisplayName("group code가 존재하지 않을때 예외가 발생한다..") + @Test + void FindByGroupIdNoCache_ThrowException_WhenCodeNotFound() { + //given + when(settlementReader.findIdByGroupCode(anyString())).thenThrow(new GroupNotFoundException("code")); + //when & then + assertThatThrownBy(() -> querySettlementService.findIdByCodeNoCache("code")) + .isInstanceOf(RuntimeException.class) + .hasMessageContaining("code"); + + verify(settlementReader, times(1)).findIdByGroupCode(anyString()); + } +} diff --git a/src/test/java/com/dnd/moddo/domain/group/service/implementation/GroupCreatorTest.java b/src/test/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementCreatorTest.java similarity index 72% rename from src/test/java/com/dnd/moddo/domain/group/service/implementation/GroupCreatorTest.java rename to src/test/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementCreatorTest.java index dd27754..fe7dbe0 100644 --- a/src/test/java/com/dnd/moddo/domain/group/service/implementation/GroupCreatorTest.java +++ b/src/test/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementCreatorTest.java @@ -1,4 +1,4 @@ -package com.dnd.moddo.domain.group.service.implementation; +package com.dnd.moddo.domain.settlement.service.implementation; import static com.dnd.moddo.global.support.UserTestFactory.*; import static org.assertj.core.api.Assertions.*; @@ -17,18 +17,18 @@ import com.dnd.moddo.domain.character.entity.Character; import com.dnd.moddo.domain.character.repository.CharacterRepository; -import com.dnd.moddo.domain.group.dto.request.GroupRequest; -import com.dnd.moddo.domain.group.entity.Group; -import com.dnd.moddo.domain.group.repository.GroupRepository; import com.dnd.moddo.domain.image.dto.CharacterResponse; import com.dnd.moddo.domain.image.service.implementation.ImageReader; +import com.dnd.moddo.domain.settlement.dto.request.SettlementRequest; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.repository.SettlementRepository; import com.dnd.moddo.domain.user.entity.User; import com.dnd.moddo.domain.user.repository.UserRepository; @ExtendWith(MockitoExtension.class) -class GroupCreatorTest { +class SettlementCreatorTest { @Mock - private GroupRepository groupRepository; + private SettlementRepository settlementRepository; @Mock private UserRepository userRepository; @@ -43,25 +43,25 @@ class GroupCreatorTest { private BCryptPasswordEncoder passwordEncoder; @InjectMocks - private GroupCreator groupCreator; + private SettlementCreator settlementCreator; private Long userId; - private GroupRequest request; + private SettlementRequest request; private User mockUser; private String encodedPassword; - private Group mockGroup; + private Settlement mockSettlement; private CharacterResponse mockCharacterResponse; @BeforeEach void setUp() { userId = 1L; - request = new GroupRequest("groupName", "password"); + request = new SettlementRequest("groupName", "password"); mockUser = createGuestDefault(); encodedPassword = "encryptedPassword"; - mockGroup = Group.builder() + mockSettlement = Settlement.builder() .writer(userId) .name(request.name()) .password(encodedPassword) @@ -78,19 +78,19 @@ void setUp() { @DisplayName("사용자는 모임 생성 시 랜덤 캐릭터도 함께 저장된다.") @Test - void createGroupSuccess() { + void createSettlementSuccess() { // given when(userRepository.getById(userId)).thenReturn(mockUser); when(passwordEncoder.encode(request.password())).thenReturn(encodedPassword); - when(groupRepository.save(any(Group.class))).thenReturn(mockGroup); + when(settlementRepository.save(any(Settlement.class))).thenReturn(mockSettlement); when(imageReader.getRandomCharacter()).thenReturn(mockCharacterResponse); when(characterRepository.save(any(Character.class))).thenAnswer(invocation -> invocation.getArgument(0)); - when(groupRepository.existsByCode(anyString())) + when(settlementRepository.existsByCode(anyString())) .thenReturn(false); // when - Group response = groupCreator.createGroup(request, userId); + Settlement response = settlementCreator.createSettlement(request, userId); // then assertThat(response).isNotNull(); @@ -98,10 +98,10 @@ void createGroupSuccess() { verify(userRepository, times(1)).getById(userId); verify(passwordEncoder, times(1)).encode(request.password()); - verify(groupRepository, times(1)).save(any(Group.class)); + verify(settlementRepository, times(1)).save(any(Settlement.class)); verify(imageReader, times(1)).getRandomCharacter(); verify(characterRepository, times(1)).save(any(Character.class)); - verify(groupRepository, times(1)).existsByCode(anyString()); + verify(settlementRepository, times(1)).existsByCode(anyString()); } @DisplayName("모임 생성 시 중복된 group code를 5번 생성시 예외가 발생한다. ") @@ -111,14 +111,14 @@ void whenGroupCodeIsDuplicatedFiveTimes_thenThrowsException() { when(userRepository.getById(userId)).thenReturn(mockUser); when(passwordEncoder.encode(request.password())).thenReturn(encodedPassword); - when(groupRepository.existsByCode(anyString())).thenReturn(true); + when(settlementRepository.existsByCode(anyString())).thenReturn(true); // when & then - assertThatThrownBy(() -> groupCreator.createGroup(request, userId)) + assertThatThrownBy(() -> settlementCreator.createSettlement(request, userId)) .isInstanceOf(RuntimeException.class) .hasMessageContaining("코드"); verify(userRepository, times(1)).getById(anyLong()); - verify(groupRepository, times((5))).existsByCode(anyString()); + verify(settlementRepository, times((5))).existsByCode(anyString()); } } diff --git a/src/test/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementReaderTest.java b/src/test/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementReaderTest.java new file mode 100644 index 0000000..f1933a2 --- /dev/null +++ b/src/test/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementReaderTest.java @@ -0,0 +1,127 @@ +package com.dnd.moddo.domain.settlement.service.implementation; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.*; + +import java.util.List; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.dnd.moddo.domain.appointmentMember.entity.AppointmentMember; +import com.dnd.moddo.domain.appointmentMember.repository.AppointmentMemberRepository; +import com.dnd.moddo.domain.expense.repository.ExpenseRepository; +import com.dnd.moddo.domain.settlement.dto.response.SettlementHeaderResponse; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.exception.GroupNotFoundException; +import com.dnd.moddo.domain.settlement.repository.SettlementRepository; + +@ExtendWith(MockitoExtension.class) +class SettlementReaderTest { + + @Mock + private SettlementRepository settlementRepository; + + @Mock + private ExpenseRepository expenseRepository; + + @Mock + private AppointmentMemberRepository appointmentMemberRepository; + + @InjectMocks + private SettlementReader settlementReader; + + @Test + @DisplayName("그룹 ID를 통해 그룹을 정상적으로 조회할 수 있다.") + void readGroup_Success() { + // Given + Long groupId = 1L; + Settlement mockSettlement = mock(Settlement.class); + + when(settlementRepository.getById(anyLong())).thenReturn(mockSettlement); + + // When + Settlement result = settlementReader.read(groupId); + + // Then + assertThat(result).isNotNull(); + verify(settlementRepository, times(1)).getById(groupId); + } + + @Test + @DisplayName("그룹을 통해 그룹 멤버 목록을 정상적으로 조회할 수 있다.") + void findBySettlement_Success() { + // Given + Settlement mockSettlement = mock(Settlement.class); + when(mockSettlement.getId()).thenReturn(1L); + List mockMembers = List.of(mock(AppointmentMember.class), mock(AppointmentMember.class)); + + when(appointmentMemberRepository.findBySettlementId(anyLong())).thenReturn(mockMembers); + + // When + List result = settlementReader.findBySettlement(mockSettlement.getId()); + + // Then + assertThat(result).hasSize(2); + verify(appointmentMemberRepository, times(1)).findBySettlementId(mockSettlement.getId()); + } + + @Test + @DisplayName("그룹 ID를 통해 그룹 헤더 정보를 정상적으로 조회할 수 있다.") + void findByHeader_Success() { + // Given + Long groupId = 1L; + Settlement mockSettlement = mock(Settlement.class); + when(mockSettlement.getName()).thenReturn("모임 이름"); + when(mockSettlement.getBank()).thenReturn("은행"); + when(mockSettlement.getAccountNumber()).thenReturn("1234-1234"); + when(settlementRepository.getById(anyLong())).thenReturn(mockSettlement); + + Long totalAmount = 1000L; + when(expenseRepository.sumAmountBySettlement(any(Settlement.class))).thenReturn(totalAmount); + + // When + SettlementHeaderResponse result = settlementReader.findByHeader(groupId); + + // Then + assertThat(result).isNotNull(); + assertThat(result.groupName()).isEqualTo("모임 이름"); + assertThat(result.totalAmount()).isEqualTo(1000L); + assertThat(result.bank()).isEqualTo("은행"); + assertThat(result.accountNumber()).isEqualTo("1234-1234"); + verify(settlementRepository, times(1)).getById(groupId); + verify(expenseRepository, times(1)).sumAmountBySettlement(mockSettlement); + } + + @DisplayName("group code로 group Id를 찾을 수 있다.") + @Test + void whenValidGroupCode_thenReturnsGroupId() { + //given + Long expected = 1L; + when(settlementRepository.getIdByCode(anyString())).thenReturn(expected); + //when + Long result = settlementReader.findIdByGroupCode("code"); + //then + assertThat(result).isEqualTo(expected); + verify(settlementRepository, times(1)).getIdByCode(anyString()); + } + + @DisplayName("group code로 group id를 찾을 수 없을때 예외가 발생한다.") + @Test + void whenInvalidGroupCode_thenThrowsException() { + //given + when(settlementRepository.getIdByCode(anyString())).thenThrow(new GroupNotFoundException("code")); + //when & then + assertThatThrownBy(() -> settlementReader.findIdByGroupCode("code")) + .isInstanceOf(GroupNotFoundException.class) + .hasMessageContaining("code"); + + verify(settlementRepository, times(1)).getIdByCode(anyString()); + } +} diff --git a/src/test/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementUpdaterTest.java b/src/test/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementUpdaterTest.java new file mode 100644 index 0000000..b860138 --- /dev/null +++ b/src/test/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementUpdaterTest.java @@ -0,0 +1,57 @@ +package com.dnd.moddo.domain.settlement.service.implementation; + +import static org.assertj.core.api.AssertionsForClassTypes.*; +import static org.mockito.Mockito.*; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.dnd.moddo.domain.settlement.dto.request.SettlementAccountRequest; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.exception.GroupNotFoundException; +import com.dnd.moddo.domain.settlement.repository.SettlementRepository; + +@ExtendWith(MockitoExtension.class) +class SettlementUpdaterTest { + @Mock + private SettlementRepository settlementRepository; + @InjectMocks + private SettlementUpdater settlementUpdater; + + @DisplayName("그룹이 존재하면 계좌 정보를 수정할 수 있다.") + @Test + void updateAccountSuccess() { + // given + Long groupId = 1L; + Settlement mockSettlement = mock(Settlement.class); + SettlementAccountRequest request = mock(SettlementAccountRequest.class); + + when(settlementRepository.getById(eq(groupId))).thenReturn(mockSettlement); + + // when + Settlement updatedSettlement = settlementUpdater.updateAccount(request, groupId); + + // then + verify(mockSettlement, times(1)).updateAccount(any()); + assertThat(updatedSettlement).isEqualTo(mockSettlement); + } + + @DisplayName("그룹이 존재하지 않으면 계좌 정보를 수정할 때 예외가 발생한다.") + @Test + void updateAccountNotFoundGroup() { + // given + Long groupId = 1L; + SettlementAccountRequest request = mock(SettlementAccountRequest.class); + + doThrow(new GroupNotFoundException(groupId)).when(settlementRepository).getById(groupId); + + // when & then + assertThatThrownBy(() -> settlementUpdater.updateAccount(request, groupId)) + .isInstanceOf(GroupNotFoundException.class); + } + +} diff --git a/src/test/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementValidatorTest.java b/src/test/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementValidatorTest.java new file mode 100644 index 0000000..9ba03ab --- /dev/null +++ b/src/test/java/com/dnd/moddo/domain/settlement/service/implementation/SettlementValidatorTest.java @@ -0,0 +1,87 @@ +package com.dnd.moddo.domain.settlement.service.implementation; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.security.crypto.password.PasswordEncoder; + +import com.dnd.moddo.domain.settlement.dto.request.SettlementPasswordRequest; +import com.dnd.moddo.domain.settlement.dto.response.SettlementPasswordResponse; +import com.dnd.moddo.domain.settlement.entity.Settlement; +import com.dnd.moddo.domain.settlement.exception.GroupNotAuthorException; +import com.dnd.moddo.domain.settlement.exception.InvalidPasswordException; + +class SettlementValidatorTest { + + private SettlementValidator settlementValidator; + + @Mock + private PasswordEncoder passwordEncoder; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + settlementValidator = new SettlementValidator(passwordEncoder, null); // GroupRepository는 필요 없으면 null 처리 + } + + @Test + @DisplayName("그룹 작성자와 요청 사용자가 같으면 예외가 발생하지 않는다.") + void checkSettlementAuthor_Success() { + // Given + Settlement settlement = mock(Settlement.class); + Long writer = 1L; + when(settlement.isWriter(writer)).thenReturn(true); + + // When & Then + settlementValidator.checkSettlementAuthor(settlement, writer); + } + + @Test + @DisplayName("그룹 작성자와 요청 사용자가 다르면 GroupNotAuthorException 예외가 발생한다.") + void checkSettlementAuthor_Fail() { + Settlement settlement = mock(Settlement.class); + Long writer = 1L; + when(settlement.isWriter(writer)).thenReturn(false); + + // When & Then + assertThatThrownBy(() -> settlementValidator.checkSettlementAuthor(settlement, writer)) + .isInstanceOf(GroupNotAuthorException.class); + } + + @Test + @DisplayName("올바른 비밀번호를 입력하면 확인 메시지를 반환한다.") + void checkSettlementPassword_Success() { + // Given + String rawPassword = "correctPassword"; + String encodedPassword = "$2a$10$WzHqXjA4oH8lTxH9m6Q7se1k2dG0B1h7U4Fv0t5y8LdHwWx7uy6MS"; + SettlementPasswordRequest request = new SettlementPasswordRequest(rawPassword); + + when(passwordEncoder.matches(rawPassword, encodedPassword)).thenReturn(true); + + // When + SettlementPasswordResponse response = settlementValidator.checkSettlementPassword(request, encodedPassword); + + // Then + assertThat(response.status()).isEqualTo("확인되었습니다."); + } + + @Test + @DisplayName("잘못된 비밀번호를 입력하면 InvalidPasswordException 예외가 발생한다.") + void checkSettlementPassword_Fail() { + // Given + String rawPassword = "wrongPassword"; + String encodedPassword = "$2a$10$WzHqXjA4oH8lTxH9m6Q7se1k2dG0B1h7U4Fv0t5y8LdHwWx7uy6MS"; + SettlementPasswordRequest request = new SettlementPasswordRequest(rawPassword); + + when(passwordEncoder.matches(rawPassword, encodedPassword)).thenReturn(false); + + // When & Then + assertThatThrownBy(() -> settlementValidator.checkSettlementPassword(request, encodedPassword)) + .isInstanceOf(InvalidPasswordException.class); + } +} diff --git a/src/test/java/com/dnd/moddo/global/support/GroupTestFactory.java b/src/test/java/com/dnd/moddo/global/support/GroupTestFactory.java index ddd14dc..d7a13eb 100644 --- a/src/test/java/com/dnd/moddo/global/support/GroupTestFactory.java +++ b/src/test/java/com/dnd/moddo/global/support/GroupTestFactory.java @@ -2,11 +2,11 @@ import java.time.LocalDateTime; -import com.dnd.moddo.domain.group.entity.Group; +import com.dnd.moddo.domain.settlement.entity.Settlement; public class GroupTestFactory { - public static Group createDefault() { - return new Group( + public static Settlement createDefault() { + return new Settlement( "group 1", 1L, "1234", @@ -18,8 +18,8 @@ public static Group createDefault() { ); } - public static Group createWithCode(String code) { - return new Group( + public static Settlement createWithCode(String code) { + return new Settlement( "group 1", 1L, "1234", diff --git a/src/test/java/com/dnd/moddo/global/util/ControllerTest.java b/src/test/java/com/dnd/moddo/global/util/ControllerTest.java index fed0773..c7f09cd 100644 --- a/src/test/java/com/dnd/moddo/global/util/ControllerTest.java +++ b/src/test/java/com/dnd/moddo/global/util/ControllerTest.java @@ -15,16 +15,16 @@ import com.dnd.moddo.domain.expense.controller.ExpenseController; import com.dnd.moddo.domain.expense.service.CommandExpenseService; import com.dnd.moddo.domain.expense.service.QueryExpenseService; -import com.dnd.moddo.domain.group.controller.GroupController; -import com.dnd.moddo.domain.group.service.CommandGroupService; -import com.dnd.moddo.domain.group.service.QueryGroupService; -import com.dnd.moddo.domain.groupMember.controller.GroupMemberController; -import com.dnd.moddo.domain.groupMember.service.CommandGroupMemberService; -import com.dnd.moddo.domain.groupMember.service.QueryGroupMemberService; +import com.dnd.moddo.domain.appointmentMember.controller.AppointmentMemberController; +import com.dnd.moddo.domain.appointmentMember.service.CommandAppointmentMemberService; +import com.dnd.moddo.domain.appointmentMember.service.QueryAppointmentMemberService; import com.dnd.moddo.domain.image.controller.ImageController; import com.dnd.moddo.domain.image.service.CommandImageService; import com.dnd.moddo.domain.memberExpense.controller.MemberExpenseController; import com.dnd.moddo.domain.memberExpense.service.QueryMemberExpenseService; +import com.dnd.moddo.domain.settlement.controller.SettlementController; +import com.dnd.moddo.domain.settlement.service.CommandSettlementService; +import com.dnd.moddo.domain.settlement.service.QuerySettlementService; import com.dnd.moddo.global.config.CookieProperties; import com.dnd.moddo.global.jwt.auth.JwtAuth; import com.dnd.moddo.global.jwt.auth.JwtFilter; @@ -37,8 +37,8 @@ AuthController.class, CharacterController.class, ExpenseController.class, - GroupController.class, - GroupMemberController.class, + SettlementController.class, + AppointmentMemberController.class, ImageController.class, MemberExpenseController.class }) @@ -73,23 +73,23 @@ public abstract class ControllerTest { protected CommandExpenseService commandExpenseService; @MockBean - protected QueryGroupService queryGroupService; + protected QuerySettlementService querySettlementService; @MockBean - protected CommandGroupService commandGroupService; + protected CommandSettlementService commandSettlementService; @MockBean - protected QueryGroupMemberService queryGroupMemberService; + protected QueryAppointmentMemberService queryAppointmentMemberService; @MockBean - protected CommandGroupMemberService commandGroupMemberService; + protected CommandAppointmentMemberService commandAppointmentMemberService; @MockBean protected CommandImageService commandImageService; @MockBean protected QueryMemberExpenseService queryMemberExpenseService; - + @MockBean protected CookieProperties cookieProperties; // Jwt diff --git a/src/test/java/com/dnd/moddo/integration/CacheIntegrationTest.java b/src/test/java/com/dnd/moddo/integration/CacheIntegrationTest.java index 9221917..19d90a7 100644 --- a/src/test/java/com/dnd/moddo/integration/CacheIntegrationTest.java +++ b/src/test/java/com/dnd/moddo/integration/CacheIntegrationTest.java @@ -19,9 +19,9 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.junit.jupiter.Testcontainers; -import com.dnd.moddo.domain.group.repository.GroupRepository; -import com.dnd.moddo.domain.group.service.QueryGroupService; -import com.dnd.moddo.domain.group.service.implementation.GroupReader; +import com.dnd.moddo.domain.settlement.repository.SettlementRepository; +import com.dnd.moddo.domain.settlement.service.QuerySettlementService; +import com.dnd.moddo.domain.settlement.service.implementation.SettlementReader; import com.dnd.moddo.global.support.GroupTestFactory; @ActiveProfiles("test") @@ -32,13 +32,13 @@ public class CacheIntegrationTest { @Autowired - private QueryGroupService queryGroupService; + private QuerySettlementService querySettlementService; @Autowired - private GroupRepository groupRepository; + private SettlementRepository settlementRepository; @MockBean - private GroupReader groupReader; + private SettlementReader settlementReader; @Autowired private StringRedisTemplate redisTemplate; @@ -61,7 +61,7 @@ private static void registerRedisProperties(DynamicPropertyRegistry registry) { @BeforeEach void setUp() { - groupRepository.save(GroupTestFactory.createDefault()); + settlementRepository.save(GroupTestFactory.createDefault()); } @AfterAll @@ -75,20 +75,20 @@ void findIdByCode_whenQueriedTwice_thenUsesCacheAndCallsReaderOnce() { //given String code = "code"; - when(groupReader.findIdByGroupCode("code")).thenReturn(1L); + when(settlementReader.findIdByGroupCode("code")).thenReturn(1L); //when - Long first = queryGroupService.findIdByCode(code); - Long second = queryGroupService.findIdByCode(code); + Long first = querySettlementService.findIdByCode(code); + Long second = querySettlementService.findIdByCode(code); //then assertThat(first).isEqualTo(second); - String cacheKey = "groups::" + code; + String cacheKey = "settlements::" + code; Object cachedValue = redisTemplate.opsForValue().get(cacheKey); assertThat(cachedValue).isNotNull(); - verify(groupReader, times(1)).findIdByGroupCode("code"); + verify(settlementReader, times(1)).findIdByGroupCode("code"); } }