Skip to content

Commit

Permalink
[fix] qa 버그 문제 해결 (#248)
Browse files Browse the repository at this point in the history
* #244 fix: 포트폴리오 종목 조회시 연배당률에 대한 소수점 2자리 실수로 변경

* #244 docs: 포트폴리오 종목 조회 API Rest Docs 추가

* #244 fix: 대시보드 오버뷰 문제 해결

- 0 나누기 문제 해결

* #244 docs: 대시보드 오버뷰 Rest Docs 추가

* #244 fix: 계정 삭제 문제 해결

* #244 docs: 계정 삭제 Rest Docs 추가

* #244 test: 테스트명 수정

* #244 feat: watchStock 추가시 현재가 갱신 이벤트 추가

* #244 feat: kisService mokcing 추가
  • Loading branch information
yonghwankim-dev authored Feb 28, 2024
1 parent 98fd590 commit f855f07
Show file tree
Hide file tree
Showing 29 changed files with 1,001 additions and 83 deletions.
11 changes: 11 additions & 0 deletions src/docs/asciidoc/api/dashboard.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[[dashboard_overview-search]]
=== 오버뷰 조회

==== HTTP Request

include::{snippets}/dashboard_overview-search/http-request.adoc[]

==== HTTP Response

include::{snippets}/dashboard_overview-search/http-response.adoc[]
include::{snippets}/dashboard_overview-search/response-fields.adoc[]
12 changes: 12 additions & 0 deletions src/docs/asciidoc/api/holding.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[[holding-search]]
=== 포트폴리오 종목 조회

==== HTTP Request

include::{snippets}/holding-search/http-request.adoc[]
include::{snippets}/holding-search/path-parameters.adoc[]

==== HTTP Response

include::{snippets}/portfolio-search/http-response.adoc[]
include::{snippets}/portfolio-search/response-fields.adoc[]
12 changes: 12 additions & 0 deletions src/docs/asciidoc/api/member.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[[member-delete]]
=== 사용자 계정 삭제

==== HTTP Request

include::{snippets}/member-delete/http-request.adoc[]
include::{snippets}/member-delete/request-fields.adoc[]

==== HTTP Response

include::{snippets}/member-delete/http-response.adoc[]
include::{snippets}/member-delete/response-fields.adoc[]
8 changes: 8 additions & 0 deletions src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ endif::[]

include::api/portfolio.adoc[]

== 포트폴리오 종목 API

include::api/holding.adoc[]

== FCM 토큰 API

include::api/fcm.adoc[]
Expand All @@ -25,3 +29,7 @@ include::api/stock_target_price.adoc[]
== 알림 API

include::api/notification.adoc[]

== 대시보드 API

include::api/dashboard.adoc[]
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,8 @@ public interface FcmRepository extends JpaRepository<FcmToken, Long> {
@Modifying
@Query("delete from FcmToken f where f.token = :token")
int deleteAllByToken(@Param("token") String token);

@Modifying
@Query("delete from FcmToken f where f.member.id = :memberId")
int deleteAllByMemberId(@Param("memberId") Long memberId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

Expand All @@ -16,4 +17,8 @@ List<Notification> findAllByMemberIdAndIds(
@Param("memberId") Long memberId,
@Param("notificationIds") List<Long> notificationIds
);

@Modifying
@Query("delete from Notification n where n.member.id = :memberId")
int deleteAllByMemberId(@Param("memberId") Long memberId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@
import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface NotificationPreferenceRepository extends JpaRepository<NotificationPreference, Long> {

@Query("select n from NotificationPreference n where n.member.id = :memberId")
Optional<NotificationPreference> findByMemberId(@Param("memberId") Long memberId);

@Modifying
@Query("delete from NotificationPreference n where n.member.id = :memberId")
int deleteAllByMemberId(@Param("memberId") Long memberId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public boolean hasAuthorization(Long memberId) {
// 포트폴리오 총 손익 = 모든 종목 총 손익의 합계
// 종목 총 손익 = (종목 현재가 - 종목 평균 매입가) * 개수
// 종목 평균 매입가 = 종목의 총 투자 금액 / 총 주식 개수
public long calculateTotalGain() {
public Long calculateTotalGain() {
return portfolioHoldings.stream()
.mapToLong(PortfolioHolding::calculateTotalGain)
.sum();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,8 @@ Optional<StockTargetPrice> findByTickerSymbolAndMemberIdUsingFetchJoin(
@Modifying
@Query("delete from StockTargetPrice s where s.stock.tickerSymbol = :tickerSymbol and s.member.id = :memberId")
int deleteByTickerSymbolAndMemberId(@Param("tickerSymbol") String tickerSymbol, @Param("memberId") Long memberId);

@Modifying
@Query("delete from StockTargetPrice s where s.member.id = :memberId")
int deleteAllByMemberId(@Param("memberId") Long memberId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import codesquad.fineants.domain.stock_target_price.StockTargetPrice;

public interface TargetPriceNotificationRepository extends JpaRepository<TargetPriceNotification, Long> {

@Query("select t from TargetPriceNotification t where t.stockTargetPrice.id = :stockTargetPriceId")
Expand All @@ -23,4 +25,8 @@ Optional<TargetPriceNotification> findByTickerSymbolAndTargetPriceAndMemberId(
@Query("delete from TargetPriceNotification t where t.id in (:targetPriceNotificationIds)")
int deleteAllByTargetPriceNotificationIds(
@Param("targetPriceNotificationIds") List<Long> targetPriceNotificationIds);

@Modifying
@Query("delete from TargetPriceNotification t where t.stockTargetPrice in(:stockTargetPrices)")
int deleteAllByStockTargetPrices(@Param("stockTargetPrices") List<StockTargetPrice> stockTargetPrices);
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class DashboardRestController {
private final DashboardService dashboardService;

@GetMapping("/overview")
public ApiResponse<OverviewResponse> readDashboard(@AuthPrincipalMember AuthMember authMember) {
public ApiResponse<OverviewResponse> readOverview(@AuthPrincipalMember AuthMember authMember) {
return ApiResponse.success(DashboardSuccessCode.OK_OVERVIEW, dashboardService.getOverview(authMember));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,22 @@
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Builder
@ToString
public class OverviewResponse {
private String username;
private Long totalValuation;
private Long totalInvestment;
private Long totalGain;
private Integer totalGainRate;
private Long totalAnnualDividend;
private Integer totalAnnualDividendYield;
private Double totalAnnualDividendYield;

public static OverviewResponse of(String username, Long totalValuation, Long totalInvestment, Long totalGain,
Integer totalGainRate, Long totalAnnualDividend, Integer totalAnnualDividendYield) {
Expand All @@ -26,7 +30,7 @@ public static OverviewResponse of(String username, Long totalValuation, Long tot
.totalGain(totalGain)
.totalGainRate(totalGainRate)
.totalAnnualDividend(totalAnnualDividend)
.totalAnnualDividendYield(totalAnnualDividendYield)
.totalAnnualDividendYield(totalAnnualDividendYield.doubleValue())
.build();
}

Expand All @@ -38,7 +42,7 @@ public static OverviewResponse empty(String username) {
.totalGain(0L)
.totalGainRate(0)
.totalAnnualDividend(0L)
.totalAnnualDividendYield(0)
.totalAnnualDividendYield(0.00)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ public class DashboardService {
@Transactional(readOnly = true)
public OverviewResponse getOverview(AuthMember authMember) {
List<Portfolio> portfolios = portfolioRepository.findAllByMemberId(authMember.getMemberId());
Member member = memberRepository.findById(authMember.getMemberId()).orElseThrow(() -> new BadRequestException(
MemberErrorCode.NOT_FOUND_MEMBER));
Member member = memberRepository.findById(authMember.getMemberId())
.orElseThrow(() -> new BadRequestException(MemberErrorCode.NOT_FOUND_MEMBER));
Long totalValuation = 0L;// 평가 금액 + 현금?
Long totalCurrentValuation = 0L; // 평가 금액
Long totalInvestment = 0L; //총 주식에 투자된 돈
long totalGain = 0L; // 총 수익
Long totalGain = 0L; // 총 수익
Long totalAnnualDividend = 0L; // 총 연간 배당금
if (portfolios.isEmpty()) {
return OverviewResponse.empty(member.getNickname());
Expand All @@ -54,8 +54,10 @@ public OverviewResponse getOverview(AuthMember authMember) {
totalGain += portfolio.calculateTotalGain();
totalAnnualDividend += portfolio.calculateAnnualDividend();
}
Integer totalAnnualDividendYield = (int)((totalAnnualDividend / totalCurrentValuation) * 100);
Integer totalGainRate = (int)(((double)totalGain / (double)totalInvestment) * 100);
Integer totalAnnualDividendYield = totalCurrentValuation != 0 ?
(int)((totalAnnualDividend / totalCurrentValuation) * 100) : 0;
Integer totalGainRate = totalInvestment != 0 ?
(int)((totalGain.doubleValue() / totalInvestment.doubleValue()) * 100) : 0;

return OverviewResponse.of(member.getNickname(), totalValuation, totalInvestment,
totalGain, totalGainRate, totalAnnualDividend, totalAnnualDividendYield);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import codesquad.fineants.domain.fcm_token.FcmRepository;
import codesquad.fineants.domain.jwt.Jwt;
import codesquad.fineants.domain.jwt.JwtProvider;
import codesquad.fineants.domain.member.Member;
import codesquad.fineants.domain.member.MemberRepository;
import codesquad.fineants.domain.notification.NotificationRepository;
import codesquad.fineants.domain.notification_preference.NotificationPreference;
import codesquad.fineants.domain.notification_preference.NotificationPreferenceRepository;
import codesquad.fineants.domain.oauth.client.AuthorizationCodeRandomGenerator;
Expand All @@ -35,6 +37,9 @@
import codesquad.fineants.domain.portfolio_holding.PortfolioHolding;
import codesquad.fineants.domain.portfolio_holding.PortfolioHoldingRepository;
import codesquad.fineants.domain.purchase_history.PurchaseHistoryRepository;
import codesquad.fineants.domain.stock_target_price.StockTargetPrice;
import codesquad.fineants.domain.stock_target_price.StockTargetPriceRepository;
import codesquad.fineants.domain.target_price_notification.TargetPriceNotificationRepository;
import codesquad.fineants.domain.watch_list.WatchList;
import codesquad.fineants.domain.watch_list.WatchListRepository;
import codesquad.fineants.domain.watch_stock.WatchStock;
Expand Down Expand Up @@ -98,6 +103,10 @@ public class MemberService {
private final VerifyCodeGenerator verifyCodeGenerator;
private final MemberNotificationPreferenceService preferenceService;
private final NotificationPreferenceRepository notificationPreferenceRepository;
private final NotificationRepository notificationRepository;
private final FcmRepository fcmRepository;
private final StockTargetPriceRepository stockTargetPriceRepository;
private final TargetPriceNotificationRepository targetPriceNotificationRepository;

public OauthMemberLoginResponse login(OauthMemberLoginRequest request) {
log.info("로그인 서비스 요청 : loginRequest={}", request);
Expand Down Expand Up @@ -392,6 +401,12 @@ public void deleteMember(AuthMember authMember) {
watchList.forEach(w -> watchStocks.addAll(watchStockRepository.findByWatchList(w)));
watchStockRepository.deleteAll(watchStocks);
watchListRepository.deleteAll(watchList);
fcmRepository.deleteAllByMemberId(member.getId());
List<StockTargetPrice> stockTargetPrices = stockTargetPriceRepository.findAllByMemberId(member.getId());
targetPriceNotificationRepository.deleteAllByStockTargetPrices(stockTargetPrices);
stockTargetPriceRepository.deleteAllByMemberId(member.getId());
notificationRepository.deleteAllByMemberId(member.getId());
notificationPreferenceRepository.deleteAllByMemberId(member.getId());
memberRepository.delete(member);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@
import codesquad.fineants.domain.portfolio.Portfolio;
import codesquad.fineants.domain.portfolio_gain_history.PortfolioGainHistory;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Builder
public class PortfolioDetailResponse {
@Getter
private Long id;
private String securitiesFirm;
private String name;
Expand All @@ -26,41 +31,12 @@ public class PortfolioDetailResponse {
private Integer dailyGainRate;
private Long balance;
private Long annualDividend;
private Integer annualDividendYield;
private Integer annualInvestmentDividendYield;
private Double annualDividendYield;
private Double annualInvestmentDividendYield;
private Long provisionalLossBalance;
private Boolean targetGainNotification;
private Boolean maxLossNotification;

@Builder(access = AccessLevel.PRIVATE)
private PortfolioDetailResponse(Long id, String securitiesFirm, String name, Long budget, Long targetGain,
Integer targetReturnRate, Long maximumLoss, Integer maximumLossRate, Long currentValuation, Long investedAmount,
Long totalGain, Integer totalGainRate, Long dailyGain, Integer dailyGainRate, Long balance,
Long annualDividend, Integer annualDividendYield, Integer annualInvestmentDividendYield,
Long provisionalLossBalance, Boolean targetGainNotification, Boolean maxLossNotification) {
this.id = id;
this.securitiesFirm = securitiesFirm;
this.name = name;
this.budget = budget;
this.targetGain = targetGain;
this.targetReturnRate = targetReturnRate;
this.maximumLoss = maximumLoss;
this.maximumLossRate = maximumLossRate;
this.currentValuation = currentValuation;
this.investedAmount = investedAmount;
this.totalGain = totalGain;
this.totalGainRate = totalGainRate;
this.dailyGain = dailyGain;
this.dailyGainRate = dailyGainRate;
this.balance = balance;
this.annualDividend = annualDividend;
this.annualDividendYield = annualDividendYield;
this.annualInvestmentDividendYield = annualInvestmentDividendYield;
this.provisionalLossBalance = provisionalLossBalance;
this.targetGainNotification = targetGainNotification;
this.maxLossNotification = maxLossNotification;
}

public static PortfolioDetailResponse from(Portfolio portfolio, PortfolioGainHistory history) {
return PortfolioDetailResponse.builder()
.id(portfolio.getId())
Expand All @@ -79,8 +55,8 @@ public static PortfolioDetailResponse from(Portfolio portfolio, PortfolioGainHis
.dailyGainRate(portfolio.calculateDailyGainRate(history))
.balance(portfolio.calculateBalance())
.annualDividend(portfolio.calculateAnnualDividend())
.annualDividendYield(portfolio.calculateAnnualDividendYield())
.annualInvestmentDividendYield(portfolio.calculateAnnualInvestmentDividendYield())
.annualDividendYield(portfolio.calculateAnnualDividendYield().doubleValue())
.annualInvestmentDividendYield(portfolio.calculateAnnualInvestmentDividendYield().doubleValue())
.provisionalLossBalance(0L)
.targetGainNotification(portfolio.getTargetGainIsActive())
.maxLossNotification(portfolio.getMaximumIsActive())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,17 @@

import codesquad.fineants.domain.portfolio_holding.PortfolioHolding;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Builder
@ToString
public class PortfolioHoldingDetailItem {
private Long portfolioHoldingId;
private Long currentValuation;
Expand All @@ -15,24 +24,7 @@ public class PortfolioHoldingDetailItem {
private Long totalGain;
private Integer totalReturnRate;
private Long annualDividend;
private Integer annualDividendYield;

@Builder(access = AccessLevel.PRIVATE)
private PortfolioHoldingDetailItem(Long portfolioHoldingId, Long currentValuation, Long currentPrice,
Double averageCostPerShare, Long numShares, Long dailyChange, Integer dailyChangeRate, Long totalGain,
Integer totalReturnRate, Long annualDividend, Integer annualDividendYield) {
this.portfolioHoldingId = portfolioHoldingId;
this.currentValuation = currentValuation;
this.currentPrice = currentPrice;
this.averageCostPerShare = averageCostPerShare;
this.numShares = numShares;
this.dailyChange = dailyChange;
this.dailyChangeRate = dailyChangeRate;
this.totalGain = totalGain;
this.totalReturnRate = totalReturnRate;
this.annualDividend = annualDividend;
this.annualDividendYield = annualDividendYield;
}
private Double annualDividendYield;

public static PortfolioHoldingDetailItem from(PortfolioHolding portfolioHolding, long lastDayClosingPrice) {
return PortfolioHoldingDetailItem.builder()
Expand All @@ -46,7 +38,7 @@ public static PortfolioHoldingDetailItem from(PortfolioHolding portfolioHolding,
.totalGain(portfolioHolding.calculateTotalGain())
.totalReturnRate(portfolioHolding.calculateTotalReturnRate())
.annualDividend(portfolioHolding.calculateAnnualExpectedDividend())
.annualDividendYield(portfolioHolding.calculateAnnualExpectedDividendYield())
.annualDividendYield(portfolioHolding.calculateAnnualExpectedDividendYield().doubleValue())
.build();
}
}
Loading

0 comments on commit f855f07

Please sign in to comment.