| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- 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.exception.UnauthorizedException;
- import com.danielbohry.stocks.repository.portfolio.PortfolioEntity;
- import com.danielbohry.stocks.repository.portfolio.PortfolioEntity.PortfolioStock;
- import com.danielbohry.stocks.repository.portfolio.PortfolioRepository;
- import com.danielbohry.stocks.service.ExchangeService.ExchangeRateResponse;
- import lombok.AllArgsConstructor;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.commons.lang3.ObjectUtils;
- import org.springframework.stereotype.Service;
- import java.math.BigDecimal;
- import java.math.RoundingMode;
- import java.util.List;
- import java.util.Map;
- import java.util.Objects;
- import java.util.UUID;
- import static com.danielbohry.stocks.domain.Portfolio.convert;
- 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;
- private final PortfolioEncryptService encryptService;
- public List<String> getAllIds() {
- return repository.findAllPortfolioIds();
- }
- public List<Portfolio> getByUser(String userId, String currency) {
- return repository.findAllByUser(userId).stream()
- .map(entity -> get(entity.getId(), currency))
- .toList();
- }
- public Portfolio get(String id, String currency) {
- PortfolioEntity entity = repository.findById(id)
- .orElseThrow(() -> new NotFoundException("No portfolio found with id: " + id));
- String encrypted = entity.getEncryptedStocks();
- if (encrypted != null) {
- entity.setStocks(encryptService.decryptStocks(encrypted));
- }
- Portfolio portfolio = convert(entity);
- 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();
- PortfolioEntity toSave = PortfolioEntity.builder()
- .id(id)
- .stocks(emptyList())
- .user(UserContextHolder.get().getId())
- .createdAt(now())
- .updatedAt(now())
- .build();
- return convert(repository.save(toSave));
- }
- public Portfolio update(String id, List<Stock> stocks) {
- log.info("Updating portfolio [{}]", id);
- PortfolioEntity toUpdate = repository.findById(id).orElseThrow(() -> new NotFoundException("Failed to update portfolio with id: " + id));
- if (!Objects.equals(toUpdate.getUser(), UserContextHolder.get().getId()) || UserContextHolder.isAdmin()) {
- throw new UnauthorizedException("You do not have permission to update portfolio");
- }
- validate(stocks);
- toUpdate.setUpdatedAt(now());
- toUpdate.setEncryptedStocks(encryptService.encryptStocks(stocks.stream()
- .map(stock -> new PortfolioStock(stock.getCode(), stock.getQuantity()))
- .toList()));
- toUpdate.setStocks(null);
- PortfolioEntity updated = repository.save(toUpdate);
- List<PortfolioStock> decryptStocks = encryptService.decryptStocks(updated.getEncryptedStocks());
- updated.setStocks(decryptStocks);
- return convert(updated);
- }
- public void delete(String id) {
- log.info("Deleting portfolio [{}]", id);
- repository.deleteById(id);
- }
- public void cleanup() {
- repository.findAll().forEach(portfolio -> {
- if ((ObjectUtils.isEmpty(portfolio.getEncryptedStocks()))) {
- 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");
- }
- }
- }
|