Data Model

Common Base Models

TimeStampedModel [TSM] (abstract)

Automatically manages created and modified timestamps. Provided by django-extensions.

created
Object creation date and time.
modified
Last modification date and time.

Accountable [ACC] (abstract)

Groups common attributes for accountable objects. These are the type of accounting (by effort / lump-sum), the status, the estimated costs and the budgeted hours.

accounting_type
Accounting by effort or lump-sum. [enum]
hours_budget
Estimated effort for this accountable in hours. [float]
cost_estimate
Estimated costs for this accountable in currency. [float]
currency
Currency for all related amounts. Defaults to settings.SANDGLASS_DEFAULT_CURRENCY. [string]

ActivityPeriod [AP] (abstract)

Groups common attributes for projects with a certain activity period.

active
Defines if new hours can be booked onto the object. [boolean]
active_from
Start date of activity period. [date]
active_to
End date of activity period. [date]

User-Management

User

The main application user or company employee. Provided by django.contrib.auth.

username
Unique username. [string]
first_name
[string]
last_name
[string]
email
[string]
password
Encrypted password. [string]
last_login
Date and time of last login. [datetime]

... and some more

UserProfile

Inherits from TSM.

An extension to User that adds sandglass-specific user properties to the User model.

user
Link to the User model. [1to1]
failed_logins

Counter for account locking after n failed logins. [int]

The number of failed login attempts that locks an account can be specified in a global configuration variable.

date_locked
When was the account locked. [timestamp]
teams

Reference to Teams including this user. [M2M]

Note

This is different from User.groups (to django.contrib.auth.models.Group) which is for grouping permissions. Teams are solely for grouping users.

status_message
Optional additional message describing the user’s status. [string]
time_model
Reference to the TimeModel assigned to this user. [FK]
date_entry
Date the employee started working for the company. [date]
avatar
Avatar image for this user. Maybe rather use something like django-avatar. [image/FK?]
theme
Select sandglass styling theme (colors, fonts, background image, ...). Reference to the Theme selected by this user. [FK]
Contact information

Basic contact info like

  • phone numbers
  • additional email addresses
  • work- and home addresses
  • room number
  • ...

Note

Currently only add the fields we need. Maybe extend the model later in a flexible way using an entity-attribute-value model.

Team

Inherits from TSM.

Group of users/employees in terms of workgroup or department, not permissions.

Note

Might better be replaced by django.contrib.auth.models.Group.

name
Team name. [string]
description
Optional short description of the team’s purpose. [string]
users
Back-reference to Users in this team. [M2M]

TimeModel

Inherits from TSM.

Defines a set of „rules” the work-time of employees. TimeModels can be reused for multiple users and should be defined by administrators.

workdays_per_week
Number of workdays per week. Defaults to five. [integer]
daily_hours

Hours the employee should do daily. The standard workday.

If daily hours should be defined on a daily basis, set daily_hours=None and use daily_hours_<weekday> instead.

Defaults to weekly_hours ÷ workdays_per_week. [float/time?]

E.g. 38.5 hours per week ÷ 5 workdays = 7.7 hours per day.

daily_hours_<weekday>

Daily hours for weekday (mon-sun) if defined on daily basis.

Defaults to None. [float/time?]

weekly_hours

Hours an employee should do weekly. The standard work-week.

Should be the product of workdays_per_week × daily_hours or the sum of all daily_hours_<weekday> values. [float/time?]

yearly_vacation

The number of vacation days the employee may consume per year. [int]

In combination with all Activity entryies for the user, activity_type == vacation, and the entry date ( UserProfile.date_entry), this can be used to calculate the employee’s vacation quota for any date (without using the TimeSheet savepoints).

Example: the user has 25 days per year of vacation and started working for the company on the 17th of April 2011.

The vacation quota for the first year is calculated like this:

import calendar
import datetime
yearly_vacation = 25
entry_date = datetime.date(2011, 4, 17)
# vacation quota for year of entry
day_of_year = entry_date.timetuple().tm_yday  # 107
days_in_year = 366 if calendar.isleap(entry_date.year) else 365  # 365
entry_quota = int(round(yearly_vacation * day_of_year / days_in_year))
# 7 days vacation in the first year

Then, let’s say the vacation history evolved that way (not taking weekends into account):

  • 2011-04-17: +7 days (initial)
  • 2011-12-04 - 2011-12-08: -5 days
  • 2012-01-01: +25 days (yearly budget 2012)
  • 2012-03-03: -1 day
  • 2012-06-10 - 2012-06-23: -15 days

So, the current quota for 2012-06-24 is 7 - 5 + 25 - 1 - 15 == 11.

Generically, for any date, the current vacation quota calcuates as:

# number of years between date_entry and date
date = datetime.date(2012, 6, 24)
nr_years = date.year - entry_date.year  # 1
# nr of days added to the quota in the meanwhile
quota_add = nr_years * yearly_vacation  # 25
# consumed days from Activity, type == vacation before date
quota_sub = Activity.objects.filter(
    user__pk=id,
    activity_type='vacation',
    end__lte=date).count()  # e.g. 21
