From 5299a7fc668e58fe3347b97a78604cf78d2c2dfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Gruszczy=C5=84ski?= Date: Sun, 19 Jul 2026 19:22:52 +0200 Subject: [PATCH] zapamietanie akcji --- app/__init__.py | 4 ++-- app/main.py | 12 +++++++++++- app/static/css/layout.css | 8 +++++--- app/static/js/core.js | 2 +- app/templates/base.html | 10 +++++++--- 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index eb5032a..034823b 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -96,11 +96,11 @@ def create_app(test_config=None): filename = request.view_args.get("filename", "") if request.view_args else "" if filename.endswith((".css", ".js")): - response.headers["Cache-Control"] = "public, max-age=3600, immutable" + response.headers["Cache-Control"] = "public, max-age=2592000, immutable" response.headers.pop("Content-Disposition", None) elif response.mimetype == "text/html": - response.headers["Cache-Control"] = "private, no-store" + response.headers["Cache-Control"] = "no-store, private, must-revalidate" return response diff --git a/app/main.py b/app/main.py index 68bcff0..bb1f5e3 100644 --- a/app/main.py +++ b/app/main.py @@ -308,7 +308,17 @@ def fuel(): p = fetch_orlen_price(request.form["fuel_type"], fueled_at.date(), price_region); wholesale=p["price_per_liter"]; source=p["source"] except Exception: pass station_label = station_company.company_name if station_company else request.form.get("station") - e = FuelEntry(vehicle=vehicle, user_id=current_user.id, fueled_at=fueled_at, liters=Decimal(request.form["liters"]), price_per_liter=Decimal(request.form["price_per_liter"]), fuel_type=request.form["fuel_type"], odometer=odometer, station=station_label, station_company_id=station_company.id if station_company else None, invoice_number=request.form.get("invoice_number"), used_fuel_card="used_fuel_card" in request.form, wholesale_price=wholesale, wholesale_source=source) + requested_card_id = request.form.get("fuel_card_id", type=int) + default_card_id = vehicle.fuel_card_id or current_user.fuel_card_id + fuel_card = db.session.get(FuelCard, requested_card_id or default_card_id) if (requested_card_id or default_card_id) else None + used_fuel_card = "used_fuel_card" in request.form and fuel_card is not None + if fuel_card and fuel_card.company_id and fuel_card.company_id != (vehicle.company_id or vehicle.owner.company_id): + response = error_response("Wybrana karta nie należy do firmy pojazdu"); return response or redirect(url_for("main.fuel")) + if used_fuel_card and station_company: + card_rule = FuelCardStationRule.query.filter_by(fuel_card_id=fuel_card.id, station_company_id=station_company.id).first() + if card_rule and not card_rule.allowed: + response = error_response("Ta stacja jest zablokowana dla wybranej karty paliwowej", 403); return response or redirect(url_for("main.fuel")) + e = FuelEntry(vehicle=vehicle, user_id=current_user.id, fueled_at=fueled_at, liters=Decimal(request.form["liters"]), price_per_liter=Decimal(request.form["price_per_liter"]), fuel_type=request.form["fuel_type"], odometer=odometer, station=station_label, station_company_id=station_company.id if station_company else None, fuel_card_id=fuel_card.id if used_fuel_card else None, invoice_number=request.form.get("invoice_number"), used_fuel_card=used_fuel_card, wholesale_price=wholesale, wholesale_source=source) freeze_vat_action(e, settings.vat_rate) freeze_settlement(e, settings, source="Automatycznie przy dodaniu") vehicle.current_odometer = odometer; db.session.add(e); db.session.commit(); response = ok_response("Zapisano tankowanie", redirect=url_for("main.dashboard")); return response or redirect(url_for("main.dashboard")) diff --git a/app/static/css/layout.css b/app/static/css/layout.css index 17beef9..5684f1f 100644 --- a/app/static/css/layout.css +++ b/app/static/css/layout.css @@ -6,8 +6,8 @@ html,body{min-height:100%}body{min-height:100vh;min-height:100dvh;display:flex;f .app-navbar .nav-link{border-radius:.6rem;padding:.55rem .75rem;font-weight:550;color:var(--bs-secondary-color)}.app-navbar .nav-link:hover{color:var(--bs-emphasis-color);background:var(--bs-tertiary-bg)}.app-navbar .nav-link.active{color:var(--bs-primary);background:color-mix(in srgb,var(--bs-primary) 10%,transparent)}.navbar-divider{height:1.5rem;border-left:1px solid var(--bs-border-color);margin-left:.35rem} .app-main{flex:1;padding-top:2rem;padding-bottom:3rem}.app-footer{padding:1.25rem 0;border-top:1px solid var(--bs-border-color-translucent);background:var(--bs-body-bg);color:var(--bs-secondary-color)}.app-footer a{color:inherit} .page-header{display:flex;justify-content:space-between;align-items:flex-end;gap:1rem;margin-bottom:1.5rem}.page-header h1{letter-spacing:-.035em}.page-kicker{font-size:.78rem;text-transform:uppercase;letter-spacing:.08em;font-weight:700;color:var(--bs-primary);margin-bottom:.3rem} -#live-alerts{max-width:min(420px,calc(100vw - 2rem))}.app-alert{box-shadow:var(--app-shadow);border:0} -.auth-page{background:radial-gradient(circle at 20% 10%,color-mix(in srgb,var(--bs-primary) 14%,transparent),transparent 34%),radial-gradient(circle at 85% 85%,color-mix(in srgb,var(--bs-warning) 10%,transparent),transparent 30%),var(--bs-tertiary-bg)}.auth-main{display:grid;place-items:center;width:100%;padding-top:2rem;padding-bottom:2rem}.auth-shell{width:min(100%,28rem)}.auth-brand{display:block;width:max-content;margin:0 auto 1.25rem;font-size:1.8rem;font-weight:850;letter-spacing:-.055em}.auth-card{border-color:color-mix(in srgb,var(--bs-primary) 18%,var(--bs-border-color));box-shadow:none} +#live-alerts,.app-alert-host{position:fixed;top:max(1rem,env(safe-area-inset-top));right:max(1rem,env(safe-area-inset-right));z-index:1080;width:min(420px,calc(100vw - 2rem));pointer-events:none}.app-alert-host .alert,#live-alerts .alert{pointer-events:auto}.app-alert{box-shadow:var(--app-shadow);border:0} +.auth-page{background:var(--bs-tertiary-bg)}.auth-main{display:grid;place-items:center;width:100%;padding-top:2rem;padding-bottom:2rem}.auth-shell{width:min(100%,28rem)}.auth-brand{display:block;width:max-content;margin:0 auto 1.25rem;font-size:1.8rem;font-weight:850;letter-spacing:-.055em}.auth-card{border-color:color-mix(in srgb,var(--bs-primary) 18%,var(--bs-border-color));box-shadow:none} /* Geometria interfejsu jest wspólna dla wszystkich motywów. Motyw zmienia wyłącznie kolory. */ .app-navbar{min-height:4.25rem} @@ -22,8 +22,10 @@ html,body{min-height:100%}body{min-height:100vh;min-height:100dvh;display:flex;f [data-bs-theme="dark"] .app-navbar{background:rgba(24,26,29,.94);border-bottom-color:#34383d;box-shadow:0 .1rem .45rem rgba(0,0,0,.18)} [data-bs-theme="dark"] .app-footer{background:#1b1d20;border-top-color:#34383d} [data-bs-theme="dark"] .brand-fuel{color:#f8f9fa} -[data-bs-theme="dark"] .auth-page{background:radial-gradient(circle at 20% 10%,rgba(55,139,230,.16),transparent 36%),radial-gradient(circle at 85% 85%,rgba(255,193,7,.08),transparent 32%),#141619} +[data-bs-theme="dark"] .auth-page{background:#141619} @media(max-width:991.98px){.app-main{padding-top:1.35rem}.app-navbar .navbar-collapse{border-top:1px solid var(--bs-border-color-translucent);margin-top:.75rem}.app-navbar .nav-link{padding:.7rem .8rem}.page-header{align-items:stretch;flex-direction:column}} @media(max-width:575.98px){.app-main{padding-left:1rem;padding-right:1rem}.page-header h1{font-size:1.65rem}.auth-main{padding-top:1.25rem;padding-bottom:1.25rem}} @supports(padding:max(0px)){.app-navbar{padding-top:max(.5rem,env(safe-area-inset-top))}.app-footer{padding-bottom:max(1.25rem,env(safe-area-inset-bottom))}} + +.auth-page .app-alert{box-shadow:none} diff --git a/app/static/js/core.js b/app/static/js/core.js index ce1a75c..d58fea1 100644 --- a/app/static/js/core.js +++ b/app/static/js/core.js @@ -2,5 +2,5 @@ window.FuelTrack=window.FuelTrack||{}; FuelTrack.charts={}; FuelTrack.qs=(s,r=document)=>r.querySelector(s); FuelTrack.qsa=(s,r=document)=>[...r.querySelectorAll(s)]; -FuelTrack.notify=(message,type='success')=>{let host=FuelTrack.qs('#live-alerts');if(!host){host=document.createElement('div');host.id='live-alerts';host.className='position-fixed top-0 end-0 p-3';host.style.zIndex='1080';document.body.append(host)}const el=document.createElement('div');el.className=`alert alert-${type} shadow`;el.textContent=message;host.append(el);setTimeout(()=>el.remove(),3500)}; +FuelTrack.notify=(message,type='success')=>{let host=FuelTrack.qs('#live-alerts');if(!host){host=document.createElement('div');host.id='live-alerts';host.className='app-alert-host';document.body.append(host)}const el=document.createElement('div');el.className=`alert alert-${type} alert-dismissible fade show app-alert`;el.textContent=message;host.append(el);setTimeout(()=>el.remove(),3500)}; FuelTrack.debounce=(fn,delay=300)=>{let timer;return(...args)=>{clearTimeout(timer);timer=setTimeout(()=>fn(...args),delay)}}; diff --git a/app/templates/base.html b/app/templates/base.html index 6a6f113..c7d2dec 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -41,10 +41,14 @@ {% endif %} -
- {% with msgs=get_flashed_messages(with_categories=true) %} +{% with msgs=get_flashed_messages(with_categories=true) %} + {% if msgs %} +
{% for cat,msg in msgs %}{% endfor %} - {% endwith %} +
+ {% endif %} +{% endwith %} +
{% block content %}{% endblock %}
{% if current_user.is_authenticated %}{% endif %}