Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BE] 행사 참여 인원 또는 지출 총액 변동시 차등 정산 초기화 기능 구현 #370

Merged
merged 7 commits into from
Aug 16, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import server.haengdong.domain.action.Action;
import server.haengdong.domain.action.ActionRepository;
import server.haengdong.domain.action.BillAction;
import server.haengdong.domain.action.BillActionDetail;
import server.haengdong.domain.action.BillActionDetailRepository;
import server.haengdong.domain.action.BillActionRepository;
import server.haengdong.domain.event.Event;
import server.haengdong.domain.event.EventRepository;
Expand All @@ -23,6 +25,7 @@ public class BillActionService {
private final BillActionRepository billActionRepository;
private final ActionRepository actionRepository;
private final EventRepository eventRepository;
private final BillActionDetailRepository billActionDetailRepository;

@Transactional
public void saveAllBillAction(String eventToken, List<BillActionAppRequest> requests) {
Expand All @@ -49,10 +52,23 @@ public void updateBillAction(String token, Long actionId, BillActionUpdateAppReq

validateToken(token, billAction);

resetBillActionDetail(billAction, request.price());

BillAction updatedBillAction = billAction.update(request.title(), request.price());
billActionRepository.save(updatedBillAction);
}

private void resetBillActionDetail(BillAction billAction, Long updatePrice) {
if (billAction.getPrice() != updatePrice) {
List<BillActionDetail> billActionDetails = billActionDetailRepository.findByBillAction(billAction);
int memberCount = billActionDetails.size();
if (memberCount != 0) {
Long eachPrice = updatePrice / memberCount;
billActionDetails.forEach(billActionDetail -> billActionDetail.updatePrice(eachPrice));
}
}
}

private void validateToken(String token, BillAction billAction) {
Event event = billAction.getEvent();
if (event.isTokenMismatch(token)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package server.haengdong.application;

import java.util.List;
import java.util.Set;
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.Action;
import server.haengdong.domain.action.ActionRepository;
import server.haengdong.domain.action.BillAction;
import server.haengdong.domain.action.BillActionDetail;
import server.haengdong.domain.action.BillActionDetailRepository;
import server.haengdong.domain.action.BillActionRepository;
import server.haengdong.domain.action.CurrentMembers;
import server.haengdong.domain.action.MemberAction;
import server.haengdong.domain.action.MemberActionRepository;
Expand All @@ -25,6 +30,8 @@ public class MemberActionService {
private final MemberActionRepository memberActionRepository;
private final EventRepository eventRepository;
private final ActionRepository actionRepository;
private final BillActionDetailRepository billActionDetailRepository;
private final BillActionRepository billActionRepository;

@Transactional
public void saveMemberAction(String token, MemberActionsSaveAppRequest request) {
Expand Down Expand Up @@ -65,6 +72,9 @@ public void deleteMember(String token, String memberName) {
.orElseThrow(() -> new HaengdongException(HaengdongErrorCode.EVENT_NOT_FOUND));

memberActionRepository.deleteAllByEventAndMemberName(event, memberName);

List<BillAction> billActions = billActionRepository.findByAction_Event(event);
billActions.forEach(billAction -> resetBillAction(event, billAction));
}

@Transactional
Expand All @@ -76,7 +86,26 @@ public void deleteMemberAction(String token, Long actionId) {
MemberAction memberAction = memberActionRepository.findByAction(action)
.orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_ACTION_NOT_FOUND));

memberActionRepository.deleteAllByMemberNameAndMinSequence(memberAction.getMemberName(),
memberAction.getSequence());
memberActionRepository.deleteAllByMemberNameAndMinSequence(memberAction.getMemberName(), memberAction.getSequence());

List<BillAction> billActions = billActionRepository.findByGreaterThanSequence(action.getSequence());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

action sequence보다 큰 billAction을 모두 조회하는 로직 같아요.
이렇게 하면 다른 이벤트의 billAction을 모두 조회하게 되지 않을까요?

billActions.forEach(billAction -> resetBillAction(event, billAction));
}

private void resetBillAction(Event event, BillAction billAction) {
List<MemberAction> memberActions = memberActionRepository.findByEventAndSequence(event, billAction.getSequence());
CurrentMembers currentMembers = CurrentMembers.of(memberActions);
Set<String> members = currentMembers.getMembers();

billActionDetailRepository.deleteAllByBillAction(billAction);

int memberCount = members.size();
if (memberCount != 0) {
Long eachPrice = billAction.getPrice() / memberCount;
for (String member : members) {
BillActionDetail billActionDetail = new BillActionDetail(billAction, member, eachPrice);
billActionDetailRepository.save(billActionDetail);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,14 @@ public class BillActionDetail {
private String memberName;

private Long price;

public BillActionDetail(BillAction billAction, String memberName, Long price) {
this.billAction = billAction;
this.memberName = memberName;
this.price = price;
}

public void updatePrice(Long price) {
this.price = price;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package server.haengdong.domain.action;

import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface BillActionDetailRepository extends JpaRepository<BillActionDetail, Long> {

List<BillActionDetail> findByBillAction(BillAction billAction);

void deleteAllByBillAction(BillAction billAction);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.Optional;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import server.haengdong.domain.event.Event;

Expand All @@ -16,4 +17,11 @@ public interface BillActionRepository extends JpaRepository<BillAction, Long> {
void deleteByAction_EventAndActionId(Event event, Long actionId);

Optional<BillAction> findByAction_Id(Long actionId);

@Query("""
select ba
from BillAction ba
where ba.action.sequence > :sequence
""")
List<BillAction> findByGreaterThanSequence(Long sequence);
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,11 @@ public interface MemberActionRepository extends JpaRepository<MemberAction, Long
List<MemberAction> findAllByAction_EventAndMemberName(Event event, String memberName);

boolean existsByAction_EventAndMemberName(Event event, String updatedMemberName);

@Query("""
select ma
from MemberAction ma
where ma.action.event = :event and ma.action.sequence < :sequence
""")
List<MemberAction> findByEventAndSequence(Event event, Long sequence);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import server.haengdong.application.request.BillActionUpdateAppRequest;
import server.haengdong.domain.action.Action;
import server.haengdong.domain.action.BillAction;
import server.haengdong.domain.action.BillActionDetail;
import server.haengdong.domain.action.BillActionDetailRepository;
import server.haengdong.domain.action.BillActionRepository;
import server.haengdong.domain.event.Event;
import server.haengdong.domain.event.EventRepository;
Expand All @@ -30,6 +32,9 @@ class BillActionServiceTest extends ServiceTestSupport {
@Autowired
private BillActionRepository billActionRepository;

@Autowired
private BillActionDetailRepository billActionDetailRepository;

@DisplayName("지출 내역을 생성한다.")
@Test
void saveAllBillAction() {
Expand Down Expand Up @@ -107,6 +112,39 @@ void updateBillAction1() {
.isInstanceOf(HaengdongException.class);
}

@DisplayName("지출 내역 금액을 변경하면 지출 디테일이 초기화 된다.")
@Test
void updateBillAction2() {
Event event = Fixture.EVENT1;
Event savedEvent = eventRepository.save(event);
Action action = Action.createFirst(savedEvent);
BillAction billAction = new BillAction(action, "뽕족", 10_000L);
BillAction savedBillAction = billActionRepository.save(billAction);
BillActionDetail billActionDetail1 = new BillActionDetail(savedBillAction, "감자", 3000L);
BillActionDetail billActionDetail2 = new BillActionDetail(savedBillAction, "고구마", 2000L);
BillActionDetail billActionDetail3 = new BillActionDetail(savedBillAction, "당근", 3000L);
BillActionDetail billActionDetail4 = new BillActionDetail(savedBillAction, "양파", 2000L);

billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3, billActionDetail4));

Long actionId = savedBillAction.getAction().getId();
BillActionUpdateAppRequest request = new BillActionUpdateAppRequest("인생맥주", 20_000L);

billActionService.updateBillAction(event.getToken(), actionId, request);

BillAction updatedBillAction = billActionRepository.findById(savedBillAction.getId()).get();
List<BillActionDetail> billActionDetails = billActionDetailRepository.findByBillAction(updatedBillAction);

assertThat(billActionDetails).hasSize(4)
.extracting("memberName", "price")
.containsExactlyInAnyOrder(
tuple("감자", 5000L),
tuple("고구마", 5000L),
tuple("당근", 5000L),
tuple("양파", 5000L)
);
}

@DisplayName("지출 내역을 삭제한다.")
@Test
void deleteBillAction() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
import server.haengdong.application.request.MemberActionSaveAppRequest;
import server.haengdong.application.request.MemberActionsSaveAppRequest;
import server.haengdong.domain.action.Action;
import server.haengdong.domain.action.BillAction;
import server.haengdong.domain.action.BillActionDetail;
import server.haengdong.domain.action.BillActionDetailRepository;
import server.haengdong.domain.action.BillActionRepository;
import server.haengdong.domain.action.MemberAction;
import server.haengdong.domain.action.MemberActionRepository;
import server.haengdong.domain.action.MemberActionStatus;
Expand All @@ -33,6 +37,12 @@ class MemberActionServiceTest extends ServiceTestSupport {
@Autowired
private EventRepository eventRepository;

@Autowired
private BillActionRepository billActionRepository;

@Autowired
private BillActionDetailRepository billActionDetailRepository;

@DisplayName("현재 행사에 참여하고 있는 경우에 나갈 수 있다.")
@Test
void saveMemberActionTest() {
Expand Down Expand Up @@ -115,6 +125,44 @@ void deleteMember() {
);
}

@DisplayName("이벤트에 속한 멤버을 삭제하면 전체 지출 내역 디테일이 초기화된다.")
@Test
void deleteMember1() {
Event event = Fixture.EVENT1;
eventRepository.save(event);
MemberAction memberAction1 = createMemberAction(new Action(event, 1L), "토다리", IN, 1L);
Action targetAction = new Action(event, 2L);
MemberAction memberAction2 = createMemberAction(targetAction, "토다리", OUT, 2L);
MemberAction memberAction3 = createMemberAction(new Action(event, 3L), "쿠키", IN, 3L);
MemberAction memberAction4 = createMemberAction(new Action(event, 4L), "웨디", IN, 4L);
MemberAction memberAction5 = createMemberAction(new Action(event, 5L), "감자", IN, 5L);
memberActionRepository.saveAll(
List.of(memberAction1,
memberAction2,
memberAction3,
memberAction4,
memberAction5
)
);
BillAction billAction = new BillAction(new Action(event, 6L), "뽕족", 100_000L);
billActionRepository.save(billAction);
BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "쿠키", 40_000L);
BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "웨디", 30_000L);
BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "감자", 30_000L);
billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3));

memberActionService.deleteMember(event.getToken(), "쿠키");

List<BillActionDetail> billActionDetails = billActionDetailRepository.findByBillAction(billAction);

assertThat(billActionDetails).hasSize(2)
.extracting("memberName", "price")
.containsExactlyInAnyOrder(
tuple("웨디", 50_000L),
tuple("감자", 50_000L)
);
}

@DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후에 기록된 해당 참여자의 모든 멤버 액션을 삭제한다.")
@Test
void deleteMemberAction() {
Expand Down Expand Up @@ -151,6 +199,45 @@ void deleteMemberAction() {
);
}

@DisplayName("이벤트에 속한 멤버 액션을 삭제하면 이후 지출 내역 디테일이 초기화된다.")
@Test
void deleteMemberAction1() {
Event event = Fixture.EVENT1;
eventRepository.save(event);
MemberAction memberAction1 = createMemberAction(new Action(event, 1L), "토다리", IN, 1L);
Action targetAction = new Action(event, 2L);
MemberAction memberAction2 = createMemberAction(targetAction, "토다리", OUT, 2L);
MemberAction memberAction3 = createMemberAction(new Action(event, 3L), "쿠키", IN, 3L);
MemberAction memberAction4 = createMemberAction(new Action(event, 4L), "웨디", IN, 4L);
MemberAction memberAction5 = createMemberAction(new Action(event, 5L), "감자", IN, 5L);
memberActionRepository.saveAll(
List.of(memberAction1,
memberAction2,
memberAction3,
memberAction4,
memberAction5
)
);
BillAction billAction = new BillAction(new Action(event, 6L), "뽕족", 100_000L);
billActionRepository.save(billAction);
BillActionDetail billActionDetail1 = new BillActionDetail(billAction, "쿠키", 40_000L);
BillActionDetail billActionDetail2 = new BillActionDetail(billAction, "웨디", 30_000L);
BillActionDetail billActionDetail3 = new BillActionDetail(billAction, "감자", 30_000L);
billActionDetailRepository.saveAll(List.of(billActionDetail1, billActionDetail2, billActionDetail3));

memberActionService.deleteMemberAction(event.getToken(), targetAction.getId());
List<BillActionDetail> billActionDetails = billActionDetailRepository.findByBillAction(billAction);

assertThat(billActionDetails).hasSize(4)
.extracting("memberName", "price")
.containsExactlyInAnyOrder(
tuple("토다리", 25_000L),
tuple("쿠키", 25_000L),
tuple("웨디", 25_000L),
tuple("감자", 25_000L)
);
}

private MemberAction createMemberAction(
Action action,
String memberName,
Expand Down
Loading