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

Feature: 동아리 회비 입금여부 수정기능, 동아리 회비 조회 기능 총 잔액 추가, 날짜별로 그룹화 하는 기능 추가 #77

Merged
merged 6 commits into from
Aug 21, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,17 @@ public ResponseEntity<ClubFeeCreateResponse> createClubFee(@AuthenticationPrinci
return ResponseEntity.ok(createdClubFee);
}

@GetMapping("/usages")
@Operation(summary = "동아리 회비 전체에 대한 사용내역 조회", description = "clubId를 지정하여 해당 동아리의 회비 사용내역 전체를 조회합니다.")
public ResponseEntity<ClubFeeUsageResponseList> findAllClubFeeUsage(@AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, @PathVariable("clubId") Long clubId) {
ClubFeeUsageResponseList clubFeeUsageResponseList = clubFeeService.findAllClubFeeUsage(customOAuth2Member, clubId);
return ResponseEntity.ok(clubFeeUsageResponseList);
}

@GetMapping("/{feeTypeId}/usage")
@Operation(summary = "동아리 회비 사용내역 조회", description = "회비의 id를 지정하여 동아리 회비의 사용내역을 조회합니다.")
public ResponseEntity<ClubFeeUsageResponseList> findAllClubFeeUsage(@AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, @PathVariable("clubId") Long clubId, @PathVariable("feeTypeId") Long feeTypeId) {
ClubFeeUsageResponseList clubFeeUsageResponseList = clubFeeService.findAllClubFeeUsage(customOAuth2Member, clubId, feeTypeId);
@Operation(summary = "동아리 회비 하나에 대한 사용내역 조회", description = "회비의 id를 지정하여 해당하는 동아리 회비의 사용내역을 조회합니다.")
public ResponseEntity<ClubFeeUsageResponseList> findAllClubFeeUsageByFeeTypeId(@AuthenticationPrincipal CustomOAuth2Member customOAuth2Member, @PathVariable("clubId") Long clubId, @PathVariable("feeTypeId") Long feeTypeId) {
ClubFeeUsageResponseList clubFeeUsageResponseList = clubFeeService.findAllClubFeeUsageByFeeTypeId(customOAuth2Member, clubId, feeTypeId);
return ResponseEntity.ok(clubFeeUsageResponseList);
}

Expand All @@ -59,6 +66,19 @@ public ResponseEntity<ClubFeePaymentInfoResponseList> findClubFeePaymentInfo(
return ResponseEntity.ok(clubFeePaymentInfo);
}

@PatchMapping("/{feeTypeId}/payment")
@Operation(summary = "동아리 회비 입금 여부 수정", description = "동아리원의 회비 입금 여부를 수정합니다.")
public ResponseEntity<ClubFeePaymentUpdateResponse> updateClubFeePaymentInfo(
@AuthenticationPrincipal CustomOAuth2Member customOAuth2Member,
@PathVariable("clubId") Long clubId,
@PathVariable("feeTypeId") Long feeTypeId,
@RequestBody ClubFeePaymentUpdateRequest clubFeePaymentUpdateRequest) {

ClubFeePaymentUpdateResponse clubFeePaymentUpdateResponse = clubFeeService.updateClubFeePaymentInfo(customOAuth2Member, clubId, feeTypeId, clubFeePaymentUpdateRequest);
return ResponseEntity.ok(clubFeePaymentUpdateResponse);
}





Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.cotato.squadus.api.fee.dto;
import java.util.Map;

public record ClubFeePaymentUpdateRequest(
Map<Long, Boolean> paymentsInfo
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.cotato.squadus.api.fee.dto;

public record ClubFeePaymentUpdateResponse(
Long feeTypeId
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
import java.util.List;

public record ClubFeeSummaryResponseList(
Long totalBalance,
List<ClubFeeSummaryResponse> clubFeeSummaryResponseList
) {

public static ClubFeeSummaryResponseList from(List<ClubFeeSummaryResponse> clubFeeSummaryResponseList) {
return new ClubFeeSummaryResponseList(clubFeeSummaryResponseList);
public static ClubFeeSummaryResponseList from(Long totalBalance, List<ClubFeeSummaryResponse> clubFeeSummaryResponseList) {
return new ClubFeeSummaryResponseList(totalBalance, clubFeeSummaryResponseList);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.time.LocalDate;

public record ClubFeeUsageResponse(
Long feeTypeId,
Long feeUsageId,
LocalDate usedAt,
String description,
Expand All @@ -13,6 +14,7 @@ public record ClubFeeUsageResponse(

public static ClubFeeUsageResponse from(FeeUsage feeUsage) {
return new ClubFeeUsageResponse(
feeUsage.getFeeType().getFeeTypeId(),
feeUsage.getFeeUsageId(),
feeUsage.getUsedAt(),
feeUsage.getDescription(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import java.util.List;

public record ClubFeeUsageResponseList(
List<ClubFeeUsageResponse> clubFeeUsageResponseList
List<DateGroupedClubFeeUsageResponse> dateGroupedClubFeeUsageResponseList
) {
public static ClubFeeUsageResponseList from(List<ClubFeeUsageResponse> clubFeeUsageResponseList) {
return new ClubFeeUsageResponseList(clubFeeUsageResponseList);
public static ClubFeeUsageResponseList from(List<DateGroupedClubFeeUsageResponse> dateGroupedClubFeeUsageResponseList) {
return new ClubFeeUsageResponseList(dateGroupedClubFeeUsageResponseList);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.cotato.squadus.api.fee.dto;

import java.time.LocalDate;
import java.util.List;

public record DateGroupedClubFeeUsageResponse(
LocalDate date,
List<ClubFeeUsageResponse> usages
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ public enum ErrorCode {
ENUM_NOT_RESOLVED(HttpStatus.BAD_REQUEST, "S-005", "입력한 Enum이 존재하지 않습니다."),

NO_BALANCE_ERROR(HttpStatus.BAD_REQUEST, "F-001", "회비의 잔액보다 사용내역의 금액이 더 큽니다."),
PAYMENT_CHANGE_DENIED(HttpStatus.BAD_REQUEST, "F-002", "이미 사용중인 회비의 입금현황을 변경할 수 없습니다."),
;

private final HttpStatus httpStatus;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.cotato.squadus.domain.club.fee.entity;


import com.cotato.squadus.domain.club.common.entity.Club;
import com.cotato.squadus.domain.club.common.entity.ClubMember;
import jakarta.persistence.*;
import lombok.Builder;
Expand All @@ -28,6 +27,10 @@ public class FeePayment {
@JoinColumn(name = "club_member_idx")
private ClubMember clubMember;

public void updateIsPaid(Boolean isPaid) {
this.isPaid = isPaid;
}

@Builder
public FeePayment(Boolean isPaid, FeeType feeType, ClubMember clubMember) {
this.isPaid = isPaid;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ public void updateFeeUsages(FeeUsage feeUsage) {
this.feeUsages.add(feeUsage);
}

public void updateTotalPrice(Long totalPrice) {
this.totalPrice = totalPrice;
}

@Builder
public FeeType(Club club, String feeTypeName, Long price, String memo, List<ClubMember> clubMembers, FeeCategory feeCategory, LocalDate startDate, LocalDate endDate, Long totalPrice, Long balance) {
this.club = club;
Expand All @@ -84,6 +88,6 @@ public void update(String feeTypeName, Long price, String memo, FeeCategory feeC


public void updateBalance(Long price) {
this.balance -= price;
this.balance += price;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@
public interface FeeUsageRepository extends JpaRepository<FeeUsage, Long> {

List<FeeUsage> findAllByFeeType(FeeType feeType);

List<FeeUsage> findAllByFeeType_Club_ClubId(Long clubId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
Expand All @@ -41,8 +45,16 @@ public class ClubFeeService {

public ClubFeeSummaryResponseList findAllClubFeeTypesSummary(CustomOAuth2Member customOAuth2Member, Long clubId) {

List<ClubFeeSummaryResponse> clubFeeSummaryResponseList = feeTypeRepository.findAllByClub_ClubId(clubId).stream().map(ClubFeeSummaryResponse::from).toList();
return ClubFeeSummaryResponseList.from(clubFeeSummaryResponseList);
List<ClubFeeSummaryResponse> clubFeeSummaryResponseList = feeTypeRepository.findAllByClub_ClubId(clubId)
.stream().
map(ClubFeeSummaryResponse::from)
.toList();

Long totalBalance = clubFeeSummaryResponseList.stream()
.mapToLong(ClubFeeSummaryResponse::balance)
.sum();

return ClubFeeSummaryResponseList.from(totalBalance, clubFeeSummaryResponseList);
}

@Transactional
Expand Down Expand Up @@ -128,7 +140,7 @@ public ClubFeeUsageCreateResponse createClubFeeUsage(CustomOAuth2Member customOA
if (clubFeeUsageRequest.price() > feeType.getBalance()) {
throw new AppException(ErrorCode.NO_BALANCE_ERROR);
}
feeType.updateBalance(clubFeeUsageRequest.price()); // price 만큼 사용
feeType.updateBalance(-clubFeeUsageRequest.price()); // price 만큼 사용

FeeUsage feeUsage = FeeUsage.builder()
.feeType(feeType)
Expand Down Expand Up @@ -164,7 +176,21 @@ public ClubFeePaymentInfoResponseList findClubFeePaymentInfo(CustomOAuth2Member

}

public ClubFeeUsageResponseList findAllClubFeeUsage(CustomOAuth2Member customOAuth2Member, Long clubId, Long feeTypeId) {
public ClubFeeUsageResponseList findAllClubFeeUsage(CustomOAuth2Member customOAuth2Member, Long clubId) {

// clubId에 해당하는 모든 FeeUsage를 조회 및 변환
List<ClubFeeUsageResponse> allUsages = feeUsageRepository.findAllByFeeType_Club_ClubId(clubId)
.stream()
.map(ClubFeeUsageResponse::from)
.toList();

List<DateGroupedClubFeeUsageResponse> dateGroupedResponses = getDateGroupedClubFeeUsageResponses(allUsages);

return ClubFeeUsageResponseList.from(dateGroupedResponses);

}

public ClubFeeUsageResponseList findAllClubFeeUsageByFeeTypeId(CustomOAuth2Member customOAuth2Member, Long clubId, Long feeTypeId) {

FeeType feeType = feeTypeRepository.findById(feeTypeId)
.orElseThrow(() -> new EntityNotFoundException("해당 id를 가진 회비를 찾을 수 없습니다."));
Expand All @@ -173,7 +199,50 @@ public ClubFeeUsageResponseList findAllClubFeeUsage(CustomOAuth2Member customOAu
.map(ClubFeeUsageResponse::from)
.toList();

return ClubFeeUsageResponseList.from(clubFeeUsageResponseList);
List<DateGroupedClubFeeUsageResponse> dateGroupedResponses = getDateGroupedClubFeeUsageResponses(clubFeeUsageResponseList);

return ClubFeeUsageResponseList.from(dateGroupedResponses);

}

private List<DateGroupedClubFeeUsageResponse> getDateGroupedClubFeeUsageResponses(List<ClubFeeUsageResponse> clubFeeUsageResponseList) {
// 사용 내역을 날짜별로 그룹화
Map<LocalDate, List<ClubFeeUsageResponse>> groupedByDate = clubFeeUsageResponseList.stream()
.collect(Collectors.groupingBy(ClubFeeUsageResponse::usedAt));

// 날짜별로 그룹화된 데이터를 적절한 응답 형태로 변환
List<DateGroupedClubFeeUsageResponse> dateGroupedResponses = groupedByDate.entrySet().stream()
.map(entry -> new DateGroupedClubFeeUsageResponse(entry.getKey(), entry.getValue()))
.sorted(Comparator.comparing(DateGroupedClubFeeUsageResponse::date).reversed()) // 날짜별로 최신 순 정렬
.toList();
return dateGroupedResponses;
}

@Transactional
public ClubFeePaymentUpdateResponse updateClubFeePaymentInfo(CustomOAuth2Member customOAuth2Member, Long clubId, Long feeTypeId, ClubFeePaymentUpdateRequest clubFeePaymentUpdateRequest) {
List<FeePayment> feePayments = feePaymentRepository.findAllByFeeType_FeeTypeId(feeTypeId);
FeeType feeType = feeTypeRepository.findById(feeTypeId)
.orElseThrow(() -> new EntityNotFoundException("해당 아이디를 가진 feeType을 찾을 수 없습니다."));

Long totalPrice = 0L;
if(!feeType.getBalance().equals(0L)) {
throw new AppException(ErrorCode.PAYMENT_CHANGE_DENIED);
}
for (FeePayment feePayment : feePayments) {
Long clubMemberIdx = feePayment.getClubMember().getClubMemberIdx();
if(clubFeePaymentUpdateRequest.paymentsInfo().get(clubMemberIdx)) {
feePayment.updateIsPaid(true);
totalPrice += feeType.getPrice();
} else {
feePayment.updateIsPaid(false);
}
feePaymentRepository.save(feePayment);
}
feeType.updateTotalPrice(totalPrice);
feeType.updateBalance(totalPrice);
feeTypeRepository.save(feeType);
return new ClubFeePaymentUpdateResponse(feeTypeId);
}


}
Loading