Skip to content

Commit

Permalink
Merge pull request #78 from bocabitlabs/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
renefs authored Jun 5, 2023
2 parents b9924df + 2dcd762 commit c58887b
Show file tree
Hide file tree
Showing 20 changed files with 2,228 additions and 107 deletions.
3 changes: 0 additions & 3 deletions .tool-versions

This file was deleted.

8 changes: 8 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ All notable changes to this project will be documented in this file.
### Removed
### Security

## [0.100.7] - 2023-06-04
### Fix
- Backend: Fix the company year stats update (PUT)
- Backend: Fix the portfolio year (all) stats update (PUT)
- UI: Fix refresh stats UI on portfolio refresh stats modal
### Improved
- UI: display toast on company/portfolio stats update

## [0.100.6] - 2023-04-23
### Improved
- UI: Sidebar width decreased a bit.
Expand Down
22 changes: 14 additions & 8 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,25 @@ ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV PYTHONPATH "${PYTHONPATH}:/usr/src"
ENV LISTEN_PORT 34800

ENV UWSGI_INI /usr/src/uwsgi.ini
COPY ./uwsgi.ini /usr/src/uwsgi.ini
# The following environment variables are used by Poetry to install dependencies
ENV POETRY_VERSION 1.5.0
ENV POETRY_HOME /opt/poetry
ENV POETRY_VIRTUALENVS_IN_PROJECT true
ENV POETRY_CACHE_DIR ${WORKING_DIR}/.cache
ENV VIRTUAL_ENVIRONMENT_PATH ${WORKING_DIR}/.venv

COPY ./nginx-app.conf /etc/nginx/conf.d/custom.conf

COPY ./uwsgi.ini /usr/src/uwsgi.ini
COPY ./nginx-app.conf /etc/nginx/conf.d/custom.conf
COPY ./prestart.sh /app/prestart.sh

# install dependencies
RUN pip install --upgrade pip
COPY ./requirements.txt /usr/src
RUN pip install --no-cache-dir --upgrade -r /usr/src/requirements.txt
# Install Poetry and dependencies
COPY pyproject.toml ./
COPY poetry.lock ./

# Using Poetry to install dependencies without requiring the project main files to be present
RUN pip install poetry==${POETRY_VERSION} && poetry install --only main --no-root --no-directory

WORKDIR /usr/src/client
COPY ./client/package.json /usr/src/client/package.json
Expand All @@ -54,7 +60,7 @@ COPY ./backend/config/config.sample.py /usr/src/app/config/config.py

EXPOSE 34800

RUN python manage.py collectstatic
RUN poetry run python manage.py collectstatic
RUN sed -i -e "s/REPLACE_SECRET_KEY/$(od -x /dev/urandom | head -1 | awk '{OFS="-"; print $2$3,$4,$5,$6,$7$8$9}')/g" /usr/src/app/config/config.py


