diff --git a/alters.txt b/alters.txt index 3e8140d..3de824c 100644 --- a/alters.txt +++ b/alters.txt @@ -1,17 +1,2 @@ -ALTER TABLE zbiorka ALTER COLUMN numer_konta DROP NOT NULL; -ALTER TABLE zbiorka ALTER COLUMN numer_telefonu_blik DROP NOT NULL; - -_______________________________ - -PGSQL -ALTER TABLE wplata ADD COLUMN ukryta boolean NOT NULL DEFAULT false; -ALTER TABLE wydatek ADD COLUMN ukryta boolean NOT NULL DEFAULT false; - --- po migracji można zdjąć DEFAULT (opcjonalnie) -ALTER TABLE wplata ALTER COLUMN ukryta DROP DEFAULT; -ALTER TABLE wydatek ALTER COLUMN ukryta DROP DEFAULT; - - -SQLite -ALTER TABLE wplata ADD COLUMN ukryta INTEGER NOT NULL DEFAULT 0; -ALTER TABLE wydatek ADD COLUMN ukryta INTEGER NOT NULL DEFAULT 0; \ No newline at end of file +ALTER TABLE zbiorka ADD COLUMN typ_zbiorki VARCHAR(20) NOT NULL DEFAULT 'standardowa'; +CREATE INDEX idx_zbiorka_typ ON zbiorka(typ_zbiorki); \ No newline at end of file diff --git a/app.py b/app.py index 01661c3..3aa9ad8 100644 --- a/app.py +++ b/app.py @@ -94,6 +94,8 @@ class Zbiorka(db.Model): pokaz_postep_kwotowo = db.Column(db.Boolean, default=True, nullable=False) uzyj_konta = db.Column(db.Boolean, default=True, nullable=False) uzyj_blik = db.Column(db.Boolean, default=True, nullable=False) + typ_zbiorki = db.Column(db.String(20), default="standardowa", nullable=False) + nazwa_typu_rezerwy = db.Column(db.String(100), nullable=True) wplaty = db.relationship( "Wplata", @@ -159,6 +161,33 @@ class Wydatek(db.Model): opis = db.Column(db.Text, nullable=True) ukryta = db.Column(db.Boolean, nullable=False, default=False) +class Przesuniecie(db.Model): + id = db.Column(db.Integer, primary_key=True) + zbiorka_zrodlo_id = db.Column( + db.Integer, + db.ForeignKey("zbiorka.id", ondelete="CASCADE"), + nullable=False, + ) + zbiorka_cel_id = db.Column( + db.Integer, + db.ForeignKey("zbiorka.id", ondelete="CASCADE"), + nullable=False, + ) + kwota = db.Column(Numeric(12, 2), nullable=False) + data = db.Column(db.DateTime, default=datetime.utcnow) + opis = db.Column(db.Text, nullable=True) + ukryta = db.Column(db.Boolean, nullable=False, default=False) + + wplata_id = db.Column( + db.Integer, + db.ForeignKey("wplata.id", ondelete="SET NULL"), + nullable=True, + ) + + zbiorka_zrodlo = db.relationship("Zbiorka", foreign_keys=[zbiorka_zrodlo_id], backref="przesuniecia_wychodzace") + zbiorka_cel = db.relationship("Zbiorka", foreign_keys=[zbiorka_cel_id], backref="przesuniecia_przychodzace") + wplata = db.relationship("Wplata", foreign_keys=[wplata_id], backref="przesuniecia") + class UstawieniaGlobalne(db.Model): __tablename__ = "ustawienia_globalne" @@ -327,27 +356,59 @@ def zbiorka(zbiorka_id): zb = db.session.get(Zbiorka, zbiorka_id) if zb is None: abort(404) + if zb.ukryta and (not current_user.is_authenticated or not current_user.czy_admin): abort(404) - + is_admin = current_user.is_authenticated and current_user.czy_admin show_hidden = is_admin and (request.args.get("show_hidden") in ("1", "true", "yes")) - + # wpłaty / wydatki z filtrem ukrycia wplaty = [ {"typ": "wpłata", "kwota": w.kwota, "opis": w.opis, "data": w.data, "ukryta": getattr(w, "ukryta", False)} for w in zb.wplaty if show_hidden or not getattr(w, "ukryta", False) ] + wydatki = [ {"typ": "wydatek", "kwota": x.kwota, "opis": x.opis, "data": x.data, "ukryta": getattr(x, "ukryta", False)} for x in zb.wydatki if show_hidden or not getattr(x, "ukryta", False) ] - - aktywnosci = wplaty + wydatki + + # Przesunięcia przychodzące + przesuniecia_przych = [ + { + "typ": "przesunięcie_przych", + "kwota": p.kwota, + "opis": p.opis or f"Przesunięcie z: {p.zbiorka_zrodlo.nazwa}", + "data": p.data, + "zbiorka_id": p.zbiorka_zrodlo_id, + "zbiorka_nazwa": p.zbiorka_zrodlo.nazwa, + "ukryta": getattr(p, "ukryta", False) + } + for p in zb.przesuniecia_przychodzace + if show_hidden or not getattr(p, "ukryta", False) + ] + + # Przesunięcia wychodzące + przesuniecia_wych = [ + { + "typ": "przesunięcie_wych", + "kwota": p.kwota, + "opis": p.opis or f"Przesunięcie do: {p.zbiorka_cel.nazwa}", + "data": p.data, + "zbiorka_id": p.zbiorka_cel_id, + "zbiorka_nazwa": p.zbiorka_cel.nazwa, + "ukryta": getattr(p, "ukryta", False) + } + for p in zb.przesuniecia_wychodzace + if show_hidden or not getattr(p, "ukryta", False) + ] + + aktywnosci = wplaty + wydatki + przesuniecia_przych + przesuniecia_wych aktywnosci.sort(key=lambda a: a["data"], reverse=True) - + return render_template("zbiorka.html", zbiorka=zb, aktywnosci=aktywnosci, show_hidden=show_hidden) @@ -428,15 +489,20 @@ def admin_dashboard(): if not current_user.czy_admin: flash("Brak uprawnień do panelu administracyjnego", "danger") return redirect(url_for("index")) - active_zbiorki = Zbiorka.query.filter_by(zrealizowana=False).all() - completed_zbiorki = Zbiorka.query.filter_by(zrealizowana=True).all() + + active_zbiorki = Zbiorka.query.filter_by(zrealizowana=False).filter( + Zbiorka.typ_zbiorki != 'rezerwa' + ).all() + completed_zbiorki = Zbiorka.query.filter_by(zrealizowana=True).filter( + Zbiorka.typ_zbiorki != 'rezerwa' + ).all() + return render_template( "admin/dashboard.html", active_zbiorki=active_zbiorki, completed_zbiorki=completed_zbiorki, ) - @app.route("/admin/zbiorka/dodaj", methods=["GET", "POST"]) @app.route("/admin/zbiorka/edytuj/", methods=["GET", "POST"]) @login_required @@ -661,6 +727,75 @@ def dodaj_wplate(zbiorka_id): return redirect(next_url or url_for("transakcje_zbiorki", zbiorka_id=zb.id)) return render_template("admin/dodaj_wplate.html", zbiorka=zb) +@app.route("/admin/zbiorka//wplata//przesun", methods=["GET", "POST"]) +@login_required +def przesun_wplate(zbiorka_id, wplata_id): + if not current_user.czy_admin: + flash("Brak uprawnień", "danger") + return redirect(url_for("index")) + + zb_zrodlo = db.session.get(Zbiorka, zbiorka_id) + if zb_zrodlo is None: + abort(404) + + wplata = db.session.get(Wplata, wplata_id) + if wplata is None or wplata.zbiorka_id != zbiorka_id: + abort(404) + + if request.method == "POST": + zbiorka_cel_id = request.form.get("zbiorka_cel_id") + if not zbiorka_cel_id: + flash("Wybierz docelową zbiórkę", "danger") + return redirect(url_for("przesun_wplate", zbiorka_id=zbiorka_id, wplata_id=wplata_id)) + + zb_cel = db.session.get(Zbiorka, int(zbiorka_cel_id)) + if zb_cel is None: + flash("Docelowa zbiórka nie istnieje", "danger") + return redirect(url_for("przesun_wplate", zbiorka_id=zbiorka_id, wplata_id=wplata_id)) + + if zb_zrodlo.stan < wplata.kwota: + flash("Niewystarczające środki w źródłowej zbiórce", "danger") + return redirect(url_for("przesun_wplate", zbiorka_id=zbiorka_id, wplata_id=wplata_id)) + + opis_dodatkowy = request.form.get("opis", "").strip() + + # Opis przesunięcia + if opis_dodatkowy: + opis_przesuniecia = f"Przesunięcie wpłaty: {wplata.opis or 'bez opisu'} - {opis_dodatkowy}" + else: + opis_przesuniecia = f"Przesunięcie wpłaty: {wplata.opis or 'bez opisu'}" + + # Utwórz przesunięcie + nowe_przesuniecie = Przesuniecie( + zbiorka_zrodlo_id=zb_zrodlo.id, + zbiorka_cel_id=zb_cel.id, + kwota=wplata.kwota, + opis=opis_przesuniecia, + wplata_id=wplata.id + ) + + # Zaktualizuj stany + zb_zrodlo.stan = (zb_zrodlo.stan or Decimal("0")) - wplata.kwota + zb_cel.stan = (zb_cel.stan or Decimal("0")) + wplata.kwota + + # Przenieś wpłatę do nowej zbiórki + wplata.zbiorka_id = zb_cel.id + + db.session.add(nowe_przesuniecie) + db.session.commit() + + flash(f"Przesunięto wpłatę {wplata.kwota} PLN do zbiórki '{zb_cel.nazwa}'", "success") + + next_url = request.args.get("next") + return redirect(next_url or url_for("transakcje_zbiorki", zbiorka_id=zb_zrodlo.id)) + + # GET - wyświetl formularz + dostepne_zbiorki = Zbiorka.query.filter(Zbiorka.id != zbiorka_id).all() + return render_template("admin/przesun_wplate.html", + zbiorka=zb_zrodlo, + wplata=wplata, + dostepne_zbiorki=dostepne_zbiorki) + @app.route("/admin/zbiorka/usun/", methods=["POST"]) @login_required @@ -1053,7 +1188,6 @@ def zapisz_wydatek(wydatek_id): delta = nowa_kwota - (x.kwota or Decimal("0")) x.kwota = nowa_kwota x.opis = request.form.get("opis", "") - # wydatki zmniejszają stan; jeżeli delta>0, stan spada bardziej zb.stan = (zb.stan or Decimal("0")) - delta db.session.commit() flash("Wydatek zaktualizowany", "success") @@ -1076,6 +1210,190 @@ def usun_wydatek(wydatek_id): return redirect(url_for("transakcje_zbiorki", zbiorka_id=zb.id)) +@app.route("/admin/zbiorka//przesuniecie/dodaj", methods=["GET", "POST"]) +@login_required +def dodaj_przesuniecie(zbiorka_id): + if not current_user.czy_admin: + flash("Brak uprawnień", "danger") + return redirect(url_for("index")) + + zb_zrodlo = db.session.get(Zbiorka, zbiorka_id) + if zb_zrodlo is None: + abort(404) + + if request.method == "POST": + try: + kwota = parse_amount(request.form.get("kwota")) + if kwota <= 0: + raise InvalidOperation + except (InvalidOperation, ValueError): + flash("Nieprawidłowa kwota (musi być > 0)", "danger") + return redirect(url_for("dodaj_przesuniecie", zbiorka_id=zbiorka_id)) + + zbiorka_cel_id = request.form.get("zbiorka_cel_id") + if not zbiorka_cel_id: + flash("Wybierz docelową zbiórkę", "danger") + return redirect(url_for("dodaj_przesuniecie", zbiorka_id=zbiorka_id)) + + zb_cel = db.session.get(Zbiorka, int(zbiorka_cel_id)) + if zb_cel is None: + flash("Docelowa zbiórka nie istnieje", "danger") + return redirect(url_for("dodaj_przesuniecie", zbiorka_id=zbiorka_id)) + + if zb_zrodlo.stan < kwota: + flash("Niewystarczające środki w źródłowej zbiórce", "danger") + return redirect(url_for("dodaj_przesuniecie", zbiorka_id=zbiorka_id)) + + opis = request.form.get("opis", "") + + nowe_przesuniecie = Przesuniecie( + zbiorka_zrodlo_id=zb_zrodlo.id, + zbiorka_cel_id=zb_cel.id, + kwota=kwota, + opis=opis + ) + + zb_zrodlo.stan = (zb_zrodlo.stan or Decimal("0")) - kwota + zb_cel.stan = (zb_cel.stan or Decimal("0")) + kwota + + db.session.add(nowe_przesuniecie) + db.session.commit() + + flash(f"Przesunięto {kwota} PLN do zbiórki '{zb_cel.nazwa}'", "success") + + next_url = request.args.get("next") + return redirect(next_url or url_for("transakcje_zbiorki", zbiorka_id=zb_zrodlo.id)) + + dostepne_zbiorki = Zbiorka.query.filter(Zbiorka.id != zbiorka_id).all() + return render_template("admin/dodaj_przesuniecie.html", zbiorka=zb_zrodlo, dostepne_zbiorki=dostepne_zbiorki) + + +@app.route("/admin/rezerwy") +@login_required +def lista_rezerwowych(): + if not current_user.czy_admin: + flash("Brak uprawnień", "danger") + return redirect(url_for("index")) + + rezerwy = Zbiorka.query.filter_by(typ_zbiorki="rezerwa").all() + return render_template("admin/lista_rezerwowych.html", rezerwy=rezerwy) + + +@app.route("/admin/rezerwa/dodaj", methods=["GET", "POST"]) +@login_required +def dodaj_rezerwe(): + if not current_user.czy_admin: + flash("Brak uprawnień", "danger") + return redirect(url_for("index")) + + if request.method == "POST": + nazwa = request.form.get("nazwa", "").strip() + if not nazwa: + flash("Nazwa jest wymagana", "danger") + global_settings = UstawieniaGlobalne.query.first() + return render_template("admin/formularz_rezerwy.html", zbiorka=None, global_settings=global_settings) + + opis = request.form.get("opis", "").strip() + global_settings = UstawieniaGlobalne.query.first() + + uzyj_konta = "uzyj_konta" in request.form + uzyj_blik = "uzyj_blik" in request.form + numer_konta = request.form.get("numer_konta", "").strip() + numer_telefonu_blik = request.form.get("numer_telefonu_blik", "").strip() + + if uzyj_konta and not numer_konta: + if global_settings and global_settings.numer_konta: + numer_konta = global_settings.numer_konta + + if uzyj_blik and not numer_telefonu_blik: + if global_settings and global_settings.numer_telefonu_blik: + numer_telefonu_blik = global_settings.numer_telefonu_blik + + nowa_rezerwa = Zbiorka( + nazwa=nazwa, + opis=opis, + cel=Decimal("0"), + stan=Decimal("0"), + typ_zbiorki="rezerwa", + ukryta=True, + ukryj_kwote=False, + pokaz_postep_finanse=False, + pokaz_postep_pozycje=False, + pokaz_postep_kwotowo=False, + uzyj_konta=uzyj_konta, + uzyj_blik=uzyj_blik, + numer_konta=numer_konta if uzyj_konta else "", + numer_telefonu_blik=numer_telefonu_blik if uzyj_blik else "" + ) + db.session.add(nowa_rezerwa) + db.session.commit() + + flash(f"Lista rezerwowa '{nazwa}' została utworzona", "success") + return redirect(url_for("lista_rezerwowych")) + + global_settings = UstawieniaGlobalne.query.first() + return render_template("admin/formularz_rezerwy.html", zbiorka=None, global_settings=global_settings) + + +@app.route("/admin/rezerwa/edytuj/", methods=["GET", "POST"]) +@login_required +def edytuj_rezerwe(rezerwa_id): + if not current_user.czy_admin: + flash("Brak uprawnień", "danger") + return redirect(url_for("index")) + + zb = db.session.get(Zbiorka, rezerwa_id) + if zb is None or zb.typ_zbiorki != "rezerwa": + abort(404) + + if request.method == "POST": + nazwa = request.form.get("nazwa", "").strip() + if not nazwa: + flash("Nazwa jest wymagana", "danger") + global_settings = UstawieniaGlobalne.query.first() + return render_template("admin/formularz_rezerwy.html", zbiorka=zb, global_settings=global_settings) + + opis = request.form.get("opis", "").strip() + + uzyj_konta = "uzyj_konta" in request.form + uzyj_blik = "uzyj_blik" in request.form + numer_konta = request.form.get("numer_konta", "").strip() + numer_telefonu_blik = request.form.get("numer_telefonu_blik", "").strip() + + zb.nazwa = nazwa + zb.opis = opis + zb.uzyj_konta = uzyj_konta + zb.uzyj_blik = uzyj_blik + zb.numer_konta = numer_konta if uzyj_konta else "" + zb.numer_telefonu_blik = numer_telefonu_blik if uzyj_blik else "" + + db.session.commit() + + flash(f"Lista rezerwowa '{nazwa}' została zaktualizowana", "success") + return redirect(url_for("lista_rezerwowych")) + + global_settings = UstawieniaGlobalne.query.first() + return render_template("admin/formularz_rezerwy.html", zbiorka=zb, global_settings=global_settings) + +@app.route("/admin/rezerwa/usun/", methods=["POST"]) +@login_required +def usun_rezerwe(rezerwa_id): + if not current_user.czy_admin: + flash("Brak uprawnień", "danger") + return redirect(url_for("index")) + + zb = db.session.get(Zbiorka, rezerwa_id) + if zb is None or zb.typ_zbiorki != "rezerwa": + abort(404) + + nazwa = zb.nazwa + db.session.delete(zb) + db.session.commit() + + flash(f"Lista rezerwowa '{nazwa}' została usunięta", "success") + return redirect(url_for("lista_rezerwowych")) + + @app.route("/favicon.ico") def favicon(): return "", 204 diff --git a/static/js/formularz_rezerwy.js b/static/js/formularz_rezerwy.js new file mode 100644 index 0000000..4616855 --- /dev/null +++ b/static/js/formularz_rezerwy.js @@ -0,0 +1,19 @@ + document.addEventListener('DOMContentLoaded', function() { + const uzyjKonta = document.getElementById('uzyj_konta'); + const kontoField = document.getElementById('konto-field'); + const uzyjBlik = document.getElementById('uzyj_blik'); + const blikField = document.getElementById('blik-field'); + + if (uzyjKonta && kontoField) { + uzyjKonta.addEventListener('change', function() { + kontoField.style.display = this.checked ? 'block' : 'none'; + }); + } + + if (uzyjBlik && blikField) { + uzyjBlik.addEventListener('change', function() { + blikField.style.display = this.checked ? 'block' : 'none'; + }); + } + }); + diff --git a/templates/admin/dashboard.html b/templates/admin/dashboard.html index beda13d..e80007b 100644 --- a/templates/admin/dashboard.html +++ b/templates/admin/dashboard.html @@ -11,6 +11,9 @@ ➕ Dodaj zbiórkę + + Listy rezerwowe + Ustawienia główne diff --git a/templates/admin/dodaj_przesuniecie.html b/templates/admin/dodaj_przesuniecie.html new file mode 100644 index 0000000..9626449 --- /dev/null +++ b/templates/admin/dodaj_przesuniecie.html @@ -0,0 +1,85 @@ +{% extends 'base.html' %} +{% block title %}Przesuń środki - {{ zbiorka.nazwa }}{% endblock %} +{% block content %} + +
+ +
+

+ Przesuń środki z: {{ zbiorka.nazwa }} +

+

Dostępne środki: {{ zbiorka.stan|round(2) }} PLN

+
+ + +
+
+
+
+ Cel przesunięcia +
+
+
+
+ + +
+ +
+ +
+ + PLN +
+ + Można użyć przecinka lub kropki + +
+ +
+ + +
+
+
+ + +
+ +
+ Jak to działa: Kwota zostanie odjęta ze źródłowej zbiórki i dodana do docelowej. + W obu zbiórkach pojawi się wpis o przesunięciu w historii transakcji. +
+
+ +
+ + Anuluj +
+
+
+ +{% endblock %} diff --git a/templates/admin/formularz_rezerwy.html b/templates/admin/formularz_rezerwy.html new file mode 100644 index 0000000..8da50f3 --- /dev/null +++ b/templates/admin/formularz_rezerwy.html @@ -0,0 +1,170 @@ +{# templates/admin/formularz_rezerwy.html #} +{% extends 'base.html' %} + +{% set has_obj = zbiorka is not none %} +{% set is_edit = has_obj and zbiorka.id is not none %} + +{% block title %}{{ 'Edytuj listę rezerwową' if is_edit else 'Dodaj listę rezerwową' }}{% endblock %} + +{% block content %} +
+ + +
+ {% if is_edit and zbiorka and zbiorka.id %} + ← Szczegóły + listy + {% else %} + ← Listy rezerwowe + {% endif %} +
+ +
+
+

+ {{ 'Edytuj listę rezerwową' if is_edit else 'Dodaj nową listę rezerwową' }} +

+ + {% if is_edit %} +
+ + Stan: {{ (zbiorka.stan or 0)|round(2) }} PLN + + Lista rezerwowa +
+ {% else %} + Utwórz dedykowaną listę do zarządzania środkami + {% endif %} +
+ +
+
+ + + + +
Podstawowe dane
+ +
+
+ + + Unikalny identyfikator tej listy rezerwowej +
+ +
+ + + Krótki opis, który pomoże w identyfikacji +
+
+ +
+ + + + +
Kanały płatności
+

+ Określ, czy ta lista ma akceptować bezpośrednie wpłaty od użytkowników. +

+ +
+ +
+
+
+ + +
+ +
+ + + + {% if global_settings and global_settings.numer_konta %} + Domyślnie: {{ global_settings.numer_konta }} + {% else %} + Zostaw puste dla globalnego numeru + {% endif %} + +
+
+
+ + +
+
+
+ + +
+ +
+ + + + {% if global_settings and global_settings.numer_telefonu_blik %} + Domyślnie: {{ global_settings.numer_telefonu_blik }} + {% else %} + Zostaw puste dla globalnego numeru + {% endif %} + +
+
+
+
+ + {% if not is_edit %} + +
+ Wskazówka: Lista rezerwowa to pomocnicze miejsce do gromadzenia środków, + które mogą być później przesuwane do konkretnych zbiórek. Jest ukryta dla użytkowników + nieadministracyjnych i nie pojawia się na stronie głównej. +
+ {% endif %} + +
+ + +
+
+ + Anuluj +
+ + {% if is_edit %} + + {% endif %} +
+ +
+
+
+
+{% endblock %} +{% block extra_scripts %} +{{ super() }} + +{% endblock %} diff --git a/templates/admin/lista_rezerwowych.html b/templates/admin/lista_rezerwowych.html new file mode 100644 index 0000000..9cf6caa --- /dev/null +++ b/templates/admin/lista_rezerwowych.html @@ -0,0 +1,146 @@ +{% extends 'base.html' %} +{% block title %}Listy rezerwowe{% endblock %} +{% block content %} + +
+ + + {% if rezerwy %} +
+ + + + + + + + + + + {% for r in rezerwy %} + + + + + + + {% endfor %} + +
IDNazwaWidocznośćOpcje
{{ r.id }} +
+ + {{ r.nazwa }} + + + Stan: {{ r.stan|round(2) }} PLN + {% if r.opis %} + · {{ r.opis[:50] }}{% if r.opis|length > 50 %}...{% endif %} + {% endif %} + +
+
+ {% if r.ukryta %} + Ukryta + {% else %} + Widoczna + {% endif %} + + +
+ Edytuj + + +
+
+
+ {% else %} + +
+
+
Brak list rezerwowych
+

Nie masz jeszcze żadnych list rezerwowych. Utwórz pierwszą, aby zarządzać nadpłatami i środkami rezerwowymi.

+ Dodaj listę rezerwową +
+
+ {% endif %} +
+ +{% endblock %} diff --git a/templates/admin/przesun_wplate.html b/templates/admin/przesun_wplate.html new file mode 100644 index 0000000..da20b2d --- /dev/null +++ b/templates/admin/przesun_wplate.html @@ -0,0 +1,119 @@ +{% extends 'base.html' %} +{% block title %}Przesuń wpłatę - {{ zbiorka.nazwa }}{% endblock %} +{% block content %} + +
+ +
+

+ Przesuń konkretną wpłatę +

+

Przenieś wybraną wpłatę do innej zbiórki

+
+ + +
+
+
+ Szczegóły wpłaty +
+
+
+
+
+
+ Źródło + {{ zbiorka.nazwa }} + {% if zbiorka.typ_zbiorki == 'rezerwa' %} + Lista rezerwowa + {% endif %} +
+
+
+
+ Kwota + {{ wplata.kwota|round(2) }} PLN +
+
+
+
+ Data wpłaty + {{ wplata.data|dt("%d.%m.%Y %H:%M") }} +
+
+ {% if wplata.opis %} +
+
+ Opis oryginalny + {{ wplata.opis }} +
+
+ {% endif %} +
+
+
+ + +
+
+
+
+ Cel przesunięcia +
+
+
+
+ + +
+ +
+ + + + Oryginalny opis wpłaty zostanie zachowany + +
+
+
+ + +
+ +
+ Jak to działa: +
    +
  • Wpłata zostanie przeniesiona do wybranej zbiórki wraz z całą historią
  • +
  • Zostanie utworzony wpis o przesunięciu w obu zbiórkach
  • +
  • Stany finansowe zostaną automatycznie zaktualizowane
  • +
+
+
+ +
+ + Anuluj +
+
+
+ +{% endblock %} diff --git a/templates/admin/transakcje.html b/templates/admin/transakcje.html index c855ce9..8bbc9fe 100644 --- a/templates/admin/transakcje.html +++ b/templates/admin/transakcje.html @@ -14,6 +14,9 @@ Dodaj wydatek + + Przesuń środki + Edytuj stan @@ -61,6 +64,10 @@
{% if a.typ == 'wpłata' %} + Przesuń +