397 lines
10 KiB
Python
397 lines
10 KiB
Python
from django.conf import settings
|
|
from django.db import models
|
|
|
|
from access.models.team import Team
|
|
|
|
from core.models.ticket.ticket_enum_values import TicketValues
|
|
|
|
from .project_common import ProjectCommonFieldsName
|
|
from .project_states import ProjectState
|
|
from .project_types import ProjectType
|
|
|
|
|
|
class Project(ProjectCommonFieldsName):
|
|
|
|
|
|
class Meta:
|
|
|
|
ordering = [
|
|
'code',
|
|
'name',
|
|
]
|
|
|
|
permissions = [
|
|
('import_project', 'Can import a project'),
|
|
]
|
|
|
|
verbose_name = 'Project'
|
|
|
|
verbose_name_plural = 'Projects'
|
|
|
|
|
|
class Ticket_ExternalSystem(models.IntegerChoices): # <null|github|gitlab>
|
|
GITHUB = TicketValues.ExternalSystem._GITHUB_INT, TicketValues.ExternalSystem._GITHUB_VALUE
|
|
GITLAB = TicketValues.ExternalSystem._GITLAB_INT, TicketValues.ExternalSystem._GITLAB_VALUE
|
|
|
|
CUSTOM_1 = TicketValues.ExternalSystem._CUSTOM_1_INT, TicketValues.ExternalSystem._CUSTOM_1_VALUE
|
|
CUSTOM_2 = TicketValues.ExternalSystem._CUSTOM_2_INT, TicketValues.ExternalSystem._CUSTOM_2_VALUE
|
|
CUSTOM_3 = TicketValues.ExternalSystem._CUSTOM_3_INT, TicketValues.ExternalSystem._CUSTOM_3_VALUE
|
|
CUSTOM_4 = TicketValues.ExternalSystem._CUSTOM_4_INT, TicketValues.ExternalSystem._CUSTOM_4_VALUE
|
|
CUSTOM_5 = TicketValues.ExternalSystem._CUSTOM_5_INT, TicketValues.ExternalSystem._CUSTOM_5_VALUE
|
|
CUSTOM_6 = TicketValues.ExternalSystem._CUSTOM_6_INT, TicketValues.ExternalSystem._CUSTOM_6_VALUE
|
|
CUSTOM_7 = TicketValues.ExternalSystem._CUSTOM_7_INT, TicketValues.ExternalSystem._CUSTOM_7_VALUE
|
|
CUSTOM_8 = TicketValues.ExternalSystem._CUSTOM_8_INT, TicketValues.ExternalSystem._CUSTOM_8_VALUE
|
|
CUSTOM_9 = TicketValues.ExternalSystem._CUSTOM_9_INT, TicketValues.ExternalSystem._CUSTOM_9_VALUE
|
|
|
|
|
|
|
|
class Priority(models.IntegerChoices):
|
|
VERY_LOW = TicketValues.Priority._VERY_LOW_INT, TicketValues.Priority._VERY_LOW_VALUE
|
|
LOW = TicketValues.Priority._LOW_INT, TicketValues.Priority._LOW_VALUE
|
|
MEDIUM = TicketValues.Priority._MEDIUM_INT, TicketValues.Priority._MEDIUM_VALUE
|
|
HIGH = TicketValues.Priority._HIGH_INT, TicketValues.Priority._HIGH_VALUE
|
|
VERY_HIGH = TicketValues.Priority._VERY_HIGH_INT, TicketValues.Priority._VERY_HIGH_VALUE
|
|
MAJOR = TicketValues.Priority._MAJOR_INT, TicketValues.Priority._MAJOR_VALUE
|
|
|
|
|
|
# class ProjectStates(enum):
|
|
# OPEN = 1
|
|
# CLOSED = 1
|
|
|
|
external_ref = models.IntegerField(
|
|
blank = True,
|
|
default=None,
|
|
help_text = 'External System reference',
|
|
null=True,
|
|
verbose_name = 'Reference Number',
|
|
) # external reference or null. i.e. github issue number
|
|
|
|
|
|
external_system = models.IntegerField(
|
|
blank = True,
|
|
choices=Ticket_ExternalSystem,
|
|
default=None,
|
|
help_text = 'External system this item derives',
|
|
null=True,
|
|
verbose_name = 'External System',
|
|
)
|
|
|
|
|
|
description = models.TextField(
|
|
blank = True,
|
|
help_text = 'Outline of this Project',
|
|
default = None,
|
|
null= True,
|
|
verbose_name = 'Description'
|
|
)
|
|
|
|
priority = models.IntegerField(
|
|
blank = False,
|
|
choices =Priority,
|
|
default = Priority.LOW,
|
|
help_text = 'Priority of the project',
|
|
null = True,
|
|
verbose_name ='Priority'
|
|
)
|
|
|
|
state = models.ForeignKey(
|
|
ProjectState,
|
|
blank= True,
|
|
help_text = 'State of the project',
|
|
on_delete=models.SET_NULL,
|
|
null = True,
|
|
verbose_name ='Project State'
|
|
)
|
|
|
|
|
|
project_type = models.ForeignKey(
|
|
ProjectType,
|
|
blank= True,
|
|
help_text = 'Type of project',
|
|
on_delete=models.SET_NULL,
|
|
null = True,
|
|
verbose_name ='Project Type'
|
|
)
|
|
|
|
code = models.CharField(
|
|
blank = True,
|
|
help_text = 'Project Code',
|
|
max_length = 25,
|
|
null = True,
|
|
unique = True,
|
|
verbose_name = 'Project Code',
|
|
)
|
|
|
|
planned_start_date = models.DateTimeField(
|
|
blank = True,
|
|
help_text = 'When the project is planned to have been started by.',
|
|
null = True,
|
|
verbose_name = 'Planned Start Date',
|
|
)
|
|
|
|
planned_finish_date = models.DateTimeField(
|
|
blank = True,
|
|
help_text = 'When the project is planned to be finished by.',
|
|
null = True,
|
|
verbose_name = 'Planned Finish Date',
|
|
)
|
|
|
|
real_start_date = models.DateTimeField(
|
|
blank = True,
|
|
help_text = 'When work commenced on the project.',
|
|
null = True,
|
|
verbose_name = 'Real Start Date',
|
|
)
|
|
|
|
real_finish_date = models.DateTimeField(
|
|
blank = True,
|
|
help_text = 'When work was completed for the project',
|
|
null = True,
|
|
verbose_name = 'Real Finish Date',
|
|
)
|
|
|
|
manager_user = models.ForeignKey(
|
|
settings.AUTH_USER_MODEL,
|
|
blank= True,
|
|
help_text = 'User who is the Project Manager',
|
|
on_delete=models.SET_NULL,
|
|
null = True,
|
|
related_name = 'manager_user',
|
|
verbose_name = 'Manager'
|
|
)
|
|
|
|
manager_team = models.ForeignKey(
|
|
Team,
|
|
blank= True,
|
|
help_text = 'Team which contains the Project Managers',
|
|
on_delete=models.SET_NULL,
|
|
null = True,
|
|
verbose_name = 'Project Manager Team'
|
|
)
|
|
|
|
model_notes = None
|
|
|
|
team_members = models.ManyToManyField(
|
|
to = settings.AUTH_USER_MODEL,
|
|
blank = True,
|
|
)
|
|
|
|
is_deleted = models.BooleanField(
|
|
blank = False,
|
|
default = False,
|
|
help_text = 'Is this project considered deleted',
|
|
null = False,
|
|
verbose_name = 'Deleted',
|
|
)
|
|
|
|
|
|
page_layout: dict = [
|
|
{
|
|
"name": "Details",
|
|
"slug": "details",
|
|
"sections": [
|
|
{
|
|
"name": "Status",
|
|
"layout": "double",
|
|
"left": [
|
|
'state',
|
|
'completed',
|
|
'priority',
|
|
],
|
|
"right": [
|
|
'estimation_project',
|
|
'duration_project',
|
|
]
|
|
},
|
|
{
|
|
"name": "Details",
|
|
"layout": "double",
|
|
"left": [
|
|
'organization',
|
|
'code',
|
|
'name',
|
|
'project_type',
|
|
],
|
|
"right": [
|
|
'planned_start_date',
|
|
'planned_finish_date',
|
|
'real_start_date',
|
|
'real_finish_date',
|
|
'duration_project'
|
|
'created',
|
|
'modified',
|
|
]
|
|
},
|
|
{
|
|
"layout": "double",
|
|
"left": [
|
|
'manager_user',
|
|
],
|
|
"right": [
|
|
'manager_team',
|
|
]
|
|
},
|
|
{
|
|
"layout": "single",
|
|
"fields": [
|
|
'description'
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"name": "Tasks",
|
|
"slug": "ticket",
|
|
"sections": [
|
|
{
|
|
"layout": "table",
|
|
"field": "tickets",
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"name": "Milestones",
|
|
"slug": "milestone",
|
|
"sections": [
|
|
{
|
|
"layout": "table",
|
|
"field": "milestone",
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"name": "Knowledge Base",
|
|
"slug": "kb_articles",
|
|
"sections": [
|
|
{
|
|
"layout": "table",
|
|
"field": "knowledge_base",
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"name": "Notes",
|
|
"slug": "notes",
|
|
"sections": []
|
|
},
|
|
]
|
|
|
|
|
|
table_fields: list = [
|
|
'code',
|
|
'name',
|
|
'project_type'
|
|
'state',
|
|
'organization',
|
|
'modified'
|
|
]
|
|
|
|
|
|
fields_all: list = []
|
|
|
|
fields_import: list = []
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.name
|
|
|
|
|
|
@property
|
|
def duration_project(self) -> int:
|
|
|
|
duration_project: int = 0
|
|
|
|
from core.models.ticket.ticket import Ticket
|
|
|
|
tickets = Ticket.objects.filter(
|
|
project = self.id
|
|
)
|
|
|
|
for ticket in tickets:
|
|
|
|
duration_project = duration_project + int(ticket.duration_ticket)
|
|
|
|
|
|
return int(duration_project)
|
|
|
|
|
|
@property
|
|
def estimation_project(self) -> int:
|
|
|
|
estimation_project: int = 0
|
|
|
|
from core.models.ticket.ticket import Ticket
|
|
|
|
tickets = Ticket.objects.filter(
|
|
project = self.id
|
|
)
|
|
|
|
for ticket in tickets:
|
|
|
|
estimation = ticket.estimate
|
|
|
|
if ticket.estimate is None:
|
|
|
|
estimation = 0
|
|
|
|
|
|
estimation_project = estimation_project + int(estimation)
|
|
|
|
|
|
return int(estimation_project)
|
|
|
|
|
|
@property
|
|
def percent_completed(self) -> str: # Auto-Calculate
|
|
""" How much of the project is completed.
|
|
|
|
Returns:
|
|
str: Calculated percentage of project completion.
|
|
"""
|
|
|
|
from core.models.ticket.ticket import Ticket
|
|
|
|
ticket_status_closed = [
|
|
TicketValues._CANCELLED_INT,
|
|
TicketValues._CLOSED_INT,
|
|
TicketValues._SOLVED_INT,
|
|
]
|
|
|
|
all_tickets = Ticket.objects.filter(
|
|
project = self.id,
|
|
)
|
|
|
|
closed_tickets = Ticket.objects.filter(
|
|
project = self.id,
|
|
status__in = ticket_status_closed
|
|
)
|
|
|
|
calculation: int = 0
|
|
|
|
if len(all_tickets) > 0:
|
|
|
|
if len(closed_tickets) > 0:
|
|
|
|
calculation: int = int(
|
|
(
|
|
len(closed_tickets) / len(all_tickets)
|
|
) * 100
|
|
)
|
|
|
|
return str(calculation) + '%'
|
|
|
|
def save_history(self, before: dict, after: dict) -> bool:
|
|
|
|
from project_management.models.project_history import ProjectAuditHistory
|
|
|
|
history = super().save_history(
|
|
before = before,
|
|
after = after,
|
|
history_model = ProjectAuditHistory,
|
|
)
|
|
|
|
|
|
return history
|