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.CharField(max_length=200) def __str__(self): return self.name def formatted_date(self): # Assuming start_date is stored as "day-month-year" parts = self.date.split('-') return f"{parts[2]}-{parts[1]}-{parts[0]}" class Tag(models.Model): name = models.CharField(max_length=50) class BusinessType(models.Model): name = models.CharField(max_length=50) 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) type = models.ForeignKey(BusinessType, on_delete=models.CASCADE, null=True, blank=True) logo = models.ImageField() business_id = models.CharField(max_length=20, null=True, blank=True) # Allow null and blank for initial creation 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 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 = ( ('Active', 'Active'), ('Suspended', 'Suspended'), ('Terminated', 'Terminated'), ) status = models.CharField(max_length=200, choices=STATUS_CHOICES, blank=True) reference = models.ForeignKey(Reference, on_delete=models.CASCADE, null=True, blank=True) business = models.ForeignKey(Business, 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 StaffPosition(models.Model): name = models.CharField(max_length=100) def __str__(self): return self.name class StaffProfile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) image = models.ImageField(null=True, blank=True) mobile_number = models.CharField(max_length=50) staff_position = models.ForeignKey(StaffPosition, on_delete=models.CASCADE, null=True, blank=True) 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 ProjectType(models.Model): name = models.CharField(max_length=50) class Project(models.Model): name = models.CharField(max_length=50) 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') STATUS_CHOICES = ( ('Active', 'Active'), ('Completed', 'Completed'), ('Pending', 'Pending'), ('Cancelled', 'Cancelled'), ) status = models.CharField(max_length=200, choices=STATUS_CHOICES) start_date = models.CharField(max_length=200) end_date = models.CharField(max_length=200) project_id = models.CharField(max_length=20, null=True, blank=True) # Allow null and blank for initial creation 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) 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() 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) 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) class ProjectFile(models.Model): name = models.CharField(max_length=350) file = models.FileField(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') 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)