update data based on selected company (#122)

Added UI elements to select a company and update shown data depending on chosen company



---------

Co-authored-by: Philipp Horstenkamp <philipp@horstenkamp.de>
This commit is contained in:
KM-R 2023-09-19 23:45:10 +02:00 committed by GitHub
parent 80f077ee7a
commit 487b2f42d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 900 additions and 732 deletions

View File

@ -47,7 +47,7 @@ jobs:
- uses: actions/checkout@v3
- uses: chartboost/ruff-action@v1
with:
version: 0.0.289
version: 0.0.290
python-requirements:
name: Check Python Requirements

3
.gitignore vendored
View File

@ -3,6 +3,9 @@
*secrets.json
*secrets_prod.json
# Settings
.vscode/
# Snyk
.dccache

View File

@ -26,7 +26,7 @@ repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.0.289
rev: v0.0.290
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]

View File

@ -1,3 +0,0 @@
{
"files.eol": "\n"
}

465
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@ requires = ["poetry-core"]
target-version = ["py311"]
[tool.coverage.report]
exclude_also = ["if __name__ == .__main__.:"]
exclude_also = ["if __name__ == .__main__.:", "if not isinstance(engine, Engine):"]
[tool.coverage.run]
branch = true
@ -81,7 +81,7 @@ mypy = "^1.5.1"
pandas-stubs = "^2.0.3.230814"
pip-audit = "^2.6.1"
pip-licenses = "^4.3.2"
ruff = "^0.0.289"
ruff = "^0.0.290"
types-cachetools = "^5.3.0.6"
types-pyOpenSSL = "*"
types-requests = "^2.31.0.2"

View File

@ -0,0 +1,69 @@
.company-header {
float: left;
background-color: var(--paynes-gray);
border: 1px solid;
width: 100%;
}
.company-header .company-header-title {
color: white;
text-align: left;
margin: 0;
vertical-align: middle;
padding: 20px;
}
.stats-wrapper {
float: left;
width: 100%;
background-color: white;
margin-top: 20px;
margin-right: 2%;
}
.stats-wrapper .widget-large {
background-color: var(--ash-gray);
border: 1px solid;
border-radius: 10px;
width: 45%;
min-width: 600px;
display: inline-block;
vertical-align: middle;
margin-left: 2%;
overflow: hidden;
}
.stats-wrapper .widget-large .widget-title {
color: var(--raisin-black);
text-align: center;
margin: 0;
padding-bottom: 10px;
padding-top: 10px;
}
.stats-wrapper .widget-small {
background-color: var(--ash-gray);
border: 1px solid;
border-radius: 10px;
width: 15%;
min-width: 200px;
height: 150px;
display: inline-block;
vertical-align: middle;
margin-top: 10px;
margin-bottom: 10px;
margin-left: 2%;
}
.stats-wrapper .widget-small .widget-title {
color: var(--raisin-black);
text-align: center;
margin: 0;
padding-bottom: 10px;
padding-top: 10px;
}
.stats-wrapper .widget-small .widget-content {
color: var(--raisin-black);
text-align: center;
}

View File

@ -0,0 +1,58 @@
:root {
--light: #edefef;
--lavender-blush: #f3e8ee;
--ash-gray: #bacdb0;
--cambridge-blue: #729b79;
--paynes-gray: #475b63;
--raisin-black: #2e2c2f;
}
.header-wrapper {
float:left;
background-color: var(--raisin-black);
border: 1px solid;
width: 100%;
overflow: visible;
min-height: 77px;
}
.header-wrapper .header-title {
float: left;
text-align: left;
margin: 0;
padding-left: 15px;
padding-top: 20px;
padding-bottom: 20px;
vertical-align: middle;
}
.header-wrapper .header-title .bi-house-door-fill {
color: white;
font-size: x-large;
display: inline-block;
vertical-align: middle;
padding-right: 15px;
}
.header-wrapper .header-title .header-title-text {
color: white;
text-align: left;
margin: 0;
display: inline-block;
vertical-align: middle;
}
.header-wrapper .header-search {
float: right;
width: 400px;
margin: 0;
padding-right: 10px;
padding-bottom: 20px;
padding-top: 20px;
vertical-align: middle;
overflow: visible !important;
}
.header-wrapper .header-search .header-search-dropdown {
overflow: visible;
}

