diff --git a/db.sqlite3 b/db.sqlite3 index 462e62b..d829c37 100644 Binary files a/db.sqlite3 and b/db.sqlite3 differ diff --git a/sheets/admin.py b/sheets/admin.py index 7f2c5ce..279c053 100644 --- a/sheets/admin.py +++ b/sheets/admin.py @@ -1,20 +1,21 @@ from django.contrib import admin -from .models import Client # Only import Client -from .models import SecondTableEntry +from .models import Institute, Client, ExcelEntry, SecondTableEntry, Betriebskosten + +# Register Institute model +admin.site.register(Institute) -# Register only the Client model @admin.register(Client) class ClientAdmin(admin.ModelAdmin): - list_display = ('name', 'address') - search_fields = ('name',) + list_display = ('name', 'institute', 'address') # Added institute here + search_fields = ('name', 'institute__name') # Added institute search - # Optional: Customize the add form fields - fields = ['name', 'address'] + # FIX: Include 'institute' in the fields list + fields = ['name', 'institute', 'address'] # Added 'institute' here @admin.register(SecondTableEntry) class SecondTableEntryAdmin(admin.ModelAdmin): list_display = ('id', 'client', 'date', 'is_warm', 'lhe_output_short', 'notes_preview') - list_display_links = ('id', 'client') # Fields that link to edit page + list_display_links = ('id', 'client') list_editable = ('is_warm',) list_filter = ('is_warm', 'client') search_fields = ('client__name', 'notes') @@ -35,11 +36,14 @@ class SecondTableEntryAdmin(admin.ModelAdmin): }) ) - # Custom display methods def lhe_output_short(self, obj): return f"{obj.lhe_output} L" if obj.lhe_output else "-" lhe_output_short.short_description = 'Output' def notes_preview(self, obj): return obj.notes[:30] + '...' if obj.notes else "" - notes_preview.short_description = 'Notes Preview' \ No newline at end of file + notes_preview.short_description = 'Notes Preview' + +# Register other models +admin.site.register(ExcelEntry) +admin.site.register(Betriebskosten) \ No newline at end of file diff --git a/sheets/forms.py b/sheets/forms.py index 9521965..1b4f3ba 100644 --- a/sheets/forms.py +++ b/sheets/forms.py @@ -1,5 +1,7 @@ from django import forms -from .models import ExcelEntry, Betriebskosten +from .models import ExcelEntry, Betriebskosten, Institute + + class ExcelEntryForm(forms.ModelForm): class Meta: diff --git a/sheets/migrations/0008_institute_alter_betriebskosten_kostentyp_and_more.py b/sheets/migrations/0008_institute_alter_betriebskosten_kostentyp_and_more.py new file mode 100644 index 0000000..883face --- /dev/null +++ b/sheets/migrations/0008_institute_alter_betriebskosten_kostentyp_and_more.py @@ -0,0 +1,31 @@ +# Generated by Django 5.1.5 on 2025-10-27 10:08 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sheets', '0007_betriebskosten'), + ] + + operations = [ + migrations.CreateModel( + name='Institute', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ], + ), + migrations.AlterField( + model_name='betriebskosten', + name='kostentyp', + field=models.CharField(choices=[('sach', 'Sachkostöen'), ('ln2', 'LN2'), ('helium', 'Helium'), ('inv', 'Inventar')], max_length=10, verbose_name='Kostentyp'), + ), + migrations.AddField( + model_name='client', + name='institute', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='sheets.institute'), + ), + ] diff --git a/sheets/migrations/0009_alter_client_institute.py b/sheets/migrations/0009_alter_client_institute.py new file mode 100644 index 0000000..253cb45 --- /dev/null +++ b/sheets/migrations/0009_alter_client_institute.py @@ -0,0 +1,20 @@ +# Generated by Django 5.1.5 on 2025-10-27 10:28 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sheets', '0008_institute_alter_betriebskosten_kostentyp_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='client', + name='institute', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='sheets.institute'), + preserve_default=False, + ), + ] diff --git a/sheets/migrations/0010_excelentry_constant_300_excelentry_druckkorrektur_and_more.py b/sheets/migrations/0010_excelentry_constant_300_excelentry_druckkorrektur_and_more.py new file mode 100644 index 0000000..31821b6 --- /dev/null +++ b/sheets/migrations/0010_excelentry_constant_300_excelentry_druckkorrektur_and_more.py @@ -0,0 +1,49 @@ +# Generated by Django 5.1.5 on 2025-11-25 11:08 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sheets', '0009_alter_client_institute'), + ] + + operations = [ + migrations.AddField( + model_name='excelentry', + name='constant_300', + field=models.DecimalField(decimal_places=3, default=300.0, max_digits=10), + ), + migrations.AddField( + model_name='excelentry', + name='druckkorrektur', + field=models.DecimalField(decimal_places=3, default=1.0, max_digits=10, validators=[django.core.validators.MinValueValidator(0)]), + ), + migrations.AddField( + model_name='excelentry', + name='korrig_druck', + field=models.DecimalField(decimal_places=6, default=0.0, max_digits=12), + ), + migrations.AddField( + model_name='excelentry', + name='lhe', + field=models.DecimalField(decimal_places=6, default=0.0, max_digits=12), + ), + migrations.AddField( + model_name='excelentry', + name='lhe_ges', + field=models.DecimalField(decimal_places=6, default=0.0, max_digits=12), + ), + migrations.AddField( + model_name='excelentry', + name='lhe_zus', + field=models.DecimalField(decimal_places=3, default=0.0, max_digits=10, validators=[django.core.validators.MinValueValidator(0)]), + ), + migrations.AddField( + model_name='excelentry', + name='nm3', + field=models.DecimalField(decimal_places=6, default=0.0, max_digits=12), + ), + ] diff --git a/sheets/models.py b/sheets/models.py index 8364335..3076f5d 100644 --- a/sheets/models.py +++ b/sheets/models.py @@ -2,6 +2,11 @@ from django.db import models from django.utils import timezone from django.core.validators import MinValueValidator, MaxValueValidator +class Institute(models.Model): + name = models.CharField(max_length=100) + + def __str__(self): + return self.name class Betriebskosten(models.Model): KOSTENTYP_CHOICES = [ @@ -30,9 +35,10 @@ class Betriebskosten(models.Model): class Client(models.Model): name = models.CharField(max_length=100) address = models.TextField() - + institute = models.ForeignKey(Institute, on_delete=models.CASCADE) # Remove null=True, blank=True + def __str__(self): - return self.name + return f"{self.name} ({self.institute.name})" class ExcelEntry(models.Model): client = models.ForeignKey(Client, on_delete=models.CASCADE) @@ -52,23 +58,65 @@ class ExcelEntry(models.Model): notes = models.TextField(blank=True, null=True) date_joined = models.DateField(auto_now_add=True) - def __str__(self): - return f"{self.client.name} - {self.date}" + # Manual input + lhe_zus = models.DecimalField( + max_digits=10, + decimal_places=3, + validators=[MinValueValidator(0)], + default=0.0 + ) + druckkorrektur = models.DecimalField( + max_digits=10, + decimal_places=3, + validators=[MinValueValidator(0)], + default=1.0 + ) + + # Auto-calculated values (saved) + constant_300 = models.DecimalField( + max_digits=10, + decimal_places=3, + default=300.0 + ) + + korrig_druck = models.DecimalField( + max_digits=12, + decimal_places=6, + default=0.0 + ) + + nm3 = models.DecimalField( + max_digits=12, + decimal_places=6, + default=0.0 + ) + + lhe = models.DecimalField( + max_digits=12, + decimal_places=6, + default=0.0 + ) + + lhe_ges = models.DecimalField( + max_digits=12, + decimal_places=6, + default=0.0 + ) class SecondTableEntry(models.Model): client = models.ForeignKey(Client, on_delete=models.CASCADE) - date = models.DateField(default=timezone.now) # Added default value + date = models.DateField(default=timezone.now) is_warm = models.BooleanField(default=False) lhe_delivery = models.CharField(max_length=100, blank=True, null=True) lhe_output = models.DecimalField( - max_digits=10, - decimal_places=2, - validators=[MinValueValidator(0)], - blank=True, - null=True + max_digits=10, + decimal_places=2, + validators=[MinValueValidator(0)], + blank=True, + null=True ) notes = models.TextField(blank=True, null=True) date_joined = models.DateField(auto_now_add=True) def __str__(self): - return f"{self.client.name} - {self.date}" \ No newline at end of file + return f"{self.client.name} - {self.date}" \ No newline at end of file diff --git a/sheets/templates/table_one.html b/sheets/templates/table_one.html index 9df8de3..8218007 100644 --- a/sheets/templates/table_one.html +++ b/sheets/templates/table_one.html @@ -15,11 +15,12 @@ background-color: #f4f4f9; } .table-container { - width: 48%; + width: 100%; background-color: white; padding: 20px; border-radius: 8px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + overflow-x: auto; } h2 { text-align: center; @@ -34,15 +35,23 @@ padding: 12px; text-align: center; border-bottom: 1px solid #ddd; + word-wrap: break-word; } - th:nth-child(1), td:nth-child(1) { width: 5%; } /* # column */ - th:nth-child(2), td:nth-child(2) { width: 5%; } /* ID column */ - th:nth-child(3), td:nth-child(3) { width: 15%; } /* Client column */ - th:nth-child(4), td:nth-child(4) { width: 10%; } /* Entry 1 (Pressure) */ - th:nth-child(5), td:nth-child(5) { width: 10%; } /* Entry 2 (Purity) */ - th:nth-child(6), td:nth-child(6) { width: 15%; } /* Date Joined */ - th:nth-child(7), td:nth-child(7) { width: 25%; } /* Notes */ - th:nth-child(7), td:nth-child(7) { width: 30%; } /* Actions */ + th:nth-child(1), td:nth-child(1) { width: 3%; } /* # column */ + th:nth-child(2), td:nth-child(2) { width: 3%; } /* ID column */ + th:nth-child(3), td:nth-child(3) { width: 8%; } /* Institute */ + th:nth-child(4), td:nth-child(4) { width: 8%; } /* Client */ + th:nth-child(5), td:nth-child(5) { width: 5%; } /* Druck */ + th:nth-child(6), td:nth-child(6) { width: 5%; } /* Reinheit */ + th:nth-child(7), td:nth-child(7) { width: 5%; } /* Druckkorrektur */ + th:nth-child(8), td:nth-child(8) { width: 6%; } /* ges. Flasch. Inhalt */ + th:nth-child(9), td:nth-child(9) { width: 6%; } /* Korrig. Druck */ + th:nth-child(10), td:nth-child(10) { width: 5%; } /* Nm³ */ + th:nth-child(11), td:nth-child(11) { width: 5%; } /* L-He */ + th:nth-child(12), td:nth-child(12) { width: 5%; } /* L-He zus. */ + th:nth-child(13), td:nth-child(13) { width: 6%; } /* L-He ges. */ + th:nth-child(14), td:nth-child(14) { width: 6%; } /* Date Joined */ + th:nth-child(15), td:nth-child(15) { width: 8%; } /* Actions */ .actions { white-space: nowrap; /* Prevent buttons from wrapping */ @@ -84,23 +93,58 @@ border-radius: 5px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); z-index: 1000; + width: 500px; + max-height: 90vh; + overflow-y: auto; } - .popup input, .popup select { + .popup h3 { + margin-top: 0; + border-bottom: 1px solid #ddd; + padding-bottom: 10px; + } + .popup label { display: block; - margin-bottom: 10px; + margin-bottom: 5px; + font-weight: bold; + } + .popup input, .popup select, .popup textarea { + display: block; + margin-bottom: 15px; width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; + box-sizing: border-box; + } + .popup textarea { + height: 100px; + resize: vertical; + } + .popup-buttons { + display: flex; + justify-content: flex-end; + gap: 10px; + margin-top: 20px; } .popup button { - margin-top: 10px; padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; } + .save-btn { + background-color: #28a745; + color: white; + } + .cancel-btn { + background-color: #6c757d; + color: white; + } + .help-btn { + background-color: #17a2b8; + color: white; + } .close-btn { cursor: pointer; float: right; @@ -120,7 +164,34 @@ .add-row-btn:hover { background-color: #0056b3; } - + .input-with-label { + display: flex; + align-items: center; + margin-bottom: 15px; + } + .input-with-label label { + width: 150px; + margin-bottom: 0; + margin-right: 10px; + } + .input-with-label input { + flex: 1; + margin-bottom: 0; + } + .formula-display { + background-color: #f8f9fa; + border: 1px solid #dee2e6; + border-radius: 4px; + padding: 8px; + margin-bottom: 15px; + font-size: 12px; + color: #6c757d; + font-style: italic; + } + .readonly-field { + background-color: #e9ecef; + color: #6c757d; + } @@ -133,64 +204,96 @@
- - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {% for entry in entries_table1 %} + + + + + + + + + + + + + + + + - - - {% for entry in entries_table1 %} - - - - - - - - - - - {% endfor %} - -
#IDClientDruckReinheitDate JoinedNotesActions
#IDInstituteClientDruckReinheitDruckkorrekturges. Flasch. InhaltKorrig. DruckNm³L-HeL-He zus.L-He ges.Date JoinedActions
{{ forloop.counter }}{{ entry.id }}{{ entry.client.institute.name }}{{ entry.client.name }}{{ entry.pressure|floatformat:2 }}{{ entry.purity|floatformat:2 }}{{ entry.druckkorrektur|floatformat:3 }}{{ entry.constant_300|floatformat:3 }}{{ entry.korrig_druck|floatformat:6 }}{{ entry.nm3|floatformat:6 }}{{ entry.lhe|floatformat:6 }}{{ entry.lhe_zus|floatformat:3 }}{{ entry.lhe_ges|floatformat:6 }}{{ entry.date_joined|date:"Y-m-d" }} + + +
{{ forloop.counter }}{{ entry.id }}{{ entry.client.name }}{{ entry.pressure|floatformat:2 }}{{ entry.purity|floatformat:2 }}{{ entry.date_joined|date:"Y-m-d" }}{{ entry.notes|default:"" }} - - -
+ {% endfor %} + +
-