diff --git a/config/__pycache__/settings.cpython-311.pyc b/config/__pycache__/settings.cpython-311.pyc index 99b0063..80f84c6 100644 Binary files a/config/__pycache__/settings.cpython-311.pyc and b/config/__pycache__/settings.cpython-311.pyc differ diff --git a/config/__pycache__/urls.cpython-311.pyc b/config/__pycache__/urls.cpython-311.pyc index ecbd4a1..52c9fc5 100644 Binary files a/config/__pycache__/urls.cpython-311.pyc and b/config/__pycache__/urls.cpython-311.pyc differ diff --git a/config/settings.py b/config/settings.py index 714f84e..ad444c4 100644 --- a/config/settings.py +++ b/config/settings.py @@ -23,14 +23,16 @@ DEBUG = os.getenv("DJANGO_DEBUG", "true").lower() == "true" ALLOWED_HOSTS = [ "127.0.0.1", "localhost", + "foxlog.flatlogic.app", os.getenv("HOST_FQDN", ""), ] CSRF_TRUSTED_ORIGINS = [ - origin for origin in [ + "https://foxlog.flatlogic.app", + *[origin for origin in [ os.getenv("HOST_FQDN", ""), os.getenv("CSRF_TRUSTED_ORIGIN", "") - ] if origin + ] if origin] ] CSRF_TRUSTED_ORIGINS = [ f"https://{host}" if not host.startswith(("http://", "https://")) else host @@ -156,6 +158,10 @@ STATICFILES_DIRS = [ BASE_DIR / 'node_modules', ] +# Media files (Uploads) +MEDIA_URL = '/media/' +MEDIA_ROOT = BASE_DIR / 'media' + # Email EMAIL_BACKEND = os.getenv( "EMAIL_BACKEND", @@ -185,4 +191,4 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' # Authentication LOGIN_URL = 'login' LOGIN_REDIRECT_URL = 'home' -LOGOUT_REDIRECT_URL = 'login' \ No newline at end of file +LOGOUT_REDIRECT_URL = 'login' diff --git a/config/urls.py b/config/urls.py index 2cb6937..7934289 100644 --- a/config/urls.py +++ b/config/urls.py @@ -27,4 +27,5 @@ urlpatterns = [ if settings.DEBUG: urlpatterns += static("/assets/", document_root=settings.BASE_DIR / "assets") - urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) \ No newline at end of file + urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index fe8bccf..0d1900a 100644 Binary files a/core/__pycache__/admin.cpython-311.pyc and b/core/__pycache__/admin.cpython-311.pyc differ diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index 1255e6c..d899904 100644 Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index bed590a..e3d2735 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/admin.py b/core/admin.py index deee1d0..e82cf4b 100644 --- a/core/admin.py +++ b/core/admin.py @@ -7,8 +7,9 @@ class UserProfileAdmin(admin.ModelAdmin): @admin.register(Worker) class WorkerAdmin(admin.ModelAdmin): - list_display = ('name', 'id_no', 'phone_no', 'monthly_salary') + list_display = ('name', 'id_no', 'phone_no', 'monthly_salary', 'date_of_employment', 'projects_worked_on_count') search_fields = ('name', 'id_no') + readonly_fields = ('projects_worked_on_count',) # Calculated field should be readonly in edit form @admin.register(Project) class ProjectAdmin(admin.ModelAdmin): @@ -24,4 +25,4 @@ class TeamAdmin(admin.ModelAdmin): class WorkLogAdmin(admin.ModelAdmin): list_display = ('date', 'project', 'supervisor') list_filter = ('date', 'project', 'supervisor') - filter_horizontal = ('workers',) + filter_horizontal = ('workers',) \ No newline at end of file diff --git a/core/migrations/0009_worker_date_of_employment_worker_id_photo_and_more.py b/core/migrations/0009_worker_date_of_employment_worker_id_photo_and_more.py new file mode 100644 index 0000000..055d561 --- /dev/null +++ b/core/migrations/0009_worker_date_of_employment_worker_id_photo_and_more.py @@ -0,0 +1,34 @@ +# Generated by Django 5.2.7 on 2026-02-04 14:11 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0008_alter_expensereceipt_payment_method_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='worker', + name='date_of_employment', + field=models.DateField(default=django.utils.timezone.now), + ), + migrations.AddField( + model_name='worker', + name='id_photo', + field=models.ImageField(blank=True, null=True, upload_to='workers/ids/', verbose_name='ID Document'), + ), + migrations.AddField( + model_name='worker', + name='notes', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='worker', + name='photo', + field=models.ImageField(blank=True, null=True, upload_to='workers/photos/'), + ), + ] diff --git a/core/migrations/__pycache__/0009_worker_date_of_employment_worker_id_photo_and_more.cpython-311.pyc b/core/migrations/__pycache__/0009_worker_date_of_employment_worker_id_photo_and_more.cpython-311.pyc new file mode 100644 index 0000000..1608208 Binary files /dev/null and b/core/migrations/__pycache__/0009_worker_date_of_employment_worker_id_photo_and_more.cpython-311.pyc differ diff --git a/core/models.py b/core/models.py index 69779cf..c43ef4b 100644 --- a/core/models.py +++ b/core/models.py @@ -27,6 +27,13 @@ class Worker(models.Model): id_no = models.CharField(max_length=50, unique=True, verbose_name="ID Number") phone_no = models.CharField(max_length=20, verbose_name="Phone Number") monthly_salary = models.DecimalField(max_digits=10, decimal_places=2, validators=[MinValueValidator(Decimal('0.00'))]) + + # New fields + photo = models.ImageField(upload_to='workers/photos/', blank=True, null=True) + id_photo = models.ImageField(upload_to='workers/ids/', blank=True, null=True, verbose_name="ID Document") + date_of_employment = models.DateField(default=timezone.now) + notes = models.TextField(blank=True) + created_at = models.DateTimeField(auto_now_add=True) is_active = models.BooleanField(default=True) @@ -34,6 +41,11 @@ class Worker(models.Model): def day_rate(self): return self.monthly_salary / Decimal('20.0') + @property + def projects_worked_on_count(self): + """Returns the number of distinct projects this worker has worked on.""" + return self.work_logs.values('project').distinct().count() + def __str__(self): return self.name diff --git a/core/templates/core/email/payslip_email.html b/core/templates/core/email/payslip_email.html new file mode 100644 index 0000000..48c203f --- /dev/null +++ b/core/templates/core/email/payslip_email.html @@ -0,0 +1,70 @@ + + +
+ + + +| Description | +Amount | +
|---|---|
| Base Pay ({{ logs_count }} days worked) | +R {{ logs_amount }} | +
| {{ adj.get_type_display }}: {{ adj.description }} | ++ R {{ adj.amount }} + | +
Net Pay: R {{ record.amount }}
+