Changes between Version 1 and Version 2 of appdevelopment


Ignore:
Timestamp:
03/04/26 20:32:58 (2 weeks ago)
Author:
231020
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • appdevelopment

    v1 v2  
    22
    33== Трансакции ==
     4
     5=== executeTrade (точка за влез) ===
     6'''Опис:''' Методот `executeTrade` во `PortfolioService` е централната точка за влез која ја повикува `TradeRequestController` при одобрување на барање за тргување. Врши рутирање кон `buyStock` или `sellStock` врз основа на типот на трансакцијата.
     7
     8Целата операција е `@Transactional` - доколку кој било чекор не успее, се откажува целосно.
     9
     10{{{
     11@Transactional
     12public void executeTrade(TradeRequest tr) {
     13    BigDecimal price = BigDecimal.valueOf(tr.getPricePerUnit());
     14    Portfolio portfolio = tr.getPortfolio();
     15
     16    if ("BUY".equalsIgnoreCase(tr.getType())) {
     17        buyStock(portfolio.getId(), tr.getStockSymbol(), tr.getQuantity(), price);
     18    } else if ("SELL".equalsIgnoreCase(tr.getType())) {
     19        sellStock(portfolio.getId(), tr.getStockSymbol(), tr.getQuantity(), price);
     20    } else {
     21        throw new RuntimeException("Unknown trade type: " + tr.getType());
     22    }
     23}
     24}}}
     25
    426
    527=== Купување на акција (buyStock) ===
    628'''Опис:''' Методот `buyStock` во `PortfolioService` извршува повеќе зависни операции:
     29 * Проверка дека портфолиото има доволно баланс за купување
    730 * Намалување на балансот на портфолиото за вкупната вредност на купените акции
    831 * Ажурирање на постоечко холдинг (или креирање на нов) со новата количина и пресметана weighted average цена
    932 * Зачувување на трансакцискиот запис
    1033
    11 Доколку кој било чекор не успее (на пр. акцијата не постои, портфолиото не е пронајдено), целата операција се откажува и балансот останува непроменет.
     34Доколку кој било чекор не успее (на пр. акцијата не постои, портфолиото не е пронајдено, недоволен баланс), целата операција се откажува и балансот останува непроменет.
     35
    1236{{{
    1337@Transactional
    14     public void buyStock(Long portfolioId, String stockSymbol, int quantity, BigDecimal pricePerUnit) {
    15         Portfolio portfolio = portfolioRepository.findById(portfolioId)
    16                 .orElseThrow(() -> new RuntimeException("Portfolio not found"));
    17 
    18 
    19         //multiply for how much stocks are bught
    20         BigDecimal totalCost = pricePerUnit.multiply(BigDecimal.valueOf(quantity));
    21 
    22 //        if (portfolio.getBalance().compareTo(totalCost) < 0) {
    23 //            throw new RuntimeException("not enough balance to buy stock");
    24 //        }
    25         //TODO - > BRING BACK , JUST FOR TESTING !!
    26 
    27         portfolio.setBalance(portfolio.getBalance().subtract(totalCost));
    28 
    29         Stock stock1 = stockRepository.findBySymbol(stockSymbol)
    30                 .orElseThrow(() -> new RuntimeException("Stock not found"));
    31 
    32         PortfolioHolding holding = holdingRepository
    33                 .findByPortfolioIdAndStock_Symbol(portfolioId, stockSymbol)
    34                 .orElse(PortfolioHolding.builder()
    35                         .portfolio(portfolio)
    36                         .stock(stock1)
    37                         .quantity(0)
    38                         .avgPrice(BigDecimal.ZERO)
    39                         .build());
    40 
    41         // avg price bought
    42         // alkaloid 2 x 22.000 + alkaloid 3x 28.000 average od ova
    43         BigDecimal currentTotalValue = holding.getAvgPrice().multiply(BigDecimal.valueOf(holding.getQuantity()));
    44         BigDecimal newTotalValue = currentTotalValue.add(totalCost);
    45         int newQuantity = holding.getQuantity() + quantity;
    46         BigDecimal newAvgPrice = newTotalValue.divide(BigDecimal.valueOf(newQuantity), BigDecimal.ROUND_HALF_UP);
    47 
    48         holding.setQuantity(newQuantity);
    49         holding.setAvgPrice(newAvgPrice);
    50 
    51         holdingRepository.save(holding);
    52         portfolioRepository.save(portfolio);
    53 
    54 
    55         //sava a transaction
    56         Transaction transaction = new Transaction();
    57         transaction.setUser(portfolio.getUser());
    58 
    59         Stock stock = stockRepository.findBySymbol(stockSymbol)
    60                 .orElseThrow(() -> new RuntimeException("stock not found: " + stockSymbol));
    61         transaction.setStock(stock);
    62 /*        transaction.setStock(stockRepository.findBySymbol(stockSymbol)
    63                 .orElseThrow(() -> new RuntimeException("Stock not found")));*/
    64         transaction.setType("BUY");
    65         transaction.setQuantity(quantity);
    66         transaction.setPrice(pricePerUnit.doubleValue());
    67         transaction.setTimestamp(LocalDateTime.now());
    68 
    69         transactionRepository.save(transaction);
    70     }
     38public void buyStock(Long portfolioId, String stockSymbol, int quantity, BigDecimal pricePerUnit) {
     39    Portfolio portfolio = portfolioRepository.findById(portfolioId)
     40            .orElseThrow(() -> new RuntimeException("Portfolio not found"));
     41
     42    BigDecimal totalCost = pricePerUnit.multiply(BigDecimal.valueOf(quantity));
     43
     44    if (portfolio.getBalance().compareTo(totalCost) < 0) {
     45        throw new RuntimeException("Insufficient balance to buy stock");
     46    }
     47
     48    portfolio.setBalance(portfolio.getBalance().subtract(totalCost));
     49
     50    Stock stock = stockRepository.findBySymbol(stockSymbol)
     51            .orElseThrow(() -> new RuntimeException("Stock not found: " + stockSymbol));
     52
     53    PortfolioHolding holding = holdingRepository
     54            .findByPortfolioIdAndStock_Symbol(portfolioId, stockSymbol)
     55            .orElse(PortfolioHolding.builder()
     56                    .portfolio(portfolio)
     57                    .stock(stock)
     58                    .quantity(0)
     59                    .avgPrice(BigDecimal.ZERO)
     60                    .build());
     61
     62    // Recalculate weighted average price
     63    BigDecimal currentTotalValue = holding.getAvgPrice().multiply(BigDecimal.valueOf(holding.getQuantity()));
     64    BigDecimal newTotalValue = currentTotalValue.add(totalCost);
     65    int newQuantity = holding.getQuantity() + quantity;
     66    BigDecimal newAvgPrice = newTotalValue.divide(BigDecimal.valueOf(newQuantity), RoundingMode.HALF_UP);
     67
     68    holding.setQuantity(newQuantity);
     69    holding.setAvgPrice(newAvgPrice);
     70
     71    holdingRepository.save(holding);
     72    portfolioRepository.save(portfolio);
     73
     74    // Save transaction
     75    Transaction transaction = new Transaction();
     76    transaction.setUser(portfolio.getUser());
     77    transaction.setStock(stock);
     78    transaction.setType("BUY");
     79    transaction.setQuantity(quantity);
     80    transaction.setPrice(pricePerUnit.doubleValue());
     81    transaction.setTimestamp(LocalDateTime.now());
     82    transactionRepository.save(transaction);
     83}
    7184}}}
    7285
     
    7487=== Продавање на акција (sellStock) ===
    7588
    76 '''Опис:''' Методот `sellStock`:
     89'''Опис:''' Методот `sellStock` во `PortfolioService`:
    7790 * Проверка дека корисникот поседува доволно акции
    7891 * Намалување на количината во холдингот (или бришење ако достигне 0)
     
    8295{{{
    8396@Transactional
    84     public void sellStock(Long portfolioId, String stockSymbol, int quantity, BigDecimal pricePerUnit) {
    85         Portfolio portfolio = portfolioRepository.findById(portfolioId)
    86                 .orElseThrow(() -> new RuntimeException("portfolio not found"));
    87 
    88         PortfolioHolding holding = holdingRepository
    89                 .findByPortfolioIdAndStock_Symbol(portfolioId, stockSymbol)
    90                 .orElseThrow(() -> new RuntimeException("stock not found in portfolio"));
    91 
    92 
    93         // checks
    94         if (holding.getQuantity() < quantity) {
    95             throw new RuntimeException("not enough shares to sell");
    96         }
    97 
    98         if (pricePerUnit == null) {
    99             // fallback: get latest price from stock history or live API
    100             Stock stock = stockRepository.findBySymbol(stockSymbol)
    101                     .orElseThrow(() -> new RuntimeException("stock not found: " + stockSymbol));
    102             pricePerUnit = BigDecimal.valueOf(stock.getCurrentPrice());
    103         }
    104 
    105         // gain from the sale made
    106         BigDecimal totalGain = pricePerUnit.multiply(BigDecimal.valueOf(quantity));
    107 
    108 
    109         holding.setQuantity(holding.getQuantity() - quantity);
    110 
    111         // if holding is zero ==== remove it from database
    112         if (holding.getQuantity() == 0) {
    113             holdingRepository.delete(holding);
    114         } else {
    115             holdingRepository.save(holding);
    116         }
    117 
    118         // update
    119         portfolio.setBalance(portfolio.getBalance().add(totalGain));
    120         portfolioRepository.save(portfolio);
    121 
    122 
     97public void sellStock(Long portfolioId, String stockSymbol, int quantity, BigDecimal pricePerUnit) {
     98    Portfolio portfolio = portfolioRepository.findById(portfolioId)
     99            .orElseThrow(() -> new RuntimeException("Portfolio not found"));
     100
     101    PortfolioHolding holding = holdingRepository
     102            .findByPortfolioIdAndStock_Symbol(portfolioId, stockSymbol)
     103            .orElseThrow(() -> new RuntimeException("Stock not found in portfolio"));
     104
     105    if (holding.getQuantity() < quantity) {
     106        throw new RuntimeException("Not enough shares to sell");
     107    }
     108
     109    if (pricePerUnit == null) {
     110        // fallback: get latest price from stock
    123111        Stock stock = stockRepository.findBySymbol(stockSymbol)
    124                 .orElseThrow(() -> new RuntimeException("stock not found: " + stockSymbol));
    125 
    126         Transaction transaction = new Transaction();
    127         transaction.setUser(portfolio.getUser());
    128         transaction.setStock(stock);
    129         transaction.setType("SELL");
    130         transaction.setQuantity(quantity);
    131         transaction.setPrice(pricePerUnit.doubleValue());
    132         transaction.setTimestamp(LocalDateTime.now());
    133 
    134         transactionRepository.save(transaction);
    135 
    136         System.out.println("saved sell");
    137     }
    138 }}}
     112                .orElseThrow(() -> new RuntimeException("Stock not found: " + stockSymbol));
     113        pricePerUnit = BigDecimal.valueOf(stock.getCurrentPrice());
     114    }
     115
     116    // gain from the sale made
     117    BigDecimal totalGain = pricePerUnit.multiply(BigDecimal.valueOf(quantity));
     118
     119    holding.setQuantity(holding.getQuantity() - quantity);
     120
     121    // if holding reaches zero - remove it from database
     122    if (holding.getQuantity() == 0) {
     123        holdingRepository.delete(holding);
     124    } else {
     125        holdingRepository.save(holding);
     126    }
     127
     128    portfolio.setBalance(portfolio.getBalance().add(totalGain));
     129    portfolioRepository.save(portfolio);
     130
     131    // Save transaction
     132    Stock stock = stockRepository.findBySymbol(stockSymbol)
     133            .orElseThrow(() -> new RuntimeException("Stock not found: " + stockSymbol));
     134
     135    Transaction transaction = new Transaction();
     136    transaction.setUser(portfolio.getUser());
     137    transaction.setStock(stock);
     138    transaction.setType("SELL");
     139    transaction.setQuantity(quantity);
     140    transaction.setPrice(pricePerUnit.doubleValue());
     141    transaction.setTimestamp(LocalDateTime.now());
     142    transactionRepository.save(transaction);
     143}
     144}}}
     145
    139146
    140147=== Поврзување на Google OAuth акаунт (confirmLink) ===