# current vacation quota
vacation_quota = entry_quota + quota_add - quota_sub  # 11
timesheet_interval

Length of the usual interval in which the employee should do settlements. [choice]

One of weekly, bi-weekly, monthly, quarter-yearly, half-yearly, yearly.

day_start_from

Begin of the time-range an employee should start his/her workday at. [time]

If workday start-times should be defined on a daily basis, set day_start_from and day_start_to to None and use day_start_<weekday>_<from/to> instead.

day_start_to
End of the time-range an emplyee should start his/her workday at. [time]
day_end_from
Begin of the time-range an employee should end his/her workday at. [time]
day_end_to
End of the time-range an employee should end his/her workday at. [time]
day_start_<weekday>_from
Like day_start_from for weekday (mon-sun) if defined on a daily basis. [time]
day_start_<weekday>_to
Like day_start_to for weekday (mon-sun) if defined on a daily basis. [time]
day_end_<weekday>_from
Like day_end_from for weekday (mon-sun) if defined on a daily basis. [time]
day_end_<weekday>_to
Like day_end_to for weekday (mon-sun) if defined on a daily basis. [time]

Project-Structure

Client

Inherits from TSM.

Client (company or person) of the company comissioning at least one project. This does not link to a

name
Client’s name or company name. [string]
avatar
Avatar image for this user. Maybe rather use something like django-avatar. [image/FK?]
contact_persons
Reference to contact persons for this client. These are general contacts, without relation to a specific project for this client.

ContactPerson

Inherits from TSM.

Generic set of contact information of a person working for a client in general or on a specific project.

first_name
[string]
last_name
[string]
email
[string]
phone
[string]

Further contact information

  • additional phone numbers
  • additional email addresses
  • address
  • room number
  • department, position

Note

Currently only add the fields we need. Maybe extend the model later in a flexible way using an entity-attribute-value model.

Project

Inherits from TSM and ACC.

Defines one project for a ceratain client (or internal, for the company itsself), that defines a list of tasks (project parts) available to book hours to.

Projects can be cloned to easily create new projects with the same attributes.

name
Project title. [string]
acronym
Project title acronym and keyboard shortcut. [string]
parent
Self-reference for grouping purposes. Limit to one level. [FK]
client

Reference to the contracting Client. [FK]

If no client is defined, the project is company-internal.

tasks
List of tasks defined for this project. [M2M]
activity_description_required
Flag indicating if any Activity assigned to this project requires a description. [boolean]
avatar
Avatar image for this user. Maybe rather use something like django-avatar. [image/FK?]
contact_persons
Reference to contact persons for this client. These are project-specific contact persons.

Task

Inherits from TSM and ACC.

Main activity categorization for projects. Describes project phases, parts and areas.

name
Task title. [string]
acronym
Task title acronym and keyboard shortcut. [string]
parent
Self-reference for grouping purposes. Limit to one level. [FK]
default_tags
List of default tags for any Activity recorded for this project. [M2M]

Tracking

Activity

Inherits from TSM.

A record of activity. This is the main unit of measure for sandglass. Activities can describe either work on a project, unassigned time, breaks or days where employees are away sick or on vacation.

user
Reference to the User this activity is recorded for. [FK]
project
Reference to the Project this activity is recorded for. Can be None whenever the activity is not project related. Required for project-related tasks (type == working). [FK]
task
Reference to the Task this activity is recorded for. Can be None whenever the activity is not project related. Required if type == working and any tasks are defined for the assigned project. [FK]
description
Usually optional description of the activity. Can be mandatory if project.activity_description_required is True.
activity_type

Indicator of the kind of activity described. [enum] Can be one of:

  • working
  • out of office
  • unassigned
  • break
  • on vacation
  • sick
  • on leave
start
Start of activity. [datetime]
end
End of activity. None if still running. [datetime]
duration

Duration of the activity in days. [int]

Denormalized difference between end and start for faster retrieval of the number of days this activity must be accounted for. Must be updated in Activity.save.

tags
List of assigned tags. [M2M]
locked

Flag indicating if this activity has already been reviewed in some report. [boolean]

Note

Potential problem with project-time settlement reports (for invoicing) and employees’ monthly timesheets (for payroll accounting). We might need different lock states here.

Tag

Inherits from TSM.

name
Tag title. [string]
acronym
Tag title acronym and keyboard shortcut. [string]
description
[string]
tag_type

Indicator of the kind of tag. [enum] Can be one of:

  • activity

    Tagging for activities regarding the type of activity. Examples are design, development, templating, frontend, testing, consulting, presentation, coordination, meetings, ...

  • accounting

    Tagging for activities regarding the price of the activity. Examples are editorial work, development, senior consulting, ...

  • time

    Tagging for activities regarding the type of time the activity was carried out at. Examples are normal work-time, overtime, business trips, assembling, ...

