rewrite styles

This commit is contained in:
Mateusz Gruszczyński
2026-07-14 11:52:36 +02:00
parent 780681dfd5
commit e200c91881
19 changed files with 220 additions and 65 deletions
+21 -26
View File
@@ -6,7 +6,7 @@ from flask import Blueprint, jsonify, request, url_for, current_app
from flask_login import current_user, login_required, login_user, logout_user
from sqlalchemy import extract
from sqlalchemy.exc import IntegrityError
from .extensions import db, socketio
from .extensions import db
from .models import User, Vehicle, FuelEntry, CompanySettings, AppSetting, OrlenPrice, FuelCardPolicy, FuelStationCompany, FuelStationPoint, FuelCard, FuelCardStationRule
from .services import calculate_costs, fetch_orlen_price, fetch_orlen_range, invoice_period, fetch_ure_stations, aggregate_ure_companies, POLISH_REGIONS
from .station_catalog import sync_station_catalog
@@ -96,7 +96,7 @@ def create_vehicle():
if current_user.role not in ('boss','admin') and owner.id!=current_user.id:return fail('Brak uprawnień',403)
if current_user.role=='boss' and owner.company_id!=current_user.company_id:return fail('Użytkownik jest w innej firmie',403)
v=Vehicle(name=d['name'].strip(),make=d['make'].strip(),model=d['model'].strip(),registration=d['registration'].strip().upper(),fuel_type=d['fuel_type'],owner_id=owner.id,company_id=owner.company_id,has_fuel_card=bool(card_id),fuel_card_id=card_id,current_odometer=int(d.get('current_odometer') or 0))
db.session.add(v); db.session.commit(); socketio.emit('app_changed',{'resource':'vehicle','id':v.id}); return response(vehicle_dict(v),'Dodano pojazd',201)
db.session.add(v); db.session.commit(); return response(vehicle_dict(v),'Dodano pojazd',201)
except (KeyError,ValueError,IntegrityError) as exc: db.session.rollback(); return fail(str(getattr(exc,'orig',exc)),400)
@api.put('/vehicles/<int:vehicle_id>/fuel-card')
@@ -108,7 +108,7 @@ def assign_vehicle_fuel_card(vehicle_id):
card=db.session.get(FuelCard,card_id) if card_id else None
if card_id and not card:return fail('Nie znaleziono karty paliwowej',404)
if card and v.company_id and card.company_id!=v.company_id:return fail('Karta należy do innej firmy',400)
v.fuel_card_id=card_id;v.has_fuel_card=bool(card_id);db.session.commit();socketio.emit('app_changed',{'resource':'vehicle','id':v.id});return response(vehicle_dict(v),'Zapisano kartę pojazdu')
v.fuel_card_id=card_id;v.has_fuel_card=bool(card_id);db.session.commit();return response(vehicle_dict(v),'Zapisano kartę pojazdu')
@api.post('/vehicles/<int:vehicle_id>/shares')
@login_required
@@ -117,8 +117,7 @@ def share_vehicle(vehicle_id):
if current_user.role!='admin' and v.owner_id!=current_user.id: return fail('Brak uprawnień',403)
d=payload(); u=User.query.filter_by(email=(d.get('email') or '').strip().lower()).first()
if not u:return fail('Nie znaleziono użytkownika',404)
if u not in v.drivers:v.drivers.append(u);db.session.commit()
socketio.emit('app_changed',{'resource':'vehicle_share','id':v.id});return response(vehicle_dict(v),'Udostępniono pojazd')
if u not in v.drivers:v.drivers.append(u);db.session.commit();return response(vehicle_dict(v),'Udostępniono pojazd')
@api.delete('/vehicles/<int:vehicle_id>/shares/<int:user_id>')
@login_required
@@ -126,8 +125,7 @@ def unshare_vehicle(vehicle_id,user_id):
v=Vehicle.query.get_or_404(vehicle_id)
if current_user.role!='admin' and v.owner_id!=current_user.id:return fail('Brak uprawnień',403)
u=User.query.get_or_404(user_id)
if u in v.drivers:v.drivers.remove(u);db.session.commit()
socketio.emit('app_changed',{'resource':'vehicle_share','id':v.id});return response(vehicle_dict(v),'Odebrano dostęp')
if u in v.drivers:v.drivers.remove(u);db.session.commit();return response(vehicle_dict(v),'Odebrano dostęp')
@api.put('/vehicles/<int:vehicle_id>/card-policy')
@login_required
@@ -136,7 +134,7 @@ def card_policy(vehicle_id):
if current_user.role!='admin' and v.owner_id!=current_user.id:return fail('Brak uprawnień',403)
d=payload();p=v.fuel_card_policy or FuelCardPolicy(vehicle=v)
p.use_orlen_last_price=False;p.discount_percent=Decimal(d.get('discount_percent') or 0);p.surcharge_per_liter=Decimal(d.get('surcharge_per_liter') or 0);p.description=(d.get('description') or '').strip() or None
db.session.add(p);db.session.commit();socketio.emit('app_changed',{'resource':'card_policy','id':v.id});return response(message='Zapisano zasady rozliczeń')
db.session.add(p);db.session.commit();return response(message='Zapisano zasady rozliczeń')
@api.post('/fuel-entries')
@login_required
@@ -164,7 +162,7 @@ def create_fuel_entry():
rule=FuelCardStationRule.query.filter_by(fuel_card_id=card.id,station_company_id=station_company.id).first()
if rule and not rule.allowed:return fail('Ta stacja jest zablokowana dla wybranej karty paliwowej',403)
e=FuelEntry(vehicle_id=vehicle.id,user_id=current_user.id,fueled_at=fueled_at,liters=Decimal(d['liters']),price_per_liter=Decimal(d['price_per_liter']),fuel_type=d['fuel_type'],odometer=odo,station=station_company.company_name if station_company else d.get('station'),station_company_id=station_company.id if station_company else None,fuel_card_id=card.id if used_card else None,invoice_number=d.get('invoice_number'),used_fuel_card=used_card,wholesale_price=wholesale,wholesale_source=source)
vehicle.current_odometer=odo;db.session.add(e);db.session.commit();socketio.emit('fuel_added',{'vehicle':vehicle.name,'gross':round(e.gross,2)});return response({'id':e.id,'redirect':url_for('main.dashboard')},'Zapisano tankowanie',201)
vehicle.current_odometer=odo;db.session.add(e);db.session.commit();return response({'id':e.id,'redirect':url_for('main.dashboard')},'Zapisano tankowanie',201)
except Exception as exc:db.session.rollback();return fail(str(exc),400)
@api.get('/orlen/prices')
@@ -192,7 +190,7 @@ def orlen_sync():
x.fetched_at=datetime.utcnow();updated+=1
else:db.session.add(OrlenPrice(**row));added+=1
result[fuel]={'added':added,'updated':updated};total+=added+updated
db.session.commit();socketio.emit('app_changed',{'resource':'orlen'});return response(result,f'Przetworzono {total} rekordów')
db.session.commit();return response(result,f'Przetworzono {total} rekordów')
except Exception as exc:db.session.rollback();return fail(str(exc),502)
@api.get('/orlen/preview')
@@ -251,7 +249,6 @@ def delete_user(user_id):
user.favorite_stations.clear()
db.session.delete(user)
db.session.commit()
socketio.emit('app_changed', {'resource':'users','deleted_id':user_id})
return response(message='Usunięto użytkownika')
@api.get('/settings')
@@ -265,7 +262,7 @@ def update_settings():
d=payload();s=CompanySettings.query.first()
try:
s.name=d['name'];s.entity_type=d['entity_type'];s.vat_rate=Decimal(d['vat_rate']);s.vat_deduction_percent=Decimal(d['vat_deduction_percent']);s.region=d['region'].strip().lower();s.invoice_split_day=int(d.get('invoice_split_day') or 15)
db.session.merge(AppSetting(key='invoice_split_enabled',value='1' if boolv(d,'invoice_split_enabled') else '0'));db.session.commit();socketio.emit('app_changed',{'resource':'settings'});return response(message='Zapisano ustawienia')
db.session.merge(AppSetting(key='invoice_split_enabled',value='1' if boolv(d,'invoice_split_enabled') else '0'));db.session.commit();return response(message='Zapisano ustawienia')
except Exception as exc:db.session.rollback();return fail(str(exc))
@@ -279,7 +276,7 @@ def get_app_settings():
def update_app_settings():
d=payload();theme=d.get('theme','bootstrap')
if theme not in THEMES:return fail('Nieprawidłowy motyw')
db.session.merge(AppSetting(key='theme',value=theme));db.session.commit();socketio.emit('app_changed',{'resource':'app_settings'});return response(message='Zapisano ustawienia aplikacji')
db.session.merge(AppSetting(key='theme',value=theme));db.session.commit();return response(message='Zapisano ustawienia aplikacji')
@api.get('/fuel-cards')
@login_required
@@ -295,7 +292,7 @@ def create_fuel_card():
company_id=int(d.get('company_id') or current_user.company_id or CompanySettings.query.first().id)
if current_user.role=='boss' and company_id!=current_user.company_id:return fail('Brak uprawnień',403)
card=FuelCard(name=d['name'].strip(),provider=d['provider'].strip(),description=(d.get('description') or '').strip() or None,active=True,company_id=company_id)
db.session.add(card);db.session.commit();socketio.emit('app_changed',{'resource':'fuel_cards'});return response({'id':card.id},'Dodano kartę paliwową',201)
db.session.add(card);db.session.commit();return response({'id':card.id},'Dodano kartę paliwową',201)
except Exception as exc:db.session.rollback();return fail(str(getattr(exc,'orig',exc)))
@api.put('/fuel-cards/<int:card_id>')
@@ -330,7 +327,6 @@ def delete_fuel_card(card_id):
company_id = card.company_id
db.session.delete(card)
db.session.commit()
socketio.emit('app_changed', {'resource':'fuel_cards', 'deleted_id':card_id})
return response(
{'redirect':url_for('main.admin_companies', company_id=company_id)},
'Usunięto kartę flotową',
@@ -342,7 +338,7 @@ def update_card_station_rule(card_id,station_id):
FuelCard.query.get_or_404(card_id);FuelStationCompany.query.get_or_404(station_id);d=payload()
rule=FuelCardStationRule.query.filter_by(fuel_card_id=card_id,station_company_id=station_id).first() or FuelCardStationRule(fuel_card_id=card_id,station_company_id=station_id)
rule.allowed=boolv(d,'allowed');rule.use_orlen_last_price=boolv(d,'use_orlen_last_price');rule.discount_net_percent=Decimal(d.get('discount_net_percent') or 0);rule.surcharge_net_per_liter=Decimal(d.get('surcharge_net_per_liter') or 0)
db.session.add(rule);db.session.commit();socketio.emit('app_changed',{'resource':'card_station_rule'});return response(message='Zapisano warunki karty dla stacji')
db.session.add(rule);db.session.commit();return response(message='Zapisano warunki karty dla stacji')
@api.get('/stations')
@login_required
@@ -381,7 +377,7 @@ def favorite_stations():
except Exception: return fail('Nieprawidłowa lista stacji')
if len(ids)>10:return fail('Użytkownik może mieć maksymalnie 10 ulubionych stacji')
current_user.favorite_stations=FuelStationCompany.query.filter(FuelStationCompany.id.in_(ids),FuelStationCompany.active.is_(True)).all() if ids else []
db.session.commit();socketio.emit('app_changed',{'resource':'favorite_stations','user_id':current_user.id});return response([station_dict(x) for x in current_user.favorite_stations],'Zapisano ulubione stacje')
db.session.commit();return response([station_dict(x) for x in current_user.favorite_stations],'Zapisano ulubione stacje')
@api.put('/settings/allowed-stations')
@role_required('boss','admin')
@@ -390,7 +386,7 @@ def allowed_stations():
try: ids=[int(x) for x in ids]
except Exception: return fail('Nieprawidłowa lista stacji')
settings=CompanySettings.query.first();settings.allowed_stations=FuelStationCompany.query.filter(FuelStationCompany.id.in_(ids),FuelStationCompany.active.is_(True)).all() if ids else []
db.session.commit();socketio.emit('app_changed',{'resource':'allowed_stations'});return response([station_dict(x) for x in settings.allowed_stations],'Zapisano dozwolone stacje')
db.session.commit();return response([station_dict(x) for x in settings.allowed_stations],'Zapisano dozwolone stacje')
@api.post('/stations/sync')
@role_required('boss','admin')
@@ -398,7 +394,7 @@ def stations_sync():
try:
companies=aggregate_ure_companies(fetch_ure_stations())
added,updated=sync_station_catalog(companies)
db.session.commit();socketio.emit('app_changed',{'resource':'stations'});return response({'added':added,'updated':updated},f'Katalog URE: dodano {added}, zaktualizowano {updated}')
db.session.commit();return response({'added':added,'updated':updated},f'Katalog URE: dodano {added}, zaktualizowano {updated}')
except Exception as exc:db.session.rollback();return fail(f'Nie udało się pobrać danych URE: {exc}',502)
@api.put('/stations/<int:station_id>')
@@ -419,7 +415,7 @@ def update_station(station_id):
s.active=boolv(d,'active');allowed=boolv(d,'allowed')
if allowed and s not in settings.allowed_stations: settings.allowed_stations.append(s)
if not allowed and s in settings.allowed_stations: settings.allowed_stations.remove(s)
db.session.commit();socketio.emit('app_changed',{'resource':'stations','company_id':settings.id});return response(station_dict(s),f'Zapisano ustawienia stacji dla firmy {settings.name}')
db.session.commit();return response(station_dict(s),f'Zapisano ustawienia stacji dla firmy {settings.name}')
@api.get('/companies')
@role_required('boss','admin')
@@ -460,7 +456,6 @@ def companies_delete(company_id):
company.allowed_stations.clear()
db.session.delete(company)
db.session.commit()
socketio.emit('app_changed', {'resource':'company','deleted_id':company_id})
return response({'redirect':url_for('main.admin_companies')}, 'Usunięto firmę')
@api.put('/companies/<int:company_id>')
@@ -470,7 +465,7 @@ def companies_update(company_id):
if current_user.role=='boss' and current_user.company_id!=c.id:return fail('Brak uprawnień',403)
try:
c.name=(d.get('name') or c.name).strip();c.entity_type=d.get('entity_type',c.entity_type);c.vat_rate=Decimal(d.get('vat_rate') or c.vat_rate);c.vat_deduction_percent=Decimal(d.get('vat_deduction_percent') or c.vat_deduction_percent);c.region=(d.get('region') or c.region).lower();c.invoice_split_day=int(d.get('invoice_split_day') or c.invoice_split_day);c.active=boolv(d,'active')
db.session.commit();socketio.emit('app_changed',{'resource':'company','id':c.id});return response(message='Zapisano firmę')
db.session.commit();return response(message='Zapisano firmę')
except Exception as exc:db.session.rollback();return fail(str(exc))
@api.put('/companies/<int:company_id>/favorite-stations')
@@ -483,7 +478,7 @@ def company_favorites(company_id):
except Exception:return fail('Nieprawidłowa lista stacji')
if len(ids)>25:return fail('Firma może mieć maksymalnie 25 ulubionych stacji')
c.favorite_stations=FuelStationCompany.query.filter(FuelStationCompany.id.in_(ids),FuelStationCompany.active.is_(True)).all() if ids else []
db.session.commit();socketio.emit('app_changed',{'resource':'company_favorites','company_id':c.id});return response(message='Zapisano ulubione stacje firmy')
db.session.commit();return response(message='Zapisano ulubione stacje firmy')
@api.put('/companies/<int:company_id>/station-access')
@@ -495,7 +490,7 @@ def company_station_access(company_id):
modes={'all_prefer_favorites','all','allowed_only','favorites_allowed_only'}
if mode not in modes:return fail('Nieprawidłowy tryb dostępu do stacji')
company.station_access_mode=mode
db.session.commit();socketio.emit('app_changed',{'resource':'station_access','company_id':company.id})
db.session.commit()
return response({'station_access_mode':mode},'Zapisano politykę dostępu do stacji')
@api.put('/companies/<int:company_id>/allowed-stations')
@@ -507,7 +502,7 @@ def company_allowed_stations(company_id):
try: ids=[int(x) for x in ids]
except Exception:return fail('Nieprawidłowa lista stacji')
company.allowed_stations=FuelStationCompany.query.filter(FuelStationCompany.id.in_(ids),FuelStationCompany.active.is_(True)).all() if ids else []
db.session.commit();socketio.emit('app_changed',{'resource':'allowed_stations','company_id':company.id})
db.session.commit()
message='Wszystkie aktywne stacje są dozwolone' if not ids else 'Zapisano zamkniętą listę dozwolonych stacji'
return response([station_dict(x) for x in company.allowed_stations],message)
@@ -520,4 +515,4 @@ def company_favorite_toggle(company_id,station_id):
else:
if len(c.favorite_stations)>=25:return fail('Firma może mieć maksymalnie 25 ulubionych stacji')
c.favorite_stations.append(s);state=True
db.session.commit();socketio.emit('app_changed',{'resource':'company_favorites','company_id':c.id});return response({'favorite':state},'Zmieniono ulubione stacje')
db.session.commit();return response({'favorite':state},'Zmieniono ulubione stacje')