View File

@ -0,0 +1,23 @@
.tabs {
float: left;
margin-top: 20px;
border: 1px solid;
width: 100%;
}
.tabs .tab-style {
border-bottom: 1px solid #d6d6d6 !important;
padding: 8px !important;
background-color: white !important;
color: var(--paynes-gray) !important;
font-weight: bold !important;
}
.tabs .selected-tab-style {
border-bottom: 1px solid #d6d6d6 !important;
border-top: 1px solid #d6d6d6 !important;
padding: 8px !important;
color: white !important;
background-color: var(--paynes-gray) !important;
font-weight: bold !important;
}

View File

@ -1,390 +1,78 @@
"""Dash."""
import dash_bootstrap_components as dbc
import pandas as pd
import plotly.graph_objs as go
from dash import Dash, Input, Output, callback, dash_table, dcc, html
from dash.exceptions import PreventUpdate
from sqlalchemy.engine import Engine
from dash import Dash, Input, Output, callback, html
from aki_prj23_transparenzregister.config.config_providers import JsonFileConfigProvider
from aki_prj23_transparenzregister.utils.sql import connector, entities
from aki_prj23_transparenzregister.ui.ui_elements import (
create_company_header,
create_company_stats,
create_header,
create_tabs,
get_company_data,
get_finance_data,
)
from aki_prj23_transparenzregister.utils.sql import connector
if __name__ == "__main__":
session = connector.get_session(JsonFileConfigProvider("./secrets.json"))
query_finance = session.query(
entities.AnnualFinanceStatement, entities.Company.name, entities.Company.id
).join(entities.Company)
query_company = session.query(entities.Company, entities.DistrictCourt.name).join(
entities.DistrictCourt
)
engine = session.bind
if not isinstance(engine, Engine):
raise TypeError
finance_df: pd.DataFrame = pd.read_sql(str(query_finance), engine)
company_df: pd.DataFrame = pd.read_sql(str(query_company), engine)
select_company_df = company_df[["company_id", "company_name"]]
select_company_dropdown = select_company_df.to_dict("records")
options = [
{"label": i["company_name"], "value": i["company_id"]}
for i in select_company_dropdown
]
colors = {
"light": "#edefef",
"lavender-blush": "#f3e8ee",
"ash-gray": "#bacdb0",
"cambridge-blue": "#729b79",
"paynes-gray": "#475b63",
"raisin-black": "#2e2c2f",
}
def financials_figure(
finance_df: pd.DataFrame, company: str, metric: str
) -> go.Figure:
"""Creates plotly line chart for a specific company and a metric."""
finance_df = finance_df.loc[finance_df["company_name"] == company]
# create figure
fig_line = go.Figure()
# add trace for company 1
fig_line.add_trace(
go.Scatter(
x=finance_df["annual_finance_statement_date"],
y=finance_df[metric],
name=company,
line_color=colors["raisin-black"],
marker_color=colors["raisin-black"],
)
)
# set title and labels
fig_line.update_layout(
title=metric,
xaxis_title="Jahr",
yaxis_title="in Mio.€",
plot_bgcolor=colors["light"],
)
return fig_line
tab_style = {
"borderBottom": "1px solid #d6d6d6",
"padding": "6px",
"backgroundColor": "white",
"color": colors["paynes-gray"],
"fontWeight": "bold",
}
tab_selected_style = {
"borderTop": "1px solid #d6d6d6",
"borderBottom": "1px solid #d6d6d6",
"padding": "6px",
"backgroundColor": colors["paynes-gray"],
"color": "white",
"fontWeight": "bold",
}
# TBD: get data from database instead of mock data
company = 1 # selected company id
selected_company = company_df.loc[company_df["company_id"] == company]
turnover = 123456
stock = "1,23"
company_data = {
"col1": ["Unternehmen", "Straße", "Stadt"],
"col2": [
selected_company["company_name"][0],
selected_company["company_street"][0],
str(
selected_company["company_zip_code"][0]
+ " "
+ selected_company["company_city"][0]
),
],
"col3": ["Branche", "Amtsgericht", "Gründungsjahr"],
"col4": [
selected_company["company_sector"][0],
selected_company["district_court_name"][0],
"xxx",
],
}
df_company_data = pd.DataFrame(data=company_data)
company_df = get_company_data(session)
finance_df = get_finance_data(session)
options = company_df["company_name"].to_dict()
app = Dash(
__name__, external_stylesheets=[dbc.icons.BOOTSTRAP]
) # use dbc for icons
kennzahlen_layout = html.Div(
[
dcc.Graph(
figure=financials_figure(
finance_df, str(company), "annual_finance_statement_ebit"
)
)
]
)
app.title = "Company Finance Data"
app.layout = html.Div(
[
# title header of page
html.Div(
style={
"backgroundColor": colors["raisin-black"],
"border": "1px solid",
},
children=[
html.I(
className="bi bi-house-door-fill",
style={
"fontSize": 24,
"paddingLeft": "10px",
"color": "white",
"display": "inline-block",
"verticalAlign": "middle",
},
),
html.H1(
children="Transparenzregister für Kapitalgesellschaften",
style={
"color": "white",
"textAlign": "left",
"margin": "0",
"paddingLeft": "10px",
"paddingBottom": "20px",
"paddingTop": "20px",
"display": "inline-block",
"verticalAlign": "middle",
},
),
html.Div(
dcc.Dropdown(
id="select_company",
placeholder="Suche nach Unternehmen oder Person",
),
style={
"float": "right",
"width": "30%",
"margin": "0",
"paddingRight": "10px",
"paddingBottom": "20px",
"paddingTop": "20px",
"display": "inline-block",
"verticalAlign": "middle",
},
),
],
),
# header company name
html.Div(
style={"backgroundColor": colors["paynes-gray"], "border": "1px solid"},
children=[
html.H1(
children=selected_company["company_name"][0],
style={
"color": "white",
"fontSize": 30,
"textAlign": "left",
"margin": "0",
"paddingLeft": "20px",
"paddingBottom": "20px",
"paddingTop": "20px",
},
)
],
),
html.Div(style={"height": "20px"}),
html.Div(style={"width": "2%", "display": "inline-block"}),
# table basic company information
html.Div(
style={
"backgroundColor": colors["ash-gray"],
"border": "1px solid",
"border-radius": 10,
"width": "45%",
"height": "150px",
"display": "inline-block",
"vertical-align": "top",
},
children=[
html.H5(
children="Stammdaten",
style={
"color": colors["raisin-black"],
"fontSize": 16,
"textAlign": "center",
"margin": "0",
"paddingBottom": "10px",
"paddingTop": "10px",
},
),
dash_table.DataTable(
df_company_data.to_dict("records"),
[{"name": i, "id": i} for i in df_company_data.columns],
style_table={
"width": "80%",
"overflowX": "auto",
"marginLeft": "auto",
"marginRight": "auto",
"paddingBottom": "20px",
"color": colors["raisin-black"],
},
# hide header of table
css=[
{
"selector": "tr:first-child",
"rule": "display: none",
},
],
style_cell={"textAlign": "center"},
style_cell_conditional=[
{"if": {"column_id": c}, "fontWeight": "bold"}
for c in ["col1", "col3"]
],
),
],
),
html.Div(style={"width": "2%", "display": "inline-block"}),
html.Div(
style={
"backgroundColor": colors["ash-gray"],
"border": "1px solid",
"border-radius": 10,
"width": "15%",
"height": "150px",
"display": "inline-block",
"vertical-align": "top",
},
children=[
html.H5(
children="Stimmung",
style={
"color": colors["raisin-black"],
"fontSize": 16,
"textAlign": "center",
"margin": "0",
"paddingBottom": "10px",
"paddingTop": "10px",
},
),
],
),
html.Div(style={"width": "2%", "display": "inline-block"}),
html.Div(
style={
"backgroundColor": colors["ash-gray"],
"border": "1px solid",
"border-radius": 10,
"width": "15%",
"height": "150px",
"display": "inline-block",
"vertical-align": "top",
},
children=[
html.H5(
children="Aktienkurs",
style={
"color": colors["raisin-black"],
"fontSize": 16,
"textAlign": "center",
"margin": "0",
"paddingBottom": "10px",
"paddingTop": "10px",
},
),
html.H1(
children=stock,
style={
"color": colors["raisin-black"],
"textAlign": "center",
},
),
],
),
html.Div(style={"width": "2%", "display": "inline-block"}),
html.Div(
style={
"backgroundColor": colors["ash-gray"],
"border": "1px solid",
"border-radius": 10,
"width": "15%",
"height": "150px",
"display": "inline-block",
"vertical-align": "top",
},
children=[
html.H5(
children="Umsatz",
style={
"color": colors["raisin-black"],
"fontSize": 16,
"textAlign": "center",
"margin": "0",
"paddingBottom": "10px",
"paddingTop": "10px",
},
),
html.H1(
children=turnover,
style={
"color": colors["raisin-black"],
"textAlign": "center",
},
),
],
),
html.Div(style={"width": "2%", "display": "inline-block"}),
# ]),
html.Div(
style={
"marginTop": "20px",
"border": "1px solid",
},
children=[
dcc.Tabs(
id="tabs",
value="tab-1",
children=[
dcc.Tab(
label="Kennzahlen",
value="tab-1",
style=tab_style,
selected_style=tab_selected_style,
children=[kennzahlen_layout],
),
dcc.Tab(
label="Beteiligte Personen",
value="tab-2",
style=tab_style,
selected_style=tab_selected_style,
),
dcc.Tab(
label="Stimmung",
value="tab-3",
style=tab_style,
selected_style=tab_selected_style,
),
dcc.Tab(
label="Verflechtungen",
value="tab-4",
style=tab_style,
selected_style=tab_selected_style,
),
],
),
html.Div(id="tabs-example-content-1"),
],
),
]
className="page_content",
children=[
create_header(options),
html.Div(id="id-company-header"),
],
)
@callback(
Output("select_company", "options"), Input("select_company", "search_value")
)
def update_options(search_value: str) -> list:
"""Update page based on selected company."""
"""Update dropdown options based on user input.
Args:
search_value: The input string in the dropdown field entered by the user.
Returns:
The available companies matching the input.
"""
if not search_value:
raise PreventUpdate
return [o for o in options if search_value in o["label"]]
return [{"label": o, "value": key} for key, o in options.items()]
return [
{"label": o, "value": key}
for key, o in options.items()
if search_value.upper() in o.upper()
]
@callback(Output("id-company-header", "children"), Input("select_company", "value"))
def update_output(value_chosen: int) -> html:
"""Update page based on chosen company.
Args:
value_chosen: Id of the selected company.
Returns:
The html divs of the company page.
"""
label = options.get(value_chosen)
if not label:
return ""
selected_company = str(label)
selected_company_stats = company_df.loc[value_chosen]
selected_finance_df = finance_df.loc[finance_df["company_id"] == value_chosen]
return (
create_company_header(selected_company),
create_company_stats(selected_company_stats),
create_tabs(selected_finance_df),
)
app.run_server(debug=True)