hourly_price
Hourly price for each tagged activity in currency. [float]
currency
Currency for all related amounts. Defaults to settings.SANDGLASS_DEFAULT_CURRENCY. [string]

OverTime

Inherits from TSM.

A record of overtime. This is an additional tracking unit, next to Activity, which is used to keep track of employees’ overtime budget.

OverTime, not to be confused with the employees’ flexible working hours balance, needs to be kept track of manually.

For time-models with flexible working hours, the daily, weekly or monthly balance can easily be calculated for any date by summing the hours done in the period and balancing that with the daily_hours, weekly_hours or daily_hours × days_in_month (defined in the employee’s time-model) respectively.

OverTime, on the other hand, is subject to legal constraints and contractual agreements. As such, there is no generically valid way of determining if any given activity is to be seen as overtime or not.

By analyzing the employee’s time-model, sandglass will try to suggest overtime periods which the user can accept or refuse.

Employees can also consume overtime by requesting payout in their montly timesheets or manually compensating their flexible working hours balance.

user
Reference to the User who this overtime is accounted for. [FK]
date
Day of overtime activity. [date]
factor

Percentual additional value of the overtime hours. [float/decimal]

Usual values would be 0.5 (50%, 1:1,5) or 1 (100%, 1:2).

duration

Length of overtime period. [timedelta]

Negative values can be provided as a matter of consuming ones overtime budget.

activities
Optional link to the activities that are affected. [M2M]

Reporting

TimeSheet

Inherits from TSM.

Montly (or weekly, bi-weekly, ...) settlement of the users’ activities. This acts as basis for salary calculations and as savepoint of the users’ status.

The employees’ vacation budget, flexible working-hours balance, overtime budget and the like are stored here and thus the development of those values in time is easily reproducable.

Any calculations should always use the last verified timesheet of a user as basis.

user
Reference to the User this timesheet is about. [FK]
name

Title of the timesheet. [string]

Will be something like “Montly timesheet, January 2012, Name”.

description
Description of the timesheet’s purpose. [string]
date_from
Start of date range limit for the timesheet. [datetime]
date_to
End of date range limit for the timesheet. [datetime]
time_model_snapshot
Serialized version of the TimeModel that was valid for a User at the time the TimeSheet was created.
verified
Flag to indicate if the report has been verified by a supervisor. [boolean]
flextime_payout
Amount of time, the User chooses to be paid out from his/her flextime budget. [timedelta]
overtime_payout
Amount of time, the User chooses to be paid out from his/her overtime budget. [timedelta]
vacation_budget

The employee’s vacation budget from now on. [int]

This value is valid for the period after the TimeSheet.

flextime_balance

The employee’s flextime budget from now on. [timedelta]

If the employee does not have a flextime model, this is optional.

This value is valid for the period after the TimeSheet.

overtime_budget

The employee’s overtime budget from now on. [timedelta]

This value is valid for the period after the TimeSheet.

ReportQuery

Inherits from TSM.

Saved filter configuration (user, team, client, project, ...) for generating a custom report.

name
Title of the report. [string]
description
Description of the report’s purpose. [string]
date_from
Start of date range limit for the report. [datetime]
date_to
End of date range limit for the report. [datetime]
users
List to users to limit the report to. [M2M]
teams
List of teams to limit the report to. [M2M]
clients
List of clients to limit the report to. [M2M]
projects
List of projects to limit the report to. [M2M]
include_sub_projects
Should children of the projects be included? [boolean]
tasks
List of tasks to limit the report to. [M2M]
include_sub_tasks
Should children of the tasks be included? [boolean]
tags
List of tags to limit the report to. [M2M]

ReportSnapshot

Inherits from TSM.

Serialized report data stored for archiving purposes. No whatsoever connection to live data is kept in the snapshots. All required data is serialized so that changes don’t affect the report output.

name
Title of the report. [string]
description
Description of the report’s purpose. [string]
Serialized data
The same fields as ReportQuery but with serialized lists of objects. Serialization format is JSON.

ReviewedReport

Inherits from TSM.

Combination of ReportQuery and ReportSnapshot for reports which need to be verified by a supervisor.

report_query
Reference to a ReportQuery which will be used before the report is verified. [FK]
report_snapshot
Reference to a ReportSnapshot which will be used after the report was verified. [FK]
verified
Flag to indicate if the report has been verified by a supervisor. [boolean]

Miscellaneous

PublicHoliday

Synchronization storage for ical feeds providing public holiday data.

name
Name of the holiday (e.g. Christmas)
date
[date]

Settings

Theme

Inherits from TSM.

Everyone likes other colors best. So let’s make some themes!

name
Name of the theme.
description
Short description of the theme. [string]
theme_folder
Identifier / path-prefix for theme CSS and images. (e.g. located in static/sandglass/themes/<theme_folder>/theme.css|background.png).