Add PPE sizing and drivers license fields to Worker model

New fields: shoe_size, overall_top_size, pants_size, tshirt_size,
has_drivers_license (boolean), drivers_license (file upload).
Admin organised into 3 fieldsets. CSV export updated with new columns.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Konrad du Plessis 2026-04-20 13:10:46 +02:00
parent 803f8696e7
commit 81009be0c6
5 changed files with 80 additions and 3 deletions

View File

@ -37,7 +37,7 @@ staticfiles/ — Collected static assets (Bootstrap, admin)
## Key Models
- **UserProfile** — extends Django User (OneToOne); minimal, no extra fields in v5
- **Project** — work sites with supervisor assignments (M2M User), start/end dates, active flag
- **Worker** — profiles with salary, `daily_rate` property (monthly_salary / 20), photo, ID doc
- **Worker** — profiles with salary, `daily_rate` property (monthly_salary / 20), photo, ID doc, PPE sizing (shoe, overall top, pants, tshirt), drivers license (boolean + file upload)
- **Team** — groups of workers under a supervisor, with optional pay schedule (`pay_frequency`: weekly/fortnightly/monthly, `pay_start_date`: anchor date)
- **WorkLog** — daily attendance: date, project, team, workers (M2M), supervisor, overtime, `priced_workers` (M2M)
- **PayrollRecord** — completed payments linked to WorkLogs (M2M) and Worker (FK)

View File

@ -20,9 +20,24 @@ class ProjectAdmin(admin.ModelAdmin):
@admin.register(Worker)
class WorkerAdmin(admin.ModelAdmin):
list_display = ('name', 'id_number', 'monthly_salary', 'active')
list_filter = ('active',)
list_filter = ('active', 'has_drivers_license')
search_fields = ('name', 'id_number', 'phone_number')
# === FIELDSETS ===
# Organise the worker edit form into clear sections
fieldsets = (
('Personal Info', {
'fields': ('name', 'id_number', 'phone_number', 'monthly_salary',
'employment_date', 'active', 'notes'),
}),
('Sizing', {
'fields': ('shoe_size', 'overall_top_size', 'pants_size', 'tshirt_size'),
}),
('Documents & License', {
'fields': ('photo', 'id_document', 'has_drivers_license', 'drivers_license'),
}),
)
@admin.register(Team)
class TeamAdmin(admin.ModelAdmin):
list_display = ('name', 'supervisor', 'pay_frequency', 'pay_start_date', 'active')

View File

@ -0,0 +1,43 @@
# Generated by Django 5.2.7 on 2026-04-20 10:48
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0005_team_pay_frequency_team_pay_start_date'),
]
operations = [
migrations.AddField(
model_name='worker',
name='drivers_license',
field=models.FileField(blank=True, null=True, upload_to='workers/documents/'),
),
migrations.AddField(
model_name='worker',
name='has_drivers_license',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='worker',
name='overall_top_size',
field=models.CharField(blank=True, max_length=10),
),
migrations.AddField(
model_name='worker',
name='pants_size',
field=models.CharField(blank=True, max_length=20),
),
migrations.AddField(
model_name='worker',
name='shoe_size',
field=models.CharField(blank=True, max_length=20),
),
migrations.AddField(
model_name='worker',
name='tshirt_size',
field=models.CharField(blank=True, max_length=10),
),
]

View File

@ -44,6 +44,18 @@ class Worker(models.Model):
notes = models.TextField(blank=True)
active = models.BooleanField(default=True)
# === SIZING ===
# Clothing and boot sizes for PPE (personal protective equipment) ordering
shoe_size = models.CharField(max_length=20, blank=True)
overall_top_size = models.CharField(max_length=10, blank=True)
pants_size = models.CharField(max_length=20, blank=True)
tshirt_size = models.CharField(max_length=10, blank=True)
# === DRIVERS LICENSE ===
# Track which workers have a valid drivers license and store a scanned copy
has_drivers_license = models.BooleanField(default=False)
drivers_license = models.FileField(upload_to='workers/documents/', blank=True, null=True)
@property
def daily_rate(self):
# monthly salary divided by 20 working days

View File

@ -769,7 +769,9 @@ def export_workers_csv(request):
writer = csv.writer(response)
writer.writerow([
'Name', 'ID Number', 'Phone Number', 'Monthly Salary',
'Daily Rate', 'Employment Date', 'Active', 'Notes'
'Daily Rate', 'Employment Date', 'Active', 'Notes',
'Shoe Size', 'Overall Top Size', 'Pants Size', 'T-Shirt Size',
'Has Drivers License',
])
for w in workers:
@ -782,6 +784,11 @@ def export_workers_csv(request):
w.employment_date.strftime('%Y-%m-%d') if w.employment_date else '',
'Yes' if w.active else 'No',
w.notes,
w.shoe_size,
w.overall_top_size,
w.pants_size,
w.tshirt_size,
'Yes' if w.has_drivers_license else 'No',
])
return response