Skip to content
Prev Previous commit
Next Next commit
fix: ♻️ make method elapsed time of class TimeEntryModel
  • Loading branch information
Angeluz-07 committed Jun 15, 2020
commit d1008632e8a389a913151b61ccd0ffba2bb45cfb
4 changes: 4 additions & 0 deletions requirements/time_tracker_api/prod.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,7 @@ PyJWT==1.7.1

#Azure
msal==1.3.0

# Time utils
pytz==2019.3
python-dateutil==2.8.1
30 changes: 24 additions & 6 deletions time_tracker_api/time_entries/time_entries_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
from flask_restplus import abort
from flask_restplus._http import HTTPStatus

from datetime import datetime, timedelta

from commons.data_access_layer.cosmos_db import (
CosmosDBDao,
CosmosDBRepository,
Expand All @@ -25,14 +27,14 @@
)
from utils.time import (
datetime_str,
str_to_datetime,
get_current_year,
get_current_month,
get_current_day,
get_date_range_of_month,
current_datetime_str,
)
from utils import worked_time
from utils.worked_time import str_to_datetime
from utils.azure_users import AzureConnection

from time_tracker_api.projects.projects_model import ProjectCosmosDBModel
Expand Down Expand Up @@ -105,6 +107,18 @@ def start_date_at_midnight(self) -> str:
start_date.replace(hour=23, minute=59, second=59, microsecond=0)
)

@property
def elapsed_time(self) -> timedelta:
start_datetime = str_to_datetime(self.start_date)
end_datetime = str_to_datetime(self.end_date)
return end_datetime - start_datetime

def in_range(self, start_date: datetime, end_date: datetime) -> bool:
return (
start_date <= str_to_datetime(self.start_date) <= end_date
and start_date <= str_to_datetime(self.end_date) <= end_date
)

def __add__(self, other):
if type(other) is ProjectCosmosDBModel:
time_entry = self.__class__
Expand All @@ -114,7 +128,7 @@ def __add__(self, other):
raise NotImplementedError

def __repr__(self):
return '<Time Entry %r>' % self.start_date # pragma: no cover
return f'<Time Entry {self.start_date} - {self.end_date}>' # pragma: no cover

