statystyki i optymalizacje
This commit is contained in:
209
app.py
209
app.py
@@ -201,6 +201,7 @@ class UstawieniaGlobalne(db.Model):
|
||||
typ_navbar = db.Column(db.String(10), default="text")
|
||||
typ_stopka = db.Column(db.String(10), default="text")
|
||||
stopka_text = db.Column(db.String(200), nullable=True)
|
||||
kolejnosc_rezerwowych = db.Column(db.String(20), default="id", nullable=False)
|
||||
|
||||
|
||||
@login_manager.user_loader
|
||||
@@ -336,7 +337,23 @@ def inject_version():
|
||||
# TRASY PUBLICZNE
|
||||
@app.route("/")
|
||||
def index():
|
||||
zbiorki = Zbiorka.query.filter_by(ukryta=False, zrealizowana=False).all()
|
||||
settings = UstawieniaGlobalne.query.first()
|
||||
kolejnosc = settings.kolejnosc_rezerwowych if settings else "id"
|
||||
|
||||
standardowe = Zbiorka.query.filter_by(ukryta=False, zrealizowana=False).filter(
|
||||
Zbiorka.typ_zbiorki != 'rezerwa'
|
||||
).all()
|
||||
|
||||
rezerwowe = Zbiorka.query.filter_by(ukryta=False, zrealizowana=False, typ_zbiorki='rezerwa').all()
|
||||
|
||||
# Sortuj według ustawienia
|
||||
if kolejnosc == "first":
|
||||
zbiorki = rezerwowe + standardowe
|
||||
elif kolejnosc == "last":
|
||||
zbiorki = standardowe + rezerwowe
|
||||
else: # "id"
|
||||
zbiorki = sorted(standardowe + rezerwowe, key=lambda z: z.id)
|
||||
|
||||
return render_template("index.html", zbiorki=zbiorki)
|
||||
|
||||
|
||||
@@ -351,12 +368,19 @@ def page_not_found(e):
|
||||
return redirect(url_for("index"))
|
||||
|
||||
|
||||
@app.route("/zbiorka/<int:zbiorka_id>")
|
||||
@app.route("/zbiorka/<int:zbiorka_id>", endpoint='zbiorka')
|
||||
@app.route("/rezerwa/<int:zbiorka_id>", endpoint='rezerwa')
|
||||
def zbiorka(zbiorka_id):
|
||||
zb = db.session.get(Zbiorka, zbiorka_id)
|
||||
if zb is None:
|
||||
abort(404)
|
||||
|
||||
# Zabezpieczenie: sprawdź czy URL pasuje do typu zbiórki
|
||||
poprawny_endpoint = 'rezerwa' if zb.typ_zbiorki == 'rezerwa' else 'zbiorka'
|
||||
|
||||
if request.endpoint != poprawny_endpoint:
|
||||
return redirect(url_for(poprawny_endpoint, zbiorka_id=zbiorka_id), code=301)
|
||||
|
||||
if zb.ukryta and (not current_user.is_authenticated or not current_user.czy_admin):
|
||||
abort(404)
|
||||
|
||||
@@ -945,9 +969,10 @@ def admin_ustawienia():
|
||||
if not current_user.czy_admin:
|
||||
flash("Brak uprawnień do panelu administracyjnego", "danger")
|
||||
return redirect(url_for("index"))
|
||||
|
||||
|
||||
client_ip = get_real_ip()
|
||||
settings = UstawieniaGlobalne.query.first()
|
||||
|
||||
if request.method == "POST":
|
||||
numer_konta = request.form.get("numer_konta")
|
||||
numer_telefonu_blik = request.form.get("numer_telefonu_blik")
|
||||
@@ -958,7 +983,8 @@ def admin_ustawienia():
|
||||
typ_stopka = request.form.get("typ_stopka", "text")
|
||||
stopka_text = request.form.get("stopka_text") or None
|
||||
pokaz_logo_w_navbar = (typ_navbar == "logo")
|
||||
|
||||
kolejnosc_rezerwowych = request.form.get("kolejnosc_rezerwowych", "id")
|
||||
|
||||
if settings is None:
|
||||
settings = UstawieniaGlobalne(
|
||||
numer_konta=numer_konta,
|
||||
@@ -970,6 +996,7 @@ def admin_ustawienia():
|
||||
typ_navbar=typ_navbar,
|
||||
typ_stopka=typ_stopka,
|
||||
stopka_text=stopka_text,
|
||||
kolejnosc_rezerwowych=kolejnosc_rezerwowych,
|
||||
)
|
||||
db.session.add(settings)
|
||||
else:
|
||||
@@ -982,11 +1009,12 @@ def admin_ustawienia():
|
||||
settings.typ_navbar = typ_navbar
|
||||
settings.typ_stopka = typ_stopka
|
||||
settings.stopka_text = stopka_text
|
||||
|
||||
settings.kolejnosc_rezerwowych = kolejnosc_rezerwowych
|
||||
|
||||
db.session.commit()
|
||||
flash("Ustawienia globalne zostały zaktualizowane", "success")
|
||||
return redirect(url_for("admin_dashboard"))
|
||||
|
||||
|
||||
return render_template("admin/ustawienia.html", settings=settings, client_ip=client_ip)
|
||||
|
||||
|
||||
@@ -1416,6 +1444,175 @@ def usun_rezerwe(rezerwa_id):
|
||||
return redirect(url_for("lista_rezerwowych"))
|
||||
|
||||
|
||||
@app.route("/admin/statystyki")
|
||||
@login_required
|
||||
def admin_statystyki():
|
||||
if not current_user.czy_admin:
|
||||
abort(403)
|
||||
|
||||
from sqlalchemy import func, extract
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
# ==================== PODSTAWOWE STATYSTYKI ====================
|
||||
total_wplaty = db.session.query(func.sum(Wplata.kwota)).filter(Wplata.ukryta == False).scalar() or 0
|
||||
total_wydatki = db.session.query(func.sum(Wydatek.kwota)).filter(Wydatek.ukryta == False).scalar() or 0
|
||||
bilans = total_wplaty - total_wydatki
|
||||
|
||||
liczba_wplat = db.session.query(func.count(Wplata.id)).filter(Wplata.ukryta == False).scalar() or 0
|
||||
liczba_wydatkow = db.session.query(func.count(Wydatek.id)).filter(Wydatek.ukryta == False).scalar() or 0
|
||||
liczba_zbiorek = db.session.query(func.count(Zbiorka.id)).scalar() or 0
|
||||
|
||||
# Najwyższa wpłata
|
||||
najwyzsza_wplata = db.session.query(Wplata).filter(Wplata.ukryta == False).order_by(Wplata.kwota.desc()).first()
|
||||
|
||||
# Najwyższy wydatek
|
||||
najwyzszy_wydatek = db.session.query(Wydatek).filter(Wydatek.ukryta == False).order_by(Wydatek.kwota.desc()).first()
|
||||
|
||||
# Średnia wpłata i wydatek
|
||||
srednia_wplata = total_wplaty / liczba_wplat if liczba_wplat > 0 else 0
|
||||
sredni_wydatek = total_wydatki / liczba_wydatkow if liczba_wydatkow > 0 else 0
|
||||
|
||||
# ==================== STATYSTYKI PRZESUNIĘĆ ====================
|
||||
total_przesuniec = db.session.query(func.sum(Przesuniecie.kwota)).filter(Przesuniecie.ukryta == False).scalar() or 0
|
||||
liczba_przesuniec = db.session.query(func.count(Przesuniecie.id)).filter(Przesuniecie.ukryta == False).scalar() or 0
|
||||
|
||||
# Top 5 źródeł przesunięć (zbiórki które najczęściej przekazują środki)
|
||||
top_zrodla_przesuniec = db.session.query(
|
||||
Zbiorka.nazwa,
|
||||
func.count(Przesuniecie.id).label('liczba'),
|
||||
func.sum(Przesuniecie.kwota).label('suma')
|
||||
).join(Przesuniecie, Przesuniecie.zbiorka_zrodlo_id == Zbiorka.id)\
|
||||
.filter(Przesuniecie.ukryta == False)\
|
||||
.group_by(Zbiorka.id, Zbiorka.nazwa)\
|
||||
.order_by(func.sum(Przesuniecie.kwota).desc())\
|
||||
.limit(5).all()
|
||||
|
||||
# ==================== TOP 10 WPŁAT ====================
|
||||
top_10_wplat = db.session.query(Wplata)\
|
||||
.filter(Wplata.ukryta == False)\
|
||||
.order_by(Wplata.kwota.desc())\
|
||||
.limit(10).all()
|
||||
|
||||
# ==================== AKTYWNOŚĆ CZASOWA ====================
|
||||
teraz = datetime.now()
|
||||
rok_temu = teraz - timedelta(days=365)
|
||||
miesiac_temu = teraz - timedelta(days=30)
|
||||
tydzien_temu = teraz - timedelta(days=7)
|
||||
|
||||
# Aktywność ostatnie 7 dni
|
||||
wplaty_7dni = db.session.query(
|
||||
func.count(Wplata.id).label('liczba'),
|
||||
func.sum(Wplata.kwota).label('suma')
|
||||
).filter(Wplata.data >= tydzien_temu, Wplata.ukryta == False).first()
|
||||
|
||||
wydatki_7dni = db.session.query(
|
||||
func.count(Wydatek.id).label('liczba'),
|
||||
func.sum(Wydatek.kwota).label('suma')
|
||||
).filter(Wydatek.data >= tydzien_temu, Wydatek.ukryta == False).first()
|
||||
|
||||
# Aktywność ostatnie 30 dni
|
||||
wplaty_30dni = db.session.query(
|
||||
func.count(Wplata.id).label('liczba'),
|
||||
func.sum(Wplata.kwota).label('suma')
|
||||
).filter(Wplata.data >= miesiac_temu, Wplata.ukryta == False).first()
|
||||
|
||||
wydatki_30dni = db.session.query(
|
||||
func.count(Wydatek.id).label('liczba'),
|
||||
func.sum(Wydatek.kwota).label('suma')
|
||||
).filter(Wydatek.data >= miesiac_temu, Wydatek.ukryta == False).first()
|
||||
|
||||
# ==================== STATYSTYKI MIESIĘCZNE (ostatnie 12 miesięcy) ====================
|
||||
wplaty_miesieczne = db.session.query(
|
||||
extract('year', Wplata.data).label('rok'),
|
||||
extract('month', Wplata.data).label('miesiac'),
|
||||
func.sum(Wplata.kwota).label('suma'),
|
||||
func.count(Wplata.id).label('liczba')
|
||||
).filter(
|
||||
Wplata.data >= rok_temu,
|
||||
Wplata.ukryta == False
|
||||
).group_by('rok', 'miesiac').order_by('rok', 'miesiac').all()
|
||||
|
||||
wydatki_miesieczne = db.session.query(
|
||||
extract('year', Wydatek.data).label('rok'),
|
||||
extract('month', Wydatek.data).label('miesiac'),
|
||||
func.sum(Wydatek.kwota).label('suma'),
|
||||
func.count(Wydatek.id).label('liczba')
|
||||
).filter(
|
||||
Wydatek.data >= rok_temu,
|
||||
Wydatek.ukryta == False
|
||||
).group_by('rok', 'miesiac').order_by('rok', 'miesiac').all()
|
||||
|
||||
przesuniecia_miesieczne = db.session.query(
|
||||
extract('year', Przesuniecie.data).label('rok'),
|
||||
extract('month', Przesuniecie.data).label('miesiac'),
|
||||
func.sum(Przesuniecie.kwota).label('suma'),
|
||||
func.count(Przesuniecie.id).label('liczba')
|
||||
).filter(
|
||||
Przesuniecie.data >= rok_temu,
|
||||
Przesuniecie.ukryta == False
|
||||
).group_by('rok', 'miesiac').order_by('rok', 'miesiac').all()
|
||||
|
||||
# ==================== STATYSTYKI ROCZNE ====================
|
||||
wplaty_roczne = db.session.query(
|
||||
extract('year', Wplata.data).label('rok'),
|
||||
func.sum(Wplata.kwota).label('suma'),
|
||||
func.count(Wplata.id).label('liczba')
|
||||
).filter(
|
||||
Wplata.ukryta == False
|
||||
).group_by('rok').order_by('rok').all()
|
||||
|
||||
wydatki_roczne = db.session.query(
|
||||
extract('year', Wydatek.data).label('rok'),
|
||||
func.sum(Wydatek.kwota).label('suma'),
|
||||
func.count(Wydatek.id).label('liczba')
|
||||
).filter(
|
||||
Wydatek.ukryta == False
|
||||
).group_by('rok').order_by('rok').all()
|
||||
|
||||
# ==================== TOP 5 ZBIÓREK ====================
|
||||
top_zbiorki = db.session.query(
|
||||
Zbiorka,
|
||||
func.sum(Wplata.kwota).label('suma_wplat')
|
||||
).join(Wplata).filter(
|
||||
Wplata.ukryta == False
|
||||
).group_by(Zbiorka.id).order_by(func.sum(Wplata.kwota).desc()).limit(5).all()
|
||||
|
||||
return render_template(
|
||||
"admin/statystyki.html",
|
||||
# Podstawowe
|
||||
total_wplaty=total_wplaty,
|
||||
total_wydatki=total_wydatki,
|
||||
bilans=bilans,
|
||||
liczba_wplat=liczba_wplat,
|
||||
liczba_wydatkow=liczba_wydatkow,
|
||||
liczba_zbiorek=liczba_zbiorek,
|
||||
najwyzsza_wplata=najwyzsza_wplata,
|
||||
najwyzszy_wydatek=najwyzszy_wydatek,
|
||||
srednia_wplata=srednia_wplata,
|
||||
sredni_wydatek=sredni_wydatek,
|
||||
# Przesunięcia
|
||||
total_przesuniec=total_przesuniec,
|
||||
liczba_przesuniec=liczba_przesuniec,
|
||||
top_zrodla_przesuniec=top_zrodla_przesuniec,
|
||||
# Top wpłaty
|
||||
top_10_wplat=top_10_wplat,
|
||||
# Aktywność czasowa
|
||||
wplaty_7dni=wplaty_7dni,
|
||||
wydatki_7dni=wydatki_7dni,
|
||||
wplaty_30dni=wplaty_30dni,
|
||||
wydatki_30dni=wydatki_30dni,
|
||||
# Miesięczne
|
||||
wplaty_miesieczne=wplaty_miesieczne,
|
||||
wydatki_miesieczne=wydatki_miesieczne,
|
||||
przesuniecia_miesieczne=przesuniecia_miesieczne,
|
||||
# Roczne
|
||||
wplaty_roczne=wplaty_roczne,
|
||||
wydatki_roczne=wydatki_roczne,
|
||||
# Top zbiórki
|
||||
top_zbiorki=top_zbiorki
|
||||
)
|
||||
|
||||
|
||||
@app.route("/favicon.ico")
|
||||
def favicon():
|
||||
return "", 204
|
||||
|
||||
Reference in New Issue
Block a user