| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- package com.danielbohry.stocks.service;
- import com.danielbohry.stocks.context.UserContextHolder;
- import com.danielbohry.stocks.domain.Portfolio;
- import com.danielbohry.stocks.domain.Quote;
- import com.danielbohry.stocks.domain.Stock;
- import com.danielbohry.stocks.exception.BadRequestException;
- import com.danielbohry.stocks.exception.NotFoundException;
- import com.danielbohry.stocks.repository.PortfolioRepository;
- import com.danielbohry.stocks.service.ExchangeService.ExchangeRateResponse;
- import lombok.AllArgsConstructor;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.cache.annotation.Cacheable;
- import org.springframework.stereotype.Service;
- import java.math.BigDecimal;
- import java.math.RoundingMode;
- import java.util.List;
- import java.util.Map;
- import java.util.Optional;
- import java.util.UUID;
- import static java.time.LocalDateTime.now;
- import static java.util.Collections.emptyList;
- @Slf4j
- @Service
- @AllArgsConstructor
- public class PortfolioService {
- private final PortfolioRepository repository;
- private final StockService stockService;
- private final ExchangeService exchangeService;
- public List<Portfolio> getAll() {
- return repository.findAll();
- }
- public List<String> getAllIds() {
- return repository.findAllPortfolioIds();
- }
- @Cacheable(value = "portfolio", key = "#username + '_' + #currency")
- public List<Portfolio> getByUser(String username, String currency) {
- List<Portfolio> portfolios = repository.findAllByUsername(username);
- return portfolios.stream()
- .map(portfolio -> get(portfolio.getId(), currency))
- .toList();
- }
- public Portfolio get(String id, String currency) {
- Portfolio portfolio = repository.findById(id)
- .orElseThrow(() -> new NotFoundException("No portfolio found with id: " + id));
- ExchangeRateResponse exchangeRate = exchangeService.getCurrentRate(currency);
- Map<String, BigDecimal> rates = exchangeRate.getConversionRates();
- BigDecimal targetRate = rates.getOrDefault(currency, BigDecimal.ONE);
- log.info("Getting portfolio [{}] and converting to [{}]", id, currency);
- List<Stock> updatedStocks = portfolio.getStocks().stream()
- .peek(stock -> {
- Quote quote = stockService.getStockQuote(stock.getCode());
- stock.setName(quote.getName());
- BigDecimal quoteRate = rates.getOrDefault(quote.getCurrency(), BigDecimal.ONE);
- BigDecimal convertedPrice = quote.getPrice()
- .divide(quoteRate, 2, RoundingMode.HALF_UP)
- .multiply(targetRate);
- stock.setPrice(convertedPrice);
- stock.setTotal(convertedPrice.multiply(new BigDecimal(stock.getQuantity())));
- }).toList();
- portfolio.setStocks(updatedStocks);
- return portfolio;
- }
- public Portfolio create() {
- String id = UUID.randomUUID().toString();
- Portfolio toSave = Portfolio.builder()
- .id(id)
- .stocks(emptyList())
- .username(UserContextHolder.get().getUsername())
- .createdAt(now())
- .updatedAt(now())
- .build();
- return repository.save(toSave);
- }
- public Portfolio update(String id, List<Stock> stocks) {
- log.info("Updating portfolio [{}]", id);
- Optional<Portfolio> portfolio = repository.findById(id);
- if (portfolio.isEmpty()) {
- throw new NotFoundException("Failed to update portfolio with id: " + id);
- }
- validate(stocks);
- Portfolio toUpdate = portfolio.get();
- toUpdate.setUpdatedAt(now());
- toUpdate.setStocks(stocks);
- return repository.save(toUpdate);
- }
- public void delete(String id) {
- log.info("Deleting portfolio [{}]", id);
- repository.deleteById(id);
- }
- public void cleanup() {
- repository.findAllByEmptyStocks().forEach(portfolio -> {
- if (portfolio.getStocks().isEmpty()) {
- log.info("Removing empty portfolio [{}]", portfolio.getId());
- repository.deleteById(portfolio.getId());
- }
- });
- }
- private void validate(List<Stock> stocks) {
- boolean anyInvalid = stocks.stream()
- .anyMatch(stock -> !stockService.isValid(stock.getCode()));
- if (anyInvalid) {
- throw new BadRequestException("Invalid stock found");
- }
- }
- }
|