diff --git a/server/src/docs/asciidoc/billAction.adoc b/server/src/docs/asciidoc/bill.adoc similarity index 77% rename from server/src/docs/asciidoc/billAction.adoc rename to server/src/docs/asciidoc/bill.adoc index dfd7e26db..db77542aa 100644 --- a/server/src/docs/asciidoc/billAction.adoc +++ b/server/src/docs/asciidoc/bill.adoc @@ -1,8 +1,8 @@ -== 지출 액션 +== 지출 -=== 지출 액션 생성 +=== 지출 생성 -operation::createBillActions[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] +operation::createBills[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] ==== [.red]#Exceptions# @@ -18,11 +18,11 @@ operation::createBillActions[snippets="path-parameters,http-request,request-body "message":"지출 내역은 비어 있으면 안됩니다." }, { - "code":"BILL_ACTION_TITLE_INVALID", + "code":"BILL_TITLE_INVALID", "message":"앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다." }, { - "code":"BILL_ACTION_PRICE_INVALID", + "code":"BILL_PRICE_INVALID", "message":"지출 금액은 10,000,000 이하의 자연수여야 합니다." }, { @@ -44,9 +44,9 @@ operation::createBillActions[snippets="path-parameters,http-request,request-body ] ---- -=== 지출 액션 수정 +=== 지출 수정 -operation::updateBillAction[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] +operation::updateBill[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] ==== [.red]#Exceptions# @@ -62,11 +62,11 @@ operation::updateBillAction[snippets="path-parameters,http-request,request-body, "message":"지출 금액은 공백일 수 없습니다." }, { - "code":"BILL_ACTION_TITLE_INVALID", + "code":"BILL_TITLE_INVALID", "message":"앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다." }, { - "code":"BILL_ACTION_PRICE_INVALID", + "code":"BILL_PRICE_INVALID", "message":"지출 금액은 %,d 이하의 자연수여야 합니다." }, { @@ -74,7 +74,7 @@ operation::updateBillAction[snippets="path-parameters,http-request,request-body, "message":"존재하지 않는 행사입니다." }, { - "code":"BILL_ACTION_NOT_FOUND", + "code":"BILL_NOT_FOUND", "message":"존재하지 않는 지출 액션입니다." }, { @@ -92,9 +92,9 @@ operation::updateBillAction[snippets="path-parameters,http-request,request-body, ] ---- -=== 지출 액션 삭제 +=== 지출 삭제 -operation::deleteBillAction[snippets="path-parameters,http-request,http-response,request-cookies"] +operation::deleteBill[snippets="path-parameters,http-request,http-response,request-cookies"] ==== [.red]#Exceptions# diff --git a/server/src/docs/asciidoc/billActionDetail.adoc b/server/src/docs/asciidoc/billDetail.adoc similarity index 78% rename from server/src/docs/asciidoc/billActionDetail.adoc rename to server/src/docs/asciidoc/billDetail.adoc index a8f19f21b..9c9cf7ff5 100644 --- a/server/src/docs/asciidoc/billActionDetail.adoc +++ b/server/src/docs/asciidoc/billDetail.adoc @@ -2,7 +2,7 @@ === 지출 상세 조회 -operation::findBillActionDetailsTest[snippets="path-parameters,http-request,http-response,request-cookies"] +operation::findBillDetails[snippets="path-parameters,http-request,http-response,request-cookies"] ==== [.red]#Exceptions# @@ -14,11 +14,11 @@ operation::findBillActionDetailsTest[snippets="path-parameters,http-request,http "message": "존재하지 않는 행사입니다." }, { - "code": "BILL_ACTION_NOT_FOUND", + "code": "BILL_NOT_FOUND", "message": "존재하지 않는 지출 액션입니다." }, { - "code": "BILL_ACTION_DETAIL_NOT_FOUND", + "code": "BILL_DETAIL_NOT_FOUND", "message": "존재하지 않는 참여자 지출입니다." }, { @@ -42,7 +42,7 @@ operation::findBillActionDetailsTest[snippets="path-parameters,http-request,http === 지출 상세 수정 -operation::updateBillActionDetailsTest[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] +operation::updateBillDetails[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] ==== [.red]#Exceptions# @@ -62,15 +62,15 @@ operation::updateBillActionDetailsTest[snippets="path-parameters,http-request,re "message": "존재하지 않는 행사입니다." }, { - "code": "BILL_ACTION_NOT_FOUND", + "code": "BILL_NOT_FOUND", "message": "존재하지 않는 지출 액션입니다." }, { - "code": "BILL_ACTION_DETAIL_NOT_FOUND", + "code": "BILL_DETAIL_NOT_FOUND", "message": "존재하지 않는 참여자 지출입니다." }, { - "code": "BILL_ACTION_PRICE_NOT_MATCHED", + "code": "BILL_PRICE_NOT_MATCHED", "message": "지출 총액이 일치하지 않습니다." }, { diff --git a/server/src/docs/asciidoc/event.adoc b/server/src/docs/asciidoc/event.adoc index 72511b91b..10b165282 100644 --- a/server/src/docs/asciidoc/event.adoc +++ b/server/src/docs/asciidoc/event.adoc @@ -68,7 +68,7 @@ operation::getEvent[snippets="path-parameters,http-request,response-body,respons === 행사 전체 참여자 목록 조회 -operation::findAllEventMember[snippets="path-parameters,http-request,response-body,response-fields,http-response,response-fields"] +operation::findAllMembers[snippets="path-parameters,http-request,response-body,response-fields,http-response,response-fields"] ==== [.red]#Exceptions# @@ -82,9 +82,9 @@ operation::findAllEventMember[snippets="path-parameters,http-request,response-bo ] ---- -=== 행사 전체 액션 이력 조회 +=== 행사 전체 지출 이력 조회 -operation::findActions[snippets="path-parameters,http-request,http-response,response-fields"] +operation::findBills[snippets="path-parameters,http-request,http-response,response-fields"] ==== [.red]#Exceptions# @@ -98,9 +98,9 @@ operation::findActions[snippets="path-parameters,http-request,http-response,resp ] ---- -=== 행사 참여자 이름 변경 +=== 행사 참여자 정보 변경 -operation::updateEventMemberName[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] +operation::updateMembers[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] ==== [.red]#Exceptions# [source,json,options="nowrap"] @@ -146,9 +146,9 @@ operation::updateEventMemberName[snippets="path-parameters,http-request,request- ] ---- -=== 행사 참여자 삭제 (특정 참여자의 모든 참여자 액션 삭제) +=== 행사 참여자 삭제 -operation::deleteAllMemberActionByName[snippets="path-parameters,http-request,http-response,request-cookies"] +operation::deleteMember[snippets="path-parameters,http-request,http-response,request-cookies"] ==== [.red]#Exceptions# [source,json,options="nowrap"] diff --git a/server/src/docs/asciidoc/index.adoc b/server/src/docs/asciidoc/index.adoc index 8e1bcd2d0..4dcc2dc26 100644 --- a/server/src/docs/asciidoc/index.adoc +++ b/server/src/docs/asciidoc/index.adoc @@ -10,6 +10,6 @@ endif::[] include::{docdir}/event.adoc[] include::{docdir}/memberBillReport.adoc[] -include::{docdir}/memberAction.adoc[] -include::{docdir}/billAction.adoc[] -include::{docdir}/billActionDetail.adoc[] +include::{docdir}/member.adoc[] +include::{docdir}/bill.adoc[] +include::{docdir}/billDetail.adoc[] diff --git a/server/src/docs/asciidoc/member.adoc b/server/src/docs/asciidoc/member.adoc new file mode 100644 index 000000000..230db1906 --- /dev/null +++ b/server/src/docs/asciidoc/member.adoc @@ -0,0 +1,152 @@ +== 참여자 + +=== 행사 참여자 추가(멤버 추가) + +operation::saveMembers[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"REQUEST_EMPTY", + "message":"멤버 목록은 공백일 수 없습니다." + }, + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"MEMBER_ALREADY_EXIST", + "message":"현재 참여하고 있는 인원이 존재합니다." + }, + { + "code":"MEMBER_NAME_DUPLICATE", + "message":"중복된 이름이 존재합니다. 입력된 이름: [이상, 이상, 감자, 백호]" + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"만료된 토큰입니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + }, + { + "code":"FORBIDDEN", + "message":"접근할 수 없는 행사입니다." + } +] +---- + +=== 행사 참여 인원에서 삭제(멤버 삭제) + +operation::deleteMember[snippets="path-parameters,http-request,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"만료된 토큰입니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + }, + { + "code":"FORBIDDEN", + "message":"접근할 수 없는 행사입니다." + } +] +---- + +=== 멤버 정보 수정 + +operation::updateMembers[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] + +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code": "REQUEST_EMPTY", + "message": "멤버 ID는 공백일 수 없습니다." + }, + { + "code": "REQUEST_EMPTY", + "message": "입금 여부는 공백일 수 없습니다." + }, + { + "code": "REQUEST_EMPTY", + "message": "멤버 이름은 공백일 수 없습니다." + }, + { + "code": "MEMBER_NAME_LENGTH_INVALID", + "message": "멤버 이름은 1자 이상 4자 이하만 입력 가능합니다." + }, + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + }, + { + "code": "MEMBER_NOT_FOUND", + "message": "존재하지 않는 참여자입니다." + }, + { + "code": "MEMBER_NAME_DUPLICATE", + "message": "중복된 행사 참여 인원 이름이 존재합니다." + }, + { + "code": "MEMBER_NAME_CHANGE_DUPLICATE", + "message": "중복된 참여 인원 이름 변경 요청이 존재합니다." + }, + { + "code":"TOKEN_NOT_FOUND", + "message":"토큰이 존재하지 않습니다." + }, + { + "code":"TOKEN_EXPIRED", + "message":"만료된 토큰입니다." + }, + { + "code":"TOKEN_INVALID", + "message":"유효하지 않은 토큰입니다." + }, + { + "code":"FORBIDDEN", + "message":"접근할 수 없는 행사입니다." + } +] +---- + +=== 현재 행사에 참여 중인 (탈주 가능한) 참여자 목록 조회 + +operation::getCurrentMembers[snippets="path-parameters,http-request,http-response,response-fields"] +==== [.red]#Exceptions# + +[source,json,options="nowrap"] +---- +[ + { + "code":"EVENT_NOT_FOUND", + "message":"존재하지 않는 행사입니다." + } +] +---- diff --git a/server/src/docs/asciidoc/memberAction.adoc b/server/src/docs/asciidoc/memberAction.adoc deleted file mode 100644 index 897102c8d..000000000 --- a/server/src/docs/asciidoc/memberAction.adoc +++ /dev/null @@ -1,100 +0,0 @@ -== 참여자 액션 - -=== 참여자 액션 생성 - -operation::createMemberAction[snippets="path-parameters,http-request,request-body,request-fields,http-response,request-cookies"] - -==== [.red]#Exceptions# - -[source,json,options="nowrap"] ----- -[ - { - "code":"REQUEST_EMPTY", - "message":"멤버 액션은 공백일 수 없습니다." - }, - { - "code":"EVENT_NOT_FOUND", - "message":"존재하지 않는 행사입니다." - }, - { - "code":"MEMBER_ACTION_STATUS_INVALID", - "message":"멤버 액션은 IN, OUT만 가능합니다. 입력한 멤버 액션: I_N" - }, - { - "code":"MEMBER_ALREADY_EXIST", - "message":"현재 참여하고 있는 인원이 존재합니다." - }, - { - "code":"MEMBER_NOT_EXIST", - "message":"현재 참여하고 있지 않는 인원이 존재합니다." - }, - { - "code":"MEMBER_NAME_DUPLICATE", - "message":"중복된 이름이 존재합니다. 입력된 이름: 이상, 이상, 감자, 백호" - }, - { - "code":"TOKEN_NOT_FOUND", - "message":"토큰이 존재하지 않습니다." - }, - { - "code":"TOKEN_EXPIRED", - "message":"토큰이 존재하지 않습니다." - }, - { - "code":"TOKEN_INVALID", - "message":"유효하지 않은 토큰입니다." - } -] ----- - -=== 현재 행사에 참여 중인 (탈주 가능한) 참여자 목록 조회 - -operation::getCurrentMembers[snippets="path-parameters,http-request,http-response,response-fields"] -==== [.red]#Exceptions# - -[source,json,options="nowrap"] ----- -[ - { - "code":"EVENT_NOT_FOUND", - "message":"존재하지 않는 행사입니다." - } -] ----- - -=== 참여자 액션 삭제 - -operation::deleteMemberAction[snippets="path-parameters,http-request,http-response,request-cookies"] - -==== [.red]#Exceptions# - -[source,json,options="nowrap"] ----- -[ - { - "code":"EVENT_NOT_FOUND", - "message":"존재하지 않는 행사입니다." - }, - { - "code":"ACTION_NOT_FOUND", - "message":"존재하지 않는 액션입니다." - }, - { - "code":"MEMBER_ACTION_NOT_FOUND", - "message":"존재하지 않는 멤버 액션입니다." - }, - { - "code":"TOKEN_NOT_FOUND", - "message":"토큰이 존재하지 않습니다." - }, - { - "code":"TOKEN_EXPIRED", - "message":"토큰이 존재하지 않습니다." - }, - { - "code":"TOKEN_INVALID", - "message":"유효하지 않은 토큰입니다." - } -] ----- diff --git a/server/src/main/java/server/haengdong/application/BillActionDetailService.java b/server/src/main/java/server/haengdong/application/BillActionDetailService.java deleted file mode 100644 index a4372c62d..000000000 --- a/server/src/main/java/server/haengdong/application/BillActionDetailService.java +++ /dev/null @@ -1,78 +0,0 @@ -package server.haengdong.application; - -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import server.haengdong.application.request.BillActionDetailUpdateAppRequest; -import server.haengdong.application.request.BillActionDetailsUpdateAppRequest; -import server.haengdong.application.response.BillActionDetailsAppResponse; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.BillActionDetail; -import server.haengdong.domain.action.BillActionRepository; -import server.haengdong.domain.event.Event; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@RequiredArgsConstructor -@Transactional(readOnly = true) -@Service -public class BillActionDetailService { - - private final BillActionRepository billActionRepository; - - public BillActionDetailsAppResponse findBillActionDetails(String token, Long billActionId) { - BillAction billAction = billActionRepository.findById(billActionId) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); - validateToken(token, billAction); - - List billActionDetails = billAction.getBillActionDetails(); - return BillActionDetailsAppResponse.of(billActionDetails); - } - - @Transactional - public void updateBillActionDetails(String token, Long billActionId, BillActionDetailsUpdateAppRequest request) { - BillAction billAction = billActionRepository.findById(billActionId) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); - - List billActionDetailUpdateAppRequests = request.billActionDetailUpdateAppRequests(); - - validateToken(token, billAction); - validateTotalPrice(billActionDetailUpdateAppRequests, billAction); - - List billActionDetails = billAction.getBillActionDetails(); - - for (BillActionDetailUpdateAppRequest updateRequest : billActionDetailUpdateAppRequests) { - BillActionDetail detailToUpdate = billActionDetails.stream() - .filter(detail -> detail.isSameName(updateRequest.name())) - .findFirst() - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_DETAIL_NOT_FOUND)); - - detailToUpdate.updatePrice(updateRequest.price()); - detailToUpdate.updateIsFixed(updateRequest.isFixed()); - } - } - - private void validateToken(String token, BillAction billAction) { - Event event = billAction.getEvent(); - if (event.isTokenMismatch(token)) { - throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND); - } - } - - private void validateTotalPrice( - List billActionDetailUpdateAppRequests, - BillAction billAction - ) { - Long requestsPriceSum = calculateUpdatePriceSum(billActionDetailUpdateAppRequests); - if (!billAction.isSamePrice(requestsPriceSum)) { - throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_PRICE_NOT_MATCHED); - } - } - - private Long calculateUpdatePriceSum(List billActionDetailUpdateAppRequests) { - return billActionDetailUpdateAppRequests.stream() - .map(BillActionDetailUpdateAppRequest::price) - .reduce(0L, Long::sum); - } -} diff --git a/server/src/main/java/server/haengdong/application/BillActionService.java b/server/src/main/java/server/haengdong/application/BillActionService.java deleted file mode 100644 index 9453a2d5f..000000000 --- a/server/src/main/java/server/haengdong/application/BillActionService.java +++ /dev/null @@ -1,85 +0,0 @@ -package server.haengdong.application; - -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import server.haengdong.application.request.BillActionAppRequest; -import server.haengdong.application.request.BillActionUpdateAppRequest; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.BillActionRepository; -import server.haengdong.domain.action.CurrentMembers; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.action.Sequence; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@RequiredArgsConstructor -@Transactional(readOnly = true) -@Service -public class BillActionService { - - private final BillActionRepository billActionRepository; - private final MemberActionRepository memberActionRepository; - private final EventRepository eventRepository; - - @Transactional - public void saveAllBillAction(String eventToken, List requests) { - Event event = getEvent(eventToken); - Sequence sequence = createStartSequence(event); - List findMemberActions = memberActionRepository.findAllByEvent(event); - CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); - - for (BillActionAppRequest request : requests) { - BillAction billAction = request.toBillAction(event, sequence, currentMembers); - billActionRepository.save(billAction); - sequence = sequence.next(); - } - } - - private Sequence createStartSequence(Event event) { - Sequence memberActionSequence = memberActionRepository.findLastByEvent(event) - .map(MemberAction::getSequence) - .orElseGet(Sequence::createFirst); - Sequence billActionSequence = billActionRepository.findLastByEvent(event) - .map(BillAction::getSequence) - .orElseGet(Sequence::createFirst); - return Sequence.getGreater(memberActionSequence, billActionSequence).next(); - } - - @Transactional - public void updateBillAction(String token, Long billActionId, BillActionUpdateAppRequest request) { - BillAction billAction = getBillAction(billActionId); - - validateToken(token, billAction); - - billAction.update(request.title(), request.price()); - } - - private void validateToken(String token, BillAction billAction) { - Event event = billAction.getEvent(); - if (event.isTokenMismatch(token)) { - throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND); - } - } - - @Transactional - public void deleteBillAction(String token, Long billActionId) { - BillAction billAction = getBillAction(billActionId); - validateToken(token, billAction); - billActionRepository.deleteById(billActionId); - } - - private Event getEvent(String eventToken) { - return eventRepository.findByToken(eventToken) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); - } - - private BillAction getBillAction(Long billActionId) { - return billActionRepository.findById(billActionId) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_ACTION_NOT_FOUND)); - } -} diff --git a/server/src/main/java/server/haengdong/application/BillService.java b/server/src/main/java/server/haengdong/application/BillService.java new file mode 100644 index 000000000..407914d29 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/BillService.java @@ -0,0 +1,155 @@ +package server.haengdong.application; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.BillAppRequest; +import server.haengdong.application.request.BillDetailUpdateAppRequest; +import server.haengdong.application.request.BillDetailsUpdateAppRequest; +import server.haengdong.application.request.BillUpdateAppRequest; +import server.haengdong.application.response.BillDetailsAppResponse; +import server.haengdong.application.response.StepAppResponse; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.bill.BillDetail; +import server.haengdong.domain.bill.BillRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.member.Member; +import server.haengdong.domain.member.MemberRepository; +import server.haengdong.domain.step.Steps; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class BillService { + + private final BillRepository billRepository; + private final EventRepository eventRepository; + private final MemberRepository memberRepository; + + @Transactional + public void saveBill(String eventToken, BillAppRequest request) { + Event event = getEvent(eventToken); + List memberIds = request.memberIds(); + List members = memberIds.stream() + .map(this::findMember) + .toList(); + + Bill bill = request.toBill(event, members); + billRepository.save(bill); + } + + private Member findMember(Long memberId) { + return memberRepository.findById(memberId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_NOT_FOUND)); + } + + public List findSteps(String token) { + Event event = getEvent(token); + List bills = billRepository.findAllByEvent(event); + + return createStepAppResponses(bills); + } + + private List createStepAppResponses(List bills) { + Steps steps = Steps.of(bills); + return steps.getSteps().stream() + .map(StepAppResponse::of) + .toList(); + } + + @Transactional + public void updateBill(String token, Long billId, BillUpdateAppRequest request) { + Bill bill = getBill(billId); + + validateToken(token, bill); + + bill.update(request.title(), request.price()); + } + + private void validateToken(String token, Bill bill) { + Event event = bill.getEvent(); + if (event.isTokenMismatch(token)) { + throw new HaengdongException(HaengdongErrorCode.BILL_NOT_FOUND); + } + } + + @Transactional + public void deleteBill(String token, Long billId) { + Bill bill = getBill(billId); + validateToken(token, bill); + billRepository.deleteById(billId); + } + + public BillDetailsAppResponse findBillDetails(String token, Long billId) { + Bill bill = billRepository.findById(billId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_NOT_FOUND)); + validateToken(token, bill); + + List billDetails = bill.getBillDetails(); + return BillDetailsAppResponse.of(billDetails); + } + + @Transactional + public void updateBillDetails(String token, Long billId, BillDetailsUpdateAppRequest request) { + Bill bill = billRepository.findById(billId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_NOT_FOUND)); + + List billDetailUpdateAppRequests = request.billDetailUpdateAppRequests(); + + validateToken(token, bill); + validateBillDetailSize(billDetailUpdateAppRequests, bill); + validateTotalPrice(billDetailUpdateAppRequests, bill); + + List billDetails = bill.getBillDetails(); + + for (BillDetailUpdateAppRequest updateRequest : billDetailUpdateAppRequests) { + BillDetail detailToUpdate = billDetails.stream() + .filter(detail -> detail.isSameId(updateRequest.id())) + .findFirst() + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_DETAIL_NOT_FOUND)); + + detailToUpdate.updatePrice(updateRequest.price()); + detailToUpdate.updateIsFixed(updateRequest.isFixed()); + } + } + + private void validateBillDetailSize(List requests, Bill bill) { + List ids = requests.stream() + .map(BillDetailUpdateAppRequest::id) + .distinct() + .toList(); + if (bill.getBillDetails().size() != ids.size()) { + throw new HaengdongException(HaengdongErrorCode.BILL_DETAIL_NOT_FOUND); + } + } + + private void validateTotalPrice( + List billDetailUpdateAppRequests, + Bill bill + ) { + Long requestsPriceSum = calculateUpdatePriceSum(billDetailUpdateAppRequests); + if (!bill.isSamePrice(requestsPriceSum)) { + throw new HaengdongException(HaengdongErrorCode.BILL_PRICE_NOT_MATCHED); + } + } + + private Long calculateUpdatePriceSum(List billDetailUpdateAppRequests) { + return billDetailUpdateAppRequests.stream() + .map(BillDetailUpdateAppRequest::price) + .reduce(0L, Long::sum); + } + + private Event getEvent(String eventToken) { + return eventRepository.findByToken(eventToken) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + } + + private Bill getBill(Long billId) { + return billRepository.findById(billId) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BILL_NOT_FOUND)); + } +} diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index 106186af3..bb6d2b51f 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -1,27 +1,20 @@ package server.haengdong.application; -import java.util.ArrayList; -import java.util.Comparator; import java.util.List; -import java.util.Set; +import java.util.Map.Entry; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import server.haengdong.application.request.EventAppRequest; import server.haengdong.application.request.EventLoginAppRequest; -import server.haengdong.application.request.MemberNameUpdateAppRequest; -import server.haengdong.application.request.MemberNamesUpdateAppRequest; -import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.request.EventUpdateAppRequest; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.application.response.MembersAppResponse; -import server.haengdong.domain.action.BillAction; -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.MemberBillReport; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.bill.BillRepository; +import server.haengdong.domain.member.Member; +import server.haengdong.domain.member.MemberBillReport; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.domain.event.EventTokenProvider; @@ -36,10 +29,7 @@ public class EventService { private final EventRepository eventRepository; private final EventTokenProvider eventTokenProvider; - private final BillActionRepository billActionRepository; - private final MemberActionRepository memberActionRepository; - private final BillActionDetailRepository billActionDetailRepository; - + private final BillRepository billRepository; @Transactional public EventAppResponse saveEvent(EventAppRequest request) { @@ -56,108 +46,6 @@ public EventDetailAppResponse findEvent(String token) { return EventDetailAppResponse.of(event); } - public List findActions(String token) { - Event event = getEvent(token); - - List billActions = billActionRepository.findByEvent(event).stream() - .sorted(Comparator.comparing(BillAction::getSequence)).toList(); - List memberActions = memberActionRepository.findAllByEvent(event).stream() - .sorted(Comparator.comparing(MemberAction::getSequence)).toList(); - - return getActionAppResponses(billActions, memberActions); - } - - private List getActionAppResponses( - List billActions, - List memberActions - ) { - int billActionIndex = 0; - int memberActionIndex = 0; - List actionAppResponses = new ArrayList<>(); - - while (billActionIndex < billActions.size() && memberActionIndex < memberActions.size()) { - BillAction billAction = billActions.get(billActionIndex); - MemberAction memberAction = memberActions.get(memberActionIndex); - if (billAction.getSequence().getValue() < memberAction.getSequence().getValue()) { - actionAppResponses.add(ActionAppResponse.of(billAction)); - billActionIndex++; - } else { - actionAppResponses.add(ActionAppResponse.of(memberAction)); - memberActionIndex++; - } - } - while (billActionIndex < billActions.size()) { - BillAction billAction = billActions.get(billActionIndex++); - actionAppResponses.add(ActionAppResponse.of(billAction)); - } - while (memberActionIndex < memberActions.size()) { - MemberAction memberAction = memberActions.get(memberActionIndex++); - actionAppResponses.add(ActionAppResponse.of(memberAction)); - } - - return actionAppResponses; - } - - public MembersAppResponse findAllMembers(String token) { - Event event = getEvent(token); - - List memberNames = memberActionRepository.findAllUniqueMemberByEvent(event); - - return new MembersAppResponse(memberNames); - } - - @Transactional - public void updateMember(String token, MemberNamesUpdateAppRequest request) { - Event event = getEvent(token); - List members = request.members(); - - validateBeforeNames(members, event); - validateAfterNames(members, event); - - members.forEach(member -> updateMemberName(event, member.before(), member.after())); - } - - private void validateBeforeNames(List members, Event event) { - List beforeNames = members.stream() - .map(MemberNameUpdateAppRequest::before) - .toList(); - if (beforeNames.size() != Set.copyOf(beforeNames).size()) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); - } - beforeNames.forEach(beforeName -> validateBeforeMemberNameExist(event, beforeName)); - } - - private void validateBeforeMemberNameExist(Event event, String beforeName) { - boolean isMemberNameExist = memberActionRepository.existsByEventAndMemberName(event, beforeName); - if (!isMemberNameExist) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_EXIST); - } - } - - private void validateAfterNames(List members, Event event) { - List afterNames = members.stream() - .map(MemberNameUpdateAppRequest::after) - .toList(); - if (afterNames.size() != Set.copyOf(afterNames).size()) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); - } - afterNames.forEach(afterName -> validateAfterMemberNameNotExist(event, afterName)); - } - - private void validateAfterMemberNameNotExist(Event event, String afterName) { - boolean isMemberNameExist = memberActionRepository.existsByEventAndMemberName(event, afterName); - if (isMemberNameExist) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); - } - } - - private void updateMemberName(Event event, String beforeName, String afterName) { - memberActionRepository.findAllByEventAndMemberName(event, beforeName) - .forEach(memberAction -> memberAction.updateMemberName(afterName)); - billActionDetailRepository.findAllByBillAction_EventAndMemberName(event, beforeName) - .forEach(billActionDetail -> billActionDetail.updateMemberName(afterName)); - } - public void validatePassword(EventLoginAppRequest request) throws HaengdongException { Event event = getEvent(request.token()); if (event.isPasswordMismatch(request.password())) { @@ -173,13 +61,35 @@ private Event getEvent(String token) { public List getMemberBillReports(String token) { Event event = eventRepository.findByToken(token) .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); - List billActions = billActionRepository.findByEvent(event); - List memberActions = memberActionRepository.findAllByEvent(event); + List bills = billRepository.findAllByEvent(event); - MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions); + MemberBillReport memberBillReport = MemberBillReport.createByBills(bills); return memberBillReport.getReports().entrySet().stream() - .map(entry -> new MemberBillReportAppResponse(entry.getKey(), entry.getValue())) + .map(this::createMemberBillReportResponse) .toList(); } + + private MemberBillReportAppResponse createMemberBillReportResponse(Entry entry) { + Member member = entry.getKey(); + Long price = entry.getValue(); + + return new MemberBillReportAppResponse( + member.getId(), + member.getName(), + member.isDeposited(), + price + ); + } + + @Transactional + public void updateEvent(String token, EventUpdateAppRequest request) { + Event event = getEvent(token); + if (request.isEventNameExist()) { + event.rename(request.eventName()); + } + if (request.isAccountExist()) { + event.changeAccount(request.bankName(), request.accountNumber()); + } + } } diff --git a/server/src/main/java/server/haengdong/application/MemberActionFactory.java b/server/src/main/java/server/haengdong/application/MemberActionFactory.java deleted file mode 100644 index 97fa1038c..000000000 --- a/server/src/main/java/server/haengdong/application/MemberActionFactory.java +++ /dev/null @@ -1,60 +0,0 @@ -package server.haengdong.application; - -import java.util.ArrayList; -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; -import server.haengdong.application.request.MemberActionSaveAppRequest; -import server.haengdong.application.request.MemberActionsSaveAppRequest; -import server.haengdong.domain.action.CurrentMembers; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionStatus; -import server.haengdong.domain.action.Sequence; -import server.haengdong.domain.event.Event; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@RequiredArgsConstructor -@Component -public class MemberActionFactory { - - public List createMemberActions( - Event event, - MemberActionsSaveAppRequest request, - CurrentMembers currentMembers, - Sequence sequence - ) { - validateMemberNames(request); - validateActions(request, currentMembers); - - List createdMemberActions = new ArrayList<>(); - List actions = request.actions(); - for (MemberActionSaveAppRequest appRequest : actions) { - MemberAction memberAction = appRequest.toMemberAction(event, sequence); - createdMemberActions.add(memberAction); - sequence = sequence.next(); - } - - return createdMemberActions; - } - - private void validateMemberNames(MemberActionsSaveAppRequest request) { - List memberNames = request.actions().stream() - .map(MemberActionSaveAppRequest::name) - .toList(); - - long uniqueCount = memberNames.stream().distinct().count(); - if (uniqueCount != memberNames.size()) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); - } - } - - private void validateActions(MemberActionsSaveAppRequest request, CurrentMembers currentMembers) { - List actions = request.actions(); - - for (MemberActionSaveAppRequest action : actions) { - MemberActionStatus memberActionStatus = MemberActionStatus.of(action.status()); - currentMembers.validate(action.name(), memberActionStatus); - } - } -} diff --git a/server/src/main/java/server/haengdong/application/MemberActionService.java b/server/src/main/java/server/haengdong/application/MemberActionService.java deleted file mode 100644 index 26186c08a..000000000 --- a/server/src/main/java/server/haengdong/application/MemberActionService.java +++ /dev/null @@ -1,100 +0,0 @@ -package server.haengdong.application; - -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import server.haengdong.application.request.MemberActionsSaveAppRequest; -import server.haengdong.application.response.CurrentMemberAppResponse; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.BillActionRepository; -import server.haengdong.domain.action.CurrentMembers; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.action.Sequence; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@RequiredArgsConstructor -@Transactional(readOnly = true) -@Service -public class MemberActionService { - - private final MemberActionFactory memberActionFactory; - private final MemberActionRepository memberActionRepository; - private final EventRepository eventRepository; - private final BillActionRepository billActionRepository; - - @Transactional - public void saveMemberAction(String token, MemberActionsSaveAppRequest request) { - Event event = findEvent(token); - - List findMemberActions = memberActionRepository.findAllByEvent(event); - CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); - Sequence sequence = createStartSequence(event); - List memberActions = memberActionFactory.createMemberActions(event, request, currentMembers, - sequence); - memberActionRepository.saveAll(memberActions); - } - - private Sequence createStartSequence(Event event) { - Sequence memberActionSequence = memberActionRepository.findLastByEvent(event) - .map(MemberAction::getSequence) - .orElseGet(Sequence::createFirst); - Sequence billActionSequence = billActionRepository.findLastByEvent(event) - .map(BillAction::getSequence) - .orElseGet(Sequence::createFirst); - return Sequence.getGreater(memberActionSequence, billActionSequence).next(); - } - - public List getCurrentMembers(String token) { - Event event = findEvent(token); - List findMemberActions = memberActionRepository.findAllByEvent(event); - CurrentMembers currentMembers = CurrentMembers.of(findMemberActions); - - return currentMembers.getMembers() - .stream() - .map(CurrentMemberAppResponse::new) - .toList(); - } - - private Event findEvent(String token) { - return eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); - } - - @Transactional - public void deleteMember(String token, String memberName) { - Event event = eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); - - memberActionRepository.deleteAllByEventAndMemberName(event, memberName); - - List billActions = billActionRepository.findByEvent(event); - billActions.forEach(billAction -> resetBillAction(event, billAction)); - } - - @Transactional - public void deleteMemberAction(String token, Long id) { - Event event = eventRepository.findByToken(token) - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); - MemberAction memberAction = memberActionRepository.findByIdAndEvent(id, event); - - memberActionRepository.deleteAllByMemberNameAndMinSequence(memberAction.getMemberName(), - memberAction.getSequence().getValue()); - - List billActions = billActionRepository.findByEventAndGreaterThanSequence(event, - memberAction.getSequence().getValue()); - billActions.forEach(billAction -> resetBillAction(event, billAction)); - } - - private void resetBillAction(Event event, BillAction billAction) { - List memberActions = memberActionRepository.findByEventAndSequence(event, - billAction.getSequence().getValue()); - CurrentMembers currentMembers = CurrentMembers.of(memberActions); - - billAction.resetBillActionDetails(currentMembers); - } -} diff --git a/server/src/main/java/server/haengdong/application/MemberService.java b/server/src/main/java/server/haengdong/application/MemberService.java new file mode 100644 index 000000000..d54d3b3a0 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/MemberService.java @@ -0,0 +1,171 @@ +package server.haengdong.application; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.MemberSaveAppRequest; +import server.haengdong.application.request.MemberUpdateAppRequest; +import server.haengdong.application.request.MembersSaveAppRequest; +import server.haengdong.application.request.MembersUpdateAppRequest; +import server.haengdong.application.response.MemberAppResponse; +import server.haengdong.application.response.MembersDepositAppResponse; +import server.haengdong.application.response.MembersSaveAppResponse; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.bill.BillDetailRepository; +import server.haengdong.domain.bill.BillRepository; +import server.haengdong.domain.member.Member; +import server.haengdong.domain.member.MemberRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class MemberService { + + private final MemberRepository memberRepository; + private final EventRepository eventRepository; + private final BillRepository billRepository; + private final BillDetailRepository billDetailRepository; + + public MembersSaveAppResponse saveMembers(String token, MembersSaveAppRequest request) { + Event event = getEvent(token); + List memberNames = request.members().stream() + .map(MemberSaveAppRequest::name) + .toList(); + + validateMemberSave(memberNames, event); + + List members = memberNames.stream() + .map(name -> new Member(event, name)) + .toList(); + + List savedMembers = memberRepository.saveAll(members); + return MembersSaveAppResponse.of(savedMembers); + } + + public List getCurrentMembers(String token) { + Event event = getEvent(token); + + return billRepository.findFirstByEventOrderByIdDesc(event) + .map(Bill::getMembers) + .orElseGet(() -> memberRepository.findAllByEvent(event)) + .stream() + .map(MemberAppResponse::of) + .toList(); + } + + private void validateMemberSave(List memberNames, Event event) { + if (memberNamesDuplicated(memberNames)) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE, + "중복된 이름이 존재합니다. 입력된 이름: " + memberNames); + } + if (memberRepository.findAllByEvent(event).stream() + .anyMatch(member -> memberNames.contains(member.getName()))) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_ALREADY_EXIST); + } + } + + public MembersDepositAppResponse findAllMembers(String token) { + Event event = getEvent(token); + + List members = memberRepository.findAllByEvent(event); + + return MembersDepositAppResponse.of(members); + } + + @Transactional + public void updateMembers(String token, MembersUpdateAppRequest request) { + Event event = getEvent(token); + validateMemberUpdate(request); + + List updatedMembers = request.members().stream() + .map(memberRequest -> memberRequest.toMember(event)) + .toList(); + List eventMembers = memberRepository.findAllByEvent(event); + + validateUpdatedMembersExist(eventMembers, updatedMembers); + validateUpdatedNamesUnique(eventMembers, updatedMembers); + memberRepository.saveAll(updatedMembers); + } + + private Event getEvent(String token) { + return eventRepository.findByToken(token) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)); + } + + private void validateMemberUpdate(MembersUpdateAppRequest request) { + validateChangedNameUnique(request.members()); + validateMemberUnique(request.members()); + } + + private void validateChangedNameUnique(List members) { + List memberNames = members.stream() + .map(MemberUpdateAppRequest::name) + .toList(); + if (memberNamesDuplicated(memberNames)) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); + } + } + + private boolean memberNamesDuplicated(List memberNames) { + return memberNames.size() != Set.copyOf(memberNames).size(); + } + + private void validateMemberUnique(List members) { + List memberIds = members.stream() + .map(MemberUpdateAppRequest::id) + .distinct() + .toList(); + if (members.size() != memberIds.size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); + } + } + + private void validateUpdatedMembersExist(List eventMembers, List updatedMembers) { + Set members = new HashSet<>(eventMembers); + + if (!members.containsAll(updatedMembers)) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_FOUND); + } + } + + private void validateUpdatedNamesUnique(List eventMembers, List updatedMembers) { + Set eventMemberNames = eventMembers.stream() + .map(Member::getName) + .collect(Collectors.toSet()); + + boolean memberNameDuplicated = updatedMembers.stream() + .map(Member::getName) + .anyMatch(eventMemberNames::contains); + + if (memberNameDuplicated) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); + } + } + + @Transactional + public void deleteMember(String token, Long memberId) { + memberRepository.findById(memberId) + .ifPresent(member -> deleteMember(token, member)); + } + + private void deleteMember(String token, Member member) { + Event event = member.getEvent(); + if (event.isTokenMismatch(token)) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_FOUND); + } + + billRepository.findAllByEvent(event).stream() + .filter(bill -> bill.containMember(member)) + .forEach(bill -> bill.removeMemberBillDetail(member)); + billDetailRepository.deleteAllByMember(member); + memberRepository.delete(member); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java deleted file mode 100644 index c702fd0be..000000000 --- a/server/src/main/java/server/haengdong/application/request/BillActionAppRequest.java +++ /dev/null @@ -1,16 +0,0 @@ -package server.haengdong.application.request; - -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.CurrentMembers; -import server.haengdong.domain.action.Sequence; -import server.haengdong.domain.event.Event; - -public record BillActionAppRequest( - String title, - Long price -) { - - public BillAction toBillAction(Event event, Sequence sequence, CurrentMembers currentMembers) { - return BillAction.create(event, sequence, title, price, currentMembers); - } -} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java deleted file mode 100644 index 1fe19798e..000000000 --- a/server/src/main/java/server/haengdong/application/request/BillActionDetailsUpdateAppRequest.java +++ /dev/null @@ -1,8 +0,0 @@ -package server.haengdong.application.request; - -import java.util.List; - -public record BillActionDetailsUpdateAppRequest( - List billActionDetailUpdateAppRequests -) { -} diff --git a/server/src/main/java/server/haengdong/application/request/BillAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillAppRequest.java new file mode 100644 index 000000000..8eb945263 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillAppRequest.java @@ -0,0 +1,17 @@ +package server.haengdong.application.request; + +import java.util.List; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.member.Member; +import server.haengdong.domain.event.Event; + +public record BillAppRequest( + String title, + Long price, + List memberIds +) { + + public Bill toBill(Event event, List members) { + return Bill.create(event, title, price, members); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillDetailUpdateAppRequest.java similarity index 58% rename from server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java rename to server/src/main/java/server/haengdong/application/request/BillDetailUpdateAppRequest.java index e514aee81..4e66b9215 100644 --- a/server/src/main/java/server/haengdong/application/request/BillActionDetailUpdateAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/BillDetailUpdateAppRequest.java @@ -1,7 +1,7 @@ package server.haengdong.application.request; -public record BillActionDetailUpdateAppRequest( - String name, +public record BillDetailUpdateAppRequest( + Long id, Long price, boolean isFixed ) { diff --git a/server/src/main/java/server/haengdong/application/request/BillDetailsUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillDetailsUpdateAppRequest.java new file mode 100644 index 000000000..7a6477e08 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/BillDetailsUpdateAppRequest.java @@ -0,0 +1,8 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record BillDetailsUpdateAppRequest( + List billDetailUpdateAppRequests +) { +} diff --git a/server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillUpdateAppRequest.java similarity index 69% rename from server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java rename to server/src/main/java/server/haengdong/application/request/BillUpdateAppRequest.java index a90e3dd42..aa09f2351 100644 --- a/server/src/main/java/server/haengdong/application/request/BillActionUpdateAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/BillUpdateAppRequest.java @@ -1,6 +1,6 @@ package server.haengdong.application.request; -public record BillActionUpdateAppRequest( +public record BillUpdateAppRequest( String title, Long price ) { diff --git a/server/src/main/java/server/haengdong/application/request/EventUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/EventUpdateAppRequest.java new file mode 100644 index 000000000..13bffccc1 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/EventUpdateAppRequest.java @@ -0,0 +1,17 @@ +package server.haengdong.application.request; + +public record EventUpdateAppRequest( + String eventName, + String bankName, + String accountNumber +) { + + public boolean isEventNameExist() { + return eventName != null && !eventName.trim().isEmpty(); + } + + public boolean isAccountExist() { + return bankName != null && !bankName.trim().isEmpty() + && accountNumber != null && !accountNumber.trim().isEmpty(); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java deleted file mode 100644 index f56b89517..000000000 --- a/server/src/main/java/server/haengdong/application/request/MemberActionSaveAppRequest.java +++ /dev/null @@ -1,13 +0,0 @@ -package server.haengdong.application.request; - -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionStatus; -import server.haengdong.domain.action.Sequence; -import server.haengdong.domain.event.Event; - -public record MemberActionSaveAppRequest(String name, String status) { - - public MemberAction toMemberAction(Event event, Sequence sequence) { - return new MemberAction(event, sequence, name, MemberActionStatus.of(status)); - } -} diff --git a/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java deleted file mode 100644 index 650b908df..000000000 --- a/server/src/main/java/server/haengdong/application/request/MemberActionsSaveAppRequest.java +++ /dev/null @@ -1,6 +0,0 @@ -package server.haengdong.application.request; - -import java.util.List; - -public record MemberActionsSaveAppRequest(List actions) { -} diff --git a/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java index d629d3a02..b36d71cc1 100644 --- a/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/MemberNameUpdateAppRequest.java @@ -1,7 +1,7 @@ package server.haengdong.application.request; public record MemberNameUpdateAppRequest( - String before, - String after + Long id, + String name ) { } diff --git a/server/src/main/java/server/haengdong/application/request/MemberSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberSaveAppRequest.java new file mode 100644 index 000000000..45dc234e3 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberSaveAppRequest.java @@ -0,0 +1,4 @@ +package server.haengdong.application.request; + +public record MemberSaveAppRequest(String name) { +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java new file mode 100644 index 000000000..77df0625b --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java @@ -0,0 +1,16 @@ +package server.haengdong.application.request; + + +import server.haengdong.domain.member.Member; +import server.haengdong.domain.event.Event; + +public record MemberUpdateAppRequest( + Long id, + String name, + boolean isDeposited +) { + + public Member toMember(Event event) { + return new Member(id, event, name, isDeposited); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/MembersSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/MembersSaveAppRequest.java new file mode 100644 index 000000000..ae0c9fc62 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MembersSaveAppRequest.java @@ -0,0 +1,8 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record MembersSaveAppRequest( + List members +) { +} diff --git a/server/src/main/java/server/haengdong/application/request/MembersUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/MembersUpdateAppRequest.java new file mode 100644 index 000000000..a8ce8b893 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/MembersUpdateAppRequest.java @@ -0,0 +1,6 @@ +package server.haengdong.application.request; + +import java.util.List; + +public record MembersUpdateAppRequest(List members) { +} diff --git a/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java b/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java deleted file mode 100644 index 931a5c6ba..000000000 --- a/server/src/main/java/server/haengdong/application/response/ActionAppResponse.java +++ /dev/null @@ -1,61 +0,0 @@ -package server.haengdong.application.response; - -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionStatus; - -public record ActionAppResponse( - Long actionId, - String name, - Long price, - Long sequence, - boolean isFixed, - ActionType actionType -) { - - public ActionAppResponse(Long actionId, String name, Long price, Long sequence, ActionType actionType) { - this(actionId, name, price, sequence, false, actionType); - } - - public static ActionAppResponse of(BillAction billAction) { - return new ActionAppResponse( - billAction.getId(), - billAction.getTitle(), - billAction.getPrice(), - billAction.getSequence().getValue(), - billAction.isFixed(), - ActionAppResponse.ActionType.BILL - ); - } - - public static ActionAppResponse of(MemberAction memberAction) { - MemberActionStatus status = memberAction.getStatus(); - - return new ActionAppResponse( - memberAction.getId(), - memberAction.getMemberName(), - null, - memberAction.getSequence().getValue(), - false, - ActionAppResponse.ActionType.of(status) - ); - } - - public String actionTypeName() { - return actionType.name(); - } - - public enum ActionType { - BILL, - IN, - OUT, - ; - - private static ActionType of(MemberActionStatus memberActionStatus) { - if (MemberActionStatus.IN == memberActionStatus) { - return IN; - } - return OUT; - } - } -} diff --git a/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java b/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java deleted file mode 100644 index 3efc7ac9d..000000000 --- a/server/src/main/java/server/haengdong/application/response/BillActionDetailAppResponse.java +++ /dev/null @@ -1,18 +0,0 @@ -package server.haengdong.application.response; - -import server.haengdong.domain.action.BillActionDetail; - -public record BillActionDetailAppResponse( - String name, - Long price, - boolean isFixed -) { - - public static BillActionDetailAppResponse of(BillActionDetail billActionDetail) { - return new BillActionDetailAppResponse( - billActionDetail.getMemberName(), - billActionDetail.getPrice(), - billActionDetail.isFixed() - ); - } -} diff --git a/server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java b/server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java deleted file mode 100644 index 061f07816..000000000 --- a/server/src/main/java/server/haengdong/application/response/BillActionDetailsAppResponse.java +++ /dev/null @@ -1,14 +0,0 @@ -package server.haengdong.application.response; - -import java.util.List; -import java.util.stream.Collectors; -import server.haengdong.domain.action.BillActionDetail; - -public record BillActionDetailsAppResponse(List billActionDetailAppResponses) { - - public static BillActionDetailsAppResponse of(List billActionDetails) { - return billActionDetails.stream() - .map(BillActionDetailAppResponse::of) - .collect(Collectors.collectingAndThen(Collectors.toList(), BillActionDetailsAppResponse::new)); - } -} diff --git a/server/src/main/java/server/haengdong/application/response/BillAppResponse.java b/server/src/main/java/server/haengdong/application/response/BillAppResponse.java new file mode 100644 index 000000000..8a5a5b2bc --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/BillAppResponse.java @@ -0,0 +1,14 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.bill.Bill; + +public record BillAppResponse( + Long id, + String title, + Long price, + boolean isFixed +) { + public static BillAppResponse of(Bill bill) { + return new BillAppResponse(bill.getId(), bill.getTitle(), bill.getPrice(), bill.isFixed()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/BillDetailAppResponse.java b/server/src/main/java/server/haengdong/application/response/BillDetailAppResponse.java new file mode 100644 index 000000000..6618135cb --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/BillDetailAppResponse.java @@ -0,0 +1,20 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.bill.BillDetail; + +public record BillDetailAppResponse( + Long id, + String memberName, + Long price, + boolean isFixed +) { + + public static BillDetailAppResponse of(BillDetail billDetail) { + return new BillDetailAppResponse( + billDetail.getId(), + billDetail.getMember().getName(), + billDetail.getPrice(), + billDetail.isFixed() + ); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/BillDetailsAppResponse.java b/server/src/main/java/server/haengdong/application/response/BillDetailsAppResponse.java new file mode 100644 index 000000000..3618e0d08 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/BillDetailsAppResponse.java @@ -0,0 +1,14 @@ +package server.haengdong.application.response; + +import java.util.List; +import java.util.stream.Collectors; +import server.haengdong.domain.bill.BillDetail; + +public record BillDetailsAppResponse(List billDetails) { + + public static BillDetailsAppResponse of(List billDetails) { + return billDetails.stream() + .map(BillDetailAppResponse::of) + .collect(Collectors.collectingAndThen(Collectors.toList(), BillDetailsAppResponse::new)); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java b/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java deleted file mode 100644 index 6c682d3e9..000000000 --- a/server/src/main/java/server/haengdong/application/response/CurrentMemberAppResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package server.haengdong.application.response; - -import server.haengdong.domain.action.MemberAction; - -public record CurrentMemberAppResponse(String name) { - - public static CurrentMemberAppResponse of(MemberAction memberAction) { - return new CurrentMemberAppResponse(memberAction.getMemberName()); - } -} diff --git a/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java b/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java index 6e38826d4..53fd0b48c 100644 --- a/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java +++ b/server/src/main/java/server/haengdong/application/response/EventDetailAppResponse.java @@ -2,9 +2,12 @@ import server.haengdong.domain.event.Event; -public record EventDetailAppResponse(String eventName) { +public record EventDetailAppResponse( + String eventName, + String account +) { public static EventDetailAppResponse of(Event event) { - return new EventDetailAppResponse(event.getName()); + return new EventDetailAppResponse(event.getName(), event.getAccount()); } } diff --git a/server/src/main/java/server/haengdong/application/response/LastBillMemberAppResponse.java b/server/src/main/java/server/haengdong/application/response/LastBillMemberAppResponse.java new file mode 100644 index 000000000..abefe009a --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/LastBillMemberAppResponse.java @@ -0,0 +1,10 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.member.Member; + +public record LastBillMemberAppResponse(Long id, String name) { + + public static LastBillMemberAppResponse of(Member member) { + return new LastBillMemberAppResponse(member.getId(), member.getName()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/MemberAppResponse.java b/server/src/main/java/server/haengdong/application/response/MemberAppResponse.java new file mode 100644 index 000000000..b253ea697 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/MemberAppResponse.java @@ -0,0 +1,12 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.member.Member; + +public record MemberAppResponse( + Long id, + String name +) { + public static MemberAppResponse of(Member member) { + return new MemberAppResponse(member.getId(), member.getName()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java b/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java index 21b6cef56..875578fbc 100644 --- a/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java +++ b/server/src/main/java/server/haengdong/application/response/MemberBillReportAppResponse.java @@ -1,4 +1,9 @@ package server.haengdong.application.response; -public record MemberBillReportAppResponse(String name, Long price) { +public record MemberBillReportAppResponse( + Long memberId, + String name, + boolean isDeposited, + Long price +) { } diff --git a/server/src/main/java/server/haengdong/application/response/MemberDepositAppResponse.java b/server/src/main/java/server/haengdong/application/response/MemberDepositAppResponse.java new file mode 100644 index 000000000..94dd77117 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/MemberDepositAppResponse.java @@ -0,0 +1,13 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.member.Member; + +public record MemberDepositAppResponse( + Long id, + String name, + boolean isDeposited +) { + public static MemberDepositAppResponse of(Member member) { + return new MemberDepositAppResponse(member.getId(), member.getName(), member.isDeposited()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/MemberSaveAppResponse.java b/server/src/main/java/server/haengdong/application/response/MemberSaveAppResponse.java new file mode 100644 index 000000000..1d08536ba --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/MemberSaveAppResponse.java @@ -0,0 +1,12 @@ +package server.haengdong.application.response; + +import server.haengdong.domain.member.Member; + +public record MemberSaveAppResponse( + Long id, + String name +) { + public static MemberSaveAppResponse of(Member member) { + return new MemberSaveAppResponse(member.getId(), member.getName()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/MembersAppResponse.java b/server/src/main/java/server/haengdong/application/response/MembersAppResponse.java deleted file mode 100644 index be8378b37..000000000 --- a/server/src/main/java/server/haengdong/application/response/MembersAppResponse.java +++ /dev/null @@ -1,8 +0,0 @@ -package server.haengdong.application.response; - -import java.util.List; - -public record MembersAppResponse( - List memberNames -) { -} diff --git a/server/src/main/java/server/haengdong/application/response/MembersDepositAppResponse.java b/server/src/main/java/server/haengdong/application/response/MembersDepositAppResponse.java new file mode 100644 index 000000000..007904d25 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/MembersDepositAppResponse.java @@ -0,0 +1,15 @@ +package server.haengdong.application.response; + +import java.util.List; +import server.haengdong.domain.member.Member; + +public record MembersDepositAppResponse( + List members +) { + + public static MembersDepositAppResponse of(List members) { + return new MembersDepositAppResponse(members.stream() + .map(MemberDepositAppResponse::of) + .toList()); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/MembersSaveAppResponse.java b/server/src/main/java/server/haengdong/application/response/MembersSaveAppResponse.java new file mode 100644 index 000000000..e171f9950 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/MembersSaveAppResponse.java @@ -0,0 +1,16 @@ +package server.haengdong.application.response; + +import java.util.List; +import server.haengdong.domain.member.Member; + +public record MembersSaveAppResponse( + List members +) { + public static MembersSaveAppResponse of(List members) { + return new MembersSaveAppResponse( + members.stream() + .map(MemberSaveAppResponse::of) + .toList() + ); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/StepAppResponse.java b/server/src/main/java/server/haengdong/application/response/StepAppResponse.java new file mode 100644 index 000000000..2537d1db1 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/StepAppResponse.java @@ -0,0 +1,21 @@ +package server.haengdong.application.response; + +import java.util.List; +import server.haengdong.domain.step.Step; + +public record StepAppResponse( + List bills, + List members +) { + public static StepAppResponse of(Step step) { + List billAppResponses = step.getBills().stream() + .map(BillAppResponse::of) + .toList(); + + List memberAppResponses = step.getMembers().stream() + .map(MemberAppResponse::of) + .toList(); + + return new StepAppResponse(billAppResponses, memberAppResponses); + } +} diff --git a/server/src/main/java/server/haengdong/config/AdminInterceptor.java b/server/src/main/java/server/haengdong/config/AdminInterceptor.java index 97bf2c774..6e13f4c96 100644 --- a/server/src/main/java/server/haengdong/config/AdminInterceptor.java +++ b/server/src/main/java/server/haengdong/config/AdminInterceptor.java @@ -27,9 +27,7 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons if (HttpMethod.OPTIONS.equals(method)) { return true; } - validateToken(request); - return true; } diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java deleted file mode 100644 index 47d5d83e5..000000000 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetailRepository.java +++ /dev/null @@ -1,20 +0,0 @@ -package server.haengdong.domain.action; - -import java.util.List; -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; - -@Repository -public interface BillActionDetailRepository extends JpaRepository { - - @Query(""" - select bd - from BillActionDetail bd - where bd.billAction = :billAction - """) - List findAllByBillAction(BillAction billAction); - - List findAllByBillAction_EventAndMemberName(Event event, String memberName); -} diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java b/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java deleted file mode 100644 index d05451882..000000000 --- a/server/src/main/java/server/haengdong/domain/action/BillActionRepository.java +++ /dev/null @@ -1,31 +0,0 @@ -package server.haengdong.domain.action; - -import java.util.List; -import java.util.Optional; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; -import server.haengdong.domain.event.Event; - -@Repository -public interface BillActionRepository extends JpaRepository { - - List findByEvent(Event event); - - @Query(""" - select ba - from BillAction ba - where ba.event = :event and ba.sequence.value > :sequence - """) - List findByEventAndGreaterThanSequence(Event event, Long sequence); - - @Query(""" - select ba - from BillAction ba - WHERE ba.event = :event - ORDER BY ba.sequence DESC - LIMIT 1 - """) - Optional findLastByEvent(@Param("event") Event event); -} diff --git a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java b/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java deleted file mode 100644 index ba380aae5..000000000 --- a/server/src/main/java/server/haengdong/domain/action/CurrentMembers.java +++ /dev/null @@ -1,81 +0,0 @@ -package server.haengdong.domain.action; - -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -public class CurrentMembers { - - private final Set members; - - public CurrentMembers() { - this(new HashSet<>()); - } - - protected CurrentMembers(Set members) { - this.members = members; - } - - public static CurrentMembers of(List memberActions) { - List sortedMemberActions = getSortedMemberActions(memberActions); - Set members = new HashSet<>(); - for (MemberAction memberAction : sortedMemberActions) { - String member = memberAction.getMemberName(); - if (memberAction.isSameStatus(MemberActionStatus.IN)) { - members.add(member); - continue; - } - members.remove(member); - } - - return new CurrentMembers(members); - } - - private static List getSortedMemberActions(List memberActions) { - return memberActions.stream() - .sorted(Comparator.comparing(MemberAction::getSequence)) - .toList(); - } - - public CurrentMembers addMemberAction(MemberAction memberAction) { - String memberName = memberAction.getMemberName(); - - Set currentMembers = new HashSet<>(members); - - if (memberAction.isIn()) { - currentMembers.add(memberName); - } else { - currentMembers.remove(memberName); - } - return new CurrentMembers(currentMembers); - } - - public void validate(String memberName, MemberActionStatus memberActionStatus) { - if (memberActionStatus == MemberActionStatus.IN && members.contains(memberName)) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_ALREADY_EXIST); - } - if (memberActionStatus == MemberActionStatus.OUT && !members.contains(memberName)) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_EXIST); - } - } - - public boolean isEmpty() { - return members.isEmpty(); - } - - public boolean isNotEmpty() { - return !members.isEmpty(); - } - - public int size() { - return members.size(); - } - - public Set getMembers() { - return Collections.unmodifiableSet(members); - } -} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberAction.java b/server/src/main/java/server/haengdong/domain/action/MemberAction.java deleted file mode 100644 index 18efc1611..000000000 --- a/server/src/main/java/server/haengdong/domain/action/MemberAction.java +++ /dev/null @@ -1,84 +0,0 @@ -package server.haengdong.domain.action; - -import jakarta.persistence.AttributeOverride; -import jakarta.persistence.Column; -import jakarta.persistence.Embedded; -import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -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 jakarta.persistence.UniqueConstraint; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import server.haengdong.domain.event.Event; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"event_id", "sequence"})}) -@Entity -public class MemberAction implements Comparable { - - public static final int MIN_NAME_LENGTH = 1; - public static final int MAX_NAME_LENGTH = 8; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @JoinColumn(name = "event_id", nullable = false) - @ManyToOne(fetch = FetchType.LAZY) - private Event event; - - @AttributeOverride(name = "value", column = @Column(name = "sequence", nullable = false)) - @Embedded - private Sequence sequence; - - @Column(nullable = false, length = MAX_NAME_LENGTH) - private String memberName; - - @Column(nullable = false) - @Enumerated(EnumType.STRING) - private MemberActionStatus status; - - public MemberAction(Event event, Sequence sequence, String memberName, MemberActionStatus status) { - validateMemberName(memberName); - this.event = event; - this.sequence = sequence; - this.memberName = memberName; - this.status = status; - } - - private void validateMemberName(String memberName) { - int memberLength = memberName.length(); - if (memberLength < MIN_NAME_LENGTH || memberLength > MAX_NAME_LENGTH) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_LENGTH_INVALID); - } - } - - public void updateMemberName(String memberName) { - validateMemberName(memberName); - this.memberName = memberName; - } - - public boolean isIn() { - return status == MemberActionStatus.IN; - } - - public boolean isSameStatus(MemberActionStatus memberActionStatus) { - return status == memberActionStatus; - } - - @Override - public int compareTo(MemberAction o) { - return sequence.compareTo(o.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 deleted file mode 100644 index 9aceed477..000000000 --- a/server/src/main/java/server/haengdong/domain/action/MemberActionRepository.java +++ /dev/null @@ -1,61 +0,0 @@ -package server.haengdong.domain.action; - -import java.util.List; -import java.util.Optional; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Modifying; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; -import server.haengdong.domain.event.Event; - -@Repository -public interface MemberActionRepository extends JpaRepository { - - List findAllByEvent(@Param("event") Event event); - - @Query(""" - select distinct ma.memberName - from MemberAction ma - where ma.event = :event - """) - List findAllUniqueMemberByEvent(Event event); - - @Modifying - @Query(""" - delete - from MemberAction ma - where ma.memberName = :memberName and ma.event = :event - """) - void deleteAllByEventAndMemberName(Event event, String memberName); - - @Modifying - @Query(""" - delete - from MemberAction ma - where ma.memberName = :memberName and ma.sequence.value >= :sequence - """) - void deleteAllByMemberNameAndMinSequence(String memberName, Long sequence); - - List findAllByEventAndMemberName(Event event, String memberName); - - boolean existsByEventAndMemberName(Event event, String updatedMemberName); - - @Query(""" - select ma - from MemberAction ma - where ma.event = :event and ma.sequence.value < :sequence - """) - List findByEventAndSequence(Event event, Long sequence); - - @Query(""" - select ma - from MemberAction ma - WHERE ma.event = :event - ORDER BY ma.sequence.value DESC - LIMIT 1 - """) - Optional findLastByEvent(@Param("event") Event event); - - MemberAction findByIdAndEvent(Long actionId, Event event); -} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java b/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java deleted file mode 100644 index 76c5a66d4..000000000 --- a/server/src/main/java/server/haengdong/domain/action/MemberActionStatus.java +++ /dev/null @@ -1,19 +0,0 @@ -package server.haengdong.domain.action; - -import java.util.Arrays; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -public enum MemberActionStatus { - IN, - OUT, - ; - - public static MemberActionStatus of(String status) { - return Arrays.stream(MemberActionStatus.values()) - .filter(s -> s.name().equals(status)) - .findFirst() - .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_ACTION_STATUS_INVALID, - String.format(HaengdongErrorCode.MEMBER_ACTION_STATUS_INVALID.getMessage(), status))); - } -} diff --git a/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java b/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java deleted file mode 100644 index 5fcb6ebd3..000000000 --- a/server/src/main/java/server/haengdong/domain/action/MemberBillReport.java +++ /dev/null @@ -1,75 +0,0 @@ -package server.haengdong.domain.action; - -import static java.util.stream.Collectors.toMap; - -import java.util.List; -import java.util.Map; -import java.util.PriorityQueue; -import java.util.function.Function; -import lombok.Getter; - -@Getter -public class MemberBillReport { - - private final Map reports; - - private MemberBillReport(Map reports) { - this.reports = reports; - } - - public static MemberBillReport createByActions(List billActions, List memberActions) { - PriorityQueue sortedBillActions = new PriorityQueue<>(billActions); - PriorityQueue sortedMemberActions = new PriorityQueue<>(memberActions); - - Map memberBillReports = initReports(memberActions); - CurrentMembers currentMembers = new CurrentMembers(); - while (!sortedBillActions.isEmpty() && !sortedMemberActions.isEmpty()) { - if (isMemberActionTurn(sortedMemberActions, sortedBillActions)) { - MemberAction memberAction = sortedMemberActions.poll(); - currentMembers = currentMembers.addMemberAction(memberAction); - continue; - } - addBillAction(sortedBillActions, currentMembers, memberBillReports); - } - - while (!sortedBillActions.isEmpty()) { - addBillAction(sortedBillActions, currentMembers, memberBillReports); - } - - return new MemberBillReport(memberBillReports); - } - - private static Map initReports(List memberActions) { - return memberActions.stream() - .map(MemberAction::getMemberName) - .distinct() - .collect(toMap(Function.identity(), i -> 0L)); - } - - private static boolean isMemberActionTurn( - PriorityQueue memberActions, - PriorityQueue billActions - ) { - MemberAction memberAction = memberActions.peek(); - BillAction billAction = billActions.peek(); - - return memberAction.getSequence().getValue() < billAction.getSequence().getValue(); - } - - private static void addBillAction( - PriorityQueue sortedBillActions, - CurrentMembers currentMembers, - Map memberBillReports - ) { - BillAction billAction = sortedBillActions.poll(); - if (currentMembers.isEmpty()) { - return; - } - - for (String currentMember : currentMembers.getMembers()) { - Long currentPrice = billAction.findPriceByMemberName(currentMember); - Long price = memberBillReports.get(currentMember) + currentPrice; - memberBillReports.put(currentMember, price); - } - } -} diff --git a/server/src/main/java/server/haengdong/domain/action/Sequence.java b/server/src/main/java/server/haengdong/domain/action/Sequence.java deleted file mode 100644 index 39a99d063..000000000 --- a/server/src/main/java/server/haengdong/domain/action/Sequence.java +++ /dev/null @@ -1,41 +0,0 @@ -package server.haengdong.domain.action; - -import jakarta.persistence.Embeddable; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@EqualsAndHashCode -@Getter -@NoArgsConstructor -@Embeddable -public class Sequence implements Comparable { - - private static final long FIRST_SEQUENCE = 1L; - - private Long value; - - public Sequence(Long value) { - this.value = value; - } - - public static Sequence createFirst() { - return new Sequence(FIRST_SEQUENCE); - } - - public static Sequence getGreater(Sequence first, Sequence second) { - if (first.compareTo(second) > 0) { - return first; - } - return second; - } - - public Sequence next() { - return new Sequence(value + 1); - } - - @Override - public int compareTo(Sequence o) { - return Long.compare(value, o.value); - } -} diff --git a/server/src/main/java/server/haengdong/domain/action/BillAction.java b/server/src/main/java/server/haengdong/domain/bill/Bill.java similarity index 51% rename from server/src/main/java/server/haengdong/domain/action/BillAction.java rename to server/src/main/java/server/haengdong/domain/bill/Bill.java index 56ca8c20e..10043bbcf 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillAction.java +++ b/server/src/main/java/server/haengdong/domain/bill/Bill.java @@ -1,9 +1,7 @@ -package server.haengdong.domain.action; +package server.haengdong.domain.bill; -import jakarta.persistence.AttributeOverride; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; -import jakarta.persistence.Embedded; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; @@ -12,25 +10,24 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; -import jakarta.persistence.Table; -import jakarta.persistence.UniqueConstraint; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; +import server.haengdong.domain.member.Member; import server.haengdong.domain.event.Event; import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"event_id", "sequence"})}) @Entity -public class BillAction implements Comparable { +public class Bill { public static final int MIN_TITLE_LENGTH = 1; public static final int MAX_TITLE_LENGTH = 30; @@ -46,24 +43,19 @@ public class BillAction implements Comparable { @ManyToOne(fetch = FetchType.LAZY) private Event event; - @AttributeOverride(name = "value", column = @Column(name = "sequence", nullable = false)) - @Embedded - private Sequence sequence; - @Column(nullable = false, length = MAX_TITLE_LENGTH) private String title; @Column(nullable = false) private Long price; - @OneToMany(mappedBy = "billAction", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) - private List billActionDetails = new ArrayList<>(); + @OneToMany(mappedBy = "bill", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) + private List billDetails = new ArrayList<>(); - public BillAction(Event event, Sequence sequence, String title, Long price) { + public Bill(Event event, String title, Long price) { validateTitle(title); validatePrice(price); this.event = event; - this.sequence = sequence; this.title = title.trim(); this.price = price; } @@ -71,40 +63,38 @@ public BillAction(Event event, Sequence sequence, String title, Long price) { private void validateTitle(String title) { int titleLength = title.trim().length(); if (titleLength < MIN_TITLE_LENGTH || titleLength > MAX_TITLE_LENGTH) { - throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_TITLE_INVALID); + throw new HaengdongException(HaengdongErrorCode.BILL_TITLE_INVALID); } } private void validatePrice(Long price) { if (price < MIN_PRICE || price > MAX_PRICE) { - throw new HaengdongException(HaengdongErrorCode.BILL_ACTION_PRICE_INVALID); + throw new HaengdongException(HaengdongErrorCode.BILL_PRICE_INVALID); } } - public static BillAction create( - Event event, Sequence sequence, String title, Long price, CurrentMembers currentMembers - ) { - BillAction billAction = new BillAction(event, sequence, title, price); - billAction.resetBillActionDetails(currentMembers); - return billAction; + public static Bill create(Event event, String title, Long price, List members) { + Bill bill = new Bill(event, title, price); + bill.resetBillDetails(members); + return bill; } - public void resetBillActionDetails(CurrentMembers currentMembers) { - this.billActionDetails.clear(); - Iterator priceIterator = distributePrice(currentMembers.size()).iterator(); + public void resetBillDetails(List members) { + this.billDetails.clear(); + Iterator priceIterator = distributePrice(members.size()).iterator(); - for (String member : currentMembers.getMembers()) { - BillActionDetail billActionDetail = new BillActionDetail(this, member, priceIterator.next(), false); - this.billActionDetails.add(billActionDetail); + for (Member member : members) { + BillDetail billDetail = new BillDetail(this, member, priceIterator.next(), false); + this.billDetails.add(billDetail); } } - private void resetBillActionDetails() { - Iterator priceIterator = distributePrice(billActionDetails.size()).iterator(); + private void resetBillDetails() { + Iterator priceIterator = distributePrice(billDetails.size()).iterator(); - billActionDetails.forEach(billActionDetail -> { - billActionDetail.updatePrice(priceIterator.next()); - billActionDetail.updateIsFixed(false); + billDetails.forEach(billDetail -> { + billDetail.updatePrice(priceIterator.next()); + billDetail.updateIsFixed(false); }); } @@ -122,42 +112,48 @@ private List distributePrice(int memberCount) { return results; } + public void removeMemberBillDetail(Member member) { + BillDetail foundBillDetail = billDetails.stream() + .filter(billDetail -> billDetail.isMember(member)) + .findFirst() + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_NOT_FOUND)); + + billDetails.remove(foundBillDetail); + resetBillDetails(); + } + public void update(String title, Long price) { validateTitle(title); validatePrice(price); this.title = title.trim(); this.price = price; - resetBillActionDetails(); + resetBillDetails(); } - public void addDetails(List billActionDetails) { - billActionDetails.forEach(this::addDetail); + public boolean containMember(Member member) { + return billDetails.stream() + .anyMatch(billDetail -> billDetail.isMember(member)); } - private void addDetail(BillActionDetail billActionDetail) { - this.billActionDetails.add(billActionDetail); - billActionDetail.setBillAction(this); - } + public boolean isSameMembers(Bill other) { + Set members = Set.copyOf(this.getMembers()); + Set otherMembers = Set.copyOf(other.getMembers()); - public boolean isFixed() { - return billActionDetails.stream() - .anyMatch(BillActionDetail::isFixed); + return members.equals(otherMembers); } public boolean isSamePrice(Long price) { return this.price.equals(price); } - public Long findPriceByMemberName(String memberName) { - return billActionDetails.stream() - .filter(billActionDetail -> billActionDetail.hasMemberName(memberName)) - .map(BillActionDetail::getPrice) - .findFirst() - .orElseGet(() -> DEFAULT_PRICE); + public boolean isFixed() { + return billDetails.stream() + .anyMatch(BillDetail::isFixed); } - @Override - public int compareTo(BillAction o) { - return sequence.compareTo(o.sequence); + public List getMembers() { + return billDetails.stream() + .map(BillDetail::getMember) + .toList(); } } diff --git a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java b/server/src/main/java/server/haengdong/domain/bill/BillDetail.java similarity index 56% rename from server/src/main/java/server/haengdong/domain/action/BillActionDetail.java rename to server/src/main/java/server/haengdong/domain/bill/BillDetail.java index 09776e0d3..6f3bcf973 100644 --- a/server/src/main/java/server/haengdong/domain/action/BillActionDetail.java +++ b/server/src/main/java/server/haengdong/domain/bill/BillDetail.java @@ -1,4 +1,4 @@ -package server.haengdong.domain.action; +package server.haengdong.domain.bill; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -11,11 +11,12 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; +import server.haengdong.domain.member.Member; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity -public class BillActionDetail { +public class BillDetail { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -23,10 +24,11 @@ public class BillActionDetail { @JoinColumn(nullable = false) @ManyToOne(fetch = FetchType.LAZY) - private BillAction billAction; + private Bill bill; - @Column(nullable = false) - private String memberName; + @JoinColumn(name = "member_id", nullable = false) + @ManyToOne(fetch = FetchType.LAZY) + private Member member; @Column(nullable = false) private Long price; @@ -34,9 +36,9 @@ public class BillActionDetail { @Column(nullable = false) private boolean isFixed; - public BillActionDetail(BillAction billAction, String memberName, Long price, boolean isFixed) { - this.billAction = billAction; - this.memberName = memberName; + public BillDetail(Bill bill, Member member, Long price, boolean isFixed) { + this.bill = bill; + this.member = member; this.price = price; this.isFixed = isFixed; } @@ -49,19 +51,11 @@ public void updateIsFixed(boolean isFixed) { this.isFixed = isFixed; } - public void updateMemberName(String name) { - this.memberName = name; - } - - public boolean hasMemberName(String memberName) { - return this.memberName.equals(memberName); - } - - public boolean isSameName(String memberName) { - return this.memberName.equals(memberName); + public boolean isSameId(Long id) { + return this.id.equals(id); } - public void setBillAction(BillAction billAction) { - this.billAction = billAction; + public boolean isMember(Member member) { + return this.member.equals(member); } } diff --git a/server/src/main/java/server/haengdong/domain/bill/BillDetailRepository.java b/server/src/main/java/server/haengdong/domain/bill/BillDetailRepository.java new file mode 100644 index 000000000..d49c01ab2 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/bill/BillDetailRepository.java @@ -0,0 +1,26 @@ +package server.haengdong.domain.bill; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.member.Member; + +@Repository +public interface BillDetailRepository extends JpaRepository { + + List findAllByBill(Bill bill); + + @Query(""" + select bd from BillDetail bd + join fetch bd.member + where bd.bill.id = :billId + """) + List findAllByBillId(Long billId); + + @Modifying + @Query("delete from BillDetail bd where bd.member = :member") + void deleteAllByMember(@Param("member") Member member); +} diff --git a/server/src/main/java/server/haengdong/domain/bill/BillRepository.java b/server/src/main/java/server/haengdong/domain/bill/BillRepository.java new file mode 100644 index 000000000..2c0b16956 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/bill/BillRepository.java @@ -0,0 +1,15 @@ +package server.haengdong.domain.bill; + +import java.util.List; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import server.haengdong.domain.event.Event; + +@Repository +public interface BillRepository extends JpaRepository { + + List findAllByEvent(Event event); + + Optional findFirstByEventOrderByIdDesc(Event event); +} diff --git a/server/src/main/java/server/haengdong/domain/event/Bank.java b/server/src/main/java/server/haengdong/domain/event/Bank.java new file mode 100644 index 000000000..cac1fdc7c --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/Bank.java @@ -0,0 +1,56 @@ +package server.haengdong.domain.event; + +import java.util.Arrays; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +public enum Bank { + WOORI_BANK("우리은행"), + JEIL_BANK("제일은행"), + SHINHAN_BANK("신한은행"), + KB_BANK("KB국민은행"), + HANA_BANK("하나은행"), + CITI_BANK("시티은행"), + IM_BANK("IM뱅크"), + BUSAN_BANK("부산은행"), + GYEONGNAM_BANK("경남은행"), + GWANGJU_BANK("광주은행"), + JEONBUK_BANK("전북은행"), + JEJU_BANK("제주은행"), + IBK_BANK("기업은행"), + KDB_BANK("산업은행"), + SUHYUP_BANK("수협은행"), + NH_BANK("농협은행"), + SAEMAUL_BANK("새마을금고"), + POST_BANK("우체국은행"), + SHINHYEOP_BANK("신협은행"), + SBI_SAVINGS_BANK("SBI저축"), + KAKAO_BANK("카카오뱅크"), + TOSS_BANK("토스뱅크"), + K_BANK("케이뱅크"), + ; + + private final String name; + + Bank(String name) { + this.name = name; + } + + public static void isExists(String bankName) { + Arrays.stream(Bank.values()) + .filter(bank -> bank.name.equals(bankName)) + .findFirst() + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.BANK_NAME_INVALID)); + } + + public static String getSupportedBanks() { + return Arrays.stream(Bank.values()) + .map(Bank::getName) + .reduce((bank1, bank2) -> bank1 + ", " + bank2) + .orElse("지원하는 은행이 없습니다."); + } + + public String getName() { + return name; + } +} diff --git a/server/src/main/java/server/haengdong/domain/event/Event.java b/server/src/main/java/server/haengdong/domain/event/Event.java index be8874414..fcbeaab9c 100644 --- a/server/src/main/java/server/haengdong/domain/event/Event.java +++ b/server/src/main/java/server/haengdong/domain/event/Event.java @@ -20,6 +20,8 @@ public class Event { public static final int MIN_NAME_LENGTH = 1; public static final int MAX_NAME_LENGTH = 20; + public static final int MIN_ACCOUNT_NUMBER_LENGTH = 8; + public static final int MAX_ACCOUNT_NUMBER_LENGTH = 30; private static final String SPACES = " "; @Id @@ -36,25 +38,25 @@ public class Event { @Column(nullable = false, unique = true) private String token; + @Column(length = MAX_ACCOUNT_NUMBER_LENGTH) + private String account; + + public Event(String name, String password, String token) { validateName(name); this.name = name; this.password = new Password(password); this.token = token; + this.account = ""; } private void validateName(String name) { int nameLength = name.trim().length(); if (nameLength < MIN_NAME_LENGTH || MAX_NAME_LENGTH < nameLength) { - throw new HaengdongException(HaengdongErrorCode.EVENT_NAME_LENGTH_INVALID, - String.format("행사 이름은 %d자 이상 %d자 이하만 입력 가능합니다. 입력한 이름 길이 : %d", - MIN_NAME_LENGTH, - MAX_NAME_LENGTH, - name.length())); + throw new HaengdongException(HaengdongErrorCode.EVENT_NAME_LENGTH_INVALID); } if (isBlankContinuous(name)) { - throw new HaengdongException(HaengdongErrorCode.EVENT_NAME_CONSECUTIVE_SPACES, - String.format("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s", name)); + throw new HaengdongException(HaengdongErrorCode.EVENT_NAME_CONSECUTIVE_SPACES); } } @@ -69,4 +71,26 @@ public boolean isTokenMismatch(String token) { public boolean isPasswordMismatch(String rawPassword) { return !password.matches(rawPassword); } + + public void rename(String name) { + validateName(name); + this.name = name; + } + + public void changeAccount(String bankName, String accountNumber) { + validateBankName(bankName); + validateAccountNumber(accountNumber); + this.account = bankName + " " + accountNumber; + } + + private void validateBankName(String bankName) { + Bank.isExists(bankName); + } + + private void validateAccountNumber(String accountNumber) { + int accountLength = accountNumber.trim().length(); + if (accountLength < MIN_ACCOUNT_NUMBER_LENGTH || MAX_ACCOUNT_NUMBER_LENGTH < accountLength) { + throw new HaengdongException(HaengdongErrorCode.ACCOUNT_LENGTH_INVALID); + } + } } diff --git a/server/src/main/java/server/haengdong/domain/event/EventImage.java b/server/src/main/java/server/haengdong/domain/event/EventImage.java new file mode 100644 index 000000000..cc5aad0dd --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/event/EventImage.java @@ -0,0 +1,30 @@ +package server.haengdong.domain.event; + +import jakarta.persistence.Column; +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 lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class EventImage { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @JoinColumn(name = "event_id", nullable = false) + @ManyToOne(fetch = FetchType.LAZY) + private Event event; + + @Column(nullable = false) + private String url; +} diff --git a/server/src/main/java/server/haengdong/domain/member/Member.java b/server/src/main/java/server/haengdong/domain/member/Member.java new file mode 100644 index 000000000..d569915e1 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/member/Member.java @@ -0,0 +1,79 @@ +package server.haengdong.domain.member; + +import jakarta.persistence.Column; +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 jakarta.persistence.UniqueConstraint; +import java.util.Objects; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.domain.event.Event; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"event_id", "name"})}) +@Entity +public class Member { + + public static final int MIN_NAME_LENGTH = 1; + public static final int MAX_NAME_LENGTH = 8; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @JoinColumn(name = "event_id", nullable = false) + @ManyToOne(fetch = FetchType.LAZY) + private Event event; + + @Column(nullable = false, length = MAX_NAME_LENGTH) + private String name; + + @Column(nullable = false) + private boolean isDeposited; + + public Member(Event event, String name) { + this(null, event, name, false); + } + + public Member(Long id, Event event, String name, boolean isDeposited) { + validateName(name); + this.id = id; + this.event = event; + this.name = name; + this.isDeposited = isDeposited; + } + + private void validateName(String name) { + int nameLength = name.length(); + if (nameLength < MIN_NAME_LENGTH || nameLength > MAX_NAME_LENGTH) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_LENGTH_INVALID); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Member member = (Member) o; + return Objects.equals(id, member.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/server/src/main/java/server/haengdong/domain/member/MemberBillReport.java b/server/src/main/java/server/haengdong/domain/member/MemberBillReport.java new file mode 100644 index 000000000..25a7d165d --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/member/MemberBillReport.java @@ -0,0 +1,31 @@ +package server.haengdong.domain.member; + +import static java.util.stream.Collectors.toMap; + +import java.util.List; +import java.util.Map; +import lombok.Getter; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.bill.BillDetail; + +@Getter +public class MemberBillReport { + + private final Map reports; + + private MemberBillReport(Map reports) { + this.reports = reports; + } + + public static MemberBillReport createByBills(List bills) { + Map reports = bills.stream() + .flatMap(bill -> bill.getBillDetails().stream()) + .collect(toMap( + BillDetail::getMember, + BillDetail::getPrice, + Long::sum + )); + + return new MemberBillReport(reports); + } +} diff --git a/server/src/main/java/server/haengdong/domain/member/MemberRepository.java b/server/src/main/java/server/haengdong/domain/member/MemberRepository.java new file mode 100644 index 000000000..15d57f4ba --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/member/MemberRepository.java @@ -0,0 +1,10 @@ +package server.haengdong.domain.member; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import server.haengdong.domain.event.Event; + +public interface MemberRepository extends JpaRepository { + + List findAllByEvent(Event event); +} diff --git a/server/src/main/java/server/haengdong/domain/step/Step.java b/server/src/main/java/server/haengdong/domain/step/Step.java new file mode 100644 index 000000000..834d3e715 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/step/Step.java @@ -0,0 +1,50 @@ +package server.haengdong.domain.step; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.member.Member; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +public class Step { + + private final List bills; + private final Set members; + + private Step(List bills, Set members) { + this.bills = bills; + this.members = members; + } + + public static Step of(Bill bill) { + List bills = new ArrayList<>(); + bills.add(bill); + Set members = new HashSet<>(bill.getMembers()); + + return new Step(bills, members); + } + + public void add(Bill bill) { + if (isNotSameMember(bill)) { + throw new HaengdongException(HaengdongErrorCode.DIFFERENT_STEP_MEMBERS); + } + + bills.add(bill); + } + + public boolean isNotSameMember(Bill bill) { + Set otherMembers = Set.copyOf(bill.getMembers()); + return !members.equals(otherMembers); + } + + public List getBills() { + return bills; + } + + public Set getMembers() { + return members; + } +} diff --git a/server/src/main/java/server/haengdong/domain/step/Steps.java b/server/src/main/java/server/haengdong/domain/step/Steps.java new file mode 100644 index 000000000..f1ad8c746 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/step/Steps.java @@ -0,0 +1,33 @@ +package server.haengdong.domain.step; + +import java.util.ArrayList; +import java.util.List; +import server.haengdong.domain.bill.Bill; + +public class Steps { + + private final List steps; + + private Steps(List steps) { + this.steps = steps; + } + + public static Steps of(List bills) { + List steps = new ArrayList<>(); + Step currentStep = null; + + for (Bill bill : bills) { + if (currentStep == null || currentStep.isNotSameMember(bill)) { + currentStep = Step.of(bill); + steps.add(currentStep); + continue; + } + currentStep.add(bill); + } + return new Steps(steps); + } + + public List getSteps() { + return steps; + } +} diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java index 475d16c11..e320a77d4 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -1,8 +1,9 @@ package server.haengdong.exception; import lombok.Getter; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.MemberAction; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.member.Member; +import server.haengdong.domain.event.Bank; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.Password; @@ -15,29 +16,31 @@ public enum HaengdongErrorCode { EVENT_NAME_LENGTH_INVALID(String.format("행사 이름은 %d자 이상 %d자 이하만 입력 가능합니다.", Event.MIN_NAME_LENGTH, Event.MAX_NAME_LENGTH)), - EVENT_NAME_CONSECUTIVE_SPACES("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s"), + EVENT_NAME_CONSECUTIVE_SPACES("행사 이름에는 공백 문자가 연속될 수 없습니다."), EVENT_PASSWORD_FORMAT_INVALID(String.format("비밀번호는 %d자리 숫자만 가능합니다.", Password.PASSWORD_LENGTH)), - - ACTION_NOT_FOUND("존재하지 않는 액션입니다."), + BANK_NAME_INVALID(String.format("지원하지 않는 은행입니다. 지원하는 은행 목록: %s", + Bank.getSupportedBanks())), + ACCOUNT_LENGTH_INVALID(String.format("계좌번호는 %d자 이상 %d자 이하만 입력 가능합니다.", + Event.MIN_ACCOUNT_NUMBER_LENGTH, + Event.MAX_ACCOUNT_NUMBER_LENGTH)), MEMBER_NAME_LENGTH_INVALID(String.format("멤버 이름은 %d자 이상 %d자 이하만 입력 가능합니다.", - MemberAction.MIN_NAME_LENGTH, - MemberAction.MAX_NAME_LENGTH)), + Member.MIN_NAME_LENGTH, + Member.MAX_NAME_LENGTH)), MEMBER_NAME_DUPLICATE("중복된 행사 참여 인원 이름이 존재합니다."), - MEMBER_NOT_EXIST("현재 참여하고 있지 않는 인원이 존재합니다."), + MEMBER_NOT_FOUND("존재하지 않는 참여자입니다."), MEMBER_ALREADY_EXIST("현재 참여하고 있는 인원이 존재합니다."), MEMBER_NAME_CHANGE_DUPLICATE("중복된 참여 인원 이름 변경 요청이 존재합니다."), - MEMBER_ACTION_NOT_FOUND("존재하지 않는 멤버 액션입니다."), - MEMBER_ACTION_STATUS_INVALID("멤버 액션은 IN, OUT만 가능합니다. 입력한 멤버 액션: %s"), + BILL_NOT_FOUND("존재하지 않는 지출입니다."), + BILL_TITLE_INVALID(String.format("앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다.", + Bill.MIN_TITLE_LENGTH, + Bill.MAX_TITLE_LENGTH)), + BILL_PRICE_INVALID(String.format("지출 금액은 %,d 이하의 자연수여야 합니다.", Bill.MAX_PRICE)), + BILL_DETAIL_NOT_FOUND("존재하지 않는 참여자 지출입니다."), + BILL_PRICE_NOT_MATCHED("지출 총액이 일치하지 않습니다."), - BILL_ACTION_NOT_FOUND("존재하지 않는 지출 액션입니다."), - BILL_ACTION_TITLE_INVALID(String.format("앞뒤 공백을 제거한 지출 내역 제목은 %d ~ %d자여야 합니다.", - BillAction.MIN_TITLE_LENGTH, - BillAction.MAX_TITLE_LENGTH)), - BILL_ACTION_PRICE_INVALID(String.format("지출 금액은 %,d 이하의 자연수여야 합니다.", BillAction.MAX_PRICE)), - BILL_ACTION_DETAIL_NOT_FOUND("존재하지 않는 참여자 지출입니다."), - BILL_ACTION_PRICE_NOT_MATCHED("지출 총액이 일치하지 않습니다."), + DIFFERENT_STEP_MEMBERS("회원 목록이 일치하지 않습니다."), /* Authentication */ diff --git a/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java b/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java deleted file mode 100644 index 924bcf32c..000000000 --- a/server/src/main/java/server/haengdong/presentation/BillActionDetailController.java +++ /dev/null @@ -1,27 +0,0 @@ -package server.haengdong.presentation; - -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.BillActionDetailService; -import server.haengdong.application.response.BillActionDetailsAppResponse; -import server.haengdong.presentation.response.BillActionDetailsResponse; - -@RequiredArgsConstructor -@RestController -public class BillActionDetailController { - - private final BillActionDetailService billActionDetailService; - - @GetMapping("/api/events/{eventId}/bill-actions/{actionId}/fixed") - public ResponseEntity findBillActionDetails( - @PathVariable("eventId") String token, - @PathVariable("actionId") Long actionId - ) { - BillActionDetailsAppResponse appResponse = billActionDetailService.findBillActionDetails(token, actionId); - - return ResponseEntity.ok(BillActionDetailsResponse.of(appResponse)); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/BillController.java b/server/src/main/java/server/haengdong/presentation/BillController.java new file mode 100644 index 000000000..f1a4f74f4 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/BillController.java @@ -0,0 +1,35 @@ +package server.haengdong.presentation; + +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.BillService; +import server.haengdong.application.response.BillDetailsAppResponse; +import server.haengdong.presentation.response.BillDetailsResponse; +import server.haengdong.presentation.response.StepsResponse; + +@RequiredArgsConstructor +@RestController +public class BillController { + + private final BillService billService; + + @GetMapping("/api/events/{eventId}/bills") + public ResponseEntity findBills(@PathVariable("eventId") String token) { + StepsResponse stepsResponse = StepsResponse.of(billService.findSteps(token)); + + return ResponseEntity.ok(stepsResponse); + } + + @GetMapping("/api/events/{eventId}/bills/{billId}/details") + public ResponseEntity findBillDetails( + @PathVariable("eventId") String token, + @PathVariable("billId") Long billId + ) { + BillDetailsAppResponse appResponse = billService.findBillDetails(token, billId); + + return ResponseEntity.ok(BillDetailsResponse.of(appResponse)); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index af725864d..77caa744a 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -15,17 +15,13 @@ 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.application.response.MemberBillReportAppResponse; import server.haengdong.infrastructure.auth.CookieProperties; import server.haengdong.presentation.request.EventLoginRequest; import server.haengdong.presentation.request.EventSaveRequest; -import server.haengdong.presentation.response.ActionsResponse; import server.haengdong.presentation.response.EventDetailResponse; import server.haengdong.presentation.response.EventResponse; import server.haengdong.presentation.response.MemberBillReportsResponse; -import server.haengdong.presentation.response.MembersResponse; -import server.haengdong.presentation.response.StepsResponse; @Slf4j @RequiredArgsConstructor @@ -44,28 +40,6 @@ public ResponseEntity findEvent(@PathVariable("eventId") St return ResponseEntity.ok(eventDetailResponse); } - @GetMapping("/api/events/{eventId}/actions") - public ResponseEntity findActions(@PathVariable("eventId") String token) { - StepsResponse stepsResponse = StepsResponse.of(eventService.findActions(token)); - - 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)); - - return ResponseEntity.ok(response); - } - @GetMapping("/api/events/{eventId}/reports") public ResponseEntity getMemberBillReports(@PathVariable("eventId") String token) { List memberBillReports = eventService.getMemberBillReports(token); diff --git a/server/src/main/java/server/haengdong/presentation/MemberActionController.java b/server/src/main/java/server/haengdong/presentation/MemberController.java similarity index 51% rename from server/src/main/java/server/haengdong/presentation/MemberActionController.java rename to server/src/main/java/server/haengdong/presentation/MemberController.java index 3a20339fd..f5662f9b2 100644 --- a/server/src/main/java/server/haengdong/presentation/MemberActionController.java +++ b/server/src/main/java/server/haengdong/presentation/MemberController.java @@ -2,23 +2,33 @@ import java.util.List; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; 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.MemberActionService; -import server.haengdong.application.response.CurrentMemberAppResponse; +import server.haengdong.application.MemberService; +import server.haengdong.application.response.MemberAppResponse; import server.haengdong.presentation.response.CurrentMembersResponse; +import server.haengdong.presentation.response.MembersResponse; +@Slf4j @RequiredArgsConstructor @RestController -public class MemberActionController { +public class MemberController { - private final MemberActionService memberActionService; + private final MemberService memberService; + + @GetMapping("/api/events/{eventId}/members") + public ResponseEntity findAllMembers(@PathVariable("eventId") String token) { + MembersResponse response = MembersResponse.of(memberService.findAllMembers(token)); + + return ResponseEntity.ok(response); + } @GetMapping("/api/events/{eventId}/members/current") public ResponseEntity getCurrentMembers(@PathVariable("eventId") String token) { - List currentMembers = memberActionService.getCurrentMembers(token); + List currentMembers = memberService.getCurrentMembers(token); return ResponseEntity.ok() .body(CurrentMembersResponse.of(currentMembers)); diff --git a/server/src/main/java/server/haengdong/presentation/admin/AdminBillActionController.java b/server/src/main/java/server/haengdong/presentation/admin/AdminBillActionController.java deleted file mode 100644 index f3e66cdb9..000000000 --- a/server/src/main/java/server/haengdong/presentation/admin/AdminBillActionController.java +++ /dev/null @@ -1,66 +0,0 @@ -package server.haengdong.presentation.admin; - -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -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.RestController; -import server.haengdong.application.BillActionDetailService; -import server.haengdong.application.BillActionService; -import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; -import server.haengdong.presentation.request.BillActionUpdateRequest; -import server.haengdong.presentation.request.BillActionsSaveRequest; - -@RequiredArgsConstructor -@RestController -public class AdminBillActionController { - - private final BillActionService billActionService; - private final BillActionDetailService billActionDetailService; - - @PostMapping("/api/admin/events/{eventId}/bill-actions") - public ResponseEntity saveAllBillAction( - @PathVariable("eventId") String token, - @Valid @RequestBody BillActionsSaveRequest request - ) { - billActionService.saveAllBillAction(token, request.toAppRequests()); - - return ResponseEntity.ok().build(); - } - - @PutMapping("/api/admin/events/{eventId}/bill-actions/{actionId}") - public ResponseEntity updateBillAction( - @PathVariable("eventId") String token, - @PathVariable("actionId") Long actionId, - @Valid @RequestBody BillActionUpdateRequest request - ) { - billActionService.updateBillAction(token, actionId, request.toAppResponse()); - - return ResponseEntity.ok().build(); - } - - @PutMapping("/api/admin/events/{eventId}/bill-actions/{actionId}/fixed") - public ResponseEntity updateBillActionDetails( - @PathVariable("eventId") String token, - @PathVariable("actionId") Long actionId, - @Valid @RequestBody BillActionDetailsUpdateRequest request - ) { - billActionDetailService.updateBillActionDetails(token, actionId, request.toAppRequest()); - - return ResponseEntity.ok().build(); - } - - @DeleteMapping("/api/admin/events/{eventId}/bill-actions/{actionId}") - public ResponseEntity deleteBillAction( - @PathVariable("eventId") String token, - @PathVariable("actionId") Long actionId - ) { - billActionService.deleteBillAction(token, actionId); - - return ResponseEntity.ok().build(); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/admin/AdminBillController.java b/server/src/main/java/server/haengdong/presentation/admin/AdminBillController.java new file mode 100644 index 000000000..5e65c04f9 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/admin/AdminBillController.java @@ -0,0 +1,64 @@ +package server.haengdong.presentation.admin; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +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.RestController; +import server.haengdong.application.BillService; +import server.haengdong.presentation.request.BillDetailsUpdateRequest; +import server.haengdong.presentation.request.BillSaveRequest; +import server.haengdong.presentation.request.BillUpdateRequest; + +@RequiredArgsConstructor +@RestController +public class AdminBillController { + + private final BillService billService; + + @PostMapping("/api/admin/events/{eventId}/bills") + public ResponseEntity saveAllBill( + @PathVariable("eventId") String token, + @Valid @RequestBody BillSaveRequest request + ) { + billService.saveBill(token, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } + + @DeleteMapping("/api/admin/events/{eventId}/bills/{billId}") + public ResponseEntity deleteBill( + @PathVariable("eventId") String token, + @PathVariable("billId") Long billId + ) { + billService.deleteBill(token, billId); + + return ResponseEntity.ok().build(); + } + + @PutMapping("/api/admin/events/{eventId}/bills/{billId}") + public ResponseEntity updateBill( + @PathVariable("eventId") String token, + @PathVariable("billId") Long billId, + @Valid @RequestBody BillUpdateRequest request + ) { + billService.updateBill(token, billId, request.toAppResponse()); + + return ResponseEntity.ok().build(); + } + + @PutMapping("/api/admin/events/{eventId}/bills/{billId}/details") + public ResponseEntity updateBillDetails( + @PathVariable("eventId") String token, + @PathVariable("billId") Long billId, + @Valid @RequestBody BillDetailsUpdateRequest request + ) { + billService.updateBillDetails(token, billId, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/admin/AdminEventController.java b/server/src/main/java/server/haengdong/presentation/admin/AdminEventController.java index aa4a8a278..46d11cdd5 100644 --- a/server/src/main/java/server/haengdong/presentation/admin/AdminEventController.java +++ b/server/src/main/java/server/haengdong/presentation/admin/AdminEventController.java @@ -3,36 +3,33 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; 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.RestController; import server.haengdong.application.EventService; -import server.haengdong.infrastructure.auth.CookieProperties; -import server.haengdong.presentation.request.MemberNamesUpdateRequest; +import server.haengdong.presentation.request.EventUpdateRequest; @Slf4j @RequiredArgsConstructor -@EnableConfigurationProperties(CookieProperties.class) @RestController public class AdminEventController { private final EventService eventService; @PostMapping("/api/admin/events/{eventId}/auth") - public ResponseEntity authenticate(@PathVariable("eventId") String token) { + public ResponseEntity authenticate() { return ResponseEntity.ok().build(); } - @PutMapping("/api/admin/events/{eventId}/members/nameChange") - public ResponseEntity updateMember( + @PatchMapping("/api/admin/events/{eventId}") + public ResponseEntity updateEvent( @PathVariable("eventId") String token, - @Valid @RequestBody MemberNamesUpdateRequest request + @Valid @RequestBody EventUpdateRequest request ) { - eventService.updateMember(token, request.toAppRequest()); + eventService.updateEvent(token, request.toAppRequest()); return ResponseEntity.ok().build(); } diff --git a/server/src/main/java/server/haengdong/presentation/admin/AdminMemberActionController.java b/server/src/main/java/server/haengdong/presentation/admin/AdminMemberActionController.java deleted file mode 100644 index c45f18405..000000000 --- a/server/src/main/java/server/haengdong/presentation/admin/AdminMemberActionController.java +++ /dev/null @@ -1,48 +0,0 @@ -package server.haengdong.presentation.admin; - -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; -import server.haengdong.application.MemberActionService; -import server.haengdong.presentation.request.MemberActionsSaveRequest; - -@RequiredArgsConstructor -@RestController -public class AdminMemberActionController { - - private final MemberActionService memberActionService; - - @PostMapping("/api/admin/events/{eventId}/member-actions") - public ResponseEntity saveMemberAction( - @PathVariable("eventId") String token, - @RequestBody MemberActionsSaveRequest request - ) { - memberActionService.saveMemberAction(token, request.toAppRequest()); - - return ResponseEntity.ok().build(); - } - - @DeleteMapping("/api/admin/events/{eventId}/members/{memberName}") - public ResponseEntity deleteMember( - @PathVariable("eventId") String token, - @PathVariable("memberName") String memberName - ) { - memberActionService.deleteMember(token, memberName); - - return ResponseEntity.ok().build(); - } - - @DeleteMapping("/api/admin/events/{eventId}/member-actions/{actionId}") - public ResponseEntity deleteMemberAction( - @PathVariable("eventId") String token, - @PathVariable("actionId") Long actionId - ) { - memberActionService.deleteMemberAction(token, actionId); - - return ResponseEntity.ok().build(); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/admin/AdminMemberController.java b/server/src/main/java/server/haengdong/presentation/admin/AdminMemberController.java new file mode 100644 index 000000000..22cb0190a --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/admin/AdminMemberController.java @@ -0,0 +1,55 @@ +package server.haengdong.presentation.admin; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +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.RestController; +import server.haengdong.application.MemberService; +import server.haengdong.application.response.MembersSaveAppResponse; +import server.haengdong.presentation.request.MembersSaveRequest; +import server.haengdong.presentation.request.MembersUpdateRequest; +import server.haengdong.presentation.response.MembersSaveResponse; + +@Slf4j +@RequiredArgsConstructor +@RestController +public class AdminMemberController { + + private final MemberService memberService; + + @PostMapping("/api/admin/events/{eventId}/members") + public ResponseEntity saveMembers( + @PathVariable("eventId") String token, + @Valid @RequestBody MembersSaveRequest request + ) { + MembersSaveAppResponse response = memberService.saveMembers(token, request.toAppRequest()); + + return ResponseEntity.ok(MembersSaveResponse.of(response)); + } + + @PutMapping("/api/admin/events/{eventId}/members") + public ResponseEntity updateMembers( + @PathVariable("eventId") String token, + @Valid @RequestBody MembersUpdateRequest request + ) { + memberService.updateMembers(token, request.toAppRequest()); + + return ResponseEntity.ok().build(); + } + + @DeleteMapping("/api/admin/events/{eventId}/members/{memberId}") + public ResponseEntity deleteMember( + @PathVariable("eventId") String token, + @PathVariable("memberId") Long memberId + ) { + memberService.deleteMember(token, memberId); + + return ResponseEntity.ok().build(); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java deleted file mode 100644 index 21c4bd60f..000000000 --- a/server/src/main/java/server/haengdong/presentation/request/BillActionDetailUpdateRequest.java +++ /dev/null @@ -1,21 +0,0 @@ -package server.haengdong.presentation.request; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import server.haengdong.application.request.BillActionDetailUpdateAppRequest; - -public record BillActionDetailUpdateRequest( - - @NotBlank(message = "맴버 이름은 공백일 수 없습니다.") - String name, - - @NotNull(message = "지출 금액은 공백일 수 없습니다.") - Long price, - - @NotNull(message = "지출 금액은 공백일 수 없습니다.") - boolean isFixed -) { - public BillActionDetailUpdateAppRequest toAppRequest() { - return new BillActionDetailUpdateAppRequest(this.name, this.price, this.isFixed); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java deleted file mode 100644 index fafbb8fd7..000000000 --- a/server/src/main/java/server/haengdong/presentation/request/BillActionDetailsUpdateRequest.java +++ /dev/null @@ -1,16 +0,0 @@ -package server.haengdong.presentation.request; - -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotEmpty; -import java.util.List; -import server.haengdong.application.request.BillActionDetailsUpdateAppRequest; - -public record BillActionDetailsUpdateRequest( - @Valid @NotEmpty List members -) { - public BillActionDetailsUpdateAppRequest toAppRequest() { - return new BillActionDetailsUpdateAppRequest(members.stream() - .map(BillActionDetailUpdateRequest::toAppRequest) - .toList()); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java deleted file mode 100644 index 6727d4cf1..000000000 --- a/server/src/main/java/server/haengdong/presentation/request/BillActionsSaveRequest.java +++ /dev/null @@ -1,18 +0,0 @@ -package server.haengdong.presentation.request; - -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotEmpty; -import java.util.List; -import server.haengdong.application.request.BillActionAppRequest; - -public record BillActionsSaveRequest( - - @Valid @NotEmpty List actions -) { - - public List toAppRequests() { - return actions.stream() - .map(BillActionSaveRequest::toAppRequest) - .toList(); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillDetailUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillDetailUpdateRequest.java new file mode 100644 index 000000000..accaf8e00 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillDetailUpdateRequest.java @@ -0,0 +1,20 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotNull; +import server.haengdong.application.request.BillDetailUpdateAppRequest; + +public record BillDetailUpdateRequest( + + @NotNull(message = "지출 상세 ID는 공백일 수 없습니다.") + Long id, + + @NotNull(message = "지출 금액은 공백일 수 없습니다.") + Long price, + + @NotNull(message = "지출 금액은 공백일 수 없습니다.") + boolean isFixed +) { + public BillDetailUpdateAppRequest toAppRequest() { + return new BillDetailUpdateAppRequest(this.id, this.price, this.isFixed); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillDetailsUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillDetailsUpdateRequest.java new file mode 100644 index 000000000..f09d101bd --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/BillDetailsUpdateRequest.java @@ -0,0 +1,16 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import java.util.List; +import server.haengdong.application.request.BillDetailsUpdateAppRequest; + +public record BillDetailsUpdateRequest( + @Valid @NotEmpty List billDetails +) { + public BillDetailsUpdateAppRequest toAppRequest() { + return new BillDetailsUpdateAppRequest(billDetails.stream() + .map(BillDetailUpdateRequest::toAppRequest) + .toList()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillSaveRequest.java similarity index 50% rename from server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java rename to server/src/main/java/server/haengdong/presentation/request/BillSaveRequest.java index 680006816..1a7365a6e 100644 --- a/server/src/main/java/server/haengdong/presentation/request/BillActionUpdateRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/BillSaveRequest.java @@ -1,18 +1,24 @@ package server.haengdong.presentation.request; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; -import server.haengdong.application.request.BillActionUpdateAppRequest; +import java.util.List; +import server.haengdong.application.request.BillAppRequest; -public record BillActionUpdateRequest( +public record BillSaveRequest( @NotBlank(message = "지출 내역 제목은 공백일 수 없습니다.") String title, @NotNull(message = "지출 금액은 공백일 수 없습니다.") - Long price + Long price, + + @NotEmpty + List memberIds ) { - public BillActionUpdateAppRequest toAppResponse() { - return new BillActionUpdateAppRequest(title, price); + + public BillAppRequest toAppRequest() { + return new BillAppRequest(title, price, memberIds); } } diff --git a/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/BillUpdateRequest.java similarity index 63% rename from server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java rename to server/src/main/java/server/haengdong/presentation/request/BillUpdateRequest.java index a47ff8316..a37c75013 100644 --- a/server/src/main/java/server/haengdong/presentation/request/BillActionSaveRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/BillUpdateRequest.java @@ -2,9 +2,9 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import server.haengdong.application.request.BillActionAppRequest; +import server.haengdong.application.request.BillUpdateAppRequest; -public record BillActionSaveRequest( +public record BillUpdateRequest( @NotBlank(message = "지출 내역 제목은 공백일 수 없습니다.") String title, @@ -12,8 +12,7 @@ public record BillActionSaveRequest( @NotNull(message = "지출 금액은 공백일 수 없습니다.") Long price ) { - - public BillActionAppRequest toAppRequest() { - return new BillActionAppRequest(title, price); + public BillUpdateAppRequest toAppResponse() { + return new BillUpdateAppRequest(title, price); } } diff --git a/server/src/main/java/server/haengdong/presentation/request/EventUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/EventUpdateRequest.java new file mode 100644 index 000000000..cafd12ea6 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/EventUpdateRequest.java @@ -0,0 +1,14 @@ +package server.haengdong.presentation.request; + +import server.haengdong.application.request.EventUpdateAppRequest; + +public record EventUpdateRequest( + String eventName, + String bankName, + String accountNumber +) { + + public EventUpdateAppRequest toAppRequest() { + return new EventUpdateAppRequest(eventName, bankName, accountNumber); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java deleted file mode 100644 index 41e95cc3c..000000000 --- a/server/src/main/java/server/haengdong/presentation/request/MemberActionsSaveRequest.java +++ /dev/null @@ -1,25 +0,0 @@ -package server.haengdong.presentation.request; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotEmpty; -import java.util.List; -import server.haengdong.application.request.MemberActionSaveAppRequest; -import server.haengdong.application.request.MemberActionsSaveAppRequest; - -public record MemberActionsSaveRequest( - - @NotEmpty - List members, - - @NotBlank(message = "멤버 액션은 공백일 수 없습니다.") - String status -) { - - public MemberActionsSaveAppRequest toAppRequest() { - List appRequests = members.stream() - .map(name -> new MemberActionSaveAppRequest(name, status)) - .toList(); - - return new MemberActionsSaveAppRequest(appRequests); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java index 3cd2294ca..fb1ff655f 100644 --- a/server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/MemberNameUpdateRequest.java @@ -1,18 +1,19 @@ package server.haengdong.presentation.request; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import server.haengdong.application.request.MemberNameUpdateAppRequest; public record MemberNameUpdateRequest( - @NotBlank(message = "멤버 이름은 공백일 수 없습니다.") - String before, + @NotNull(message = "멤버 id는 공백일 수 없습니다.") + Long id, @NotBlank(message = "멤버 이름은 공백일 수 없습니다.") - String after + String name ) { public MemberNameUpdateAppRequest toAppRequest() { - return new MemberNameUpdateAppRequest(before, after); + return new MemberNameUpdateAppRequest(id, name); } } diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java index 872aa55de..79c46590d 100644 --- a/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/MemberNamesUpdateRequest.java @@ -6,12 +6,15 @@ import server.haengdong.application.request.MemberNamesUpdateAppRequest; public record MemberNamesUpdateRequest( - @Valid @NotEmpty List members + @Valid + @NotEmpty + List members ) { public MemberNamesUpdateAppRequest toAppRequest() { return new MemberNamesUpdateAppRequest(members.stream() - .map(MemberNameUpdateRequest::toAppRequest) - .toList()); + .map(MemberNameUpdateRequest::toAppRequest) + .toList() + ); } } diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberSaveRequest.java new file mode 100644 index 000000000..f1d75e1b1 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberSaveRequest.java @@ -0,0 +1,4 @@ +package server.haengdong.presentation.request; + +public record MemberSaveRequest(String name) { +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java new file mode 100644 index 000000000..1f3bfe95a --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MemberUpdateRequest.java @@ -0,0 +1,22 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import server.haengdong.application.request.MemberUpdateAppRequest; + +public record MemberUpdateRequest( + + @NotNull(message = "멤버 ID는 공백일 수 없습니다.") + Long id, + + @NotBlank(message = "멤버 이름은 공백일 수 없습니다.") + String name, + + @NotNull(message = "입금 여부는 공백일 수 없습니다.") + boolean isDeposited +) { + + public MemberUpdateAppRequest toAppRequest() { + return new MemberUpdateAppRequest(id, name, isDeposited); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MembersSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/MembersSaveRequest.java new file mode 100644 index 000000000..c5e2100fd --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MembersSaveRequest.java @@ -0,0 +1,14 @@ +package server.haengdong.presentation.request; + +import java.util.List; +import server.haengdong.application.request.MemberSaveAppRequest; +import server.haengdong.application.request.MembersSaveAppRequest; + +public record MembersSaveRequest(List members) { + public MembersSaveAppRequest toAppRequest() { + return new MembersSaveAppRequest(members.stream() + .map(member -> new MemberSaveAppRequest(member.name())) + .toList()); + + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/MembersUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/MembersUpdateRequest.java new file mode 100644 index 000000000..db3715130 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/MembersUpdateRequest.java @@ -0,0 +1,20 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import java.util.List; +import server.haengdong.application.request.MembersUpdateAppRequest; + +public record MembersUpdateRequest( + + @Valid + @NotNull + List members +) { + + public MembersUpdateAppRequest toAppRequest() { + return new MembersUpdateAppRequest(members.stream() + .map(MemberUpdateRequest::toAppRequest) + .toList()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java b/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java deleted file mode 100644 index ea26ea769..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/ActionResponse.java +++ /dev/null @@ -1,26 +0,0 @@ -package server.haengdong.presentation.response; - -import server.haengdong.application.response.ActionAppResponse; - -public record ActionResponse( - Long actionId, - String name, - Long price, - Long sequence, - boolean isFixed -) { - - public ActionResponse(Long actionId, String name, Long price, Long sequence) { - this(actionId, name, price, sequence, false); - } - - public static ActionResponse of(ActionAppResponse actionAppResponse) { - return new ActionResponse( - actionAppResponse.actionId(), - actionAppResponse.name(), - actionAppResponse.price(), - actionAppResponse.sequence(), - actionAppResponse.isFixed() - ); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java b/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java deleted file mode 100644 index ea46c5bd9..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/ActionResponse2.java +++ /dev/null @@ -1,22 +0,0 @@ -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 deleted file mode 100644 index c8ae780e3..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/ActionsResponse.java +++ /dev/null @@ -1,14 +0,0 @@ -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/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java deleted file mode 100644 index 10f71b82e..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/BillActionDetailResponse.java +++ /dev/null @@ -1,18 +0,0 @@ -package server.haengdong.presentation.response; - -import server.haengdong.application.response.BillActionDetailAppResponse; - -public record BillActionDetailResponse( - String name, - Long price, - boolean isFixed -) { - - public static BillActionDetailResponse of(BillActionDetailAppResponse billActionDetailAppResponse) { - return new BillActionDetailResponse( - billActionDetailAppResponse.name(), - billActionDetailAppResponse.price(), - billActionDetailAppResponse.isFixed() - ); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java b/server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java deleted file mode 100644 index 182e76db6..000000000 --- a/server/src/main/java/server/haengdong/presentation/response/BillActionDetailsResponse.java +++ /dev/null @@ -1,16 +0,0 @@ -package server.haengdong.presentation.response; - -import java.util.List; -import java.util.stream.Collectors; -import server.haengdong.application.response.BillActionDetailsAppResponse; - -public record BillActionDetailsResponse( - List members -) { - - public static BillActionDetailsResponse of(BillActionDetailsAppResponse billActionDetailsAppResponse) { - return billActionDetailsAppResponse.billActionDetailAppResponses().stream() - .map(BillActionDetailResponse::of) - .collect(Collectors.collectingAndThen(Collectors.toList(), BillActionDetailsResponse::new)); - } -} diff --git a/server/src/main/java/server/haengdong/presentation/response/BillDetailResponse.java b/server/src/main/java/server/haengdong/presentation/response/BillDetailResponse.java new file mode 100644 index 000000000..9ff993b8a --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/BillDetailResponse.java @@ -0,0 +1,20 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.BillDetailAppResponse; + +public record BillDetailResponse( + Long id, + String memberName, + Long price, + boolean isFixed +) { + + public static BillDetailResponse of(BillDetailAppResponse billDetailAppResponse) { + return new BillDetailResponse( + billDetailAppResponse.id(), + billDetailAppResponse.memberName(), + billDetailAppResponse.price(), + billDetailAppResponse.isFixed() + ); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/BillDetailsResponse.java b/server/src/main/java/server/haengdong/presentation/response/BillDetailsResponse.java new file mode 100644 index 000000000..888b0160d --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/BillDetailsResponse.java @@ -0,0 +1,16 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import java.util.stream.Collectors; +import server.haengdong.application.response.BillDetailsAppResponse; + +public record BillDetailsResponse( + List members +) { + + public static BillDetailsResponse of(BillDetailsAppResponse billDetailsAppResponse) { + return billDetailsAppResponse.billDetails().stream() + .map(BillDetailResponse::of) + .collect(Collectors.collectingAndThen(Collectors.toList(), BillDetailsResponse::new)); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/BillResponse.java b/server/src/main/java/server/haengdong/presentation/response/BillResponse.java new file mode 100644 index 000000000..8b79896bb --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/BillResponse.java @@ -0,0 +1,14 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.BillAppResponse; + +public record BillResponse( + Long id, + String title, + Long price, + boolean isFixed +) { + public static BillResponse of(BillAppResponse response) { + return new BillResponse(response.id(), response.title(), response.price(), response.isFixed()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java b/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java index 289cca4fa..b1fe5720b 100644 --- a/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/CurrentMembersResponse.java @@ -1,13 +1,14 @@ package server.haengdong.presentation.response; import java.util.List; -import server.haengdong.application.response.CurrentMemberAppResponse; +import server.haengdong.application.response.LastBillMemberAppResponse; +import server.haengdong.application.response.MemberAppResponse; -public record CurrentMembersResponse(List memberNames) { +public record CurrentMembersResponse(List members) { - public static CurrentMembersResponse of(List currentMembers) { - List responses = currentMembers.stream() - .map(CurrentMemberAppResponse::name) + public static CurrentMembersResponse of(List currentMembers) { + List responses = currentMembers.stream() + .map(MemberResponse::of) .toList(); return new CurrentMembersResponse(responses); diff --git a/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java b/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java index c18694393..c03ae8178 100644 --- a/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/EventDetailResponse.java @@ -2,9 +2,12 @@ import server.haengdong.application.response.EventDetailAppResponse; -public record EventDetailResponse(String eventName) { +public record EventDetailResponse( + String eventName, + String account +) { public static EventDetailResponse of(EventDetailAppResponse response) { - return new EventDetailResponse(response.eventName()); + return new EventDetailResponse(response.eventName(), response.account()); } } diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java index 0ea409202..1ab22b83e 100644 --- a/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/MemberBillReportResponse.java @@ -2,9 +2,19 @@ import server.haengdong.application.response.MemberBillReportAppResponse; -public record MemberBillReportResponse(String name, Long price) { +public record MemberBillReportResponse( + Long memberId, + String memberName, + boolean isDeposited, + Long price +) { public static MemberBillReportResponse of(MemberBillReportAppResponse memberBillReportAppResponse) { - return new MemberBillReportResponse(memberBillReportAppResponse.name(), memberBillReportAppResponse.price()); + return new MemberBillReportResponse( + memberBillReportAppResponse.memberId(), + memberBillReportAppResponse.name(), + memberBillReportAppResponse.isDeposited(), + memberBillReportAppResponse.price() + ); } } diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberDepositResponse.java b/server/src/main/java/server/haengdong/presentation/response/MemberDepositResponse.java new file mode 100644 index 000000000..26699bc72 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MemberDepositResponse.java @@ -0,0 +1,14 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.MemberDepositAppResponse; + +public record MemberDepositResponse( + Long id, + String name, + boolean isDeposited +) { + + public static MemberDepositResponse of(MemberDepositAppResponse response) { + return new MemberDepositResponse(response.id(), response.name(), response.isDeposited()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberResponse.java b/server/src/main/java/server/haengdong/presentation/response/MemberResponse.java new file mode 100644 index 000000000..6b43d72ee --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MemberResponse.java @@ -0,0 +1,18 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.LastBillMemberAppResponse; +import server.haengdong.application.response.MemberAppResponse; + +public record MemberResponse( + Long id, + String name +) { + + public static MemberResponse of(MemberAppResponse response) { + return new MemberResponse(response.id(), response.name()); + } + + public static MemberResponse of(LastBillMemberAppResponse response) { + return new MemberResponse(response.id(), response.name()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/MemberSaveResponse.java b/server/src/main/java/server/haengdong/presentation/response/MemberSaveResponse.java new file mode 100644 index 000000000..b0740c6ca --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MemberSaveResponse.java @@ -0,0 +1,12 @@ +package server.haengdong.presentation.response; + +import server.haengdong.application.response.MemberSaveAppResponse; + +public record MemberSaveResponse( + Long id, + String name +) { + public static MemberSaveResponse of(MemberSaveAppResponse response) { + return new MemberSaveResponse(response.id(), response.name()); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java b/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java index 0947d9e02..333428761 100644 --- a/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/MembersResponse.java @@ -1,13 +1,16 @@ package server.haengdong.presentation.response; import java.util.List; -import server.haengdong.application.response.MembersAppResponse; +import server.haengdong.application.response.MemberDepositAppResponse; +import server.haengdong.application.response.MembersDepositAppResponse; public record MembersResponse( - List memberNames + List members ) { - public static MembersResponse of(MembersAppResponse response) { - return new MembersResponse(response.memberNames()); + public static MembersResponse of(MembersDepositAppResponse response) { + return new MembersResponse(response.members().stream() + .map(MemberDepositResponse::of) + .toList()); } } diff --git a/server/src/main/java/server/haengdong/presentation/response/MembersSaveResponse.java b/server/src/main/java/server/haengdong/presentation/response/MembersSaveResponse.java new file mode 100644 index 000000000..04e9b133e --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/MembersSaveResponse.java @@ -0,0 +1,16 @@ +package server.haengdong.presentation.response; + +import java.util.List; +import server.haengdong.application.response.MembersSaveAppResponse; + +public record MembersSaveResponse( + List members +) { + public static MembersSaveResponse of(MembersSaveAppResponse response) { + return new MembersSaveResponse( + response.members().stream() + .map(MemberSaveResponse::of) + .toList() + ); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java index 55dd62c58..924651c73 100644 --- a/server/src/main/java/server/haengdong/presentation/response/StepResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/StepResponse.java @@ -1,27 +1,22 @@ package server.haengdong.presentation.response; -import java.util.ArrayList; import java.util.List; -import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.response.StepAppResponse; public record StepResponse( - String stepName, - String type, - List members, - List actions + List bills, + List members ) { - public static StepResponse of(String stepName, List members, List actions) { - return new StepResponse( - stepName, - actions.get(0).actionTypeName(), - new ArrayList<>(members), - toActionsResponse(actions) - ); - } + public static StepResponse of(StepAppResponse response) { + List bills = response.bills().stream() + .map(BillResponse::of) + .toList(); - private static List toActionsResponse(List actions) { - return actions.stream() - .map(ActionResponse::of) + List members = response.members().stream() + .map(MemberResponse::of) .toList(); + return new StepResponse(bills, members); + } } + diff --git a/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java b/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java index 5f7573d67..baceeb549 100644 --- a/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java +++ b/server/src/main/java/server/haengdong/presentation/response/StepsResponse.java @@ -1,56 +1,14 @@ package server.haengdong.presentation.response; -import java.util.ArrayList; import java.util.List; -import server.haengdong.application.response.ActionAppResponse; -import server.haengdong.application.response.ActionAppResponse.ActionType; - -public record StepsResponse(List steps) { - - public static StepsResponse of(List actions) { - List steps = new ArrayList<>(); - List currentMembers = new ArrayList<>(); - List> groups = createGroups(actions); - - int billStepCount = 0; - for (List group : groups) { - changeCurrentMembers(group, currentMembers); - if (group.get(0).actionType() == ActionType.BILL) { - billStepCount++; - } - StepResponse stepResponse = StepResponse.of(billStepCount + "차", currentMembers, group); - steps.add(stepResponse); - } - return new StepsResponse(steps); - } - - private static List> createGroups(List actions) { - List> groups = new ArrayList<>(); - - for (ActionAppResponse action : actions) { - if (groups.isEmpty() || isActionTypeChange(action, groups)) { - groups.add(new ArrayList<>()); - } - groups.get(groups.size() - 1).add(action); - } - - return groups; - } - - private static boolean isActionTypeChange(ActionAppResponse action, List> groups) { - List currentGroup = groups.get(groups.size() - 1); - return currentGroup.get(0).actionType() != action.actionType(); - } - - private static void changeCurrentMembers(List group, List currentMembers) { - for (ActionAppResponse action : group) { - if (action.actionType() == ActionType.IN) { - currentMembers.add(action.name()); - continue; - } - if (action.actionType() == ActionType.OUT) { - currentMembers.remove(action.name()); - } - } +import server.haengdong.application.response.StepAppResponse; + +public record StepsResponse( + List steps +) { + public static StepsResponse of(List steps) { + return new StepsResponse(steps.stream() + .map(StepResponse::of) + .toList()); } } diff --git a/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java deleted file mode 100644 index c89d057eb..000000000 --- a/server/src/test/java/server/haengdong/application/BillActionDetailServiceTest.java +++ /dev/null @@ -1,111 +0,0 @@ -package server.haengdong.application; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.tuple; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import server.haengdong.application.request.BillActionDetailUpdateAppRequest; -import server.haengdong.application.request.BillActionDetailsUpdateAppRequest; -import server.haengdong.application.response.BillActionDetailAppResponse; -import server.haengdong.application.response.BillActionDetailsAppResponse; -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.Sequence; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongException; -import server.haengdong.support.fixture.Fixture; - -class BillActionDetailServiceTest extends ServiceTestSupport { - - @Autowired - private BillActionDetailService billActionDetailService; - - @Autowired - private EventRepository eventRepository; - - @Autowired - private BillActionRepository billActionRepository; - - @Autowired - private BillActionDetailRepository billActionDetailRepository; - - @DisplayName("참여자별 지출 금액을 조회한다.") - @Test - void findBillActionDetailsTest() { - Event event1 = Fixture.EVENT1; - eventRepository.save(event1); - Sequence sequence = Sequence.createFirst(); - BillAction billAction = new BillAction(event1, sequence, "뽕족", 10000L); - billActionRepository.save(billAction); - BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "토다리", 6000L, true); - BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "쿠키", 4000L, true); - billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); - - BillActionDetailsAppResponse response = billActionDetailService.findBillActionDetails( - event1.getToken(), billAction.getId()); - - assertThat(response.billActionDetailAppResponses()).hasSize(2) - .extracting(BillActionDetailAppResponse::name, BillActionDetailAppResponse::price) - .containsExactly( - tuple("토다리", 6000L), - tuple("쿠키", 4000L) - ); - } - - @DisplayName("지출 금액 수정 요청의 총합이 지출 금액과 일치하지 않으면 예외가 발생한다.") - @Test - void updateBillActionDetailsTest1() { - Event event1 = Fixture.EVENT1; - eventRepository.save(event1); - Sequence sequence = Sequence.createFirst(); - BillAction billAction = new BillAction(event1, sequence, "뽕족", 10000L); - billActionRepository.save(billAction); - BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "토다리", 5000L, false); - BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "쿠키", 5000L, false); - billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); - - BillActionDetailsUpdateAppRequest request = new BillActionDetailsUpdateAppRequest(List.of( - new BillActionDetailUpdateAppRequest("토다리", 3000L, true), - new BillActionDetailUpdateAppRequest("쿠키", 4000L, true) - )); - assertThatCode( - () -> billActionDetailService.updateBillActionDetails(event1.getToken(), billAction.getId(), request)) - .isInstanceOf(HaengdongException.class) - .hasMessage("지출 총액이 일치하지 않습니다."); - } - - @DisplayName("지출 고정 금액을 수정한다.") - @Test - void updateBillActionDetailsTest2() { - Event event1 = Fixture.EVENT1; - eventRepository.save(event1); - Sequence sequence = Sequence.createFirst(); - BillAction billAction = new BillAction(event1, sequence, "뽕족", 10000L); - billActionRepository.save(billAction); - BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "토다리", 5000L, false); - BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "쿠키", 5000L, false); - billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); - - BillActionDetailsUpdateAppRequest request = new BillActionDetailsUpdateAppRequest(List.of( - new BillActionDetailUpdateAppRequest("토다리", 3000L, true), - new BillActionDetailUpdateAppRequest("쿠키", 7000L, true) - )); - billActionDetailService.updateBillActionDetails(event1.getToken(), billAction.getId(), request); - - List results = billActionDetailRepository.findAll(); - - assertThat(results).hasSize(2) - .extracting(BillActionDetail::getMemberName, BillActionDetail::getPrice) - .containsExactly( - tuple("토다리", 3000L), - tuple("쿠키", 7000L) - ); - } -} diff --git a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java b/server/src/test/java/server/haengdong/application/BillActionServiceTest.java deleted file mode 100644 index 30675acdd..000000000 --- a/server/src/test/java/server/haengdong/application/BillActionServiceTest.java +++ /dev/null @@ -1,229 +0,0 @@ -package server.haengdong.application; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.assertj.core.api.Assertions.tuple; -import static org.junit.jupiter.api.Assertions.assertAll; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import server.haengdong.application.request.BillActionAppRequest; -import server.haengdong.application.request.BillActionUpdateAppRequest; -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; -import server.haengdong.domain.action.Sequence; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongException; -import server.haengdong.support.fixture.Fixture; - -class BillActionServiceTest extends ServiceTestSupport { - - @Autowired - private BillActionService billActionService; - - @Autowired - private EventRepository eventRepository; - - @Autowired - private BillActionRepository billActionRepository; - - @Autowired - private BillActionDetailRepository billActionDetailRepository; - - @Autowired - private MemberActionRepository memberActionRepository; - - @DisplayName("지출 내역을 생성한다.") - @Test - void saveAllBillAction() { - Event event = Fixture.EVENT1; - Event savedEvent = eventRepository.save(event); - Sequence sequence1 = Sequence.createFirst(); - Sequence sequence2 = sequence1.next(); - MemberAction memberAction1 = new MemberAction(event, sequence1, "백호", MemberActionStatus.IN); - MemberAction memberAction2 = new MemberAction(event, sequence2, "망쵸", MemberActionStatus.IN); - memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); - - List requests = List.of( - new BillActionAppRequest("뽕족", 10_000L), - new BillActionAppRequest("인생맥주", 15_000L) - ); - - billActionService.saveAllBillAction(event.getToken(), requests); - - List actions = billActionRepository.findByEvent(savedEvent); - - assertThat(actions).extracting(BillAction::getTitle, BillAction::getPrice, BillAction::getSequence) - .containsExactlyInAnyOrder( - tuple("뽕족", 10_000L, new Sequence(3L)), - tuple("인생맥주", 15_000L, new Sequence(4L)) - ); - } - - @DisplayName("지출 내역을 생성하면 지출 상세 내역이 생성된다.") - @Test - void saveAllBillActionTest1() { - Event event = Fixture.EVENT1; - Event savedEvent = eventRepository.save(event); - Sequence sequence1 = Sequence.createFirst(); - Sequence sequence2 = sequence1.next(); - MemberAction memberAction1 = new MemberAction(event, sequence1, "백호", MemberActionStatus.IN); - MemberAction memberAction2 = new MemberAction(event, sequence2, "망쵸", MemberActionStatus.IN); - memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); - - List request = List.of( - new BillActionAppRequest("뽕족", 10_000L), - new BillActionAppRequest("인생맥주", 15_000L) - ); - - billActionService.saveAllBillAction(event.getToken(), request); - - List billActionDetails = billActionDetailRepository.findAll(); - - assertThat(billActionDetails) - .hasSize(4) - .extracting("memberName", "price") - .containsExactlyInAnyOrder( - tuple("백호", 5_000L), - tuple("망쵸", 5_000L), - tuple("백호", 7_500L), - tuple("망쵸", 7_500L) - ); - } - - @DisplayName("이벤트가 존재하지 않으면 지출 내역을 생성할 수 없다.") - @Test - void saveAllBillAction1() { - List requests = List.of( - new BillActionAppRequest("뽕족", 10_000L), - new BillActionAppRequest("인생맥주", 15_000L) - ); - - assertThatThrownBy(() -> billActionService.saveAllBillAction("token", requests)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("지출 액션을 수정한다.") - @Test - void updateBillAction() { - Event event = Fixture.EVENT1; - Event savedEvent = eventRepository.save(event); - Sequence sequence = Sequence.createFirst(); - BillAction billAction = new BillAction(event, sequence, "뽕족", 10_000L); - BillAction savedBillAction = billActionRepository.save(billAction); - - Long actionId = savedBillAction.getId(); - BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); - - billActionService.updateBillAction(event.getToken(), actionId, request); - - BillAction updatedBillAction = billActionRepository.findById(savedBillAction.getId()).get(); - - assertAll( - () -> assertThat(updatedBillAction.getTitle()).isEqualTo("인생맥주"), - () -> assertThat(updatedBillAction.getPrice()).isEqualTo(20_000L) - ); - } - - @DisplayName("행사에 속하지 않은 지출 액션은 수정할 수 없다.") - @Test - void updateBillAction1() { - Event event1 = Fixture.EVENT1; - Event event2 = Fixture.EVENT2; - Event savedEvent1 = eventRepository.save(event1); - Event savedEvent2 = eventRepository.save(event2); - Sequence sequence1 = Sequence.createFirst(); - Sequence sequence2 = Sequence.createFirst(); - BillAction billAction1 = new BillAction(event1, sequence1, "뽕족", 10_000L); - BillAction billAction2 = new BillAction(event2, sequence2, "뽕족", 10_000L); - BillAction savedBillAction1 = billActionRepository.save(billAction1); - billActionRepository.save(billAction2); - - Long actionId = savedBillAction1.getId(); - BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); - - assertThatThrownBy(() -> billActionService.updateBillAction(event2.getToken(), actionId, request)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("지출 내역 금액을 변경하면 지출 디테일이 초기화 된다.") - @Test - void updateBillAction2() { - Event event = Fixture.EVENT1; - Event savedEvent = eventRepository.save(event); - Sequence sequence = Sequence.createFirst(); - BillAction billAction = new BillAction(event, sequence, "뽕족", 10_000L); - BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "감자", 3000L, true); - BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "고구마", 2000L, true); - BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "당근", 3000L, true); - BillActionDetail billActionDetail4 = new BillActionDetail(billAction, "양파", 2000L, true); - billAction.addDetails(List.of(billActionDetail1, billActionDetail2, billActionDetail3, billActionDetail4)); - BillAction savedBillAction = billActionRepository.save(billAction); - - Long actionId = savedBillAction.getId(); - BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L); - - billActionService.updateBillAction(event.getToken(), actionId, request); - - BillAction updatedBillAction = billActionRepository.findById(savedBillAction.getId()).get(); - List billActionDetails = billActionDetailRepository.findAllByBillAction(updatedBillAction); - - assertThat(billActionDetails).hasSize(4) - .extracting("memberName", "price") - .containsExactlyInAnyOrder( - tuple("감자", 5000L), - tuple("고구마", 5000L), - tuple("당근", 5000L), - tuple("양파", 5000L) - ); - } - - @DisplayName("지출 내역을 삭제한다.") - @Test - void deleteBillAction() { - Event event = Fixture.EVENT1; - eventRepository.save(event); - BillAction billAction = Fixture.createBillAction(event, 1L, "커피", 50_900L); - billActionRepository.save(billAction); - Long actionId = billAction.getId(); - - billActionService.deleteBillAction(event.getToken(), actionId); - - assertThat(billActionRepository.findById(billAction.getId())).isEmpty(); - } - - @DisplayName("지출 내역을 삭제하면 지출 상세도 삭제된다.") - @Test - void deleteBillActionTest1() { - Event event = Fixture.EVENT1; - eventRepository.save(event); - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "백호", MemberActionStatus.IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "망쵸", MemberActionStatus.IN); - BillAction billAction = Fixture.createBillAction(event, 3L, "커피", 50_900L); - BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "백호", 25_450L, false); - BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "망쵸", 25_450L, false); - memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); - billActionRepository.save(billAction); - billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2)); - Long actionId = billAction.getId(); - - billActionService.deleteBillAction(event.getToken(), actionId); - - assertThat(billActionDetailRepository.findAll()).isEmpty(); - } - - @DisplayName("지출 내역 삭제 시 행사가 존재하지 않으면 예외가 발생한다.") - @Test - void deleteBillAction1() { - assertThatThrownBy(() -> billActionService.deleteBillAction("소하망쵸", 1L)) - .isInstanceOf(HaengdongException.class); - } -} diff --git a/server/src/test/java/server/haengdong/application/BillServiceTest.java b/server/src/test/java/server/haengdong/application/BillServiceTest.java new file mode 100644 index 000000000..72fd0192f --- /dev/null +++ b/server/src/test/java/server/haengdong/application/BillServiceTest.java @@ -0,0 +1,308 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; +import static org.junit.jupiter.api.Assertions.assertAll; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import server.haengdong.application.request.BillAppRequest; +import server.haengdong.application.request.BillDetailUpdateAppRequest; +import server.haengdong.application.request.BillDetailsUpdateAppRequest; +import server.haengdong.application.request.BillUpdateAppRequest; +import server.haengdong.application.response.BillAppResponse; +import server.haengdong.application.response.BillDetailAppResponse; +import server.haengdong.application.response.BillDetailsAppResponse; +import server.haengdong.application.response.MemberAppResponse; +import server.haengdong.application.response.StepAppResponse; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.bill.BillDetail; +import server.haengdong.domain.bill.BillDetailRepository; +import server.haengdong.domain.bill.BillRepository; +import server.haengdong.domain.member.Member; +import server.haengdong.domain.member.MemberRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; +import server.haengdong.support.fixture.Fixture; + +class BillServiceTest extends ServiceTestSupport { + + @Autowired + private BillService billService; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillRepository billRepository; + + @Autowired + private BillDetailRepository billDetailRepository; + + @Autowired + private MemberRepository memberRepository; + + @DisplayName("전체 지출 내역을 조회한다.") + @Test + void findSteps() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + Member member = new Member(event, "토다리"); + memberRepository.save(member); + Bill bill = Bill.create(event, "행동대장 회식", 100000L, List.of(member)); + billRepository.save(bill); + + List steps = billService.findSteps(event.getToken()); + + assertThat(steps.get(0).bills()).hasSize(1) + .extracting(BillAppResponse::id, BillAppResponse::title, BillAppResponse::price, + BillAppResponse::isFixed) + .containsExactlyInAnyOrder( + tuple(bill.getId(), bill.getTitle(), bill.getPrice(), bill.isFixed()) + ); + + assertThat(steps.get(0).members()).hasSize(1) + .extracting(MemberAppResponse::id, MemberAppResponse::name) + .containsExactlyInAnyOrder( + tuple(member.getId(), member.getName()) + ); + } + + @DisplayName("지출 내역을 생성한다.") + @Test + void saveBill() { + Event event = Fixture.EVENT1; + Event savedEvent = eventRepository.save(event); + + Member member1 = Fixture.MEMBER1; + Member member2 = Fixture.MEMBER2; + memberRepository.saveAll(List.of(member1, member2)); + List memberIds = List.of(member1.getId(), member2.getId()); + BillAppRequest billAppRequest = new BillAppRequest("뽕족", 10_000L, memberIds); + + billService.saveBill(event.getToken(), billAppRequest); + + List bills = billRepository.findAllByEvent(savedEvent); + + assertThat(bills).extracting(Bill::getTitle, Bill::getPrice) + .containsExactlyInAnyOrder( + tuple("뽕족", 10_000L) + ); + } + + @DisplayName("지출 내역을 생성하면 지출 상세 내역이 생성된다.") + @Test + void saveBillTest1() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + + Member member1 = Fixture.MEMBER1; + Member member2 = Fixture.MEMBER2; + List members = List.of(member1, member2); + memberRepository.saveAll(members); + + BillAppRequest request = new BillAppRequest("뽕족", 10_000L, List.of(member1.getId(), member2.getId())); + + billService.saveBill(event.getToken(), request); + + List billDetails = billDetailRepository.findAllByBillId(1L); + + assertThat(billDetails) + .hasSize(2) + .extracting("member", "price") + .containsExactlyInAnyOrder( + tuple(member1, 5_000L), + tuple(member2, 5_000L) + ); + } + + @DisplayName("토큰에 해당하는 이벤트가 존재하지 않으면 지출 내역을 생성할 수 없다.") + @Test + void saveBill1() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + + Member member1 = Fixture.MEMBER1; + Member member2 = Fixture.MEMBER2; + List members = List.of(member1, member2); + memberRepository.saveAll(members); + + BillAppRequest request = new BillAppRequest("뽕족", 10_000L, List.of(member1.getId(), member2.getId())); + + assertThatThrownBy(() -> billService.saveBill("wrongToken", request)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("지출을 수정한다.") + @Test + void updateBill() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + + Bill bill = new Bill(event, "뽕족", 10_000L); + Bill savedBill = billRepository.save(bill); + + Long billId = savedBill.getId(); + BillUpdateAppRequest request = new BillUpdateAppRequest("인생맥주", 20_000L); + + billService.updateBill(event.getToken(), billId, request); + + Bill updatedBill = billRepository.findById(savedBill.getId()).get(); + + assertAll( + () -> assertThat(updatedBill.getTitle()).isEqualTo("인생맥주"), + () -> assertThat(updatedBill.getPrice()).isEqualTo(20_000L) + ); + } + + @DisplayName("행사에 속하지 않은 지출은 수정할 수 없다.") + @Test + void updateBill1() { + Event event1 = Fixture.EVENT1; + Event event2 = Fixture.EVENT2; + eventRepository.saveAll(List.of(event1, event2)); + Bill bill1 = new Bill(event1, "뽕족", 10_000L); + Bill bill2 = new Bill(event2, "뽕족", 10_000L); + Bill savedBill1 = billRepository.save(bill1); + billRepository.save(bill2); + + Long bill1Id = savedBill1.getId(); + BillUpdateAppRequest request = new BillUpdateAppRequest("인생맥주", 20_000L); + + assertThatThrownBy(() -> billService.updateBill(event2.getToken(), bill1Id, request)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("지출 내역 금액을 변경하면 지출 디테일이 초기화 된다.") + @Test + void updateBill2() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + Member member1 = new Member(event, "감자"); + Member member2 = new Member(event, "고구마"); + Member member3 = new Member(event, "당근"); + Member member4 = new Member(event, "양파"); + List members = List.of(member1, member2, member3, member4); + memberRepository.saveAll(members); + Bill bill = Bill.create(event, "뽕족", 10_000L, members); + bill.getBillDetails().forEach(billDetail -> billDetail.updateIsFixed(true)); + billRepository.save(bill); + BillUpdateAppRequest request = new BillUpdateAppRequest("인생맥주", 20_000L); + + billService.updateBill(event.getToken(), bill.getId(), request); + + Bill updatedBill = billRepository.findById(bill.getId()).get(); + List billDetails = billDetailRepository.findAllByBill(updatedBill); + + assertThat(billDetails).hasSize(4) + .extracting(BillDetail::getPrice) + .containsExactly(5000L, 5000L, 5000L, 5000L); + } + + @DisplayName("지출 내역을 삭제한다.") + @Test + void deleteBill() { + Event event = Fixture.EVENT1; + eventRepository.save(event); + Member member1 = new Member(event, "토다리"); + Member member2 = new Member(event, "쿠키"); + memberRepository.saveAll(List.of(member1, member2)); + + Bill bill = Bill.create(event, "뽕족", 10000L, List.of(member1, member2)); + billRepository.save(bill); + Long billId = bill.getId(); + + billService.deleteBill(event.getToken(), billId); + + assertThat(billRepository.findById(billId)).isEmpty(); + } + + @DisplayName("지출 내역 삭제 시 행사가 존재하지 않으면 예외가 발생한다.") + @Test + void deleteBill1() { + assertThatThrownBy(() -> billService.deleteBill("소하망쵸", 1L)) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("지출 금액 수정 요청의 총합이 지출 금액과 일치하지 않으면 예외가 발생한다.") + @Test + void updateBillDetailsTest1() { + Event event1 = Fixture.EVENT1; + eventRepository.save(event1); + Member member1 = new Member(event1, "토다리"); + Member member2 = new Member(event1, "쿠키"); + memberRepository.saveAll(List.of(member1, member2)); + + Bill bill = Bill.create(event1, "뽕족", 10000L, List.of(member1, member2)); + billRepository.save(bill); + List billDetails = bill.getBillDetails(); + + BillDetailsUpdateAppRequest request = new BillDetailsUpdateAppRequest(List.of( + new BillDetailUpdateAppRequest(billDetails.get(0).getId(), 3000L, true), + new BillDetailUpdateAppRequest(billDetails.get(1).getId(), 4000L, true) + )); + + assertThatThrownBy( + () -> billService.updateBillDetails(event1.getToken(), bill.getId(), request)) + .isInstanceOf(HaengdongException.class) + .hasMessage("지출 총액이 일치하지 않습니다."); + } + + @DisplayName("지출 고정 금액을 수정한다.") + @Test + void updateBillDetailsTest2() { + Event event1 = Fixture.EVENT1; + eventRepository.save(event1); + Member member1 = new Member(event1, "토다리"); + Member member2 = new Member(event1, "쿠키"); + memberRepository.saveAll(List.of(member1, member2)); + + Bill bill = Bill.create(event1, "뽕족", 10000L, List.of(member1, member2)); + billRepository.save(bill); + List billDetails = bill.getBillDetails(); + + BillDetailsUpdateAppRequest request = new BillDetailsUpdateAppRequest(List.of( + new BillDetailUpdateAppRequest(billDetails.get(0).getId(), 3000L, true), + new BillDetailUpdateAppRequest(billDetails.get(1).getId(), 7000L, true) + )); + + billService.updateBillDetails(event1.getToken(), bill.getId(), request); + + List foundBillDetails = billDetailRepository.findAllByBill(bill); + + assertThat(foundBillDetails).hasSize(2) + .extracting(BillDetail::getId, BillDetail::getPrice) + .containsExactly( + tuple(billDetails.get(0).getId(), 3000L), + tuple(billDetails.get(1).getId(), 7000L) + ); + } + + @DisplayName("참여자별 지출 금액을 조회한다.") + @Test + void findBillDetailsTest() { + Event event1 = Fixture.EVENT1; + eventRepository.save(event1); + + Member member1 = Fixture.MEMBER1; + Member member2 = Fixture.MEMBER2; + List members = List.of(member1, member2); + memberRepository.saveAll(members); + + Bill bill = Bill.create(event1, "뽕족", 10000L, members); + billRepository.save(bill); + + BillDetailsAppResponse response = billService.findBillDetails(event1.getToken(), bill.getId()); + + assertThat(response.billDetails()).hasSize(2) + .extracting(BillDetailAppResponse::memberName, BillDetailAppResponse::price) + .containsExactly( + tuple("토다리", 5000L), + tuple("쿠키", 5000L) + ); + } +} diff --git a/server/src/test/java/server/haengdong/application/EventServiceTest.java b/server/src/test/java/server/haengdong/application/EventServiceTest.java index 37e6372a8..e5fef4184 100644 --- a/server/src/test/java/server/haengdong/application/EventServiceTest.java +++ b/server/src/test/java/server/haengdong/application/EventServiceTest.java @@ -2,12 +2,9 @@ import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.assertj.core.api.Assertions.tuple; +import static org.assertj.core.api.AssertionsForClassTypes.tuple; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.mockito.BDDMockito.given; -import static server.haengdong.domain.action.MemberActionStatus.IN; -import static server.haengdong.domain.action.MemberActionStatus.OUT; -import static server.haengdong.support.fixture.Fixture.BILL_ACTION; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -15,24 +12,17 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.MockBean; import server.haengdong.application.request.EventAppRequest; -import server.haengdong.application.request.MemberNameUpdateAppRequest; -import server.haengdong.application.request.MemberNamesUpdateAppRequest; -import server.haengdong.application.response.ActionAppResponse; +import server.haengdong.application.request.EventUpdateAppRequest; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.application.response.MembersAppResponse; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.BillActionDetail; -import server.haengdong.domain.action.BillActionRepository; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.action.Sequence; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.bill.BillRepository; +import server.haengdong.domain.member.Member; +import server.haengdong.domain.member.MemberRepository; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; import server.haengdong.domain.event.EventTokenProvider; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; import server.haengdong.support.fixture.Fixture; class EventServiceTest extends ServiceTestSupport { @@ -44,10 +34,10 @@ class EventServiceTest extends ServiceTestSupport { private EventRepository eventRepository; @Autowired - private BillActionRepository billActionRepository; + private BillRepository billRepository; @Autowired - private MemberActionRepository memberActionRepository; + private MemberRepository memberRepository; @MockBean private EventTokenProvider eventTokenProvider; @@ -74,156 +64,68 @@ void findEventTest() { assertThat(eventDetailAppResponse.eventName()).isEqualTo(event.getName()); } - @DisplayName("행사에 속한 모든 액션을 조회한다.") + @DisplayName("행사 정보를 수정한다.") @Test - void findActionsTest() { - Event event = Fixture.EVENT1; - MemberAction memberAction = Fixture.createMemberAction(event, 1L, "토다리", IN); - MemberAction memberAction1 = Fixture.createMemberAction(event, 2L, "쿠키", IN); - BillAction billAction = Fixture.createBillAction(event, 3L, "뽕나무쟁이족발", 30000L); - eventRepository.save(event); - memberActionRepository.saveAll(List.of(memberAction, memberAction1)); - billActionRepository.save(billAction); - - List actionAppResponses = eventService.findActions(event.getToken()); - - assertThat(actionAppResponses).hasSize(3) - .extracting(ActionAppResponse::actionId, - ActionAppResponse::name, - ActionAppResponse::price, - ActionAppResponse::sequence, - ActionAppResponse::actionTypeName) - .containsExactly( - tuple(1L, "토다리", null, 1L, "IN"), - tuple(2L, "쿠키", null, 2L, "IN"), - tuple(1L, "뽕나무쟁이족발", 30000L, 3L, "BILL") - ); - } - - @DisplayName("행사에 참여한 전체 인원을 중복 없이 조회한다.") - @Test - void findAllMembersTest() { - Event event = Fixture.EVENT1; - BillAction billAction = Fixture.createBillAction(event, 3L, "뽕나무쟁이족발", 30000L); - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "쿠키", IN); - MemberAction memberAction3 = Fixture.createMemberAction(event, 4L, "쿠키", OUT); - eventRepository.save(event); - billActionRepository.save(billAction); - memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); - - MembersAppResponse membersAppResponse = eventService.findAllMembers(event.getToken()); - - assertThat(membersAppResponse.memberNames()).containsExactlyInAnyOrder("토다리", "쿠키"); - } - - @DisplayName("행사 참여 인원들의 이름을 변경한다.") - @Test - void updateMember() { - Event event = Fixture.EVENT1; - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "쿠키", IN); - MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "웨디", IN); - MemberAction memberAction4 = Fixture.createMemberAction(event, 4L, "쿠키", OUT); - MemberAction memberAction5 = Fixture.createMemberAction(event, 5L, "쿠키", IN); - MemberAction memberAction6 = Fixture.createMemberAction(event, 6L, "쿠키", OUT); - eventRepository.save(event); - memberActionRepository.saveAll(List.of( - memberAction1, memberAction2, memberAction3, memberAction4, memberAction5, memberAction6 - )); - - eventService.updateMember(event.getToken(), new MemberNamesUpdateAppRequest(List.of( - new MemberNameUpdateAppRequest("쿠키", "쿡쿡"), - new MemberNameUpdateAppRequest("토다리", "토쟁이") - ))); - - List foundMemberActions = memberActionRepository.findAllByEvent(event); - assertThat(foundMemberActions) - .extracting(MemberAction::getId, MemberAction::getMemberName) - .contains( - tuple(memberAction1.getId(), "토쟁이"), - tuple(memberAction2.getId(), "쿡쿡"), - tuple(memberAction3.getId(), "웨디"), - tuple(memberAction4.getId(), "쿡쿡"), - tuple(memberAction5.getId(), "쿡쿡"), - tuple(memberAction6.getId(), "쿡쿡") - ); - } - - @DisplayName("이미 존재하는 인원의 이름으로 변경할 수 없다.") - @Test - void updateMember1() { - Event event = Fixture.EVENT1; - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "쿠키", IN); - MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "웨디", IN); + void updateEventTest() { + Event event = new Event("행동대장 비대위", "1234", "token"); eventRepository.save(event); - memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); - MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( - new MemberNameUpdateAppRequest("쿠키", "쿡쿡"), - new MemberNameUpdateAppRequest("웨디", "토다리") - )); + EventUpdateAppRequest eventUpdateAppRequest = new EventUpdateAppRequest("새로운 행사 이름", "토스뱅크", "12345678"); + eventService.updateEvent(event.getToken(), eventUpdateAppRequest); - assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) - .isInstanceOf(HaengdongException.class); + Event updateEvent = eventRepository.findByToken(event.getToken()).get(); + assertAll( + () -> assertThat(updateEvent.getName()).isEqualTo("새로운 행사 이름"), + () -> assertThat(updateEvent.getAccount()).isEqualTo("토스뱅크 12345678") + ); } - @DisplayName("존재하지 않는 인원은 변경할 수 없다.") + @DisplayName("행사의 은행 정보만 수정한다.") @Test - void updateMember2() { - Event event = Fixture.EVENT1; - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "쿠키", IN); - MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "웨디", IN); + void updateEventTest1() { + Event event = new Event("행동대장 비대위", "1234", "token"); eventRepository.save(event); - memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); - MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( - new MemberNameUpdateAppRequest("쿡쿡", "토쟁이"), - new MemberNameUpdateAppRequest("웨디", "말복") - )); + EventUpdateAppRequest eventUpdateAppRequest = new EventUpdateAppRequest(null, "토스뱅크", "12345678"); + eventService.updateEvent(event.getToken(), eventUpdateAppRequest); - assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) - .isInstanceOf(HaengdongException.class); + Event updateEvent = eventRepository.findByToken(event.getToken()).get(); + assertAll( + () -> assertThat(updateEvent.getName()).isEqualTo("행동대장 비대위"), + () -> assertThat(updateEvent.getAccount()).isEqualTo("토스뱅크 12345678") + ); } - @DisplayName("변경 전 참여 인원 이름이 중복될 수 없다.") + @DisplayName("행사의 이름만 수정한다.") @Test - void updateMember3() { - Event event = Fixture.EVENT1; - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "쿠키", IN); - MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "웨디", IN); + void updateEventTest2() { + Event event = new Event("행동대장 비대위", "1234", "token"); eventRepository.save(event); - memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); - MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( - new MemberNameUpdateAppRequest("쿠키", "쿡쿡"), - new MemberNameUpdateAppRequest("쿠키", "토쟁이") - )); + EventUpdateAppRequest eventUpdateAppRequest = new EventUpdateAppRequest("행동대장 정상 영업", null, null); + eventService.updateEvent(event.getToken(), eventUpdateAppRequest); - assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) - .isInstanceOf(HaengdongException.class); + Event updateEvent = eventRepository.findByToken(event.getToken()).get(); + assertAll( + () -> assertThat(updateEvent.getName()).isEqualTo("행동대장 정상 영업"), + () -> assertThat(updateEvent.getAccount()).isEqualTo("") + ); } - @DisplayName("변경 후 참여 인원 이름이 중복될 수 없다.") + @DisplayName("행사의 계좌 정보 일부가 누락되면 변경하지 않는다.") @Test - void updateMember4() { - Event event = Fixture.EVENT1; - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "쿠키", IN); - MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "웨디", IN); + void updateEventTest3() { + Event event = new Event("행동대장 비대위", "1234", "token"); eventRepository.save(event); - memberActionRepository.saveAll(List.of(memberAction1, memberAction2, memberAction3)); - MemberNamesUpdateAppRequest appRequest = new MemberNamesUpdateAppRequest(List.of( - new MemberNameUpdateAppRequest("쿠키", "쿡쿡"), - new MemberNameUpdateAppRequest("토다리", "쿡쿡") - )); + EventUpdateAppRequest eventUpdateAppRequest = new EventUpdateAppRequest(null, "망쵸뱅크", null); + eventService.updateEvent(event.getToken(), eventUpdateAppRequest); - assertThatThrownBy(() -> eventService.updateMember(event.getToken(), appRequest)) - .isInstanceOf(HaengdongException.class); + Event updateEvent = eventRepository.findByToken(event.getToken()).get(); + assertAll( + () -> assertThat(updateEvent.getName()).isEqualTo("행동대장 비대위"), + () -> assertThat(updateEvent.getAccount()).isEqualTo("") + ); } @DisplayName("참여자별 정산 현황을 조회한다.") @@ -231,49 +133,29 @@ void updateMember4() { void getMemberBillReports() { Event event = Fixture.EVENT1; Event savedEvent = eventRepository.save(event); - List memberActions = List.of( - new MemberAction(savedEvent, new Sequence(1L), "소하", IN), - new MemberAction(savedEvent, new Sequence(2L), "감자", IN), - new MemberAction(savedEvent, new Sequence(3L), "쿠키", IN), - new MemberAction(savedEvent, new Sequence(5L), "감자", OUT) - ); - List billActions = List.of( - new BillAction(savedEvent, new Sequence(4L), "뽕족", 60_000L), - new BillAction(savedEvent, new Sequence(7L), "인생네컷", 20_000L) + List members = List.of( + new Member(savedEvent, "소하"), + new Member(savedEvent, "감자"), + new Member(savedEvent, "쿠키"), + new Member(savedEvent, "고구마") ); - billActions.get(0).addDetails( - List.of( - new BillActionDetail(BILL_ACTION, "소하", 10_000L, false), - new BillActionDetail(BILL_ACTION, "감자", 40_000L, true), - new BillActionDetail(BILL_ACTION, "쿠키", 10_000L, false) - ) + memberRepository.saveAll(members); + List bills = List.of( + Bill.create(savedEvent, "뽕족", 60_000L, members), + Bill.create(savedEvent, "인생네컷", 20_000L, members) ); - billActions.get(1).addDetails( - List.of( - new BillActionDetail(BILL_ACTION, "소하", 5_000L, true), - new BillActionDetail(BILL_ACTION, "쿠키", 15_000L, true) - ) - ); - memberActionRepository.saveAll(memberActions); - billActionRepository.saveAll(billActions); + billRepository.saveAll(bills); List responses = eventService.getMemberBillReports(event.getToken()); assertThat(responses) - .hasSize(3) + .hasSize(4) .extracting(MemberBillReportAppResponse::name, MemberBillReportAppResponse::price) .containsExactlyInAnyOrder( - tuple("감자", 40_000L), - tuple("쿠키", 25_000L), - tuple("소하", 15_000L) + tuple("감자", 20_000L), + tuple("쿠키", 20_000L), + tuple("소하", 20_000L), + tuple("고구마", 20_000L) ); } - - @DisplayName("존재하지 않는 이벤트의 참여자별 정산 현황을 조회하는 경우 예외가 발생한다.") - @Test - void getMemberBillReports1() { - assertThatThrownBy(() -> eventService.getMemberBillReports("invalid token")) - .isInstanceOf(HaengdongException.class) - .hasMessage(HaengdongErrorCode.EVENT_NOT_FOUND.getMessage()); - } } diff --git a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java b/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java deleted file mode 100644 index 4f1156714..000000000 --- a/server/src/test/java/server/haengdong/application/MemberActionFactoryTest.java +++ /dev/null @@ -1,216 +0,0 @@ -package server.haengdong.application; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.assertj.core.api.Assertions.tuple; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import server.haengdong.application.request.MemberActionSaveAppRequest; -import server.haengdong.application.request.MemberActionsSaveAppRequest; -import server.haengdong.domain.action.CurrentMembers; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionRepository; -import server.haengdong.domain.action.MemberActionStatus; -import server.haengdong.domain.action.Sequence; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongException; -import server.haengdong.support.fixture.Fixture; - -class MemberActionFactoryTest extends ServiceTestSupport { - - @Autowired - private MemberActionFactory memberActionFactory; - - @Autowired - private MemberActionRepository memberActionRepository; - - @Autowired - private EventRepository eventRepository; - - @DisplayName("이전 멤버 액션이 시퀀스 기준으로 정렬되지 않은 상태에서 새로운 멤버 액션 요청을 검증한다.") - @Test - void createMemberActionsTest() { - Event event = eventRepository.save(Fixture.EVENT1); - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", MemberActionStatus.IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "토다리", MemberActionStatus.OUT); - memberActionRepository.saveAll(List.of(memberAction1, memberAction2)); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); - - List unorderedMemberActions = List.of(memberAction2, memberAction1); - CurrentMembers currentMembers = CurrentMembers.of(unorderedMemberActions); - Sequence sequence = new Sequence(3L); - - assertThatThrownBy(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("인원 변동 액션을 생성한다.") - @Test - void createMemberActionsTest1() { - Event event = eventRepository.save(Fixture.EVENT1); - MemberAction memberAction = Fixture.createMemberAction(event, 1L, "토다리", MemberActionStatus.IN); - memberActionRepository.save(memberAction); - - MemberActionsSaveAppRequest memberActionsSaveAppRequest = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); - Sequence sequence = new Sequence(2L); - - CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - List memberActions = memberActionFactory.createMemberActions(event, memberActionsSaveAppRequest, - currentMembers, sequence - ); - - assertThat(memberActions).hasSize(1) - .extracting(MemberAction::getEvent, MemberAction::getSequence, MemberAction::getMemberName, - MemberAction::getStatus) - .containsExactly( - tuple(event, sequence, "토다리", MemberActionStatus.OUT) - ); - } - - @DisplayName("현재 행사에 참여 중인 경우에 퇴장할 수 있다.") - @Test - void createMemberActionsTest2() { - Event event = eventRepository.save(Fixture.EVENT1); - MemberAction memberAction = Fixture.createMemberAction(event, 1L, "토다리", MemberActionStatus.IN); - memberActionRepository.save(memberAction); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("토다리", "OUT"))); - Sequence sequence = new Sequence(2L); - CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - - assertThatCode(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) - .doesNotThrowAnyException(); - } - - @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다.") - @Test - void createMemberActionsTest3() { - Event event = eventRepository.save(Fixture.EVENT1); - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", MemberActionStatus.IN); - memberActionRepository.save(memberAction1); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "토다리", MemberActionStatus.OUT); - memberActionRepository.save(memberAction2); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("토다리", "IN"))); - Sequence sequence = new Sequence(3L); - CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction1, memberAction2)); - - assertThatCode(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) - .doesNotThrowAnyException(); - } - - @DisplayName("행사에 입장한 적 없는 경우에 입장할 수 있다.") - @Test - void createMemberActionsTest4() { - Event event = eventRepository.save(Fixture.EVENT1); - MemberAction memberAction = Fixture.createMemberAction(event, 1L, "토다리", MemberActionStatus.IN); - memberActionRepository.save(memberAction); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); - Sequence sequence = new Sequence(2L); - CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - - assertThatCode(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) - .doesNotThrowAnyException(); - } - - @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다.") - @Test - void createMemberActionTest5() { - Event event = eventRepository.save(Fixture.EVENT1); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("쿠키", "OUT"))); - Sequence sequence = new Sequence(2L); - CurrentMembers currentMembers = CurrentMembers.of(List.of()); - - assertThatCode( - () -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("행사에 이미 참여 중인 경우 다시 입장할 수 없다.") - @Test - void createMemberActionTest6() { - Event event = eventRepository.save(Fixture.EVENT1); - MemberAction memberAction = Fixture.createMemberAction(event, 1L, "쿠키", MemberActionStatus.IN); - memberActionRepository.save(memberAction); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("쿠키", "IN"))); - Sequence sequence = new Sequence(2L); - CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - - assertThatCode(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("한 명의 사용자는 동시에 여러 번 입장할 수 없다.") - @Test - void createMemberActionTest7() { - Event event = eventRepository.save(Fixture.EVENT1); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of( - new MemberActionSaveAppRequest("쿠키", "IN"), - new MemberActionSaveAppRequest("쿠키", "IN") - )); - Sequence sequence = new Sequence(1L); - CurrentMembers currentMembers = CurrentMembers.of(List.of()); - - assertThatCode( - () -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("한 명의 사용자는 동시에 여러 번 퇴장할 수 없다.") - @Test - void createMemberActionTest8() { - Event event = eventRepository.save(Fixture.EVENT1); - Sequence sequence1 = new Sequence(1L); - MemberAction memberAction = new MemberAction(event, sequence1, "쿠키", MemberActionStatus.IN); - memberActionRepository.save(memberAction); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of( - new MemberActionSaveAppRequest("쿠키", "OUT"), - new MemberActionSaveAppRequest("쿠키", "OUT") - )); - Sequence sequence2 = new Sequence(2L); - CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - - assertThatCode(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence2)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("한 명의 사용자는 입장과 퇴장을 동시에 할 수 없다.") - @Test - void createMemberActionTest9() { - Event event = eventRepository.save(Fixture.EVENT1); - Sequence sequence = new Sequence(1L); - MemberAction memberAction = new MemberAction(event, sequence, "쿠키", MemberActionStatus.IN); - memberActionRepository.save(memberAction); - - MemberActionsSaveAppRequest request = new MemberActionsSaveAppRequest( - List.of( - new MemberActionSaveAppRequest("쿠키", "IN"), - new MemberActionSaveAppRequest("쿠키", "OUT") - )); - Sequence sequence2 = new Sequence(2L); - CurrentMembers currentMembers = CurrentMembers.of(List.of(memberAction)); - - assertThatCode(() -> memberActionFactory.createMemberActions(event, request, currentMembers, sequence2)) - .isInstanceOf(HaengdongException.class); - } -} diff --git a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java b/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java deleted file mode 100644 index 51f5428f0..000000000 --- a/server/src/test/java/server/haengdong/application/MemberActionServiceTest.java +++ /dev/null @@ -1,231 +0,0 @@ -package server.haengdong.application; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.assertj.core.groups.Tuple.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 server.haengdong.application.request.MemberActionSaveAppRequest; -import server.haengdong.application.request.MemberActionsSaveAppRequest; -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.event.Event; -import server.haengdong.domain.event.EventRepository; -import server.haengdong.exception.HaengdongException; -import server.haengdong.support.fixture.Fixture; - -class MemberActionServiceTest extends ServiceTestSupport { - - @Autowired - private MemberActionService memberActionService; - - @Autowired - private MemberActionRepository memberActionRepository; - - @Autowired - private EventRepository eventRepository; - - @Autowired - private BillActionRepository billActionRepository; - - @Autowired - private BillActionDetailRepository billActionDetailRepository; - - @DisplayName("현재 행사에 참여하고 있는 경우에 나갈 수 있다.") - @Test - void saveMemberActionTest() { - Event event = eventRepository.save(Fixture.EVENT1); - MemberAction memberAction = Fixture.createMemberAction(event, 1L, "망쵸", IN); - memberActionRepository.save(memberAction); - - assertThatCode(() -> memberActionService.saveMemberAction(event.getToken(), new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("망쵸", "OUT"))))) - .doesNotThrowAnyException(); - } - - @DisplayName("행사에서 퇴장한 경우에 입장할 수 있다.") - @Test - void saveMemberActionTest1() { - Event event = eventRepository.save(Fixture.EVENT1); - MemberAction memberActionOne = Fixture.createMemberAction(event, 1L, "망쵸", IN); - memberActionRepository.save(memberActionOne); - - MemberAction memberActionTwo = Fixture.createMemberAction(event, 2L, "망쵸", OUT); - memberActionRepository.save(memberActionTwo); - - assertThatCode(() -> memberActionService.saveMemberAction(event.getToken(), new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("망쵸", "IN"))))) - .doesNotThrowAnyException(); - } - - @DisplayName("행사에 입장하지 않았을 경우 퇴장할 수 없다.") - @Test - void saveMemberActionTest2() { - MemberActionsSaveAppRequest appRequest = new MemberActionsSaveAppRequest( - List.of(new MemberActionSaveAppRequest("TOKEN", "OUT"))); - - assertThatCode(() -> memberActionService.saveMemberAction("TOKEN", appRequest)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("이벤트가 없으면 현재 참여 인원을 조회할 수 없다.") - @Test - void getCurrentMembers() { - assertThatThrownBy(() -> memberActionService.getCurrentMembers("token")) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") - @Test - void deleteMember() { - Event event = Fixture.EVENT1; - eventRepository.save(event); - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "참여자", IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "토다리", IN); - MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "쿠키", IN); - MemberAction memberAction4 = Fixture.createMemberAction(event, 4L, "소하", IN); - MemberAction memberAction5 = Fixture.createMemberAction(event, 5L, "웨디", IN); - MemberAction memberAction6 = Fixture.createMemberAction(event, 6L, "참여자", OUT); - memberActionRepository.saveAll( - List.of(memberAction1, memberAction2, memberAction3, memberAction4, memberAction5, memberAction6)); - - Event event2 = Fixture.EVENT2; - eventRepository.save(event2); - MemberAction anotherMemberAction = Fixture.createMemberAction(event2, 1L, "참여자", IN); - memberActionRepository.save(anotherMemberAction); - - memberActionService.deleteMember(event.getToken(), "참여자"); - - List memberActions = memberActionRepository.findAll(); - - assertThat(memberActions).hasSize(5) - .extracting("memberName", "status") - .containsExactly( - tuple("토다리", IN), - tuple("쿠키", IN), - tuple("소하", IN), - tuple("웨디", IN), - tuple("참여자", IN) - ); - } - - @DisplayName("이벤트에 속한 멤버을 삭제하면 전체 지출 내역 디테일이 초기화된다.") - @Test - void deleteMember1() { - Event event = Fixture.EVENT1; - eventRepository.save(event); - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "토다리", OUT); - MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "쿠키", IN); - MemberAction memberAction4 = Fixture.createMemberAction(event, 4L, "웨디", IN); - MemberAction memberAction5 = Fixture.createMemberAction(event, 5L, "감자", IN); - memberActionRepository.saveAll( - List.of(memberAction1, - memberAction2, - memberAction3, - memberAction4, - memberAction5 - ) - ); - BillAction billAction = Fixture.createBillAction(event, 6L, "뽕족", 100_000L); - billActionRepository.save(billAction); - BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "쿠키", 40_000L, true); - BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "웨디", 30_000L, false); - BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "감자", 30_000L, false); - billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3)); - - memberActionService.deleteMember(event.getToken(), "쿠키"); - - List billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); - - assertThat(billActionDetails).hasSize(2) - .extracting("memberName", "price") - .containsExactlyInAnyOrder( - tuple("웨디", 50_000L), - tuple("감자", 50_000L) - ); - } - - @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") - @Test - void deleteMemberAction() { - Event event = Fixture.EVENT1; - eventRepository.save(event); - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "토다리", OUT); - MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "쿠키", IN); - MemberAction memberAction4 = Fixture.createMemberAction(event, 4L, "웨디", IN); - MemberAction memberAction5 = Fixture.createMemberAction(event, 5L, "토다리", IN); - MemberAction memberAction6 = Fixture.createMemberAction(event, 6L, "토다리", OUT); - MemberAction memberAction7 = Fixture.createMemberAction(event, 7L, "쿠키", OUT); - memberActionRepository.saveAll( - List.of(memberAction1, - memberAction2, - memberAction3, - memberAction4, - memberAction5, - memberAction6, - memberAction7) - ); - - memberActionService.deleteMemberAction(event.getToken(), memberAction2.getId()); - List memberActions = memberActionRepository.findAll(); - - assertThat(memberActions).hasSize(4) - .extracting("id", "memberName", "status") - .containsExactly( - tuple(memberAction1.getId(), "토다리", IN), - tuple(memberAction3.getId(), "쿠키", IN), - tuple(memberAction4.getId(), "웨디", IN), - tuple(memberAction7.getId(), "쿠키", OUT) - ); - } - - @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후 지출 내역 디테일이 초기화된다.") - @Test - void deleteMemberAction1() { - Event event = Fixture.EVENT1; - eventRepository.save(event); - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "토다리", IN); - MemberAction memberAction2 = Fixture.createMemberAction(event, 2L, "토다리", OUT); - MemberAction memberAction3 = Fixture.createMemberAction(event, 3L, "쿠키", IN); - MemberAction memberAction4 = Fixture.createMemberAction(event, 4L, "웨디", IN); - MemberAction memberAction5 = Fixture.createMemberAction(event, 5L, "감자", IN); - memberActionRepository.saveAll( - List.of(memberAction1, - memberAction2, - memberAction3, - memberAction4, - memberAction5 - ) - ); - BillAction billAction = Fixture.createBillAction(event, 6L, "뽕족", 100_000L); - billActionRepository.save(billAction); - BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "쿠키", 40_000L, true); - BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "웨디", 30_000L, false); - BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "감자", 30_000L, false); - billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3)); - - memberActionService.deleteMemberAction(event.getToken(), memberAction2.getId()); - List billActionDetails = billActionDetailRepository.findAllByBillAction(billAction); - - assertThat(billActionDetails).hasSize(4) - .extracting("memberName", "price") - .containsExactlyInAnyOrder( - tuple("토다리", 25_000L), - tuple("쿠키", 25_000L), - tuple("웨디", 25_000L), - tuple("감자", 25_000L) - ); - } -} diff --git a/server/src/test/java/server/haengdong/application/MemberServiceTest.java b/server/src/test/java/server/haengdong/application/MemberServiceTest.java new file mode 100644 index 000000000..88709eb29 --- /dev/null +++ b/server/src/test/java/server/haengdong/application/MemberServiceTest.java @@ -0,0 +1,364 @@ +package server.haengdong.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.tuple; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static server.haengdong.support.fixture.Fixture.BILL1; +import static server.haengdong.support.fixture.Fixture.EVENT1; +import static server.haengdong.support.fixture.Fixture.EVENT2; +import static server.haengdong.support.fixture.Fixture.MEMBER1; +import static server.haengdong.support.fixture.Fixture.MEMBER2; +import static server.haengdong.support.fixture.Fixture.MEMBER3; + +import java.util.List; +import org.assertj.core.groups.Tuple; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import server.haengdong.application.request.MemberSaveAppRequest; +import server.haengdong.application.request.MemberUpdateAppRequest; +import server.haengdong.application.request.MembersSaveAppRequest; +import server.haengdong.application.request.MembersUpdateAppRequest; +import server.haengdong.application.response.MemberAppResponse; +import server.haengdong.application.response.MemberDepositAppResponse; +import server.haengdong.application.response.MemberSaveAppResponse; +import server.haengdong.application.response.MembersDepositAppResponse; +import server.haengdong.application.response.MembersSaveAppResponse; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.bill.BillDetail; +import server.haengdong.domain.bill.BillDetailRepository; +import server.haengdong.domain.bill.BillRepository; +import server.haengdong.domain.member.Member; +import server.haengdong.domain.member.MemberRepository; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.event.EventRepository; +import server.haengdong.exception.HaengdongException; + +class MemberServiceTest extends ServiceTestSupport { + + @Autowired + private MemberService memberService; + + @Autowired + private MemberRepository memberRepository; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private BillRepository billRepository; + + @Autowired + private BillDetailRepository billDetailRepository; + + @DisplayName("행사에 참여자를 추가한다.") + @Test + void saveMembersTest() { + Event event = EVENT1; + String memberName1 = "웨디"; + String memberName2 = "쿠키"; + Member member1 = new Member(event, memberName1); + Member member2 = new Member(event, memberName2); + eventRepository.save(event); + MembersSaveAppRequest request = new MembersSaveAppRequest( + List.of( + new MemberSaveAppRequest(member1.getName()), + new MemberSaveAppRequest(member2.getName()) + ) + ); + + MembersSaveAppResponse response = memberService.saveMembers(event.getToken(), request); + + List savedMembers = memberRepository.findAll(); + assertAll( + () -> assertThat(savedMembers) + .extracting(Member::getName) + .containsExactlyInAnyOrder(memberName1, memberName2), + () -> assertThat(response.members()) + .extracting(MemberSaveAppResponse::id, MemberSaveAppResponse::name) + .containsExactlyInAnyOrder( + Tuple.tuple(response.members().get(0).id(), memberName1), + Tuple.tuple(response.members().get(1).id(), memberName2) + ) + ); + } + + @DisplayName("행사에 존재하는 참여자를 추가하는 경우 예외가 발생한다.") + @Test + void saveMembersTest1() { + Event event = EVENT1; + Member member1 = MEMBER1; + Member member2 = MEMBER2; + eventRepository.save(event); + memberRepository.save(member1); + MembersSaveAppRequest request = new MembersSaveAppRequest( + List.of( + new MemberSaveAppRequest(member1.getName()), + new MemberSaveAppRequest(member2.getName()) + ) + ); + + assertThatThrownBy(() -> memberService.saveMembers(event.getToken(), request)) + .isInstanceOf(HaengdongException.class) + .hasMessage("현재 참여하고 있는 인원이 존재합니다."); + } + + @DisplayName("중복된 이름이 존재하는 경우 예외가 발생한다.") + @Test + void saveMembersTest2() { + Event event = EVENT1; + eventRepository.save(event); + MembersSaveAppRequest request = new MembersSaveAppRequest( + List.of( + new MemberSaveAppRequest("토다리"), + new MemberSaveAppRequest("토다리") + ) + ); + + assertThatThrownBy(() -> memberService.saveMembers(event.getToken(), request)) + .isInstanceOf(HaengdongException.class) + .hasMessageContaining("중복된 이름이 존재합니다. 입력된 이름: [토다리, 토다리]"); + } + + @DisplayName("행사 참여 인원을 삭제한다.") + @Test + void deleteMemberTest() { + Event event = EVENT1; + Member member = MEMBER1; + eventRepository.save(event); + memberRepository.save(member); + + memberService.deleteMember(event.getToken(), member.getId()); + + assertThat(memberRepository.findById(member.getId())).isEmpty(); + } + + @DisplayName("다른 이벤트의 참여 인원을 삭제하는 경우 예외가 발생한다.") + @Test + void deleteMemberTest1() { + Event event1 = EVENT1; + Event event2 = EVENT2; + Member member = new Member(EVENT2, "감자"); + eventRepository.saveAll(List.of(event1, event2)); + memberRepository.save(member); + + assertThatThrownBy(() -> memberService.deleteMember(event1.getToken(), member.getId())) + .isInstanceOf(HaengdongException.class); + + assertThat(memberRepository.findById(member.getId())).isNotEmpty(); + } + + @DisplayName("행사 참여 인원을 삭제하는 경우 해당 참여자가 포함된 Bill이 초기화된다.") + @Test + void deleteMemberTest2() { + Event event1 = EVENT1; + Member member1 = MEMBER1; + Member member2 = MEMBER2; + List members = List.of(member1, member2); + Bill bill = Bill.create(event1, "title", 10000L, members); + eventRepository.save(event1); + memberRepository.saveAll(members); + + BillDetail billDetail1 = getDetailByMember(bill, member1); + BillDetail billDetail2 = getDetailByMember(bill, member2); + billDetail1.updatePrice(8000L); + billDetail1.updateIsFixed(false); + billDetail2.updatePrice(2000L); + billDetail2.updateIsFixed(true); + billRepository.save(bill); + + memberService.deleteMember(event1.getToken(), member1.getId()); + + assertAll( + () -> assertThat(memberRepository.findById(member1.getId())).isEmpty(), + () -> assertThat(billDetailRepository.findById(billDetail1.getId())).isEmpty(), + () -> { + BillDetail foundDetail = billDetailRepository.findById(billDetail2.getId()).orElseThrow(); + assertThat(foundDetail.getPrice()).isEqualTo(10000L); + assertThat(foundDetail.isFixed()).isEqualTo(false); + } + ); + } + + private BillDetail getDetailByMember(Bill bill, Member member) { + return bill.getBillDetails() + .stream() + .filter(billDetail -> billDetail.isMember(member)) + .findFirst() + .orElseThrow(); + } + + @DisplayName("멤버 정보를 수정한다.") + @Test + void updateMembersTest() { + Event event = EVENT1; + Member member = MEMBER1; + eventRepository.save(event); + memberRepository.save(member); + MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( + List.of( + new MemberUpdateAppRequest(member.getId(), "수정된이름", true) + ) + ); + + memberService.updateMembers(event.getToken(), membersUpdateAppRequest); + + Member updatedMember = memberRepository.findById(member.getId()).orElseThrow(); + assertAll( + () -> assertThat(updatedMember.getName()).isEqualTo("수정된이름"), + () -> assertTrue(updatedMember.isDeposited()) + ); + } + + @DisplayName("수정할 멤버 id가 중복된 경우 예외가 발생한다.") + @Test + void updateMembersTest2() { + Event event = EVENT1; + Member member = MEMBER1; + eventRepository.save(event); + memberRepository.save(member); + MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( + List.of( + new MemberUpdateAppRequest(member.getId(), "수정", true), + new MemberUpdateAppRequest(member.getId(), "수정수정", false) + ) + ); + + assertThatThrownBy(() -> memberService.updateMembers(event.getToken(), membersUpdateAppRequest)) + .isInstanceOf(HaengdongException.class) + .hasMessage("중복된 참여 인원 이름 변경 요청이 존재합니다."); + } + + @DisplayName("수정할 멤버 이름이 중복된 경우 예외가 발생한다.") + @Test + void updateMembersTest3() { + Event event = EVENT1; + Member member1 = MEMBER1; + Member member2 = MEMBER2; + eventRepository.save(event); + memberRepository.saveAll(List.of(member1, member2)); + MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( + List.of( + new MemberUpdateAppRequest(member1.getId(), "수정", true), + new MemberUpdateAppRequest(member2.getId(), "수정", false) + ) + ); + + assertThatThrownBy(() -> memberService.updateMembers(event.getToken(), membersUpdateAppRequest)) + .isInstanceOf(HaengdongException.class) + .hasMessage("중복된 참여 인원 이름 변경 요청이 존재합니다."); + } + + @DisplayName("수정할 멤버가 행사에 존재하지 않는 경우 예외가 발생한다.") + @Test + void updateMembersTest4() { + Event event1 = EVENT1; + Event event2 = EVENT2; + Member member = new Member(event2, "이상"); + eventRepository.saveAll(List.of(event1, event2)); + memberRepository.save(member); + MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( + List.of( + new MemberUpdateAppRequest(member.getId(), "수정", true) + ) + ); + + assertThatThrownBy(() -> memberService.updateMembers(event1.getToken(), membersUpdateAppRequest)) + .isInstanceOf(HaengdongException.class) + .hasMessage("존재하지 않는 참여자입니다."); + } + + @DisplayName("수정하려는 행사 참여 인원 이름이 이미 존재하는 경우 예외가 발생한다.") + @Test + void updateMembersTest5() { + Event event1 = EVENT1; + Member member1 = MEMBER1; + Member member2 = MEMBER2; + eventRepository.save(event1); + memberRepository.saveAll(List.of(member1, member2)); + MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( + List.of( + new MemberUpdateAppRequest(member1.getId(), member2.getName(), true) + ) + ); + + assertThatThrownBy(() -> memberService.updateMembers(event1.getToken(), membersUpdateAppRequest)) + .isInstanceOf(HaengdongException.class) + .hasMessage("중복된 행사 참여 인원 이름이 존재합니다."); + } + + @DisplayName("참여자 간 서로의 이름으로 수정하려는 경우 예외가 발생한다.") + @Test + void updateMembersTest6() { + Event event = EVENT1; + Member member1 = MEMBER1; + Member member2 = MEMBER2; + eventRepository.save(event); + memberRepository.saveAll(List.of(member1, member2)); + MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( + List.of( + new MemberUpdateAppRequest(member1.getId(), member2.getName(), true), + new MemberUpdateAppRequest(member2.getId(), member1.getName(), false) + ) + ); + + assertThatThrownBy(() -> memberService.updateMembers(event.getToken(), membersUpdateAppRequest)) + .isInstanceOf(HaengdongException.class) + .hasMessage("중복된 행사 참여 인원 이름이 존재합니다."); + } + + @DisplayName("행사에 참여한 전체 인원을 조회한다.") + @Test + void findAllMembersTest() { + Event event = EVENT1; + Bill bill = BILL1; + Member member1 = MEMBER1; + Member member2 = MEMBER2; + Member member3 = MEMBER3; + eventRepository.save(event); + memberRepository.saveAll(List.of(member1, member2, member3)); + billRepository.save(bill); + + MembersDepositAppResponse membersDepositAppResponse = memberService.findAllMembers(event.getToken()); + + assertThat(membersDepositAppResponse.members()).hasSize(3) + .extracting(MemberDepositAppResponse::name, MemberDepositAppResponse::isDeposited) + .containsExactlyInAnyOrder( + tuple(member1.getName(), member1.isDeposited()), + tuple(member2.getName(), member2.isDeposited()), + tuple(member3.getName(), member3.isDeposited()) + ); + } + + @DisplayName("행사에 현재 참여 중인 인원을 조회한다.") + @Test + void getCurrentMembersTest() { + Event event = EVENT1; + Member member1 = MEMBER1; + Member member2 = MEMBER2; + Member member3 = MEMBER3; + Bill bill = Bill.create(event, "title", 100000L, List.of(member1, member2, member3)); + eventRepository.save(event); + memberRepository.saveAll(List.of(member1, member2, member3)); + billRepository.save(bill); + + List currentMembers = memberService.getCurrentMembers(event.getToken()); + + assertThat(currentMembers).hasSize(3) + .extracting(MemberAppResponse::id, MemberAppResponse::name) + .containsExactlyInAnyOrder( + tuple(member1.getId(), member1.getName()), + tuple(member2.getId(), member2.getName()), + tuple(member3.getId(), member3.getName()) + ); + } + + @DisplayName("행사가 없으면 현재 참여 인원을 조회할 수 없다.") + @Test + void getCurrentMembersTest1() { + assertThatThrownBy(() -> memberService.getCurrentMembers("token")) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/docs/AdminBillActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/AdminBillControllerDocsTest.java similarity index 60% rename from server/src/test/java/server/haengdong/docs/AdminBillActionControllerDocsTest.java rename to server/src/test/java/server/haengdong/docs/AdminBillControllerDocsTest.java index 705adaa5c..1c275801e 100644 --- a/server/src/test/java/server/haengdong/docs/AdminBillActionControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/AdminBillControllerDocsTest.java @@ -23,44 +23,39 @@ import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; import org.springframework.restdocs.payload.JsonFieldType; -import server.haengdong.application.BillActionDetailService; -import server.haengdong.application.BillActionService; -import server.haengdong.presentation.admin.AdminBillActionController; -import server.haengdong.presentation.request.BillActionDetailUpdateRequest; -import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; -import server.haengdong.presentation.request.BillActionSaveRequest; -import server.haengdong.presentation.request.BillActionUpdateRequest; -import server.haengdong.presentation.request.BillActionsSaveRequest; +import server.haengdong.application.BillService; +import server.haengdong.presentation.admin.AdminBillController; +import server.haengdong.presentation.request.BillDetailUpdateRequest; +import server.haengdong.presentation.request.BillDetailsUpdateRequest; +import server.haengdong.presentation.request.BillSaveRequest; +import server.haengdong.presentation.request.BillUpdateRequest; +import server.haengdong.support.fixture.Fixture; -class AdminBillActionControllerDocsTest extends RestDocsSupport { +class AdminBillControllerDocsTest extends RestDocsSupport { - private final BillActionService billActionService = mock(BillActionService.class); - private final BillActionDetailService billActionDetailService = mock(BillActionDetailService.class); + private final BillService billService = mock(BillService.class); @Override protected Object initController() { - return new AdminBillActionController(billActionService, billActionDetailService); + return new AdminBillController(billService); } @DisplayName("지출 내역을 생성한다.") @Test - void saveAllBillAction() throws Exception { - BillActionsSaveRequest request = new BillActionsSaveRequest( - List.of( - new BillActionSaveRequest("뽕족", 10_000L), - new BillActionSaveRequest("인생맥주", 10_000L) - ) - ); + void saveAllBill() throws Exception { + List members = List.of(1L, 2L); + BillSaveRequest request = new BillSaveRequest("뽕족", 10_000L, members); + String requestBody = objectMapper.writeValueAsString(request); String eventId = "쿠키토큰"; - mockMvc.perform(post("/api/admin/events/{eventId}/bill-actions", eventId) + mockMvc.perform(post("/api/admin/events/{eventId}/bills", eventId) .contentType(MediaType.APPLICATION_JSON) - .cookie(EVENT_COOKIE) - .content(requestBody)) + .content(requestBody) + .cookie(Fixture.EVENT_COOKIE)) .andDo(print()) .andExpect(status().isOk()) - .andDo(document("createBillActions", + .andDo(document("createBills", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), pathParameters( @@ -70,81 +65,81 @@ void saveAllBillAction() throws Exception { cookieWithName("eventToken").description("행사 관리자 토큰") ), requestFields( - fieldWithPath("actions").description("생성할 지출 액션 목록"), - fieldWithPath("actions[0].title").description("생성할 지출 액션의 제목"), - fieldWithPath("actions[0].price").description("생성할 지출 액션의 금액") + fieldWithPath("title").description("생성할 지출 제목"), + fieldWithPath("price").description("생성할 지출 금액"), + fieldWithPath("memberIds").description("생성할 지출의 참여인원 ID 리스트") ) )); } - @DisplayName("지출 액션을 수정한다.") + @DisplayName("지출을 수정한다.") @Test - void updateBillAction() throws Exception { - BillActionUpdateRequest request = new BillActionUpdateRequest("뽕족", 10_000L); + void updateBill() throws Exception { + BillUpdateRequest request = new BillUpdateRequest("뽕족", 10_000L); String requestBody = objectMapper.writeValueAsString(request); String eventId = "웨디토큰"; - mockMvc.perform(put("/api/admin/events/{eventId}/bill-actions/{actionId}", eventId, 1L) - .cookie(EVENT_COOKIE) + mockMvc.perform(put("/api/admin/events/{eventId}/bills/{billId}", eventId, 1L) .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + .content(requestBody) + .cookie(EVENT_COOKIE)) .andDo(print()) .andExpect(status().isOk()) - .andDo(document("updateBillAction", + .andDo(document("updateBill", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), pathParameters( parameterWithName("eventId").description("행사 ID"), - parameterWithName("actionId").description("지출 액션 ID") + parameterWithName("billId").description("지출 ID") ), requestCookies( cookieWithName("eventToken").description("행사 관리자 토큰") ), requestFields( - fieldWithPath("title").description("수정할 지출 액션의 제목"), - fieldWithPath("price").description("수정할 지출 액션의 금액") + fieldWithPath("title").description("수정할 지출 제목"), + fieldWithPath("price").description("수정할 지출 금액") ) )); } @DisplayName("참여자별 지출 금액을 수정한다.") @Test - void updateBillActionDetailsTest() throws Exception { - List billActionDetailUpdateRequests = List.of( - new BillActionDetailUpdateRequest("소하", 10000L, true), - new BillActionDetailUpdateRequest("웨디", 20000L, true) + void updateBillDetailsTest() throws Exception { + List billDetailUpdateRequests = List.of( + new BillDetailUpdateRequest(1L, 10000L, true), + new BillDetailUpdateRequest(2L, 20000L, true) ); - BillActionDetailsUpdateRequest request = new BillActionDetailsUpdateRequest( - billActionDetailUpdateRequests); + BillDetailsUpdateRequest request = new BillDetailsUpdateRequest( + billDetailUpdateRequests); String json = objectMapper.writeValueAsString(request); - mockMvc.perform(put("/api/admin/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) + mockMvc.perform(put("/api/admin/events/{eventId}/bills/{billId}/details", "TOKEN", 1L) .cookie(EVENT_COOKIE) .contentType(MediaType.APPLICATION_JSON) .content(json)) .andDo(print()) .andExpect(status().isOk()) .andDo( - document("updateBillActionDetailsTest", + document("updateBillDetails", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), pathParameters( parameterWithName("eventId").description("행사 ID"), - parameterWithName("actionId").description("액션 ID") + parameterWithName("billId").description("지출 ID") ), requestCookies( cookieWithName("eventToken").description("행사 관리자 토큰") ), requestFields( - fieldWithPath("members").type(JsonFieldType.ARRAY) + fieldWithPath("billDetails").type(JsonFieldType.ARRAY) .description("전체 정산 수정 요청 목록"), - fieldWithPath("members[0].name").type(JsonFieldType.STRING) + fieldWithPath("billDetails[0].id").type(JsonFieldType.NUMBER) .description("참여자 이름"), - fieldWithPath("members[0].price").type(JsonFieldType.NUMBER) + fieldWithPath("billDetails[0].price").type(JsonFieldType.NUMBER) .description("참여자 정산 금액"), - fieldWithPath("members[0].isFixed").type(JsonFieldType.BOOLEAN) + fieldWithPath("billDetails[0].isFixed").type(JsonFieldType.BOOLEAN) .description("참여자 정산 금액 수정 여부") ) ) @@ -153,20 +148,20 @@ void updateBillActionDetailsTest() throws Exception { @DisplayName("지출 내역을 삭제한다.") @Test - void deleteBillAction() throws Exception { + void deleteBill() throws Exception { String eventId = "토다리토큰"; - mockMvc.perform(delete("/api/admin/events/{eventId}/bill-actions/{actionId}", eventId, 1) + mockMvc.perform(delete("/api/admin/events/{eventId}/bills/{billId}", eventId, 1) .cookie(EVENT_COOKIE) ) .andDo(print()) .andExpect(status().isOk()) - .andDo(document("deleteBillAction", + .andDo(document("deleteBill", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), pathParameters( parameterWithName("eventId").description("행사 ID"), - parameterWithName("actionId").description("지출 액션 ID") + parameterWithName("billId").description("지출 ID") ), requestCookies( cookieWithName("eventToken").description("행사 관리자 토큰") diff --git a/server/src/test/java/server/haengdong/docs/AdminEventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/AdminEventControllerDocsTest.java index 956035e92..22c028169 100644 --- a/server/src/test/java/server/haengdong/docs/AdminEventControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/AdminEventControllerDocsTest.java @@ -4,8 +4,8 @@ import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.patch; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; @@ -17,17 +17,15 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; -import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; import org.springframework.restdocs.payload.JsonFieldType; import server.haengdong.application.EventService; import server.haengdong.presentation.admin.AdminEventController; -import server.haengdong.presentation.request.MemberNameUpdateRequest; -import server.haengdong.presentation.request.MemberNamesUpdateRequest; +import server.haengdong.presentation.request.EventUpdateRequest; -public class AdminEventControllerDocsTest extends RestDocsSupport { +class AdminEventControllerDocsTest extends RestDocsSupport { private final EventService eventService = mock(EventService.class); @@ -59,40 +57,38 @@ void authenticateTest() throws Exception { ); } - @DisplayName("행사 참여 인원의 이름을 수정한다.") + @DisplayName("행사 정보를 업데이트한다.") @Test - void updateMember() throws Exception { + void updateEventTest() throws Exception { String token = "TOKEN"; - MemberNamesUpdateRequest memberNameUpdateRequest = new MemberNamesUpdateRequest(List.of( - new MemberNameUpdateRequest("토다링", "토쟁이"), - new MemberNameUpdateRequest("감자", "고구마") - )); + EventUpdateRequest eventUpdateRequest = new EventUpdateRequest("행동대장 비대위", "행대뱅크", "12345678"); - String requestBody = objectMapper.writeValueAsString(memberNameUpdateRequest); + String requestBody = objectMapper.writeValueAsString(eventUpdateRequest); - mockMvc.perform(put("/api/admin/events/{eventId}/members/nameChange", token) - .cookie(EVENT_COOKIE) - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + mockMvc.perform(patch("/api/admin/events/{eventId}", token) + .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("수정 후 참여자 이름") - ) + document("updateEvent", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 관리자 토큰") + ), + requestFields( + fieldWithPath("eventName").type(JsonFieldType.STRING) + .description("수정할 이벤트 이름").optional(), + fieldWithPath("bankName").type(JsonFieldType.STRING) + .description("은행 이름").optional(), + fieldWithPath("accountNumber").type(JsonFieldType.STRING) + .description("계좌 번호").optional() + ) ) ); } diff --git a/server/src/test/java/server/haengdong/docs/AdminMemberActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/AdminMemberActionControllerDocsTest.java deleted file mode 100644 index f8a4f7dbd..000000000 --- a/server/src/test/java/server/haengdong/docs/AdminMemberActionControllerDocsTest.java +++ /dev/null @@ -1,121 +0,0 @@ -package server.haengdong.docs; - -import static org.mockito.Mockito.mock; -import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; -import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; -import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; -import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; -import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; -import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.http.MediaType; -import org.springframework.restdocs.payload.JsonFieldType; -import server.haengdong.application.MemberActionService; -import server.haengdong.presentation.admin.AdminMemberActionController; -import server.haengdong.presentation.request.MemberActionsSaveRequest; - -public class AdminMemberActionControllerDocsTest extends RestDocsSupport { - - private final MemberActionService memberActionService = mock(MemberActionService.class); - - @Override - protected Object initController() { - return new AdminMemberActionController(memberActionService); - } - - @DisplayName("참여자 행동을 추가한다.") - @Test - void saveMemberActionTest() throws Exception { - MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest( - List.of("웨디", "소하", "토다리", "쿠키"), "IN"); - - String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); - - mockMvc.perform(post("/api/admin/events/{eventId}/member-actions", "망쵸토큰") - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody) - .cookie(EVENT_COOKIE)) - .andDo(print()) - .andExpect(status().isOk()) - .andDo( - document("createMemberAction", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - requestCookies( - cookieWithName("eventToken").description("토큰 토큰") - ), - requestFields( - fieldWithPath("members").type(JsonFieldType.ARRAY) - .description("액션 대상 참여자 목록"), - fieldWithPath("status").type(JsonFieldType.STRING) - .description("참여자 액션 상태 [IN(늦참), OUT(탈주)]") - ) - ) - ); - } - - @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") - @Test - void deleteMemberAction() throws Exception { - String eventId = "망쵸토큰"; - Long actionId = 2L; - - mockMvc.perform(delete("/api/admin/events/{eventId}/member-actions/{actionId}", eventId, actionId) - .cookie(EVENT_COOKIE)) - .andDo(print()) - .andExpect(status().isOk()) - .andDo( - document("deleteMemberAction", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID"), - parameterWithName("actionId").description("액션 ID") - ), - requestCookies( - cookieWithName("eventToken").description("행사 관리자용 토큰") - ) - ) - ); - } - - @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") - @Test - void deleteMember() throws Exception { - String eventId = "망쵸토큰"; - String memberName = "행동대장"; - - mockMvc.perform(delete("/api/admin/events/{eventId}/members/{memberName}", eventId, memberName) - .cookie(EVENT_COOKIE)) - .andDo(print()) - .andExpect(status().isOk()) - .andDo( - document("deleteAllMemberActionByName", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID"), - parameterWithName("memberName").description("행사 참여자 이름") - ), - requestCookies( - cookieWithName("eventToken").description("행사 관리자용 토큰") - ) - ) - ); - } -} diff --git a/server/src/test/java/server/haengdong/docs/AdminMemberControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/AdminMemberControllerDocsTest.java new file mode 100644 index 000000000..9d70673f9 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/AdminMemberControllerDocsTest.java @@ -0,0 +1,173 @@ +package server.haengdong.docs; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; +import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import server.haengdong.application.MemberService; +import server.haengdong.application.response.MemberSaveAppResponse; +import server.haengdong.application.response.MembersSaveAppResponse; +import server.haengdong.presentation.admin.AdminMemberController; +import server.haengdong.presentation.request.MemberSaveRequest; +import server.haengdong.presentation.request.MemberUpdateRequest; +import server.haengdong.presentation.request.MembersSaveRequest; +import server.haengdong.presentation.request.MembersUpdateRequest; + +class AdminMemberControllerDocsTest extends RestDocsSupport { + + private final MemberService memberService = mock(MemberService.class); + + @Override + protected Object initController() { + return new AdminMemberController(memberService); + } + + @DisplayName("행사 참여자를 추가한다.") + @Test + void saveMemberTest() throws Exception { + String eventToken = "망쵸토큰"; + MembersSaveRequest membersSaveRequest = new MembersSaveRequest( + List.of( + new MemberSaveRequest("웨디"), + new MemberSaveRequest("소하") + ) + ); + String requestBody = objectMapper.writeValueAsString(membersSaveRequest); + MembersSaveAppResponse appResponse = new MembersSaveAppResponse( + List.of( + new MemberSaveAppResponse(1L, "웨디"), + new MemberSaveAppResponse(2L, "소하") + ) + ); + given(memberService.saveMembers(eventToken, membersSaveRequest.toAppRequest())) + .willReturn(appResponse); + + mockMvc.perform(post("/api/admin/events/{eventId}/members", "망쵸토큰") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.members[0].id").value(equalTo(1))) + .andExpect(MockMvcResultMatchers.jsonPath("$.members[0].name").value(equalTo("웨디"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.members[1].id").value(equalTo(2))) + .andExpect(MockMvcResultMatchers.jsonPath("$.members[1].name").value(equalTo("소하"))) + .andDo( + document("saveMembers", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("토큰 토큰") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("행사에 추가할 참여자 목록"), + fieldWithPath("members[].name").type(JsonFieldType.STRING) + .description("참여자 이름") + ), + responseFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("행사에 추가된 참여자 목록"), + fieldWithPath("members[].id").type(JsonFieldType.NUMBER) + .description("참여자 ID"), + fieldWithPath("members[].name").type(JsonFieldType.STRING) + .description("참여자 이름") + ) + ) + ); + } + + @DisplayName("행사 참여 인원을 삭제한다.") + @Test + void deleteMember() throws Exception { + String eventId = "망쵸토큰"; + Long memberId = 1L; + + mockMvc.perform(delete("/api/admin/events/{eventId}/members/{memberId}", eventId, memberId) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("deleteMember", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("memberId").description("삭제할 참여자 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 토큰") + ) + ) + ); + } + + @DisplayName("행사 참여 인원 정보를 수정한다.") + @Test + void updateMembers() throws Exception { + String eventId = "망쵸토큰"; + MembersUpdateRequest membersUpdateRequest = new MembersUpdateRequest( + List.of( + new MemberUpdateRequest(1L, "토다리", true), + new MemberUpdateRequest(2L, "쿠키", false) + ) + ); + String requestBody = objectMapper.writeValueAsString(membersUpdateRequest); + + mockMvc.perform(put("/api/admin/events/{eventId}/members", eventId) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + .cookie(EVENT_COOKIE) + ) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("updateMembers", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + requestCookies( + cookieWithName("eventToken").description("행사 토큰") + ), + requestFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("수정할 참여자 목록"), + fieldWithPath("members[].id").type(JsonFieldType.NUMBER) + .description("참여자 ID"), + fieldWithPath("members[].name").type(JsonFieldType.STRING) + .description("참여자 이름"), + fieldWithPath("members[].isDeposited").type(JsonFieldType.BOOLEAN) + .description("참여자 입금 여부") + ) + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java deleted file mode 100644 index d79bd2c02..000000000 --- a/server/src/test/java/server/haengdong/docs/BillActionDetailControllerDocsTest.java +++ /dev/null @@ -1,79 +0,0 @@ -package server.haengdong.docs; - -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; -import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; -import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; -import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; -import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; -import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.restdocs.payload.JsonFieldType; -import server.haengdong.application.BillActionDetailService; -import server.haengdong.application.response.BillActionDetailAppResponse; -import server.haengdong.application.response.BillActionDetailsAppResponse; -import server.haengdong.presentation.BillActionDetailController; - -public class BillActionDetailControllerDocsTest extends RestDocsSupport { - - private final BillActionDetailService billActionDetailService = mock(BillActionDetailService.class); - - @Override - protected Object initController() { - return new BillActionDetailController(billActionDetailService); - } - - @DisplayName("참여자별 지출 금액을 조회한다.") - @Test - void findBillActionDetailsTest() throws Exception { - BillActionDetailsAppResponse appResponse = new BillActionDetailsAppResponse( - List.of(new BillActionDetailAppResponse("토다리", 1000L, false))); - given(billActionDetailService.findBillActionDetails(anyString(), anyLong())) - .willReturn(appResponse); - - mockMvc.perform(get("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) - .cookie(EVENT_COOKIE)) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.members").isArray()) - .andExpect(jsonPath("$.members[0].name").value("토다리")) - .andExpect(jsonPath("$.members[0].price").value(1000L)) - .andExpect(jsonPath("$.members[0].isFixed").value(false)) - .andDo( - document("findBillActionDetailsTest", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID"), - parameterWithName("actionId").description("액션 ID") - ), requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") - ), responseFields( - fieldWithPath("members").type(JsonFieldType.ARRAY) - .description("전체 정산 수정 요청 목록"), - fieldWithPath("members[0].name").type(JsonFieldType.STRING) - .description("참여자 이름"), - fieldWithPath("members[0].price").type(JsonFieldType.NUMBER) - .description("참여자 정산 금액"), - fieldWithPath("members[0].isFixed").type(JsonFieldType.BOOLEAN) - .description("참여자 정산 금액 수정 여부") - ) - ) - ); - } -} diff --git a/server/src/test/java/server/haengdong/docs/BillControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/BillControllerDocsTest.java new file mode 100644 index 000000000..f960d6195 --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/BillControllerDocsTest.java @@ -0,0 +1,119 @@ +package server.haengdong.docs; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +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 server.haengdong.application.BillService; +import server.haengdong.application.response.BillAppResponse; +import server.haengdong.application.response.BillDetailAppResponse; +import server.haengdong.application.response.BillDetailsAppResponse; +import server.haengdong.application.response.MemberAppResponse; +import server.haengdong.application.response.StepAppResponse; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.member.Member; +import server.haengdong.presentation.BillController; +import server.haengdong.support.fixture.Fixture; + +class BillControllerDocsTest extends RestDocsSupport { + + private final BillService billService = mock(BillService.class); + + @Override + protected Object initController() { + return new BillController(billService); + } + + @DisplayName("전체 지출 내역을 조회한다.") + @Test + void findBills() throws Exception { + Bill bill = Fixture.BILL1; + List bills = List.of(BillAppResponse.of(bill)); + + Member member = Fixture.MEMBER1; + List members = List.of(MemberAppResponse.of(member)); + + StepAppResponse stepAppResponse = new StepAppResponse(bills, members); + given(billService.findSteps(anyString())).willReturn(List.of(stepAppResponse)); + + mockMvc.perform(get("/api/events/{eventId}/bills", "token")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.steps").isArray()) + .andExpect(jsonPath("$.steps[0].bills").isArray()) + .andExpect(jsonPath("$.steps[0].bills[0].id").value(bill.getId())) + .andExpect(jsonPath("$.steps[0].bills[0].title").value(bill.getTitle())) + .andExpect(jsonPath("$.steps[0].bills[0].price").value(bill.getPrice())) + .andExpect(jsonPath("$.steps[0].bills[0].isFixed").value(bill.isFixed())) + .andExpect(jsonPath("$.steps[0].members").isArray()) + .andExpect(jsonPath("$.steps[0].members[0].id").value(member.getId())) + .andExpect(jsonPath("$.steps[0].members[0].name").value(member.getName())) + .andDo(document("findBills", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("steps").description("지출 차수 목록"), + fieldWithPath("steps[].bills").description("해당 차수의 지출 내역"), + fieldWithPath("steps[].bills[].id").description("지출 ID"), + fieldWithPath("steps[].bills[].title").description("지출 이름"), + fieldWithPath("steps[].bills[].price").description("지출 금액"), + fieldWithPath("steps[].bills[].isFixed").description("지출 수정 여부"), + fieldWithPath("steps[].members").description("해당 차수의 참여자 목록"), + fieldWithPath("steps[].members[].id").description("참여자 ID"), + fieldWithPath("steps[].members[].name").description("참여자 이름") + ) + ) + ); + } + + + @DisplayName("참여자별 지출 금액을 조회한다.") + @Test + void findBillActionDetails() throws Exception { + BillDetailsAppResponse appResponse = new BillDetailsAppResponse( + List.of(new BillDetailAppResponse(1L, "토다리", 1000L, false))); + given(billService.findBillDetails(anyString(), anyLong())).willReturn(appResponse); + + mockMvc.perform(get("/api/events/{eventId}/bills/{billId}/details", "TOKEN", 1L)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].id").value(1L)) + .andExpect(jsonPath("$.members[0].memberName").value("토다리")) + .andExpect(jsonPath("$.members[0].price").value(1000L)) + .andExpect(jsonPath("$.members[0].isFixed").value(false)) + .andDo(document("findBillDetails", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID"), + parameterWithName("billId").description("지출 ID") + ), responseFields( + fieldWithPath("members").description("참여자 목록"), + fieldWithPath("members[].id").description("참여자 ID"), + fieldWithPath("members[].memberName").description("참여자 이름"), + fieldWithPath("members[].price").description("참여자별 지출 금액"), + fieldWithPath("members[].isFixed").description("지출 수정 여부") + ) + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java index 6950f3d23..36a752953 100644 --- a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java @@ -2,7 +2,6 @@ import static org.hamcrest.Matchers.equalTo; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; @@ -33,18 +32,15 @@ import server.haengdong.application.AuthService; import server.haengdong.application.EventService; import server.haengdong.application.request.EventAppRequest; -import server.haengdong.application.response.ActionAppResponse; -import server.haengdong.application.response.ActionAppResponse.ActionType; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.application.response.MembersAppResponse; import server.haengdong.infrastructure.auth.CookieProperties; import server.haengdong.presentation.EventController; import server.haengdong.presentation.request.EventLoginRequest; import server.haengdong.presentation.request.EventSaveRequest; -public class EventControllerDocsTest extends RestDocsSupport { +class EventControllerDocsTest extends RestDocsSupport { private final EventService eventService = mock(EventService.class); private final AuthService authService = mock(AuthService.class); @@ -61,7 +57,7 @@ protected Object initController() { @Test void findEventTest() throws Exception { String eventId = "망쵸토큰"; - EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식"); + EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식", "토스 12312455"); given(eventService.findEvent(eventId)).willReturn(eventDetailAppResponse); mockMvc.perform(get("/api/events/{eventId}", eventId)) @@ -76,170 +72,8 @@ void findEventTest() throws Exception { parameterWithName("eventId").description("행사 ID") ), responseFields( - fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름") - ) - ) - ); - } - - @DisplayName("행사에 참여한 전체 인원을 중복 없이 조회한다.") - @Test - void findAllMembersTest() throws Exception { - MembersAppResponse memberAppResponse = new MembersAppResponse(List.of("토다리", "쿠키")); - given(eventService.findAllMembers(anyString())).willReturn(memberAppResponse); - - mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.memberNames").isArray()) - .andExpect(jsonPath("$.memberNames[0]").value("토다리")) - .andExpect(jsonPath("$.memberNames[1]").value("쿠키")) - .andDo( - document("findAllEventMember", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("memberNames").type(JsonFieldType.ARRAY) - .description("행사 참여자 목록") - ) - ) - ); - } - - @DisplayName("행사 전체 액션 이력 조회") - @Test - void findActions() 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", token) - .accept(MediaType.APPLICATION_JSON)) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.steps[0].type").value(equalTo("IN"))) - .andExpect(jsonPath("$.steps[0].stepName").value(equalTo("0차"))) - .andExpect(jsonPath("$.steps[0].members[0]").value(equalTo("망쵸"))) - .andExpect(jsonPath("$.steps[0].actions[0].actionId").value(equalTo(1))) - .andExpect(jsonPath("$.steps[0].actions[0].name").value(equalTo("망쵸"))) - .andExpect(jsonPath("$.steps[0].actions[0].price").value(equalTo(null))) - .andExpect(jsonPath("$.steps[0].actions[0].sequence").value(equalTo(1))) - - .andExpect(jsonPath("$.steps[1].type").value(equalTo("BILL"))) - .andExpect(jsonPath("$.steps[1].stepName").value(equalTo("1차"))) - .andExpect(jsonPath("$.steps[1].members[0]").value(equalTo("망쵸"))) - .andExpect(jsonPath("$.steps[1].actions[0].actionId").value(equalTo(2))) - .andExpect(jsonPath("$.steps[1].actions[0].name").value(equalTo("족발"))) - .andExpect(jsonPath("$.steps[1].actions[0].price").value(equalTo(100))) - .andExpect(jsonPath("$.steps[1].actions[0].sequence").value(equalTo(2))) - - .andExpect(jsonPath("$.steps[1].actions[1].actionId").value(equalTo(3))) - .andExpect(jsonPath("$.steps[1].actions[1].name").value(equalTo("인생네컷"))) - .andExpect(jsonPath("$.steps[1].actions[1].price").value(equalTo(1000))) - .andExpect(jsonPath("$.steps[1].actions[1].sequence").value(equalTo(3))) - - .andExpect(jsonPath("$.steps[2].type").value(equalTo("OUT"))) - .andExpect(jsonPath("$.steps[2].stepName").value(equalTo("1차"))) - .andExpect(jsonPath("$.steps[2].actions[0].actionId").value(equalTo(4))) - .andExpect(jsonPath("$.steps[2].actions[0].name").value(equalTo("망쵸"))) - .andExpect(jsonPath("$.steps[2].actions[0].price").value(equalTo(null))) - .andExpect(jsonPath("$.steps[2].actions[0].sequence").value(equalTo(4))) - - .andDo( - document("findActions", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("steps[].stepName").type(JsonFieldType.STRING) - .description("스탭 이름"), - 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("액션 순서"), - fieldWithPath("steps[].actions[].isFixed").type(JsonFieldType.BOOLEAN) - .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("액션 타입") + fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름"), + fieldWithPath("account").type(JsonFieldType.STRING).description("행사 계좌") ) ) ); @@ -249,7 +83,9 @@ void findActions2() throws Exception { @Test void getMemberBillReports() throws Exception { List memberBillReportAppResponses = List.of( - new MemberBillReportAppResponse("소하", 20_000L), new MemberBillReportAppResponse("토다리", 200_000L)); + new MemberBillReportAppResponse(1L, "소하", false, 20_000L), + new MemberBillReportAppResponse(2L, "토다리", false, 200_000L) + ); given(eventService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); @@ -257,9 +93,13 @@ void getMemberBillReports() throws Exception { .accept(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].name").value(equalTo("소하"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].memberId").value(equalTo(1))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].memberName").value(equalTo("소하"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].isDeposited").value(equalTo(false))) .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].price").value(equalTo(20_000))) - .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].name").value(equalTo("토다리"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].memberId").value(equalTo(2))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].memberName").value(equalTo("토다리"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].isDeposited").value(equalTo(false))) .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].price").value(equalTo(200_000))) .andDo( document("getMemberBillReports", @@ -270,7 +110,11 @@ void getMemberBillReports() throws Exception { ), responseFields( fieldWithPath("reports").type(JsonFieldType.ARRAY).description("전체 정산 현황 목록"), - fieldWithPath("reports[0].name").type(JsonFieldType.STRING) + fieldWithPath("reports[0].memberId").type(JsonFieldType.NUMBER) + .description("참여자 ID"), + fieldWithPath("reports[0].memberName").type(JsonFieldType.STRING) + .description("참여자 이름"), + fieldWithPath("reports[0].isDeposited").type(JsonFieldType.BOOLEAN) .description("참여자 이름"), fieldWithPath("reports[0].price").type(JsonFieldType.NUMBER) .description("참여자 정산 금액") diff --git a/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java deleted file mode 100644 index ace03c5ef..000000000 --- a/server/src/test/java/server/haengdong/docs/MemberActionControllerDocsTest.java +++ /dev/null @@ -1,66 +0,0 @@ -package server.haengdong.docs; - -import static org.hamcrest.Matchers.equalTo; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; -import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; -import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; -import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; -import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -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.http.MediaType; -import org.springframework.restdocs.payload.JsonFieldType; -import server.haengdong.application.MemberActionService; -import server.haengdong.application.response.CurrentMemberAppResponse; -import server.haengdong.presentation.MemberActionController; - -public class MemberActionControllerDocsTest extends RestDocsSupport { - - private final MemberActionService memberActionService = mock(MemberActionService.class); - - @Override - protected Object initController() { - return new MemberActionController(memberActionService); - } - - @DisplayName("현재 참여 인원을 조회합니다.") - @Test - void getCurrentMembers() throws Exception { - List currentMemberAppResponses = List.of( - new CurrentMemberAppResponse("소하"), new CurrentMemberAppResponse("토다리")); - - given(memberActionService.getCurrentMembers(any())).willReturn(currentMemberAppResponses); - - mockMvc.perform(get("/api/events/{eventId}/members/current", "망쵸토큰") - .accept(MediaType.APPLICATION_JSON)) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.memberNames[0]").value(equalTo("소하"))) - .andExpect(jsonPath("$.memberNames[1]").value(equalTo("토다리"))) - .andDo( - document("getCurrentMembers", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint()), - pathParameters( - parameterWithName("eventId").description("행사 ID") - ), - responseFields( - fieldWithPath("memberNames").type(JsonFieldType.ARRAY) - .description("현재 탈주 가능한 참여 인원 이름 목록") - ) - ) - ); - } -} diff --git a/server/src/test/java/server/haengdong/docs/MemberControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/MemberControllerDocsTest.java new file mode 100644 index 000000000..2997ad4ee --- /dev/null +++ b/server/src/test/java/server/haengdong/docs/MemberControllerDocsTest.java @@ -0,0 +1,120 @@ +package server.haengdong.docs; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +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.restdocs.payload.JsonFieldType; +import server.haengdong.application.MemberService; +import server.haengdong.application.response.MemberAppResponse; +import server.haengdong.application.response.MemberDepositAppResponse; +import server.haengdong.application.response.MembersDepositAppResponse; +import server.haengdong.presentation.MemberController; + +class MemberControllerDocsTest extends RestDocsSupport { + + private final MemberService memberService = mock(MemberService.class); + + @Override + protected Object initController() { + return new MemberController(memberService); + } + + @DisplayName("행사에 참여한 전체 인원을 조회한다.") + @Test + void findAllMembersTest() throws Exception { + List members = List.of( + new MemberDepositAppResponse(1L, "감자", false), + new MemberDepositAppResponse(2L, "백호", true), + new MemberDepositAppResponse(3L, "이상", true) + ); + + MembersDepositAppResponse memberAppResponse = new MembersDepositAppResponse(members); + given(memberService.findAllMembers(anyString())).willReturn(memberAppResponse); + + mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].id").value(1L)) + .andExpect(jsonPath("$.members[0].name").value("감자")) + .andExpect(jsonPath("$.members[0].isDeposited").value(false)) + .andExpect(jsonPath("$.members[1].id").value(2L)) + .andExpect(jsonPath("$.members[1].name").value("백호")) + .andExpect(jsonPath("$.members[1].isDeposited").value(true)) + .andExpect(jsonPath("$.members[2].id").value(3L)) + .andExpect(jsonPath("$.members[2].name").value("이상")) + .andExpect(jsonPath("$.members[2].isDeposited").value(true)) + .andDo( + document("findAllMembers", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("행사에 참여 중인 전체 멤버 목록"), + fieldWithPath("members[0].id").type(JsonFieldType.NUMBER) + .description("멤버 ID"), + fieldWithPath("members[0].name").type(JsonFieldType.STRING) + .description("멤버 이름"), + fieldWithPath("members[0].isDeposited").type(JsonFieldType.BOOLEAN) + .description("입금 여부") + ) + ) + ); + } + + @DisplayName("현재 참여 인원을 조회합니다.") + @Test + void getCurrentMembers() throws Exception { + List members = List.of( + new MemberAppResponse(1L, "감자"), + new MemberAppResponse(2L, "백호") + ); + + given(memberService.getCurrentMembers(any())).willReturn(members); + + mockMvc.perform(get("/api/events/{eventId}/members/current", "TOKEN")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].id").value(1L)) + .andExpect(jsonPath("$.members[0].name").value("감자")) + .andExpect(jsonPath("$.members[1].id").value(2L)) + .andExpect(jsonPath("$.members[1].name").value("백호")) + .andDo( + document("getCurrentMembers", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + pathParameters( + parameterWithName("eventId").description("행사 ID") + ), + responseFields( + fieldWithPath("members").type(JsonFieldType.ARRAY) + .description("현재 행사에 참여 중인 멤버 목록"), + fieldWithPath("members[0].id").type(JsonFieldType.NUMBER) + .description("멤버 ID"), + fieldWithPath("members[0].name").type(JsonFieldType.STRING) + .description("멤버 이름") + ) + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java b/server/src/test/java/server/haengdong/domain/action/BillActionTest.java deleted file mode 100644 index d66202663..000000000 --- a/server/src/test/java/server/haengdong/domain/action/BillActionTest.java +++ /dev/null @@ -1,86 +0,0 @@ -package server.haengdong.domain.action; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.assertAll; -import static server.haengdong.support.fixture.Fixture.BILL_ACTION; -import static server.haengdong.support.fixture.Fixture.EVENT1; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import server.haengdong.exception.HaengdongException; -import server.haengdong.support.fixture.Fixture; - -class BillActionTest { - - @DisplayName("지출 내역 제목의 앞뒤 공백을 제거한 길이가 1 ~ 30자가 아니면 지출을 생성할 수 없다.") - @ParameterizedTest - @ValueSource(strings = {"", " ", "1234567890123456789012345678901"}) - void validateTitle(String title) { - Sequence sequence = new Sequence(1L); - Long price = 100L; - - assertThatThrownBy(() -> new BillAction(EVENT1, sequence, title, price)) - .isInstanceOf(HaengdongException.class) - .hasMessage("앞뒤 공백을 제거한 지출 내역 제목은 1 ~ 30자여야 합니다."); - } - - @DisplayName("금액이 10,000,000 이하의 자연수가 아니면 지출을 생성할 수 없다.") - @ParameterizedTest - @ValueSource(longs = {0, 10_000_001, 20_000_000}) - void validatePrice(long price) { - Sequence sequence = new Sequence(1L); - String title = "title"; - - assertThatThrownBy(() -> new BillAction(EVENT1, sequence, title, price)) - .isInstanceOf(HaengdongException.class) - .hasMessage("지출 금액은 10,000,000 이하의 자연수여야 합니다."); - } - - @DisplayName("지출 내역을 올바르게 생성한다.") - @Test - void createBillAction() { - Sequence sequence = new Sequence(1L); - String title = "title"; - Long price = 1_000L; - - BillAction billAction = new BillAction(EVENT1, sequence, title, price); - - assertAll( - () -> assertThat(billAction.getSequence().getValue()).isEqualTo(1L), - () -> assertThat(billAction.getTitle()).isEqualTo(title), - () -> assertThat(billAction.getPrice()).isEqualTo(price) - ); - } - - @DisplayName("지출 액션에 멤버별 고정 금액이 설정되어 있는지 확인한다.") - @Test - void isFixed1() { - BillAction fixedBillAction = Fixture.createBillAction(EVENT1, 1L, "인생네컷", 2_000L); - - List unfixedBillActionDetails = List.of( - new BillActionDetail(BILL_ACTION, "감자", 1_000L, false), - new BillActionDetail(BILL_ACTION, "고구마", 1_000L, false) - ); - fixedBillAction.addDetails(unfixedBillActionDetails); - - assertThat(fixedBillAction.isFixed()).isEqualTo(false); - } - - @DisplayName("지출 액션에 멤버별 고정 금액이 설정되어 있는지 확인한다.") - @Test - void isFixed2() { - BillAction fixedBillAction = Fixture.createBillAction(EVENT1, 1L, "인생네컷", 5_000L); - - List unfixedBillActionDetails = List.of( - new BillActionDetail(BILL_ACTION, "감자", 4_000L, true), - new BillActionDetail(BILL_ACTION, "고구마", 1_000L, true) - ); - fixedBillAction.addDetails(unfixedBillActionDetails); - - assertThat(fixedBillAction.isFixed()).isEqualTo(true); - } -} diff --git a/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java b/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java deleted file mode 100644 index 95eab19cc..000000000 --- a/server/src/test/java/server/haengdong/domain/action/CurrentMembersTest.java +++ /dev/null @@ -1,97 +0,0 @@ -package server.haengdong.domain.action; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static server.haengdong.domain.action.MemberActionStatus.IN; -import static server.haengdong.domain.action.MemberActionStatus.OUT; - -import java.util.List; -import java.util.Set; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import server.haengdong.domain.event.Event; -import server.haengdong.exception.HaengdongException; -import server.haengdong.support.fixture.Fixture; - -class CurrentMembersTest { - - @DisplayName("인원 변동 이력으로 현재 참여 인원을 계산한다.") - @Test - void of() { - Event event = Fixture.EVENT1; - List memberActions = List.of( - Fixture.createMemberAction(event, 1L, "망쵸", IN), - Fixture.createMemberAction(event, 2L, "백호", IN), - Fixture.createMemberAction(event, 3L, "백호", OUT), - Fixture.createMemberAction(event, 4L, "웨디", IN) - ); - - CurrentMembers currentMembers = CurrentMembers.of(memberActions); - - assertThat(currentMembers.getMembers()) - .containsExactlyInAnyOrder("망쵸", "웨디"); - } - - @DisplayName("인원 변동 액션의 상태가 IN이면 현재 인원에 추가한다.") - @Test - void addMemberAction1() { - CurrentMembers currentMembers = new CurrentMembers(); - Event event = Fixture.EVENT1; - MemberAction memberAction = Fixture.createMemberAction(event, 1L, "웨디", IN); - - CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction); - Set members = addedCurrentMembers.getMembers(); - - assertThat(members).hasSize(1) - .containsExactly("웨디"); - } - - @DisplayName("인원 변동 액션의 상태가 OUT이면 현재 인원에서 제외한다.") - @Test - void addMemberAction2() { - Event event = Fixture.EVENT1; - MemberAction memberAction1 = Fixture.createMemberAction(event, 1L, "웨디", IN); - CurrentMembers currentMembers = new CurrentMembers().addMemberAction(memberAction1); - MemberAction memberAction2 = Fixture.createMemberAction(event, 1L, "웨디", OUT); - - CurrentMembers addedCurrentMembers = currentMembers.addMemberAction(memberAction2); - - assertThat(addedCurrentMembers.getMembers()).hasSize(0); - } - - @DisplayName("현재 참여중인 인원은 나갈 수 있다.") - @Test - void validate1() { - CurrentMembers currentMembers = new CurrentMembers(Set.of("토다리")); - - assertThatCode(() -> currentMembers.validate("토다리", OUT)) - .doesNotThrowAnyException(); - } - - @DisplayName("현재 참여중이지 않은 인원은 들어올 수 있다.") - @Test - void validate2() { - CurrentMembers currentMembers = new CurrentMembers(Set.of("쿠키")); - - assertThatCode(() -> currentMembers.validate("토다리", IN)) - .doesNotThrowAnyException(); - } - - @DisplayName("현재 참여중인 인원은 들어올 수 없다.") - @Test - void validate3() { - CurrentMembers currentMembers = new CurrentMembers(Set.of("토다리")); - - assertThatCode(() -> currentMembers.validate("토다리", IN)) - .isInstanceOf(HaengdongException.class); - } - - @DisplayName("현재 참여중이지 않은 인원은 나갈 수 없다.") - @Test - void validate4() { - CurrentMembers currentMembers = new CurrentMembers(Set.of("쿠키")); - - assertThatCode(() -> currentMembers.validate("토다리", OUT)) - .isInstanceOf(HaengdongException.class); - } -} diff --git a/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java b/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java deleted file mode 100644 index 4a009d2df..000000000 --- a/server/src/test/java/server/haengdong/domain/action/MemberBillReportTest.java +++ /dev/null @@ -1,56 +0,0 @@ -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 static server.haengdong.support.fixture.Fixture.BILL_ACTION; - -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; -import server.haengdong.support.fixture.Fixture; - -class MemberBillReportTest { - - @DisplayName("액션 목록으로 참가자 정산 리포트를 생성한다.") - @Test - void createByActions() { - Event event = Fixture.EVENT1; - List billActions = List.of( - Fixture.createBillAction(event, 4L, "뽕족", 60_000L), - Fixture.createBillAction(event, 7L, "인생네컷", 20_000L) - ); - billActions.get(0).addDetails( - List.of( - new BillActionDetail(BILL_ACTION, "소하", 10_000L, false), - new BillActionDetail(BILL_ACTION, "감자", 40_000L, true), - new BillActionDetail(BILL_ACTION, "쿠키", 10_000L, false) - ) - ); - billActions.get(1).addDetails( - List.of( - new BillActionDetail(BILL_ACTION, "소하", 5_000L, true), - new BillActionDetail(BILL_ACTION, "쿠키", 15_000L, true) - ) - ); - List memberActions = List.of( - Fixture.createMemberAction(event, 1L, "소하", IN), - Fixture.createMemberAction(event, 2L, "감자", IN), - Fixture.createMemberAction(event, 3L, "쿠키", IN), - Fixture.createMemberAction(event, 5L, "감자", OUT) - ); - - MemberBillReport memberBillReport = MemberBillReport.createByActions(billActions, memberActions); - - assertThat(memberBillReport.getReports()) - .containsAllEntriesOf( - Map.of( - "감자", 40_000L, - "쿠키", 25_000L, - "소하", 15_000L - ) - ); - } -} diff --git a/server/src/test/java/server/haengdong/domain/action/SequenceTest.java b/server/src/test/java/server/haengdong/domain/action/SequenceTest.java deleted file mode 100644 index d2277d593..000000000 --- a/server/src/test/java/server/haengdong/domain/action/SequenceTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package server.haengdong.domain.action; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -class SequenceTest { - - @DisplayName("액션의 초기 순서번호는 1이다.") - @Test - void createFirst() { - Sequence sequence = Sequence.createFirst(); - - assertThat(sequence.getValue()).isOne(); - } - - @DisplayName("현재 액션의 다음 액션의 순서는 1만큼 증가한다.") - @Test - void next() { - Sequence sequence = new Sequence(2L); - - Sequence nextAction = sequence.next(); - - assertThat(nextAction.getValue()).isEqualTo(3L); - } -} diff --git a/server/src/test/java/server/haengdong/domain/bill/BillTest.java b/server/src/test/java/server/haengdong/domain/bill/BillTest.java new file mode 100644 index 000000000..d1c2e3d8c --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/bill/BillTest.java @@ -0,0 +1,98 @@ +package server.haengdong.domain.bill; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static server.haengdong.support.fixture.Fixture.EVENT1; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import server.haengdong.domain.member.Member; +import server.haengdong.exception.HaengdongException; + +class BillTest { + + @DisplayName("지출 내역 제목의 앞뒤 공백을 제거한 길이가 1 ~ 30자가 아니면 지출을 생성할 수 없다.") + @ParameterizedTest + @ValueSource(strings = {"", " ", "1234567890123456789012345678901"}) + void validateTitle(String title) { + Long price = 100L; + + assertThatThrownBy(() -> new Bill(EVENT1, title, price)) + .isInstanceOf(HaengdongException.class) + .hasMessage("앞뒤 공백을 제거한 지출 내역 제목은 1 ~ 30자여야 합니다."); + } + + @DisplayName("금액이 10,000,000 이하의 자연수가 아니면 지출을 생성할 수 없다.") + @ParameterizedTest + @ValueSource(longs = {0, 10_000_001, 20_000_000}) + void validatePrice(long price) { + String title = "title"; + + assertThatThrownBy(() -> new Bill(EVENT1, title, price)) + .isInstanceOf(HaengdongException.class) + .hasMessage("지출 금액은 10,000,000 이하의 자연수여야 합니다."); + } + + @DisplayName("지출 내역을 올바르게 생성한다.") + @Test + void createBill() { + String title = "title"; + Long price = 1_000L; + + Bill bill = new Bill(EVENT1, title, price); + + assertAll( + () -> assertThat(bill.getTitle()).isEqualTo(title), + () -> assertThat(bill.getPrice()).isEqualTo(price) + ); + } + + @DisplayName("지출에 멤버별 고정 금액이 설정되어 있는지 확인한다.") + @Test + void isFixed1() { + List members = List.of(new Member(EVENT1, "감자"), new Member(EVENT1, "고구마")); + Bill fixedBill = Bill.create(EVENT1, "인생네컷", 2_000L, members); + + assertThat(fixedBill.isFixed()).isEqualTo(false); + } + + @DisplayName("같은 멤버 목록을 가지고 있는지 비교한다.") + @Test + void isSameMember1() { + Member member1 = new Member(1L, EVENT1, "감자", false); + Member member2 = new Member(2L, EVENT1, "고구마", false); + Member member3 = new Member(3L, EVENT1, "당근", false); + + List members1 = List.of(member1, member2, member3); + List members2 = List.of(member2, member3, member1); + + Bill bill1 = Bill.create(EVENT1, "뽕족", 20_000L, members1); + Bill bill2 = Bill.create(EVENT1, "인생네컷", 30_000L, members2); + + boolean isSameMembers = bill1.isSameMembers(bill2); + + assertThat(isSameMembers).isTrue(); + } + + @DisplayName("같은 멤버 목록을 가지고 있는지 비교한다.") + @Test + void isSameMember2() { + Member member1 = new Member(1L, EVENT1, "감자", false); + Member member2 = new Member(2L, EVENT1, "고구마", false); + Member member3 = new Member(3L, EVENT1, "당근", false); + + List members1 = List.of(member1, member2, member3); + List members2 = List.of(member2, member1); + + Bill bill1 = Bill.create(EVENT1, "뽕족", 20_000L, members1); + Bill bill2 = Bill.create(EVENT1, "인생네컷", 30_000L, members2); + + boolean isSameMembers = bill1.isSameMembers(bill2); + + assertThat(isSameMembers).isFalse(); + } +} diff --git a/server/src/test/java/server/haengdong/domain/event/EventTest.java b/server/src/test/java/server/haengdong/domain/event/EventTest.java index 12c0c0569..83cd700a0 100644 --- a/server/src/test/java/server/haengdong/domain/event/EventTest.java +++ b/server/src/test/java/server/haengdong/domain/event/EventTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -25,7 +26,7 @@ void createSuccessTest(String eventName) { void createFailTest1(String eventName) { assertThatCode(() -> new Event(eventName, "1234", "TEST_TOKEN")) .isInstanceOf(HaengdongException.class) - .hasMessage(String.format("행사 이름에는 공백 문자가 연속될 수 없습니다. 입력한 이름 : %s", eventName)); + .hasMessage("행사 이름에는 공백 문자가 연속될 수 없습니다."); } @DisplayName("이름이 1자 미만이거나 20자 초과인 경우 예외가 발생한다.") @@ -34,7 +35,7 @@ void createFailTest1(String eventName) { void createFilTest2(String eventName) { assertThatCode(() -> new Event(eventName, "1234", "TEST_TOKEN")) .isInstanceOf(HaengdongException.class) - .hasMessage(String.format("행사 이름은 1자 이상 20자 이하만 입력 가능합니다. 입력한 이름 길이 : %d", eventName.length())); + .hasMessage("행사 이름은 1자 이상 20자 이하만 입력 가능합니다."); } @DisplayName("비밀번호는 4자리 숫자 입니다.") @@ -62,4 +63,73 @@ void isNotSamePassword1() { assertThat(event.isPasswordMismatch(rawPassword)).isTrue(); } + + @DisplayName("이름을 수정한다.") + @Test + void renameTest() { + Event event = new Event("이름", "1234", "TEST_TOKEN"); + + event.rename("새로운 이름"); + + assertThat(event.getName()).isEqualTo("새로운 이름"); + } + + @DisplayName("계좌 정보에 은행 이름과 계좌 번호가 모두 포함된다.") + @Test + void changeAccountTest() { + Event event = new Event("이름", "1234", "TEST_TOKEN"); + + event.changeAccount("토스뱅크", "12345678"); + + assertThat(event.getAccount()).isEqualTo("토스뱅크 12345678"); + } + + @DisplayName("계좌 정보에 은행 이름과 계좌 번호가 모두 포함되지 않으면 예외가 발생한다.") + @Test + void changeAccountTest1() { + Event event = new Event("이름", "1234", "TEST_TOKEN"); + + assertThatThrownBy(() -> event.changeAccount("행대뱅크", "")) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("지원하는 은행이면 예외가 발생하지 않는다.") + @ParameterizedTest + @ValueSource(strings = {"토스뱅크", "KB국민은행"}) + void changeAccountTest2(String bankName) { + Event event = new Event("이름", "1234", "TEST_TOKEN"); + + assertThatCode(() -> event.changeAccount(bankName, "12345678")) + .doesNotThrowAnyException(); + } + + @DisplayName("지원하지 않는 은행이면 예외가 발생한다.") + @ParameterizedTest + @ValueSource(strings = {"행대뱅크", "토스 뱅크", "망쵸뱅크", "KB 국민은행"}) + void changeAccountTest3(String bankName) { + Event event = new Event("이름", "1234", "TEST_TOKEN"); + + assertThatThrownBy(() -> event.changeAccount(bankName, "12345678")) + .isInstanceOf(HaengdongException.class); + } + + @DisplayName("계좌 번호가 8자 이상 30자 이하면 예외가 발생하지 않는다.") + @ParameterizedTest + @ValueSource(strings = {"12345678", "123456789012345678901234567890"}) + void changeAccountTest4(String accountNumber) { + Event event = new Event("이름", "1234", "TEST_TOKEN"); + + assertThatCode(() -> event.changeAccount("토스뱅크", accountNumber)) + .doesNotThrowAnyException(); + } + + @DisplayName("계좌 번호가 8자 미만 30자 초과면 예외가 발생한다.") + @ParameterizedTest + @ValueSource(strings = {"", " ", "1234567", "1234567890123456789012345678901"}) + void changeAccountTest5(String accountNumber) { + Event event = new Event("이름", "1234", "TEST_TOKEN"); + + assertThatThrownBy(() -> event.changeAccount("토스뱅크", accountNumber)) + .isInstanceOf(HaengdongException.class); + } } diff --git a/server/src/test/java/server/haengdong/domain/member/MemberBillReportTest.java b/server/src/test/java/server/haengdong/domain/member/MemberBillReportTest.java new file mode 100644 index 000000000..ca33603a1 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/member/MemberBillReportTest.java @@ -0,0 +1,41 @@ +package server.haengdong.domain.member; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.event.Event; +import server.haengdong.support.fixture.Fixture; + +class MemberBillReportTest { + + @DisplayName("지출 목록으로 참가자 정산 리포트를 생성한다.") + @Test + void createByBills() { + Event event = Fixture.EVENT1; + Member member1 = new Member(1L, event, "소하", false); + Member member2 = new Member(2L, event, "감자", false); + Member member3 = new Member(3L, event, "쿠키", false); + Member member4 = new Member(4L, event, "고구마", false); + List members = List.of(member1, member2, member3, member4); + List bills = List.of( + Bill.create(event, "뽕족", 60_000L, members), + Bill.create(event, "인생네컷", 20_000L, members) + ); + + MemberBillReport memberBillReport = MemberBillReport.createByBills(bills); + + assertThat(memberBillReport.getReports()) + .containsAllEntriesOf( + Map.of( + member1, 20_000L, + member2, 20_000L, + member3, 20_000L, + member4, 20_000L + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/domain/step/StepTest.java b/server/src/test/java/server/haengdong/domain/step/StepTest.java new file mode 100644 index 000000000..5c5631840 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/step/StepTest.java @@ -0,0 +1,50 @@ +package server.haengdong.domain.step; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static server.haengdong.support.fixture.Fixture.EVENT1; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.member.Member; +import server.haengdong.exception.HaengdongException; + +class StepTest { + + @DisplayName("회원 구성이 같은 지출은 Step에 추가될 수 있다.") + @Test + void add1() { + Member member1 = new Member(1L, EVENT1, "감자", false); + Member member2 = new Member(2L, EVENT1, "고구마", false); + Member member3 = new Member(3L, EVENT1, "당근", false); + Member member4 = new Member(4L, EVENT1, "양파", false); + Bill bill1 = Bill.create(EVENT1, "뽕족", 10_000L, List.of(member1, member2, member3, member4)); + Step step = Step.of(bill1); + + Bill bill2 = Bill.create(EVENT1, "인생네컷", 5_000L, List.of(member2, member3, member1, member4)); + + step.add(bill2); + + List bills = step.getBills(); + + assertThat(bills).hasSize(2); + } + + @DisplayName("회원 구성이 댜른 지출은 Step에 추가될 수 없다.") + @Test + void add2() { + Member member1 = new Member(1L, EVENT1, "감자", false); + Member member2 = new Member(2L, EVENT1, "고구마", false); + Member member3 = new Member(3L, EVENT1, "당근", false); + Member member4 = new Member(4L, EVENT1, "양파", false); + Bill bill1 = Bill.create(EVENT1, "뽕족", 10_000L, List.of(member1, member2, member3, member4)); + Step step = Step.of(bill1); + + Bill bill2 = Bill.create(EVENT1, "인생네컷", 5_000L, List.of(member2, member3, member1)); + + assertThatThrownBy(() -> step.add(bill2)) + .isInstanceOf(HaengdongException.class); + } +} diff --git a/server/src/test/java/server/haengdong/domain/step/StepsTest.java b/server/src/test/java/server/haengdong/domain/step/StepsTest.java new file mode 100644 index 000000000..799cb0d4c --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/step/StepsTest.java @@ -0,0 +1,48 @@ +package server.haengdong.domain.step; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; +import static server.haengdong.support.fixture.Fixture.EVENT1; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.member.Member; + +class StepsTest { + + @DisplayName("지출 목록 순으로 같은 회원 구성인 경우 같은 Step으로 묶는다.") + @Test + void of() { + Member member1 = new Member(1L, EVENT1, "감자", false); + Member member2 = new Member(2L, EVENT1, "고구마", false); + Member member3 = new Member(3L, EVENT1, "당근", false); + Member member4 = new Member(4L, EVENT1, "양파", false); + Bill bill1 = Bill.create(EVENT1, "뽕족", 10_000L, List.of(member1, member2)); + Bill bill2 = Bill.create(EVENT1, "용용선생", 20_000L, List.of(member2, member1)); + Bill bill3 = Bill.create(EVENT1, "보승회관", 30_000L, List.of(member1, member2, member3)); + Bill bill4 = Bill.create(EVENT1, "감자", 40_000L, List.of(member1, member2, member3, member4)); + Bill bill5 = Bill.create(EVENT1, "인생네컷", 5_000L, List.of(member2, member3, member1, member4)); + List bills = List.of(bill1, bill2, bill3, bill4, bill5); + + Steps step = Steps.of(bills); + + List steps = step.getSteps(); + assertAll( + () -> assertThat(steps).hasSize(3), + () -> assertThat(steps.get(0).getBills()).hasSize(2) + .containsExactly(bill1, bill2), + () -> assertThat(steps.get(0).getMembers()).hasSize(2) + .containsExactly(member1, member2), + () -> assertThat(steps.get(1).getBills()).hasSize(1) + .containsExactly(bill3), + () -> assertThat(steps.get(1).getMembers()).hasSize(3) + .containsExactly(member1, member2, member3), + () -> assertThat(steps.get(2).getBills()).hasSize(2) + .containsExactly(bill4, bill5), + () -> assertThat(steps.get(2).getMembers()).hasSize(4) + .containsExactly(member1, member2, member3, member4) + ); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java deleted file mode 100644 index 0fa3311b3..000000000 --- a/server/src/test/java/server/haengdong/presentation/ActionControllerTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package server.haengdong.presentation; - -class ActionControllerTest extends ControllerTestSupport { -} diff --git a/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java deleted file mode 100644 index f4e65d4f0..000000000 --- a/server/src/test/java/server/haengdong/presentation/BillActionDetailControllerTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package server.haengdong.presentation; - -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.BDDMockito.given; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -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 server.haengdong.application.response.BillActionDetailAppResponse; -import server.haengdong.application.response.BillActionDetailsAppResponse; - -class BillActionDetailControllerTest extends ControllerTestSupport { - - @DisplayName("참여자별 지출 금액을 조회한다.") - @Test - void findBillActionDetails() throws Exception { - BillActionDetailsAppResponse appResponse = new BillActionDetailsAppResponse( - List.of(new BillActionDetailAppResponse("토다리", 1000L, false))); - given(billActionDetailService.findBillActionDetails(anyString(), anyLong())) - .willReturn(appResponse); - - mockMvc.perform(get("/api/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.members").isArray()) - .andExpect(jsonPath("$.members[0].name").value("토다리")) - .andExpect(jsonPath("$.members[0].price").value(1000L)); - } -} diff --git a/server/src/test/java/server/haengdong/presentation/BillControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillControllerTest.java new file mode 100644 index 000000000..10d7fd1f6 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/BillControllerTest.java @@ -0,0 +1,66 @@ +package server.haengdong.presentation; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +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.jsonPath; +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 server.haengdong.application.response.BillAppResponse; +import server.haengdong.application.response.BillDetailAppResponse; +import server.haengdong.application.response.BillDetailsAppResponse; +import server.haengdong.application.response.MemberAppResponse; +import server.haengdong.application.response.StepAppResponse; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.member.Member; +import server.haengdong.support.fixture.Fixture; + +class BillControllerTest extends ControllerTestSupport { + + @DisplayName("전체 지출 내역을 조회한다.") + @Test + void findBills() throws Exception { + Bill bill = Fixture.BILL1; + List bills = List.of(BillAppResponse.of(bill)); + + Member member = Fixture.MEMBER1; + List members = List.of(MemberAppResponse.of(member)); + + StepAppResponse stepAppResponse = new StepAppResponse(bills, members); + given(billService.findSteps(anyString())).willReturn(List.of(stepAppResponse)); + + mockMvc.perform(get("/api/events/{eventId}/bills", "token")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.steps").isArray()) + .andExpect(jsonPath("$.steps[0].bills").isArray()) + .andExpect(jsonPath("$.steps[0].bills[0].id").value(bill.getId())) + .andExpect(jsonPath("$.steps[0].bills[0].title").value(bill.getTitle())) + .andExpect(jsonPath("$.steps[0].bills[0].price").value(bill.getPrice())) + .andExpect(jsonPath("$.steps[0].bills[0].isFixed").value(bill.isFixed())) + .andExpect(jsonPath("$.steps[0].members").isArray()) + .andExpect(jsonPath("$.steps[0].members[0].id").value(member.getId())) + .andExpect(jsonPath("$.steps[0].members[0].name").value(member.getName())); + } + + @DisplayName("참여자별 지출 금액을 조회한다.") + @Test + void findBillActionDetails() throws Exception { + BillDetailsAppResponse appResponse = new BillDetailsAppResponse( + List.of(new BillDetailAppResponse(1L, "토다리", 1000L, false))); + given(billService.findBillDetails(anyString(), anyLong())).willReturn(appResponse); + + mockMvc.perform(get("/api/events/{eventId}/bills/{billId}/details", "TOKEN", 1L)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].id").value(1L)) + .andExpect(jsonPath("$.members[0].memberName").value("토다리")) + .andExpect(jsonPath("$.members[0].price").value(1000L)) + .andExpect(jsonPath("$.members[0].isFixed").value(false)); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java b/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java index f5964e897..6ba5540d5 100644 --- a/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java +++ b/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java @@ -9,22 +9,21 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import server.haengdong.application.AuthService; -import server.haengdong.application.BillActionDetailService; -import server.haengdong.application.BillActionService; +import server.haengdong.application.BillService; import server.haengdong.application.EventService; -import server.haengdong.application.MemberActionService; -import server.haengdong.presentation.admin.AdminBillActionController; +import server.haengdong.application.MemberService; +import server.haengdong.presentation.admin.AdminBillController; import server.haengdong.presentation.admin.AdminEventController; -import server.haengdong.presentation.admin.AdminMemberActionController; +import server.haengdong.presentation.admin.AdminMemberController; @WebMvcTest( controllers = { AdminEventController.class, - AdminBillActionController.class, - AdminMemberActionController.class, + AdminBillController.class, + AdminMemberController.class, EventController.class, - MemberActionController.class, - BillActionDetailController.class + MemberController.class, + BillController.class }, excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {WebMvcConfigurer.class})} ) @@ -43,11 +42,8 @@ public abstract class ControllerTestSupport { protected AuthService authService; @MockBean - protected MemberActionService memberActionService; + protected MemberService memberService; @MockBean - protected BillActionService billActionService; - - @MockBean - protected BillActionDetailService billActionDetailService; + protected BillService billService; } diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java index a58924a32..f1f11d4a6 100644 --- a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -2,10 +2,9 @@ import static org.hamcrest.Matchers.equalTo; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; @@ -20,7 +19,6 @@ import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.application.response.MembersAppResponse; import server.haengdong.presentation.request.EventLoginRequest; import server.haengdong.presentation.request.EventSaveRequest; @@ -31,7 +29,7 @@ class EventControllerTest extends ControllerTestSupport { @Test void findEventTest() throws Exception { String eventId = "망쵸토큰"; - EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식"); + EventDetailAppResponse eventDetailAppResponse = new EventDetailAppResponse("행동대장 회식", "토스 1231245"); given(eventService.findEvent(eventId)).willReturn(eventDetailAppResponse); mockMvc.perform(get("/api/events/{eventId}", eventId)) @@ -40,25 +38,13 @@ void findEventTest() throws Exception { .andExpect(jsonPath("$.eventName").value("행동대장 회식")); } - @DisplayName("행사에 참여한 전체 인원을 중복 없이 조회한다.") - @Test - void findAllMembersTest() throws Exception { - MembersAppResponse memberAppResponse = new MembersAppResponse(List.of("토다리", "쿠키")); - given(eventService.findAllMembers(anyString())).willReturn(memberAppResponse); - - mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.memberNames").isArray()) - .andExpect(jsonPath("$.memberNames[0]").value("토다리")) - .andExpect(jsonPath("$.memberNames[1]").value("쿠키")); - } - @DisplayName("참여자별 정산 현황을 조회한다.") @Test void getMemberBillReports() throws Exception { List memberBillReportAppResponses = List.of( - new MemberBillReportAppResponse("소하", 20_000L), new MemberBillReportAppResponse("토다리", 200_000L)); + new MemberBillReportAppResponse(1L, "소하", false, 20_000L), + new MemberBillReportAppResponse(2L, "토다리", false, 200_000L) + ); given(eventService.getMemberBillReports(any())).willReturn(memberBillReportAppResponses); @@ -66,9 +52,13 @@ void getMemberBillReports() throws Exception { .accept(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].name").value(equalTo("소하"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].memberId").value(equalTo(1))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].memberName").value(equalTo("소하"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].isDeposited").value(equalTo(false))) .andExpect(MockMvcResultMatchers.jsonPath("$.reports[0].price").value(equalTo(20_000))) - .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].name").value(equalTo("토다리"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].memberId").value(equalTo(2))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].memberName").value(equalTo("토다리"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].isDeposited").value(equalTo(false))) .andExpect(MockMvcResultMatchers.jsonPath("$.reports[1].price").value(equalTo(200_000))); } diff --git a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java deleted file mode 100644 index a2fd05437..000000000 --- a/server/src/test/java/server/haengdong/presentation/MemberActionControllerTest.java +++ /dev/null @@ -1,34 +0,0 @@ -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.jsonPath; -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.http.MediaType; -import server.haengdong.application.response.CurrentMemberAppResponse; - -class MemberActionControllerTest extends ControllerTestSupport { - - @DisplayName("현재 참여 인원을 조회합니다.") - @Test - void getCurrentMembers() throws Exception { - List currentMemberAppResponses = List.of( - new CurrentMemberAppResponse("소하"), new CurrentMemberAppResponse("토다리")); - - given(memberActionService.getCurrentMembers(any())).willReturn(currentMemberAppResponses); - - mockMvc.perform(get("/api/events/{eventId}/members/current", "망쵸토큰") - .accept(MediaType.APPLICATION_JSON)) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.memberNames[0]").value(equalTo("소하"))) - .andExpect(jsonPath("$.memberNames[1]").value(equalTo("토다리"))); - } -} diff --git a/server/src/test/java/server/haengdong/presentation/MemberControllerTest.java b/server/src/test/java/server/haengdong/presentation/MemberControllerTest.java new file mode 100644 index 000000000..ff824831b --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/MemberControllerTest.java @@ -0,0 +1,77 @@ +package server.haengdong.presentation; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +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.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.MEMBER1; +import static server.haengdong.support.fixture.Fixture.MEMBER2; +import static server.haengdong.support.fixture.Fixture.MEMBER3; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import server.haengdong.application.response.MemberAppResponse; +import server.haengdong.application.response.MemberDepositAppResponse; +import server.haengdong.application.response.MembersDepositAppResponse; +import server.haengdong.domain.member.Member; + +class MemberControllerTest extends ControllerTestSupport { + + @DisplayName("행사에 참여한 전체 인원을 조회한다.") + @Test + void findAllMembersTest() throws Exception { + Member member1 = MEMBER1; + Member member2 = MEMBER2; + Member member3 = MEMBER3; + List members = List.of( + MemberDepositAppResponse.of(member1), + MemberDepositAppResponse.of(member2), + MemberDepositAppResponse.of(member3) + ); + + MembersDepositAppResponse memberAppResponse = new MembersDepositAppResponse(members); + given(memberService.findAllMembers(anyString())).willReturn(memberAppResponse); + + mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].id").value(member1.getId())) + .andExpect(jsonPath("$.members[0].name").value(member1.getName())) + .andExpect(jsonPath("$.members[0].isDeposited").value(member1.isDeposited())) + .andExpect(jsonPath("$.members[1].id").value(member2.getId())) + .andExpect(jsonPath("$.members[1].name").value(member2.getName())) + .andExpect(jsonPath("$.members[1].isDeposited").value(member2.isDeposited())) + .andExpect(jsonPath("$.members[2].id").value(member3.getId())) + .andExpect(jsonPath("$.members[2].name").value(member3.getName())) + .andExpect(jsonPath("$.members[2].isDeposited").value(member3.isDeposited())); + } + + @DisplayName("현재 참여 인원을 조회합니다.") + @Test + void getCurrentMembers() throws Exception { + Member member1 = MEMBER1; + Member member2 = MEMBER2; + List members = List.of( + MemberAppResponse.of(member1), + MemberAppResponse.of(member2) + ); + + given(memberService.getCurrentMembers(any())).willReturn(members); + + mockMvc.perform(get("/api/events/{eventId}/members/current", "TOKEN") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.members").isArray()) + .andExpect(jsonPath("$.members[0].id").value(member1.getId())) + .andExpect(jsonPath("$.members[0].name").value(member1.getName())) + .andExpect(jsonPath("$.members[1].id").value(member2.getId())) + .andExpect(jsonPath("$.members[1].name").value(member2.getName())); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/admin/AdminBillActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/admin/AdminBillControllerTest.java similarity index 58% rename from server/src/test/java/server/haengdong/presentation/admin/AdminBillActionControllerTest.java rename to server/src/test/java/server/haengdong/presentation/admin/AdminBillControllerTest.java index 7e401d9b0..f776a1624 100644 --- a/server/src/test/java/server/haengdong/presentation/admin/AdminBillActionControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/admin/AdminBillControllerTest.java @@ -1,12 +1,14 @@ package server.haengdong.presentation.admin; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doThrow; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -15,29 +17,26 @@ import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; import server.haengdong.presentation.ControllerTestSupport; -import server.haengdong.presentation.request.BillActionDetailUpdateRequest; -import server.haengdong.presentation.request.BillActionDetailsUpdateRequest; -import server.haengdong.presentation.request.BillActionSaveRequest; -import server.haengdong.presentation.request.BillActionUpdateRequest; -import server.haengdong.presentation.request.BillActionsSaveRequest; +import server.haengdong.presentation.request.BillDetailUpdateRequest; +import server.haengdong.presentation.request.BillDetailsUpdateRequest; +import server.haengdong.presentation.request.BillSaveRequest; +import server.haengdong.presentation.request.BillUpdateRequest; -class AdminBillActionControllerTest extends ControllerTestSupport { +class AdminBillControllerTest extends ControllerTestSupport { @DisplayName("지출 내역을 생성한다.") @Test void saveAllBillAction() throws Exception { - BillActionsSaveRequest request = new BillActionsSaveRequest( - List.of( - new BillActionSaveRequest("뽕족", 10_000L), - new BillActionSaveRequest("인생맥주", 10_000L) - ) - ); + List members = List.of(1L, 2L); + BillSaveRequest request = new BillSaveRequest("뽕족", 10_000L, members); + String requestBody = objectMapper.writeValueAsString(request); String eventId = "쿠키토큰"; - mockMvc.perform(post("/api/admin/events/{eventId}/bill-actions", eventId) + mockMvc.perform(post("/api/admin/events/{eventId}/bills", eventId) .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + .content(requestBody) + .cookie(EVENT_COOKIE)) .andDo(print()) .andExpect(status().isOk()); } @@ -45,16 +44,13 @@ void saveAllBillAction() throws Exception { @DisplayName("title이 비어 있는 경우 지출 내역을 생성할 수 없다.") @Test void saveAllBillAction1() throws Exception { - BillActionsSaveRequest request = new BillActionsSaveRequest( - List.of( - new BillActionSaveRequest("", 10_000L), - new BillActionSaveRequest("인생맥주", 10_000L) - ) - ); + List members = List.of(1L, 2L); + BillSaveRequest request = new BillSaveRequest("", 10_000L, members); + String requestBody = objectMapper.writeValueAsString(request); String eventId = "소하토큰"; - mockMvc.perform(post("/api/admin/events/{eventId}/bill-actions", eventId) + mockMvc.perform(post("/api/admin/events/{eventId}/bills", eventId) .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) .andDo(print()) @@ -64,14 +60,15 @@ void saveAllBillAction1() throws Exception { @DisplayName("지출 액션을 수정한다.") @Test void updateBillAction() throws Exception { - BillActionUpdateRequest request = new BillActionUpdateRequest("뽕족", 10_000L); + BillUpdateRequest request = new BillUpdateRequest("뽕족", 10_000L); String requestBody = objectMapper.writeValueAsString(request); String eventId = "웨디토큰"; - mockMvc.perform(put("/api/admin/events/{eventId}/bill-actions/{actionId}", eventId, 1L) + mockMvc.perform(put("/api/admin/events/{eventId}/bills/{billId}", eventId, 1L) .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + .content(requestBody) + .cookie(EVENT_COOKIE)) .andDo(print()) .andExpect(status().isOk()); } @@ -81,7 +78,7 @@ void updateBillAction() throws Exception { void deleteBillAction() throws Exception { String eventId = "토다리토큰"; - mockMvc.perform(delete("/api/admin/events/{eventId}/bill-actions/{actionId}", eventId, 1)) + mockMvc.perform(delete("/api/admin/events/{eventId}/bills/{billId}", eventId, 1)) .andDo(print()) .andExpect(status().isOk()); } @@ -91,9 +88,9 @@ void deleteBillAction() throws Exception { void deleteBillAction1() throws Exception { String eventId = "이상해토큰"; doThrow(new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND)) - .when(billActionService).deleteBillAction(any(String.class), any(Long.class)); + .when(billService).deleteBill(any(String.class), any(Long.class)); - mockMvc.perform(delete("/api/admin/events/{eventId}/bill-actions/{actionId}", eventId, 1)) + mockMvc.perform(delete("/api/admin/events/{eventId}/bills/{billId}", eventId, 1)) .andDo(print()) .andExpect(status().isBadRequest()); } @@ -101,16 +98,16 @@ void deleteBillAction1() throws Exception { @DisplayName("참여자별 지출 금액을 수정한다.") @Test void updateBillActionDetailsTest() throws Exception { - List billActionDetailUpdateRequests = List.of( - new BillActionDetailUpdateRequest("소하", 10000L, true), - new BillActionDetailUpdateRequest("웨디", 20000L, true) + List billActionDetailUpdateRequests = List.of( + new BillDetailUpdateRequest(1L, 10000L, true), + new BillDetailUpdateRequest(2L, 20000L, true) ); - BillActionDetailsUpdateRequest request = new BillActionDetailsUpdateRequest( + BillDetailsUpdateRequest request = new BillDetailsUpdateRequest( billActionDetailUpdateRequests); String json = objectMapper.writeValueAsString(request); - mockMvc.perform(put("/api/admin/events/{eventId}/bill-actions/{actionId}/fixed", "TOKEN", 1L) + mockMvc.perform(put("/api/admin/events/{eventId}/bills/{billId}/details", "TOKEN", 1L) .contentType(MediaType.APPLICATION_JSON) .content(json)) .andDo(print()) diff --git a/server/src/test/java/server/haengdong/presentation/admin/AdminEventControllerTest.java b/server/src/test/java/server/haengdong/presentation/admin/AdminEventControllerTest.java index 3ce2422c6..df7b70e92 100644 --- a/server/src/test/java/server/haengdong/presentation/admin/AdminEventControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/admin/AdminEventControllerTest.java @@ -1,34 +1,29 @@ package server.haengdong.presentation.admin; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; 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.http.MediaType; import server.haengdong.presentation.ControllerTestSupport; -import server.haengdong.presentation.request.MemberNameUpdateRequest; -import server.haengdong.presentation.request.MemberNamesUpdateRequest; +import server.haengdong.presentation.request.EventUpdateRequest; class AdminEventControllerTest extends ControllerTestSupport { - @DisplayName("행사 참여 인원의 이름을 수정한다.") + @DisplayName("행사 정보를 수정한다.") @Test - void updateMember() throws Exception { + void updateEventTest() throws Exception { String token = "TOKEN"; - MemberNamesUpdateRequest memberNameUpdateRequest = new MemberNamesUpdateRequest(List.of( - new MemberNameUpdateRequest("토다링", "토쟁이"), - new MemberNameUpdateRequest("감자", "고구마") - )); + EventUpdateRequest eventUpdateRequest = new EventUpdateRequest("행동대장 비대위", "행대뱅크", "12345678"); - String requestBody = objectMapper.writeValueAsString(memberNameUpdateRequest); + String requestBody = objectMapper.writeValueAsString(eventUpdateRequest); - mockMvc.perform(put("/api/admin/events/{eventId}/members/nameChange", token) - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) + mockMvc.perform(patch("/api/admin/events/{eventId}", token) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) .andDo(print()) .andExpect(status().isOk()); } diff --git a/server/src/test/java/server/haengdong/presentation/admin/AdminMemberActionControllerTest.java b/server/src/test/java/server/haengdong/presentation/admin/AdminMemberActionControllerTest.java deleted file mode 100644 index e3d74640d..000000000 --- a/server/src/test/java/server/haengdong/presentation/admin/AdminMemberActionControllerTest.java +++ /dev/null @@ -1,53 +0,0 @@ -package server.haengdong.presentation.admin; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -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.http.MediaType; -import server.haengdong.presentation.ControllerTestSupport; -import server.haengdong.presentation.request.MemberActionsSaveRequest; - -class AdminMemberActionControllerTest extends ControllerTestSupport { - - @DisplayName("참여자 행동을 추가한다.") - @Test - void saveMemberActionTest() throws Exception { - MemberActionsSaveRequest memberActionsSaveRequest = new MemberActionsSaveRequest( - List.of("웨디", "소하", "토다리", "쿠키"), "IN"); - - String requestBody = objectMapper.writeValueAsString(memberActionsSaveRequest); - - mockMvc.perform(post("/api/admin/events/{eventId}/member-actions", "망쵸토큰") - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) - .andDo(print()) - .andExpect(status().isOk()); - } - - @DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.") - @Test - void deleteMemberAction() throws Exception { - String eventId = "망쵸토큰"; - Long actionId = 2L; - - mockMvc.perform(delete("/api/admin/events/{eventId}/member-actions/{actionId}", eventId, actionId)) - .andDo(print()) - .andExpect(status().isOk()); - } - - @DisplayName("행사의 전체 참여자 중에서 특정 참여자의 맴버 액션을 전부 삭제한다.") - @Test - void deleteMember() throws Exception { - String eventId = "망쵸토큰"; - String memberName = "행동대장"; - - mockMvc.perform(delete("/api/admin/events/{eventId}/members/{memberName}", eventId, memberName)) - .andDo(print()) - .andExpect(status().isOk()); - } -} diff --git a/server/src/test/java/server/haengdong/presentation/admin/AdminMemberControllerTest.java b/server/src/test/java/server/haengdong/presentation/admin/AdminMemberControllerTest.java new file mode 100644 index 000000000..6afb013f9 --- /dev/null +++ b/server/src/test/java/server/haengdong/presentation/admin/AdminMemberControllerTest.java @@ -0,0 +1,90 @@ +package server.haengdong.presentation.admin; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static server.haengdong.support.fixture.Fixture.EVENT_COOKIE; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import server.haengdong.application.response.MemberSaveAppResponse; +import server.haengdong.application.response.MembersSaveAppResponse; +import server.haengdong.presentation.ControllerTestSupport; +import server.haengdong.presentation.request.MemberSaveRequest; +import server.haengdong.presentation.request.MemberUpdateRequest; +import server.haengdong.presentation.request.MembersSaveRequest; +import server.haengdong.presentation.request.MembersUpdateRequest; + +class AdminMemberControllerTest extends ControllerTestSupport { + + @DisplayName("행사 참여자를 추가한다.") + @Test + void saveMemberTest() throws Exception { + String eventToken = "망쵸토큰"; + MembersSaveRequest membersSaveRequest = new MembersSaveRequest( + List.of( + new MemberSaveRequest("웨디"), + new MemberSaveRequest("소하") + ) + ); + String requestBody = objectMapper.writeValueAsString(membersSaveRequest); + MembersSaveAppResponse appResponse = new MembersSaveAppResponse( + List.of( + new MemberSaveAppResponse(1L, "웨디"), + new MemberSaveAppResponse(2L, "소하") + ) + ); + given(memberService.saveMembers(eventToken, membersSaveRequest.toAppRequest())) + .willReturn(appResponse); + + mockMvc.perform(post("/api/admin/events/{eventId}/members", "망쵸토큰") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + .cookie(EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.members[0].id").value(equalTo(1))) + .andExpect(MockMvcResultMatchers.jsonPath("$.members[0].name").value(equalTo("웨디"))) + .andExpect(MockMvcResultMatchers.jsonPath("$.members[1].id").value(equalTo(2))) + .andExpect(MockMvcResultMatchers.jsonPath("$.members[1].name").value(equalTo("소하"))); + } + + @DisplayName("행사 참여 인원을 삭제한다.") + @Test + void deleteMember() throws Exception { + String eventId = "망쵸토큰"; + Long memberId = 1L; + + mockMvc.perform(delete("/api/admin/events/{eventId}/members/{memberId}", eventId, memberId)) + .andDo(print()) + .andExpect(status().isOk()); + } + + @DisplayName("행사 참여 인원 정보를 수정한다.") + @Test + void updateMembers() throws Exception { + String eventId = "망쵸토큰"; + MembersUpdateRequest membersUpdateRequest = new MembersUpdateRequest( + List.of( + new MemberUpdateRequest(1L, "토다리", true), + new MemberUpdateRequest(2L, "쿠키", false) + ) + ); + String requestBody = objectMapper.writeValueAsString(membersUpdateRequest); + + mockMvc.perform(put("/api/admin/events/{eventId}/members", eventId) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + .cookie(EVENT_COOKIE) + ) + .andDo(print()) + .andExpect(status().isOk()); + } +} diff --git a/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java b/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java deleted file mode 100644 index 051fcae0f..000000000 --- a/server/src/test/java/server/haengdong/presentation/response/StepsResponseTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package server.haengdong.presentation.response; - - -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import server.haengdong.application.response.ActionAppResponse; -import server.haengdong.application.response.ActionAppResponse.ActionType; - -class StepsResponseTest { - - @DisplayName("이웃한 같은 타입의 액션들을 그룹화 하여 응답객체를 생성한다.") - @Test - void of() { - List actions = List.of( - new ActionAppResponse(1L, "망쵸", null, 1L, ActionType.IN), - new ActionAppResponse(2L, "백호", null, 2L, ActionType.IN), - new ActionAppResponse(3L, "감자탕", 10_000L, 3L, ActionType.BILL), - new ActionAppResponse(4L, "인생네컷", 10_000L, 4L, ActionType.BILL), - new ActionAppResponse(5L, "소하", null, 5L, ActionType.IN), - new ActionAppResponse(6L, "웨디", null, 6L, ActionType.IN), - new ActionAppResponse(7L, "망쵸", null, 7L, ActionType.OUT), - new ActionAppResponse(8L, "백호", null, 8L, ActionType.OUT), - new ActionAppResponse(9L, "노래방", 20_000L, 9L, ActionType.BILL) - ); - - StepsResponse stepsResponse = StepsResponse.of(actions); - - StepsResponse expected = new StepsResponse( - List.of( - new StepResponse("0차", "IN", List.of("망쵸", "백호"), List.of( - new ActionResponse(1L, "망쵸", null, 1L), - new ActionResponse(2L, "백호", null, 2L) - )), - new StepResponse("1차", "BILL", List.of("망쵸", "백호"), List.of( - new ActionResponse(3L, "감자탕", 10_000L, 3L), - new ActionResponse(4L, "인생네컷", 10_000L, 4L) - )), - new StepResponse("1차", "IN", List.of("망쵸", "백호", "소하", "웨디"), List.of( - new ActionResponse(5L, "소하", null, 5L), - new ActionResponse(6L, "웨디", null, 6L) - )), - new StepResponse("1차", "OUT", List.of("소하", "웨디"), List.of( - new ActionResponse(7L, "망쵸", null, 7L), - new ActionResponse(8L, "백호", null, 8L) - )), - new StepResponse("2차", "BILL", List.of("소하", "웨디"), List.of( - new ActionResponse(9L, "노래방", 20_000L, 9L) - )) - ) - ); - assertThat(stepsResponse).isEqualTo(expected); - } - - @DisplayName("액션이 없으면 빈 스탭들이 만들어진다.") - @Test - void ofEmpty() { - StepsResponse stepsResponse = StepsResponse.of(List.of()); - assertThat(stepsResponse.steps()).isEmpty(); - } -} diff --git a/server/src/test/java/server/haengdong/support/fixture/Fixture.java b/server/src/test/java/server/haengdong/support/fixture/Fixture.java index b8d736d4b..e05b43c23 100644 --- a/server/src/test/java/server/haengdong/support/fixture/Fixture.java +++ b/server/src/test/java/server/haengdong/support/fixture/Fixture.java @@ -1,10 +1,8 @@ package server.haengdong.support.fixture; import jakarta.servlet.http.Cookie; -import server.haengdong.domain.action.BillAction; -import server.haengdong.domain.action.MemberAction; -import server.haengdong.domain.action.MemberActionStatus; -import server.haengdong.domain.action.Sequence; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.member.Member; import server.haengdong.domain.event.Event; public class Fixture { @@ -12,15 +10,9 @@ public class Fixture { public static final Event EVENT1 = new Event("쿠키", "1234", "TOKEN1"); public static final Event EVENT2 = new Event("웨디", "1234", "TOKEN2"); public static final Cookie EVENT_COOKIE = new Cookie("eventToken", "토큰토큰"); - public static final BillAction BILL_ACTION = new BillAction(EVENT1, new Sequence(1L), "뽕족", 30_000L); - - public static BillAction createBillAction(Event event, Long sequence, String title, Long price) { - return new BillAction(event, new Sequence(sequence), title, price); - } - - public static MemberAction createMemberAction( - Event event, Long sequence, String memberName, MemberActionStatus status - ) { - return new MemberAction(event, new Sequence(sequence), memberName, status); - } + public static final Member MEMBER1 = new Member(EVENT1, "토다리"); + public static final Member MEMBER2 = new Member(EVENT1, "쿠키"); + public static final Member MEMBER3 = new Member(EVENT1, "소하"); + public static final Bill BILL1 = new Bill(EVENT1, "행동대장 회식", 10000L); + public static final Bill BILL2 = new Bill(EVENT2, "행동대장 회식2", 20000L); }