diff --git a/http/onjung/OnjungControllerHttpRequest.http b/http/onjung/OnjungControllerHttpRequest.http index 236cf28..cb29dd9 100644 --- a/http/onjung/OnjungControllerHttpRequest.http +++ b/http/onjung/OnjungControllerHttpRequest.http @@ -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}} \ No newline at end of file diff --git a/src/main/java/com/daon/onjung/account/application/dto/response/ReadUserOverviewsResponseDto.java b/src/main/java/com/daon/onjung/account/application/dto/response/ReadUserOverviewsResponseDto.java index d5595a4..c4e3b75 100644 --- a/src/main/java/com/daon/onjung/account/application/dto/response/ReadUserOverviewsResponseDto.java +++ b/src/main/java/com/daon/onjung/account/application/dto/response/ReadUserOverviewsResponseDto.java @@ -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 { + @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; @@ -22,6 +25,7 @@ public ReadUserOverviewsResponseDto( ) { this.userName = userName; this.profileImgUrl = profileImgUrl; + this.validateSelf(); } public static ReadUserOverviewsResponseDto fromEntity( diff --git a/src/main/java/com/daon/onjung/account/application/dto/response/UpdateUserNotificationAllowedResponseDto.java b/src/main/java/com/daon/onjung/account/application/dto/response/UpdateUserNotificationAllowedResponseDto.java index 0916007..bddf15f 100644 --- a/src/main/java/com/daon/onjung/account/application/dto/response/UpdateUserNotificationAllowedResponseDto.java +++ b/src/main/java/com/daon/onjung/account/application/dto/response/UpdateUserNotificationAllowedResponseDto.java @@ -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 { + @NotNull(message = "notification_allowed은 null이 될 수 없습니다.") @JsonProperty("notification_allowed") private final Boolean notificationAllowed; @@ -16,6 +19,7 @@ public UpdateUserNotificationAllowedResponseDto( Boolean notificationAllowed ) { this.notificationAllowed = notificationAllowed; + this.validateSelf(); } public static UpdateUserNotificationAllowedResponseDto fromEntity(User user) { diff --git a/src/main/java/com/daon/onjung/core/utility/DateTimeUtil.java b/src/main/java/com/daon/onjung/core/utility/DateTimeUtil.java index d4772be..fd0626e 100644 --- a/src/main/java/com/daon/onjung/core/utility/DateTimeUtil.java +++ b/src/main/java/com/daon/onjung/core/utility/DateTimeUtil.java @@ -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); } @@ -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); + } + /** * 날짜 문자열을 특정 포맷으로 변환 diff --git a/src/main/java/com/daon/onjung/event/application/dto/response/ReadTicketResponseDto.java b/src/main/java/com/daon/onjung/event/application/dto/response/ReadTicketResponseDto.java index 7d1b44a..7847e00 100644 --- a/src/main/java/com/daon/onjung/event/application/dto/response/ReadTicketResponseDto.java +++ b/src/main/java/com/daon/onjung/event/application/dto/response/ReadTicketResponseDto.java @@ -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(); diff --git a/src/main/java/com/daon/onjung/event/application/service/ProcessCompletedEventService.java b/src/main/java/com/daon/onjung/event/application/service/ProcessCompletedEventService.java index 1b680db..c3186f2 100644 --- a/src/main/java/com/daon/onjung/event/application/service/ProcessCompletedEventService.java +++ b/src/main/java/com/daon/onjung/event/application/service/ProcessCompletedEventService.java @@ -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; @@ -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); } diff --git a/src/main/java/com/daon/onjung/onjung/application/controller/query/OnjungQueryV1Controller.java b/src/main/java/com/daon/onjung/onjung/application/controller/query/OnjungQueryV1Controller.java index 326093e..cd1cbbd 100644 --- a/src/main/java/com/daon/onjung/onjung/application/controller/query/OnjungQueryV1Controller.java +++ b/src/main/java/com/daon/onjung/onjung/application/controller/query/OnjungQueryV1Controller.java @@ -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; @@ -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 전체 온기 통계 조회하기 @@ -49,4 +52,14 @@ public ResponseDto readOnjungBrief( ) { return ResponseDto.ok(readOnjungBriefUseCase.execute(accountId)); } + + /** + * 4.8 나의 온기 조회 + */ + @GetMapping("/api/v1/users/onjungs/overviews") + public ResponseDto readUserOnjungOverview( + @AccountID UUID accountId + ) { + return ResponseDto.ok(readUserOnjungOverviewUseCase.execute(accountId)); + } } diff --git a/src/main/java/com/daon/onjung/onjung/application/dto/response/ReadUserOnjungOverviewResponseDto.java b/src/main/java/com/daon/onjung/onjung/application/dto/response/ReadUserOnjungOverviewResponseDto.java new file mode 100644 index 0000000..8bec1cc --- /dev/null +++ b/src/main/java/com/daon/onjung/onjung/application/dto/response/ReadUserOnjungOverviewResponseDto.java @@ -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 { + + @JsonProperty("store_list") + @NotNull(message = "store_list는 null일 수 없습니다.") + private final List storeList; + + @Builder + public ReadUserOnjungOverviewResponseDto(List storeList) { + this.storeList = storeList; + this.validateSelf(); + } + + @Getter + public static class StoreDto extends SelfValidating { + + @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 sortedEntities) { + + List 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(); + } +} diff --git a/src/main/java/com/daon/onjung/onjung/application/service/ReadUserOnjungOverviewService.java b/src/main/java/com/daon/onjung/onjung/application/service/ReadUserOnjungOverviewService.java new file mode 100644 index 0000000..44e684f --- /dev/null +++ b/src/main/java/com/daon/onjung/onjung/application/service/ReadUserOnjungOverviewService.java @@ -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 donations = donationRepository.findAllByUser(user); + List shares = shareRepository.findAllByUser(user); + List receipts = receiptRepository.findAllByUser(user); + + Onjung onjung = onjungService.createOnjung(donations, receipts, shares); + + // 생성 시간 기준으로 정렬 + List sortedOnjungByCreatedAt = onjungService.sortOnjungByCreatedAt(onjung); + + return ReadUserOnjungOverviewResponseDto.of(sortedOnjungByCreatedAt); + } +} diff --git a/src/main/java/com/daon/onjung/onjung/application/usecase/ReadUserOnjungOverviewUseCase.java b/src/main/java/com/daon/onjung/onjung/application/usecase/ReadUserOnjungOverviewUseCase.java new file mode 100644 index 0000000..162fec6 --- /dev/null +++ b/src/main/java/com/daon/onjung/onjung/application/usecase/ReadUserOnjungOverviewUseCase.java @@ -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); +} diff --git a/src/main/java/com/daon/onjung/onjung/domain/service/OnjungService.java b/src/main/java/com/daon/onjung/onjung/domain/service/OnjungService.java index 82f0dab..e68885b 100644 --- a/src/main/java/com/daon/onjung/onjung/domain/service/OnjungService.java +++ b/src/main/java/com/daon/onjung/onjung/domain/service/OnjungService.java @@ -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 @@ -87,4 +87,25 @@ public Integer calculateTotalOnjungAmount(Onjung onjung) { }) .reduce(0, Integer::sum); } + + // 온정 객체를 받아서 생성일 기준으로 정렬 + public List sortOnjungByCreatedAt(Onjung onjung) { + List 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()); + } }