From 34f040df306a05fde68a6602898fd3cc54d71fb8 Mon Sep 17 00:00:00 2001 From: Mohamad Hesham Jenbaz Date: Tue, 6 Jan 2026 11:52:03 +0100 Subject: [PATCH] update --- db.sqlite3 | Bin 155648 -> 172032 bytes sheets/admin.py | 24 +- sheets/forms.py | 4 +- ...alter_betriebskosten_kostentyp_and_more.py | 31 + .../migrations/0009_alter_client_institute.py | 20 + ..._300_excelentry_druckkorrektur_and_more.py | 49 ++ sheets/models.py | 70 +- sheets/templates/table_one.html | 602 +++++++++++++++--- sheets/templates/table_two.html | 463 ++++++++++---- sheets/urls.py | 1 + sheets/views.py | 27 +- 11 files changed, 1027 insertions(+), 264 deletions(-) create mode 100644 sheets/migrations/0008_institute_alter_betriebskosten_kostentyp_and_more.py create mode 100644 sheets/migrations/0009_alter_client_institute.py create mode 100644 sheets/migrations/0010_excelentry_constant_300_excelentry_druckkorrektur_and_more.py diff --git a/db.sqlite3 b/db.sqlite3 index 462e62bd15f7f6a6347208c450a273cb6ee90376..d829c37dba676d232d8dfcb6951fc2992949ee7e 100644 GIT binary patch delta 4543 zcmcInYj7LY72dn6$F5e|W5-tfO7PlEuw_f~u2%1oV#jgfU}ERtq$Cu}vb?qw%Tj8| zAr56s9t?p@o2H&r86HDl)7P|wAX-g_b_yNJ&~~OY(@+XC5NMeeW>T18fKEecdv;~n zk=y`3TFd$*-Fwb=zkBYz=bpXmN$##EEnjY`j#CuXf$#PBCip&i+Ns#%l>6XGBmSb{ zeMHIuAHe(PvqzyCf7Hnc_BtEl8n$=AT&0-U%k1~r-h59L!_KQ~OjN@Wz9$n`)oezR zWGSK^im6F8m7ST3#L}ruHk!&t6sfFzd}cN_HI<&3QKz!AGm&U&JTjf0Q9Y8!=aOZY z$0y2iSPF*aklU~Ly^629$w)QyE{!6EBGF`4or%oHk_j9tlE85i+1czOh2-)CL|F=Z zf?>tyR(xK`=fAZPDdv_bg3C^eWMgV}CZUdHrqY?Lnu-)ZvU3M2^p(g_pO^K!y-G;( zd-7Wwo-nQ9g$o4Uga&v54#G*eAG(CULQJ>-wD6;Ri+DybHa0UMk{cN%t0OhF^^A)Y z1GlV&X;{q!O0DIJSbHUB|SQn2I4}YYa>$iOy!@kpt??bRv^Uq*Km?lU@CUU%1%S*}TSrTY!gp3f_X> zz)SEm_!>^p1#=LCdf1Y0k*)~#T0=wgBJa|Y@C&XRUtpZSIpTX@j z!OmarG*ZMN^9K{^?aMLfjiyAcMO@L&Wa67W@>KRu+a3u zFX4yq9r!vt0B7J7+zZFxJ@`5N1oHXn13O@!7BaJ4$66h0bX=ulwT@Lff{ucQyiG@| zj=bJ((UH@U)zO@L`5b9OO=l_iC;T1Wfxp2UsOuGY5iY`W@M~1|Bxb=M!+H1tD*OgK z1ZPpx1PmJ(j@UJ*)c~^&M^<9Sh#$tzLAGI z3T3>AgZ~sBhWp?UjKOAbLLKI&e+c#(-as`p7Z+%0#dFT*$RFKy%Xtc(f)Pw-M0i>_ zAq)sM+XdTc+iqKv^^*0hb%z!BU-5VIH(1`aoW~71Z<+70a}>03orLQN_G}S{#rEE~ zI-O7*x8Bi;$wM7)4U2c&dFO5B;^8UY8gkeZ2>bkQMV7rGd2=mN$T~#;DK^fgvQzF) z$TN>bUKxp$px3vh28k4%$iHdEEpAT7XVjTb$b>{5pF7|W2Bgr&RY>H}iF~N2Cpj@8 zwr`8xo>(!f`4!WWWw*!U3kHIls*%K{lX#J2%WQTciPQS8G!-oVurKJAWsl-hx~q_7 zz0RU+9oR0mZ;#Jq5>q81^Vf>6KkW6n{T`nb@b&>xbm+$Xn;jciBo;99H&(&^yd84J#L8__4!ElG`5)c|y`>EarPq82Syv>e*q?U3SJ@GPT{kus++Nh&JOMr|9G{bP5HY5%2X;;O2 z@NPkol!?)A zVT1NeU}ZFYCdQ|!FobknH|UBsd|RTc1neyRwZiubLN~n~X!t{Jbco(D-&P|~Eu_Up zb2P`|Un!yxQeBcI|}YqEZdT^QyVfaE`*e?HoE?MyH2is=WrvVtDN!u3v?g zR|Rp=azzv^k5R1g1Z9g^AK_H?8S~??-+01W&8S$c4=|SF!CTCAp%6L2=k|^gnY8Cl zjuIvJs!IL^SVdj^u$MbOLF_{LW1ik-)t>qilM%g3Z=sX%+@lj@wK*AABa>=IZ(OJS zI6Rwa701TrQ~f|DcMXqa@-_2ZoRsq%!S5DJ6kF@{_i#8HX;b`kjSywVLe9oG+Y&< z7Q&luG3f{3NaNm|tdhP$c8okon-4A5!xR0cJ&QIq1LnG2ZRAKOks4PIEf%(w&)Zlr zM`Avo6dVis%1l~vpC2Rky&q-YDh>@UmB2;AR<)sr@^D%1^fPPCMygrwDV9|g-Pf6nREvWw7fTiWO-3Wtq`PZ1PG#IY8)I^E#)1Jw2@ld#+6Euvd%_Q>eKJ4vcCTS0jZ&> delta 1301 zcmZWnZA@Eb6n@|LUixvN_w)i?DTuTQlWz3Vdy8}wwyYBoh;Bdv{&8t3rM8uRY;Bor zF$!f%aD=eg;5C~@ml@+PH`68kfs4#6G24vH#E*@L#PMSqbxVvN37F`6O9&e8$H|lD zob$ZrocByDaubXCGc|%2A@msix1PvZN3+R`nvTtsPzu9_>M+BGq4vW}76j{|-T^CR zOtl7TE&86E*4Ui4SwWxgu`Fn+IQ~9?AHf0(a13VP90b7$gukD+Nw@eC%MNA_R*b{g z)TA?+7$;6gLZM9B9~uvaVxdGPbzG< zw^eqvHOp;MYg4mZZk65n&y#K|$CS-s!xetHY>oy`mgVQ(9Ah{J;s{=Y0>tye5kKVP zmlP{w2UAXan`%l|`MhcM;SeLBR|{G%Ua!-Z7*IJ{MG8NJEwIYGOm37+5C>%t^Xb_G z=JF}Qqcyj;<7{7t*6i`%lkG}!ipaQLxiCeVx$J1?CVf<;%>_J+4-w_cEGaM4&yp{& zEo~lj;>mr{#7Jm-d$O7i4V@1{lhscs{XyJWnSEZrgzp$N z{4|1V;Go&10GVgpg84kq;2CYv9Qt@;qFp}Zm0X^y-qJ7?j^#X4s%it&Tki-~d(7rjhNk?|Cny{gr< zy(bYPZvY=Hq(arMfPDqtOZtEyqzv_v{#UTxCAnHeSrR3;jzX6xxkTA@FpwG@OIx2w zMiQYkV=vVq8@35pTMU-=h?0ldhAtQJB6jAd=fr~s{wU&jJH!9Mf5rFG%|8GcFvA_* z&VRr+sW0vQUr#~mBXxYeRo1Hq=nR0jWmyVkQC2?(1FtJ-9~oxrL_JdO`baHXx0|AM uAL(LcH$|O(GJtK$f}hkX1wXMuelOLzO$sXFHD7AElV$rcU`|&?HqDe6T 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 %} + +
-