diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java index 9f577c1b4..078752191 100644 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ b/server/src/main/java/server/haengdong/application/BillActionService.java @@ -68,10 +68,23 @@ public void updateBillAction(String token, Long actionId, BillActionUpdateAppReq validateToken(token, billAction); + resetBillActionDetail(billAction, request.price()); + BillAction updatedBillAction = billAction.update(request.title(), request.price()); billActionRepository.save(updatedBillAction); } + private void resetBillActionDetail(BillAction billAction, Long updatePrice) { + if (billAction.getPrice() != updatePrice) { + List billActionDetails = billActionDetailRepository.findByBillAction(billAction); + int memberCount = billActionDetails.size(); + if (memberCount != 0) { + Long eachPrice = updatePrice / memberCount; + billActionDetails.forEach(billActionDetail -> billActionDetail.updatePrice(eachPrice)); + } + } + } + private void validateToken(String token, BillAction billAction) { Event event = billAction.getEvent(); if (event.isTokenMismatch(token)) { diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java index 79318fa98..47d336c60 100644 --- a/server/src/main/java/server/haengdong/application/MemberActionService.java +++ b/server/src/main/java/server/haengdong/application/MemberActionService.java @@ -8,6 +8,10 @@ import server.haengdong.application.response.CurrentMemberAppResponse; import server.haengdong.domain.action.Action; import server.haengdong.domain.action.ActionRepository; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionDetailRepository; +import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.action.CurrentMembers; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionRepository; @@ -25,6 +29,8 @@ public class MemberActionService { private final MemberActionRepository memberActionRepository; private final EventRepository eventRepository; private final ActionRepository actionRepository; + private final BillActionDetailRepository billActionDetailRepository; + private final BillActionRepository billActionRepository; @Transactional public void saveMemberAction(String token, MemberActionsSaveAppRequest request) { @@ -65,6 +71,9 @@ public void deleteMember(String token, String memberName) { .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); memberActionRepository.deleteAllByEventAndMemberName(event, memberName); + + List billActions = billActionRepository.findByAction_Event(event); + billActions.forEach(billAction -> resetBillAction(event, billAction)); } @Transactional @@ -77,6 +86,26 @@ public void deleteMemberAction(String token, Long actionId) { .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_ACTION_NOT_FOUND)); memberActionRepository.deleteAllByMemberNameAndMinSequence(memberAction.getMemberName(), - memberAction.getSequence()); + memberAction.getSequence()); + + List billActions = billActionRepository.findByEventAndGreaterThanSequence(event, + action.getSequence()); + billActions.forEach(billAction -> resetBillAction(event, billAction)); + } + + private void resetBillAction(Event event, BillAction billAction) { + List memberActions = memberActionRepository.findByEventAndSequence(event, + billAction.getSequence()); + CurrentMembers currentMembers = CurrentMembers.of(memberActions); + + billActionDetailRepository.deleteAllByBillAction(billAction); + + if (currentMembers.isNotEmpty()) { + Long eachPrice = billAction.getPrice() / currentMembers.size(); + for (String member : currentMembers.getMembers()) { + BillActionDetail billActionDetail = new BillActionDetail(billAction, member, eachPrice); + billActionDetailRepository.save(billActionDetail); + } + } } } diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java index 40aeead63..161a6663b 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java @@ -31,4 +31,8 @@ public BillActionDetail(BillAction billAction, String memberName, Long price) { this.memberName = memberName; this.price = price; } + + public void updatePrice(Long price) { + this.price = price; + } } diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java index 7197b54bf..5d74462ff 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java @@ -1,5 +1,6 @@ package server.haengdong.domain.action; +import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import server.haengdong.domain.event.Event; @@ -7,5 +8,9 @@ @Repository public interface BillActionDetailRepository extends JpaRepository { + List findByBillAction(BillAction billAction); + + void deleteAllByBillAction(BillAction billAction); + void deleteByBillAction_Action_EventAndBillAction_ActionId(Event event, Long actionId); } diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java index a0e6a1bf1..817a63bf8 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java @@ -4,6 +4,7 @@ import java.util.Optional; import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import server.haengdong.domain.event.Event; @@ -16,4 +17,11 @@ public interface BillActionRepository extends JpaRepository { void deleteByAction_EventAndActionId(Event event, Long actionId); Optional findByAction_Id(Long actionId); + + @Query(""" + select ba + from BillAction ba + where ba.action.event = :event and ba.action.sequence > :sequence + """) + List findByEventAndGreaterThanSequence(Event event, Long sequence); } diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java index 8cf9e42cf..324ff9797 100644 --- a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java +++ b/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java @@ -43,4 +43,11 @@ public interface MemberActionRepository extends JpaRepository findAllByAction_EventAndMemberName(Event event, String memberName); boolean existsByAction_EventAndMemberName(Event event, String updatedMemberName); + + @Query(""" + select ma + from MemberAction ma + where ma.action.event = :event and ma.action.sequence < :sequence + """) + List findByEventAndSequence(Event event, Long sequence); } diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index 54de966e5..34261042f 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -1,6 +1,7 @@ package server.haengdong.presentation; import jakarta.validation.Valid; +import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -15,10 +16,12 @@ import org.springframework.web.bind.annotation.RestController; import server.haengdong.application.AuthService; import server.haengdong.application.EventService; +import server.haengdong.application.response.ActionAppResponse; import server.haengdong.infrastructure.auth.CookieProperties; import server.haengdong.presentation.request.EventLoginRequest; import server.haengdong.presentation.request.EventSaveRequest; import server.haengdong.presentation.request.MemberNamesUpdateRequest; +import server.haengdong.presentation.response.ActionsResponse; import server.haengdong.presentation.response.EventDetailResponse; import server.haengdong.presentation.response.EventResponse; import server.haengdong.presentation.response.MembersResponse; @@ -60,6 +63,14 @@ public ResponseEntity findActions(@PathVariable("eventId") String return ResponseEntity.ok(stepsResponse); } + @GetMapping("/api/events/{eventId}/actions/v2") + public ResponseEntity findActions2(@PathVariable("eventId") String token) { + List actions = eventService.findActions(token); + ActionsResponse actionsResponse = ActionsResponse.of(actions); + + return ResponseEntity.ok(actionsResponse); + } + @GetMapping("/api/events/{eventId}/members") public ResponseEntity findAllMembers(@PathVariable("eventId") String token) { MembersResponse response = MembersResponse.of(eventService.findAllMembers(token)); diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java b/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java new file mode 100644 index 000000000..ea46c5bd9 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java @@ -0,0 +1,22 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.ActionAppResponse; + +public record ActionResponse2( + Long actionId, + String name, + Long price, + Long sequence, + String type +) { + + public static ActionResponse2 of(ActionAppResponse actionAppResponse) { + return new ActionResponse2( + actionAppResponse.actionId(), + actionAppResponse.name(), + actionAppResponse.price(), + actionAppResponse.sequence(), + actionAppResponse.actionType().name() + ); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java b/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java new file mode 100644 index 000000000..c8ae780e3 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java @@ -0,0 +1,14 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.ActionAppResponse; + +public record ActionsResponse( + List actions +) { + public static ActionsResponse of(List actions) { + return new ActionsResponse(actions.stream() + .map(ActionResponse2::of) + .toList()); + } +} diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java index 48f24a6fb..fc0db9a37 100644 --- a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java @@ -154,6 +154,40 @@ void updateBillAction1() { .isInstanceOf(HaengdongException.class); } + @DisplayName("지출 내역 금액을 변경하면 지출 디테일이 초기화 된다.") + @Test + void updateBillAction2() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + Action action = Action.createFirst(savedEvent); + BillAction billAction = new BillAction(action, "뽕족", 10_000L); + BillAction savedBillAction = billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(savedBillAction, "감자", 3000L); + BillActionDetail billActionDetail2 = new BillActionDetail(savedBillAction, "고구마", 2000L); + BillActionDetail billActionDetail3 = new BillActionDetail(savedBillAction, "당근", 3000L); + BillActionDetail billActionDetail4 = new BillActionDetail(savedBillAction, "양파", 2000L); + + billActionDetailRepository.saveAll( + List.of(billActionDetail1, billActionDetail2, billActionDetail3, billActionDetail4)); + + Long actionId = savedBillAction.getAction().getId(); + BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); + + billActionService.updateBillAction(event.getToken(), actionId, request); + + BillAction updatedBillAction = billActionRepository.findById(savedBillAction.getId()).get(); + List billActionDetails = billActionDetailRepository.findByBillAction(updatedBillAction); + + assertThat(billActionDetails).hasSize(4) + .extracting("memberName", "price") + .containsExactlyInAnyOrder( + tuple("감자", 5000L), + tuple("고구마", 5000L), + tuple("당근", 5000L), + tuple("양파", 5000L) + ); + } + @DisplayName("지출 내역을 삭제한다.") @Test void deleteBillAction() { diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java index 8f0af8dfe..14a7d4225 100644 --- a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java +++ b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java @@ -14,6 +14,10 @@ import server.haengdong.application.request.MemberActionSaveAppRequest; import server.haengdong.application.request.MemberActionsSaveAppRequest; import server.haengdong.domain.action.Action; +import server.haengdong.domain.action.BillAction; +import server.haengdong.domain.action.BillActionDetail; +import server.haengdong.domain.action.BillActionDetailRepository; +import server.haengdong.domain.action.BillActionRepository; import server.haengdong.domain.action.MemberAction; import server.haengdong.domain.action.MemberActionRepository; import server.haengdong.domain.action.MemberActionStatus; @@ -33,6 +37,12 @@ class MemberActionServiceTest extends ServiceTestSupport { @Autowired private EventRepository eventRepository; + @Autowired + private BillActionRepository billActionRepository; + + @Autowired + private BillActionDetailRepository billActionDetailRepository; + @DisplayName("현재 행사에 참여하고 있는 경우에 나갈 수 있다.") @Test void saveMemberActionTest() { @@ -115,6 +125,44 @@ void deleteMember() { ); } + @DisplayName("이벤트에 속한 멤버을 삭제하면 전체 지출 내역 디테일이 초기화된다.") + @Test + void deleteMember1() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + MemberAction memberAction1 = createMemberAction(new Action(event, 1L), "토다리", IN, 1L); + Action targetAction = new Action(event, 2L); + MemberAction memberAction2 = createMemberAction(targetAction, "토다리", OUT, 2L); + MemberAction memberAction3 = createMemberAction(new Action(event, 3L), "쿠키", IN, 3L); + MemberAction memberAction4 = createMemberAction(new Action(event, 4L), "웨디", IN, 4L); + MemberAction memberAction5 = createMemberAction(new Action(event, 5L), "감자", IN, 5L); + memberActionRepository.saveAll( + List.of(memberAction1, + memberAction2, + memberAction3, + memberAction4, + memberAction5 + ) + ); + BillAction billAction = new BillAction(new Action(event, 6L), "뽕족", 100_000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "쿠키", 40_000L); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "웨디", 30_000L); + BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "감자", 30_000L); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3)); + + memberActionService.deleteMember(event.getToken(), "쿠키"); + + List billActionDetails = billActionDetailRepository.findByBillAction(billAction); + + assertThat(billActionDetails).hasSize(2) + .extracting("memberName", "price") + .containsExactlyInAnyOrder( + tuple("웨디", 50_000L), + tuple("감자", 50_000L) + ); + } + @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") @Test void deleteMemberAction() { @@ -151,6 +199,45 @@ void deleteMemberAction() { ); } + @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후 지출 내역 디테일이 초기화된다.") + @Test + void deleteMemberAction1() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + MemberAction memberAction1 = createMemberAction(new Action(event, 1L), "토다리", IN, 1L); + Action targetAction = new Action(event, 2L); + MemberAction memberAction2 = createMemberAction(targetAction, "토다리", OUT, 2L); + MemberAction memberAction3 = createMemberAction(new Action(event, 3L), "쿠키", IN, 3L); + MemberAction memberAction4 = createMemberAction(new Action(event, 4L), "웨디", IN, 4L); + MemberAction memberAction5 = createMemberAction(new Action(event, 5L), "감자", IN, 5L); + memberActionRepository.saveAll( + List.of(memberAction1, + memberAction2, + memberAction3, + memberAction4, + memberAction5 + ) + ); + BillAction billAction = new BillAction(new Action(event, 6L), "뽕족", 100_000L); + billActionRepository.save(billAction); + BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "쿠키", 40_000L); + BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "웨디", 30_000L); + BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "감자", 30_000L); + billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3)); + + memberActionService.deleteMemberAction(event.getToken(), targetAction.getId()); + List billActionDetails = billActionDetailRepository.findByBillAction(billAction); + + assertThat(billActionDetails).hasSize(4) + .extracting("memberName", "price") + .containsExactlyInAnyOrder( + tuple("토다리", 25_000L), + tuple("쿠키", 25_000L), + tuple("웨디", 25_000L), + tuple("감자", 25_000L) + ); + } + private MemberAction createMemberAction( Action action, String memberName, diff --git a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java index 09546bcc3..9ee8985a3 100644 --- a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java @@ -136,15 +136,15 @@ void findAllMembersTest() throws Exception { .andExpect(jsonPath("$.memberNames[1]").value("쿠키")) .andDo( document("findAllEventMember", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("memberNames").type(JsonFieldType.ARRAY) - .description("행사 참여자 목록") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("memberNames").type(JsonFieldType.ARRAY) + .description("행사 참여자 목록") + ) ) ); } @@ -161,26 +161,28 @@ void updateMember() throws Exception { String requestBody = objectMapper.writeValueAsString(memberNameUpdateRequest); mockMvc.perform(put("/api/events/{eventId}/members/nameChange", token) - .cookie(EVENT_COOKIE) - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + .cookie(EVENT_COOKIE) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) .andDo(print()) .andExpect(status().isOk()) .andDo( document("updateEventMemberName", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") - ), - requestFields( - fieldWithPath("members").type(JsonFieldType.ARRAY).description("수정할 참여자 목록"), - fieldWithPath("members[].before").type(JsonFieldType.STRING).description("수정 전 참여자 이름"), - fieldWithPath("members[].after").type(JsonFieldType.STRING).description("수정 후 참여자 이름") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY).description("수정할 참여자 목록"), + fieldWithPath("members[].before").type(JsonFieldType.STRING) + .description("수정 전 참여자 이름"), + fieldWithPath("members[].after").type(JsonFieldType.STRING) + .description("수정 후 참여자 이름") + ) ) ); } @@ -195,25 +197,25 @@ void loginEvent() throws Exception { given(authService.getTokenName()).willReturn("eventToken"); mockMvc.perform(post("/api/events/{eventId}/login", token) - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) .andDo(print()) .andExpect(cookie().value("eventToken", "jwtToken")) .andExpect(status().isOk()) .andDo( document("eventLogin", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - requestFields( - fieldWithPath("password").type(JsonFieldType.STRING) - .description("행사 비밀 번호") - ), - responseCookies( - cookieWithName("eventToken").description("행사 관리자용 토큰") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestFields( + fieldWithPath("password").type(JsonFieldType.STRING) + .description("행사 비밀 번호") + ), + responseCookies( + cookieWithName("eventToken").description("행사 관리자용 토큰") + ) ) ); } @@ -231,7 +233,7 @@ void findActions() throws Exception { given(eventService.findActions(token)).willReturn(actionAppResponses); mockMvc.perform(get("/api/events/{eventId}/actions", token) - .accept(MediaType.APPLICATION_JSON)) + .accept(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.steps[0].type").value(equalTo("IN"))) @@ -261,25 +263,88 @@ void findActions() throws Exception { .andDo( document("findActions", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("steps[].type").type(JsonFieldType.STRING) - .description("액션 유형 [BILL, IN, OUT]"), - fieldWithPath("steps[].members").type(JsonFieldType.ARRAY) - .description("해당 step에 참여한 참여자 목록"), - fieldWithPath("steps[].actions[].actionId").type(JsonFieldType.NUMBER) - .description("액션 ID"), - fieldWithPath("steps[].actions[].name").type(JsonFieldType.STRING) - .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), - fieldWithPath("steps[].actions[].price").type(JsonFieldType.NUMBER).optional() - .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), - fieldWithPath("steps[].actions[].sequence").type(JsonFieldType.NUMBER) - .description("액션 순서") - ) + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("steps[].type").type(JsonFieldType.STRING) + .description("액션 유형 [BILL, IN, OUT]"), + fieldWithPath("steps[].members").type(JsonFieldType.ARRAY) + .description("해당 step에 참여한 참여자 목록"), + fieldWithPath("steps[].actions[].actionId").type(JsonFieldType.NUMBER) + .description("액션 ID"), + fieldWithPath("steps[].actions[].name").type(JsonFieldType.STRING) + .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), + fieldWithPath("steps[].actions[].price").type(JsonFieldType.NUMBER).optional() + .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), + fieldWithPath("steps[].actions[].sequence").type(JsonFieldType.NUMBER) + .description("액션 순서") + ) + ) + ); + } + + @DisplayName("행사 전체 액션 이력 조회 v2") + @Test + void findActions2() throws Exception { + String token = "TOKEN"; + List actionAppResponses = List.of( + new ActionAppResponse(1L, "망쵸", null, 1L, ActionType.IN), + new ActionAppResponse(2L, "족발", 100L, 2L, ActionType.BILL), + new ActionAppResponse(3L, "인생네컷", 1000L, 3L, ActionType.BILL), + new ActionAppResponse(4L, "망쵸", null, 4L, ActionType.OUT) + ); + given(eventService.findActions(token)).willReturn(actionAppResponses); + + mockMvc.perform(get("/api/events/{eventId}/actions/v2", token) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.actions[0].actionId").value(equalTo(1))) + .andExpect(jsonPath("$.actions[0].name").value(equalTo("망쵸"))) + .andExpect(jsonPath("$.actions[0].price").value(equalTo(null))) + .andExpect(jsonPath("$.actions[0].sequence").value(equalTo(1))) + .andExpect(jsonPath("$.actions[0].type").value(equalTo("IN"))) + + .andExpect(jsonPath("$.actions[1].actionId").value(equalTo(2))) + .andExpect(jsonPath("$.actions[1].name").value(equalTo("족발"))) + .andExpect(jsonPath("$.actions[1].price").value(equalTo(100))) + .andExpect(jsonPath("$.actions[1].sequence").value(equalTo(2))) + .andExpect(jsonPath("$.actions[1].type").value(equalTo("BILL"))) + + .andExpect(jsonPath("$.actions[2].actionId").value(equalTo(3))) + .andExpect(jsonPath("$.actions[2].name").value(equalTo("인생네컷"))) + .andExpect(jsonPath("$.actions[2].price").value(equalTo(1000))) + .andExpect(jsonPath("$.actions[2].sequence").value(equalTo(3))) + .andExpect(jsonPath("$.actions[2].type").value(equalTo("BILL"))) + + .andExpect(jsonPath("$.actions[3].actionId").value(equalTo(4))) + .andExpect(jsonPath("$.actions[3].name").value(equalTo("망쵸"))) + .andExpect(jsonPath("$.actions[3].price").value(equalTo(null))) + .andExpect(jsonPath("$.actions[3].sequence").value(equalTo(4))) + .andExpect(jsonPath("$.actions[3].type").value(equalTo("OUT"))) + + .andDo( + document("findActions", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("actions[].actionId").type(JsonFieldType.NUMBER) + .description("액션 ID"), + fieldWithPath("actions[].name").type(JsonFieldType.STRING) + .description("참여자 액션일 경우 참여자 이름, 지출 액션일 경우 지출 내역 이름"), + fieldWithPath("actions[].price").type(JsonFieldType.NUMBER).optional() + .description("참여자 액션일 경우 null, 지출 액션일 경우 지출 금액"), + fieldWithPath("actions[].sequence").type(JsonFieldType.NUMBER) + .description("액션 순서"), + fieldWithPath("actions[].type").type(JsonFieldType.STRING) + .description("액션 타입") + ) ) ); }