479 lines
19 KiB
HTML
479 lines
19 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Betriebskosten</title>
|
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-modal/0.9.1/jquery.modal.min.js"></script>
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-modal/0.9.1/jquery.modal.min.css" />
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
margin: 0;
|
|
padding: 20px;
|
|
background-color: #f4f4f9;
|
|
}
|
|
.table-container {
|
|
width: 100%;
|
|
background-color: white;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
}
|
|
h2 {
|
|
text-align: center;
|
|
color: #333;
|
|
}
|
|
table {
|
|
width: 100%;
|
|
table-layout: fixed;
|
|
border-collapse: collapse;
|
|
}
|
|
th, td {
|
|
padding: 12px;
|
|
text-align: center;
|
|
border-bottom: 1px solid #ddd;
|
|
}
|
|
th:nth-child(1), td:nth-child(1) { width: 5%; } /* # column */
|
|
th:nth-child(2), td:nth-child(2) { width: 10%; } /* Buchungsdatum */
|
|
th:nth-child(3), td:nth-child(3) { width: 15%; } /* Rechnungsnummer */
|
|
th:nth-child(4), td:nth-child(4) { width: 10%; } /* Kostentyp */
|
|
th:nth-child(5), td:nth-child(5) { width: 10%; } /* Gasvolumen */
|
|
th:nth-child(6), td:nth-child(6) { width: 10%; } /* Betrag */
|
|
th:nth-child(7), td:nth-child(7) { width: 25%; } /* Beschreibung */
|
|
th:nth-child(8), td:nth-child(8) { width: 15%; } /* Actions */
|
|
|
|
.actions {
|
|
white-space: nowrap; /* Prevent buttons from wrapping */
|
|
}
|
|
th {
|
|
background-color: #007bff;
|
|
color: white;
|
|
font-weight: bold;
|
|
position: sticky;
|
|
top: 0;
|
|
}
|
|
tr:hover {
|
|
background-color: #f1f1f1;
|
|
}
|
|
.actions button {
|
|
margin: 2px;
|
|
padding: 5px 10px;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-size: 14px;
|
|
}
|
|
.edit-btn {
|
|
background-color: #28a745;
|
|
color: white;
|
|
}
|
|
.delete-btn {
|
|
background-color: #dc3545;
|
|
color: white;
|
|
}
|
|
.popup {
|
|
display: none;
|
|
position: fixed;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
background: white;
|
|
padding: 20px;
|
|
border-radius: 5px;
|
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
|
|
z-index: 1000;
|
|
width: 400px;
|
|
}
|
|
.popup input, .popup select, .popup textarea {
|
|
display: block;
|
|
margin-bottom: 10px;
|
|
width: 100%;
|
|
padding: 8px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
}
|
|
.popup button {
|
|
margin-top: 10px;
|
|
padding: 8px 16px;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-size: 14px;
|
|
}
|
|
.close-btn {
|
|
cursor: pointer;
|
|
float: right;
|
|
font-size: 18px;
|
|
color: #333;
|
|
}
|
|
.add-row-btn {
|
|
padding: 10px 20px;
|
|
background-color: #007bff;
|
|
color: white;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-size: 16px;
|
|
margin-bottom: 20px;
|
|
}
|
|
.add-row-btn:hover {
|
|
background-color: #0056b3;
|
|
}
|
|
.save-btn {
|
|
background-color: #28a745;
|
|
color: white;
|
|
}
|
|
.cancel-btn {
|
|
background-color: #6c757d;
|
|
color: white;
|
|
}
|
|
.help-btn {
|
|
background-color: #17a2b8;
|
|
color: white;
|
|
}
|
|
#price-per-liter-group {
|
|
display: none;
|
|
}
|
|
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<a href="{% url 'clients_list' %}" class="btn btn-outline-primary">
|
|
⇦ Go to Clients
|
|
</a>
|
|
|
|
<h2>Betriebskosten</h2>
|
|
<div class="table-container">
|
|
<button class="add-row-btn" id="add-row-btn">Add Row</button>
|
|
<table id="betriebskosten-table">
|
|
<thead>
|
|
<tr>
|
|
<th>#</th>
|
|
<th>Buchungsdatum</th>
|
|
<th>Rechnungsnummer</th>
|
|
<th>Kostentyp</th>
|
|
<th>Gasvolumen (L)</th>
|
|
<th>Betrag (€)</th>
|
|
<th>Beschreibung</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for item in items %}
|
|
<tr data-id="{{ item.id }}">
|
|
<td>{{ forloop.counter }}</td>
|
|
<td>{{ item.buchungsdatum|date:"Y-m-d" }}</td>
|
|
<td>{{ item.rechnungsnummer }}</td>
|
|
<td>{{ item.get_kostentyp_display }}</td>
|
|
<td>{{ item.gas_volume|default_if_none:"-" }}</td>
|
|
<td>{{ item.betrag }}</td>
|
|
<td>{{ item.beschreibung|default:"" }}</td>
|
|
<td class="actions">
|
|
<button class="edit-btn">Edit</button>
|
|
<button class="delete-btn">Delete</button>
|
|
</td>
|
|
</tr>
|
|
{% empty %}
|
|
<tr>
|
|
<td colspan="8" style="text-align: center;">No entries found</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Add Popup -->
|
|
<div id="add-popup" class="popup">
|
|
<span class="close-btn">×</span>
|
|
<h3>Betriebskosten Eintrag</h3>
|
|
|
|
<label for="add-buchungsdatum">Buchungsdatum:</label>
|
|
<input type="date" id="add-buchungsdatum" required>
|
|
|
|
<label for="add-rechnungsnummer">Rechnungsnummer:</label>
|
|
<input type="text" id="add-rechnungsnummer" required>
|
|
|
|
<label for="add-kostentyp">Kostentyp:</label>
|
|
<select id="add-kostentyp" required onchange="toggleGasVolume('add')">
|
|
<option value="">Bitte auswählen</option>
|
|
<option value="sach">Sachkosten</option>
|
|
<option value="ln2">LN2</option>
|
|
<option value="helium">Helium</option>
|
|
<option value="inv">Inventar</option>
|
|
</select>
|
|
|
|
<div id="add-gas-volume-group" style="display: none;">
|
|
<label for="add-gas-volume">Gasvolumen (Liter):</label>
|
|
<input type="number" id="add-gas-volume" step="0.01" min="0" oninput="calculatePrice('add')">
|
|
</div>
|
|
|
|
<label for="add-betrag">Betrag (€):</label>
|
|
<input type="number" id="add-betrag" step="0.01" min="0" required oninput="calculatePrice('add')">
|
|
|
|
<div id="add-price-per-liter-group" style="display: none;">
|
|
<label for="add-price-per-liter">Preis pro Liter (€):</label>
|
|
<input type="text" id="add-price-per-liter" readonly>
|
|
</div>
|
|
|
|
<label for="add-beschreibung">Beschreibung:</label>
|
|
<textarea id="add-beschreibung" placeholder="Optionale Beschreibung"></textarea>
|
|
|
|
<div class="popup-buttons">
|
|
<button class="save-btn" id="save-add">Save</button>
|
|
<button class="cancel-btn">Cancel</button>
|
|
<button class="help-btn">Help</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Edit Popup -->
|
|
<div id="edit-popup" class="popup">
|
|
<span class="close-btn">×</span>
|
|
<h3>Betriebskosten Eintrag</h3>
|
|
<input type="hidden" id="edit-id">
|
|
|
|
<label for="edit-buchungsdatum">Buchungsdatum:</label>
|
|
<input type="date" id="edit-buchungsdatum" required>
|
|
|
|
<label for="edit-rechnungsnummer">Rechnungsnummer:</label>
|
|
<input type="text" id="edit-rechnungsnummer" required>
|
|
|
|
<label for="edit-kostentyp">Kostentyp:</label>
|
|
<select id="edit-kostentyp" required onchange="toggleGasVolume('edit')">
|
|
<option value="">Bitte auswählen</option>
|
|
<option value="sach">Sachkosten</option>
|
|
<option value="ln2">LN2</option>
|
|
<option value="helium">Helium</option>
|
|
<option value="inv">Inventar</option>
|
|
</select>
|
|
|
|
<div id="edit-gas-volume-group" style="display: none;">
|
|
<label for="edit-gas-volume">Gasvolumen (Liter):</label>
|
|
<input type="number" id="edit-gas-volume" step="0.01" min="0" oninput="calculatePrice('edit')">
|
|
</div>
|
|
|
|
<label for="edit-betrag">Betrag (€):</label>
|
|
<input type="number" id="edit-betrag" step="0.01" min="0" required oninput="calculatePrice('edit')">
|
|
|
|
<div id="edit-price-per-liter-group" style="display: none;">
|
|
<label for="edit-price-per-liter">Preis pro Liter (€):</label>
|
|
<input type="text" id="edit-price-per-liter" readonly>
|
|
</div>
|
|
|
|
<label for="edit-beschreibung">Beschreibung:</label>
|
|
<textarea id="edit-beschreibung" placeholder="Optionale Beschreibung"></textarea>
|
|
|
|
<div class="popup-buttons">
|
|
<button class="save-btn" id="save-edit">Save</button>
|
|
<button class="cancel-btn">Cancel</button>
|
|
<button class="help-btn">Help</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
$(document).ready(function () {
|
|
// Open add popup
|
|
$('#add-row-btn').on('click', function () {
|
|
$('#add-popup').fadeIn();
|
|
});
|
|
|
|
// Close popups
|
|
$('.close-btn, .cancel-btn').on('click', function () {
|
|
$('.popup').fadeOut();
|
|
});
|
|
|
|
// Add new entry
|
|
$('#save-add').on('click', function() {
|
|
const formData = {
|
|
'buchungsdatum': $('#add-buchungsdatum').val(),
|
|
'rechnungsnummer': $('#add-rechnungsnummer').val(),
|
|
'kostentyp': $('#add-kostentyp').val(),
|
|
'gas_volume': $('#add-gas-volume').val(),
|
|
'betrag': $('#add-betrag').val(),
|
|
'beschreibung': $('#add-beschreibung').val(),
|
|
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
|
};
|
|
|
|
// Validate required fields
|
|
if (!formData.buchungsdatum || !formData.rechnungsnummer || !formData.kostentyp || !formData.betrag) {
|
|
alert('Bitte füllen Sie alle erforderlichen Felder aus');
|
|
return;
|
|
}
|
|
|
|
$.ajax({
|
|
url: "{% url 'betriebskosten_create' %}",
|
|
method: 'POST',
|
|
data: formData,
|
|
success: function(response) {
|
|
if (response.status === 'success') {
|
|
// Add the new row to the table
|
|
const newRow = `
|
|
<tr data-id="${response.id}">
|
|
<td>${$('#betriebskosten-table tbody tr').length + 1}</td>
|
|
<td>${response.buchungsdatum}</td>
|
|
<td>${response.rechnungsnummer}</td>
|
|
<td>${response.kostentyp_display}</td>
|
|
<td>${response.gas_volume || '-'}</td>
|
|
<td>${response.betrag}</td>
|
|
<td>${response.beschreibung || ''}</td>
|
|
<td class="actions">
|
|
<button class="edit-btn">Edit</button>
|
|
<button class="delete-btn">Delete</button>
|
|
</td>
|
|
</tr>
|
|
`;
|
|
$('#betriebskosten-table tbody').append(newRow);
|
|
$('#add-popup').fadeOut();
|
|
$('#add-popup input, #add-popup select, #add-popup textarea').val('');
|
|
} else {
|
|
alert('Error: ' + (response.message || 'Failed to add entry'));
|
|
}
|
|
},
|
|
error: function(xhr) {
|
|
alert('Error: ' + (xhr.responseJSON?.message || 'Server error'));
|
|
}
|
|
});
|
|
});
|
|
|
|
// Edit entry
|
|
$(document).on('click', '.edit-btn', function() {
|
|
const row = $(this).closest('tr');
|
|
const id = row.data('id');
|
|
|
|
// Fill the edit form with current data
|
|
$('#edit-id').val(id);
|
|
$('#edit-buchungsdatum').val(row.find('td:eq(1)').text());
|
|
$('#edit-rechnungsnummer').val(row.find('td:eq(2)').text());
|
|
|
|
// Set kostentyp based on display text
|
|
const kostentypText = row.find('td:eq(3)').text();
|
|
const kostentypMap = {
|
|
'Sachkosten': 'sach',
|
|
'LN2': 'ln2',
|
|
'Helium': 'helium',
|
|
'Inventar': 'inv'
|
|
};
|
|
$('#edit-kostentyp').val(kostentypMap[kostentypText] || '');
|
|
|
|
$('#edit-gas-volume').val(row.find('td:eq(4)').text() === '-' ? '' : row.find('td:eq(4)').text());
|
|
$('#edit-betrag').val(row.find('td:eq(5)').text());
|
|
$('#edit-beschreibung').val(row.find('td:eq(6)').text());
|
|
|
|
// Show/hide gas volume based on kostentyp
|
|
toggleGasVolume('edit');
|
|
calculatePrice('edit');
|
|
|
|
$('#edit-popup').fadeIn();
|
|
});
|
|
|
|
// Save edit
|
|
$('#save-edit').on('click', function() {
|
|
const formData = {
|
|
'id': $('#edit-id').val(),
|
|
'buchungsdatum': $('#edit-buchungsdatum').val(),
|
|
'rechnungsnummer': $('#edit-rechnungsnummer').val(),
|
|
'kostentyp': $('#edit-kostentyp').val(),
|
|
'gas_volume': $('#edit-gas-volume').val(),
|
|
'betrag': $('#edit-betrag').val(),
|
|
'beschreibung': $('#edit-beschreibung').val(),
|
|
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
|
};
|
|
|
|
// Validate required fields
|
|
if (!formData.buchungsdatum || !formData.rechnungsnummer || !formData.kostentyp || !formData.betrag) {
|
|
alert('Bitte füllen Sie alle erforderlichen Felder aus');
|
|
return;
|
|
}
|
|
|
|
$.ajax({
|
|
url: "{% url 'betriebskosten_create' %}",
|
|
method: 'POST',
|
|
data: formData,
|
|
success: function(response) {
|
|
if (response.status === 'success') {
|
|
// Update the row in the table
|
|
const row = $(`tr[data-id="${response.id}"]`);
|
|
row.find('td:eq(1)').text(response.buchungsdatum);
|
|
row.find('td:eq(2)').text(response.rechnungsnummer);
|
|
row.find('td:eq(3)').text(response.kostentyp_display);
|
|
row.find('td:eq(4)').text(response.gas_volume || '-');
|
|
row.find('td:eq(5)').text(response.betrag);
|
|
row.find('td:eq(6)').text(response.beschreibung || '');
|
|
|
|
$('#edit-popup').fadeOut();
|
|
} else {
|
|
alert('Error: ' + (response.message || 'Failed to update entry'));
|
|
}
|
|
},
|
|
error: function(xhr) {
|
|
alert('Error: ' + (xhr.responseJSON?.message || 'Server error'));
|
|
}
|
|
});
|
|
});
|
|
|
|
// Delete entry
|
|
$(document).on('click', '.delete-btn', function () {
|
|
const row = $(this).closest('tr');
|
|
const id = row.data('id');
|
|
|
|
if (!confirm('Are you sure you want to delete this entry?')) return;
|
|
|
|
$.ajax({
|
|
url: "{% url 'betriebskosten_delete' %}",
|
|
method: 'POST',
|
|
data: {
|
|
'id': id,
|
|
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
|
},
|
|
success: function (response) {
|
|
if (response.status === 'success') {
|
|
row.fadeOut(300, function () { $(this).remove(); });
|
|
// Update row numbers
|
|
$('#betriebskosten-table tbody tr').each(function(index) {
|
|
$(this).find('td:first').text(index + 1);
|
|
});
|
|
} else {
|
|
alert('Failed to delete entry: ' + response.message);
|
|
}
|
|
},
|
|
error: function () {
|
|
alert('Failed to delete entry. Please try again.');
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
// Toggle gas volume field based on kostentyp
|
|
function toggleGasVolume(type) {
|
|
const kostentyp = $(`#${type}-kostentyp`).val();
|
|
const gasVolumeGroup = $(`#${type}-gas-volume-group`);
|
|
const pricePerLiterGroup = $(`#${type}-price-per-liter-group`);
|
|
|
|
if (kostentyp === 'helium') {
|
|
gasVolumeGroup.show();
|
|
pricePerLiterGroup.show();
|
|
} else {
|
|
gasVolumeGroup.hide();
|
|
pricePerLiterGroup.hide();
|
|
$(`#${type}-gas-volume`).val('');
|
|
$(`#${type}-price-per-liter`).val('');
|
|
}
|
|
}
|
|
|
|
// Calculate price per liter
|
|
function calculatePrice(type) {
|
|
const kostentyp = $(`#${type}-kostentyp`).val();
|
|
const volume = parseFloat($(`#${type}-gas-volume`).val()) || 0;
|
|
const betrag = parseFloat($(`#${type}-betrag`).val()) || 0;
|
|
|
|
if (kostentyp === 'helium' && volume > 0 && betrag > 0) {
|
|
$(`#${type}-price-per-liter`).val((betrag / volume).toFixed(2) + ' €/L');
|
|
} else {
|
|
$(`#${type}-price-per-liter`).val('');
|
|
}
|
|
}
|
|
</script>
|
|
</body>
|
|
</html> |