+ Berichtsheft {{ report.year }} / {{ report.week }} +
++ Is Approved? + + {{ report.is_approved }} + +
+Content:
+-
+
diff --git a/.gitignore b/.gitignore
old mode 100755
new mode 100644
diff --git a/azube/__init__.py b/azube/__init__.py
old mode 100755
new mode 100644
diff --git a/azube/asgi.py b/azube/asgi.py
old mode 100755
new mode 100644
diff --git a/azube/settings.py b/azube/settings.py
old mode 100755
new mode 100644
diff --git a/azube/urls.py b/azube/urls.py
old mode 100755
new mode 100644
diff --git a/azube/wsgi.py b/azube/wsgi.py
old mode 100755
new mode 100644
diff --git a/core/__init__.py b/core/__init__.py
old mode 100755
new mode 100644
diff --git a/core/admin.py b/core/admin.py
old mode 100755
new mode 100644
diff --git a/core/apps.py b/core/apps.py
old mode 100755
new mode 100644
diff --git a/core/azure_auth.py b/core/azure_auth.py
old mode 100755
new mode 100644
index 3797d8a..2dee84e
--- a/core/azure_auth.py
+++ b/core/azure_auth.py
@@ -1,8 +1,17 @@
+import datetime
import json
import base64
from core.models import Berichtsheft
-from core.report_templates import ReportTemplates
+from core.reports import DailyReport, WeeklyReport, choose_report_kind
+import core.util
+from enum import Enum
+
+
+class Roles(Enum):
+ TRAINEE = "trainee"
+ MANAGER = "manager"
+ ADMIN = "admin"
class AzureUser:
@@ -33,8 +42,32 @@ class AzureUser:
self.id = "anon"
def reports(self):
- return Berichtsheft.objects.filter(user=self.id)
+ return Berichtsheft.objects.filter(user=self.id).order_by("-year", "-week")
- def get_report_template(self):
+ def get_report_kind(self):
# TODO : Implement
- return ReportTemplates.get_template("weekly")
+ return "weekly"
+
+ def get_report_kind_form(self, request=None, files=None):
+ return choose_report_kind(self.get_report_kind(), request, files)
+
+ def latest_report(self):
+ return self.reports().order_by("-year", "-week").first()
+
+ def late_reports(self) -> int:
+ year_now, week_now, _ = datetime.datetime.today().isocalendar()
+ count = 0
+ latest = self.latest_report()
+
+ new_year, new_week = (latest.year, latest.week)
+
+ while week_now != new_week or (week_now == new_week and year_now != new_year):
+ count += 1
+ new_year, new_week = core.util.next_date(new_year, new_week)
+
+ return count
+
+ @property
+ def role(self) -> Roles:
+ # TODO : Implement
+ return Roles.TRAINEE
diff --git a/core/doc_gen.py b/core/doc_gen.py
old mode 100755
new mode 100644
index e6b3040..7999cf8
--- a/core/doc_gen.py
+++ b/core/doc_gen.py
@@ -1,12 +1,35 @@
import json
+from weasyprint import HTML, CSS
+from io import BytesIO
+from pdf2image import convert_from_bytes
+from PIL import Image
+from django.conf import settings
+from django.template.loader import render_to_string
+from .models import Berichtsheft
+from io import BytesIO
-def gen_doc(template: str, vars: dict) -> str:
- definition = json.loads(open(f"{template}.json").read())
- content = open(f"{template}.html").read()
+def gen_doc_html(report: Berichtsheft):
+ return render_to_string(f"report_template/{report.kind}.html", report.vars())
- for var in definition["vars"]:
- var_r = var["name"].upper()
- content = content.replace(f"[[{var_r}]]", vars[var["name"]])
- return content
+def gen_doc_pdf(report: Berichtsheft):
+ main_content = gen_doc_html(report)
+
+ pdf_buffer = BytesIO()
+ HTML(
+ string=main_content,
+ ).write_pdf(pdf_buffer, stylesheets=[CSS(string="@page { size: A4; margin: 1cm }")])
+ pdf_buffer.seek(0)
+ return pdf_buffer
+
+
+def gen_doc_png(report: Berichtsheft):
+ pdf_buffer = gen_doc_pdf(report)
+ pages = convert_from_bytes(pdf_buffer.getvalue(), 300)
+
+ for page in pages:
+ img_byte_array = BytesIO()
+ page.save(img_byte_array, format="PNG")
+ img_byte_array.seek(0)
+ return img_byte_array
diff --git a/core/forms.py b/core/forms.py
deleted file mode 100755
index be9c917..0000000
--- a/core/forms.py
+++ /dev/null
@@ -1,5 +0,0 @@
-def extract_post_values(post, vars) -> dict:
- res = {}
- for var in vars:
- res[var["name"]] = post.get(var["name"], "")
- return res
diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py
old mode 100755
new mode 100644
index eaacbb1..7be4550
--- a/core/migrations/0001_initial.py
+++ b/core/migrations/0001_initial.py
@@ -6,7 +6,6 @@ import django.db.models.deletion
class Migration(migrations.Migration):
-
initial = True
dependencies = [
diff --git a/core/migrations/0002_alter_berichtsheft_id.py b/core/migrations/0002_alter_berichtsheft_id.py
old mode 100755
new mode 100644
index 21edbf1..2ccae28
--- a/core/migrations/0002_alter_berichtsheft_id.py
+++ b/core/migrations/0002_alter_berichtsheft_id.py
@@ -4,7 +4,6 @@ from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
("core", "0001_initial"),
]
diff --git a/core/migrations/0003_group_azureuser_alter_berichtsheft_user.py b/core/migrations/0003_group_azureuser_alter_berichtsheft_user.py
old mode 100755
new mode 100644
index 6050d9c..8cc8a8e
--- a/core/migrations/0003_group_azureuser_alter_berichtsheft_user.py
+++ b/core/migrations/0003_group_azureuser_alter_berichtsheft_user.py
@@ -8,7 +8,6 @@ import django.utils.timezone
class Migration(migrations.Migration):
-
dependencies = [
("auth", "0012_alter_user_first_name_max_length"),
("core", "0002_alter_berichtsheft_id"),
diff --git a/core/migrations/0004_remove_berichtsheft_approved_by.py b/core/migrations/0004_remove_berichtsheft_approved_by.py
old mode 100755
new mode 100644
index aa1f29b..78b4b3f
--- a/core/migrations/0004_remove_berichtsheft_approved_by.py
+++ b/core/migrations/0004_remove_berichtsheft_approved_by.py
@@ -4,7 +4,6 @@ from django.db import migrations
class Migration(migrations.Migration):
-
dependencies = [
("core", "0003_group_azureuser_alter_berichtsheft_user"),
]
diff --git a/core/migrations/0005_user_alter_berichtsheft_user_delete_azureuser.py b/core/migrations/0005_user_alter_berichtsheft_user_delete_azureuser.py
old mode 100755
new mode 100644
index cf368b3..f52a13b
--- a/core/migrations/0005_user_alter_berichtsheft_user_delete_azureuser.py
+++ b/core/migrations/0005_user_alter_berichtsheft_user_delete_azureuser.py
@@ -7,7 +7,6 @@ import django.utils.timezone
class Migration(migrations.Migration):
-
dependencies = [
("auth", "0012_alter_user_first_name_max_length"),
("core", "0004_remove_berichtsheft_approved_by"),
diff --git a/core/migrations/0006_berichtsheft_num.py b/core/migrations/0006_berichtsheft_num.py
old mode 100755
new mode 100644
index 985fc22..4ab5e4d
--- a/core/migrations/0006_berichtsheft_num.py
+++ b/core/migrations/0006_berichtsheft_num.py
@@ -4,7 +4,6 @@ from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
("core", "0005_user_alter_berichtsheft_user_delete_azureuser"),
]
diff --git a/core/migrations/0007_approval.py b/core/migrations/0007_approval.py
new file mode 100644
index 0000000..1cb35ba
--- /dev/null
+++ b/core/migrations/0007_approval.py
@@ -0,0 +1,28 @@
+# Generated by Django 4.2.16 on 2024-12-03 12:41
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("core", "0006_berichtsheft_num"),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name="Approval",
+ fields=[
+ ("id", models.AutoField(primary_key=True, serialize=False)),
+ ("user", models.TextField()),
+ (
+ "report",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="report",
+ to="core.berichtsheft",
+ ),
+ ),
+ ],
+ ),
+ ]
diff --git a/core/migrations/0008_berichtsheft_needs_rewrite.py b/core/migrations/0008_berichtsheft_needs_rewrite.py
new file mode 100644
index 0000000..a67dc54
--- /dev/null
+++ b/core/migrations/0008_berichtsheft_needs_rewrite.py
@@ -0,0 +1,17 @@
+# Generated by Django 4.2.16 on 2024-12-03 12:44
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("core", "0007_approval"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="berichtsheft",
+ name="needs_rewrite",
+ field=models.BooleanField(default=False),
+ ),
+ ]
diff --git a/core/migrations/0009_berichtsheft_kind.py b/core/migrations/0009_berichtsheft_kind.py
new file mode 100644
index 0000000..016887d
--- /dev/null
+++ b/core/migrations/0009_berichtsheft_kind.py
@@ -0,0 +1,21 @@
+# Generated by Django 4.2.16 on 2024-12-03 14:24
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("core", "0008_berichtsheft_needs_rewrite"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="berichtsheft",
+ name="kind",
+ field=models.CharField(
+ choices=[("weekly", "Weekly"), ("daily", "Daily")],
+ default="weekly",
+ max_length=20,
+ ),
+ ),
+ ]
diff --git a/core/migrations/0010_berichtsheft_department.py b/core/migrations/0010_berichtsheft_department.py
new file mode 100644
index 0000000..57c931f
--- /dev/null
+++ b/core/migrations/0010_berichtsheft_department.py
@@ -0,0 +1,17 @@
+# Generated by Django 4.2.16 on 2024-12-03 15:51
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("core", "0009_berichtsheft_kind"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="berichtsheft",
+ name="department",
+ field=models.CharField(default="", max_length=160),
+ ),
+ ]
diff --git a/core/migrations/0011_berichtsheftdraft.py b/core/migrations/0011_berichtsheftdraft.py
new file mode 100644
index 0000000..9f73ecf
--- /dev/null
+++ b/core/migrations/0011_berichtsheftdraft.py
@@ -0,0 +1,20 @@
+# Generated by Django 4.2.17 on 2024-12-05 10:37
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("core", "0010_berichtsheft_department"),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name="BerichtsheftDraft",
+ fields=[
+ ("user", models.TextField(primary_key=True, serialize=False)),
+ ("department", models.CharField(default="", max_length=160)),
+ ("content", models.JSONField()),
+ ],
+ ),
+ ]
diff --git a/core/migrations/0012_berichtsheft_image.py b/core/migrations/0012_berichtsheft_image.py
new file mode 100644
index 0000000..b6e5aed
--- /dev/null
+++ b/core/migrations/0012_berichtsheft_image.py
@@ -0,0 +1,17 @@
+# Generated by Django 4.2.17 on 2024-12-06 09:38
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("core", "0011_berichtsheftdraft"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="berichtsheft",
+ name="image",
+ field=models.BinaryField(blank=True, null=True),
+ ),
+ ]
diff --git a/core/migrations/__init__.py b/core/migrations/__init__.py
old mode 100755
new mode 100644
diff --git a/core/models.py b/core/models.py
old mode 100755
new mode 100644
index 8a57865..96df7f8
--- a/core/models.py
+++ b/core/models.py
@@ -1,6 +1,8 @@
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.models import Group as BuiltinGroup
+from .util import get_week_range
+import base64
class User(AbstractUser):
@@ -21,22 +23,66 @@ class Group(BuiltinGroup):
proxy = True
+class ReportKind(models.TextChoices):
+ WEEKLY = "weekly"
+ DAILY = "daily"
+
+
class Berichtsheft(models.Model):
id = models.AutoField(primary_key=True)
user = models.TextField()
+ kind = models.CharField(
+ max_length=20, choices=ReportKind.choices, default=ReportKind.WEEKLY
+ )
num = models.PositiveBigIntegerField(default=0)
year = models.PositiveIntegerField()
week = models.PositiveSmallIntegerField()
+ department = models.CharField(max_length=160, default="")
content = models.JSONField()
+ needs_rewrite = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
+ image = models.BinaryField(null=True, blank=True)
def __str__(self):
return f"Berichtsheft: {self.user}, Year: {self.year}, Week: {self.week}"
+ @property
+ def is_approved(self):
+ approvals = Approval.objects.filter(report=self.id)
+ return len(approvals) >= 2
-class Approval:
+ def vars(self):
+ start_date, end_date = get_week_range(self.year, self.week)
+
+ vars = {
+ "user": self.user,
+ "kind": self.kind,
+ "num": self.num,
+ "year": self.year,
+ "week": self.week,
+ "department": self.department,
+ "start_date": start_date,
+ "end_date": end_date,
+ "image": base64.b64encode(self.image).decode("utf-8")
+ if self.image is not None
+ else None,
+ }
+
+ for key, val in self.content.items():
+ vars[key] = val
+
+ return vars
+
+
+class Approval(models.Model):
id = models.AutoField(primary_key=True)
user = models.TextField()
report = models.ForeignKey(
Berichtsheft, on_delete=models.CASCADE, related_name="report"
)
+
+
+class BerichtsheftDraft(models.Model):
+ user = models.TextField(primary_key=True)
+ department = models.CharField(max_length=160, default="")
+ content = models.JSONField()
diff --git a/core/report_templates.py b/core/report_templates.py
deleted file mode 100755
index a5f2073..0000000
--- a/core/report_templates.py
+++ /dev/null
@@ -1,29 +0,0 @@
-class ReportTemplates:
- report_global = {
- "vars": [
- {"name": "name", "display_name": "Name"},
- {"name": "num_doc", "display_name": "Berichtsheft Nummer"},
- {"name": "year", "display_name": "Jahr"},
- {"name": "week", "display_name": "Kalenderwoche"},
- {"name": "start_date", "display_name": "Von"},
- {"name": "end_date", "display_name": "bis"},
- {"name": "department", "display_name": "Abteilung"},
- ]
- }
-
- def get_template(id) -> dict:
- match id:
- case "weekly":
- weekly = {
- "vars": [
- {
- "name": "company_text",
- "display_name": "Betriebliche Tätigkeiten",
- },
- {"name": "week_topic", "display_name": "Thema der Woche"},
- {"name": "school_text", "display_name": "Berufsschule"},
- ]
- }
-
- weekly["vars"].extend(ReportTemplates.report_global["vars"])
- return weekly
diff --git a/core/reports.py b/core/reports.py
new file mode 100644
index 0000000..fa637af
--- /dev/null
+++ b/core/reports.py
@@ -0,0 +1,196 @@
+from django import forms
+
+from core.styles import label_span, STYLE
+
+
+class WeeklyReport(forms.Form):
+ department = forms.CharField(
+ label=label_span("Abteilung"),
+ max_length=150,
+ widget=forms.TextInput(
+ attrs={
+ "placeholder": "Abteilung",
+ "class": STYLE["text-input"],
+ }
+ ),
+ )
+ company_text = forms.CharField(
+ label=label_span("Betriebliche Tätigkeiten"),
+ max_length=300,
+ widget=forms.Textarea(
+ attrs={
+ "class": STYLE["text-input"],
+ "rows": 5,
+ "placeholder": "Betriebliche Tätigkeiten",
+ }
+ ),
+ )
+ week_topic = forms.CharField(
+ label=label_span("Thema der Woche"),
+ max_length=600,
+ widget=forms.Textarea(
+ attrs={
+ "class": STYLE["text-input"],
+ "rows": 10,
+ "placeholder": "Thema der Woche",
+ }
+ ),
+ )
+ school_text = forms.CharField(
+ label=label_span("Berufsschule"),
+ max_length=300,
+ widget=forms.Textarea(
+ attrs={
+ "class": STYLE["text-input"],
+ "rows": 5,
+ "placeholder": "Berufsschule",
+ }
+ ),
+ )
+ img = forms.ImageField(
+ label=label_span("Bild"),
+ required=False,
+ widget=forms.ClearableFileInput(
+ attrs={
+ "class": "block w-full p-2 text-sm text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-none dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400",
+ "accept": "image/*",
+ }
+ ),
+ )
+
+ @property
+ def display_names(self):
+ return {
+ "department": self.fields["department"].label,
+ "company_text": self.fields["company_text"].label,
+ "week_topic": self.fields["week_topic"].label,
+ "school_text": self.fields["school_text"].label,
+ }
+
+ def content_values(self) -> dict:
+ if self.is_valid():
+ return {
+ "company_text": self.cleaned_data["company_text"],
+ "week_topic": self.cleaned_data["week_topic"],
+ "school_text": self.cleaned_data["school_text"],
+ }
+
+
+class DailyReport(forms.Form):
+ department = forms.CharField(
+ label=label_span("Abteilung"),
+ max_length=150,
+ widget=forms.TextInput(
+ attrs={
+ "placeholder": "Abteilung",
+ "class": STYLE["text-input"],
+ }
+ ),
+ )
+ week_topic = forms.CharField(
+ label=label_span("Thema der Woche"),
+ max_length=600,
+ widget=forms.Textarea(
+ attrs={
+ "class": STYLE["text-input"],
+ "rows": 5,
+ "placeholder": "Thema der Woche",
+ }
+ ),
+ )
+ monday_text = forms.CharField(
+ label=label_span("Montag"),
+ max_length=300,
+ widget=forms.Textarea(
+ attrs={
+ "class": STYLE["text-input"],
+ "rows": 5,
+ "placeholder": "Montag",
+ }
+ ),
+ )
+ tuesday_text = forms.CharField(
+ label=label_span("Dienstag"),
+ max_length=300,
+ widget=forms.Textarea(
+ attrs={
+ "class": STYLE["text-input"],
+ "rows": 5,
+ "placeholder": "Dienstag",
+ }
+ ),
+ )
+ wednesday_text = forms.CharField(
+ label=label_span("Mittwoch"),
+ max_length=300,
+ widget=forms.Textarea(
+ attrs={
+ "class": STYLE["text-input"],
+ "rows": 5,
+ "placeholder": "Mittwoch,",
+ }
+ ),
+ )
+ thursday_text = forms.CharField(
+ label=label_span("Donnerstag"),
+ max_length=300,
+ widget=forms.Textarea(
+ attrs={
+ "class": STYLE["text-input"],
+ "rows": 5,
+ "placeholder": "Donnerstag",
+ }
+ ),
+ )
+ friday_text = forms.CharField(
+ label=label_span("Freitag"),
+ max_length=300,
+ widget=forms.Textarea(
+ attrs={
+ "class": STYLE["text-input"],
+ "rows": 5,
+ "placeholder": "Freitag",
+ }
+ ),
+ )
+ img = forms.ImageField(
+ label=label_span("Bild"),
+ required=False,
+ widget=forms.ClearableFileInput(
+ attrs={
+ "class": "block w-full p-2 text-sm text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-none dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400",
+ "accept": "image/*",
+ }
+ ),
+ )
+
+ @property
+ def display_names(self) -> dict:
+ return {
+ "department": self.fields["department"].label,
+ "week_topic": self.fields["week_topic"].label,
+ "monday_text": self.fields["monday_text"].label,
+ "tuesday_text": self.fields["tuesday_text"].label,
+ "wednesday_text": self.fields["wednesday_text"].label,
+ "thursday_text": self.fields["thursday_text"].label,
+ "friday_text": self.fields["friday_text"].label,
+ }
+
+ def content_values(self) -> dict:
+ if self.is_valid():
+ return {
+ "week_topic": self.cleaned_data["week_topic"],
+ "monday_text": self.cleaned_data["monday_text"],
+ "tuesday_text": self.cleaned_data["tuesday_text"],
+ "wednesday_text": self.cleaned_data["wednesday_text"],
+ "thursday_text": self.cleaned_data["thursday_text"],
+ "friday_text": self.cleaned_data["friday_text"],
+ }
+
+
+def choose_report_kind(kind, request=None, files=None):
+ match kind:
+ case "weekly":
+ return WeeklyReport(request, files)
+ case "daily":
+ return DailyReport(request, files)
diff --git a/core/styles.py b/core/styles.py
new file mode 100644
index 0000000..7f9ce5a
--- /dev/null
+++ b/core/styles.py
@@ -0,0 +1,11 @@
+# Tailwind Styles
+
+STYLE = {
+ "red_btn": "text-white bg-red-700 hover:bg-red-800 focus:outline-none focus:ring-4 focus:ring-red-300 font-medium rounded-full text-sm px-5 py-2.5 text-center me-2 mb-2 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-900",
+ "card": "bg-white drop-shadow-md mx-auto mt-5 aspect-[2/3] hover:drop-shadow-xl hover:scale-[0.85] scale-[0.8] lg:hover:scale-[0.95] lg:scale-[0.9] transition-all duration-50 transform ease-in-out w-60 sm:w-80 flex items-center justify-center",
+ "text-input": "w-full p-2 border border-gray-300 rounded-lg focus:ring focus:ring-blue-400 mb-5",
+}
+
+
+def label_span(txt):
+ return f'{txt}'
diff --git a/core/templates/component/report.html b/core/templates/component/report.html
new file mode 100644
index 0000000..331469c
--- /dev/null
+++ b/core/templates/component/report.html
@@ -0,0 +1,13 @@
+
+ {% if report.is_approved %}
+
+
diff --git a/core/templates/head.html b/core/templates/head.html
new file mode 100644
index 0000000..e1d2240
--- /dev/null
+++ b/core/templates/head.html
@@ -0,0 +1,3 @@
+
+
+
diff --git a/core/templates/htmx/reports.html b/core/templates/htmx/reports.html
new file mode 100644
index 0000000..aee0210
--- /dev/null
+++ b/core/templates/htmx/reports.html
@@ -0,0 +1,12 @@
+{% if reports|length != 0 %}
+ {% for report in reports %}
+
+ {% include 'component/report.html' with report=report %}
+
+ {% endfor %}
+
+
Du bist nicht aktuell!
+Du hast noch {{ late_reports }} Berichtshefte nachzuschreiben.
+{{ report }}
-+ Berichtsheft {{ report.year }} / {{ report.week }} +
++ Is Approved? + + {{ report.is_approved }} + +
++ +
+ |
+
+ |
+ ||||||
+ Name: {{ user }} |
+
+ Ausbildungsnachweis Nr. {{ num }}
+ |
+ ||||||
+ |
+
+ |
+ ||||||
+ |
+
+ |
+
+ Ausbildungsjahr: {{ year }} |
+ |||||
+ Firma: |
+
+ Ausbildungsabteilung: {{ department }} |
+
+ |
+ |||||
+ |
+
+ |
+
+ |
+ |||||
+ CANCOM GmbH |
+
+ |
+
+ Woche: {{ week }} |
+ |||||
+ Messerschmittstr. 20 |
+
+ |
+
+ |
+ |||||
+ 89343 Jettingen-Scheppach |
+
+ |
+
+ |
+ |||||
+ |
+
+ |
+
+ vom: {{ start_date }} bis: {{ end_date }} |
+ |||||
+ |
+
+ |
+
+ |
+ |||||
+ Betriebliche
+ Tätigkeit (bitte
+ Ausbildungsverlauf mit der zeitlichen und sachlichen Gliederung abgleichen): {{ company_text|markdown|safe }} |
+
+ Stunden
+ |
+ ||||||
+ Thema der Woche: |
+
+ |
+ ||||||
+ |
+ |||||||
+ |
+ |||||||
+ Berufsschule (Themen des
+ Unterrichts) {{ school_text|markdown|safe }} |
+
+ |
+ ||||||
+ |
+ |||||||
+ |
+
+ 8 |
+ ||||||
+ Gesamtstunden |
+
+ 40 |
+ ||||||
+ |
+
+ |
+
+ |
+ |||||
+ Für
+ die |
+
+ |
+
+ |
+
+ |
+
+ |
+ |||
+ Richtigkeit |
+
+ ____________________ |
+
+ ____________________ |
+
+ ____________________ |
+
+ ____________________ |
+ |||
+ |
+
+ Datum |
+
+ Auszubildender |
+
+ Datum |
+
+ Ausbilder |
+ |||
+ |
+
+ |
+
+ |
+ |||||
+ | + | + | + | + | + | + | + |
+ Benutzer: +
+ +{{ user.display_name }}
+{{ user.role.value|capfirst }}
diff --git a/core/templates/shell.html b/core/templates/shell.html new file mode 100644 index 0000000..a4402a5 --- /dev/null +++ b/core/templates/shell.html @@ -0,0 +1,70 @@ + + +{{ user.display_name }}
++ Berichtsheft {{ year }} / {{ week }} +
++ Von: {{ start_date|date:"d.m.Y" }} bis: {{ end_date|date:"d.m.Y" }} +
+Berichtsheft {{ year }} / {{ week }}
+ + + + - - + + +