from django.db import models from django.contrib.auth.models import User from colorfield.fields import ColorField from datetime import datetime from django.db.models import Max from django.utils import timezone from django.db.models import Sum, F from datetime import timedelta # Create your models here. class Reference(models.Model): name = models.CharField(max_length=50) date = models.DateField() def __str__(self): return self.name class Tag(models.Model): name = models.CharField(max_length=50) def __str__(self): return self.name class BusinessType(models.Model): name = models.CharField(max_length=50) def __str__(self): return self.name class CustomerProfile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, blank=True) mobile_number = models.CharField(max_length=50, blank=True) personal_website = models.URLField(null=True, blank=True) STATUS_CHOICES = ( ('Pending', 'Pending'), ('Active', 'Active'), ('Suspended', 'Suspended'), ('Terminated', 'Terminated'), ) status = models.CharField(max_length=200, choices=STATUS_CHOICES, default='Active', blank=True) reference = models.ForeignKey(Reference, on_delete=models.CASCADE, null=True, blank=True) customer_id = models.CharField(max_length=20, null=True, blank=True) def __str__(self): return self.user.username def save(self, *args, **kwargs): if not self.customer_id: # Get the last two digits of the current year current_year = str(datetime.now().year)[-2:] # Find the maximum project ID in the database and increment it max_id = CustomerProfile.objects.aggregate(models.Max('customer_id'))['customer_id__max'] new_id = str(int(max_id[-4:]) + 1).zfill(4) if max_id else '0001' # If no existing records, start with '0001' self.customer_id = current_year + new_id # Add 'p' prefix super(CustomerProfile, self).save(*args, **kwargs) class Business(models.Model): name = models.CharField(max_length=50) email = models.EmailField(unique=True) financial_number = models.CharField(max_length=50) vat = models.BooleanField(default=False) commercial_registration = models.CharField(max_length=50) phone_number = models.CharField(max_length=50) website = models.URLField(null=True) customer = models.ForeignKey(CustomerProfile, on_delete=models.CASCADE, null=True, blank=True) type = models.ForeignKey(BusinessType, on_delete=models.CASCADE, null=True, blank=True) logo = models.ImageField(upload_to='uploaded_images') business_id = models.CharField(max_length=20, null=True, blank=True) def __str__(self): return self.name class Meta: verbose_name_plural = u'Businesses' def __str__(self): return self.name def save(self, *args, **kwargs): if not self.business_id: # Get the last two digits of the current year current_year = str(datetime.now().year)[-2:] # Find the maximum project ID in the database and increment it max_id = Business.objects.aggregate(models.Max('business_id'))['business_id__max'] new_id = str(int(max_id[-4:]) + 1).zfill(4) if max_id else '0001' # If no existing records, start with '0001' self.business_id = 'B' + current_year + new_id # Add 'p' prefix super(Business, self).save(*args, **kwargs) class Department(models.Model): name = models.CharField(max_length=100) def __str__(self): return self.name def get_staff(self): # Retrieve all staff profiles associated with positions in this department staff_profiles = StaffProfile.objects.filter(staffposition__position__department=self) return staff_profiles class JobPosition(models.Model): name = models.CharField(max_length=100) department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True) def __str__(self): return self.name class StaffProfile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) image = models.ImageField(upload_to='uploaded_images', null=True, blank=True) mobile_number = models.CharField(max_length=50) intern = models.BooleanField(default=False) active = models.BooleanField(default=True) staff_id = models.CharField(max_length=20, null=True, blank=True) # Allow null and blank for initial creation def __str__(self): return self.user.username def save(self, *args, **kwargs): if not self.staff_id: # Get the last two digits of the current year current_year = str(datetime.now().year)[-2:] # Find the maximum project ID in the database and increment it max_id = StaffProfile.objects.aggregate(models.Max('staff_id'))['staff_id__max'] new_id = str(int(max_id[-4:]) + 1).zfill(4) if max_id else '0001' # If no existing records, start with '0001' self.staff_id = 'O' + current_year + new_id # Add 'p' prefix super(StaffProfile, self).save(*args, **kwargs) class StaffPosition(models.Model): staff = models.ForeignKey(StaffProfile, on_delete=models.CASCADE) position = models.ForeignKey(JobPosition, null=True, on_delete=models.SET_NULL) start_date = models.DateField() end_date = models.DateField(null=True, blank=True) class ProjectType(models.Model): name = models.CharField(max_length=50) department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True) def __str__(self): return self.name class Project(models.Model): name = models.CharField(max_length=50) logo = models.ImageField(null=True, blank=True) customer = models.ForeignKey(CustomerProfile, on_delete=models.CASCADE, null=True) manager = models.ForeignKey(StaffProfile, on_delete=models.CASCADE, null=True) project_type = models.ManyToManyField('ProjectType', default='', related_name='manager_project') details = models.TextField() members = models.ManyToManyField('StaffProfile', default='', related_name='members_project') start_date = models.DateField() end_date = models.DateField() active = models.BooleanField(default=True, null=True) project_id = models.CharField(max_length=20, null=True, blank=True) def __str__(self): return self.name def save(self, *args, **kwargs): if not self.project_id: # Get the last two digits of the current year current_year = str(datetime.now().year)[-2:] # Find the maximum project ID in the database and increment it max_id = Project.objects.aggregate(models.Max('project_id'))['project_id__max'] new_id = str(int(max_id[-4:]) + 1).zfill(4) if max_id else '0001' # If no existing records, start with '0001' self.project_id = 'P' + current_year + new_id # Add 'p' prefix super(Project, self).save(*args, **kwargs) def is_pinned(self, user): return PinnedProject.objects.filter(user=user, project=self).exists() def total_time_worked(self, user): total_time_seconds = 0 tasks = self.task_set.all() if user.is_superuser else self.task_set.filter(assigned_to=user.staffprofile) for task in tasks: total_time_hours, total_time_minutes, total_time_seconds_task = task.total_task_time() total_time_seconds += (total_time_hours * 3600) + (total_time_minutes * 60) + total_time_seconds_task total_time_hours = total_time_seconds // 3600 total_time_minutes = (total_time_seconds % 3600) // 60 total_time_seconds = total_time_seconds % 60 return { 'hours': total_time_hours, 'minutes': total_time_minutes, 'seconds': total_time_seconds } def open_tasks_count(self, user): if user.is_superuser: return Task.objects.filter(project=self).exclude(status='Closed').count() else: return Task.objects.filter(project=self, assigned_to=user.staffprofile).exclude(status='Closed').count() class ProjectStatus(models.Model): STATUS_CHOICES = ( ('In Progress', 'In Progress'), ('Completed', 'Completed'), ('Pending', 'Pending'), ('Cancelled', 'Cancelled'), ) project = models.ForeignKey(Project, on_delete=models.CASCADE) status = models.CharField(max_length=200, choices=STATUS_CHOICES) date = models.DateTimeField() class PinnedProject(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) project = models.ForeignKey(Project, on_delete=models.CASCADE) class PinnedProject(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) project = models.ForeignKey(Project, on_delete=models.CASCADE) class Milestone(models.Model): title = models.CharField(max_length=150) description = models.TextField() project = models.ForeignKey(Project, on_delete=models.CASCADE, null=True) start_date = models.DateField() end_date = models.DateField() def __str__(self): return self.title class Epic(models.Model): title = models.CharField(max_length=150) STATUS_CHOICES = ( ('Open', 'Open'), ('Closed', 'Closed') ) status = models.CharField(max_length=200, choices=STATUS_CHOICES, null=True) description = models.TextField() project = models.ForeignKey(Project, on_delete=models.CASCADE, null=True) start_date = models.CharField(max_length=200) end_date = models.CharField(max_length=200) def __str__(self): return self.title class ProjectRequirement(models.Model): content = models.CharField(max_length=350) project = models.ForeignKey(Project, on_delete=models.CASCADE, null=True) date = models.DateField(null=True, auto_now=True) added_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True) def __str__(self): return self.content class ProjectFile(models.Model): name = models.CharField(max_length=350) file = models.FileField(upload_to='uploaded_images', blank=True) date = models.DateField() project = models.ForeignKey(Project, on_delete=models.CASCADE, null=True) class ProjectCredential(models.Model): emailorusername = models.CharField(max_length=350) password = models.CharField(max_length=350) usedfor = models.CharField(max_length=350) project = models.ForeignKey(Project, on_delete=models.CASCADE, null=True) class Note(models.Model): text = models.TextField(blank=True) date = models.DateTimeField(null=True,blank=True) user = models.ForeignKey(User, on_delete=models.CASCADE, null=True,blank=True) color = ColorField(default='#FF0000',blank=True) project = models.ForeignKey(Project, on_delete=models.CASCADE, null=True, blank=True) class Task(models.Model): name = models.CharField(max_length=250) project = models.ForeignKey(Project, on_delete=models.CASCADE, null=True) epic = models.ForeignKey(Epic, on_delete=models.CASCADE, null=True) STATUS_CHOICES = ( ('Open', 'Open'), ('Working On', 'Working On'), ('Closed', 'Closed') ) status = models.CharField(max_length=200, choices=STATUS_CHOICES, null=True) status_date = models.DateTimeField(default=timezone.now) extra = models.BooleanField(default=False) description = models.TextField() start_date = models.DateField(null=True) end_date = models.DateField(null=True) assigned_to = models.ForeignKey(StaffProfile, on_delete=models.CASCADE, null=True) requirement = models.ForeignKey(ProjectRequirement, on_delete=models.SET_NULL, null=True, blank=True) task_id = models.CharField(max_length=20, null=True, blank=True) def save(self, *args, **kwargs): if not self.task_id: # Get the last two digits of the current year current_year = str(datetime.now().year)[-2:] # Find the maximum project ID in the database and increment it max_id = Task.objects.aggregate(models.Max('task_id'))['task_id__max'] new_id = str(int(max_id[-4:]) + 1).zfill(4) if max_id else '0001' # If no existing records, start with '0001' self.task_id = 'T' + current_year + new_id # Add 'p' prefix if self.pk is not None: original_task = Task.objects.get(pk=self.pk) if original_task.status != self.status: self.status_date = timezone.now() super(Task, self).save(*args, **kwargs) def total_task_time(self): total_time_seconds = 0 for point in self.point_set.all(): if point: point_hours, point_minutes, point_seconds = point.total_activity_time() total_time_seconds += (point_hours * 3600) + (point_minutes * 60) + point_seconds total_time_hours = total_time_seconds // 3600 total_time_minutes = (total_time_seconds % 3600) // 60 total_time_seconds = total_time_seconds % 60 return total_time_hours, total_time_minutes, total_time_seconds class Point(models.Model): text = models.TextField(blank=True) STATUS_CHOICES = ( ('Not Completed', 'Not Completed'), ('Working On', 'Working On'), ('Paused', 'Paused'), ('Completed', 'Completed') ) status = models.CharField(max_length=200, choices=STATUS_CHOICES, null=True) task = models.ForeignKey(Task, on_delete=models.CASCADE, null=True) def total_activity_time(self): total_time_seconds = 0 for activity in self.pointactivity_set.all(): if activity.total_time: total_time_seconds += activity.total_time.total_seconds() total_time_hours = int(total_time_seconds // 3600) total_time_minutes = int((total_time_seconds % 3600) // 60) total_time_seconds = int(total_time_seconds % 60) return total_time_hours, total_time_minutes, total_time_seconds class PointActivity(models.Model): point = models.ForeignKey(Point, on_delete=models.CASCADE, null=True) start_time = models.DateTimeField() end_time = models.DateTimeField(null=True, blank=True) total_time = models.DurationField(null=True, blank=True) def save(self, *args, **kwargs): if self.start_time and not self.end_time: self.total_time = datetime.now() - self.start_time elif self.start_time and self.end_time: self.total_time = self.end_time - self.start_time super(PointActivity, self).save(*args, **kwargs) def total_time_in_hours_minutes_seconds(self): if self.total_time: total_seconds = self.total_time.total_seconds() hours = int(total_seconds // 3600) minutes = int((total_seconds % 3600) // 60) seconds = int(total_seconds % 60) return hours, minutes, seconds return 0, 0, 0 class Status(models.Model): text = models.TextField(blank=True) date = models.CharField(max_length=40) time = models.CharField(max_length=40) staff = models.ForeignKey(StaffProfile, on_delete=models.CASCADE, null=True,blank=True, related_name='staff') task = models.ForeignKey(Task, on_delete=models.SET_NULL ,null=True, blank=True, related_name='reference_task') def __str__(self): return self.text class Reaction(models.Model): status = models.ForeignKey(Status, on_delete=models.CASCADE) emoji = models.CharField(max_length=15) user = models.ForeignKey(User, on_delete=models.CASCADE) class DailyReport(models.Model): text = models.TextField(blank=True) date = models.CharField(max_length=40) time = models.CharField(max_length=40) staff = models.ForeignKey(StaffProfile, on_delete=models.CASCADE, null=True,blank=True, related_name='dailyreport_staff') class Connection(models.Model): STATUS_CHOICES = ( ('Online', 'Online'), ('Offline', 'Offline'), ) status = models.CharField(max_length=200, choices=STATUS_CHOICES, null=True) date = models.DateTimeField(null=True) user = models.ForeignKey(User, on_delete=models.CASCADE)