9 changes: 8 additions & 1 deletion backend/stats/utils/company_stats_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def __init__(
self.update_api_price = update_api_price
self.company_utils = CompanyUtils(self.company.id, use_portfolio_currency=self.use_portfolio_currency)

self.stock_prices_utils = StockPricesUtils(self.company, self.year)
self.stock_prices_utils = StockPricesUtils(self.company, self.year, update_api_price=update_api_price)
self.exchange_rates_utils = ExchangeRateService()

def get_portfolio_value(self, stock_price, shares_count):
Expand Down Expand Up @@ -176,3 +176,10 @@ def get_stats_for_year(self):
instance = self.update_or_create_stats_for_year(temp_year, results_dict)

return instance

def update_stats_for_year(self):
temp_year = self.year_for_all if self.year == "all" else self.year
results_dict = self.calculate_stats_for_year(temp_year)
instance = self.update_or_create_stats_for_year(temp_year, results_dict)
logger.debug(instance.company)
return instance
14 changes: 7 additions & 7 deletions backend/stats/utils/portfolio_stats_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def _get_total_invested_in_rights(self):
continue

query = company.rights_transactions
if self.year == "all":
if self.year == "all" or self.year == self.year_for_all:
query = query.all()
else:
query = query.filter(
Expand All @@ -60,7 +60,7 @@ def _get_total_invested_in_shares(self):
continue

query = company.shares_transactions
if self.year == "all":
if self.year == "all" or self.year == self.year_for_all:
query = query.filter(type=TransactionType.BUY)
else:
query = query.filter(transaction_date__year=self.year, type=TransactionType.BUY)
Expand All @@ -80,7 +80,7 @@ def _get_accumulated_invested_in_shares_until_year(self):
continue

query = company.shares_transactions
if self.year == "all":
if self.year == "all" or self.year == self.year_for_all:
query = query.filter(type=TransactionType.BUY)
else:
query = query.filter(transaction_date__year__lte=self.year, type=TransactionType.BUY)
Expand All @@ -100,7 +100,7 @@ def _get_accumulated_invested_in_rights_until_year(self):
continue

query = company.rights_transactions
if self.year == "all":
if self.year == "all" or self.year == self.year_for_all:
query = query.filter(type=TransactionType.BUY)
else:
query = query.filter(transaction_date__year__lte=self.year, type=TransactionType.BUY)
Expand All @@ -117,7 +117,7 @@ def get_dividends(self):
total = 0
for company in self.portfolio.companies.all():
query = company.dividends_transactions
if self.year == "all":
if self.year == "all" or self.year == self.year_for_all:
query = query.all()
else:
query = query.filter(transaction_date__year=self.year)
Expand All @@ -137,7 +137,7 @@ def get_accumulated_dividends_until_year(self):
continue

query = company.dividends_transactions
if self.year == "all":
if self.year == "all" or self.year == self.year_for_all:
query = query.all()
else:
query = query.filter(transaction_date__year__lte=self.year)
Expand Down Expand Up @@ -171,7 +171,7 @@ def get_portfolio_value(self):

first_year = CompanyUtils(company.id).get_company_first_year()
logger.debug(f"{company.name} First year: {first_year} vs {self.year}")
if self.year != "all":
if self.year != "all" or self.year != self.year_for_all:
if not first_year or first_year > int(self.year):
total += 0
continue
Expand Down
13 changes: 10 additions & 3 deletions backend/stats/views/company_stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from stats.models.company_stats import CompanyStatsForYear
from stats.serializers.company_stats import CompanyStatsForYearSerializer
from stats.utils.company_stats_utils import CompanyStatsUtils

Expand All @@ -20,6 +21,14 @@ def get_object(self, company_id, year, update_api_price=False):
except Company.DoesNotExist:
return None

def update_object(self, portfolio_id, year, update_api_price=False):
logger.debug("Updating company stats")
if year == "all":
year = 9999
company_stats = CompanyStatsUtils(portfolio_id, year=year, update_api_price=update_api_price)
stats = company_stats.update_stats_for_year()
return stats

# 3. Retrieve
@swagger_auto_schema(tags=["company_stats"])
def get(self, request, company_id, year, *args, **kwargs):
Expand All @@ -42,9 +51,7 @@ def put(self, request, company_id, year, *args, **kwargs):
"""
update_api_price = request.data.get("update_api_price", False)

if year == "all":
year = 9999
instance = self.get_object(company_id, year, update_api_price=update_api_price)
instance = self.update_object(company_id, year, update_api_price=update_api_price)

if not instance:
return Response(
Expand Down
2 changes: 2 additions & 0 deletions backend/stats/views/portfolio_stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ def get_stats_grouped(self, portfolio_id, year, update_api_price, group_by):
def update_object(self, portfolio_id, year, update_api_price=False):
logger.debug("Updating portfolio stats")
try:
if year == "all":
year = 9999
portfolio_stats = PortfolioStatsUtils(portfolio_id, year=year, update_api_price=update_api_price)
stats = portfolio_stats.update_stats_for_year()
serializer = PortfolioStatsForYearSerializer(stats)
Expand Down
9 changes: 6 additions & 3 deletions backend/stock_prices/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@


class StockPricesUtils:
def __init__(self, company: Company, year: int):
def __init__(self, company: Company, year: int, update_api_price=False):
self.company = company
self.year = year
self.update_api_price = update_api_price

def get_stock_price_for_tickers(self, tickers: Optional[str]) -> Optional[dict]:
"""Get the stock price for a list of tickers.
Expand All @@ -30,7 +31,7 @@ def get_stock_price_for_tickers(self, tickers: Optional[str]) -> Optional[dict]:
return stock_price
return None

def get_year_last_stock_price(self):
def get_year_last_stock_price(self) -> Optional[dict]:
api_service = YFinanceApiClient()
api = StockPricesApi(api_service)

Expand All @@ -44,7 +45,9 @@ def get_year_last_stock_price(self):
first_year = company_utils.get_company_first_year()
if not first_year or first_year > int(self.year):
return None
stock_price = api.get_last_data_from_year(self.company.ticker, self.year)
stock_price = api.get_last_data_from_year(
self.company.ticker, self.year, update_api_price=self.update_api_price
)
if not stock_price:
stock_price = self.get_stock_price_for_tickers(self.company.alt_tickers)
return stock_price
2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "client",
"version": "0.100.6",
"version": "0.100.7",
"homepage": "/",
"private": true,
"dependencies": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { ReactElement, useState } from "react";
import { useTranslation } from "react-i18next";
import { toast } from "react-toastify";
import { SyncOutlined } from "@ant-design/icons";
import { Button, Checkbox, Form, Modal, Typography } from "antd";
import axios from "axios";
Expand All @@ -22,7 +23,6 @@ export default function StatsRefreshModal({
const [updateStatsSwitch, setUpdateStatsSwitch] = useState(false);
const [errorsList, setErrorsList] = useState<string[]>([]);

// const { mutateAsync: updateStockPrice } = useUpdateCompanyStockPrice();
const { mutateAsync: updateStats } = useUpdateYearStats();

const showModal = () => {
Expand All @@ -45,6 +45,7 @@ export default function StatsRefreshModal({
year: selectedYear,
updateApiPrice: updateStockPriceSwitch,
});
toast.success<string>(t("Stats for company updated"));
return { result: true, message: "" };
} catch (error: any) {
let message = error;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { ReactElement, useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { toast } from "react-toastify";
import { SyncOutlined } from "@ant-design/icons";
import { Button, Checkbox, Form, Modal, Typography } from "antd";
import { CheckboxValueType } from "antd/lib/checkbox/Group";
Expand Down Expand Up @@ -79,7 +80,7 @@ export default function StatsRefreshModal({

const getStatsForced = useCallback(
async (companyId: number, companyName: string) => {
setUpdateMessage(`${t("Updating stats for company")} #${companyId}`);
setUpdateMessage(`${t("Updating stats for company")}: ${companyName}`);
try {
await updateCompanyStats({
companyId: +companyId,
Expand Down Expand Up @@ -115,6 +116,13 @@ export default function StatsRefreshModal({
year: selectedYear,
updateApiPrice: updateStockPriceSwitch,
});
toast.success<string>(
t(
`${t("Stats updated for portfolio")} #${id} ${t("and year")} ${t(
selectedYear,
)}`,
),
);
setUpdateMessage(
`${t("Stats updated for portfolio")} #${id} ${t("and year")} ${t(
selectedYear,
Expand Down Expand Up @@ -186,9 +194,7 @@ export default function StatsRefreshModal({
icon={<SyncOutlined />}
/>
<Modal
title={`${t("Refresh stats and stock prices for")} &quot;${t(
selectedYear,
)}&quot;`}
title={`${t("Refresh stats and stock prices for")} ${t(selectedYear)}`}
open={visible}
confirmLoading={confirmLoading}
onCancel={handleCancel}
Expand All @@ -211,7 +217,7 @@ export default function StatsRefreshModal({
</Form.Item>
<Form.Item name="updateStats" valuePropName="checked">
<Checkbox onChange={onStatsChange}>
{t("Update the stats for the year")} &quot;{t(selectedYear)}&quot;
{t("Update the stats for the year")} {t(selectedYear)}
</Checkbox>
</Form.Item>
<Typography.Title level={5}>
Expand All @@ -231,7 +237,11 @@ export default function StatsRefreshModal({
style={{ marginBottom: 10 }}
valuePropName="checked"
>
<Checkbox.Group onChange={onChange} value={checkedList}>
<Checkbox.Group
onChange={onChange}
value={checkedList}
style={{ display: "block" }}
>
{checkboxes.map((company: CheckboxesProps) => (
<div key={company.id}>
<Checkbox value={company.id}>
Expand Down
2 changes: 1 addition & 1 deletion client/src/version.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export const PACKAGE_VERSION = "0.100.6";
export const PACKAGE_VERSION = "0.100.7";
export default { PACKAGE_VERSION };
43 changes: 0 additions & 43 deletions docker-compose.yml

This file was deleted.

Loading

0 comments on commit c58887b

Please sign in to comment.