diff --git a/README.md b/README.md index 4927f0dc..a3bd9ecc 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@

📈 미국 배당 투자자를 위한 배당금 진단 서비스, Payout

--
1분 내로 간단하게, 배당 포트폴리오 셀프 체크할 수 있어요
--
포트폴리오 밸런스 진단, 섹터별 인사이트를 제공해요
--
월간 / 연간 배당금 체크, 종목별 주요 배당 정보를 알 수 있어요
+1분 내로 간단하게, 배당 포트폴리오 셀프 체크할 수 있어요 ✅️ +포트폴리오 밸런스 진단, 섹터별 인사이트를 제공해요 💡 +월간 / 연간 배당금 체크, 종목별 주요 배당 정보를 알 수 있어요 💰 ## 🔗 Link diff --git a/api-server/src/main/java/nexters/payout/apiserver/dividend/application/DividendQueryService.java b/api-server/src/main/java/nexters/payout/apiserver/dividend/application/DividendQueryService.java index a9f6db6f..8e7c037e 100644 --- a/api-server/src/main/java/nexters/payout/apiserver/dividend/application/DividendQueryService.java +++ b/api-server/src/main/java/nexters/payout/apiserver/dividend/application/DividendQueryService.java @@ -4,15 +4,15 @@ import lombok.extern.slf4j.Slf4j; import nexters.payout.apiserver.dividend.application.dto.request.DividendRequest; import nexters.payout.apiserver.dividend.application.dto.request.TickerShare; -import nexters.payout.apiserver.dividend.application.dto.response.SingleMonthlyDividendResponse; import nexters.payout.apiserver.dividend.application.dto.response.MonthlyDividendResponse; +import nexters.payout.apiserver.dividend.application.dto.response.SingleMonthlyDividendResponse; import nexters.payout.apiserver.dividend.application.dto.response.SingleYearlyDividendResponse; import nexters.payout.apiserver.dividend.application.dto.response.YearlyDividendResponse; -import nexters.payout.core.exception.error.NotFoundException; import nexters.payout.core.time.InstantProvider; import nexters.payout.domain.dividend.domain.Dividend; import nexters.payout.domain.dividend.domain.repository.DividendRepository; import nexters.payout.domain.stock.domain.Stock; +import nexters.payout.domain.stock.domain.exception.TickerNotFoundException; import nexters.payout.domain.stock.domain.repository.StockRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -70,7 +70,7 @@ private List getLastYearDividendsByTicker(final String ticker) { private Stock getStock(final String ticker) { return stockRepository.findByTicker(ticker) - .orElseThrow(() -> new NotFoundException(String.format("not found ticker [%s]", ticker))); + .orElseThrow(() -> new TickerNotFoundException(ticker)); } private List getDividendsOfLastYearAndMonth( @@ -80,7 +80,7 @@ private List getDividendsOfLastYearAndMonth( .stream() .flatMap(tickerShare -> stockRepository.findByTicker(tickerShare.ticker()) .map(stock -> getMonthlyDividendResponse(month, tickerShare, stock)) - .orElseThrow(() -> new NotFoundException(String.format("not found ticker [%s]", tickerShare.ticker())))) + .orElseThrow(() -> new TickerNotFoundException(tickerShare.ticker()))) .toList(); } diff --git a/api-server/src/main/java/nexters/payout/apiserver/stock/application/StockQueryService.java b/api-server/src/main/java/nexters/payout/apiserver/stock/application/StockQueryService.java index d2e4ac8a..7134972d 100644 --- a/api-server/src/main/java/nexters/payout/apiserver/stock/application/StockQueryService.java +++ b/api-server/src/main/java/nexters/payout/apiserver/stock/application/StockQueryService.java @@ -4,17 +4,17 @@ import nexters.payout.apiserver.stock.application.dto.request.SectorRatioRequest; import nexters.payout.apiserver.stock.application.dto.request.TickerShare; import nexters.payout.apiserver.stock.application.dto.response.*; -import nexters.payout.core.exception.error.NotFoundException; import nexters.payout.core.time.InstantProvider; import nexters.payout.domain.dividend.domain.Dividend; import nexters.payout.domain.dividend.domain.repository.DividendRepository; import nexters.payout.domain.stock.domain.Sector; import nexters.payout.domain.stock.domain.Stock; +import nexters.payout.domain.stock.domain.exception.TickerNotFoundException; import nexters.payout.domain.stock.domain.repository.StockRepository; -import nexters.payout.domain.stock.domain.service.StockDividendAnalysisService; import nexters.payout.domain.stock.domain.service.SectorAnalysisService; import nexters.payout.domain.stock.domain.service.SectorAnalysisService.SectorInfo; import nexters.payout.domain.stock.domain.service.SectorAnalysisService.StockShare; +import nexters.payout.domain.stock.domain.service.StockDividendAnalysisService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -76,7 +76,7 @@ private List combinedDividends(final List lastYearDividends, private Stock getStock(final String ticker) { return stockRepository.findByTicker(ticker) - .orElseThrow(() -> new NotFoundException(String.format("not found ticker [%s]", ticker))); + .orElseThrow(() -> new TickerNotFoundException(ticker)); } private List getLastYearDividends(final Stock stock) { diff --git a/api-server/src/main/resources/application-prod.yml b/api-server/src/main/resources/application-prod.yml index 933816a8..38da2410 100644 --- a/api-server/src/main/resources/application-prod.yml +++ b/api-server/src/main/resources/application-prod.yml @@ -13,6 +13,7 @@ spring: hibernate: format_sql: true show-sql: false + open-in-view: false flyway: enabled: true diff --git a/core/src/main/java/nexters/payout/core/time/InstantProvider.java b/core/src/main/java/nexters/payout/core/time/InstantProvider.java index fcbfb307..cc775f1f 100644 --- a/core/src/main/java/nexters/payout/core/time/InstantProvider.java +++ b/core/src/main/java/nexters/payout/core/time/InstantProvider.java @@ -34,10 +34,6 @@ public static Integer getThisYear() { return getNow().getYear(); } - public static Integer getNextYear() { - return getNow().plusYears(1).getYear(); - } - public static Integer getLastYear() { return getNow().minusYears(1).getYear(); } diff --git a/domain/src/main/generated/nexters/payout/domain/QBaseEntity.java b/domain/src/main/generated/nexters/payout/domain/QBaseEntity.java index 420f56d4..2abee65d 100644 --- a/domain/src/main/generated/nexters/payout/domain/QBaseEntity.java +++ b/domain/src/main/generated/nexters/payout/domain/QBaseEntity.java @@ -21,6 +21,8 @@ public class QBaseEntity extends EntityPathBase { public final DateTimePath createdAt = createDateTime("createdAt", java.time.Instant.class); + public final ComparablePath id = createComparable("id", java.util.UUID.class); + public final DateTimePath lastModifiedAt = createDateTime("lastModifiedAt", java.time.Instant.class); public QBaseEntity(String variable) { diff --git a/domain/src/main/generated/nexters/payout/domain/dividend/domain/QDividend.java b/domain/src/main/generated/nexters/payout/domain/dividend/domain/QDividend.java index 2d5f4b21..02e8370d 100644 --- a/domain/src/main/generated/nexters/payout/domain/dividend/domain/QDividend.java +++ b/domain/src/main/generated/nexters/payout/domain/dividend/domain/QDividend.java @@ -30,7 +30,8 @@ public class QDividend extends EntityPathBase { public final DateTimePath exDividendDate = createDateTime("exDividendDate", java.time.Instant.class); - public final ComparablePath id = createComparable("id", java.util.UUID.class); + //inherited + public final ComparablePath id = _super.id; //inherited public final DateTimePath lastModifiedAt = _super.lastModifiedAt; diff --git a/domain/src/main/java/nexters/payout/domain/BaseEntity.java b/domain/src/main/java/nexters/payout/domain/BaseEntity.java index 22ca1dc5..02bef398 100644 --- a/domain/src/main/java/nexters/payout/domain/BaseEntity.java +++ b/domain/src/main/java/nexters/payout/domain/BaseEntity.java @@ -2,6 +2,7 @@ import jakarta.persistence.*; import lombok.Getter; +import nexters.payout.domain.dividend.domain.Dividend; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; @@ -14,6 +15,9 @@ @EntityListeners(AuditingEntityListener.class) @Getter public class BaseEntity { + @Id + @GeneratedValue(strategy = GenerationType.UUID) + private UUID id; @Column(name = "created_at", updatable = false) @CreatedDate @@ -23,4 +27,17 @@ public class BaseEntity { @LastModifiedDate private Instant lastModifiedAt; + public BaseEntity(UUID id) { + this.id = id; + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof BaseEntity && this.id.equals(((BaseEntity) obj).getId()); + } } diff --git a/domain/src/main/java/nexters/payout/domain/dividend/application/dto/UpdateDividendRequest.java b/domain/src/main/java/nexters/payout/domain/dividend/application/dto/UpdateDividendRequest.java deleted file mode 100644 index 36235eb1..00000000 --- a/domain/src/main/java/nexters/payout/domain/dividend/application/dto/UpdateDividendRequest.java +++ /dev/null @@ -1,10 +0,0 @@ -package nexters.payout.domain.dividend.application.dto; - -import java.time.Instant; - -public record UpdateDividendRequest( - Double dividend, - Instant paymentDate, - Instant declarationDate -) { -} diff --git a/domain/src/main/java/nexters/payout/domain/dividend/domain/Dividend.java b/domain/src/main/java/nexters/payout/domain/dividend/domain/Dividend.java index 15561333..ef1fed60 100644 --- a/domain/src/main/java/nexters/payout/domain/dividend/domain/Dividend.java +++ b/domain/src/main/java/nexters/payout/domain/dividend/domain/Dividend.java @@ -1,24 +1,17 @@ package nexters.payout.domain.dividend.domain; -import jakarta.persistence.*; -import lombok.AccessLevel; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; import lombok.Getter; -import lombok.NoArgsConstructor; import nexters.payout.domain.BaseEntity; import java.time.Instant; -import java.util.Objects; import java.util.UUID; @Entity @Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) public class Dividend extends BaseEntity { - @Id - @GeneratedValue(strategy = GenerationType.UUID) - private UUID id; - @Column(nullable = false, updatable = false) private UUID stockId; @@ -31,9 +24,13 @@ public class Dividend extends BaseEntity { private Instant declarationDate; + public Dividend() { + super(null); + } + public Dividend(final UUID id, final UUID stockId, final Double dividend, final Instant exDividendDate, final Instant paymentDate, final Instant declarationDate) { - this.id = id; + super(id); this.stockId = stockId; this.dividend = dividend; this.exDividendDate = exDividendDate; @@ -58,16 +55,6 @@ public static Dividend create( return new Dividend(stockId, dividend, exDividendDate, paymentDate, declarationDate); } - @Override - public boolean equals(Object obj) { - return obj instanceof Dividend && this.id.equals(((Dividend) obj).getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } - @Override public String toString() { return "Dividend{" + diff --git a/domain/src/main/java/nexters/payout/domain/dividend/domain/repository/DividendRepository.java b/domain/src/main/java/nexters/payout/domain/dividend/domain/repository/DividendRepository.java index 3412fb1a..e929edea 100644 --- a/domain/src/main/java/nexters/payout/domain/dividend/domain/repository/DividendRepository.java +++ b/domain/src/main/java/nexters/payout/domain/dividend/domain/repository/DividendRepository.java @@ -8,8 +8,5 @@ import java.util.UUID; public interface DividendRepository extends JpaRepository, DividendRepositoryCustom { - List findAllByStockId(UUID stockId); - - List findAllByStockIdIn(List stockIds); } diff --git a/domain/src/main/java/nexters/payout/domain/stock/application/dto/UpdateStockRequest.java b/domain/src/main/java/nexters/payout/domain/stock/application/dto/UpdateStockRequest.java deleted file mode 100644 index 4868f9c7..00000000 --- a/domain/src/main/java/nexters/payout/domain/stock/application/dto/UpdateStockRequest.java +++ /dev/null @@ -1,7 +0,0 @@ -package nexters.payout.domain.stock.application.dto; - -public record UpdateStockRequest( - Double price, - Integer volume -) { -} diff --git a/domain/src/main/java/nexters/payout/domain/stock/domain/Stock.java b/domain/src/main/java/nexters/payout/domain/stock/domain/Stock.java index 634de7df..2c0667de 100644 --- a/domain/src/main/java/nexters/payout/domain/stock/domain/Stock.java +++ b/domain/src/main/java/nexters/payout/domain/stock/domain/Stock.java @@ -11,13 +11,8 @@ @Entity @Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) public class Stock extends BaseEntity { - @Id - @GeneratedValue(strategy = GenerationType.UUID) - private UUID id; - @Column(unique = true, nullable = false, length = 50) private String ticker; @@ -37,11 +32,13 @@ public class Stock extends BaseEntity { private String logoUrl; + public Stock() {super(null);} + public Stock(final UUID id, final String ticker, final String name, final Sector sector, final String exchange, final String industry, final Double price, final Integer volume, final String logoUrl) { + super(id); validateTicker(ticker); - this.id = id; this.ticker = ticker; this.name = name; this.sector = sector; @@ -73,16 +70,6 @@ public void update( this.sector = sector; } - @Override - public boolean equals(Object obj) { - return obj instanceof Stock && this.id.equals(((Stock) obj).getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } - @Override public String toString() { return "Stock{" + diff --git a/domain/src/main/java/nexters/payout/domain/stock/domain/exception/TickerNotFoundException.java b/domain/src/main/java/nexters/payout/domain/stock/domain/exception/TickerNotFoundException.java new file mode 100644 index 00000000..52274290 --- /dev/null +++ b/domain/src/main/java/nexters/payout/domain/stock/domain/exception/TickerNotFoundException.java @@ -0,0 +1,10 @@ +package nexters.payout.domain.stock.domain.exception; + +import nexters.payout.core.exception.error.NotFoundException; + +public class TickerNotFoundException extends NotFoundException { + + public TickerNotFoundException(String ticker) { + super(String.format("not found ticker [%s]", ticker)); + } +} diff --git a/domain/src/main/java/nexters/payout/domain/stock/domain/service/SectorAnalysisService.java b/domain/src/main/java/nexters/payout/domain/stock/domain/service/SectorAnalysisService.java index 2470f356..b423f2f8 100644 --- a/domain/src/main/java/nexters/payout/domain/stock/domain/service/SectorAnalysisService.java +++ b/domain/src/main/java/nexters/payout/domain/stock/domain/service/SectorAnalysisService.java @@ -1,7 +1,6 @@ package nexters.payout.domain.stock.domain.service; import nexters.payout.domain.common.config.DomainService; -import nexters.payout.domain.dividend.domain.Dividend; import nexters.payout.domain.stock.domain.Sector; import nexters.payout.domain.stock.domain.Stock; @@ -15,6 +14,9 @@ @DomainService public class SectorAnalysisService { + /** + * 포트폴리오의 섹터 별 비중을 계산합니다. + */ public Map calculateSectorRatios(final List stockShares) { Map sectorCountMap = getSectorCountMap(stockShares); Map> sectorStockMap = getSectorStockMap(stockShares); @@ -73,13 +75,11 @@ public record SectorInfo( Double ratio, List stockShares ) { - } public record StockShare( Stock stock, Integer share ) { - } } diff --git a/domain/src/main/java/nexters/payout/domain/stock/infra/StockRepositoryCustom.java b/domain/src/main/java/nexters/payout/domain/stock/infra/StockRepositoryCustom.java index ee12f309..846a7008 100644 --- a/domain/src/main/java/nexters/payout/domain/stock/infra/StockRepositoryCustom.java +++ b/domain/src/main/java/nexters/payout/domain/stock/infra/StockRepositoryCustom.java @@ -8,8 +8,9 @@ import java.util.List; public interface StockRepositoryCustom { - List findStocksByTickerOrNameWithPriority(String search, Integer pageNumber, Integer pageSize); + List findUpcomingDividendStock(Sector sector, int pageNumber, int pageSize); + List findBiggestDividendYieldStock(int lastYear, Sector sector, int pageNumber, int pageSize); } diff --git a/domain/src/main/java/nexters/payout/domain/stock/infra/StockRepositoryImpl.java b/domain/src/main/java/nexters/payout/domain/stock/infra/StockRepositoryImpl.java index 1d02e905..9ab05217 100644 --- a/domain/src/main/java/nexters/payout/domain/stock/infra/StockRepositoryImpl.java +++ b/domain/src/main/java/nexters/payout/domain/stock/infra/StockRepositoryImpl.java @@ -25,7 +25,7 @@ @RequiredArgsConstructor public class StockRepositoryImpl implements StockRepositoryCustom { - private final Double MAX_DIVIDEND_YIELD = 0.9; + private static final Double MAX_DIVIDEND_YIELD = 0.9; private final JPAQueryFactory queryFactory; @Override