uprawnienia do stacji i usuwanie firm
This commit is contained in:
+33
@@ -303,6 +303,39 @@ def create_fuel_card():
|
||||
def update_fuel_card(card_id):
|
||||
card=FuelCard.query.get_or_404(card_id);d=payload();card.name=d.get('name',card.name).strip();card.provider=d.get('provider',card.provider).strip();card.description=(d.get('description') or '').strip() or None;card.active=boolv(d,'active');db.session.commit();return response(message='Zapisano kartę')
|
||||
|
||||
@api.delete('/fuel-cards/<int:card_id>')
|
||||
@role_required('boss','admin')
|
||||
def delete_fuel_card(card_id):
|
||||
card = FuelCard.query.get_or_404(card_id)
|
||||
if current_user.role == 'boss' and card.company_id != current_user.company_id:
|
||||
return fail('Brak uprawnień', 403)
|
||||
|
||||
users_count = User.query.filter_by(fuel_card_id=card.id).count()
|
||||
vehicles_count = Vehicle.query.filter_by(fuel_card_id=card.id).count()
|
||||
entries_count = FuelEntry.query.filter_by(fuel_card_id=card.id).count()
|
||||
blockers = []
|
||||
if users_count:
|
||||
blockers.append(f'{users_count} użytkowników')
|
||||
if vehicles_count:
|
||||
blockers.append(f'{vehicles_count} pojazdów')
|
||||
if entries_count:
|
||||
blockers.append(f'{entries_count} tankowań')
|
||||
if blockers:
|
||||
return fail(
|
||||
'Nie można usunąć karty, ponieważ jest przypisana do: ' + ', '.join(blockers) +
|
||||
'. Najpierw odłącz kartę od użytkowników i pojazdów. Karty użytej w tankowaniach nie można usunąć; możesz ją wyłączyć.',
|
||||
409,
|
||||
)
|
||||
|
||||
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ą',
|
||||
)
|
||||
|
||||
@api.put('/fuel-cards/<int:card_id>/stations/<int:station_id>')
|
||||
@role_required('boss','admin')
|
||||
def update_card_station_rule(card_id,station_id):
|
||||
|
||||
+7
-2
@@ -146,6 +146,12 @@ def update_card_policy(vehicle_id):
|
||||
@login_required
|
||||
def fuel():
|
||||
vehicles = accessible_vehicles()
|
||||
settings = current_user.company or CompanySettings.query.first()
|
||||
if settings is None:
|
||||
flash("Najpierw utwórz firmę i przypisz do niej użytkownika, aby korzystać z tankowań.", "warning")
|
||||
if current_user.role in ("admin", "boss"):
|
||||
return redirect(url_for("main.admin_companies"))
|
||||
return redirect(url_for("main.dashboard"))
|
||||
if request.method == "POST":
|
||||
vehicle = next((v for v in vehicles if v.id == int(request.form["vehicle_id"])), None)
|
||||
if not vehicle:
|
||||
@@ -156,7 +162,7 @@ def fuel():
|
||||
fueled_at = datetime.fromisoformat(request.form["fueled_at"]); wholesale = None; source = None
|
||||
station_company_id = request.form.get("station_company_id", type=int)
|
||||
station_company = db.session.get(FuelStationCompany, station_company_id) if station_company_id else None
|
||||
settings = vehicle.company or current_user.company or CompanySettings.query.first()
|
||||
settings = vehicle.company or settings
|
||||
access_mode = settings.station_access_mode or "all_prefer_favorites"
|
||||
if station_company and access_mode == "allowed_only" and station_company not in settings.allowed_stations:
|
||||
response = error_response("Ta stacja nie jest dozwolona przez politykę firmy", 403); return response or redirect(url_for("main.fuel"))
|
||||
@@ -169,7 +175,6 @@ def fuel():
|
||||
station_label = station_company.company_name if station_company else request.form.get("station")
|
||||
e = FuelEntry(vehicle_id=vehicle.id, 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)
|
||||
vehicle.current_odometer = odometer; db.session.add(e); db.session.commit(); socketio.emit("fuel_added", {"vehicle": vehicle.name, "gross": round(e.gross,2)}); response = ok_response("Zapisano tankowanie", redirect=url_for("main.dashboard")); return response or redirect(url_for("main.dashboard"))
|
||||
settings=current_user.company or CompanySettings.query.first()
|
||||
allowed=list(settings.allowed_stations)
|
||||
company_favorites=list(settings.favorite_stations)
|
||||
access_mode=settings.station_access_mode or "all_prefer_favorites"
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
<div class="card mb-4"><div class="card-header"><strong>Karty paliwowe</strong></div><div class="card-body">
|
||||
<form action="/api/fuel-cards" method="post" class="ajax-form row g-3 mb-4"><input type="hidden" name="company_id" value="{{selected_company.id}}"><div class="col-md-4"><label class="form-label">Nazwa karty</label><input class="form-control" name="name" placeholder="Np. UTA – flota główna" required></div><div class="col-md-3"><label class="form-label">Operator karty</label><input class="form-control" name="provider" placeholder="UTA, DKV, Orlen" required></div><div class="col-md-3"><label class="form-label">Opis</label><input class="form-control" name="description" placeholder="Opcjonalnie"></div><div class="col-md-2 d-flex align-items-end"><button class="btn btn-primary w-100">Dodaj kartę</button></div></form>
|
||||
<div class="table-responsive"><table class="table table-hover align-middle mb-0"><thead><tr><th>Karta</th><th>Operator karty</th><th>Opis</th><th>Status</th></tr></thead><tbody>{% for card in fuel_cards %}<tr><td><strong>{{card.name}}</strong></td><td>{{card.provider}}</td><td>{{card.description or '—'}}</td><td><span class="badge {% if card.active %}text-bg-success{% else %}text-bg-secondary{% endif %}">{{'aktywna' if card.active else 'wyłączona'}}</span></td></tr>{% else %}<tr><td colspan="4" class="text-center text-body-secondary py-4">Brak kart paliwowych.</td></tr>{% endfor %}</tbody></table></div>
|
||||
<div class="table-responsive"><table class="table table-hover align-middle mb-0"><thead><tr><th>Karta</th><th>Operator karty</th><th>Opis</th><th>Status</th><th class="text-end">Akcje</th></tr></thead><tbody>{% for card in fuel_cards %}<tr><td><strong>{{card.name}}</strong></td><td>{{card.provider}}</td><td>{{card.description or '—'}}</td><td><span class="badge {% if card.active %}text-bg-success{% else %}text-bg-secondary{% endif %}">{{'aktywna' if card.active else 'wyłączona'}}</span></td><td class="text-end"><form action="/api/fuel-cards/{{ card.id }}" data-method="DELETE" class="ajax-form d-inline" onsubmit="return confirm('Usunąć kartę {{ card.name|e }}? Tej operacji nie można cofnąć.')"><button type="submit" class="btn btn-sm btn-outline-danger">Usuń</button></form></td></tr>{% else %}<tr><td colspan="5" class="text-center text-body-secondary py-4">Brak kart paliwowych.</td></tr>{% endfor %}</tbody></table></div>
|
||||
</div></div>
|
||||
|
||||
<div class="card"><div class="card-body d-flex flex-column flex-md-row justify-content-between align-items-md-center gap-3"><div><h2 class="h5 mb-1">Ulubione stacje firmy</h2><p class="text-body-secondary mb-0">Do 25 stacji. Pusta lista oznacza 10 największych sieci w Polsce.</p></div><button class="btn btn-secondary" data-bs-toggle="modal" data-bs-target="#companyFavoritesModal">Edytuj ulubione</button></div></div>
|
||||
|
||||
@@ -263,3 +263,56 @@ def test_admin_stations_without_company_shows_company_picker(tmp_path):
|
||||
assert 'Wybierz firmę' in html
|
||||
assert 'name="company_id"' in html
|
||||
assert 'Przejdź do konfiguracji' in html
|
||||
|
||||
|
||||
def test_fuel_without_company_redirects_instead_of_500(tmp_path):
|
||||
from app.extensions import db
|
||||
from app.models import CompanySettings, User
|
||||
|
||||
app = make_app(tmp_path, "fuel-no-company.db")
|
||||
client = app.test_client()
|
||||
client.post('/login', data={'email':'admin@example.com','password':'admin123!'})
|
||||
with app.app_context():
|
||||
User.query.update({User.company_id: None})
|
||||
CompanySettings.query.delete()
|
||||
db.session.commit()
|
||||
response = client.get('/fuel', follow_redirects=False)
|
||||
assert response.status_code == 302
|
||||
assert '/admin/companies' in response.headers['Location']
|
||||
|
||||
|
||||
def test_delete_unused_fuel_card(tmp_path):
|
||||
app=make_app(tmp_path, "delete_card.db")
|
||||
client=app.test_client()
|
||||
client.post('/login',data={'email':'admin@example.com','password':'admin123!'})
|
||||
with app.app_context():
|
||||
from app.extensions import db
|
||||
from app.models import CompanySettings, FuelCard
|
||||
company=CompanySettings.query.first()
|
||||
card=FuelCard(name='Karta do usunięcia',provider='Test',company_id=company.id)
|
||||
db.session.add(card);db.session.commit();card_id=card.id
|
||||
response=client.delete(f'/api/fuel-cards/{card_id}')
|
||||
assert response.status_code == 200
|
||||
assert response.json['ok'] is True
|
||||
with app.app_context():
|
||||
from app.models import FuelCard
|
||||
assert FuelCard.query.get(card_id) is None
|
||||
|
||||
|
||||
def test_cannot_delete_assigned_fuel_card(tmp_path):
|
||||
app=make_app(tmp_path, "assigned_card.db")
|
||||
client=app.test_client()
|
||||
client.post('/login',data={'email':'admin@example.com','password':'admin123!'})
|
||||
with app.app_context():
|
||||
from app.extensions import db
|
||||
from app.models import CompanySettings, FuelCard, User
|
||||
company=CompanySettings.query.first()
|
||||
card=FuelCard(name='Karta przypisana',provider='Test',company_id=company.id)
|
||||
db.session.add(card);db.session.flush()
|
||||
user=User.query.filter_by(email='admin@example.com').first()
|
||||
user.fuel_card_id=card.id
|
||||
db.session.commit();card_id=card.id
|
||||
response=client.delete(f'/api/fuel-cards/{card_id}')
|
||||
assert response.status_code == 409
|
||||
assert response.json['ok'] is False
|
||||
assert 'użytkowników' in response.json['message']
|
||||
|
||||
Reference in New Issue
Block a user