Files
he-database/sheets/templates/monthly_sheet.html

674 lines
24 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block content %}
<div class="spreadsheet-container">
<!-- Navigation Header -->
<div class="sheet-navigation">
<a href="{% url 'monthly_sheet' prev_month.year prev_month.month %}">← Previous</a>
<h2>{{ year }} - {{ month_name }} (Sheet {{ month }}/6)</h2>
<a href="{% url 'monthly_sheet' next_month.year next_month.month %}">Next →</a>
<a href="{% url 'summary_sheet' year month %}">Go to Summary</a>
</div>
<!-- Top Tables Container -->
<div class="top-tables">
<!-- Left Table (18 rows × clients) -->
<div class="table-container top-left-table">
<h3>Table 1: Top Left</h3>
<table class="spreadsheet-table">
<thead>
<tr>
<th>Row Label</th>
{% for header in top_left_headers %}
<th>{{ header }}</th>
{% endfor %}
<th>Sum</th>
</tr>
</thead>
<tbody>
{% for row in top_left_rows %}
{% with rownum=forloop.counter %}
<tr data-row="{{ forloop.counter0 }}">
<td class="row-label">
{% if rownum == 1 %}
Stand der Gaszähler (Nm³)
{% elif rownum == 2 %}
Stand der Gaszähler (Vormonat) (Nm³)
{% elif rownum == 3 %}
Gasrückführung (Nm³)
{% elif rownum == 4 %}
Rückführung flüssig (Lit. L-He)
{% elif rownum == 5 %}
Sonderrückführungen (Lit. L-He)
{% elif rownum == 6 %}
Bestand in Kannen-1 (Lit. L-He)
{% elif rownum == 7 %}
Summe Bestand (Lit. L-He)
{% elif rownum == 8 %}
Best. in Kannen Vormonat (Lit. L-He)
{% elif rownum == 9 %}
Bezug (Liter L-He)
{% elif rownum == 10 %}
Rückführ. Soll (Lit. L-He)
{% elif rownum == 11 %}
Verluste (Soll-Rückf.) (Lit. L-He)
{% elif rownum == 12 %}
Füllungen warm (Lit. L-He)
{% elif rownum == 13 %}
Kaltgas Rückgabe (Lit. L-He) Faktor
{% elif rownum == 14 %}
Faktor 0.06
{% elif rownum == 15 %}
Verbraucherverluste (Liter L-He)
{% elif rownum == 16 %}
%
{% elif rownum == 17 %}
Gesamtrückführung (Nm³)
{% elif rownum == 18 %}
Aufgeteilte Verluste (Liter L-He)
{% endif %}
</td>
{% for cell in row.cells %}
{% if is_start_sheet or rownum == 1 or rownum == 5 or rownum == 6 %}
{# Editable in start sheet OR always editable rows (B3, B7, B8) #}
<td class="editable-cell"
data-cell-id="{{ cell.id|default:'' }}"
data-table="top_left"
data-row="{{ forloop.parentloop.counter0 }}"
data-col="{{ forloop.counter0 }}"
data-client-id="{{ cell.client.id|default:'' }}"
contenteditable="true">
{{ cell.value|default:"" }}
</td>
{% else %}
{# Readonly for non-start sheets #}
<td class="readonly-cell"
data-cell-id="{{ cell.id|default:'' }}"
data-table="top_left"
data-row="{{ forloop.parentloop.counter0 }}"
data-col="{{ forloop.counter0 }}"
data-client-id="{{ cell.client.id|default:'' }}"
contenteditable="false">
{{ cell.value|default:"" }}
</td>
{% endif %}
{% endfor %}
<td class="sum-cell">
{{ row.sum|default_if_none:"" }}
</td>
</tr>
{% endwith %}
{% endfor %}
</tbody>
</table>
</div>
<!-- Right Table (24 rows × 6 clients) -->
<!-- Update the top-right table section in monthly_sheet.html -->
<div class="table-container top-right-table">
<h3>Table 2: Top Right</h3>
<table class="spreadsheet-table">
<thead>
<tr>
<th>Row Label</th>
{% for header in top_right_headers %}
<th>{{ header }}</th>
{% endfor %}
<th>Sum</th>
</tr>
</thead>
<tbody>
{% for row in top_right_rows %}
{% with rownum=forloop.counter %}
<tr data-row="{{ forloop.counter0 }}">
<td class="row-label">
{% if rownum == 1 %}
Stand der Gaszähler (Vormonat) (Nm³)
{% elif rownum == 2 %}
Gasrückführung (Nm³)
{% elif rownum == 3 %}
Rückführung flüssig (Lit. L-He)
{% elif rownum == 4 %}
Sonderrückführungen (Lit. L-He)
{% elif rownum == 5 %}
Sammelrückführungen (Lit. L-He)
{% elif rownum == 6 %}
Bestand in Kannen-1 (Lit. L-He)
{% elif rownum == 7 %}
Summe Bestand (Lit. L-He)
{% elif rownum == 8 %}
Best. in Kannen Vormonat (Lit. L-He)
{% elif rownum == 9 %}
Bezug (Liter L-He)
{% elif rownum == 10 %}
Rückführ. Soll (Lit. L-He)
{% elif rownum == 11 %}
Verluste (Soll-Rückf.) (Lit. L-He)
{% elif rownum == 12 %}
Füllungen warm (Lit. L-He)
{% elif rownum == 13 %}
Kaltgas Rückgabe (Lit. L-He) Faktor
{% elif rownum == 14 %}
Faktor 0.06
{% elif rownum == 15 %}
Verbraucherverluste (Liter L-He)
{% elif rownum == 16 %}
%
{% endif %}
</td>
{% for cell in row.cells %}
{% with client_name=cell.client.name|default:"" %}
{# Determine if this cell should be editable #}
{% if is_start_sheet %}
<td class="editable-cell"
data-cell-id="{{ cell.id|default:'' }}"
data-table="top_right"
data-row="{{ forloop.parentloop.counter0 }}"
data-col="{{ forloop.counter0 }}"
data-client-id="{{ cell.client.id|default:'' }}"
contenteditable="true">
{{ cell.value|default:"" }}
</td>
{% elif rownum == 4 or rownum == 6 or rownum == 1 and client_name in "M3 Thiele,M3 Buntkowsky,M3 Gutfleisch" %}
<td class="editable-cell"
data-cell-id="{{ cell.id|default:'' }}"
data-table="top_right"
data-row="{{ forloop.parentloop.counter0 }}"
data-col="{{ forloop.counter0 }}"
data-client-id="{{ cell.client.id|default:'' }}"
contenteditable="true">
{{ cell.value|default:"" }}
</td>
{% else %}
<td class="readonly-cell"
data-cell-id="{{ cell.id|default:'' }}"
data-table="top_right"
data-row="{{ forloop.parentloop.counter0 }}"
data-col="{{ forloop.counter0 }}"
data-client-id="{{ cell.client.id|default:'' }}"
contenteditable="false">
{% if rownum == 2 %}
Aufteilung Nach Verbrauch
{% else %}
{{ cell.value|default:"" }}
{% endif %}
</td>
{% endif %}
{% endwith %}
{% endfor %}
<td class="sum-cell">
{{ row.sum|default_if_none:"" }}
</td>
</tr>
{% endwith %}
{% endfor %}
</tbody>
</table>
</div>
<!-- Bottom Tables -->
<div class="bottom-tables">
<div class="table-container bottom-table-1">
<h3>Bottom Table 1</h3>
<table class="spreadsheet-table">
<thead>
<tr>
<th>Row Label</th>
{% for client in clients %}
<th>{{ client.name }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in cells_by_table.bottom_1 %}
<tr data-row="{{ forloop.counter0 }}">
<td class="row-label">Row {{ forloop.counter }}</td>
{% for cell in row %}
<td class="editable-cell"
data-cell-id="{{ cell.id|default:'' }}"
data-table="bottom_1"
data-row="{{ forloop.parentloop.counter0 }}"
data-col="{{ forloop.counter0 }}"
data-client-id="{{ cell.client.id|default:'' }}"
contenteditable="true">
{{ cell.value|default:"" }}
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="table-container bottom-table-2">
<h3>Bottom Table 2</h3>
<table class="spreadsheet-table">
<thead>
<tr>
<th>Row Label</th>
{% for client in clients %}
<th>{{ client.name }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in cells_by_table.bottom_2 %}
<tr data-row="{{ forloop.counter0 }}">
<td class="row-label">Row {{ forloop.counter }}</td>
{% for cell in row %}
<td class="editable-cell"
data-cell-id="{{ cell.id|default:'' }}"
data-table="bottom_2"
data-row="{{ forloop.parentloop.counter0 }}"
data-col="{{ forloop.counter0 }}"
data-client-id="{{ cell.client.id|default:'' }}"
contenteditable="true">
{{ cell.value|default:"" }}
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="table-container bottom-table-3">
<h3>Bottom Table 3</h3>
<table class="spreadsheet-table">
<thead>
<tr>
<th>Row Label</th>
{% for client in clients %}
<th>{{ client.name }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in cells_by_table.bottom_3 %}
<tr data-row="{{ forloop.counter0 }}">
<td class="row-label">Row {{ forloop.counter }}</td>
{% for cell in row %}
<td class="editable-cell"
data-cell-id="{{ cell.id|default:'' }}"
data-table="bottom_3"
data-row="{{ forloop.parentloop.counter0 }}"
data-col="{{ forloop.counter0 }}"
data-client-id="{{ cell.client.id|default:'' }}"
contenteditable="true">
{{ cell.value|default:"" }}
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Save Button -->
<div class="action-bar">
<button id="save-all-btn" class="btn btn-primary">Save All Cells</button>
<div id="save-status"></div>
<div class="legend">
<small>
<span style="background-color: #d1ecf1; padding: 2px 5px;">Saved cells</span>
<span style="background-color: #d4edda; padding: 2px 5px;">Calculated cells</span>
</small>
</div>
</div>
</div>
<!-- Hidden form for cell data -->
<form id="cell-data-form" style="display: none;">
{% csrf_token %}
<input type="hidden" name="sheet_id" value="{{ sheet.id }}">
</form>
<style>
.spreadsheet-container {
padding: 20px;
}
.sheet-navigation {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding: 10px;
background-color: #f8f9fa;
border-radius: 5px;
}
.sheet-navigation h2 {
margin: 0;
}
.top-tables {
display: flex;
gap: 20px;
margin-bottom: 20px;
}
.top-tables .table-container {
flex: 1;
border: 1px solid #ddd;
border-radius: 5px;
padding: 10px;
background-color: white;
}
.merged-cell-left {
border-right-width: 0;
}
.merged-cell-right {
border-left-width: 0;
}
.cell-group-LM {
background-color: #f0f8ff; /* Light blue for L&M group */
}
.cell-group-NO {
background-color: #f0fff0; /* Light green for N&O group */
}
.cell-group-PQR {
background-color: #fff0f0; /* Light red for P,Q,R group */
}
.bottom-tables {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
margin-bottom: 20px;
}
.bottom-tables .table-container {
border: 1px solid #ddd;
border-radius: 5px;
padding: 10px;
background-color: white;
}
.spreadsheet-table {
width: 100%;
border-collapse: collapse;
}
.spreadsheet-table th,
.spreadsheet-table td {
border: 1px solid #ddd;
padding: 8px;
text-align: center;
}
.spreadsheet-table th {
background-color: #f2f2f2;
font-weight: bold;
}
.row-label {
background-color: #f9f9f9;
font-weight: bold;
}
.editable-cell {
min-width: 100px;
min-height: 30px;
background-color: white;
cursor: text;
}
.editable-cell:focus {
outline: 2px solid #007bff;
background-color: #f0f8ff;
}
.editable-cell:hover {
background-color: #f1f1f1;
}
.readonly-cell {
background-color: #f8f9fa;
color: #495057;
cursor: default;
min-height: 30px;
}
.cell-calculated {
font-style: italic;
font-weight: bold;
background-color: #e8f4f8;
}
.sum-cell {
font-weight: bold;
background-color: #f0f0f0;
padding: 5px;
}
.action-bar {
display: flex;
gap: 10px;
align-items: center;
padding: 10px;
background-color: #f8f9fa;
border-radius: 5px;
}
.btn {
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.btn-primary {
background-color: #007bff;
color: white;
}
#save-status {
margin-left: 10px;
color: #28a745;
font-weight: bold;
}
.saving-text {
position: absolute;
font-size: 11px;
color: #666;
margin-left: 5px;
}
.saving {
background-color: #fff3cd !important;
font-style: italic;
}
.saved-success {
background-color: #d4edda !important;
transition: background-color 0.5s ease;
}
.calculated-cell {
background-color: #e8f4f8 !important;
font-style: italic;
color: #0c5460;
}
.editable-cell[contenteditable="false"] {
background-color: #f8f9fa !important;
cursor: not-allowed;
}
</style>
<script>
$(document).ready(function() {
// Enable editing on focus
$('.editable-cell').on('focus', function() {
$(this).data('original-value', $(this).text().trim());
});
// Save on blur
$('.editable-cell').on('blur', function() {
saveCell($(this));
});
// Save on Enter key
$('.editable-cell').on('keydown', function(e) {
if (e.key === 'Enter') {
e.preventDefault();
$(this).blur();
}
});
// Prevent editing of readonly cells
$('.readonly-cell').on('focus click', function(e) {
e.preventDefault();
$(this).blur();
});
function saveCell($cell) {
const cellId = $cell.data('cell-id');
const newValue = $cell.text().trim();
const originalValue = $cell.data('original-value') || '';
// Skip if no change
if (newValue === originalValue) {
return;
}
// Skip if no cell ID
if (!cellId) {
console.error('No cell ID found');
return;
}
// Show saving indicator
$cell.addClass('saving');
// Prepare AJAX request
const csrfToken = $('[name=csrfmiddlewaretoken]').val();
$.ajax({
url: '{% url "save_cells" %}',
method: 'POST',
headers: {
'X-CSRFToken': csrfToken
},
data: {
'sheet_id': '{{ sheet.id }}',
'cell_id': cellId,
'value': newValue
},
success: function(response) {
$cell.removeClass('saving');
if (response.status === 'success') {
// Update all cells returned by the server
if (response.updated_cells) {
response.updated_cells.forEach(function(cellData) {
const targetCell = $('[data-cell-id="' + cellData.id + '"]');
if (targetCell.length) {
targetCell.text(cellData.value || '');
targetCell.data('original-value', cellData.value || '');
// Style calculated cells differently
// Style calculated cells differently
if (cellData.is_calculated) {
targetCell.addClass('calculated-cell');
// Leave contenteditable as set by the template
}
}
});
}
// Show success message
showStatus('Saved successfully!', 'success');
// Highlight the saved cell briefly
$cell.addClass('saved-success');
setTimeout(function() {
$cell.removeClass('saved-success');
}, 1000);
} else {
// Restore original value on error
$cell.text(originalValue);
showStatus('Error: ' + response.message, 'error');
}
},
error: function(xhr, status, error) {
$cell.removeClass('saving');
$cell.text(originalValue);
showStatus('Error: ' + error, 'error');
console.error('Save error:', error);
}
});
}
// Save All button
$('#save-all-btn').on('click', function() {
const csrfToken = $('[name=csrfmiddlewaretoken]').val();
const formData = new FormData();
formData.append('sheet_id', '{{ sheet.id }}');
formData.append('csrfmiddlewaretoken', csrfToken);
// Collect all cell values
$('.editable-cell').each(function() {
const cellId = $(this).data('cell-id');
if (cellId) {
formData.append('cell_' + cellId, $(this).text().trim());
}
});
$.ajax({
url: '{% url "save_cells" %}',
method: 'POST',
data: formData,
processData: false,
contentType: false,
headers: {
'X-CSRFToken': csrfToken
},
success: function(response) {
if (response.status === 'success') {
if (response.updated_cells) {
response.updated_cells.forEach(function(cellData) {
const targetCell = $('[data-cell-id="' + cellData.id + '"]');
if (targetCell.length) {
targetCell.text(cellData.value || '');
targetCell.data('original-value', cellData.value || '');
}
});
}
showStatus('All cells saved!', 'success');
} else {
showStatus('Error: ' + response.message, 'error');
}
},
error: function() {
showStatus('Error saving all cells', 'error');
}
});
});
function showStatus(message, type) {
const statusEl = $('#save-status');
statusEl.text(message);
statusEl.css('color', type === 'success' ? '#28a745' : '#dc3545');
setTimeout(function() {
statusEl.text('');
}, 3000);
}
});
</script>
{% endblock %}