from django.db import models from django.core.validators import MinValueValidator from decimal import Decimal from django.contrib.auth.models import User from django.utils import timezone class UserProfile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile') pin = models.CharField(max_length=4, help_text="4-digit PIN for login") is_admin = models.BooleanField(default=False) def __str__(self): return f"{self.user.username}'s profile" class Project(models.Model): name = models.CharField(max_length=200) description = models.TextField(blank=True) supervisors = models.ManyToManyField(User, related_name='assigned_projects', blank=True) created_at = models.DateTimeField(auto_now_add=True) is_active = models.BooleanField(default=True) def __str__(self): return self.name class Worker(models.Model): name = models.CharField(max_length=200) 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'))]) created_at = models.DateTimeField(auto_now_add=True) is_active = models.BooleanField(default=True) @property def day_rate(self): return self.monthly_salary / Decimal('20.0') def __str__(self): return self.name class Team(models.Model): name = models.CharField(max_length=200) workers = models.ManyToManyField(Worker, related_name='teams') supervisor = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='managed_teams') created_at = models.DateTimeField(auto_now_add=True) is_active = models.BooleanField(default=True) def __str__(self): return self.name class WorkLog(models.Model): date = models.DateField() project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name='logs') workers = models.ManyToManyField(Worker, related_name='work_logs') supervisor = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True) notes = models.TextField(blank=True) def __str__(self): return f"{self.date} - {self.project.name}" class PayrollRecord(models.Model): worker = models.ForeignKey(Worker, on_delete=models.CASCADE, related_name='payroll_records') date = models.DateField(default=timezone.now) amount = models.DecimalField(max_digits=10, decimal_places=2) work_logs = models.ManyToManyField(WorkLog, related_name='paid_in') created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"Payment to {self.worker.name} on {self.date}" class Loan(models.Model): worker = models.ForeignKey(Worker, on_delete=models.CASCADE, related_name='loans') amount = models.DecimalField(max_digits=10, decimal_places=2, help_text="Principal amount borrowed") balance = models.DecimalField(max_digits=10, decimal_places=2, default=0, help_text="Remaining amount to be repaid") date = models.DateField(default=timezone.now) reason = models.TextField(blank=True) is_active = models.BooleanField(default=True) def save(self, *args, **kwargs): if not self.pk: # On creation self.balance = self.amount super().save(*args, **kwargs) def __str__(self): return f"Loan for {self.worker.name} - R{self.amount}" class PayrollAdjustment(models.Model): ADJUSTMENT_TYPES = [ ('BONUS', 'Bonus'), ('OVERTIME', 'Overtime'), ('DEDUCTION', 'Deduction'), ('LOAN_REPAYMENT', 'Loan Repayment'), ('LOAN', 'New Loan'), ] worker = models.ForeignKey(Worker, on_delete=models.CASCADE, related_name='adjustments') payroll_record = models.ForeignKey(PayrollRecord, on_delete=models.SET_NULL, null=True, blank=True, related_name='adjustments') loan = models.ForeignKey(Loan, on_delete=models.SET_NULL, null=True, blank=True, related_name='repayments') amount = models.DecimalField(max_digits=10, decimal_places=2, help_text="Positive adds to pay, negative subtracts (except for Loan Repayment which is auto-handled)") date = models.DateField(default=timezone.now) description = models.CharField(max_length=255) type = models.CharField(max_length=20, choices=ADJUSTMENT_TYPES, default='DEDUCTION') def __str__(self): return f"{self.get_type_display()} - {self.amount} for {self.worker.name}"