View File

@ -0,0 +1,331 @@
"""Dash elements."""
import pandas as pd
import plotly.graph_objs as go
from dash import dash_table, dcc, html
from sqlalchemy.engine import Engine
from sqlalchemy.orm import Session
from aki_prj23_transparenzregister.utils.sql import entities
COLORS = {
"light": "#edefef",
"lavender-blush": "#f3e8ee",
"ash-gray": "#bacdb0",
"cambridge-blue": "#729b79",
"paynes-gray": "#475b63",
"raisin-black": "#2e2c2f",
}
def get_company_data(session: Session) -> pd.DataFrame:
"""Creates a session to the database and get's all available company data.
Args:
session: A session connecting to the database.
Returns:
A dataframe containing all available company data including the corresponding district court.
"""
query_company = session.query(entities.Company, entities.DistrictCourt.name).join(
entities.DistrictCourt
)
engine = session.bind
if not isinstance(engine, Engine):
raise TypeError
return pd.read_sql(str(query_company), engine, index_col="company_id")
def get_finance_data(session: Session) -> pd.DataFrame:
"""Creates a session to the database and get's all available company data.
Args:
session: A session connecting to the database.
Returns:
A dataframe containing all financial data of all companies.
"""
query_finance = session.query(
entities.AnnualFinanceStatement, entities.Company.name, entities.Company.id
).join(entities.Company)
engine = session.bind
if not isinstance(engine, Engine):
raise TypeError
return pd.read_sql(str(query_finance), engine)
def create_header(options: dict) -> html:
"""Creates header for dashboard.
Args:
options: A dictionary with company names and ids for the dropdown.
Returns:
The html div to create the page's header including the name of the page and the search for companies.
"""
return html.Div(
className="header-wrapper",
children=[
html.Div(
className="header-title",
children=[
html.I(
className="bi-house-door-fill",
),
html.H1(
className="header-title-text",
children="Transparenzregister für Kapitalgesellschaften",
),
],
),
html.Div(
className="header-search",
children=[
html.Div(
className="header-search-dropdown",
children=[
dcc.Dropdown(
id="select_company",
options=[
{"label": o, "value": key}
for key, o in options.items()
],
placeholder="Suche nach Unternehmen oder Person",
),
],
),
],
),
],
)
def create_company_header(selected_company_name: str) -> html:
"""Create company header based on selected company.
Args:
selected_company_name: The company name that has been chosen in the dropdown.
Returns:
The html div to create the company header.
"""
return html.Div(
className="company-header",
children=[
html.H1(
className="company-header-title",
id="id-company-header-title",
children=selected_company_name,
),
],
)
def create_company_stats(selected_company_data: pd.Series) -> html:
"""Create company stats.
Args:
selected_company_data: A series containing all company information of the selected company.
Returns:
The html div to create the company stats table and the three small widgets.
"""
company_data = {
"col1": ["Unternehmen", "Straße", "Stadt"],
"col2": [
selected_company_data["company_name"],
selected_company_data["company_street"],
str(
selected_company_data["company_zip_code"]
+ " "
+ selected_company_data["company_city"]
),
],
"col3": ["Branche", "Amtsgericht", "Gründungsjahr"],
"col4": [
selected_company_data["company_sector"],
selected_company_data["district_court_name"],
"xxx",
],
}
df_company_data = pd.DataFrame(data=company_data)
return html.Div(
className="stats-wrapper",
children=[
html.Div(
className="widget-large",
children=[
html.H3(
className="widget-title",
children="Stammdaten",
),
dash_table.DataTable(
df_company_data.to_dict("records"),
[{"name": i, "id": i} for i in df_company_data.columns],
style_table={
"width": "90%",
"marginLeft": "auto",
"marginRight": "auto",
"paddingBottom": "20px",
"color": COLORS["raisin-black"],
},
# hide header of table
css=[
{
"selector": "tr:first-child",
"rule": "display: none",
},
],
style_cell={"textAlign": "center"},
style_cell_conditional=[
{"if": {"column_id": c}, "fontWeight": "bold"}
for c in ["col1", "col3"]
],
style_data={
"whiteSpace": "normal",
"height": "auto",
},
),
],
),
html.Div(
className="widget-small",
children=[
html.H3(
className="widget-title",
children="Stimmung",
),
],
),
html.Div(
className="widget-small",
children=[
html.H3(
className="widget-title",
children="Aktienkurs",
),
html.H1(
className="widget-content",
children="123",
),
],
),
html.Div(
className="widget-small",
children=[
html.H3(
className="widget-title",
children="Umsatz",
),
html.H1(
className="widget-content",
children="1234",
),
],
),
],
)
def create_tabs(selected_finance_df: pd.DataFrame) -> html:
"""Create tabs for more company information.
Args:
selected_company_id: Id of the chosen company in the dropdown.
selected_finance_df: A dataframe containing all available finance information of the companies.
Returns:
The html div to create the tabs of the company page.
"""
return html.Div(
className="tabs",
children=[
dcc.Tabs(
id="tabs",
value="tab-1",
children=[
dcc.Tab(
label="Kennzahlen",
value="tab-1",
className="tab-style",
selected_className="selected-tab-style",
children=[kennzahlen_layout(selected_finance_df)],
),
dcc.Tab(
label="Beteiligte Personen",
value="tab-2",
className="tab-style",
selected_className="selected-tab-style",
),
dcc.Tab(
label="Stimmung",
value="tab-3",
className="tab-style",
selected_className="selected-tab-style",
),
dcc.Tab(
label="Verflechtungen",
value="tab-4",
className="tab-style",
selected_className="selected-tab-style",
),
],
),
html.Div(id="tabs-example-content-1"),
],
)
def kennzahlen_layout(selected_finance_df: pd.DataFrame) -> html:
"""Create metrics tab.
Args:
selected_company_id: Id of the chosen company in the dropdown.
selected_finance_df: A dataframe containing all available finance information of the companies.
Returns:
The html div to create the metrics tab of the company page.
"""
return html.Div(
[
dcc.Graph(
figure=financials_figure(
selected_finance_df, "annual_finance_statement_ebit"
)
)
]
)
def financials_figure(selected_finance_df: pd.DataFrame, metric: str) -> go.Figure:
"""Creates plotly line chart for a specific company and a metric.
Args:
selected_finance_df: A dataframe containing all finance information of the selected company.
metric: The metric that should be visualized.
Returns:
A plotly figure showing the available metric data of the company.
"""
# create figure
fig_line = go.Figure()
# add trace for company 1
fig_line.add_trace(
go.Scatter(
x=selected_finance_df["annual_finance_statement_date"],
y=selected_finance_df[metric],
line_color=COLORS["raisin-black"],
marker_color=COLORS["raisin-black"],
)
)
# set title and labels
fig_line.update_layout(
title=metric,
xaxis_title="Jahr",
yaxis_title="in Mio.€",
plot_bgcolor=COLORS["light"],
)
return fig_line

