Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@
import com.dnd.moddo.event.application.impl.ExpenseReader;
import com.dnd.moddo.event.application.impl.MemberExpenseReader;
import com.dnd.moddo.event.application.impl.MemberReader;
import com.dnd.moddo.event.application.impl.PaymentRequestReader;
import com.dnd.moddo.event.application.impl.SettlementReader;
import com.dnd.moddo.event.domain.expense.Expense;
import com.dnd.moddo.event.domain.member.Member;
import com.dnd.moddo.event.domain.memberExpense.MemberExpense;
import com.dnd.moddo.event.domain.settlement.Settlement;
import com.dnd.moddo.event.presentation.response.MemberExpenseDetailResponse;
import com.dnd.moddo.event.presentation.response.MemberExpenseItemResponse;
import com.dnd.moddo.event.presentation.response.MemberExpenseResponse;
Expand All @@ -28,6 +31,8 @@ public class QueryMemberExpenseService {
private final MemberExpenseReader memberExpenseReader;
private final MemberReader memberReader;
private final ExpenseReader expenseReader;
private final SettlementReader settlementReader;
private final PaymentRequestReader paymentRequestReader;

public List<MemberExpenseResponse> findAllByExpenseId(
Long expenseId) {
Expand All @@ -37,7 +42,12 @@ public List<MemberExpenseResponse> findAllByExpenseId(
.toList();
}

public MembersExpenseResponse findMemberExpenseDetailsBySettlementId(Long settlementId) {
public MembersExpenseResponse findMemberExpenseDetailsBySettlementId(Long settlementId, Long userId) {
Settlement settlement = settlementReader.read(settlementId);
Map<Long, Long> paymentRequestIdByMemberId = settlement.isWriter(userId)
? paymentRequestReader.findPendingRequestIdByMemberId(settlementId)
: Map.of();

List<Member> members = memberReader.findAllBySettlementId(settlementId);

Map<Long, Member> appointmentMemberById = convertAppointmentMembersToMap(members);
Expand All @@ -55,7 +65,8 @@ public MembersExpenseResponse findMemberExpenseDetailsBySettlementId(Long settle
.map(
key -> findMemberExpenseDetailByAppointmentMember(appointmentMemberById.get(key),
memberExpenses.get(key),
expenses)
expenses,
paymentRequestIdByMemberId)
)
.filter(Objects::nonNull)
.toList();
Expand All @@ -72,16 +83,19 @@ private Map<Long, Member> convertAppointmentMembersToMap(List<Member> members) {
}

private MemberExpenseItemResponse findMemberExpenseDetailByAppointmentMember(
Member member, List<MemberExpense> memberExpenses, List<Expense> expenses) {
Member member, List<MemberExpense> memberExpenses, List<Expense> expenses,
Map<Long, Long> paymentRequestIdByMemberId) {

Long paymentRequestId = paymentRequestIdByMemberId.get(member.getId());

if (memberExpenses == null) {
return MemberExpenseItemResponse.of(member, 0L, new ArrayList<>());
return MemberExpenseItemResponse.of(member, 0L, new ArrayList<>(), paymentRequestId);
}

List<MemberExpenseDetailResponse> memberExpenseDetails = mapToMemberExpenseDetails(memberExpenses, expenses);
Long totalAmount = calculateTotalAmount(memberExpenses);

return MemberExpenseItemResponse.of(member, totalAmount, memberExpenseDetails);
return MemberExpenseItemResponse.of(member, totalAmount, memberExpenseDetails, paymentRequestId);
}

private Long calculateTotalAmount(List<MemberExpense> memberExpenses) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.dnd.moddo.auth.infrastructure.security.LoginUser;
import com.dnd.moddo.auth.presentation.response.LoginUserInfo;
import com.dnd.moddo.event.application.query.QueryMemberExpenseService;
import com.dnd.moddo.event.application.query.QuerySettlementService;
import com.dnd.moddo.event.presentation.response.MembersExpenseResponse;
Expand All @@ -22,13 +24,14 @@ public class MemberExpenseController {

@GetMapping
public ResponseEntity<MembersExpenseResponse> getMemberExpensesDetails(
@PathVariable String code
@PathVariable String code,
@LoginUser LoginUserInfo loginUser
) {
Long settlementId = querySettlementService.findIdByCode(code);

MembersExpenseResponse response =
queryMemberExpenseService.findMemberExpenseDetailsBySettlementId(settlementId);
queryMemberExpenseService.findMemberExpenseDetailsBySettlementId(settlementId, loginUser.userId());

return ResponseEntity.ok(response);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ public record MemberExpenseItemResponse(
String profile,
boolean isPaid,
LocalDateTime paidAt,
Long paymentRequestId,
List<MemberExpenseDetailResponse> expenses
) {
public static MemberExpenseItemResponse of(Member member, Long totalAmount,
List<MemberExpenseDetailResponse> expenses) {
List<MemberExpenseDetailResponse> expenses, Long paymentRequestId) {
return MemberExpenseItemResponse.builder()
.id(member.getId())
.role(member.getRole())
Expand All @@ -29,6 +30,7 @@ public static MemberExpenseItemResponse of(Member member, Long totalAmount,
.profile(member.getProfileUrl())
.isPaid(member.isPaid())
.paidAt(member.getPaidAt())
.paymentRequestId(paymentRequestId)
.expenses(expenses).build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;

import com.dnd.moddo.auth.presentation.response.LoginUserInfo;
import com.dnd.moddo.event.presentation.response.MemberExpenseDetailResponse;
import com.dnd.moddo.event.presentation.response.MemberExpenseItemResponse;
import com.dnd.moddo.event.presentation.response.MembersExpenseResponse;
Expand All @@ -30,26 +31,31 @@ void getMemberExpensesDetailsSuccess() throws Exception {
List.of(
new MemberExpenseItemResponse(1L, MANAGER, "김모또", 10000L,
"https://moddo-s3.s3.amazonaws.com/profile/MODDO.png", true, LocalDateTime.now(),
List.of(new MemberExpenseDetailResponse("카페", 10000L))
null, List.of(new MemberExpenseDetailResponse("카페", 10000L))
),
new MemberExpenseItemResponse(2L, PARTICIPANT, "군계란", 10000L,
"https://moddo-s3.s3.amazonaws.com/profile/1.png", false, null,
List.of(new MemberExpenseDetailResponse("카페", 10000L))
100L, List.of(new MemberExpenseDetailResponse("카페", 10000L))
)
)
);

when(loginUserArgumentResolver.supportsParameter(any()))
.thenReturn(true);
when(loginUserArgumentResolver.resolveArgument(any(), any(), any(), any()))
.thenReturn(new LoginUserInfo(1L, "USER"));
when(querySettlementService.findIdByCode(code)).thenReturn(groupId);
when(queryMemberExpenseService.findMemberExpenseDetailsBySettlementId(groupId)).thenReturn(
when(queryMemberExpenseService.findMemberExpenseDetailsBySettlementId(groupId, 1L)).thenReturn(
membersExpenseResponse);

// when & then
mockMvc.perform(get("/api/v1/groups/{code}/member-expenses", code)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.memberExpenses").isArray());
.andExpect(jsonPath("$.memberExpenses").isArray())
.andExpect(jsonPath("$.memberExpenses[1].paymentRequestId").value(100L));

verify(querySettlementService, times(1)).findIdByCode(code);
verify(queryMemberExpenseService, times(1)).findMemberExpenseDetailsBySettlementId(groupId);
verify(queryMemberExpenseService, times(1)).findMemberExpenseDetailsBySettlementId(groupId, 1L);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

Expand All @@ -17,6 +18,8 @@
import com.dnd.moddo.event.application.impl.ExpenseReader;
import com.dnd.moddo.event.application.impl.MemberExpenseReader;
import com.dnd.moddo.event.application.impl.MemberReader;
import com.dnd.moddo.event.application.impl.PaymentRequestReader;
import com.dnd.moddo.event.application.impl.SettlementReader;
import com.dnd.moddo.event.application.query.QueryMemberExpenseService;
import com.dnd.moddo.event.domain.expense.Expense;
import com.dnd.moddo.event.domain.member.ExpenseRole;
Expand All @@ -25,16 +28,22 @@
import com.dnd.moddo.event.domain.settlement.Settlement;
import com.dnd.moddo.event.presentation.response.MemberExpenseResponse;
import com.dnd.moddo.event.presentation.response.MembersExpenseResponse;
import com.dnd.moddo.global.support.GroupTestFactory;

@ExtendWith(MockitoExtension.class)
class QueryMemberExpenseServiceTest {
private static final Long MANAGER_USER_ID = 1L;
private static final Long PARTICIPANT_USER_ID = 2L;

@Mock
private MemberExpenseReader memberExpenseReader;
@Mock
private ExpenseReader expenseReader;
@Mock
private MemberReader memberReader;
@Mock
private SettlementReader settlementReader;
@Mock
private PaymentRequestReader paymentRequestReader;
@InjectMocks
private QueryMemberExpenseService queryMemberExpenseService;

Expand All @@ -44,7 +53,7 @@ class QueryMemberExpenseServiceTest {

@BeforeEach
void setUp() {
mockSettlement = GroupTestFactory.createDefault();
mockSettlement = createSettlementWithWriter(MANAGER_USER_ID);

mockMember1 = Member.builder()
.name("김모또")
Expand Down Expand Up @@ -91,6 +100,7 @@ void findAllByExpenseId() {
void findMemberExpenseDetailsBySettlementId_Success() {
//given
Long groupId = 1L;
Long userId = MANAGER_USER_ID;
Member member1 = mock(Member.class);
Member member2 = mock(Member.class);

Expand All @@ -114,24 +124,58 @@ void findMemberExpenseDetailsBySettlementId_Success() {
when(expense1.getId()).thenReturn(1L);
when(expense2.getId()).thenReturn(2L);

when(settlementReader.read(groupId)).thenReturn(mockSettlement);
when(paymentRequestReader.findPendingRequestIdByMemberId(groupId)).thenReturn(Map.of(2L, 100L));
Comment thread
coderabbitai[bot] marked this conversation as resolved.
when(memberReader.findAllBySettlementId(eq(groupId))).thenReturn(members);
when(memberExpenseReader.findAllByAppointMemberIds(List.of(1L, 2L)))
.thenReturn(List.of(memberExpense1, memberExpense2));
when(expenseReader.findAllBySettlementId(any())).thenReturn(List.of(expense1, expense2));

// when
MembersExpenseResponse response = queryMemberExpenseService.findMemberExpenseDetailsBySettlementId(
groupId);
groupId, userId);

// then
assertThat(response).isNotNull();
assertThat(response.memberExpenses()).hasSize(2);
assertThat(response.memberExpenses().get(0).paymentRequestId()).isNull();
assertThat(response.memberExpenses().get(1).paymentRequestId()).isEqualTo(100L);

verify(settlementReader, times(1)).read(groupId);
verify(paymentRequestReader, times(1)).findPendingRequestIdByMemberId(groupId);
verify(memberReader, times(1)).findAllBySettlementId(groupId);
verify(memberExpenseReader, times(1)).findAllByAppointMemberIds(anyList());
verify(expenseReader, times(1)).findAllBySettlementId(groupId);
}

@DisplayName("총무가 아닐 때 참여자별 정산내역 조회 시 입금 확인 요청 ID를 조회하지 않는다.")
@Test
void findMemberExpenseDetailsBySettlementId_Success_WhenNotManager() {
//given
Long groupId = 1L;
Long userId = PARTICIPANT_USER_ID;
Member member = mock(Member.class);

when(member.getId()).thenReturn(1L);
when(settlementReader.read(groupId)).thenReturn(mockSettlement);
when(memberReader.findAllBySettlementId(eq(groupId))).thenReturn(List.of(member));
when(memberExpenseReader.findAllByAppointMemberIds(List.of(1L))).thenReturn(List.of());
when(expenseReader.findAllBySettlementId(groupId)).thenReturn(List.of());

// when
MembersExpenseResponse response = queryMemberExpenseService.findMemberExpenseDetailsBySettlementId(
groupId, userId);

// then
assertThat(response).isNotNull();
assertThat(response.memberExpenses()).hasSize(1);
assertThat(response.memberExpenses().get(0).paymentRequestId()).isNull();

verify(settlementReader, times(1)).read(groupId);
verify(paymentRequestReader, never()).findPendingRequestIdByMemberId(anyLong());
verify(memberReader, times(1)).findAllBySettlementId(groupId);
}

@DisplayName("지출내역 id를 통해 참여자 지출내역을 찾아 지출내역 id에 해당하는 참여자 이름들을 map으로 조회할 수 있다.")
@Test
void getMemberNamesByExpenseIds_Success() {
Expand Down Expand Up @@ -168,4 +212,16 @@ void getMemberNamesByExpenseIds_Success() {

verify(memberExpenseReader, times(1)).findAllByExpenseIds(eq(expenseIds));
}

private Settlement createSettlementWithWriter(Long writerId) {
return new Settlement(
"group 1",
writerId,
LocalDateTime.now().plusMinutes(1),
"은행",
"계좌",
"code",
LocalDateTime.now().plusDays(1)
);
}
}
Loading