Skip to content
This repository has been archived by the owner on May 13, 2024. It is now read-only.

Commit

Permalink
chore(models): add type annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
c0rydoras committed Apr 29, 2024
1 parent 61a12c1 commit 6b1c0a2
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 28 deletions.
48 changes: 25 additions & 23 deletions timed/employment/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
"""Models for the employment app."""

from __future__ import annotations

from datetime import date, timedelta
from typing import TYPE_CHECKING

from dateutil import rrule
from django.conf import settings
Expand All @@ -12,7 +15,10 @@

from timed.models import WeekdaysField
from timed.projects.models import CustomerAssignee, ProjectAssignee, TaskAssignee
from timed.tracking.models import Absence
from timed.tracking.models import Absence, Report

if TYPE_CHECKING:
from django.db.models import QuerySet


class Location(models.Model):
Expand Down Expand Up @@ -76,7 +82,7 @@ def __str__(self) -> str:
"""Represent the model as a string."""
return self.name

def calculate_credit(self, user, start, end):
def calculate_credit(self, user: User, start: date, end: date) -> int | None:
"""Calculate approved days of type for user in given time frame.
For absence types which fill worktime this will be None.
Expand All @@ -90,7 +96,7 @@ def calculate_credit(self, user, start, end):
data = credits.aggregate(credit=Sum("days"))
return data["credit"] or 0

def calculate_used_days(self, user, start, end):
def calculate_used_days(self, user: User, start: date, end: date) -> int | None:
"""Calculate used days of type for user in given time frame.
For absence types which fill worktime this will be None.
Expand Down Expand Up @@ -157,7 +163,7 @@ def __str__(self) -> str:
class EmploymentManager(models.Manager):
"""Custom manager for employments."""

def get_at(self, user, date):
def get_at(self, user: User, date: date) -> Employment:
"""Get employment of user at given date.
:param User user: The user of the searched employments
Expand All @@ -170,7 +176,7 @@ def get_at(self, user, date):
user=user,
)

def for_user(self, user, start, end):
def for_user(self, user: User, start: date, end: date) -> QuerySet[Employment]:
"""Get employments in given time frame for current user.
This includes overlapping employments.
Expand Down Expand Up @@ -228,7 +234,9 @@ def __str__(self) -> str:
self.end_date.strftime("%d.%m.%Y") if self.end_date else "today",
)

def calculate_worktime(self, start, end):
def calculate_worktime(
self, start: date, end: date
) -> tuple[timedelta, timedelta, timedelta]:
"""Calculate reported, expected and balance for employment.
1. It shortens the time frame so it is within given employment
Expand All @@ -245,13 +253,8 @@ def calculate_worktime(self, start, end):
7. The balance is the reported time plus the absences plus the
overtime credit minus the expected worktime
:param start: calculate worktime starting on given day.
:param end: calculate worktime till given day
:returns: tuple of 3 values reported, expected and delta in given
time frame
Return a tuple with 3 timedeltas of reported, expected and the given delta.
"""
from timed.tracking.models import Absence, Report

# shorten time frame to employment
start = max(start, self.start_date)
end = min(self.end_date or date.today(), end)
Expand Down Expand Up @@ -303,13 +306,13 @@ def calculate_worktime(self, start, end):


class UserManager(UserManager):
def all_supervisors(self):
def all_supervisors(self) -> QuerySet[User]:
objects = self.model.objects.annotate(
supervisees_count=models.Count("supervisees")
)
return objects.filter(supervisees_count__gt=0)

def all_reviewers(self):
def all_reviewers(self) -> QuerySet[User]:
return self.all().filter(
models.Q(
pk__in=TaskAssignee.objects.filter(is_reviewer=True).values("user")
Expand All @@ -322,7 +325,7 @@ def all_reviewers(self):
)
)

def all_supervisees(self):
def all_supervisees(self) -> QuerySet[User]:
objects = self.model.objects.annotate(
supervisors_count=models.Count("supervisors")
)
Expand Down Expand Up @@ -352,28 +355,27 @@ class User(AbstractUser):
objects = UserManager()

@property
def is_reviewer(self):
def is_reviewer(self) -> bool:
return (
TaskAssignee.objects.filter(user=self, is_reviewer=True).exists()
or ProjectAssignee.objects.filter(user=self, is_reviewer=True).exists()
or CustomerAssignee.objects.filter(user=self, is_reviewer=True).exists()
)

@property
def user_id(self):
def user_id(self) -> int:
"""Map to id to be able to use generic permissions."""
return self.id

def calculate_worktime(self, start, end):
def calculate_worktime(
self, start: date, end: date
) -> tuple[timedelta, timedelta, timedelta]:
"""Calculate reported, expected and balance for user.
This calculates summarizes worktime for all employments of users which
are in given time frame.
:param start: calculate worktime starting on given day.
:param end: calculate worktime till given day
:returns: tuple of 3 values reported, expected and delta in given
time frame
Return a tuple with 3 timedeltas of reported, expected and balance.
"""
employments = Employment.objects.for_user(self, start, end).select_related(
"location"
Expand All @@ -389,7 +391,7 @@ def calculate_worktime(self, start, end):

return (reported, expected, balance)

def get_active_employment(self):
def get_active_employment(self) -> Employment | None:
"""Get current employment of the user.
Get current active employment of the user.
Expand Down
7 changes: 4 additions & 3 deletions timed/projects/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class Meta:

ordering = ("name",)

def __str__(self):
def __str__(self) -> str:
"""Represent the model as a string."""
return self.name

Expand All @@ -50,7 +50,8 @@ class CostCenter(models.Model):
class Meta:
ordering = ("name",)

def __str__(self):
def __str__(self) -> str:
"""Represent the model as a string."""
return self.name


Expand All @@ -63,7 +64,7 @@ class BillingType(models.Model):
class Meta:
ordering = ("name",)

def __str__(self):
def __str__(self) -> str:
"""Represent the model as a string."""
return self.name

Expand Down
10 changes: 8 additions & 2 deletions timed/tracking/models.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
"""Models for the tracking app."""

from __future__ import annotations

from datetime import timedelta
from typing import TYPE_CHECKING

from django.conf import settings
from django.db import models

if TYPE_CHECKING:
from timed.employment.models import Employment


class Activity(models.Model):
"""Activity model.
Expand Down Expand Up @@ -104,7 +110,7 @@ def __str__(self) -> str:
"""Represent the model as a string."""
return f"{self.user}: {self.task}"

def save(self, *args, **kwargs):
def save(self, *args, **kwargs) -> None: # noqa: ANN002,ANN003
"""Save the report with some custom functionality.
This rounds the duration of the report to the nearest 15 minutes.
Expand Down Expand Up @@ -149,7 +155,7 @@ def __str__(self) -> str:
self.comment,
)

def calculate_duration(self, employment):
def calculate_duration(self, employment: Employment) -> timedelta:
"""Calculate duration of absence with given employment.
For fullday absences duration is equal worktime per day of employment
Expand Down

0 comments on commit 6b1c0a2

Please sign in to comment.