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/#83 - 4.8 나의 온기 조회 API 구현 #84

Merged
merged 1 commit into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions http/onjung/OnjungControllerHttpRequest.http
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,8 @@ Content-Type: application/json
{
"donation_amount": {{onjung.API_4_7.donation_amount}}
}

### 4.8 나의 온기 조회하기
// @no-log
GET {{host_url}}/api/v1/users/onjungs/overviews
Authorization: Bearer {{access_token}}
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@
import com.daon.onjung.account.domain.User;
import com.daon.onjung.core.dto.SelfValidating;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;
import lombok.Getter;

@Getter
public class ReadUserOverviewsResponseDto extends SelfValidating<ReadUserOverviewsResponseDto> {

@NotNull(message = "user_name은 null이 될 수 없습니다.")
@JsonProperty("user_name")
private final String userName;

@NotNull(message = "profile_img_url은 null이 될 수 없습니다.")
@JsonProperty("profile_img_url")
private final String profileImgUrl;

Expand All @@ -22,6 +25,7 @@ public ReadUserOverviewsResponseDto(
) {
this.userName = userName;
this.profileImgUrl = profileImgUrl;
this.validateSelf();
}

public static ReadUserOverviewsResponseDto fromEntity(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package com.daon.onjung.account.application.dto.response;

import com.daon.onjung.account.domain.User;
import com.daon.onjung.core.dto.SelfValidating;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;
import lombok.Getter;

@Getter
public class UpdateUserNotificationAllowedResponseDto {
public class UpdateUserNotificationAllowedResponseDto extends SelfValidating<UpdateUserNotificationAllowedResponseDto> {

@NotNull(message = "notification_allowed은 null이 될 수 없습니다.")
@JsonProperty("notification_allowed")
private final Boolean notificationAllowed;

Expand All @@ -16,6 +19,7 @@ public UpdateUserNotificationAllowedResponseDto(
Boolean notificationAllowed
) {
this.notificationAllowed = notificationAllowed;
this.validateSelf();
}

public static UpdateUserNotificationAllowedResponseDto fromEntity(User user) {
Expand Down
14 changes: 12 additions & 2 deletions src/main/java/com/daon/onjung/core/utility/DateTimeUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,10 @@ public static String convertLocalDateTimeToCustomDateTime(LocalDateTime dateTime
/**
* 나의 식권 조회 시간 포맷팅: "yyyy.MM.dd"
*
* @param date LocalDateTime
* @param date LocalDate
* @return String
*/
public static String convertLocalDateTimeToDotSeparatedDateTime(LocalDate date) {
public static String convertLocalDateToDotSeparatedDateTime(LocalDate date) {
return date.format(DotSeparatedDateFormatter);
}

Expand All @@ -214,6 +214,16 @@ public static LocalDate convertDotSeparatedToLocalDate(String date) {
return LocalDate.parse(date, DotSeparatedDateFormatter);
}

/**
* 나의 온기 조회 시간 포맷팅: "yyyy.MM.dd"
*
* @param dateTime LocalDate
* @return String
*/
public static String convertLocalDateTimeToDotSeparatedDateTime(LocalDateTime dateTime) {
return dateTime.format(DotSeparatedDateFormatter);
}


/**
* 날짜 문자열을 특정 포맷으로 변환
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public static TicketDto fromEntity(Ticket ticket, Store store) {
return TicketDto.builder()
.id(ticket.getId())
.storeInfo(StoreInfoDto.fromEntity(store))
.expirationDate(DateTimeUtil.convertLocalDateTimeToDotSeparatedDateTime(ticket.getExpirationDate()))
.expirationDate(DateTimeUtil.convertLocalDateToDotSeparatedDateTime(ticket.getExpirationDate()))
.ticketPrice(ticket.getTicketPrice())
.isValidate(ticket.getIsValidate())
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import com.daon.onjung.event.domain.event.EventScheduled;
import com.daon.onjung.event.domain.service.EventService;
import com.daon.onjung.event.domain.service.TicketService;
import com.daon.onjung.event.domain.type.EStatus;
import com.daon.onjung.event.repository.mysql.EventRepository;
import com.daon.onjung.event.repository.mysql.TicketRepository;
import com.daon.onjung.onjung.repository.mysql.DonationRepository;
Expand Down Expand Up @@ -177,7 +176,7 @@ public void execute(Long eventId) {
store.getCategory().toString(),
store.getOcrStoreAddress(),
store.getLogoImgUrl(),
DateTimeUtil.convertLocalDateTimeToDotSeparatedDateTime(ticket.getExpirationDate())
DateTimeUtil.convertLocalDateToDotSeparatedDateTime(ticket.getExpirationDate())
);
restClientUtil.sendPostMethod(url, headers, firebaseRequestBody);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
import com.daon.onjung.onjung.application.dto.response.ReadOnjungBriefResponseDto;
import com.daon.onjung.onjung.application.dto.response.ReadOnjungCountResponseDto;
import com.daon.onjung.onjung.application.dto.response.ReadOnjungSummaryResponseDto;
import com.daon.onjung.onjung.application.dto.response.ReadUserOnjungOverviewResponseDto;
import com.daon.onjung.onjung.application.usecase.ReadOnjungBriefUseCase;
import com.daon.onjung.onjung.application.usecase.ReadOnjungCountUseCase;
import com.daon.onjung.onjung.application.usecase.ReadOnjungSummaryUseCase;
import com.daon.onjung.onjung.application.usecase.ReadUserOnjungOverviewUseCase;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
Expand All @@ -21,6 +23,7 @@ public class OnjungQueryV1Controller {
private final ReadOnjungSummaryUseCase readOnjungSummaryUseCase;
private final ReadOnjungCountUseCase readOnjungCountUseCase;
private final ReadOnjungBriefUseCase readOnjungBriefUseCase;
private final ReadUserOnjungOverviewUseCase readUserOnjungOverviewUseCase;

/**
* 4.1 전체 온기 통계 조회하기
Expand Down Expand Up @@ -49,4 +52,14 @@ public ResponseDto<ReadOnjungBriefResponseDto> readOnjungBrief(
) {
return ResponseDto.ok(readOnjungBriefUseCase.execute(accountId));
}

/**
* 4.8 나의 온기 조회
*/
@GetMapping("/api/v1/users/onjungs/overviews")
public ResponseDto<ReadUserOnjungOverviewResponseDto> readUserOnjungOverview(
@AccountID UUID accountId
) {
return ResponseDto.ok(readUserOnjungOverviewUseCase.execute(accountId));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package com.daon.onjung.onjung.application.dto.response;

import com.daon.onjung.core.dto.SelfValidating;
import com.daon.onjung.core.exception.error.ErrorCode;
import com.daon.onjung.core.exception.type.CommonException;
import com.daon.onjung.core.utility.DateTimeUtil;
import com.daon.onjung.onjung.domain.Donation;
import com.daon.onjung.onjung.domain.Receipt;
import com.daon.onjung.onjung.domain.Share;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;
import lombok.Getter;

import java.util.List;
import java.util.stream.Collectors;

@Getter
public class ReadUserOnjungOverviewResponseDto extends SelfValidating<ReadUserOnjungOverviewResponseDto> {

@JsonProperty("store_list")
@NotNull(message = "store_list는 null일 수 없습니다.")
private final List<StoreDto> storeList;

@Builder
public ReadUserOnjungOverviewResponseDto(List<StoreDto> storeList) {
this.storeList = storeList;
this.validateSelf();
}

@Getter
public static class StoreDto extends SelfValidating<StoreDto> {

@JsonProperty("onjung_type")
@NotNull(message = "onjung_type은 null일 수 없습니다.")
private final String onjungType;

@JsonProperty("store_name")
@NotNull(message = "store_name은 null일 수 없습니다.")
private final String storeName;

@JsonProperty("store_title")
@NotNull(message = "store_title은 null일 수 없습니다.")
private final String storeTitle;

@JsonProperty("amount")
@NotNull(message = "amount는 null일 수 없습니다.")
private final Integer amount;

@JsonProperty("date")
@NotNull(message = "date는 null일 수 없습니다.")
private final String date;

@Builder
public StoreDto(String onjungType, String storeName, String storeTitle, Integer amount, String date) {
this.onjungType = onjungType;
this.storeName = storeName;
this.storeTitle = storeTitle;
this.amount = amount;
this.date = date;
this.validateSelf();
}

public static StoreDto of(String onjungType, String storeName, String storeTitle, Integer amount, String date) {
return StoreDto.builder()
.onjungType(onjungType)
.storeName(storeName)
.storeTitle(storeTitle)
.amount(amount)
.date(date)
.build();
}
}

public static ReadUserOnjungOverviewResponseDto of(List<Object> sortedEntities) {

List<StoreDto> storeList = sortedEntities.stream()
.map(entity -> {
if (entity instanceof Donation donation) {
return StoreDto.of(
"DONATION",
donation.getStore().getName(),
donation.getStore().getTitle(),
donation.getDonationAmount(),
DateTimeUtil.convertLocalDateTimeToDotSeparatedDateTime(donation.getCreatedAt())
);
} else if (entity instanceof Receipt receipt) {
return StoreDto.of(
"RECEIPT",
receipt.getStore().getName(),
receipt.getStore().getTitle(),
receipt.getPaymentAmount(),
DateTimeUtil.convertLocalDateTimeToDotSeparatedDateTime(receipt.getCreatedAt())
);
} else if (entity instanceof Share share) {
return StoreDto.of(
"SHARE",
share.getStore().getName(),
share.getStore().getTitle(),
share.getCount() * 100,
DateTimeUtil.convertLocalDateTimeToDotSeparatedDateTime(share.getCreatedAt().atStartOfDay())
);
}
throw new CommonException(ErrorCode.INVALID_ARGUMENT);
})
.collect(Collectors.toList());

return ReadUserOnjungOverviewResponseDto.builder()
.storeList(storeList)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.daon.onjung.onjung.application.service;

import com.daon.onjung.account.domain.User;
import com.daon.onjung.account.repository.mysql.UserRepository;
import com.daon.onjung.core.exception.error.ErrorCode;
import com.daon.onjung.core.exception.type.CommonException;
import com.daon.onjung.onjung.application.dto.response.ReadUserOnjungOverviewResponseDto;
import com.daon.onjung.onjung.application.usecase.ReadUserOnjungOverviewUseCase;
import com.daon.onjung.onjung.domain.Donation;
import com.daon.onjung.onjung.domain.Onjung;
import com.daon.onjung.onjung.domain.Receipt;
import com.daon.onjung.onjung.domain.Share;
import com.daon.onjung.onjung.domain.service.OnjungService;
import com.daon.onjung.onjung.repository.mysql.DonationRepository;
import com.daon.onjung.onjung.repository.mysql.ReceiptRepository;
import com.daon.onjung.onjung.repository.mysql.ShareRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.UUID;

@Service
@RequiredArgsConstructor
public class ReadUserOnjungOverviewService implements ReadUserOnjungOverviewUseCase {

private final UserRepository userRepository;
private final DonationRepository donationRepository;
private final ShareRepository shareRepository;
private final ReceiptRepository receiptRepository;

private final OnjungService onjungService;

@Override
@Transactional(readOnly = true)
public ReadUserOnjungOverviewResponseDto execute(
UUID accountId) {

// 유저 조회
User user = userRepository.findById(accountId)
.orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_RESOURCE));

// 유저의 동참, 공유, 영수증 인증 조회
List<Donation> donations = donationRepository.findAllByUser(user);
List<Share> shares = shareRepository.findAllByUser(user);
List<Receipt> receipts = receiptRepository.findAllByUser(user);

Onjung onjung = onjungService.createOnjung(donations, receipts, shares);

// 생성 시간 기준으로 정렬
List<Object> sortedOnjungByCreatedAt = onjungService.sortOnjungByCreatedAt(onjung);

return ReadUserOnjungOverviewResponseDto.of(sortedOnjungByCreatedAt);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.daon.onjung.onjung.application.usecase;

import com.daon.onjung.core.annotation.bean.UseCase;
import com.daon.onjung.onjung.application.dto.response.ReadUserOnjungOverviewResponseDto;

import java.util.UUID;

@UseCase
public interface ReadUserOnjungOverviewUseCase {

ReadUserOnjungOverviewResponseDto execute(UUID accountId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

import com.daon.onjung.account.domain.Store;
import com.daon.onjung.account.domain.User;
import com.daon.onjung.core.exception.error.ErrorCode;
import com.daon.onjung.core.exception.type.CommonException;
import com.daon.onjung.onjung.domain.Donation;
import com.daon.onjung.onjung.domain.Onjung;
import com.daon.onjung.onjung.domain.Receipt;
import com.daon.onjung.onjung.domain.Share;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;

@Service
Expand Down Expand Up @@ -87,4 +87,25 @@ public Integer calculateTotalOnjungAmount(Onjung onjung) {
})
.reduce(0, Integer::sum);
}

// 온정 객체를 받아서 생성일 기준으로 정렬
public List<Object> sortOnjungByCreatedAt(Onjung onjung) {
List<Object> allEntities = new ArrayList<>();
allEntities.addAll(onjung.getDonations());
allEntities.addAll(onjung.getReceipts());
allEntities.addAll(onjung.getShares());

return allEntities.stream()
.sorted(Comparator.comparing(entity -> {
if (entity instanceof Donation) {
return ((Donation) entity).getCreatedAt();
} else if (entity instanceof Receipt) {
return ((Receipt) entity).getCreatedAt();
} else if (entity instanceof Share) {
return ((Share) entity).getCreatedAt().atStartOfDay();
}
throw new CommonException(ErrorCode.INVALID_ARGUMENT);
}))
.collect(Collectors.toList());
}
}
Loading