View File

@ -124,7 +124,7 @@ def get_district_court_id(name: str, city: str | None, db: Session) -> int:
@cached(cache=LRUCache(maxsize=2000), key=lambda name, surname, date_of_birth, db: hash((name, surname, date_of_birth))) # type: ignore
def get_person_id(
name: str, surname: str, date_of_birth: date | str, db: Session
name: str, surname: str, date_of_birth: date | str | None, db: Session
) -> int:
"""Identifies the id of and court.

View File

@ -3,6 +3,7 @@ import datetime
import os
from collections.abc import Generator
from inspect import getmembers, isfunction
from typing import Any
import pytest
from sqlalchemy.engine import Engine
@ -49,7 +50,60 @@ def empty_db() -> Generator[Session, None, None]:
@pytest.fixture()
def full_db(empty_db: Session) -> Session:
def finance_statements() -> list[dict[str, Any]]:
"""Creates a list of finance statements."""
return [
{
"id": 1,
"company_id": 1,
"date": datetime.date.fromisoformat("2023-01-01"),
"total_volume": 1000.0,
"ebit": 1000.0,
"ebitda": 1000.0,
"ebit_margin": 1000.0,
"total_balance": 1000.0,
"equity": 1000.0,
"debt": 1000.0,
"return_on_equity": 1000.0,
"capital_turnover_rate": 1000.0,
"current_liabilities": 1000.0,
"dividends": float("NaN"),
"net_income": float("NaN"),
"assets": 1000.0,
"long_term_debt": 1000.0,
"short_term_debt": 1000.0,
"revenue": 1000.0,
"cash_flow": 1000.0,
"current_assets": 1000.0,
},
{
"id": 2,
"company_id": 1,
"date": datetime.date.fromisoformat("2022-01-01"),
"total_volume": 1100.0,
"ebit": 1100.0,
"ebitda": 1100.0,
"ebit_margin": 1100.0,
"total_balance": 1100.0,
"equity": 1100.0,
"debt": 1100.0,
"return_on_equity": 1100.0,
"capital_turnover_rate": 1100.0,
"current_liabilities": 1100.0,
"dividends": float("NaN"),
"net_income": float("NaN"),
"assets": 1100.0,
"long_term_debt": 1100.0,
"short_term_debt": 1100.0,
"revenue": 1100.0,
"cash_flow": 1100.0,
"current_assets": 1100.0,
},
]
@pytest.fixture()
def full_db(empty_db: Session, finance_statements: list[dict[str, Any]]) -> Session:
"""Fills a db with some test data."""
empty_db.add_all(
[
@ -112,5 +166,13 @@ def full_db(empty_db: Session) -> Session:
]
)
empty_db.commit()
empty_db.add_all(
[
entities.AnnualFinanceStatement(**finance_statement)
for finance_statement in finance_statements
]
)
empty_db.commit()
# print(pd.read_sql_table("company", empty_db.bind).to_string())
return empty_db

View File

@ -0,0 +1,118 @@
"""Tests for ui elements."""
import pandas as pd
from sqlalchemy.orm import Session
from aki_prj23_transparenzregister.ui import ui_elements
def test_import() -> None:
"""Checks if an import co ui_elements can be made."""
assert ui_elements is not None
def test_get_company_data(full_db: Session) -> None:
"""Checks if data from the company and district court tables can be accessed."""
company_df = ui_elements.get_company_data(full_db)
test_data = pd.DataFrame(
{
"company_id": {0: 1, 1: 2, 2: 3},
"company_hr": {0: "HRB 123", 1: "HRB 123", 2: "HRB 12"},
"company_court_id": {0: 2, 1: 1, 2: 2},
"company_name": {
0: "Some Company GmbH",
1: "Other Company GmbH",
2: "Third Company GmbH",
},
"company_street": {0: "Sesamstr.", 1: "Sesamstr.", 2: None},
"company_zip_code": {0: "12345", 1: "12345", 2: None},
"company_city": {0: "TV City", 1: "TV City", 2: None},
"company_last_update": {
0: "2023-01-01",
1: "2023-01-01",
2: "2023-01-01",
},
"company_sector": {0: None, 1: None, 2: None},
"district_court_name": {
0: "Amtsgericht Dortmund",
1: "Amtsgericht Bochum",
2: "Amtsgericht Dortmund",
},
}
)
test_data = test_data.set_index("company_id")
pd.testing.assert_frame_equal(company_df, test_data)
def test_get_finance_data(full_db: Session) -> None:
"""Checks if data from the company and finance tables can be accessed."""
finance_df = ui_elements.get_finance_data(full_db)
test_data = pd.DataFrame(
{
"annual_finance_statement_id": {0: 1, 1: 2},
"annual_finance_statement_company_id": {0: 1, 1: 1},
"annual_finance_statement_date": {0: "2023-01-01", 1: "2022-01-01"},
"annual_finance_statement_total_volume": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_ebit": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_ebitda": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_ebit_margin": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_total_balance": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_equity": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_debt": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_return_on_equity": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_capital_turnover_rate": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_current_liabilities": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_dividends": {0: None, 1: None},
"annual_finance_statement_net_income": {0: None, 1: None},
"annual_finance_statement_assets": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_long_term_debt": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_short_term_debt": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_revenue": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_cash_flow": {0: 1000.0, 1: 1100.0},
"annual_finance_statement_current_assets": {0: 1000.0, 1: 1100.0},
"company_name": {0: "Some Company GmbH", 1: "Some Company GmbH"},
"company_id": {0: 1, 1: 1},
}
)
pd.testing.assert_frame_equal(finance_df, test_data)
def test_create_header() -> None:
"""Checks if the header can be created."""
options = {1: "a", 2: "b"}
ui_elements.create_header(options)
def test_create_company_header() -> None:
"""Checks if the company header can be created."""
selected_company = "Test GmbH"
ui_elements.create_company_header(selected_company)
def test_create_company_stats(full_db: Session) -> None:
"""Checks if the company widgets can be created."""
company_df = ui_elements.get_company_data(full_db)
value_chosen = 1
selected_company_stats = company_df.loc[value_chosen]
ui_elements.create_company_stats(selected_company_stats)
def test_create_tabs(full_db: Session) -> None:
"""Checks if the tabs of the company page can be created."""
selected_company_id = 1
finance_df = ui_elements.get_finance_data(full_db)
selected_finance_df = finance_df.loc[
finance_df["company_id"] == selected_company_id
]
ui_elements.create_tabs(selected_finance_df)
def test_kennzahlen_layout(full_db: Session) -> None:
"""Checks if the financial metric layout of the company page can be created."""
selected_company_id = 1
finance_df = ui_elements.get_finance_data(full_db)
selected_finance_df = finance_df.loc[
finance_df["company_id"] == selected_company_id
]
ui_elements.kennzahlen_layout(selected_finance_df)

View File

@ -168,7 +168,7 @@ def test_get_person_id_value_check(
data_transfer.get_person_id(
firstname,
surname,
date.fromisoformat(date_str) if date_str else None, # type: ignore
date.fromisoformat(date_str) if date_str else None,
full_db,
)
@ -941,7 +941,11 @@ def test_add_annual_report_to_unknown_company(
@pytest.mark.parametrize("year", [2023, 2025, 2020])
@pytest.mark.parametrize("short_term_debt", [2023.2, 2025.5, 2020.5, float("NaN")])
def test_add_annual_report(
short_term_debt: float, company_id: int, year: int, full_db: Session
short_term_debt: float,
company_id: int,
year: int,
finance_statements: list[dict[str, Any]],
full_db: Session,
) -> None:
"""Tests the addition of annual financial records."""
data_transfer.add_annual_report(
@ -961,34 +965,38 @@ def test_add_annual_report(
df_prior = pd.read_sql_table(
entities.AnnualFinanceStatement.__tablename__, full_db.bind # type: ignore
)
expected_results = pd.DataFrame(
finance_statements
+ [
{
"id": 3,
"company_id": company_id,
"date": pd.to_datetime(date(year, 1, 1)),
"total_volume": float("NaN"),
"ebit": 123.0,
"ebitda": 235.0,
"ebit_margin": float("NaN"),
"total_balance": float("NaN"),
"equity": float("NaN"),
"debt": float("NaN"),
"return_on_equity": float("NaN"),
"capital_turnover_rate": float("NaN"),
"current_liabilities": float("NaN"),
"dividends": float("NaN"),
"net_income": float("NaN"),
"assets": float("NaN"),
"long_term_debt": float("NaN"),
"short_term_debt": short_term_debt,
"revenue": float("NaN"),
"cash_flow": float("NaN"),
"current_assets": float("NaN"),
}
]
)
expected_results["date"] = pd.to_datetime(expected_results["date"])
pd.testing.assert_frame_equal(
pd.DataFrame(
[
{
"id": 1,
"company_id": company_id,
"date": pd.to_datetime(date(year, 1, 1)),
"total_volume": float("NaN"),
"ebit": 123.0,
"ebitda": 235.0,
"ebit_margin": float("NaN"),
"total_balance": float("NaN"),
"equity": float("NaN"),
"debt": float("NaN"),
"return_on_equity": float("NaN"),
"capital_turnover_rate": float("NaN"),
"current_liabilities": float("NaN"),
"dividends": float("NaN"),
"net_income": float("NaN"),
"assets": float("NaN"),
"long_term_debt": float("NaN"),
"short_term_debt": short_term_debt,
"revenue": float("NaN"),
"cash_flow": float("NaN"),
"current_assets": float("NaN"),
}
]
),
expected_results,
df_prior,
)