37680-vm/core/models.py
2026-01-22 08:34:23 +00:00

115 lines
4.8 KiB
Python

from django.db import models
from django.contrib.auth.models import User
from django.core.validators import MinLengthValidator
import uuid
from datetime import timedelta
from django.utils import timezone
class Company(models.Model):
name = models.CharField(max_length=255)
is_uprn_required = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Profile(models.Model):
ROLE_CHOICES = [
('ADMIN', 'Admin'),
('STANDARD', 'Standard User'),
]
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name='users', null=True, blank=True)
role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='STANDARD')
def __str__(self):
return f"{self.user.username} - {self.company.name if self.company else 'No Company'}"
class JobStatus(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name='statuses')
name = models.CharField(max_length=100)
is_starting_status = models.BooleanField(default=False)
order = models.PositiveIntegerField(default=0)
class Meta:
verbose_name_plural = "Job Statuses"
ordering = ['order']
def __str__(self):
return f"{self.name} ({self.company.name})"
class RequiredFolder(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name='required_folders')
name = models.CharField(max_length=100)
def __str__(self):
return f"{self.name} ({self.company.name})"
class Client(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name='clients')
name = models.CharField(max_length=255)
client_job_ref_prefix = models.CharField(max_length=50, blank=True, null=True)
class Meta:
unique_together = [['company', 'name']]
def __str__(self):
return self.name
class Job(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name='jobs')
client = models.ForeignKey(Client, on_delete=models.PROTECT, related_name='jobs', null=True, blank=True)
job_ref = models.CharField(max_length=100)
uprn = models.CharField(max_length=100, null=True, blank=True)
address_line_1 = models.CharField(max_length=255)
address_line_2 = models.CharField(max_length=255, null=True, blank=True)
address_line_3 = models.CharField(max_length=255, null=True, blank=True)
postcode = models.CharField(max_length=20)
description = models.TextField(null=True, blank=True)
action = models.TextField(null=True, blank=True)
notes = models.TextField(null=True, blank=True)
status = models.ForeignKey(JobStatus, on_delete=models.PROTECT, related_name='jobs')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
unique_together = [['company', 'job_ref'], ['company', 'uprn']]
# Add a custom constraint to allow null=True and blank=True for uprn,
# but still enforce unique_together when it's not null.
# This is handled by a custom validator or by overriding save method if needed.
# For now, Django's unique_together with null=True will allow multiple nulls.
def __str__(self):
return f"{self.job_ref} - {self.address_line_1}"
class JobFolderCompletion(models.Model):
job = models.ForeignKey(Job, on_delete=models.CASCADE, related_name='folder_completions')
folder = models.ForeignKey(RequiredFolder, on_delete=models.CASCADE)
is_completed = models.BooleanField(default=False)
class Meta:
unique_together = ['job', 'folder']
class JobFile(models.Model):
job = models.ForeignKey(Job, on_delete=models.CASCADE, related_name='files')
folder = models.ForeignKey(RequiredFolder, on_delete=models.CASCADE, related_name='files')
file = models.FileField(upload_to='job_files/')
uploaded_at = models.DateTimeField(auto_now_add=True)
uploaded_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
def __str__(self):
return f"{self.file.name} in {self.folder.name}"
class Invitation(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name='invitations')
invited_by = models.ForeignKey(User, on_delete=models.CASCADE)
email = models.EmailField(unique=True)
token = models.CharField(max_length=32, unique=True, default=uuid.uuid4().hex)
created_at = models.DateTimeField(auto_now_add=True)
expires_at = models.DateTimeField(default=timezone.now() + timedelta(days=7))
is_accepted = models.BooleanField(default=False)
def __str__(self):
return f"Invitation for {self.email} to {self.company.name}"