-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
348 additions
and
2 deletions.
There are no files selected for viewing
38 changes: 38 additions & 0 deletions
38
server/src/main/java/server/haengdong/application/ActionService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package server.haengdong.application; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import server.haengdong.application.response.MemberBillReportAppResponse; | ||
import server.haengdong.domain.action.BillAction; | ||
import server.haengdong.domain.action.BillActionRepository; | ||
import server.haengdong.domain.action.MemberAction; | ||
import server.haengdong.domain.action.MemberActionRepository; | ||
import server.haengdong.domain.action.MemberBillReports; | ||
import server.haengdong.domain.event.Event; | ||
import server.haengdong.domain.event.EventRepository; | ||
|
||
@RequiredArgsConstructor | ||
@Service | ||
public class ActionService { | ||
|
||
private final BillActionRepository billActionRepository; | ||
private final MemberActionRepository memberActionRepository; | ||
private final EventRepository eventRepository; | ||
|
||
public List<MemberBillReportAppResponse> getMemberBillReports(String token) { | ||
Event event = eventRepository.findByToken(token) | ||
.orElseThrow(() -> new IllegalArgumentException("event not found")); | ||
List<BillAction> billActions = billActionRepository.findByAction_Event(event); | ||
List<MemberAction> memberActions = memberActionRepository.findAllByEvent(event); | ||
|
||
MemberBillReports memberBillReports = MemberBillReports.createByActions(billActions, memberActions); | ||
|
||
List<MemberBillReportAppResponse> memberBillReportResponses = new ArrayList<>(); | ||
memberBillReports.getReports().forEach( | ||
(member, price) -> memberBillReportResponses.add(new MemberBillReportAppResponse(member, price)) | ||
); | ||
return memberBillReportResponses; | ||
} | ||
} |
4 changes: 4 additions & 0 deletions
4
server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package server.haengdong.application.response; | ||
|
||
public record MemberBillReportAppResponse(String name, Long price) { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
server/src/main/java/server/haengdong/domain/action/MemberBillReports.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package server.haengdong.domain.action; | ||
|
||
import static java.util.stream.Collectors.toMap; | ||
|
||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.PriorityQueue; | ||
import java.util.Set; | ||
import java.util.function.Function; | ||
import lombok.Getter; | ||
|
||
@Getter | ||
public class MemberBillReports { | ||
|
||
private final Map<String, Long> reports; | ||
|
||
private MemberBillReports(Map<String, Long> reports) { | ||
this.reports = reports; | ||
} | ||
|
||
public static MemberBillReports createByActions(List<BillAction> billActions, List<MemberAction> memberActions) { | ||
PriorityQueue<BillAction> sortedBillActions = new PriorityQueue<>(billActions); | ||
PriorityQueue<MemberAction> sortedMemberActions = new PriorityQueue<>(memberActions); | ||
|
||
Map<String, Long> memberBillReports = initReports(memberActions); | ||
Set<String> currentMembers = new HashSet<>(); | ||
|
||
while (!sortedBillActions.isEmpty() && !sortedMemberActions.isEmpty()) { | ||
if (isMemberActionTurn(sortedMemberActions, sortedBillActions)) { | ||
addMemberAction(sortedMemberActions, currentMembers); | ||
continue; | ||
} | ||
addBillAction(sortedBillActions, currentMembers, memberBillReports); | ||
} | ||
|
||
while (!sortedBillActions.isEmpty()) { | ||
addBillAction(sortedBillActions, currentMembers, memberBillReports); | ||
} | ||
|
||
return new MemberBillReports(memberBillReports); | ||
} | ||
|
||
private static Map<String, Long> initReports(List<MemberAction> memberActions) { | ||
return memberActions.stream() | ||
.map(MemberAction::getMemberName) | ||
.distinct() | ||
.collect(toMap(Function.identity(), i -> 0L)); | ||
} | ||
|
||
private static boolean isMemberActionTurn( | ||
PriorityQueue<MemberAction> memberActions, | ||
PriorityQueue<BillAction> billActions | ||
) { | ||
MemberAction memberAction = memberActions.peek(); | ||
BillAction billAction = billActions.peek(); | ||
|
||
return memberAction.getSequence() < billAction.getSequence(); | ||
} | ||
|
||
private static void addMemberAction(PriorityQueue<MemberAction> sortedMemberActions, Set<String> currentMembers) { | ||
MemberAction memberAction = sortedMemberActions.poll(); | ||
String memberName = memberAction.getMemberName(); | ||
if (memberAction.isSameStatus(MemberActionStatus.IN)) { | ||
currentMembers.add(memberName); | ||
return; | ||
} | ||
currentMembers.remove(memberAction.getMemberName()); | ||
} | ||
|
||
private static void addBillAction( | ||
PriorityQueue<BillAction> sortedBillActions, | ||
Set<String> currentMembers, | ||
Map<String, Long> memberBillReports | ||
) { | ||
BillAction billAction = sortedBillActions.poll(); | ||
Long pricePerMember = billAction.getPrice() / currentMembers.size(); | ||
for (String currentMember : currentMembers) { | ||
Long price = memberBillReports.getOrDefault(currentMember, 0L) + pricePerMember; | ||
memberBillReports.put(currentMember, price); | ||
} | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
server/src/main/java/server/haengdong/presentation/ActionController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package server.haengdong.presentation; | ||
|
||
import java.util.List; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import server.haengdong.application.ActionService; | ||
import server.haengdong.application.response.MemberBillReportAppResponse; | ||
import server.haengdong.presentation.response.MemberBillReportsResponse; | ||
|
||
@RequiredArgsConstructor | ||
@RestController | ||
public class ActionController { | ||
|
||
private final ActionService actionService; | ||
|
||
@GetMapping("/api/events/{token}/actions/reports") | ||
public ResponseEntity<MemberBillReportsResponse> getMemberBillReports(@PathVariable("token") String token) { | ||
List<MemberBillReportAppResponse> memberBillReports = actionService.getMemberBillReports(token); | ||
|
||
return ResponseEntity.ok() | ||
.body(MemberBillReportsResponse.of(memberBillReports)); | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package server.haengdong.presentation.response; | ||
|
||
import server.haengdong.application.response.MemberBillReportAppResponse; | ||
|
||
public record MemberBillReportResponse(String name, Long price) { | ||
|
||
public static MemberBillReportResponse of(MemberBillReportAppResponse memberBillReportAppResponse) { | ||
return new MemberBillReportResponse(memberBillReportAppResponse.name(), memberBillReportAppResponse.price()); | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
server/src/main/java/server/haengdong/presentation/response/MemberBillReportsResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package server.haengdong.presentation.response; | ||
|
||
import java.util.List; | ||
import server.haengdong.application.response.MemberBillReportAppResponse; | ||
|
||
public record MemberBillReportsResponse(List<MemberBillReportResponse> reports) { | ||
|
||
public static MemberBillReportsResponse of(List<MemberBillReportAppResponse> memberBillReports) { | ||
List<MemberBillReportResponse> reports = memberBillReports.stream() | ||
.map(MemberBillReportResponse::of) | ||
.toList(); | ||
|
||
return new MemberBillReportsResponse(reports); | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
server/src/test/java/server/haengdong/application/ActionServiceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package server.haengdong.application; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.assertj.core.api.Assertions.tuple; | ||
import static server.haengdong.domain.action.MemberActionStatus.IN; | ||
import static server.haengdong.domain.action.MemberActionStatus.OUT; | ||
|
||
import java.util.List; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import server.haengdong.application.response.MemberBillReportAppResponse; | ||
import server.haengdong.domain.action.Action; | ||
import server.haengdong.domain.action.BillAction; | ||
import server.haengdong.domain.action.BillActionRepository; | ||
import server.haengdong.domain.action.MemberAction; | ||
import server.haengdong.domain.action.MemberActionRepository; | ||
import server.haengdong.domain.event.Event; | ||
import server.haengdong.domain.event.EventRepository; | ||
|
||
@SpringBootTest | ||
class ActionServiceTest { | ||
|
||
@Autowired | ||
private ActionService actionService; | ||
|
||
@Autowired | ||
private EventRepository eventRepository; | ||
|
||
@Autowired | ||
private BillActionRepository billActionRepository; | ||
|
||
@Autowired | ||
private MemberActionRepository memberActionRepository; | ||
|
||
@DisplayName("참여자별 정산 현황을 조회한다.") | ||
@Test | ||
void getMemberBillReports() { | ||
String token = "tOkEn1"; | ||
Event event = new Event("행동대장", token); | ||
Event savedEvent = eventRepository.save(event); | ||
List<MemberAction> memberActions = List.of( | ||
new MemberAction(new Action(savedEvent, 1L), "소하", IN, 1L), | ||
new MemberAction(new Action(savedEvent, 2L), "감자", IN, 1L), | ||
new MemberAction(new Action(savedEvent, 3L), "쿠키", IN, 1L), | ||
new MemberAction(new Action(savedEvent, 5L), "감자", OUT, 2L) | ||
); | ||
List<BillAction> billActions = List.of( | ||
new BillAction(new Action(savedEvent, 4L), "뽕족", 60_000L), | ||
new BillAction(new Action(savedEvent, 6L), "인생맥주", 40_000L), | ||
new BillAction(new Action(savedEvent, 7L), "인생네컷", 20_000L) | ||
); | ||
memberActionRepository.saveAll(memberActions); | ||
billActionRepository.saveAll(billActions); | ||
|
||
List<MemberBillReportAppResponse> responses = actionService.getMemberBillReports(token); | ||
|
||
assertThat(responses) | ||
.hasSize(3) | ||
.extracting(MemberBillReportAppResponse::name, MemberBillReportAppResponse::price) | ||
.containsExactlyInAnyOrder( | ||
tuple("감자", 20_000L), | ||
tuple("쿠키", 50_000L), | ||
tuple("소하", 50_000L) | ||
); | ||
} | ||
} |
43 changes: 43 additions & 0 deletions
43
server/src/test/java/server/haengdong/domain/action/MemberBillReportsTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package server.haengdong.domain.action; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static server.haengdong.domain.action.MemberActionStatus.IN; | ||
import static server.haengdong.domain.action.MemberActionStatus.OUT; | ||
|
||
import java.util.List; | ||
import java.util.Map; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import server.haengdong.domain.event.Event; | ||
|
||
class MemberBillReportsTest { | ||
|
||
@DisplayName("액션 목록으로 참가자 정산 리포트를 생성한다.") | ||
@Test | ||
void createByActions() { | ||
String token = "TOK2N"; | ||
Event event = new Event("행동대장", token); | ||
List<BillAction> billActions = List.of( | ||
new BillAction(new Action(event, 4L), "뽕족", 60_000L), | ||
new BillAction(new Action(event, 6L), "인생맥주", 40_000L), | ||
new BillAction(new Action(event, 7L), "인생네컷", 20_000L) | ||
); | ||
List<MemberAction> memberActions = List.of( | ||
new MemberAction(new Action(event, 1L), "소하", IN, 1L), | ||
new MemberAction(new Action(event, 2L), "감자", IN, 1L), | ||
new MemberAction(new Action(event, 3L), "쿠키", IN, 1L), | ||
new MemberAction(new Action(event, 5L), "감자", OUT, 2L) | ||
); | ||
|
||
MemberBillReports memberBillReports = MemberBillReports.createByActions(billActions, memberActions); | ||
|
||
assertThat(memberBillReports.getReports()) | ||
.containsAllEntriesOf( | ||
Map.of( | ||
"감자", 20_000L, | ||
"쿠키", 50_000L, | ||
"소하", 50_000L | ||
) | ||
); | ||
} | ||
} |
49 changes: 49 additions & 0 deletions
49
server/src/test/java/server/haengdong/presentation/ActionControllerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package server.haengdong.presentation; | ||
|
||
import static org.hamcrest.Matchers.equalTo; | ||
import static org.mockito.ArgumentMatchers.any; | ||
import static org.mockito.BDDMockito.given; | ||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||
|
||
import java.util.List; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; | ||
import org.springframework.boot.test.mock.mockito.MockBean; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.test.web.servlet.MockMvc; | ||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers; | ||
import server.haengdong.application.ActionService; | ||
import server.haengdong.application.response.MemberBillReportAppResponse; | ||
|
||
@WebMvcTest(ActionController.class) | ||
class ActionControllerTest { | ||
|
||
@Autowired | ||
private MockMvc mockMvc; | ||
|
||
@MockBean | ||
private ActionService actionService; | ||
|
||
@DisplayName("참여자별 정산 현황을 조회한다.") | ||
@Test | ||
void getMemberBillReports() throws Exception { | ||
List<MemberBillReportAppResponse> memberBillReportAppResponses = List.of( | ||
new MemberBillReportAppResponse("소하", 20_000L), new MemberBillReportAppResponse("토다리", 200_000L)); | ||
|
||
given(actionService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); | ||
|
||
mockMvc.perform(get("/api/events/{token}/actions/reports", "token") | ||
.accept(MediaType.APPLICATION_JSON)) | ||
.andDo(print()) | ||
.andExpect(status().isOk()) | ||
.andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].name").value(equalTo("소하"))) | ||
.andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].price").value(equalTo(20_000))) | ||
.andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].name").value(equalTo("토다리"))) | ||
.andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].price").value(equalTo(200_000))); | ||
|
||
} | ||
} |