Initial commit
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
Rechnungswesen - Kunden
|
||||
{% endblock %}
|
||||
|
||||
{% block header_title %}
|
||||
Kunde hinzufügen
|
||||
{% endblock %}
|
||||
|
||||
{% block header_description %}
|
||||
Neuen Kunden anlegen
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors mb-8">
|
||||
|
||||
<form method="post" enctype="multipart/form-data" class="space-y-4">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
{{ form.as_p }}
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="btn mt-4 btn-save">
|
||||
Speichern
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,230 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
Rechnungswesen - Kunden
|
||||
{% endblock %}
|
||||
|
||||
{% block header_title %}
|
||||
{{ customer.customer_number }} - {{ customer.company_name }}
|
||||
{% endblock %}
|
||||
|
||||
{% block header_description %}
|
||||
Kunde bearbeiten
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form method="post" action="{% url 'invoices:customers_edit' customer.id %}">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
|
||||
<h2 class="text-xl font-bold mb-2">Kundendaten</h2>
|
||||
|
||||
<div class="grid md:grid-cols-2 gap-4 mb-8">
|
||||
|
||||
{% for field in form %}
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-1">
|
||||
{{ field.label }}
|
||||
</label>
|
||||
|
||||
{{ field }}
|
||||
|
||||
{% if field.errors %}
|
||||
<div class="text-red-600 text-sm mt-1">
|
||||
{{ field.errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="grid lg:grid-cols-2 gap-8">
|
||||
|
||||
<!-- Ansprechpartner -->
|
||||
<div>
|
||||
|
||||
<h2 class="font-bold text-lg mb-2">
|
||||
Ansprechpartner
|
||||
</h2>
|
||||
|
||||
{% for contact in customer.contacts.all %}
|
||||
<div class="bg-slate-100 dark:bg-slate-700 rounded-xl p-4 mb-3">
|
||||
|
||||
<div class="grid md:grid-cols-2 gap-3">
|
||||
|
||||
<input
|
||||
type="text"
|
||||
name="contact_first_name_{{ contact.id }}"
|
||||
value="{{ contact.first_name }}"
|
||||
placeholder="Vorname"
|
||||
class="border rounded px-3 py-2">
|
||||
|
||||
<input
|
||||
type="text"
|
||||
name="contact_last_name_{{ contact.id }}"
|
||||
value="{{ contact.last_name }}"
|
||||
placeholder="Nachname"
|
||||
class="border rounded px-3 py-2">
|
||||
|
||||
<input
|
||||
type="email"
|
||||
name="contact_email_{{ contact.id }}"
|
||||
value="{{ contact.email }}"
|
||||
placeholder="E-Mail"
|
||||
class="border rounded px-3 py-2">
|
||||
|
||||
<input
|
||||
type="text"
|
||||
name="contact_phone_{{ contact.id }}"
|
||||
value="{{ contact.phone }}"
|
||||
placeholder="Telefon"
|
||||
class="border rounded px-3 py-2">
|
||||
|
||||
</div>
|
||||
|
||||
<button type="submit"
|
||||
name="delete_contact_id"
|
||||
value="{{ contact.id }}"
|
||||
class="btn btn-delete">
|
||||
Löschen
|
||||
</button>
|
||||
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div id="contacts-container"></div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onclick="addContact()"
|
||||
class="btn btn-add">
|
||||
+ Ansprechpartner hinzufügen
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Standorte -->
|
||||
<div>
|
||||
|
||||
<h2 class="font-bold text-lg mb-2">
|
||||
Standorte
|
||||
</h2>
|
||||
|
||||
{% for location in customer.locations.all %}
|
||||
<div class="bg-slate-100 dark:bg-slate-700 rounded-xl p-4 mb-3">
|
||||
|
||||
<div class="grid md:grid-cols-2 gap-3">
|
||||
|
||||
<input
|
||||
type="text"
|
||||
name="location_name_{{ location.id }}"
|
||||
value="{{ location.name }}"
|
||||
placeholder="Name"
|
||||
class="border rounded px-3 py-2">
|
||||
|
||||
<input
|
||||
type="text"
|
||||
name="location_street_{{ location.id }}"
|
||||
value="{{ location.street }}"
|
||||
placeholder="Straße"
|
||||
class="border rounded px-3 py-2">
|
||||
|
||||
<input
|
||||
type="text"
|
||||
name="location_zip_{{ location.id }}"
|
||||
value="{{ location.zip_code }}"
|
||||
placeholder="PLZ"
|
||||
class="border rounded px-3 py-2">
|
||||
|
||||
<input
|
||||
type="text"
|
||||
name="location_city_{{ location.id }}"
|
||||
value="{{ location.city }}"
|
||||
placeholder="Ort"
|
||||
class="border rounded px-3 py-2">
|
||||
|
||||
<input
|
||||
type="text"
|
||||
name="location_country_{{ location.id }}"
|
||||
value="{{ location.country }}"
|
||||
placeholder="Land"
|
||||
class="border rounded px-3 py-2 md:col-span-2">
|
||||
|
||||
</div>
|
||||
|
||||
<button type="submit"
|
||||
name="delete_location_id"
|
||||
value="{{ location.id }}"
|
||||
class="btn btn-delete">
|
||||
Löschen
|
||||
</button>
|
||||
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div id="locations-container"></div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onclick="addLocation()"
|
||||
class="btn btn-add">
|
||||
+ Standort hinzufügen
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="btn mt-8 btn-save">
|
||||
Speichern
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
function addContact() {
|
||||
document.getElementById("contacts-container").insertAdjacentHTML("beforeend", `
|
||||
<div class="contact-card bg-slate-100 dark:bg-slate-700 rounded-xl p-4 mb-3">
|
||||
<div class="grid md:grid-cols-2 gap-3">
|
||||
|
||||
<input type="text" name="new_contact_first_name" placeholder="Vorname" class="border rounded px-3 py-2">
|
||||
<input type="text" name="new_contact_last_name" placeholder="Nachname" class="border rounded px-3 py-2">
|
||||
<input type="email" name="new_contact_email" placeholder="E-Mail" class="border rounded px-3 py-2">
|
||||
<input type="text" name="new_contact_phone" placeholder="Telefon" class="border rounded px-3 py-2">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
||||
function addLocation() {
|
||||
document.getElementById("locations-container").insertAdjacentHTML("beforeend", `
|
||||
<div class="location-card bg-slate-100 dark:bg-slate-700 rounded-xl p-4 mb-3">
|
||||
|
||||
<div class="grid md:grid-cols-2 gap-3">
|
||||
|
||||
<input type="text" name="new_location_name" placeholder="Name" class="border rounded px-3 py-2">
|
||||
<input type="text" name="new_location_street" placeholder="Straße" class="border rounded px-3 py-2">
|
||||
<input type="text" name="new_location_zip" placeholder="PLZ" class="border rounded px-3 py-2">
|
||||
<input type="text" name="new_location_city" placeholder="Ort" class="border rounded px-3 py-2">
|
||||
<input type="text" name="new_location_country" placeholder="Land" class="border rounded px-3 py-2 md:col-span-2">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,62 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
Rechnungswesen - Kunden
|
||||
{% endblock %}
|
||||
|
||||
{% block header_title %}
|
||||
Kunden
|
||||
{% endblock %}
|
||||
|
||||
{% block header_description %}
|
||||
Kundenstammdaten verwalten
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% load django_tables2 %}
|
||||
<div class="mb-8">
|
||||
<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>
|
||||
<p class="text-slate-400 text-sm mt-1">
|
||||
Kunden anlegen
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-col sm:flex-row gap-2">
|
||||
<a href="{% url 'invoices:customers_add' %}"
|
||||
class="btn btn-add">
|
||||
+ Kunde
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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">Kundenliste</h2>
|
||||
<p class="text-slate-400 text-sm mt-1">Alle Kunden, inkl. Standorte und Ansprechpartner</p>
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto rounded-xl">
|
||||
{% render_table table %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
|
||||
<div class="mb-6">
|
||||
<h2 class="text-xl font-bold">Archivierte Kunden</h2>
|
||||
<p class="text-slate-400 text-sm mt-1">Alle inaktiven Kunden, inkl. Standorte und Ansprechpartner</p>
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto rounded-xl">
|
||||
|
||||
{% render_table table_archived %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,69 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Rechnungswesen - Rechnungen{% endblock %}
|
||||
|
||||
{% block header_title %}
|
||||
Kundenrechnung
|
||||
{% endblock %}
|
||||
|
||||
{% block header_description %}
|
||||
Rechnung auf Basis eines Kunden erstellen
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
|
||||
<form method="post" enctype="multipart/form-data" class="space-y-4">
|
||||
{% csrf_token %}
|
||||
|
||||
{{ form.as_p }}
|
||||
|
||||
<button class="btn btn-save">
|
||||
Speichern
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
const customer = document.getElementById("id_customer");
|
||||
const contact = document.getElementById("id_contact");
|
||||
const location = document.getElementById("id_location");
|
||||
|
||||
function fill(select, data) {
|
||||
select.innerHTML = "<option value=''>---------</option>";
|
||||
data.forEach(item => {
|
||||
select.innerHTML += `<option value="${item.id}">${item.text}</option>`;
|
||||
});
|
||||
}
|
||||
|
||||
if (customer) {
|
||||
customer.addEventListener("change", function () {
|
||||
|
||||
const id = this.value;
|
||||
|
||||
if (!id) {
|
||||
contact.innerHTML = "";
|
||||
location.innerHTML = "";
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/invoices/ajax/customer/${id}/contacts/`)
|
||||
.then(r => r.json())
|
||||
.then(data => fill(contact, data));
|
||||
|
||||
fetch(`/invoices/ajax/customer/${id}/locations/`)
|
||||
.then(r => r.json())
|
||||
.then(data => fill(location, data));
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,221 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Rechnungswesen - Rechnungen{% endblock %}
|
||||
|
||||
{% block header_title %}
|
||||
Projektrechnung
|
||||
{% endblock %}
|
||||
|
||||
{% block header_description %}
|
||||
Rechnung auf Basis eines Projekts erstellen
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
|
||||
<form method="post" enctype="multipart/form-data" class="space-y-4">
|
||||
{% csrf_token %}
|
||||
|
||||
{{ form.as_p }}
|
||||
|
||||
<button class="btn btn-save">
|
||||
Speichern
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
const project = document.getElementById("id_project");
|
||||
|
||||
const contact = document.getElementById("id_contact");
|
||||
const location = document.getElementById("id_location");
|
||||
|
||||
|
||||
const customerFields = [
|
||||
"id_contact",
|
||||
"id_location"
|
||||
];
|
||||
|
||||
|
||||
const manualFields = [
|
||||
"id_contact_name_manual",
|
||||
"id_contact_email_manual",
|
||||
"id_contact_phone_manual",
|
||||
|
||||
"id_location_name_manual",
|
||||
"id_location_street_manual",
|
||||
"id_location_zip_manual",
|
||||
"id_location_city_manual",
|
||||
"id_location_country_manual"
|
||||
];
|
||||
|
||||
|
||||
|
||||
function hideField(id){
|
||||
|
||||
const field = document.getElementById(id);
|
||||
|
||||
if(field){
|
||||
const row = field.closest("p");
|
||||
row.style.display = "none";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function showField(id){
|
||||
|
||||
const field = document.getElementById(id);
|
||||
|
||||
if(field){
|
||||
const row = field.closest("p");
|
||||
row.style.display = "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function hideCustomerFields(){
|
||||
|
||||
customerFields.forEach(hideField);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function showCustomerFields(){
|
||||
|
||||
customerFields.forEach(showField);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function hideManualFields(){
|
||||
|
||||
manualFields.forEach(hideField);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function showManualFields(){
|
||||
|
||||
manualFields.forEach(showField);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function fill(select, data){
|
||||
|
||||
if(!select){
|
||||
return;
|
||||
}
|
||||
|
||||
select.innerHTML = "<option value=''>---------</option>";
|
||||
|
||||
data.forEach(item => {
|
||||
|
||||
select.innerHTML += `
|
||||
<option value="${item.id}">
|
||||
${item.text}
|
||||
</option>
|
||||
`;
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function checkProject(projectId){
|
||||
|
||||
if(!projectId){
|
||||
|
||||
hideCustomerFields();
|
||||
hideManualFields();
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
fetch(`/invoices/ajax/project/${projectId}/invoice-data/`)
|
||||
|
||||
|
||||
.then(response => response.json())
|
||||
|
||||
|
||||
.then(data => {
|
||||
|
||||
|
||||
if(data.has_customer){
|
||||
|
||||
|
||||
showCustomerFields();
|
||||
|
||||
hideManualFields();
|
||||
|
||||
|
||||
fill(
|
||||
contact,
|
||||
data.contacts
|
||||
);
|
||||
|
||||
|
||||
fill(
|
||||
location,
|
||||
data.locations
|
||||
);
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
hideCustomerFields();
|
||||
|
||||
showManualFields();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Anfang prüfen
|
||||
if(project.value){
|
||||
|
||||
checkProject(project.value);
|
||||
|
||||
} else {
|
||||
|
||||
hideCustomerFields();
|
||||
hideManualFields();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
project.addEventListener("change", function(){
|
||||
|
||||
checkProject(this.value);
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,239 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Rechnungswesen - Rechnungen{% endblock %}
|
||||
|
||||
{% block header_title %}
|
||||
Rechnung {{ invoice.invoice_number }}
|
||||
{% endblock %}
|
||||
|
||||
{% block header_description %}
|
||||
Details & Positionen
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% load django_tables2 %}
|
||||
<div class="mb-8">
|
||||
<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>
|
||||
<p class="text-slate-400 text-sm mt-1">
|
||||
Positionen zur Rechnung hinzufügen
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-col sm:flex-row gap-2">
|
||||
{% if invoice.status == "draft" %}
|
||||
<a href="{% url 'invoices:invoice_item_add' invoice.id %}" class="btn btn-add">+ Position</a>
|
||||
<a href="{% url 'invoices:invoices_preview' invoice.id %}" class="btn btn-action">Vorschau</a>
|
||||
<a href="{% url 'invoices:invoices_download' invoice.id %}" onclick="startDownloadAndRedirect()" class="btn btn-action">Download</a>
|
||||
<a href="{% url 'invoices:invoices_delete' invoice.id %}" class="btn btn-delete">Löschen</a>
|
||||
{% endif %}
|
||||
{% if invoice.status == "sent" %}
|
||||
<a href="{% url 'invoices:invoices_download' invoice.id %}" class="btn btn-action">Download</a>
|
||||
<a href="{% url 'invoices:invoices_cancel' invoice.id %}" onclick="startDownloadAndRedirect()" class="btn btn-delete">Stornieren</a>
|
||||
<a href="{% url 'invoices:invoices_paid' invoice.id %}" class="btn btn-action">Zahlung verbuchen</a>
|
||||
<a href="{% url 'invoices:invoices_overdue' invoice.id %}" class="btn btn-action">Überfällig</a>
|
||||
{% endif %}
|
||||
{% if invoice.status == "paid" %}
|
||||
<a href="{% url 'invoices:invoices_download' invoice.id %}" class="btn btn-action">Download</a>
|
||||
<a href="{% url 'invoices:invoices_cancel' invoice.id %}" onclick="startDownloadAndRedirect()" class="btn btn-delete">Stornieren</a>
|
||||
{% endif %}
|
||||
{% if invoice.status == "canceled" %}
|
||||
<a href="{% url 'invoices:invoices_download' invoice.id %}" class="btn btn-action">Download</a>
|
||||
<a href="{% url 'invoices:invoices_cancel' invoice.id %}" class="btn btn-action">Stornorechnung</a>
|
||||
{% endif %}
|
||||
{% if invoice.status == "overdue" %}
|
||||
<a href="{% url 'invoices:invoices_download' invoice.id %}" class="btn btn-action">Download</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if reminders %}
|
||||
<div class="mb-8 p-6 border border-orange-500 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
|
||||
<h2 class="text-xl font-bold mb-6 text-orange-500">Mahnungen</h2>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
{% for reminder in reminders %}
|
||||
{% if reminder.status != "canceled" %}
|
||||
<div class="bg-slate-100 dark:bg-slate-700 rounded-xl p-6">
|
||||
|
||||
<div class="flex justify-between items-start">
|
||||
|
||||
<div>
|
||||
<a href="{% url 'invoices:reminders_detail' reminder.id %}" class="company_link">
|
||||
{{ reminder.reminder_number }}
|
||||
</a>
|
||||
|
||||
<p class="text-sm text-slate-500 dark:text-slate-300 mt-1">
|
||||
Mahnstufe {{ reminder.level }}
|
||||
· {{ reminder.issue_date|date:"d.m.Y" }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
<span class="px-3 py-1 rounded-full text-xs font-medium bg-slate-200 text-slate-700 dark:bg-slate-600 dark:text-slate-200">
|
||||
{{ reminder.get_status_display }}
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mt-4 text-sm text-slate-600 dark:text-slate-300">
|
||||
|
||||
{% if reminder.due_date %}
|
||||
<p>
|
||||
Neue Zahlungsfrist:
|
||||
<span class="font-medium">
|
||||
{{ reminder.due_date|date:"d.m.Y" }}
|
||||
</span>
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if reminder.fee %}
|
||||
<p>
|
||||
Mahngebühr:
|
||||
<span class="font-medium">
|
||||
{{ reminder.fee|floatformat:2 }} €
|
||||
</span>
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- HEADER INFO -->
|
||||
<div class="mb-8 p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
|
||||
<h2 class="text-xl font-bold mb-6">Allgemein</h2>
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
|
||||
<!-- Kunde -->
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Kunde</div>
|
||||
<div class="font-semibold">{{ invoice.customer.company_name }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Projekt -->
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Projekt</div>
|
||||
<div class="font-semibold">
|
||||
{% if invoice.project %}
|
||||
{{ invoice.project.name }}
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Status -->
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Status</div>
|
||||
<div class="font-semibold">{{ invoice.get_status_display }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Datum -->
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Rechnungsdatum</div>
|
||||
<div class="font-semibold">{{ invoice.issue_date|date:"d.m.Y" }}</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Fälligkeitsdatum</div>
|
||||
<div class="font-semibold">{{ invoice.due_date|date:"d.m.Y" }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- SNAPSHOT: KONTAKT & ADRESSE -->
|
||||
<div class="mb-8 p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
|
||||
<h2 class="text-xl font-bold mb-6">Rechnungsadresse</h2>
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-6">
|
||||
|
||||
<!-- Kontakt -->
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Ansprechpartner</div>
|
||||
<div class="font-semibold">{{ invoice.contact_name|default:"-" }}</div>
|
||||
|
||||
{% if invoice.contact_email %}
|
||||
<div class="text-slate-400 text-sm">{{ invoice.contact_email }}</div>
|
||||
{% endif %}
|
||||
|
||||
{% if invoice.contact_phone %}
|
||||
<div class="text-slate-400 text-sm">{{ invoice.contact_phone }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Adresse -->
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Standort</div>
|
||||
|
||||
<div class="font-semibold">
|
||||
{{ invoice.location_name|default:"-" }}
|
||||
</div>
|
||||
|
||||
<div class="text-slate-400 text-sm">
|
||||
{{ invoice.location_street }}
|
||||
</div>
|
||||
|
||||
<div class="text-slate-400 text-sm">
|
||||
{{ invoice.location_zip }} {{ invoice.location_city }}
|
||||
</div>
|
||||
|
||||
<div class="text-slate-400 text-sm">
|
||||
{{ invoice.location_country }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-8 p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<h2 class="text-xl font-bold mb-6">Rechnungshinweis</h2>
|
||||
<div class="grid grid-cols-1 gap-6">
|
||||
<div>
|
||||
<div class="font-semibold">{{ invoice.note|default:"-" }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- POSITIONEN -->
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
|
||||
<h2 class="text-xl font-bold mb-6">Positionen</h2>
|
||||
|
||||
<div class="overflow-x-auto rounded-xl">
|
||||
{% render_table table %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mt-4 text-right font-bold">
|
||||
Gesamt: {{ total_net|floatformat:2 }} €
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script>
|
||||
function startDownloadAndRedirect() {
|
||||
setTimeout(function() {
|
||||
window.location.href = "{% url 'invoices:invoices_detail' invoice.id %}";
|
||||
}, 1000);
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,197 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
Rechnungswesen - Rechnungen
|
||||
{% endblock %}
|
||||
|
||||
{% block header_title %}
|
||||
Rechnungsposition hinzufügen
|
||||
{% endblock %}
|
||||
|
||||
{% block header_description %}
|
||||
Neue Rechnungsposition anlegen
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
|
||||
<form method="post" enctype="multipart/form-data" class="space-y-4">
|
||||
{% csrf_token %}
|
||||
|
||||
{{ form.as_p }}
|
||||
|
||||
<button class="btn btn-save">
|
||||
Speichern
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
const source = document.getElementById("id_source_type");
|
||||
|
||||
const fields = {
|
||||
item: document.getElementById("id_item"),
|
||||
time: document.getElementById("id_time_entry"),
|
||||
expense: document.getElementById("id_expense"),
|
||||
};
|
||||
|
||||
|
||||
function toggleFields() {
|
||||
|
||||
const value = source.value;
|
||||
|
||||
|
||||
Object.keys(fields).forEach(key => {
|
||||
|
||||
const field = fields[key];
|
||||
|
||||
if (!field) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const row = field.closest("p");
|
||||
|
||||
|
||||
if (key === value) {
|
||||
|
||||
row.style.display = "";
|
||||
|
||||
} else {
|
||||
|
||||
row.style.display = "none";
|
||||
|
||||
field.value = "";
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
source.addEventListener(
|
||||
"change",
|
||||
toggleFields
|
||||
);
|
||||
|
||||
|
||||
// Initial ausführen
|
||||
toggleFields();
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
|
||||
const source = document.getElementById("id_source_type");
|
||||
|
||||
|
||||
const selects = {
|
||||
|
||||
item: document.getElementById("id_item"),
|
||||
|
||||
time: document.getElementById("id_time_entry"),
|
||||
|
||||
expense: document.getElementById("id_expense"),
|
||||
|
||||
};
|
||||
|
||||
|
||||
const description = document.getElementById(
|
||||
"id_description"
|
||||
);
|
||||
|
||||
const quantity = document.getElementById(
|
||||
"id_quantity"
|
||||
);
|
||||
|
||||
const unit = document.getElementById(
|
||||
"id_unit"
|
||||
);
|
||||
|
||||
const price = document.getElementById(
|
||||
"id_unit_price_net"
|
||||
);
|
||||
|
||||
const tax = document.getElementById(
|
||||
"id_unit_tax_rate"
|
||||
);
|
||||
|
||||
|
||||
|
||||
function loadData(type, id){
|
||||
|
||||
|
||||
if(!id){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
fetch(
|
||||
`/invoices/ajax/invoice-item-data/?source=${type}&id=${id}`
|
||||
)
|
||||
|
||||
|
||||
.then(response => response.json())
|
||||
|
||||
|
||||
.then(data => {
|
||||
|
||||
|
||||
description.value = data.description;
|
||||
|
||||
quantity.value = data.quantity;
|
||||
|
||||
unit.value = data.unit;
|
||||
|
||||
price.value = data.unit_price_net;
|
||||
|
||||
tax.value = data.unit_tax_rate;
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Object.keys(selects).forEach(type => {
|
||||
|
||||
|
||||
if(selects[type]){
|
||||
|
||||
|
||||
selects[type].addEventListener(
|
||||
"change",
|
||||
function(){
|
||||
|
||||
loadData(
|
||||
type,
|
||||
this.value
|
||||
);
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,35 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Rechnungswesen - Rechnungen{% endblock %}
|
||||
|
||||
{% block header_title %}Rechnungen{% endblock %}
|
||||
{% block header_description %}Rechnungen erstellen und verwalten{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% load django_tables2 %}
|
||||
<div class="mb-8">
|
||||
<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>
|
||||
<p class="text-slate-400 text-sm mt-1">Neue Rechnung erstellen</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row gap-2">
|
||||
<a href="{% url 'invoices:invoice_add_customer' %}" class="btn btn-add">+ Kundenrechnung</a>
|
||||
<a href="{% url 'invoices:invoice_add_project' %}" class="btn btn-add">+ Projektrechnung</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<div class="mb-6">
|
||||
<h2 class="text-xl font-bold">Rechnungen</h2>
|
||||
<p class="text-slate-400 text-sm mt-1">Alle Rechnungen mit aktuellem Status</p>
|
||||
</div>
|
||||
<div class="overflow-x-auto rounded-xl">
|
||||
{% render_table table %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,747 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
|
||||
<head>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
|
||||
<style>
|
||||
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 18mm;
|
||||
}
|
||||
|
||||
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 11px;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
|
||||
h1,h2,h3,p {
|
||||
margin:0;
|
||||
}
|
||||
|
||||
|
||||
table {
|
||||
width:100%;
|
||||
border-collapse:collapse;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.header {
|
||||
display:flex;
|
||||
justify-content:space-between;
|
||||
}
|
||||
|
||||
|
||||
.logo {
|
||||
height:128px;
|
||||
margin-bottom:15px;
|
||||
}
|
||||
|
||||
|
||||
.company-name {
|
||||
font-size:24px;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
|
||||
.invoice-title {
|
||||
font-size:32px;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.info-table td {
|
||||
padding:4px 0;
|
||||
}
|
||||
|
||||
|
||||
.label {
|
||||
color:#64748b;
|
||||
padding-right:30px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.divider {
|
||||
border-top:1px solid #e2e8f0;
|
||||
margin:30px 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.receiver-title {
|
||||
font-size:10px;
|
||||
text-transform:uppercase;
|
||||
color:#64748b;
|
||||
letter-spacing:1px;
|
||||
}
|
||||
|
||||
|
||||
.receiver-name {
|
||||
font-size:16px;
|
||||
font-weight:bold;
|
||||
margin-top:5px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.invoice-heading {
|
||||
font-size:22px;
|
||||
font-weight:bold;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.items-wrapper {
|
||||
border:1px solid #e2e8f0;
|
||||
border-radius:10px;
|
||||
overflow:hidden;
|
||||
margin-top:20px;
|
||||
}
|
||||
|
||||
|
||||
.items {
|
||||
width:100%;
|
||||
border-collapse:collapse;
|
||||
}
|
||||
|
||||
|
||||
.items thead th:first-child {
|
||||
border-top-left-radius:10px;
|
||||
}
|
||||
|
||||
|
||||
.items thead th:last-child {
|
||||
border-top-right-radius:10px;
|
||||
}
|
||||
|
||||
|
||||
.items th {
|
||||
background:{{ company.color }};
|
||||
color:white;
|
||||
padding:10px;
|
||||
text-align:left;
|
||||
}
|
||||
|
||||
|
||||
.items td {
|
||||
padding:10px;
|
||||
border-bottom:1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
|
||||
.items tbody tr:last-child td {
|
||||
border-bottom:none;
|
||||
}
|
||||
|
||||
|
||||
.right {
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.total-box {
|
||||
|
||||
margin-top:30px;
|
||||
margin-left:auto;
|
||||
width:250px;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.total-row {
|
||||
|
||||
display:flex;
|
||||
justify-content:space-between;
|
||||
padding:6px 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
.total-final {
|
||||
|
||||
border-top:1px solid #cbd5e1;
|
||||
margin-top:10px;
|
||||
padding-top:10px;
|
||||
font-size:16px;
|
||||
font-weight:bold;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.note {
|
||||
margin-top:30px;
|
||||
padding:12px;
|
||||
border:1px solid #e2e8f0;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.small-business {
|
||||
|
||||
margin-top:25px;
|
||||
color:#64748b;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 18mm 18mm 35mm 18mm;
|
||||
}
|
||||
|
||||
|
||||
.footer {
|
||||
position: fixed;
|
||||
bottom: -25mm;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
padding-top:15px;
|
||||
border-top:1px solid #e2e8f0;
|
||||
|
||||
display:flex;
|
||||
justify-content:space-between;
|
||||
|
||||
font-size:10px;
|
||||
color:#64748b;
|
||||
}
|
||||
|
||||
|
||||
.footer-title {
|
||||
font-weight:bold;
|
||||
color:#334155;
|
||||
margin-bottom:5px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
|
||||
<!-- HEADER -->
|
||||
|
||||
|
||||
<div class="header">
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
{% if company.logo %}
|
||||
<img src="{{ company.logo.url }}" class="logo">
|
||||
{% else %}
|
||||
<h1 class="company-name" style="color: {{ company.color }}">
|
||||
{{ company.companyname }}
|
||||
</h1>
|
||||
|
||||
{% if company.slogan %}
|
||||
<p>
|
||||
{{ company.slogan }}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
<p style="margin-top:15px">
|
||||
{{ company.name }}<br>
|
||||
{{ company.street }} · {{ company.zip }} {{ company.city }}
|
||||
</p>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div style="text-align:right">
|
||||
|
||||
|
||||
<div class="invoice-title">
|
||||
RECHNUNG
|
||||
</div>
|
||||
|
||||
|
||||
<table class="info-table">
|
||||
|
||||
|
||||
<tr>
|
||||
<td class="label">
|
||||
Rechnungsnummer
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ invoice.invoice_number }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td class="label">
|
||||
Rechnungsdatum
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ invoice.issue_date|date:"d.m.Y" }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
{% if invoice.due_date %}
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="label">
|
||||
Fälligkeitsdatum
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ invoice.due_date|date:"d.m.Y" }}
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- EMPFÄNGER -->
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
|
||||
<div class="receiver-title">
|
||||
Rechnungsempfänger
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="receiver-name">
|
||||
|
||||
{% if invoice.customer.type == "company" %}
|
||||
{{ invoice.customer.company_name }}
|
||||
{% else %}
|
||||
{{ invoice.contact_name }}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{% if invoice.customer.type == "company" %}
|
||||
|
||||
<p>
|
||||
z.Hd. {{ invoice.contact_name }}
|
||||
</p>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
<p style="margin-top:10px">
|
||||
|
||||
{{ invoice.location_street }}<br>
|
||||
|
||||
{{ invoice.location_zip }}
|
||||
{{ invoice.location_city }}
|
||||
|
||||
</p>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- TITEL -->
|
||||
|
||||
|
||||
<div style="margin-top:40px">
|
||||
|
||||
|
||||
<div class="invoice-heading"
|
||||
style="color:{{ company.color }}">
|
||||
|
||||
Rechnung
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{% if company.invoice_header_text %}
|
||||
|
||||
<p>
|
||||
{{ company.invoice_header_text|linebreaksbr }}
|
||||
</p>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- POSITIONEN -->
|
||||
|
||||
<div class="items-wrapper">
|
||||
<table class="items">
|
||||
|
||||
|
||||
<thead>
|
||||
|
||||
<tr>
|
||||
|
||||
<th>
|
||||
Nr.
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Beschreibung
|
||||
</th>
|
||||
|
||||
{% if show_service_date %}
|
||||
<th class="left">Leistungsdatum</th>
|
||||
{% endif %}
|
||||
|
||||
<th class="left">
|
||||
Menge
|
||||
</th>
|
||||
|
||||
<th class="left">
|
||||
Einheit
|
||||
</th>
|
||||
|
||||
<th class="left">
|
||||
Preis
|
||||
</th>
|
||||
|
||||
|
||||
{% if not company.is_small_business %}
|
||||
|
||||
<th class="left">
|
||||
Steuer
|
||||
</th>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
<th class="left">
|
||||
Gesamt
|
||||
</th>
|
||||
|
||||
|
||||
</tr>
|
||||
|
||||
</thead>
|
||||
|
||||
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
{% for item in items %}
|
||||
|
||||
<tr>
|
||||
|
||||
|
||||
<td>
|
||||
{{ forloop.counter }}
|
||||
</td>
|
||||
|
||||
|
||||
<td>
|
||||
{{ item.description }}
|
||||
</td>
|
||||
|
||||
|
||||
{% if show_service_date %}
|
||||
<td class="left">
|
||||
{% if item.service_period_from %}
|
||||
{{ item.service_period_from|date:"d.m.Y" }}
|
||||
{% endif %}
|
||||
{% if item.service_period_to %}
|
||||
- {{ item.service_period_to|date:"d.m.Y" }}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
|
||||
<td class="left">
|
||||
{{ item.quantity }}
|
||||
</td>
|
||||
|
||||
|
||||
<td class="left">
|
||||
{{ item.unit }}
|
||||
</td>
|
||||
|
||||
|
||||
<td class="left">
|
||||
{{ item.unit_price_net|floatformat:2 }} €
|
||||
</td>
|
||||
|
||||
|
||||
{% if not company.is_small_business %}
|
||||
|
||||
<td class="left">
|
||||
{{ item.unit_tax_rate|floatformat:0 }} %
|
||||
</td>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
<td class="left">
|
||||
{{ item.calculated_total_net|floatformat:2 }} €
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
</tr>
|
||||
|
||||
|
||||
{% endfor %}
|
||||
|
||||
|
||||
</tbody>
|
||||
|
||||
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- SUMMEN -->
|
||||
|
||||
|
||||
<div class="total-box">
|
||||
|
||||
|
||||
<div class="total-row">
|
||||
|
||||
<span>
|
||||
Netto
|
||||
</span>
|
||||
|
||||
<span>
|
||||
{{ total_net|floatformat:2 }} €
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{% if not company.is_small_business %}
|
||||
{% for tax_rate,tax_amount in tax_summary.items %}
|
||||
|
||||
<div class="total-row">
|
||||
|
||||
<span>
|
||||
Umsatzsteuer {{ tax_rate|floatformat:0 }} %
|
||||
</span>
|
||||
|
||||
|
||||
<span>
|
||||
{{ tax_amount|floatformat:2 }} €
|
||||
</span>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="total-row total-final">
|
||||
|
||||
<span>
|
||||
Gesamt
|
||||
</span>
|
||||
|
||||
|
||||
<span>
|
||||
|
||||
{% if company.is_small_business %}
|
||||
{{ total_net|floatformat:2 }}
|
||||
{% else %}
|
||||
{{ total_gross|floatformat:2 }}
|
||||
{% endif %}
|
||||
|
||||
€
|
||||
|
||||
</span>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{% if invoice.note %}
|
||||
|
||||
<div class="note">
|
||||
|
||||
<div class="receiver-title">
|
||||
Rechnungshinweis
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
{{ invoice.note|linebreaksbr }}
|
||||
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{% if company.is_small_business %}
|
||||
|
||||
<div class="note">
|
||||
|
||||
<div class="receiver-title">
|
||||
Kleinunternehmerhinweis
|
||||
</div>
|
||||
<br>
|
||||
{{ company.small_business_text }}
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- FOOTER -->
|
||||
|
||||
|
||||
<div class="footer">
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
<div class="footer-title">
|
||||
Kontakt
|
||||
</div>
|
||||
|
||||
{% if company.phone %}
|
||||
{{ company.phone }}<br>
|
||||
{% endif %}
|
||||
|
||||
{% if company.email %}
|
||||
{{ company.email }}<br>
|
||||
{% endif %}
|
||||
|
||||
{% if company.website %}
|
||||
{{ company.website }}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
<div class="footer-title">
|
||||
Steuern
|
||||
</div>
|
||||
|
||||
|
||||
{% if company.tax_number %}
|
||||
Steuernummer: {{ company.tax_number }}<br>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.vat_number %}
|
||||
USt-IdNr.: {{ company.vat_number }}
|
||||
{% endif %}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
<div class="footer-title">
|
||||
Bank
|
||||
</div>
|
||||
|
||||
|
||||
{% if company.bank_name %}
|
||||
{{ company.bank_name }}<br>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.iban %}
|
||||
IBAN: {{ company.iban }}<br>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.bic %}
|
||||
BIC: {{ company.bic }}
|
||||
{% endif %}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,756 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
|
||||
<head>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
|
||||
<style>
|
||||
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 18mm;
|
||||
}
|
||||
|
||||
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 11px;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
|
||||
h1,h2,h3,p {
|
||||
margin:0;
|
||||
}
|
||||
|
||||
|
||||
table {
|
||||
width:100%;
|
||||
border-collapse:collapse;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.header {
|
||||
display:flex;
|
||||
justify-content:space-between;
|
||||
}
|
||||
|
||||
|
||||
.logo {
|
||||
height:128px;
|
||||
margin-bottom:15px;
|
||||
}
|
||||
|
||||
|
||||
.company-name {
|
||||
font-size:24px;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
|
||||
.invoice-title {
|
||||
font-size:32px;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.info-table td {
|
||||
padding:4px 0;
|
||||
}
|
||||
|
||||
|
||||
.label {
|
||||
color:#64748b;
|
||||
padding-right:30px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.divider {
|
||||
border-top:1px solid #e2e8f0;
|
||||
margin:30px 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.receiver-title {
|
||||
font-size:10px;
|
||||
text-transform:uppercase;
|
||||
color:#64748b;
|
||||
letter-spacing:1px;
|
||||
}
|
||||
|
||||
|
||||
.receiver-name {
|
||||
font-size:16px;
|
||||
font-weight:bold;
|
||||
margin-top:5px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.invoice-heading {
|
||||
font-size:22px;
|
||||
font-weight:bold;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.items-wrapper {
|
||||
border:1px solid #e2e8f0;
|
||||
border-radius:10px;
|
||||
overflow:hidden;
|
||||
margin-top:20px;
|
||||
}
|
||||
|
||||
|
||||
.items {
|
||||
width:100%;
|
||||
border-collapse:collapse;
|
||||
}
|
||||
|
||||
|
||||
.items thead th:first-child {
|
||||
border-top-left-radius:10px;
|
||||
}
|
||||
|
||||
|
||||
.items thead th:last-child {
|
||||
border-top-right-radius:10px;
|
||||
}
|
||||
|
||||
|
||||
.items th {
|
||||
background:{{ company.color }};
|
||||
color:white;
|
||||
padding:10px;
|
||||
text-align:left;
|
||||
}
|
||||
|
||||
|
||||
.items td {
|
||||
padding:10px;
|
||||
border-bottom:1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
|
||||
.items tbody tr:last-child td {
|
||||
border-bottom:none;
|
||||
}
|
||||
|
||||
|
||||
.right {
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.total-box {
|
||||
|
||||
margin-top:30px;
|
||||
margin-left:auto;
|
||||
width:250px;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.total-row {
|
||||
|
||||
display:flex;
|
||||
justify-content:space-between;
|
||||
padding:6px 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
.total-final {
|
||||
|
||||
border-top:1px solid #cbd5e1;
|
||||
margin-top:10px;
|
||||
padding-top:10px;
|
||||
font-size:16px;
|
||||
font-weight:bold;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.note {
|
||||
margin-top:30px;
|
||||
padding:12px;
|
||||
border:1px solid #e2e8f0;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.small-business {
|
||||
|
||||
margin-top:25px;
|
||||
color:#64748b;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 18mm 18mm 35mm 18mm;
|
||||
}
|
||||
|
||||
|
||||
.footer {
|
||||
position: fixed;
|
||||
bottom: -25mm;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
padding-top:15px;
|
||||
border-top:1px solid #e2e8f0;
|
||||
|
||||
display:flex;
|
||||
justify-content:space-between;
|
||||
|
||||
font-size:10px;
|
||||
color:#64748b;
|
||||
}
|
||||
|
||||
|
||||
.footer-title {
|
||||
font-weight:bold;
|
||||
color:#334155;
|
||||
margin-bottom:5px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
|
||||
<!-- HEADER -->
|
||||
|
||||
|
||||
<div class="header">
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
{% if company.logo %}
|
||||
<img src="{{ company.logo.url }}" class="logo">
|
||||
{% else %}
|
||||
<h1 class="company-name" style="color: {{ company.color }}">
|
||||
{{ company.companyname }}
|
||||
</h1>
|
||||
|
||||
{% if company.slogan %}
|
||||
<p>
|
||||
{{ company.slogan }}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
<p style="margin-top:15px">
|
||||
{{ company.name }}<br>
|
||||
{{ company.street }} · {{ company.zip }} {{ company.city }}
|
||||
</p>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div style="text-align:right">
|
||||
|
||||
|
||||
<div class="invoice-title">
|
||||
STORNO
|
||||
</div>
|
||||
|
||||
<table class="info-table">
|
||||
|
||||
<tr>
|
||||
<td class="label">
|
||||
Stornonummer
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ cancel_number }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="label">
|
||||
Stornodatum
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ cancel_date|date:"d.m.Y" }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="label">
|
||||
Ursprüngliche Rechnung
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ invoice.invoice_number }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="label">
|
||||
Rechnungsdatum
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ invoice.issue_date|date:"d.m.Y" }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- EMPFÄNGER -->
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
|
||||
<div class="receiver-title">
|
||||
Rechnungsempfänger
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="receiver-name">
|
||||
|
||||
{% if invoice.customer.type == "company" %}
|
||||
{{ invoice.customer.company_name }}
|
||||
{% else %}
|
||||
{{ invoice.contact_name }}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{% if invoice.customer.type == "company" %}
|
||||
|
||||
<p>
|
||||
z.Hd. {{ invoice.contact_name }}
|
||||
</p>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
<p style="margin-top:10px">
|
||||
|
||||
{{ invoice.location_street }}<br>
|
||||
|
||||
{{ invoice.location_zip }}
|
||||
{{ invoice.location_city }}
|
||||
|
||||
</p>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- TITEL -->
|
||||
|
||||
|
||||
<div style="margin-top:40px">
|
||||
|
||||
|
||||
<div class="invoice-heading"
|
||||
style="color:{{ company.color }}">
|
||||
Stornorechnung
|
||||
</div>
|
||||
|
||||
<p style="margin-top:10px;">
|
||||
Diese Stornorechnung storniert die Rechnung
|
||||
<strong>{{ invoice.invoice_number }}</strong>
|
||||
vom {{ invoice.issue_date|date:"d.m.Y" }} vollständig.
|
||||
</p>
|
||||
|
||||
<p style="margin-top:5px;">
|
||||
Stornodatum: {{ cancel_date|date:"d.m.Y" }}
|
||||
</p>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- POSITIONEN -->
|
||||
|
||||
<div class="items-wrapper">
|
||||
<table class="items">
|
||||
|
||||
|
||||
<thead>
|
||||
|
||||
<tr>
|
||||
|
||||
<th>
|
||||
Nr.
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Beschreibung
|
||||
</th>
|
||||
|
||||
{% if show_service_date %}
|
||||
<th class="left">Leistungsdatum</th>
|
||||
{% endif %}
|
||||
|
||||
<th class="left">
|
||||
Menge
|
||||
</th>
|
||||
|
||||
<th class="left">
|
||||
Einheit
|
||||
</th>
|
||||
|
||||
<th class="left">
|
||||
Preis
|
||||
</th>
|
||||
|
||||
|
||||
{% if not company.is_small_business %}
|
||||
|
||||
<th class="left">
|
||||
Steuer
|
||||
</th>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
<th class="left">
|
||||
Gesamt
|
||||
</th>
|
||||
|
||||
|
||||
</tr>
|
||||
|
||||
</thead>
|
||||
|
||||
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
{% for item in items %}
|
||||
|
||||
<tr>
|
||||
|
||||
|
||||
<td>
|
||||
{{ forloop.counter }}
|
||||
</td>
|
||||
|
||||
|
||||
<td>
|
||||
{{ item.description }}
|
||||
</td>
|
||||
|
||||
|
||||
{% if show_service_date %}
|
||||
<td class="left">
|
||||
{% if item.service_period_from %}
|
||||
{{ item.service_period_from|date:"d.m.Y" }}
|
||||
{% endif %}
|
||||
{% if item.service_period_to %}
|
||||
- {{ item.service_period_to|date:"d.m.Y" }}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
|
||||
<td class="left">
|
||||
{{ item.quantity }}
|
||||
</td>
|
||||
|
||||
|
||||
<td class="left">
|
||||
{{ item.unit }}
|
||||
</td>
|
||||
|
||||
|
||||
<td class="left">
|
||||
-{{ item.unit_price_net|floatformat:2 }} €
|
||||
</td>
|
||||
|
||||
|
||||
{% if not company.is_small_business %}
|
||||
|
||||
<td class="left">
|
||||
{{ item.unit_tax_rate|floatformat:0 }} %
|
||||
</td>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
<td class="left">
|
||||
-{{ item.calculated_total_net|floatformat:2 }} €
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
</tr>
|
||||
|
||||
|
||||
{% endfor %}
|
||||
|
||||
|
||||
</tbody>
|
||||
|
||||
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- SUMMEN -->
|
||||
|
||||
|
||||
<div class="total-box">
|
||||
|
||||
|
||||
<div class="total-row">
|
||||
|
||||
<span>
|
||||
Netto
|
||||
</span>
|
||||
|
||||
<span>
|
||||
-{{ total_net|floatformat:2 }} €
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{% if not company.is_small_business %}
|
||||
{% for tax_rate,tax_amount in tax_summary.items %}
|
||||
|
||||
<div class="total-row">
|
||||
|
||||
<span>
|
||||
Umsatzsteuer {{ tax_rate|floatformat:0 }} %
|
||||
</span>
|
||||
|
||||
|
||||
<span>
|
||||
-{{ tax_amount|floatformat:2 }} €
|
||||
</span>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="total-row total-final">
|
||||
|
||||
<span>
|
||||
Gesamt
|
||||
</span>
|
||||
|
||||
|
||||
<span>
|
||||
|
||||
{% if company.is_small_business %}
|
||||
-{{ total_net|floatformat:2 }}
|
||||
{% else %}
|
||||
-{{ total_gross|floatformat:2 }}
|
||||
{% endif %}
|
||||
|
||||
€
|
||||
|
||||
</span>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="note">
|
||||
|
||||
<div class="receiver-title">
|
||||
Stornohinweis
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
Die Rechnung {{ invoice.invoice_number }}
|
||||
wird durch diese Stornorechnung vollständig aufgehoben.
|
||||
|
||||
{% if original_status == "paid" %}
|
||||
|
||||
<br><br>
|
||||
|
||||
Die ursprüngliche Rechnung wurde bereits bezahlt.
|
||||
|
||||
Es entsteht ein Guthaben in Höhe von
|
||||
|
||||
{% if company.is_small_business %}
|
||||
{{ total_net|floatformat:2 }}
|
||||
{% else %}
|
||||
{{ total_gross|floatformat:2 }}
|
||||
{% endif %}
|
||||
|
||||
€.
|
||||
|
||||
Die Rückerstattung erfolgt separat.
|
||||
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{% if company.is_small_business %}
|
||||
|
||||
<div class="note">
|
||||
|
||||
<div class="receiver-title">
|
||||
Kleinunternehmerhinweis
|
||||
</div>
|
||||
<br>
|
||||
{{ company.small_business_text }}
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- FOOTER -->
|
||||
|
||||
|
||||
<div class="footer">
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
<div class="footer-title">
|
||||
Kontakt
|
||||
</div>
|
||||
|
||||
{% if company.phone %}
|
||||
{{ company.phone }}<br>
|
||||
{% endif %}
|
||||
|
||||
{% if company.email %}
|
||||
{{ company.email }}<br>
|
||||
{% endif %}
|
||||
|
||||
{% if company.website %}
|
||||
{{ company.website }}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
<div class="footer-title">
|
||||
Steuern
|
||||
</div>
|
||||
|
||||
|
||||
{% if company.tax_number %}
|
||||
Steuernummer: {{ company.tax_number }}<br>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.vat_number %}
|
||||
USt-IdNr.: {{ company.vat_number }}
|
||||
{% endif %}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
<div class="footer-title">
|
||||
Bank
|
||||
</div>
|
||||
|
||||
|
||||
{% if company.bank_name %}
|
||||
{{ company.bank_name }}<br>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.iban %}
|
||||
IBAN: {{ company.iban }}<br>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.bic %}
|
||||
BIC: {{ company.bic }}
|
||||
{% endif %}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,465 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Rechnungswesen - Rechnungen{% endblock %}
|
||||
|
||||
{% block header_title %}Rechnung {{ invoice.invoice_number }}{% endblock %}
|
||||
|
||||
{% block header_description %}Vorschau{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="max-w-5xl w-5xl mx-auto bg-white rounded-2xl shadow p-10 text-slate-900">
|
||||
|
||||
<!-- HEADER -->
|
||||
<div class="flex justify-between items-start">
|
||||
|
||||
<div>
|
||||
{% if company.logo %}
|
||||
<img src="{{ company.logo.url }}" class="h-32 mb-4">
|
||||
{% else %}
|
||||
<h1 class="text-2xl font-bold" style="color: {{ company.color }}">
|
||||
{{ company.companyname }}
|
||||
</h1>
|
||||
|
||||
{% if company.slogan %}
|
||||
<p class="text-sm text-slate-600 mt-1">
|
||||
{{ company.slogan }}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
<div class="mt-4 text-sm">
|
||||
<p>{{ company.name }}</p>
|
||||
<p>
|
||||
{{ company.street }}
|
||||
·
|
||||
{{ company.zip }}
|
||||
{{ company.city }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="text-right">
|
||||
|
||||
<h2 class="text-3xl font-bold ">
|
||||
RECHNUNG
|
||||
</h2>
|
||||
|
||||
|
||||
<table class="mt-4 text-sm ml-auto">
|
||||
|
||||
<tr>
|
||||
<td class="text-slate-600 pr-8 py-1">
|
||||
Rechnungsnummer
|
||||
</td>
|
||||
<td class="font-medium">
|
||||
{{ invoice.invoice_number }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="text-slate-600 pr-8 py-1">
|
||||
Rechnungsdatum
|
||||
</td>
|
||||
<td class="font-medium">
|
||||
{{ invoice.issue_date|date:"d.m.Y" }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
{% if invoice.due_date %}
|
||||
<tr>
|
||||
<td class="text-slate-600 pr-8 py-1">
|
||||
Fälligkeitsdatum
|
||||
</td>
|
||||
<td class="font-medium">
|
||||
{{ invoice.due_date|date:"d.m.Y" }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="my-8 border-t"></div>
|
||||
|
||||
|
||||
<!-- EMPFÄNGER -->
|
||||
|
||||
<div class="mb-10">
|
||||
|
||||
<p class="text-xs uppercase tracking-wide text-slate-600 mb-2">
|
||||
Rechnungsempfänger
|
||||
</p>
|
||||
|
||||
<p class="font-semibold text-lg ">
|
||||
|
||||
{% if invoice.customer.type == "company" %}
|
||||
{{ invoice.customer.company_name }}
|
||||
{% else %}
|
||||
{{ invoice.contact_name }}
|
||||
{% endif %}
|
||||
|
||||
</p>
|
||||
|
||||
|
||||
{% if invoice.customer.type == "company" %}
|
||||
<p class="text-sm">
|
||||
z.Hd. {{ invoice.contact_name }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<p class="mt-2 text-sm">
|
||||
{{ invoice.location_street }}<br>
|
||||
{{ invoice.location_zip }}
|
||||
{{ invoice.location_city }}
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- TITEL -->
|
||||
|
||||
<div class="mb-8">
|
||||
|
||||
<h2 class="text-2xl font-bold" style="color: {{ company.color }}">
|
||||
Rechnung
|
||||
</h2>
|
||||
|
||||
|
||||
{% if company.invoice_header_text %}
|
||||
<div class="mt-3 text-sm text-slate-600">
|
||||
{{ company.invoice_header_text|linebreaks }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- POSITIONEN -->
|
||||
|
||||
<div class="border rounded-xl overflow-hidden">
|
||||
|
||||
<table class="w-full text-sm">
|
||||
|
||||
<thead>
|
||||
|
||||
<tr style="background-color: {{ company.color }}" class="text-white">
|
||||
|
||||
<th class="p-3 text-left">
|
||||
Nr.
|
||||
</th>
|
||||
|
||||
<th class="p-3 text-left">
|
||||
Beschreibung
|
||||
</th>
|
||||
|
||||
{% if show_service_date %}
|
||||
<th class="p-3 text-left">Leistungsdatum</th>
|
||||
{% endif %}
|
||||
|
||||
<th class="p-3 text-right">
|
||||
Menge
|
||||
</th>
|
||||
|
||||
<th class="p-3 text-right">
|
||||
Einheit
|
||||
</th>
|
||||
|
||||
<th class="p-3 text-right">
|
||||
Preis
|
||||
</th>
|
||||
|
||||
|
||||
{% if not company.is_small_business %}
|
||||
<th class="p-3 text-right">
|
||||
Steuer
|
||||
</th>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<th class="p-3 text-right">
|
||||
Gesamt
|
||||
</th>
|
||||
|
||||
</tr>
|
||||
|
||||
</thead>
|
||||
|
||||
|
||||
<tbody>
|
||||
|
||||
{% for item in items %}
|
||||
|
||||
<tr class="border-t">
|
||||
|
||||
<td class="p-3 text-left">
|
||||
{{ forloop.counter }}
|
||||
</td>
|
||||
|
||||
<td class="p-3 text-left">
|
||||
{{ item.description }}
|
||||
</td>
|
||||
|
||||
{% if show_service_date %}
|
||||
<td class="p-3 text-left">
|
||||
{% if item.service_period_from %}
|
||||
{{ item.service_period_from|date:"d.m.Y" }}
|
||||
{% endif %}
|
||||
{% if item.service_period_to %}
|
||||
- {{ item.service_period_to|date:"d.m.Y" }}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
|
||||
<td class="p-3 text-right">
|
||||
{{ item.quantity }}
|
||||
</td>
|
||||
|
||||
<td class="p-3 text-right">
|
||||
{{ item.unit }}
|
||||
</td>
|
||||
|
||||
<td class="p-3 text-right">
|
||||
{{ item.unit_price_net|floatformat:2 }} €
|
||||
</td>
|
||||
|
||||
|
||||
{% if not company.is_small_business %}
|
||||
<td class="p-3 text-right">
|
||||
{{ item.unit_tax_rate|floatformat:0 }} %
|
||||
</td>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<td class="p-3 text-right font-medium">
|
||||
{{ item.calculated_total_net|floatformat:2 }} €
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- SUMMEN -->
|
||||
|
||||
<div class="flex justify-end mt-8">
|
||||
|
||||
<div class="w-80 text-sm">
|
||||
|
||||
<div class="flex justify-between py-2">
|
||||
<span class="text-slate-600">
|
||||
Netto
|
||||
</span>
|
||||
|
||||
<span>
|
||||
{{ total_net|floatformat:2 }} €
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
{% if not company.is_small_business %}
|
||||
|
||||
{% for tax_rate, tax_amount in tax_summary.items %}
|
||||
|
||||
<div class="flex justify-between py-2">
|
||||
|
||||
<span class="text-slate-600">
|
||||
Umsatzsteuer {{ tax_rate|floatformat:0 }} %
|
||||
</span>
|
||||
|
||||
<span>
|
||||
{{ tax_amount|floatformat:2 }} €
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
<div class="border-t mt-3 pt-4 flex justify-between text-lg font-bold ">
|
||||
|
||||
<span>
|
||||
Gesamt
|
||||
</span>
|
||||
|
||||
<span>
|
||||
{% if company.is_small_business %}
|
||||
{{ total_net|floatformat:2 }} €
|
||||
{% else %}
|
||||
{{ total_gross|floatformat:2 }} €
|
||||
{% endif %}
|
||||
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- NOTIZ -->
|
||||
|
||||
{% if invoice.note %}
|
||||
|
||||
<div class="mt-10 border rounded-xl p-4">
|
||||
|
||||
<p class="text-xs uppercase tracking-wide text-slate-600 mb-2">
|
||||
Rechnungshinweis
|
||||
</p>
|
||||
|
||||
|
||||
<div class="text-sm">
|
||||
{{ invoice.note|linebreaks }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- KLEINUNTERNEHMER -->
|
||||
{% if company.is_small_business %}
|
||||
|
||||
<div class="mt-10 border rounded-xl p-4">
|
||||
|
||||
<p class="text-xs uppercase tracking-wide text-slate-600 mb-2">
|
||||
Kleinunternehmerhinweis
|
||||
</p>
|
||||
<div class="text-sm">
|
||||
{{ company.small_business_text }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- FOOTER -->
|
||||
|
||||
<div class="mt-14 pt-6 border-t grid grid-cols-3 gap-6 text-xs text-slate-600">
|
||||
|
||||
|
||||
<!-- KONTAKT -->
|
||||
|
||||
<div>
|
||||
|
||||
<p class="font-semibold mb-2">
|
||||
Kontakt
|
||||
</p>
|
||||
|
||||
|
||||
{% if company.phone %}
|
||||
<p>{{ company.phone }}</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.email %}
|
||||
<p>{{ company.email }}</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.website %}
|
||||
<p>{{ company.website }}</p>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- STEUERN -->
|
||||
|
||||
<div>
|
||||
|
||||
<p class="font-semibold mb-2">
|
||||
Steuern
|
||||
</p>
|
||||
|
||||
|
||||
{% if company.tax_number %}
|
||||
<p>
|
||||
Steuernummer:
|
||||
{{ company.tax_number }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.vat_number %}
|
||||
<p>
|
||||
USt-IdNr.:
|
||||
{{ company.vat_number }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- BANK -->
|
||||
|
||||
<div>
|
||||
|
||||
<p class="font-semibold mb-2">
|
||||
Bankverbindung
|
||||
</p>
|
||||
|
||||
|
||||
{% if company.bank_name %}
|
||||
<p>
|
||||
{{ company.bank_name }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.iban %}
|
||||
<p>
|
||||
IBAN:
|
||||
{{ company.iban }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.bic %}
|
||||
<p>
|
||||
BIC:
|
||||
{{ company.bic }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,36 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
Rechnungswesen - Posten
|
||||
{% endblock %}
|
||||
|
||||
{% block header_title %}
|
||||
Posten hinzufügen
|
||||
{% endblock %}
|
||||
|
||||
{% block header_description %}
|
||||
Neue Ware oder Leistung hinzufügen
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
|
||||
<form method="post" enctype="multipart/form-data" class="space-y-4">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
{{ form.as_p }}
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="btn mt-4 btn-save">
|
||||
Speichern
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,56 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
Rechnungswesen - Posten
|
||||
{% endblock %}
|
||||
|
||||
{% block header_title %}
|
||||
Posten
|
||||
{% endblock %}
|
||||
|
||||
{% block header_description %}
|
||||
Leistungen und Artikel verwalten
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% load django_tables2 %}
|
||||
<div class="mb-8">
|
||||
<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>
|
||||
<p class="text-slate-400 text-sm mt-1">
|
||||
Leistungen und Artikel anlegen
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-col sm:flex-row gap-2">
|
||||
<a href="{% url 'invoices:items_add' %}"
|
||||
class="btn btn-add">
|
||||
+ Posten
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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="flex flex-wrap justify-between items-center mb-6">
|
||||
|
||||
<div>
|
||||
<h2 class="text-xl font-bold">
|
||||
Artikel und Leistungen
|
||||
</h2>
|
||||
|
||||
<p class="text-slate-400 text-sm mt-1">
|
||||
Übersicht über alle Artikel und Leistungen
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto rounded-xl">
|
||||
{% render_table table %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,69 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Rechnungswesen - Angebote{% endblock %}
|
||||
|
||||
{% block header_title %}
|
||||
Angebot erstellen
|
||||
{% endblock %}
|
||||
|
||||
{% block header_description %}
|
||||
Angebot für einen Kunden erstellen
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
|
||||
<form method="post" enctype="multipart/form-data" class="space-y-4">
|
||||
{% csrf_token %}
|
||||
|
||||
{{ form.as_p }}
|
||||
|
||||
<button class="btn btn-save">
|
||||
Speichern
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
const customer = document.getElementById("id_customer");
|
||||
const contact = document.getElementById("id_contact");
|
||||
const location = document.getElementById("id_location");
|
||||
|
||||
function fill(select, data) {
|
||||
select.innerHTML = "<option value=''>---------</option>";
|
||||
data.forEach(item => {
|
||||
select.innerHTML += `<option value="${item.id}">${item.text}</option>`;
|
||||
});
|
||||
}
|
||||
|
||||
if (customer) {
|
||||
customer.addEventListener("change", function () {
|
||||
|
||||
const id = this.value;
|
||||
|
||||
if (!id) {
|
||||
contact.innerHTML = "";
|
||||
location.innerHTML = "";
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/invoices/ajax/customer/${id}/contacts/`)
|
||||
.then(r => r.json())
|
||||
.then(data => fill(contact, data));
|
||||
|
||||
fetch(`/invoices/ajax/customer/${id}/locations/`)
|
||||
.then(r => r.json())
|
||||
.then(data => fill(location, data));
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,156 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Rechnungswesen - Angebote{% endblock %}
|
||||
|
||||
{% block header_title %}
|
||||
Angebot {{ offer.offer_number }}
|
||||
{% endblock %}
|
||||
|
||||
{% block header_description %}
|
||||
Details & Positionen
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% load django_tables2 %}
|
||||
<div class="mb-8">
|
||||
<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>
|
||||
<p class="text-slate-400 text-sm mt-1">
|
||||
Positionen zum Angebot hinzufügen
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-col sm:flex-row gap-2">
|
||||
{% if offer.status == "draft" %}
|
||||
<a href="{% url 'invoices:offers_item_add' offer.id %}" class="btn btn-add">+ Position</a>
|
||||
<a href="{% url 'invoices:offers_preview' offer.id %}" class="btn btn-action">Vorschau</a>
|
||||
<a href="{% url 'invoices:offers_download' offer.id %}" onclick="startDownloadAndRedirect()" class="btn btn-action">Download</a>
|
||||
<a href="{% url 'invoices:offers_delete' offer.id %}" class="btn btn-delete">Löschen</a>
|
||||
{% endif %}
|
||||
{% if offer.status == "sent" %}
|
||||
<a href="{% url 'invoices:offers_download' offer.id %}" class="btn btn-action">Download</a>
|
||||
<a href="{% url 'invoices:offers_accept' offer.id %}" class="btn btn-action">Akzeptiert</a>
|
||||
<a href="{% url 'invoices:offers_reject' offer.id %}" class="btn btn-action">Abgelehnt</a>
|
||||
<a href="{% url 'invoices:offers_expire' offer.id %}" class="btn btn-action">Ausgelaufen</a>
|
||||
{% endif %}
|
||||
{% if offer.status == "accepted" or offer.status == "rejected" or offer.status == "expired" %}
|
||||
<a href="{% url 'invoices:offers_download' offer.id %}" class="btn btn-action">Download</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- HEADER INFO -->
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors mb-8">
|
||||
|
||||
<h2 class="text-xl font-bold mb-6">Allgemein</h2>
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
|
||||
<!-- Kunde -->
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Kunde</div>
|
||||
<div class="font-semibold">{{ offer.customer.company_name }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Status -->
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Status</div>
|
||||
<div class="font-semibold">{{ offer.get_status_display }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Datum -->
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Angebotsdatum</div>
|
||||
<div class="font-semibold">{{ offer.issue_date|date:"d.m.Y" }}</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Gültig bis</div>
|
||||
<div class="font-semibold">{{ offer.due_date|date:"d.m.Y" }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- SNAPSHOT: KONTAKT & ADRESSE -->
|
||||
<div class="mb-8 p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
|
||||
<h2 class="text-xl font-bold mb-6">Angebotsadresse</h2>
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-6">
|
||||
|
||||
<!-- Kontakt -->
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Ansprechpartner</div>
|
||||
<div class="font-semibold">{{ offer.contact_name|default:"-" }}</div>
|
||||
|
||||
{% if offer.contact_email %}
|
||||
<div class="text-slate-400 text-sm">{{ offer.contact_email }}</div>
|
||||
{% endif %}
|
||||
|
||||
{% if offer.contact_phone %}
|
||||
<div class="text-slate-400 text-sm">{{ offer.contact_phone }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Adresse -->
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Standort</div>
|
||||
|
||||
<div class="font-semibold">
|
||||
{{ offer.location_name|default:"-" }}
|
||||
</div>
|
||||
|
||||
<div class="text-slate-400 text-sm">
|
||||
{{ offer.location_street }}
|
||||
</div>
|
||||
|
||||
<div class="text-slate-400 text-sm">
|
||||
{{ offer.location_zip }} {{ offer.location_city }}
|
||||
</div>
|
||||
|
||||
<div class="text-slate-400 text-sm">
|
||||
{{ offer.location_country }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-8 p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<h2 class="text-xl font-bold mb-6">Angebotshinweis</h2>
|
||||
<div class="grid grid-cols-1 gap-6">
|
||||
<div>
|
||||
<div class="font-semibold">{{ offer.note|default:"-" }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- POSITIONEN -->
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
|
||||
<h2 class="text-xl font-bold mb-6">Positionen</h2>
|
||||
<div class="overflow-x-auto rounded-xl">
|
||||
{% render_table table %}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mt-4 text-right font-bold">
|
||||
Gesamt: {{ total_net|floatformat:2 }} €
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script>
|
||||
function startDownloadAndRedirect() {
|
||||
setTimeout(function() {
|
||||
window.location.href = "{% url 'invoices:offers_detail' offer.id %}";
|
||||
}, 1000);
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,197 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
Rechnungswesen - Rechnungen
|
||||
{% endblock %}
|
||||
|
||||
{% block header_title %}
|
||||
Rechnungsposition hinzufügen
|
||||
{% endblock %}
|
||||
|
||||
{% block header_description %}
|
||||
Neue Rechnungsposition anlegen
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
|
||||
<form method="post" enctype="multipart/form-data" class="space-y-4">
|
||||
{% csrf_token %}
|
||||
|
||||
{{ form.as_p }}
|
||||
|
||||
<button class="btn btn-save">
|
||||
Speichern
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
const source = document.getElementById("id_source_type");
|
||||
|
||||
const fields = {
|
||||
item: document.getElementById("id_item"),
|
||||
time: document.getElementById("id_time_entry"),
|
||||
expense: document.getElementById("id_expense"),
|
||||
};
|
||||
|
||||
|
||||
function toggleFields() {
|
||||
|
||||
const value = source.value;
|
||||
|
||||
|
||||
Object.keys(fields).forEach(key => {
|
||||
|
||||
const field = fields[key];
|
||||
|
||||
if (!field) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const row = field.closest("p");
|
||||
|
||||
|
||||
if (key === value) {
|
||||
|
||||
row.style.display = "";
|
||||
|
||||
} else {
|
||||
|
||||
row.style.display = "none";
|
||||
|
||||
field.value = "";
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
source.addEventListener(
|
||||
"change",
|
||||
toggleFields
|
||||
);
|
||||
|
||||
|
||||
// Initial ausführen
|
||||
toggleFields();
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
|
||||
const source = document.getElementById("id_source_type");
|
||||
|
||||
|
||||
const selects = {
|
||||
|
||||
item: document.getElementById("id_item"),
|
||||
|
||||
time: document.getElementById("id_time_entry"),
|
||||
|
||||
expense: document.getElementById("id_expense"),
|
||||
|
||||
};
|
||||
|
||||
|
||||
const description = document.getElementById(
|
||||
"id_description"
|
||||
);
|
||||
|
||||
const quantity = document.getElementById(
|
||||
"id_quantity"
|
||||
);
|
||||
|
||||
const unit = document.getElementById(
|
||||
"id_unit"
|
||||
);
|
||||
|
||||
const price = document.getElementById(
|
||||
"id_unit_price_net"
|
||||
);
|
||||
|
||||
const tax = document.getElementById(
|
||||
"id_unit_tax_rate"
|
||||
);
|
||||
|
||||
|
||||
|
||||
function loadData(type, id){
|
||||
|
||||
|
||||
if(!id){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
fetch(
|
||||
`/invoices/ajax/invoice-item-data/?source=${type}&id=${id}`
|
||||
)
|
||||
|
||||
|
||||
.then(response => response.json())
|
||||
|
||||
|
||||
.then(data => {
|
||||
|
||||
|
||||
description.value = data.description;
|
||||
|
||||
quantity.value = data.quantity;
|
||||
|
||||
unit.value = data.unit;
|
||||
|
||||
price.value = data.unit_price_net;
|
||||
|
||||
tax.value = data.unit_tax_rate;
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Object.keys(selects).forEach(type => {
|
||||
|
||||
|
||||
if(selects[type]){
|
||||
|
||||
|
||||
selects[type].addEventListener(
|
||||
"change",
|
||||
function(){
|
||||
|
||||
loadData(
|
||||
type,
|
||||
this.value
|
||||
);
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,35 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Rechnungswesen - Angebote{% endblock %}
|
||||
|
||||
{% block header_title %}Angebote{% endblock %}
|
||||
{% block header_description %}Angebote erstellen und verwalten{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% load django_tables2 %}
|
||||
<div class="mb-8">
|
||||
<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>
|
||||
<p class="text-slate-400 text-sm mt-1">Neues Angebot erstellen</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row gap-2">
|
||||
<a href="{% url 'invoices:invoices_offers_add' %}" class="btn btn-add">+ Angebot</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<div class="mb-6">
|
||||
<h2 class="text-xl font-bold">Angebote</h2>
|
||||
<p class="text-slate-400 text-sm mt-1">Alle Angebote mit aktuellem Status</p>
|
||||
</div>
|
||||
<div class="overflow-x-auto rounded-xl">
|
||||
{% render_table table %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,732 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
|
||||
<head>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
|
||||
<style>
|
||||
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 18mm;
|
||||
}
|
||||
|
||||
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 11px;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
|
||||
h1,h2,h3,p {
|
||||
margin:0;
|
||||
}
|
||||
|
||||
|
||||
table {
|
||||
width:100%;
|
||||
border-collapse:collapse;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.header {
|
||||
display:flex;
|
||||
justify-content:space-between;
|
||||
}
|
||||
|
||||
|
||||
.logo {
|
||||
height:128px;
|
||||
margin-bottom:15px;
|
||||
}
|
||||
|
||||
|
||||
.company-name {
|
||||
font-size:24px;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
|
||||
.invoice-title {
|
||||
font-size:32px;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.info-table td {
|
||||
padding:4px 0;
|
||||
}
|
||||
|
||||
|
||||
.label {
|
||||
color:#64748b;
|
||||
padding-right:30px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.divider {
|
||||
border-top:1px solid #e2e8f0;
|
||||
margin:30px 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.receiver-title {
|
||||
font-size:10px;
|
||||
text-transform:uppercase;
|
||||
color:#64748b;
|
||||
letter-spacing:1px;
|
||||
}
|
||||
|
||||
|
||||
.receiver-name {
|
||||
font-size:16px;
|
||||
font-weight:bold;
|
||||
margin-top:5px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.invoice-heading {
|
||||
font-size:22px;
|
||||
font-weight:bold;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.items-wrapper {
|
||||
border:1px solid #e2e8f0;
|
||||
border-radius:10px;
|
||||
overflow:hidden;
|
||||
margin-top:20px;
|
||||
}
|
||||
|
||||
|
||||
.items {
|
||||
width:100%;
|
||||
border-collapse:collapse;
|
||||
}
|
||||
|
||||
|
||||
.items thead th:first-child {
|
||||
border-top-left-radius:10px;
|
||||
}
|
||||
|
||||
|
||||
.items thead th:last-child {
|
||||
border-top-right-radius:10px;
|
||||
}
|
||||
|
||||
|
||||
.items th {
|
||||
background:{{ company.color }};
|
||||
color:white;
|
||||
padding:10px;
|
||||
text-align:left;
|
||||
}
|
||||
|
||||
|
||||
.items td {
|
||||
padding:10px;
|
||||
border-bottom:1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
|
||||
.items tbody tr:last-child td {
|
||||
border-bottom:none;
|
||||
}
|
||||
|
||||
|
||||
.right {
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.total-box {
|
||||
|
||||
margin-top:30px;
|
||||
margin-left:auto;
|
||||
width:250px;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.total-row {
|
||||
|
||||
display:flex;
|
||||
justify-content:space-between;
|
||||
padding:6px 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
.total-final {
|
||||
|
||||
border-top:1px solid #cbd5e1;
|
||||
margin-top:10px;
|
||||
padding-top:10px;
|
||||
font-size:16px;
|
||||
font-weight:bold;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.note {
|
||||
margin-top:30px;
|
||||
padding:12px;
|
||||
border:1px solid #e2e8f0;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.small-business {
|
||||
|
||||
margin-top:25px;
|
||||
color:#64748b;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 18mm 18mm 35mm 18mm;
|
||||
}
|
||||
|
||||
|
||||
.footer {
|
||||
position: fixed;
|
||||
bottom: -25mm;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
padding-top:15px;
|
||||
border-top:1px solid #e2e8f0;
|
||||
|
||||
display:flex;
|
||||
justify-content:space-between;
|
||||
|
||||
font-size:10px;
|
||||
color:#64748b;
|
||||
}
|
||||
|
||||
|
||||
.footer-title {
|
||||
font-weight:bold;
|
||||
color:#334155;
|
||||
margin-bottom:5px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
|
||||
<!-- HEADER -->
|
||||
|
||||
|
||||
<div class="header">
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
{% if company.logo %}
|
||||
<img src="{{ company.logo.url }}" class="logo">
|
||||
{% else %}
|
||||
<h1 class="company-name" style="color: {{ company.color }}">
|
||||
{{ company.companyname }}
|
||||
</h1>
|
||||
|
||||
{% if company.slogan %}
|
||||
<p>
|
||||
{{ company.slogan }}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
<p style="margin-top:15px">
|
||||
{{ company.name }}<br>
|
||||
{{ company.street }} · {{ company.zip }} {{ company.city }}
|
||||
</p>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div style="text-align:right">
|
||||
|
||||
|
||||
<div class="invoice-title">
|
||||
ANGEBOT
|
||||
</div>
|
||||
|
||||
|
||||
<table class="info-table">
|
||||
|
||||
|
||||
<tr>
|
||||
<td class="label">
|
||||
Angebotsnummer
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ offer.offer_number }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td class="label">
|
||||
Angebotsdatum
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ offer.issue_date|date:"d.m.Y" }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
{% if offer.due_date %}
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="label">
|
||||
Gültig bis
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ offer.due_date|date:"d.m.Y" }}
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- EMPFÄNGER -->
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
|
||||
<div class="receiver-title">
|
||||
Angebotsempfänger
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="receiver-name">
|
||||
|
||||
{% if offer.customer.type == "company" %}
|
||||
{{ offer.customer.company_name }}
|
||||
{% else %}
|
||||
{{ offer.contact_name }}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{% if offer.customer.type == "company" %}
|
||||
|
||||
<p>
|
||||
z.Hd. {{ offer.contact_name }}
|
||||
</p>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
<p style="margin-top:10px">
|
||||
|
||||
{{ offer.location_street }}<br>
|
||||
|
||||
{{ offer.location_zip }}
|
||||
{{ offer.location_city }}
|
||||
|
||||
</p>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- TITEL -->
|
||||
|
||||
|
||||
<div style="margin-top:40px">
|
||||
|
||||
|
||||
<div class="invoice-heading"
|
||||
style="color:{{ company.color }}">
|
||||
|
||||
Angebot
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{% if company.offer_header_text %}
|
||||
|
||||
<p>
|
||||
{{ company.offer_header_text|linebreaksbr }}
|
||||
</p>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- POSITIONEN -->
|
||||
|
||||
<div class="items-wrapper">
|
||||
<table class="items">
|
||||
|
||||
|
||||
<thead>
|
||||
|
||||
<tr>
|
||||
|
||||
<th>
|
||||
Nr.
|
||||
</th>
|
||||
|
||||
<th>
|
||||
Beschreibung
|
||||
</th>
|
||||
|
||||
<th class="left">
|
||||
Menge
|
||||
</th>
|
||||
|
||||
<th class="left">
|
||||
Einheit
|
||||
</th>
|
||||
|
||||
<th class="left">
|
||||
Preis
|
||||
</th>
|
||||
|
||||
|
||||
{% if not company.is_small_business %}
|
||||
|
||||
<th class="left">
|
||||
Steuer
|
||||
</th>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
<th class="left">
|
||||
Gesamt
|
||||
</th>
|
||||
|
||||
|
||||
</tr>
|
||||
|
||||
</thead>
|
||||
|
||||
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
{% for item in items %}
|
||||
|
||||
<tr>
|
||||
|
||||
|
||||
<td>
|
||||
{{ forloop.counter }}
|
||||
</td>
|
||||
|
||||
|
||||
<td>
|
||||
{{ item.description }}
|
||||
</td>
|
||||
|
||||
|
||||
<td class="left">
|
||||
{{ item.quantity }}
|
||||
</td>
|
||||
|
||||
|
||||
<td class="left">
|
||||
{{ item.unit }}
|
||||
</td>
|
||||
|
||||
|
||||
<td class="left">
|
||||
{{ item.unit_price_net|floatformat:2 }} €
|
||||
</td>
|
||||
|
||||
|
||||
{% if not company.is_small_business %}
|
||||
|
||||
<td class="left">
|
||||
{{ item.unit_tax_rate|floatformat:0 }} %
|
||||
</td>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
<td class="left">
|
||||
{{ item.calculated_total_net|floatformat:2 }} €
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
</tr>
|
||||
|
||||
|
||||
{% endfor %}
|
||||
|
||||
|
||||
</tbody>
|
||||
|
||||
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- SUMMEN -->
|
||||
|
||||
|
||||
<div class="total-box">
|
||||
|
||||
|
||||
<div class="total-row">
|
||||
|
||||
<span>
|
||||
Netto
|
||||
</span>
|
||||
|
||||
<span>
|
||||
{{ total_net|floatformat:2 }} €
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{% if not company.is_small_business %}
|
||||
{% for tax_rate,tax_amount in tax_summary.items %}
|
||||
|
||||
<div class="total-row">
|
||||
|
||||
<span>
|
||||
Umsatzsteuer {{ tax_rate|floatformat:0 }} %
|
||||
</span>
|
||||
|
||||
|
||||
<span>
|
||||
{{ tax_amount|floatformat:2 }} €
|
||||
</span>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="total-row total-final">
|
||||
|
||||
<span>
|
||||
Gesamt
|
||||
</span>
|
||||
|
||||
|
||||
<span>
|
||||
|
||||
{% if company.is_small_business %}
|
||||
{{ total_net|floatformat:2 }}
|
||||
{% else %}
|
||||
{{ total_gross|floatformat:2 }}
|
||||
{% endif %}
|
||||
|
||||
€
|
||||
|
||||
</span>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{% if offer.note %}
|
||||
|
||||
<div class="note">
|
||||
|
||||
<div class="receiver-title">
|
||||
Angebotshinweis
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
{{ offer.note|linebreaksbr }}
|
||||
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{% if company.is_small_business %}
|
||||
|
||||
<div class="note">
|
||||
|
||||
<div class="receiver-title">
|
||||
Kleinunternehmerhinweis
|
||||
</div>
|
||||
<br>
|
||||
{{ company.small_business_text }}
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- FOOTER -->
|
||||
|
||||
|
||||
<div class="footer">
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
<div class="footer-title">
|
||||
Kontakt
|
||||
</div>
|
||||
|
||||
{% if company.phone %}
|
||||
{{ company.phone }}<br>
|
||||
{% endif %}
|
||||
|
||||
{% if company.email %}
|
||||
{{ company.email }}<br>
|
||||
{% endif %}
|
||||
|
||||
{% if company.website %}
|
||||
{{ company.website }}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
<div class="footer-title">
|
||||
Steuern
|
||||
</div>
|
||||
|
||||
|
||||
{% if company.tax_number %}
|
||||
Steuernummer: {{ company.tax_number }}<br>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.vat_number %}
|
||||
USt-IdNr.: {{ company.vat_number }}
|
||||
{% endif %}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
<div class="footer-title">
|
||||
Bank
|
||||
</div>
|
||||
|
||||
|
||||
{% if company.bank_name %}
|
||||
{{ company.bank_name }}<br>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.iban %}
|
||||
IBAN: {{ company.iban }}<br>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.bic %}
|
||||
BIC: {{ company.bic }}
|
||||
{% endif %}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,450 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Rechnungswesen - Angebote{% endblock %}
|
||||
|
||||
{% block header_title %}Angebot {{ offer.offer_number }}{% endblock %}
|
||||
|
||||
{% block header_description %}Vorschau{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="w-5xl max-w-5xl mx-auto bg-white rounded-2xl shadow p-10 text-slate-900">
|
||||
|
||||
<!-- HEADER -->
|
||||
<div class="flex justify-between items-start">
|
||||
|
||||
<div>
|
||||
{% if company.logo %}
|
||||
<img src="{{ company.logo.url }}" class="h-32 mb-4">
|
||||
{% else %}
|
||||
<h1 class="text-2xl font-bold" style="color: {{ company.color }}">
|
||||
{{ company.companyname }}
|
||||
</h1>
|
||||
|
||||
{% if company.slogan %}
|
||||
<p class="text-sm text-slate-600 mt-1">
|
||||
{{ company.slogan }}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
<div class="mt-4 text-sm">
|
||||
<p>{{ company.name }}</p>
|
||||
<p>
|
||||
{{ company.street }}
|
||||
·
|
||||
{{ company.zip }}
|
||||
{{ company.city }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="text-right">
|
||||
|
||||
<h2 class="text-3xl font-bold ">
|
||||
ANGEBOT
|
||||
</h2>
|
||||
|
||||
|
||||
<table class="mt-4 text-sm ml-auto">
|
||||
|
||||
<tr>
|
||||
<td class="text-slate-600 pr-8 py-1">
|
||||
Angebotsnummer
|
||||
</td>
|
||||
<td class="font-medium">
|
||||
{{ offer.offer_number }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="text-slate-600 pr-8 py-1">
|
||||
Angebotsdatum
|
||||
</td>
|
||||
<td class="font-medium">
|
||||
{{ offer.issue_date|date:"d.m.Y" }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
{% if offer.due_date %}
|
||||
<tr>
|
||||
<td class="text-slate-600 pr-8 py-1">
|
||||
Gültig bis
|
||||
</td>
|
||||
<td class="font-medium">
|
||||
{{ offer.due_date|date:"d.m.Y" }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="my-8 border-t"></div>
|
||||
|
||||
|
||||
<!-- EMPFÄNGER -->
|
||||
|
||||
<div class="mb-10">
|
||||
|
||||
<p class="text-xs uppercase tracking-wide text-slate-600 mb-2">
|
||||
Angebotsempfänger
|
||||
</p>
|
||||
|
||||
<p class="font-semibold text-lg ">
|
||||
|
||||
{% if offer.customer.type == "company" %}
|
||||
{{ offer.customer.company_name }}
|
||||
{% else %}
|
||||
{{ offer.contact_name }}
|
||||
{% endif %}
|
||||
|
||||
</p>
|
||||
|
||||
|
||||
{% if offer.customer.type == "company" %}
|
||||
<p class="text-sm">
|
||||
z.Hd. {{ offer.contact_name }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<p class="mt-2 text-sm">
|
||||
{{ offer.location_street }}<br>
|
||||
{{ offer.location_zip }}
|
||||
{{ offer.location_city }}
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- TITEL -->
|
||||
|
||||
<div class="mb-8">
|
||||
|
||||
<h2 class="text-2xl font-bold" style="color: {{ company.color }}">
|
||||
Angebot
|
||||
</h2>
|
||||
|
||||
|
||||
{% if company.offer_header_text %}
|
||||
<div class="mt-3 text-sm text-slate-600">
|
||||
{{ company.offer_header_text|linebreaks }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- POSITIONEN -->
|
||||
|
||||
<div class="border rounded-xl overflow-hidden">
|
||||
|
||||
<table class="w-full text-sm">
|
||||
|
||||
<thead>
|
||||
|
||||
<tr style="background-color: {{ company.color }}" class="text-white">
|
||||
|
||||
<th class="p-3 text-left">
|
||||
Nr.
|
||||
</th>
|
||||
|
||||
<th class="p-3 text-left">
|
||||
Beschreibung
|
||||
</th>
|
||||
|
||||
<th class="p-3 text-right">
|
||||
Menge
|
||||
</th>
|
||||
|
||||
<th class="p-3 text-right">
|
||||
Einheit
|
||||
</th>
|
||||
|
||||
<th class="p-3 text-right">
|
||||
Preis
|
||||
</th>
|
||||
|
||||
|
||||
{% if not company.is_small_business %}
|
||||
<th class="p-3 text-right">
|
||||
Steuer
|
||||
</th>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<th class="p-3 text-right">
|
||||
Gesamt
|
||||
</th>
|
||||
|
||||
</tr>
|
||||
|
||||
</thead>
|
||||
|
||||
|
||||
<tbody>
|
||||
|
||||
{% for item in items %}
|
||||
|
||||
<tr class="border-t">
|
||||
|
||||
<td class="p-3 text-left">
|
||||
{{ forloop.counter }}
|
||||
</td>
|
||||
|
||||
<td class="p-3 text-left">
|
||||
{{ item.description }}
|
||||
</td>
|
||||
|
||||
<td class="p-3 text-right">
|
||||
{{ item.quantity }}
|
||||
</td>
|
||||
|
||||
<td class="p-3 text-right">
|
||||
{{ item.unit }}
|
||||
</td>
|
||||
|
||||
<td class="p-3 text-right">
|
||||
{{ item.unit_price_net|floatformat:2 }} €
|
||||
</td>
|
||||
|
||||
|
||||
{% if not company.is_small_business %}
|
||||
<td class="p-3 text-right">
|
||||
{{ item.unit_tax_rate|floatformat:0 }} %
|
||||
</td>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<td class="p-3 text-right font-medium">
|
||||
{{ item.calculated_total_net|floatformat:2 }} €
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- SUMMEN -->
|
||||
|
||||
<div class="flex justify-end mt-8">
|
||||
|
||||
<div class="w-80 text-sm">
|
||||
|
||||
<div class="flex justify-between py-2">
|
||||
<span class="text-slate-600">
|
||||
Netto
|
||||
</span>
|
||||
|
||||
<span>
|
||||
{{ total_net|floatformat:2 }} €
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
{% if not company.is_small_business %}
|
||||
|
||||
{% for tax_rate, tax_amount in tax_summary.items %}
|
||||
|
||||
<div class="flex justify-between py-2">
|
||||
|
||||
<span class="text-slate-600">
|
||||
Umsatzsteuer {{ tax_rate|floatformat:0 }} %
|
||||
</span>
|
||||
|
||||
<span>
|
||||
{{ tax_amount|floatformat:2 }} €
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
<div class="border-t mt-3 pt-4 flex justify-between text-lg font-bold ">
|
||||
|
||||
<span>
|
||||
Gesamt
|
||||
</span>
|
||||
|
||||
<span>
|
||||
{% if company.is_small_business %}
|
||||
{{ total_net|floatformat:2 }} €
|
||||
{% else %}
|
||||
{{ total_gross|floatformat:2 }} €
|
||||
{% endif %}
|
||||
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- NOTIZ -->
|
||||
|
||||
{% if offer.note %}
|
||||
|
||||
<div class="mt-10 border rounded-xl p-4">
|
||||
|
||||
<p class="text-xs uppercase tracking-wide text-slate-600 mb-2">
|
||||
Angebotshinweis
|
||||
</p>
|
||||
|
||||
|
||||
<div class="text-sm">
|
||||
{{ offer.note|linebreaks }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- KLEINUNTERNEHMER -->
|
||||
{% if company.is_small_business %}
|
||||
|
||||
<div class="mt-10 border rounded-xl p-4">
|
||||
|
||||
<p class="text-xs uppercase tracking-wide text-slate-600 mb-2">
|
||||
Kleinunternehmerhinweis
|
||||
</p>
|
||||
<div class="text-sm">
|
||||
{{ company.small_business_text }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- FOOTER -->
|
||||
|
||||
<div class="mt-14 pt-6 border-t grid grid-cols-3 gap-6 text-xs text-slate-600">
|
||||
|
||||
|
||||
<!-- KONTAKT -->
|
||||
|
||||
<div>
|
||||
|
||||
<p class="font-semibold mb-2">
|
||||
Kontakt
|
||||
</p>
|
||||
|
||||
|
||||
{% if company.phone %}
|
||||
<p>{{ company.phone }}</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.email %}
|
||||
<p>{{ company.email }}</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.website %}
|
||||
<p>{{ company.website }}</p>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- STEUERN -->
|
||||
|
||||
<div>
|
||||
|
||||
<p class="font-semibold mb-2">
|
||||
Steuern
|
||||
</p>
|
||||
|
||||
|
||||
{% if company.tax_number %}
|
||||
<p>
|
||||
Steuernummer:
|
||||
{{ company.tax_number }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.vat_number %}
|
||||
<p>
|
||||
USt-IdNr.:
|
||||
{{ company.vat_number }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- BANK -->
|
||||
|
||||
<div>
|
||||
|
||||
<p class="font-semibold mb-2">
|
||||
Bankverbindung
|
||||
</p>
|
||||
|
||||
|
||||
{% if company.bank_name %}
|
||||
<p>
|
||||
{{ company.bank_name }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.iban %}
|
||||
<p>
|
||||
IBAN:
|
||||
{{ company.iban }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.bic %}
|
||||
<p>
|
||||
BIC:
|
||||
{{ company.bic }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,61 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
Rechnungswesen
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block header_title %}
|
||||
Rechnungswesen
|
||||
{% endblock %}
|
||||
|
||||
{% block header_description %}
|
||||
Angebote, Rechnungen, Mahnungen verwalten
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<!-- MODULE GRID -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
|
||||
<a href="{% url 'invoices:invoices_offers_overview' %}" class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<div class="text-2xl mb-2">📄</div>
|
||||
<h2 class="text-xl font-bold">Angebote</h2>
|
||||
<p class="text-slate-400 text-sm mt-1">Angebote erstellen und verwalten</p>
|
||||
</a>
|
||||
<a href="{% url 'invoices:invoices_invoices_overview' %}" class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<div class="text-2xl mb-2">🧾</div>
|
||||
<h2 class="text-xl font-bold">Rechnungen</h2>
|
||||
<p class="text-slate-400 text-sm mt-1">Rechnungen erstellen und verwalten</p>
|
||||
</a>
|
||||
<a href="{% url 'invoices:invoices_reminders_overview' %}" class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<div class="text-2xl mb-2">⚠️</div>
|
||||
<h2 class="text-xl font-bold">Mahnungen</h2>
|
||||
<p class="text-slate-400 text-sm mt-1">Offene Forderungen verfolgen</p>
|
||||
</a>
|
||||
<a href="{% url 'invoices:customers_overview' %}" class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<div class="text-2xl mb-2">👥</div>
|
||||
<h2 class="text-xl font-bold">Kunden</h2>
|
||||
<p class="text-slate-400 text-sm mt-1">Kundenstammdaten verwalten</p>
|
||||
</a>
|
||||
<a href="{% url 'invoices:items_overview' %}" class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<div class="text-2xl mb-2">📦</div>
|
||||
<h2 class="text-xl font-bold">Posten</h2>
|
||||
<p class="text-slate-400 text-sm mt-1">Leistungen und Artikel verwalten</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- OPTIONAL INFO BOX -->
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors mt-8">
|
||||
|
||||
<h2 class="text-xl font-bold">
|
||||
Zusammenfassung
|
||||
</h2>
|
||||
|
||||
<p class="text-slate-400 text-sm mt-1">
|
||||
folgt
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,31 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Rechnungswesen - Mahnungen{% endblock %}
|
||||
|
||||
{% block header_title %}
|
||||
Mahnung erstellen
|
||||
{% endblock %}
|
||||
|
||||
{% block header_description %}
|
||||
Mahnung für einen Kunden erstellen
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
||||
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
|
||||
<form method="post" enctype="multipart/form-data" class="space-y-4">
|
||||
{% csrf_token %}
|
||||
|
||||
{{ form.as_p }}
|
||||
|
||||
<button class="btn btn-save">
|
||||
Speichern
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,184 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Rechnungswesen - Mahnungen{% endblock %}
|
||||
|
||||
{% block header_title %}
|
||||
Mahnung {{ reminder.reminder_number }}
|
||||
{% endblock %}
|
||||
|
||||
{% block header_description %}
|
||||
Details
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="mb-8">
|
||||
<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>
|
||||
<p class="text-slate-400 text-sm mt-1">
|
||||
Mahnung verwalten
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-col sm:flex-row gap-2">
|
||||
{% if reminder.status == "draft" %}
|
||||
<a href="{% url 'invoices:reminders_download' reminder.id %}" onclick="startDownloadAndRedirect()" class="btn btn-action">Download</a>
|
||||
<a href="{% url 'invoices:reminders_delete' reminder.id %}" class="btn btn-delete">Löschen</a>
|
||||
{% endif %}
|
||||
{% if reminder.status == "sent" %}
|
||||
<a href="{% url 'invoices:reminders_download' reminder.id %}" class="btn btn-action">Download</a>
|
||||
<a href="{% url 'invoices:reminders_cancel' reminder.id %}" class="btn btn-delete">Stornieren</a>
|
||||
<a href="{% url 'invoices:reminders_paid' reminder.id %}" class="btn btn-action">Zahlung verbuchen</a>
|
||||
<a href="{% url 'invoices:reminders_expire' reminder.id %}" class="btn btn-action">Überfällig</a>
|
||||
{% endif %}
|
||||
{% if reminder.status == "paid" or reminder.status == "canceled" or reminder.status == "expired" %}
|
||||
<a href="{% url 'invoices:reminders_download' reminder.id %}" class="btn btn-action">Download</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- HEADER INFO -->
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors mb-8">
|
||||
|
||||
<h2 class="text-xl font-bold mb-6">Allgemein</h2>
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<!-- Status -->
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Status</div>
|
||||
<div class="font-semibold">{{ reminder.get_status_display }}</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Level</div>
|
||||
<div class="font-semibold">{{ reminder.level }}/3</div>
|
||||
</div>
|
||||
|
||||
<!-- Datum -->
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Mahnungsdatum</div>
|
||||
<div class="font-semibold">{{ reminder.issue_date|date:"d.m.Y" }}</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Neues Zahlungsziel</div>
|
||||
<div class="font-semibold">{{ reminder.due_date|date:"d.m.Y" }}</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Mahngebühr</div>
|
||||
<div class="font-semibold">{{ reminder.fee }} €</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- HEADER INFO -->
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors mb-8">
|
||||
|
||||
<h2 class="text-xl font-bold mb-6">Rechnungsinformationen</h2>
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Rechnungsnummer</div>
|
||||
<div class="font-semibold"><a class="company_link" href="{% url 'invoices:invoices_detail' reminder.invoice.id %}">{{ reminder.invoice.invoice_number }}</a></div>
|
||||
</div>
|
||||
|
||||
<!-- Kunde -->
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Kunde</div>
|
||||
<div class="font-semibold">{{ reminder.invoice.customer.company_name }}</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Projekt</div>
|
||||
<div class="font-semibold">{{ reminder.invoice.project.name|default:"-" }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Status -->
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Rechnungsstatus</div>
|
||||
<div class="font-semibold">{{ reminder.invoice.get_status_display }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Datum -->
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Rechnungsdatum</div>
|
||||
<div class="font-semibold">{{ reminder.invoice.issue_date|date:"d.m.Y" }}</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Ursprüngliches Zahlungsziel</div>
|
||||
<div class="font-semibold">{{ reminder.invoice.due_date|date:"d.m.Y" }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- SNAPSHOT: KONTAKT & ADRESSE -->
|
||||
<div class="mb-8 p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
|
||||
<h2 class="text-xl font-bold mb-6">Mahnungsadresse</h2>
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-6">
|
||||
|
||||
<!-- Kontakt -->
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Ansprechpartner</div>
|
||||
<div class="font-semibold">{{ reminder.invoice.contact_name|default:"-" }}</div>
|
||||
|
||||
{% if reminder.invoice.contact_email %}
|
||||
<div class="text-slate-400 text-sm">{{ reminder.invoice.contact_email }}</div>
|
||||
{% endif %}
|
||||
|
||||
{% if reminder.invoice.contact_phone %}
|
||||
<div class="text-slate-400 text-sm">{{ reminder.invoice.contact_phone }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Adresse -->
|
||||
<div>
|
||||
<div class="text-slate-400 text-sm">Standort</div>
|
||||
|
||||
<div class="font-semibold">
|
||||
{{ reminder.invoice.location_name|default:"-" }}
|
||||
</div>
|
||||
|
||||
<div class="text-slate-400 text-sm">
|
||||
{{ reminder.invoice.location_street }}
|
||||
</div>
|
||||
|
||||
<div class="text-slate-400 text-sm">
|
||||
{{ reminder.invoice.location_zip }} {{ reminder.invoice.location_city }}
|
||||
</div>
|
||||
|
||||
<div class="text-slate-400 text-sm">
|
||||
{{ reminder.invoice.location_country }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-8 p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<h2 class="text-xl font-bold mb-6">Mahnungshinweis</h2>
|
||||
<div class="grid grid-cols-1 gap-6">
|
||||
<div>
|
||||
<div class="font-semibold">{{ reminder.note|default:"-" }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
function startDownloadAndRedirect() {
|
||||
setTimeout(function() {
|
||||
window.location.href = "{% url 'invoices:reminders_detail' reminder.id %}";
|
||||
}, 1000);
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,35 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Rechnungswesen - Mahnungen{% endblock %}
|
||||
|
||||
{% block header_title %}Mahnungen{% endblock %}
|
||||
{% block header_description %}Offene Forderungen verfolgen{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% load django_tables2 %}
|
||||
<div class="mb-8">
|
||||
<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>
|
||||
<p class="text-slate-400 text-sm mt-1">Neue Mahnung erstellen</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row gap-2">
|
||||
<a href="{% url 'invoices:invoices_reminders_add' %}" class="btn btn-add">+ Mahnung</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-6 rounded-xl shadow bg-white dark:bg-slate-800 text-slate-900 dark:text-white transition-colors">
|
||||
<div class="mb-6">
|
||||
<h2 class="text-xl font-bold">Mahnungen</h2>
|
||||
<p class="text-slate-400 text-sm mt-1">Alle Mahnungen mit aktuellem Status</p>
|
||||
</div>
|
||||
<div class="overflow-x-auto rounded-xl">
|
||||
{% render_table table %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,663 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
|
||||
<head>
|
||||
|
||||
<meta charset="UTF-8">
|
||||
|
||||
<style>
|
||||
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 18mm;
|
||||
}
|
||||
|
||||
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 11px;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
|
||||
h1,h2,h3,p {
|
||||
margin:0;
|
||||
}
|
||||
|
||||
|
||||
table {
|
||||
width:100%;
|
||||
border-collapse:collapse;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.header {
|
||||
display:flex;
|
||||
justify-content:space-between;
|
||||
}
|
||||
|
||||
|
||||
.logo {
|
||||
height:128px;
|
||||
margin-bottom:15px;
|
||||
}
|
||||
|
||||
|
||||
.company-name {
|
||||
font-size:24px;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
|
||||
.invoice-title {
|
||||
font-size:32px;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.info-table td {
|
||||
padding:4px 0;
|
||||
}
|
||||
|
||||
|
||||
.label {
|
||||
color:#64748b;
|
||||
padding-right:30px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.divider {
|
||||
border-top:1px solid #e2e8f0;
|
||||
margin:30px 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.receiver-title {
|
||||
font-size:10px;
|
||||
text-transform:uppercase;
|
||||
color:#64748b;
|
||||
letter-spacing:1px;
|
||||
}
|
||||
|
||||
|
||||
.receiver-name {
|
||||
font-size:16px;
|
||||
font-weight:bold;
|
||||
margin-top:5px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.invoice-heading {
|
||||
font-size:22px;
|
||||
font-weight:bold;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.items-wrapper {
|
||||
border:1px solid #e2e8f0;
|
||||
border-radius:10px;
|
||||
overflow:hidden;
|
||||
margin-top:20px;
|
||||
}
|
||||
|
||||
|
||||
.items {
|
||||
width:100%;
|
||||
border-collapse:collapse;
|
||||
}
|
||||
|
||||
|
||||
.items thead th:first-child {
|
||||
border-top-left-radius:10px;
|
||||
}
|
||||
|
||||
|
||||
.items thead th:last-child {
|
||||
border-top-right-radius:10px;
|
||||
}
|
||||
|
||||
|
||||
.items th {
|
||||
background:{{ company.color }};
|
||||
color:white;
|
||||
padding:10px;
|
||||
text-align:left;
|
||||
}
|
||||
|
||||
|
||||
.items td {
|
||||
padding:10px;
|
||||
border-bottom:1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
|
||||
.items tbody tr:last-child td {
|
||||
border-bottom:none;
|
||||
}
|
||||
|
||||
|
||||
.right {
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.total-box {
|
||||
|
||||
margin-top:30px;
|
||||
margin-left:auto;
|
||||
width:250px;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.total-row {
|
||||
|
||||
display:flex;
|
||||
justify-content:space-between;
|
||||
padding:6px 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
.total-final {
|
||||
|
||||
border-top:1px solid #cbd5e1;
|
||||
margin-top:10px;
|
||||
padding-top:10px;
|
||||
font-size:16px;
|
||||
font-weight:bold;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.note {
|
||||
margin-top:30px;
|
||||
padding:12px;
|
||||
border:1px solid #e2e8f0;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.small-business {
|
||||
|
||||
margin-top:25px;
|
||||
color:#64748b;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 18mm 18mm 35mm 18mm;
|
||||
}
|
||||
|
||||
|
||||
.footer {
|
||||
position: fixed;
|
||||
bottom: -25mm;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
padding-top:15px;
|
||||
border-top:1px solid #e2e8f0;
|
||||
|
||||
display:flex;
|
||||
justify-content:space-between;
|
||||
|
||||
font-size:10px;
|
||||
color:#64748b;
|
||||
}
|
||||
|
||||
|
||||
.footer-title {
|
||||
font-weight:bold;
|
||||
color:#334155;
|
||||
margin-bottom:5px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
|
||||
<!-- HEADER -->
|
||||
|
||||
|
||||
<div class="header">
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
{% if company.logo %}
|
||||
<img src="{{ company.logo.url }}" class="logo">
|
||||
{% else %}
|
||||
<h1 class="company-name" style="color: {{ company.color }}">
|
||||
{{ company.companyname }}
|
||||
</h1>
|
||||
|
||||
{% if company.slogan %}
|
||||
<p>
|
||||
{{ company.slogan }}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
<p style="margin-top:15px">
|
||||
{{ company.name }}<br>
|
||||
{{ company.street }} · {{ company.zip }} {{ company.city }}
|
||||
</p>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div style="text-align:right">
|
||||
|
||||
|
||||
<div class="invoice-title">
|
||||
MAHNUNG
|
||||
</div>
|
||||
|
||||
|
||||
<table class="info-table">
|
||||
<tr>
|
||||
<td class="label">Mahnungsnummer</td>
|
||||
<td>{{ reminder.reminder_number }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="label">Mahnungsdatum</td>
|
||||
<td>{{ reminder.issue_date|date:"d.m.Y" }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="label">Mahnungsstufe</td>
|
||||
<td>{{ reminder.level }}. Mahnung</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="label">Ursprüngliches Zahlungsziel</td>
|
||||
<td>{{ reminder.invoice.due_date|date:"d.m.Y" }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="label">Neues Zahlungsziel</td>
|
||||
<td>{{ reminder.due_date|date:"d.m.Y" }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="label">Rechnungsnummer</td>
|
||||
<td>{{ reminder.invoice.invoice_number }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- EMPFÄNGER -->
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
|
||||
<div class="receiver-title">
|
||||
Empfänger
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="receiver-name">
|
||||
|
||||
{% if reminder.invoice.customer.type == "company" %}
|
||||
{{ reminder.invoice.customer.company_name }}
|
||||
{% else %}
|
||||
{{ reminder.invoice.contact_name }}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{% if reminder.invoice.customer.type == "company" %}
|
||||
|
||||
<p>
|
||||
z.Hd. {{ reminder.invoice.contact_name }}
|
||||
</p>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
<p style="margin-top:10px">
|
||||
|
||||
{{ reminder.invoice.location_street }}<br>
|
||||
|
||||
{{ reminder.invoice.location_zip }}
|
||||
{{ reminder.invoice.location_city }}
|
||||
|
||||
</p>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- TITEL -->
|
||||
|
||||
|
||||
<div style="margin-top:40px">
|
||||
|
||||
|
||||
<div class="invoice-heading"
|
||||
style="color:{{ company.color }}">
|
||||
|
||||
Mahnung
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{% if company.reminder_header_text %}
|
||||
|
||||
<p>
|
||||
{{ company.reminder_header_text|linebreaksbr }}
|
||||
</p>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- FORDERUNGSÜBERSICHT -->
|
||||
|
||||
|
||||
<div class="items-wrapper">
|
||||
|
||||
<table class="items">
|
||||
|
||||
|
||||
<thead>
|
||||
|
||||
<tr>
|
||||
|
||||
<th>
|
||||
Beschreibung
|
||||
</th>
|
||||
|
||||
<th class="right">
|
||||
Betrag
|
||||
</th>
|
||||
|
||||
</tr>
|
||||
|
||||
</thead>
|
||||
|
||||
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td>
|
||||
Rechnung {{ reminder.invoice.invoice_number }}
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ invoice_amount|floatformat:2 }} €
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
{% if previous_reminders or reminder.fee > 0 %}
|
||||
|
||||
{% for old_reminder in previous_reminders %}
|
||||
|
||||
<tr>
|
||||
|
||||
<td>
|
||||
{{ old_reminder.level }}. Mahnung
|
||||
({{ old_reminder.issue_date|date:"d.m.Y" }})
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ old_reminder.fee|floatformat:2 }} €
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td>
|
||||
Aktuelle Mahngebühr
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ reminder.fee|floatformat:2 }} €
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
</tbody>
|
||||
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- GESAMTFORDERUNG -->
|
||||
|
||||
|
||||
<div class="total-box">
|
||||
|
||||
|
||||
<div class="total-row">
|
||||
|
||||
<span>
|
||||
Offener Rechnungsbetrag
|
||||
</span>
|
||||
|
||||
<span>
|
||||
{{ invoice_amount|floatformat:2 }} €
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{% if previous_reminders or reminder.fee > 0 %}
|
||||
|
||||
<div class="total-row">
|
||||
|
||||
<span>
|
||||
Mahngebühren
|
||||
</span>
|
||||
|
||||
<span>
|
||||
{{ total_fees|floatformat:2 }} €
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
<div class="total-row total-final">
|
||||
|
||||
<span>
|
||||
Gesamtforderung
|
||||
</span>
|
||||
|
||||
|
||||
<span>
|
||||
{{ total_due|floatformat:2 }} €
|
||||
</span>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{% if reminder.note %}
|
||||
|
||||
<div class="note">
|
||||
|
||||
<div class="receiver-title">
|
||||
Mahnungshinweis
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
{{ reminder.note|linebreaksbr }}
|
||||
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- FOOTER -->
|
||||
|
||||
|
||||
<div class="footer">
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
<div class="footer-title">
|
||||
Kontakt
|
||||
</div>
|
||||
|
||||
{% if company.phone %}
|
||||
{{ company.phone }}<br>
|
||||
{% endif %}
|
||||
|
||||
{% if company.email %}
|
||||
{{ company.email }}<br>
|
||||
{% endif %}
|
||||
|
||||
{% if company.website %}
|
||||
{{ company.website }}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
<div class="footer-title">
|
||||
Steuern
|
||||
</div>
|
||||
|
||||
|
||||
{% if company.tax_number %}
|
||||
Steuernummer: {{ company.tax_number }}<br>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.vat_number %}
|
||||
USt-IdNr.: {{ company.vat_number }}
|
||||
{% endif %}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
<div class="footer-title">
|
||||
Bank
|
||||
</div>
|
||||
|
||||
|
||||
{% if company.bank_name %}
|
||||
{{ company.bank_name }}<br>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.iban %}
|
||||
IBAN: {{ company.iban }}<br>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if company.bic %}
|
||||
BIC: {{ company.bic }}
|
||||
{% endif %}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,218 @@
|
||||
<div>
|
||||
|
||||
|
||||
<div class="grid md:grid-cols-2 xl:grid-cols-3 gap-6">
|
||||
|
||||
|
||||
<!-- Ansprechpartner -->
|
||||
|
||||
<div>
|
||||
|
||||
<h3 class="font-bold mb-3">
|
||||
Ansprechpartner
|
||||
</h3>
|
||||
|
||||
|
||||
{% for contact in item.contacts.all %}
|
||||
|
||||
<div class="
|
||||
bg-slate-100
|
||||
dark:bg-slate-700
|
||||
rounded-xl
|
||||
p-3
|
||||
mb-2
|
||||
">
|
||||
|
||||
<div class="font-medium">
|
||||
{{ contact.first_name }}
|
||||
{{ contact.last_name }}
|
||||
</div>
|
||||
|
||||
|
||||
{% if contact.phone %}
|
||||
|
||||
<div class="text-sm text-slate-400">
|
||||
{{ contact.phone }}
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if contact.email %}
|
||||
|
||||
<div class="text-sm text-slate-400">
|
||||
{{ contact.email }}
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{% empty %}
|
||||
|
||||
<div class="
|
||||
bg-white
|
||||
dark:bg-slate-800
|
||||
border
|
||||
border-orange-500
|
||||
rounded-xl
|
||||
p-6
|
||||
text-orange-500
|
||||
">
|
||||
Keine Ansprechpartner vorhanden
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- Standorte -->
|
||||
|
||||
<div>
|
||||
|
||||
<h3 class="font-bold mb-3">
|
||||
Standorte
|
||||
</h3>
|
||||
|
||||
|
||||
{% for location in item.locations.all %}
|
||||
|
||||
<div class="
|
||||
bg-slate-100
|
||||
dark:bg-slate-700
|
||||
rounded-xl
|
||||
p-3
|
||||
mb-2
|
||||
">
|
||||
|
||||
<div class="font-medium">
|
||||
{{ location.name }}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="text-sm text-slate-400">
|
||||
{{ location.street }}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="text-sm text-slate-400">
|
||||
{{ location.zip_code }}
|
||||
{{ location.city }}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="text-sm text-slate-400">
|
||||
{{ location.country }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{% empty %}
|
||||
|
||||
<div class="
|
||||
bg-white
|
||||
dark:bg-slate-800
|
||||
border
|
||||
border-orange-500
|
||||
rounded-xl
|
||||
p-6
|
||||
text-orange-500
|
||||
">
|
||||
Keine Standorte vorhanden
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- Projekte -->
|
||||
|
||||
<div>
|
||||
|
||||
<h3 class="font-bold mb-3">
|
||||
Projekte
|
||||
</h3>
|
||||
|
||||
|
||||
{% for project in item.projects.all %}
|
||||
|
||||
<div class="
|
||||
bg-slate-100
|
||||
dark:bg-slate-700
|
||||
rounded-xl
|
||||
p-3
|
||||
mb-2
|
||||
">
|
||||
|
||||
{{ project.name }}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{% empty %}
|
||||
|
||||
<div class="
|
||||
bg-white
|
||||
dark:bg-slate-800
|
||||
border
|
||||
border-orange-500
|
||||
rounded-xl
|
||||
p-6
|
||||
text-orange-500
|
||||
">
|
||||
Keine Projekte zugeordnet
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="mt-5 flex gap-2">
|
||||
|
||||
|
||||
<a
|
||||
href="{% url 'invoices:customers_detail' item.id %}"
|
||||
class="btn btn-edit">
|
||||
|
||||
Bearbeiten
|
||||
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<form
|
||||
method="post"
|
||||
action="{% url 'invoices:customers_archive' item.id %}">
|
||||
|
||||
{% csrf_token %}
|
||||
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
name="archiv"
|
||||
value="1"
|
||||
class="btn btn-action">
|
||||
|
||||
Archivieren
|
||||
|
||||
</button>
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,218 @@
|
||||
<div>
|
||||
|
||||
|
||||
<div class="grid md:grid-cols-2 xl:grid-cols-3 gap-6">
|
||||
|
||||
|
||||
<!-- Ansprechpartner -->
|
||||
|
||||
<div>
|
||||
|
||||
<h3 class="font-bold mb-3">
|
||||
Ansprechpartner
|
||||
</h3>
|
||||
|
||||
|
||||
{% for contact in item.contacts.all %}
|
||||
|
||||
<div class="
|
||||
bg-slate-100
|
||||
dark:bg-slate-700
|
||||
rounded-xl
|
||||
p-3
|
||||
mb-2
|
||||
">
|
||||
|
||||
<div class="font-medium">
|
||||
{{ contact.first_name }}
|
||||
{{ contact.last_name }}
|
||||
</div>
|
||||
|
||||
|
||||
{% if contact.phone %}
|
||||
|
||||
<div class="text-sm text-slate-400">
|
||||
{{ contact.phone }}
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if contact.email %}
|
||||
|
||||
<div class="text-sm text-slate-400">
|
||||
{{ contact.email }}
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{% empty %}
|
||||
|
||||
<div class="
|
||||
bg-white
|
||||
dark:bg-slate-800
|
||||
border
|
||||
border-orange-500
|
||||
rounded-xl
|
||||
p-6
|
||||
text-orange-500
|
||||
">
|
||||
Keine Ansprechpartner vorhanden
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- Standorte -->
|
||||
|
||||
<div>
|
||||
|
||||
<h3 class="font-bold mb-3">
|
||||
Standorte
|
||||
</h3>
|
||||
|
||||
|
||||
{% for location in item.locations.all %}
|
||||
|
||||
<div class="
|
||||
bg-slate-100
|
||||
dark:bg-slate-700
|
||||
rounded-xl
|
||||
p-3
|
||||
mb-2
|
||||
">
|
||||
|
||||
<div class="font-medium">
|
||||
{{ location.name }}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="text-sm text-slate-400">
|
||||
{{ location.street }}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="text-sm text-slate-400">
|
||||
{{ location.zip_code }}
|
||||
{{ location.city }}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="text-sm text-slate-400">
|
||||
{{ location.country }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{% empty %}
|
||||
|
||||
<div class="
|
||||
bg-white
|
||||
dark:bg-slate-800
|
||||
border
|
||||
border-orange-500
|
||||
rounded-xl
|
||||
p-6
|
||||
text-orange-500
|
||||
">
|
||||
Keine Standorte vorhanden
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- Projekte -->
|
||||
|
||||
<div>
|
||||
|
||||
<h3 class="font-bold mb-3">
|
||||
Projekte
|
||||
</h3>
|
||||
|
||||
|
||||
{% for project in item.projects.all %}
|
||||
|
||||
<div class="
|
||||
bg-slate-100
|
||||
dark:bg-slate-700
|
||||
rounded-xl
|
||||
p-3
|
||||
mb-2
|
||||
">
|
||||
|
||||
{{ project.name }}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
{% empty %}
|
||||
|
||||
<div class="
|
||||
bg-white
|
||||
dark:bg-slate-800
|
||||
border
|
||||
border-orange-500
|
||||
rounded-xl
|
||||
p-6
|
||||
text-orange-500
|
||||
">
|
||||
Keine Projekte zugeordnet
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="mt-5 flex gap-2">
|
||||
|
||||
|
||||
<a
|
||||
href="{% url 'invoices:customers_detail' item.id %}"
|
||||
class="btn btn-edit">
|
||||
|
||||
Bearbeiten
|
||||
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<form
|
||||
method="post"
|
||||
action="{% url 'invoices:customers_reactivate' item.id %}">
|
||||
|
||||
{% csrf_token %}
|
||||
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
name="archiv"
|
||||
value="1"
|
||||
class="btn btn-action">
|
||||
|
||||
Aktivieren
|
||||
|
||||
</button>
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,20 @@
|
||||
<form
|
||||
method="post"
|
||||
action="{% url 'invoices:invoice_item_delete' invoice.id record.id %}">
|
||||
|
||||
{% csrf_token %}
|
||||
|
||||
<input
|
||||
type="hidden"
|
||||
name="delete_item"
|
||||
value="{{ record.id }}">
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-delete">
|
||||
|
||||
Löschen
|
||||
|
||||
</button>
|
||||
|
||||
</form>
|
||||
@@ -0,0 +1,7 @@
|
||||
{% if record.service_period_from %}
|
||||
{{ record.service_period_from|date:"d.m.Y" }}
|
||||
{% endif %}
|
||||
|
||||
{% if record.service_period_to %}
|
||||
- {{ record.service_period_to|date:"d.m.Y" }}
|
||||
{% endif %}
|
||||
@@ -0,0 +1 @@
|
||||
USt. {{ record.unit_tax_rate|floatformat:0 }}%
|
||||
@@ -0,0 +1 @@
|
||||
{{ record.calculated_total_net|floatformat:2 }} €
|
||||
@@ -0,0 +1 @@
|
||||
{{ record.unit_price_net }} €
|
||||
@@ -0,0 +1,7 @@
|
||||
<a
|
||||
href="{% url 'invoices:invoices_detail' record.id %}"
|
||||
class="btn btn-edit">
|
||||
|
||||
Bearbeiten
|
||||
|
||||
</a>
|
||||
@@ -0,0 +1,35 @@
|
||||
<form
|
||||
id="save-form-{{ record.id }}"
|
||||
method="post"
|
||||
action="{% url 'invoices:items_edit' record.id %}">
|
||||
|
||||
{% csrf_token %}
|
||||
|
||||
</form>
|
||||
|
||||
|
||||
<div class="flex gap-2">
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
form="save-form-{{ record.id }}"
|
||||
class="btn btn-save">
|
||||
Speichern
|
||||
</button>
|
||||
|
||||
|
||||
<form
|
||||
method="post"
|
||||
action="{% url 'invoices:items_delete' record.id %}">
|
||||
|
||||
{% csrf_token %}
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-delete">
|
||||
Löschen
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,6 @@
|
||||
<input
|
||||
type="text"
|
||||
name="description"
|
||||
form="save-form-{{ record.id }}"
|
||||
value="{{ record.description }}"
|
||||
class="border rounded px-2 py-1 w-full">
|
||||
@@ -0,0 +1,16 @@
|
||||
<select
|
||||
name="item_type"
|
||||
form="save-form-{{ record.id }}"
|
||||
class="border rounded px-2 py-1 w-full">
|
||||
|
||||
{% for v,l in table.types %}
|
||||
|
||||
<option
|
||||
value="{{ v }}"
|
||||
{% if record.item_type == v %}selected{% endif %}>
|
||||
{{ l }}
|
||||
</option>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</select>
|
||||
@@ -0,0 +1,7 @@
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
name="price_net"
|
||||
form="save-form-{{ record.id }}"
|
||||
value="{{ record.price_net }}"
|
||||
class="border rounded px-2 py-1 w-full">
|
||||
@@ -0,0 +1,7 @@
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
name="tax_rate"
|
||||
form="save-form-{{ record.id }}"
|
||||
value="{{ record.tax_rate }}"
|
||||
class="border rounded px-2 py-1 w-full">
|
||||
@@ -0,0 +1,20 @@
|
||||
<select
|
||||
name="unit"
|
||||
form="save-form-{{ record.id }}"
|
||||
class="border rounded px-2 py-1 w-full">
|
||||
|
||||
|
||||
{% for unit in table.units %}
|
||||
|
||||
<option
|
||||
value="{{ unit.id }}"
|
||||
{% if record.unit_id == unit.id %}selected{% endif %}>
|
||||
|
||||
{{ unit.name }}
|
||||
|
||||
</option>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
|
||||
</select>
|
||||
@@ -0,0 +1,20 @@
|
||||
<form
|
||||
method="post"
|
||||
action="{% url 'invoices:offers_item_delete' table.offer.id record.id %}">
|
||||
|
||||
{% csrf_token %}
|
||||
|
||||
<input
|
||||
type="hidden"
|
||||
name="delete_item"
|
||||
value="{{ record.id }}">
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-delete">
|
||||
|
||||
Löschen
|
||||
|
||||
</button>
|
||||
|
||||
</form>
|
||||
@@ -0,0 +1 @@
|
||||
USt. {{ record.unit_tax_rate|floatformat:0 }}%
|
||||
@@ -0,0 +1 @@
|
||||
{{ record.calculated_total_net|floatformat:2 }} €
|
||||
@@ -0,0 +1 @@
|
||||
{{ record.unit_price_net }} €
|
||||
@@ -0,0 +1,7 @@
|
||||
<a
|
||||
href="{% url 'invoices:offers_detail' record.id %}"
|
||||
class="btn btn-edit">
|
||||
|
||||
Bearbeiten
|
||||
|
||||
</a>
|
||||
@@ -0,0 +1,7 @@
|
||||
<a
|
||||
href="{% url 'invoices:reminders_detail' record.id %}"
|
||||
class="btn btn-edit">
|
||||
|
||||
Bearbeiten
|
||||
|
||||
</a>
|
||||
@@ -0,0 +1,7 @@
|
||||
<a
|
||||
class="company_link"
|
||||
href="{% url 'invoices:invoices_detail' record.invoice.id %}">
|
||||
|
||||
{{ record.invoice.invoice_number }}
|
||||
|
||||
</a>
|
||||
Reference in New Issue
Block a user