feat: Add complete Verpachtung management system

- Add LandVerpachtung model with Land and Paechter relationships
- Implement full CRUD operations for Verpachtungen
- Add responsive Bootstrap templates with JavaScript calculations
- Integrate document linking functionality similar to other entities
- Add navigation links and URL patterns
- Include CSV import support for Paechter data
- Fix template encoding issues for proper UTF-8 support
- Enhance administration interface with Verpachtung CSV import

This implements the complete Verpachtung management feature requested,
allowing users to manage land lease agreements with proper relationships
to properties (Laenderei) and tenants (Paechter), following the same
patterns as Foerderung/Destinataer relationships.
This commit is contained in:
Stiftung Development
2025-09-15 21:18:01 +02:00
parent c8bef800c8
commit 4be6be203e
14 changed files with 1743 additions and 127 deletions

View File

@@ -0,0 +1,421 @@
{% extends 'base.html' %}
{% load static %}
{% block title %}{{ title }} - Stiftungsverwaltung{% endblock %}
{% block content %}
<!-- Header -->
<div class="row mb-4">
<div class="col-md-8">
<h1 class="h3">
<i class="fas fa-handshake text-success me-2"></i>
{{ title }}
</h1>
<p class="text-muted">
{% if form.instance.land %}Länderei: {{ form.instance.land }}{% endif %}
{% if form.instance.paechter %} | Pächter: {{ form.instance.paechter.get_full_name }}{% endif %}
</p>
</div>
<div class="col-md-4 text-end">
<a href="{% if form.instance.pk %}{% url 'stiftung:verpachtung_detail' form.instance.pk %}{% else %}{% url 'stiftung:verpachtung_list' %}{% endif %}"
class="btn btn-outline-secondary">
<i class="fas fa-arrow-left me-2"></i>Abbrechen
</a>
</div>
</div>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="row">
<!-- Main Form -->
<div class="col-lg-8">
<div class="card shadow">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">
<i class="fas fa-user-tie me-2"></i>Verpachtungsdetails
</h6>
</div>
<div class="card-body">
<!-- Pächter und Grunddaten -->
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label for="{{ form.land.id_for_label }}" class="form-label">
<i class="fas fa-map-marked-alt me-1"></i>Länderei *
</label>
{{ form.land }}
{% if form.land.errors %}
<div class="invalid-feedback d-block">
{{ form.land.errors.0 }}
</div>
{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="{{ form.paechter.id_for_label }}" class="form-label">
<i class="fas fa-user me-1"></i>Pächter *
</label>
{{ form.paechter }}
{% if form.paechter.errors %}
<div class="invalid-feedback d-block">
{{ form.paechter.errors.0 }}
</div>
{% endif %}
</div>
</div>
</div>
<!-- Vertragsnummer und Status -->
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label for="{{ form.vertragsnummer.id_for_label }}" class="form-label">
<i class="fas fa-file-contract me-1"></i>Vertragsnummer *
</label>
{{ form.vertragsnummer }}
{% if form.vertragsnummer.errors %}
<div class="invalid-feedback d-block">
{{ form.vertragsnummer.errors.0 }}
</div>
{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="{{ form.status.id_for_label }}" class="form-label">
<i class="fas fa-flag me-1"></i>Status
</label>
{{ form.status }}
{% if form.status.errors %}
<div class="invalid-feedback d-block">
{{ form.status.errors.0 }}
</div>
{% endif %}
</div>
</div>
</div>
<!-- Pachtzeiten -->
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label for="{{ form.pachtbeginn.id_for_label }}" class="form-label">
<i class="fas fa-calendar me-1"></i>Pachtbeginn *
</label>
{{ form.pachtbeginn }}
{% if form.pachtbeginn.errors %}
<div class="invalid-feedback d-block">
{{ form.pachtbeginn.errors.0 }}
</div>
{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="{{ form.pachtende.id_for_label }}" class="form-label">
<i class="fas fa-calendar-times me-1"></i>Pachtende
</label>
{{ form.pachtende }}
{% if form.pachtende.errors %}
<div class="invalid-feedback d-block">
{{ form.pachtende.errors.0 }}
</div>
{% endif %}
<div class="form-text">Leer lassen für unbefristete Verpachtung</div>
</div>
</div>
</div>
<!-- Automatische Verlängerung -->
<div class="row">
<div class="col-md-12">
<div class="mb-3">
<div class="form-check">
{{ form.verlaengerung_klausel }}
<label class="form-check-label" for="{{ form.verlaengerung_klausel.id_for_label }}">
<i class="fas fa-refresh me-1"></i>Automatische Verlängerung
</label>
</div>
{% if form.verlaengerung_klausel.errors %}
<div class="invalid-feedback d-block">
{{ form.verlaengerung_klausel.errors.0 }}
</div>
{% endif %}
</div>
</div>
</div>
<!-- Flächeninformationen -->
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label for="{{ form.verpachtete_flaeche.id_for_label }}" class="form-label">
<i class="fas fa-expand-arrows-alt me-1"></i>Verpachtete Fläche (qm) *
</label>
{{ form.verpachtete_flaeche }}
{% if form.verpachtete_flaeche.errors %}
<div class="invalid-feedback d-block">
{{ form.verpachtete_flaeche.errors.0 }}
</div>
{% endif %}
<div class="form-text">
<span id="verpachtete_flaeche_ha">0,00 ha</span>
</div>
</div>
</div>
</div>
<!-- Pachtzins -->
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label for="{{ form.pachtzins_pauschal.id_for_label }}" class="form-label">
<i class="fas fa-euro-sign me-1"></i>Pachtzins pauschal/Jahr (€) *
</label>
{{ form.pachtzins_pauschal }}
{% if form.pachtzins_pauschal.errors %}
<div class="invalid-feedback d-block">
{{ form.pachtzins_pauschal.errors.0 }}
</div>
{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="{{ form.pachtzins_pro_ha.id_for_label }}" class="form-label">
<i class="fas fa-euro-sign me-1"></i>Pachtzins pro ha (€)
</label>
{{ form.pachtzins_pro_ha }}
{% if form.pachtzins_pro_ha.errors %}
<div class="invalid-feedback d-block">
{{ form.pachtzins_pro_ha.errors.0 }}
</div>
{% endif %}
<div class="form-text">Wird automatisch berechnet</div>
</div>
</div>
</div>
<!-- Zahlungsweise -->
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label for="{{ form.zahlungsweise.id_for_label }}" class="form-label">
<i class="fas fa-calendar-check me-1"></i>Zahlungsweise
</label>
{{ form.zahlungsweise }}
{% if form.zahlungsweise.errors %}
<div class="invalid-feedback d-block">
{{ form.zahlungsweise.errors.0 }}
</div>
{% endif %}
</div>
</div>
</div>
<!-- Umsatzsteuer -->
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<div class="form-check">
{{ form.ust_option }}
<label class="form-check-label" for="{{ form.ust_option.id_for_label }}">
<i class="fas fa-percent me-1"></i>USt-Option
</label>
</div>
{% if form.ust_option.errors %}
<div class="invalid-feedback d-block">
{{ form.ust_option.errors.0 }}
</div>
{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="{{ form.ust_satz.id_for_label }}" class="form-label">
<i class="fas fa-percent me-1"></i>USt-Satz (%)
</label>
{{ form.ust_satz }}
{% if form.ust_satz.errors %}
<div class="invalid-feedback d-block">
{{ form.ust_satz.errors.0 }}
</div>
{% endif %}
</div>
</div>
</div>
<!-- Umlagen -->
<h6 class="mt-4 mb-3">
<i class="fas fa-share-alt me-2"></i>Umlagefähige Kosten
</h6>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<div class="form-check">
{{ form.grundsteuer_umlage }}
<label class="form-check-label" for="{{ form.grundsteuer_umlage.id_for_label }}">
<i class="fas fa-home me-1"></i>Grundsteuer umlagefähig
</label>
</div>
</div>
<div class="mb-3">
<div class="form-check">
{{ form.versicherungen_umlage }}
<label class="form-check-label" for="{{ form.versicherungen_umlage.id_for_label }}">
<i class="fas fa-shield-alt me-1"></i>Versicherungen umlagefähig
</label>
</div>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<div class="form-check">
{{ form.verbandsbeitraege_umlage }}
<label class="form-check-label" for="{{ form.verbandsbeitraege_umlage.id_for_label }}">
<i class="fas fa-users me-1"></i>Verbandsbeiträge umlagefähig
</label>
</div>
</div>
<div class="mb-3">
<div class="form-check">
{{ form.jagdpacht_anteil_umlage }}
<label class="form-check-label" for="{{ form.jagdpacht_anteil_umlage.id_for_label }}">
<i class="fas fa-tree me-1"></i>Jagdpachtanteile umlagefähig
</label>
</div>
</div>
</div>
</div>
<!-- Bemerkungen -->
<div class="row">
<div class="col-md-12">
<div class="mb-3">
<label for="{{ form.bemerkungen.id_for_label }}" class="form-label">
<i class="fas fa-sticky-note me-1"></i>Bemerkungen
</label>
{{ form.bemerkungen }}
{% if form.bemerkungen.errors %}
<div class="invalid-feedback d-block">
{{ form.bemerkungen.errors.0 }}
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Sidebar -->
<div class="col-lg-4">
<!-- Aktionen -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">
<i class="fas fa-cogs me-2"></i>Aktionen
</h6>
</div>
<div class="card-body">
<button type="submit" class="btn btn-primary btn-block mb-2">
<i class="fas fa-save me-2"></i>Verpachtung speichern
</button>
<a href="{% if form.instance.pk %}{% url 'stiftung:verpachtung_detail' form.instance.pk %}{% else %}{% url 'stiftung:verpachtung_list' %}{% endif %}"
class="btn btn-outline-secondary btn-block">
<i class="fas fa-times me-2"></i>Abbrechen
</a>
</div>
</div>
{% if form.instance.pk %}
<!-- Dokumente -->
<div class="card shadow">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">
<i class="fas fa-paperclip me-2"></i>Dokumente verknüpfen
</h6>
</div>
<div class="card-body">
<p class="text-muted small">Dokumente können nach dem Speichern der Verpachtung verknüpft werden.</p>
<a href="{% url 'stiftung:dokument_create' %}?land_verpachtung_id={{ form.instance.pk }}"
class="btn btn-outline-primary btn-sm">
<i class="fas fa-plus me-1"></i>Neues Dokument
</a>
</div>
</div>
{% else %}
<!-- Info Card -->
<div class="card shadow">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-info">
<i class="fas fa-info-circle me-2"></i>Hinweis
</h6>
</div>
<div class="card-body">
<p class="text-muted small">
Nach dem Erstellen der Verpachtung können Dokumente verknüpft und weitere Details bearbeitet werden.
</p>
</div>
</div>
{% endif %}
</div>
</div>
</form>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Auto-calculate Pachtzins pro Hektar and Fläche in Hektar
const pachtzinsPauschal = document.getElementById('{{ form.pachtzins_pauschal.id_for_label }}');
const pachtzinsProHa = document.getElementById('{{ form.pachtzins_pro_ha.id_for_label }}');
const verpachteteFlaeche = document.getElementById('{{ form.verpachtete_flaeche.id_for_label }}');
const verpachteteFlaeheHa = document.getElementById('verpachtete_flaeche_ha');
function updateCalculations() {
const flaeche = parseFloat(verpachteteFlaeche.value) || 0;
const pachtzins = parseFloat(pachtzinsPauschal.value) || 0;
// Update Hektar display
const hektar = flaeche / 10000;
verpachteteFlaeheHa.textContent = hektar.toFixed(2) + ' ha';
// Calculate Pachtzins pro Hektar
if (hektar > 0) {
const pachtzinsPerHa = pachtzins / hektar;
pachtzinsProHa.value = pachtzinsPerHa.toFixed(2);
} else {
pachtzinsProHa.value = '';
}
}
// Attach event listeners
if (verpachteteFlaeche) verpachteteFlaeche.addEventListener('input', updateCalculations);
if (pachtzinsPauschal) pachtzinsPauschal.addEventListener('input', updateCalculations);
// Initial calculation
updateCalculations();
// USt-Satz handling
const ustOption = document.getElementById('{{ form.ust_option.id_for_label }}');
const ustSatz = document.getElementById('{{ form.ust_satz.id_for_label }}');
function toggleUstSatz() {
if (ustSatz) {
ustSatz.disabled = !ustOption.checked;
if (!ustOption.checked) {
ustSatz.value = '19.00';
}
}
}
if (ustOption) {
ustOption.addEventListener('change', toggleUstSatz);
toggleUstSatz(); // Initial state
}
});
</script>
{% endblock %}