def __str___(self):
return (
Expand Down Expand Up @@ -171,17 +185,21 @@ def find_all(

if time_entries:
custom_conditions = create_in_condition(time_entries, "project_id")
custom_conditions_activity = create_in_condition(time_entries, "activity_id")
custom_conditions_activity = create_in_condition(
time_entries, "activity_id"
)

project_dao = projects_model.create_dao()
projects = project_dao.get_all(
custom_sql_conditions=[custom_conditions],
visible_only=False
custom_sql_conditions=[custom_conditions], visible_only=False
)
add_project_name_to_time_entries(time_entries, projects)

activity_dao = activities_model.create_dao()
activities = activity_dao.get_all(custom_sql_conditions=[custom_conditions_activity], visible_only=False)
activities = activity_dao.get_all(
custom_sql_conditions=[custom_conditions_activity],
visible_only=False,
)
add_activity_name_to_time_entries(time_entries, activities)

users = AzureConnection().users()
Expand Down
16 changes: 7 additions & 9 deletions time_tracker_api/time_entries/time_entries_namespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,6 @@
description='The id of the selected project',
example=faker.uuid4(),
),
'start_date': fields.DateTime(
dt_format='iso8601',
title='Start date',
required=False,
description='When the user started doing this activity',
example=datetime_str(current_datetime() - timedelta(days=1)),
),
'activity_id': UUID(
title='Activity',
required=False,
Expand All @@ -53,8 +46,13 @@
example=faker.paragraph(nb_sentences=2),
max_length=COMMENTS_MAX_LENGTH,
),
'end_date': fields.DateTime(
dt_format='iso8601',
'start_date': fields.String(
title='Start date',
required=False,
description='When the user started doing this activity',
example=datetime_str(current_datetime() - timedelta(days=1)),
),
'end_date': fields.String(
title='End date',
required=False,
description='When the user ended doing this activity',
Expand Down
39 changes: 37 additions & 2 deletions utils/time.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pytz
from typing import Dict
from datetime import datetime, timezone
from datetime import datetime, timezone, timedelta


def current_datetime_str() -> str:
Expand All @@ -9,7 +10,7 @@ def current_datetime_str() -> str:


def current_datetime() -> datetime:
return datetime.now(timezone.utc)
return datetime.now(pytz.UTC)


def get_current_year() -> int:
Expand Down Expand Up @@ -58,3 +59,37 @@ def get_last_day_of_month(year: int, month: int) -> int:
'start_date': datetime_str(start_date),
'end_date': datetime_str(end_date),
}


def start_datetime_of_current_month() -> datetime:
return datetime(
year=get_current_year(),
month=get_current_month(),
day=1,
tzinfo=timezone.utc,
)


def start_datetime_of_current_week() -> datetime:
today = current_datetime()
monday = today - timedelta(days=today.weekday())
monday = monday.replace(hour=0, minute=0, second=0, microsecond=000000)
return monday


def start_datetime_of_current_day() -> datetime:
today = current_datetime()
today = today.replace(hour=0, minute=0, second=0, microsecond=000000)
return today


def start_datetime_of_current_month_str() -> str:
return datetime_str(start_datetime_of_current_month())


def str_to_datetime(value: str) -> datetime:
from dateutil.parser import isoparse
from dateutil.tz import tzutc

assert type(isoparse(value).tzinfo) == tzutc
return isoparse(value)
111 changes: 33 additions & 78 deletions utils/worked_time.py
Original file line number Diff line number Diff line change
@@ -1,68 +1,21 @@
from datetime import datetime, timedelta, timezone
from datetime import datetime, timedelta
from utils.time import (
datetime_str,
get_current_month,
get_current_year,
current_datetime,
current_datetime_str,
start_datetime_of_current_month,
start_datetime_of_current_week,
start_datetime_of_current_day,
start_datetime_of_current_month_str,
)


def start_datetime_of_current_month() -> datetime:
return datetime(
year=get_current_year(),
month=get_current_month(),
day=1,
tzinfo=timezone.utc,
)


def start_datetime_of_current_week() -> datetime:
today = current_datetime()
monday = today - timedelta(days=today.weekday())
monday = monday.replace(hour=0, minute=0, second=0, microsecond=000000)
return monday


def start_datetime_of_current_day() -> datetime:
today = current_datetime()
today = today.replace(hour=0, minute=0, second=0, microsecond=000000)
return today


def start_datetime_of_current_month_str() -> str:
return datetime_str(start_datetime_of_current_month())


def str_to_datetime(
value: str, conversion_format: str = '%Y-%m-%dT%H:%M:%S.%fZ'
) -> datetime:
if 'Z' in value:
return datetime.strptime(value, conversion_format).astimezone(
timezone.utc
)
else:
return datetime.fromisoformat(value).astimezone(timezone.utc)


def date_range():
return {
"start_date": start_datetime_of_current_month_str(),
"end_date": current_datetime_str(),
}


def filter_time_entries(
time_entries, start_date: datetime, end_date: datetime = current_datetime()
):
return [
t
for t in time_entries
if start_date <= str_to_datetime(t.start_date) <= end_date
or start_date <= str_to_datetime(t.end_date) <= end_date
]


def stop_running_time_entry(time_entries):
for t in time_entries:
if t.end_date is None:
Expand All @@ -73,20 +26,18 @@ class WorkedTime:
def __init__(self, time_entries):
self.time_entries = time_entries

def total_time_in_seconds(self):
times = []

for t in self.time_entries:
start_datetime = str_to_datetime(t.start_date)
end_datetime = str_to_datetime(t.end_date)

elapsed_time = end_datetime - start_datetime
times.append(elapsed_time)

total_time = timedelta()
for time in times:
total_time += time
@classmethod
def from_time_entries_in_range(
cls, time_entries, start_date: datetime, end_date: datetime
):
time_entries_in_range = [
t for t in time_entries if t.in_range(start_date, end_date)
]
return cls(time_entries_in_range)

def total_time_in_seconds(self):
times = [t.elapsed_time for t in self.time_entries]
total_time = sum(times, timedelta())
return total_time.total_seconds()

def hours(self):
Expand All @@ -107,28 +58,32 @@ def summary(self):


def worked_time_in_day(time_entries):
day_time_entries = filter_time_entries(
time_entries, start_date=start_datetime_of_current_day()
)
return WorkedTime(day_time_entries).summary()
return WorkedTime.from_time_entries_in_range(
time_entries,
start_date=start_datetime_of_current_day(),
end_date=current_datetime(),
).summary()


def worked_time_in_week(time_entries):
week_time_entries = filter_time_entries(
time_entries, start_date=start_datetime_of_current_week()
)
return WorkedTime(week_time_entries).summary()
return WorkedTime.from_time_entries_in_range(
time_entries,
start_date=start_datetime_of_current_week(),
end_date=current_datetime(),
).summary()


def worked_time_in_month(time_entries):
month_time_entries = filter_time_entries(
time_entries, start_date=start_datetime_of_current_month()
)
return WorkedTime(month_time_entries).summary()
return WorkedTime.from_time_entries_in_range(
time_entries,
start_date=start_datetime_of_current_month(),
end_date=current_datetime(),
).summary()


def summary(time_entries, time_offset):
print(time_offset)
offset_in_minutes = time_offset if time_offset else 300
print(offset_in_minutes)
stop_running_time_entry(time_entries)
return {
'day': worked_time_in_day(time_entries),
Expand Down