diff --git a/osinaweb/core/__init__.py b/osinaweb/core/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/osinaweb/core/admin.py b/osinaweb/core/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/osinaweb/core/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/osinaweb/core/apps.py b/osinaweb/core/apps.py new file mode 100644 index 00000000..8115ae60 --- /dev/null +++ b/osinaweb/core/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CoreConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'core' diff --git a/osinaweb/core/migrations/__init__.py b/osinaweb/core/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/osinaweb/core/models.py b/osinaweb/core/models.py new file mode 100644 index 00000000..71a83623 --- /dev/null +++ b/osinaweb/core/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/osinaweb/core/tests.py b/osinaweb/core/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/osinaweb/core/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/osinaweb/core/views.py b/osinaweb/core/views.py new file mode 100644 index 00000000..b4af412e --- /dev/null +++ b/osinaweb/core/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render +from osinacore.models import * + diff --git a/osinaweb/osinacore/models.py b/osinaweb/osinacore/models.py index 2a646c10..d5f6abd4 100644 --- a/osinaweb/osinacore/models.py +++ b/osinaweb/osinacore/models.py @@ -12,22 +12,25 @@ from asgiref.sync import async_to_sync from channels.layers import get_channel_layer 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 @@ -44,9 +47,11 @@ class CustomerProfile(models.Model): ) 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) + 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 @@ -54,7 +59,7 @@ class CustomerProfile(models.Model): # 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 + self.customer_id = current_year + new_id # Add 'p' prefix super(CustomerProfile, self).save(*args, **kwargs) @property @@ -77,7 +82,6 @@ class CustomerProfile(models.Model): return f"last seen on {last_seen_time.strftime('%b %d at %I:%M %p')}" - class Business(models.Model): name = models.CharField(max_length=50) email = models.EmailField(unique=True) @@ -85,17 +89,18 @@ class Business(models.Model): vat = models.BooleanField(default=False) commercial_registration = models.CharField(max_length=50) phone_number = models.CharField(max_length=50) - website = models.URLField(null=True) + 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) + 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 @@ -106,36 +111,38 @@ class Business(models.Model): 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) 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 @@ -169,8 +176,6 @@ class StaffProfile(models.Model): def active(self): return self.staffposition_set.filter(end_date__isnull=True).exists() - - class StaffPosition(models.Model): staff = models.ForeignKey(StaffProfile, on_delete=models.CASCADE) @@ -182,9 +187,9 @@ class StaffPosition(models.Model): 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): @@ -198,9 +203,11 @@ class Project(models.Model): start_date = models.DateField() end_date = models.DateField(null=True, blank=True) active = models.BooleanField(default=True, null=True) - project_id = models.CharField(max_length=20, null=True, blank=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 @@ -210,8 +217,10 @@ class Project(models.Model): 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) @@ -229,6 +238,7 @@ class Project(models.Model): '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() @@ -236,8 +246,6 @@ class Project(models.Model): return Task.objects.filter(project=self, assigned_to=user.staffprofile).exclude(status='Closed').count() - - class ProjectStatus(models.Model): STATUS_CHOICES = ( ('In Progress', 'In Progress'), @@ -250,13 +258,11 @@ class ProjectStatus(models.Model): date = models.DateTimeField() - class PinnedProject(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) project = models.ForeignKey(Project, on_delete=models.CASCADE) - class Epic(models.Model): title = models.CharField(max_length=150) STATUS_CHOICES = ( @@ -268,22 +274,22 @@ class Epic(models.Model): 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 Milestone(models.Model): name = 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.name - class UserStory(models.Model): milestone = models.ForeignKey(Milestone, on_delete=models.SET_NULL, null=True) content = models.CharField(max_length=350) @@ -292,6 +298,7 @@ class UserStory(models.Model): added_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True) confirmed = models.BooleanField(default=True) completed = models.BooleanField(default=False) + def __str__(self): return self.content @@ -301,27 +308,25 @@ class ProjectFileAlbum(models.Model): project = models.ForeignKey(Project, on_delete=models.CASCADE, null=True) - class ProjectFile(models.Model): album = models.ForeignKey(ProjectFileAlbum, on_delete=models.CASCADE, null=True) file = models.FileField(null=True, upload_to='project_files') date_added = models.DateTimeField(null=True) - class ProjectCredential(models.Model): identifier = models.CharField(max_length=350) password = models.CharField(max_length=350) - description = models.TextField(null=True, blank=True) + description = models.TextField(null=True, blank=True) project = models.ForeignKey(Project, on_delete=models.CASCADE, null=True) date_added = models.DateTimeField(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) + 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) @@ -340,10 +345,11 @@ class Task(models.Model): 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) - userstory = models.ForeignKey(UserStory, on_delete=models.SET_NULL, null=True, blank=True) + assigned_to = models.ForeignKey(StaffProfile, on_delete=models.CASCADE, null=True) + userstory = models.ForeignKey(UserStory, on_delete=models.SET_NULL, null=True, blank=True) milestone = models.ForeignKey(Milestone, on_delete=models.SET_NULL, null=True, blank=True) - task_id = models.CharField(max_length=20, 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 @@ -374,8 +380,6 @@ class Task(models.Model): return total_time_hours, total_time_minutes, total_time_seconds - - class Point(models.Model): text = models.TextField(blank=True) STATUS_CHOICES = ( @@ -386,6 +390,7 @@ class Point(models.Model): ) 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(): @@ -397,12 +402,12 @@ class Point(models.Model): 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 = timezone.now() - self.start_time @@ -421,17 +426,19 @@ class PointActivity(models.Model): class Status(models.Model): - TYPE_CHOICES = ( + TYPE_CHOICES = ( ('Task', 'Task'), ('Daily Report', 'Daily Report'), ) text = models.TextField(blank=True) - staff = models.ForeignKey(StaffProfile, on_delete=models.CASCADE, null=True,blank=True, related_name='staff') - type = models.CharField(max_length=200, choices=TYPE_CHOICES, null=True, blank=True) + staff = models.ForeignKey(StaffProfile, on_delete=models.CASCADE, null=True, blank=True, related_name='staff') + type = models.CharField(max_length=200, choices=TYPE_CHOICES, null=True, blank=True) type_id = models.IntegerField(null=True, blank=True) date_time = models.DateTimeField(null=True, blank=True) + def __str__(self): return self.text + @property def time_ago(self): if not self.date_time: @@ -470,6 +477,7 @@ class Status(models.Model): return None return None + @receiver(post_save, sender=Status) def new_ticket_update_handler(sender, instance, created, **kwargs): if created: @@ -481,20 +489,17 @@ def new_ticket_update_handler(sender, instance, created, **kwargs): async_to_sync(channel_layer.group_send)("new_status_group", event) - 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') - + staff = models.ForeignKey(StaffProfile, on_delete=models.CASCADE, null=True, blank=True, related_name='dailyreport_staff') class Connection(models.Model): @@ -503,5 +508,3 @@ class Connection(models.Model): online = models.BooleanField(default=True) last_seen = models.DateTimeField(null=True, blank=True) disconnected = models.BooleanField(default=False) - -