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] 변경된 요구사항에 맞게 API 전체 수정 #558

Merged
merged 8 commits into from
Sep 19, 2024

This file was deleted.

This file was deleted.

177 changes: 177 additions & 0 deletions server/src/main/java/server/haengdong/application/BillService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package server.haengdong.application;

import java.util.ArrayList;
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.LastBillMemberAppResponse;
import server.haengdong.application.response.StepAppResponse;
import server.haengdong.domain.action.Bill;
import server.haengdong.domain.action.BillDetail;
import server.haengdong.domain.action.BillRepository;
import server.haengdong.domain.action.Member;
import server.haengdong.domain.action.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 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<Long> memberIds = request.memberIds();
List<Member> 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));
}
Comment on lines +45 to +48
Copy link
Contributor

Choose a reason for hiding this comment

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

메서드명이 getMember가 되는게 맞겠네요.
각 repository에 default 메서드로 get 메서드를 만드는거 어떻게 생각하시나요?

Copy link
Contributor

Choose a reason for hiding this comment

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

default 메서드를 만든다면 어느 정도까지 만드는 것이 좋은지 잘 모르겠네요.
현재는 findById만 있지만 findByIdAndName 등등이 생기면 계속 추가하는 것이 좋을까요?

또한 사용하는 사람 입장에서 findById, getById 둘다 열려있으면 혼용하는 경우가 발생해서 통일성을 지키기 더 어렵다고 생각합니다.

Copy link
Contributor

@kunsanglee kunsanglee Sep 15, 2024

Choose a reason for hiding this comment

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

기본적으로 repository에서 id를 가지고 찾는 정도는 get 메서드로 가지면 보일러플레이트 코드를 줄일 수 있어서 충분히 유용하다고 생각합니다. 이외 것들은 백호가 말씀해주신 것 처럼 오히려 예측 불가능해질 수 있겠네요.


public List<StepAppResponse> findSteps(String token) {
Event event = getEvent(token);
List<Bill> bills = billRepository.findByEvent(event);

return createStepAppResponses(bills);
}

private List<StepAppResponse> createStepAppResponses(List<Bill> bills) {
return divideByMembers(bills).stream()
.map(StepAppResponse::of)
.toList();
}

private static List<List<Bill>> divideByMembers(List<Bill> bills) {
List<List<Bill>> split = new ArrayList<>();
for (Bill bill : bills) {
if (split.isEmpty()) {
List<Bill> temp = new ArrayList<>();
temp.add(bill);
split.add(temp);
continue;
}
List<Bill> bills1 = split.get(split.size() - 1);
Bill find = bills1.get(0);
if (find.isSameMembers(bill)) {
bills1.add(bill);
} else {
List<Bill> temp = new ArrayList<>();
temp.add(bill);
split.add(temp);
}
}
return split;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
private static List<List<Bill>> divideByMembers(List<Bill> bills) {
List<List<Bill>> split = new ArrayList<>();
for (Bill bill : bills) {
if (split.isEmpty()) {
List<Bill> temp = new ArrayList<>();
temp.add(bill);
split.add(temp);
continue;
}
List<Bill> bills1 = split.get(split.size() - 1);
Bill find = bills1.get(0);
if (find.isSameMembers(bill)) {
bills1.add(bill);
} else {
List<Bill> temp = new ArrayList<>();
temp.add(bill);
split.add(temp);
}
}
return split;
}
private List<List<Bill>> divideByMembers(List<Bill> bills) {
List<List<Bill>> billGroup = new ArrayList<>();
List<Bill> currentGroup = null;
for (Bill bill : bills) {
if (currentGroup == null || !currentGroup.get(0).isSameMembers(bill)) {
currentGroup = new ArrayList<>();
billGroup.add(currentGroup);
}
currentGroup.add(bill);
}
return billGroup;
}

조금 단순화 해봤습니다. 그리고 static 메서드일 필요가 없네요.

Copy link
Contributor

Choose a reason for hiding this comment

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

이 로직을 Steps, Step 객체를 만들어 넣어도 좋겠네요.


@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<BillDetail> 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<BillDetailUpdateAppRequest> billDetailUpdateAppRequests = request.billDetailUpdateAppRequests();

validateToken(token, bill);
validateBillDetailSize(billDetailUpdateAppRequests, bill);
validateTotalPrice(billDetailUpdateAppRequests, bill);

List<BillDetail> 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<BillDetailUpdateAppRequest> requests, Bill bill) {
List<Long> 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<BillDetailUpdateAppRequest> billDetailUpdateAppRequests,
Bill bill
) {
Long requestsPriceSum = calculateUpdatePriceSum(billDetailUpdateAppRequests);
if (!bill.isSamePrice(requestsPriceSum)) {
throw new HaengdongException(HaengdongErrorCode.BILL_PRICE_NOT_MATCHED);
}
}

private Long calculateUpdatePriceSum(List<BillDetailUpdateAppRequest> 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));
}
}
Loading
Loading