This commit is contained in:
Felix Baumann
2026-06-28 10:20:36 +00:00
parent 64b32d0b44
commit 148efd919d
86 changed files with 2475 additions and 760 deletions
+8 -5
View File
@@ -1,4 +1,4 @@
# Generated by Django 6.0.6 on 2026-06-27 17:19
# Generated by Django 6.0.6 on 2026-06-28 10:19
import django.db.models.deletion
from django.conf import settings
@@ -46,12 +46,15 @@ class Migration(migrations.Migration):
('projects_inventory_shopping_add', models.BooleanField(default=False, help_text='Benutzer darf Einkaufspositionen erstellen.', verbose_name='Einkauf hinzufügen')),
('projects_inventory_shopping_edit', models.BooleanField(default=False, help_text='Benutzer darf Einkaufspositionen ändern.', verbose_name='Einkauf bearbeiten')),
('projects_inventory_shopping_delete', models.BooleanField(default=False, help_text='Benutzer darf Einkaufspositionen löschen.', verbose_name='Einkauf löschen')),
('projects_inventory_shopping_to_expense', models.BooleanField(default=False, help_text='Benutzer darf Einkäufe als erledigt markieren.', verbose_name='Einkäufe durchführen')),
('inventory_view', models.BooleanField(default=False, help_text='Benutzer darf Inventar einsehen.', verbose_name='Inventar anzeigen')),
('inventory_add', models.BooleanField(default=False, help_text='Benutzer darf Inventareinträge erstellen.', verbose_name='Inventar hinzufügen')),
('inventory_edit', models.BooleanField(default=False, help_text='Benutzer darf Inventareinträge ändern.', verbose_name='Inventar bearbeiten')),
('inventory_delete', models.BooleanField(default=False, help_text='Benutzer darf Inventareinträge löschen.', verbose_name='Inventar löschen')),
('invoices_view', models.BooleanField(default=False, help_text='Benutzer darf Rechnungen verwalten.', verbose_name='Rechnungsbereich anzeigen')),
('invoices_info', models.BooleanField(default=False, help_text='Benutzer darf Statistiken sehen.', verbose_name='Statistiken ansehen')),
('invoices_customers_view', models.BooleanField(default=False, help_text='Benutzer darf Kunden sehen.', verbose_name='Kunden anzeigen')),
('invoices_customers_info', models.BooleanField(default=False, help_text='Benutzer darf Kundenstatistiken sehen.', verbose_name='Kundenstatistiken ansehen')),
('invoices_customers_detail_view', models.BooleanField(default=False, help_text='Benutzer darf Details des Kunden sehen.', verbose_name='Kundendetails anzeigen')),
('invoices_customers_add', models.BooleanField(default=False, help_text='Benutzer darf Kunden anlegen.', verbose_name='Kunden erstellen')),
('invoices_customers_edit', models.BooleanField(default=False, help_text='Benutzer darf Kunden ändern.', verbose_name='Kunden bearbeiten')),
@@ -62,6 +65,7 @@ class Migration(migrations.Migration):
('invoices_items_edit', models.BooleanField(default=False, help_text='Benutzer darf Artikel ändern.', verbose_name='Artikel bearbeiten')),
('invoices_items_delete', models.BooleanField(default=False, help_text='Benutzer darf Artikel löschen.', verbose_name='Artikel löschen')),
('invoices_invoices_view', models.BooleanField(default=False, help_text='Benutzer darf Rechnungen sehen.', verbose_name='Rechnungen anzeigen')),
('invoices_invoices_info', models.BooleanField(default=False, help_text='Benutzer darf Rechnungsstatistiken sehen.', verbose_name='Rechnungsstatistiken ansehen')),
('invoices_invoices_project_add', models.BooleanField(default=False, help_text='Benutzer darf Rechnungen aus Projekten erstellen.', verbose_name='Projekt-Rechnung erstellen')),
('invoices_invoices_customer_add', models.BooleanField(default=False, help_text='Benutzer darf Rechnungen für Kunden erstellen.', verbose_name='Kunden-Rechnung erstellen')),
('invoices_invoices_invoices_view', models.BooleanField(default=False, help_text='Benutzer darf Rechnungsdetails sehen.', verbose_name='Rechnungsdetails anzeigen')),
@@ -72,24 +76,23 @@ class Migration(migrations.Migration):
('invoices_invoices_invoices_cancel', models.BooleanField(default=False, help_text='Benutzer darf Rechnungen stornieren.', verbose_name='Rechnung stornieren')),
('invoices_invoices_invoices_paid', models.BooleanField(default=False, help_text='Benutzer darf Rechnungsstatus ändern.', verbose_name='Rechnung auf bezahlt setzen')),
('invoices_invoices_invoices_delete', models.BooleanField(default=False, help_text='Benutzer darf Rechnungen löschen.', verbose_name='Rechnungen löschen')),
('invoices_invoices_invoices_overdue', models.BooleanField(default=False, help_text='Benutzer darf überfällige Rechnungen einsehen.', verbose_name='Überfällige Rechnungen anzeigen')),
('invoices_offers_view', models.BooleanField(default=False, help_text='Benutzer darf Angebote sehen.', verbose_name='Angebote anzeigen')),
('invoices_offers_info', models.BooleanField(default=False, help_text='Benutzer darf Angebotsstatistiken sehen.', verbose_name='Angebotsstatistiken ansehen')),
('invoices_offers_add', models.BooleanField(default=False, help_text='Benutzer darf Angebote für Kunden erstellen.', verbose_name='Angebot erstellen')),
('invoices_offers_offers_view', models.BooleanField(default=False, help_text='Benutzer darf Angebotsdetails sehen.', verbose_name='Angebotsdetails anzeigen')),
('invoices_offers_offers_item_add', models.BooleanField(default=False, help_text='Benutzer darf Positionen hinzufügen.', verbose_name='Angebotsposition hinzufügen')),
('invoices_offers_offers_item_delete', models.BooleanField(default=False, help_text='Benutzer darf Positionen löschen.', verbose_name='Angebotsposition löschen')),
('invoices_offers_offers_preview', models.BooleanField(default=False, help_text='Benutzer darf Vorschauen öffnen.', verbose_name='Angebotsvorschau anzeigen')),
('invoices_offers_offers_download', models.BooleanField(default=False, help_text='Benutzer darf Angebote herunterladen.', verbose_name='Angebot herunterladen')),
('invoices_offers_offers_status', models.BooleanField(default=False, help_text='Benutzer darf Angebotsstatus ändern.', verbose_name='Angebotsstatus bearbeiten')),
('invoices_offers_offers_delete', models.BooleanField(default=False, help_text='Benutzer darf Angebote löschen.', verbose_name='Angebote löschen')),
('invoices_reminders_view', models.BooleanField(default=False, help_text='Benutzer darf Mahnungen einsehen.', verbose_name='Mahnungen anzeigen')),
('invoices_reminders_info', models.BooleanField(default=False, help_text='Benutzer darf Mahnungsstatistiken sehen.', verbose_name='Mahnungsstatistiken ansehen')),
('invoices_reminders_add', models.BooleanField(default=False, help_text='Benutzer darf Mahnungen erstellen.', verbose_name='Mahnungen hinzufügen')),
('invoices_reminders_reminders_view', models.BooleanField(default=False, help_text='Benutzer darf Zahlungserinnerungen einsehen.', verbose_name='Erinnerungen anzeigen')),
('invoices_reminders_reminders_cancel', models.BooleanField(default=False, help_text='Benutzer darf Zahlungserinnerungen stornieren.', verbose_name='Erinnerungen stornieren')),
('invoices_reminders_reminders_delete', models.BooleanField(default=False, help_text='Benutzer darf Zahlungserinnerungen löschen.', verbose_name='Erinnerungen löschen')),
('invoices_reminders_reminders_download', models.BooleanField(default=False, help_text='Benutzer darf Zahlungserinnerungen herunterladen.', verbose_name='Erinnerungen herunterladen')),
('invoices_reminders_reminders_paid', models.BooleanField(default=False, help_text='Benutzer darf Zahlungserinnerungen als bezahlt markieren.', verbose_name='Erinnerungen als bezahlt markieren')),
('invoices_reminders_reminders_expire', models.BooleanField(default=False, help_text='Benutzer darf Zahlungserinnerungen als abgelaufen markieren.', verbose_name='Erinnerungen ablaufen lassen')),
('invoices_payments_view', models.BooleanField(default=False, help_text='Benutzer darf Zahlungen einsehen.', verbose_name='Zahlungen anzeigen')),
('users_view', models.BooleanField(default=False, help_text='Benutzer darf Mitarbeiter sehen.', verbose_name='Benutzer anzeigen')),
('users_add', models.BooleanField(default=False, help_text='Benutzer darf neue Mitarbeiter anlegen.', verbose_name='Benutzer erstellen')),
('users_edit', models.BooleanField(default=False, help_text='Benutzer darf Mitarbeiter bearbeiten.', verbose_name='Benutzer bearbeiten')),
+8 -6
View File
@@ -42,7 +42,7 @@ class Role(models.Model):
projects_inventory_shopping_add = models.BooleanField(default=False, verbose_name="Einkauf hinzufügen", help_text="Benutzer darf Einkaufspositionen erstellen.")
projects_inventory_shopping_edit = models.BooleanField(default=False, verbose_name="Einkauf bearbeiten", help_text="Benutzer darf Einkaufspositionen ändern.")
projects_inventory_shopping_delete = models.BooleanField(default=False, verbose_name="Einkauf löschen", help_text="Benutzer darf Einkaufspositionen löschen.")
#projects_inventory_shopping_buy = models.BooleanField(default=False, verbose_name="Einkäufe durchführen", help_text="Benutzer darf Einkäufe als erledigt markieren.")
projects_inventory_shopping_to_expense = models.BooleanField(default=False, verbose_name="Einkäufe durchführen", help_text="Benutzer darf Einkäufe als erledigt markieren.")
# =====================
@@ -58,8 +58,10 @@ class Role(models.Model):
# Rechnungen
# =====================
invoices_view = models.BooleanField(default=False, verbose_name="Rechnungsbereich anzeigen", help_text="Benutzer darf Rechnungen verwalten.")
invoices_info = models.BooleanField(default=False, verbose_name="Statistiken ansehen", help_text="Benutzer darf Statistiken sehen.")
invoices_customers_view = models.BooleanField(default=False, verbose_name="Kunden anzeigen", help_text="Benutzer darf Kunden sehen.")
invoices_customers_info = models.BooleanField(default=False, verbose_name="Kundenstatistiken ansehen", help_text="Benutzer darf Kundenstatistiken sehen.")
invoices_customers_detail_view = models.BooleanField(default=False, verbose_name="Kundendetails anzeigen", help_text="Benutzer darf Details des Kunden sehen.")
invoices_customers_add = models.BooleanField(default=False, verbose_name="Kunden erstellen", help_text="Benutzer darf Kunden anlegen.")
invoices_customers_edit = models.BooleanField(default=False, verbose_name="Kunden bearbeiten", help_text="Benutzer darf Kunden ändern.")
@@ -72,6 +74,7 @@ class Role(models.Model):
invoices_items_delete = models.BooleanField(default=False, verbose_name="Artikel löschen", help_text="Benutzer darf Artikel löschen.")
invoices_invoices_view = models.BooleanField(default=False, verbose_name="Rechnungen anzeigen", help_text="Benutzer darf Rechnungen sehen.")
invoices_invoices_info = models.BooleanField(default=False, verbose_name="Rechnungsstatistiken ansehen", help_text="Benutzer darf Rechnungsstatistiken sehen.")
invoices_invoices_project_add = models.BooleanField(default=False, verbose_name="Projekt-Rechnung erstellen", help_text="Benutzer darf Rechnungen aus Projekten erstellen.")
invoices_invoices_customer_add = models.BooleanField(default=False, verbose_name="Kunden-Rechnung erstellen", help_text="Benutzer darf Rechnungen für Kunden erstellen.")
invoices_invoices_invoices_view = models.BooleanField(default=False, verbose_name="Rechnungsdetails anzeigen", help_text="Benutzer darf Rechnungsdetails sehen.")
@@ -82,27 +85,26 @@ class Role(models.Model):
invoices_invoices_invoices_cancel = models.BooleanField(default=False, verbose_name="Rechnung stornieren", help_text="Benutzer darf Rechnungen stornieren.")
invoices_invoices_invoices_paid = models.BooleanField(default=False, verbose_name="Rechnung auf bezahlt setzen", help_text="Benutzer darf Rechnungsstatus ändern.")
invoices_invoices_invoices_delete = models.BooleanField(default=False, verbose_name="Rechnungen löschen", help_text="Benutzer darf Rechnungen löschen.")
invoices_invoices_invoices_overdue = models.BooleanField(default=False, verbose_name="Überfällige Rechnungen anzeigen", help_text="Benutzer darf überfällige Rechnungen einsehen.")
invoices_offers_view = models.BooleanField(default=False, verbose_name="Angebote anzeigen", help_text="Benutzer darf Angebote sehen.")
invoices_offers_info = models.BooleanField(default=False, verbose_name="Angebotsstatistiken ansehen", help_text="Benutzer darf Angebotsstatistiken sehen.")
invoices_offers_add = models.BooleanField(default=False, verbose_name="Angebot erstellen", help_text="Benutzer darf Angebote für Kunden erstellen.")
invoices_offers_offers_view = models.BooleanField(default=False, verbose_name="Angebotsdetails anzeigen", help_text="Benutzer darf Angebotsdetails sehen.")
invoices_offers_offers_item_add = models.BooleanField(default=False, verbose_name="Angebotsposition hinzufügen", help_text="Benutzer darf Positionen hinzufügen.")
invoices_offers_offers_item_delete = models.BooleanField(default=False, verbose_name="Angebotsposition löschen", help_text="Benutzer darf Positionen löschen.")
invoices_offers_offers_preview = models.BooleanField(default=False, verbose_name="Angebotsvorschau anzeigen", help_text="Benutzer darf Vorschauen öffnen.")
invoices_offers_offers_download = models.BooleanField(default=False, verbose_name="Angebot herunterladen", help_text="Benutzer darf Angebote herunterladen.")
invoices_offers_offers_status = models.BooleanField(default=False, verbose_name="Angebotsstatus bearbeiten", help_text="Benutzer darf Angebotsstatus ändern.")
invoices_offers_offers_delete = models.BooleanField(default=False, verbose_name="Angebote löschen", help_text="Benutzer darf Angebote löschen.")
invoices_reminders_view = models.BooleanField(default=False, verbose_name="Mahnungen anzeigen", help_text="Benutzer darf Mahnungen einsehen.")
invoices_reminders_info = models.BooleanField(default=False, verbose_name="Mahnungsstatistiken ansehen", help_text="Benutzer darf Mahnungsstatistiken sehen.")
invoices_reminders_add = models.BooleanField(default=False, verbose_name="Mahnungen hinzufügen", help_text="Benutzer darf Mahnungen erstellen.")
invoices_reminders_reminders_view = models.BooleanField(default=False, verbose_name="Erinnerungen anzeigen", help_text="Benutzer darf Zahlungserinnerungen einsehen.")
invoices_reminders_reminders_cancel = models.BooleanField(default=False, verbose_name="Erinnerungen stornieren", help_text="Benutzer darf Zahlungserinnerungen stornieren.")
invoices_reminders_reminders_delete = models.BooleanField(default=False, verbose_name="Erinnerungen löschen", help_text="Benutzer darf Zahlungserinnerungen löschen.")
invoices_reminders_reminders_download = models.BooleanField(default=False, verbose_name="Erinnerungen herunterladen", help_text="Benutzer darf Zahlungserinnerungen herunterladen.")
invoices_reminders_reminders_paid = models.BooleanField(default=False, verbose_name="Erinnerungen als bezahlt markieren", help_text="Benutzer darf Zahlungserinnerungen als bezahlt markieren.")
invoices_reminders_reminders_expire = models.BooleanField(default=False, verbose_name="Erinnerungen ablaufen lassen", help_text="Benutzer darf Zahlungserinnerungen als abgelaufen markieren.")
invoices_payments_view = models.BooleanField(default=False, verbose_name="Zahlungen anzeigen", help_text="Benutzer darf Zahlungen einsehen.")
# =====================
# Benutzerverwaltung
# =====================
+40 -41
View File
@@ -1,60 +1,60 @@
{% extends "base.html" %}
{% block title %}
Login
{% endblock %}
{% block title %}Login{% endblock %}
{% block header_title %}
<div class="flex justify-center">
{% if company_settings.logo %}
<img src="{{ company_settings.logo.url }}" alt="" class="h-32">
{% elif company_settings.companyname %}
{{ company_settings.companyname }}
{% else %}
Projektverwaltung
{% endif %}
</div>
{% endblock %}
{% block header_description %}
{% endblock %}
{% block header %}{% endblock %}
{% block content %}
<div class="fixed inset-0 flex justify-center items-center">
<div class="p-8 rounded-2xl shadow-lg bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors w-full max-w-md">
<div class="flex justify-center items-center min-h-[80vh]">
<!-- Logo / Firmenname -->
<div class="flex justify-center mb-6">
{% if company_settings.logo %}
<img src="{{ company_settings.logo.url }}" alt="" class="h-30 object-contain">
{% elif company_settings.companyname %}
<span class="text-2xl font-bold tracking-tight">{{ company_settings.companyname }}</span>
{% else %}
<span class="text-2xl font-bold tracking-tight">Projektverwaltung</span>
{% endif %}
</div>
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors w-full max-w-md">
<!-- Trennlinie mit Company Color -->
<div class="h-0.5 rounded-full mb-6" style="background: var(--company-color, #6366f1);"></div>
<h1 class="text-3xl font-bold text-center mb-6">
Anmelden
</h1>
<h1 class="text-xl font-semibold text-center mb-6">Anmelden</h1>
<form method="post" class="space-y-4">
{% csrf_token %}
{% for field in form %}
<div class="space-y-1">
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300">
{{ field.label }}
</label>
<input
type="{{ field.field.widget.input_type }}"
name="{{ field.html_name }}"
id="{{ field.id_for_label }}"
{% if field.value %}value="{{ field.value }}"{% endif %}
class="w-full px-4 py-3 rounded-lg border border-slate-300 dark:border-slate-600 bg-slate-50 dark:bg-slate-700 text-slate-900 dark:text-white placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition"
placeholder="{{ field.label }}"
>
{% if field.errors %}
<p class="text-sm text-red-500">{{ field.errors|join:", " }}</p>
{% endif %}
</div>
<div class="space-y-1">
<label for="{{ field.id_for_label }}"
class="block text-sm font-medium text-slate-700 dark:text-slate-300">
{{ field.label }}
</label>
<input
type="{{ field.field.widget.input_type }}"
name="{{ field.html_name }}"
id="{{ field.id_for_label }}"
{% if field.value %}value="{{ field.value }}"{% endif %}
placeholder="{{ field.label }}"
class="mt-1 w-full px-4 py-2 rounded-lg border border-slate-300 dark:border-slate-600
bg-slate-50 dark:bg-slate-700 text-slate-900 dark:text-white
placeholder-slate-400 focus:outline-none focus:ring-2
focus:border-transparent transition"
style="--tw-ring-color: var(--company-color, #6366f1);"
>
{% if field.errors %}
<p class="text-sm text-red-500">{{ field.errors|join:", " }}</p>
{% endif %}
</div>
{% endfor %}
<button
type="submit"
class="btn w-full btn-action"
class="w-full py-3 rounded-lg font-semibold text-white transition hover:opacity-90 active:scale-95 mt-2"
style="background: var(--company-color, #6366f1);"
>
Anmelden
</button>
@@ -62,7 +62,6 @@ Login
</form>
</div>
</div>
{% endblock %}
+4 -4
View File
@@ -18,7 +18,7 @@ Mitarbeiter, Rollen und Berechtigungen verwalten
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
<div class="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-4">
<div>
<h2 class="text-xl font-bold">Aktionen</h2>
<h2 class="text-lg font-bold">Aktionen</h2>
<p class="text-slate-400 text-sm mt-1">Mitarbeiter oder Rollen hinzufügen</p>
</div>
@@ -35,7 +35,7 @@ Mitarbeiter, Rollen und Berechtigungen verwalten
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors mb-8">
<div class="mb-6">
<h2 class="text-xl font-bold">
<h2 class="text-lg font-bold">
Benutzer
</h2>
@@ -59,7 +59,7 @@ Mitarbeiter, Rollen und Berechtigungen verwalten
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors mb-8">
<div class="mb-6">
<h2 class="text-xl font-bold">
<h2 class="text-lg font-bold">
Archivierte Benutzer
</h2>
@@ -79,7 +79,7 @@ Mitarbeiter, Rollen und Berechtigungen verwalten
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors mt-8">
<div class="mb-6">
<h2 class="text-xl font-bold">
<h2 class="text-lg font-bold">
Rollen
</h2>
@@ -91,7 +91,7 @@
type="text"
disabled
value="{{ item.last_login|date:'d.m.Y H:i' }}"
class="border rounded px-3 py-2 w-full bg-slate-100">
class="border rounded px-3 py-2 w-full bg-slate-100 dark:bg-slate-700">
</div>
@@ -86,12 +86,11 @@
<label class="block text-sm mb-1">
Letzter Login
</label>
<input
type="text"
disabled
value="{{ item.last_login|date:'d.m.Y H:i' }}"
class="border rounded px-3 py-2 w-full bg-slate-100">
class="border rounded px-3 py-2 w-full bg-slate-100 dark:bg-slate-700">
</div>