.. _datamodel: ============ Data Model ============ .. _datamodel-base: Common Base Models ================== .. _datamodel-tsm: 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. .. _datamodel-acc: 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] .. _datamodel-activityperiod: 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] .. _datamodel-usermanagement: User-Management =============== .. _datamodel-user: 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 .. _datamodel-userprofile: UserProfile ----------- Inherits from :ref:`TSM `. An extension to :ref:`datamodel-user` that adds sandglass-specific user properties to the ``User`` model. ``user`` Link to the :ref:`datamodel-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 :ref:`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 :ref:`datamodel-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 :ref:`datamodel-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`_. .. _django-avatar: https://github.com/ericflo/django-avatar .. _entity-attribute-value model: http://en.wikipedia.org/wiki/Entity-attribute-value_model .. _datamodel-team: Team ---- Inherits from :ref:`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 :ref:`Users ` in this team. [M2M] .. _datamodel-timemodel: TimeModel --------- Inherits from :ref:`TSM `. Defines a set of „rules” the work-time of :ref:`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_`` 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_`` 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_`` values. [float/time?] ``yearly_vacation`` The number of vacation days the employee may consume per year. [int] In combination with all :ref:`datamodel-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: .. code-block:: python 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: .. code-block:: python # 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__`` 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__from`` Like ``day_start_from`` for ``weekday`` (mon-sun) if defined on a daily basis. [time] ``day_start__to`` Like ``day_start_to`` for ``weekday`` (mon-sun) if defined on a daily basis. [time] ``day_end__from`` Like ``day_end_from`` for ``weekday`` (mon-sun) if defined on a daily basis. [time] ``day_end__to`` Like ``day_end_to`` for ``weekday`` (mon-sun) if defined on a daily basis. [time] .. _datamodel-projectstructure: Project-Structure ================= .. _datamodel-client: Client ------ Inherits from :ref:`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 :ref:`contact persons ` for this client. These are general contacts, without relation to a specific project for this client. .. _datamodel-contactperson: ContactPerson ------------- Inherits from :ref:`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`_. .. _datamodel-project: Project ------- Inherits from :ref:`TSM ` and :ref:`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 :ref:`datamodel-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 :ref:`datamodel-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 :ref:`contact persons ` for this client. These are project-specific contact persons. .. _datamodel-task: Task ---- Inherits from :ref:`TSM ` and :ref:`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 :ref:`tags ` for any :ref:`datamodel-activity` recorded for this project. [M2M] .. _datamodel-tracking: Tracking ======== .. _datamodel-activity: Activity -------- Inherits from :ref:`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 :ref:`datamodel-user` this activity is recorded for. [FK] ``project`` Reference to the :ref:`datamodel-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 :ref:`datamodel-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 :ref:`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. .. _datamodel-tag: Tag --- Inherits from :ref:`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 :ref:`activities ` regarding the type of activity. Examples are design, development, templating, frontend, testing, consulting, presentation, coordination, meetings, ... * ``accounting`` Tagging for :ref:`activities ` regarding the price of the activity. Examples are editorial work, development, senior consulting, ... * ``time`` Tagging for :ref:`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] .. _datamodel-overtime: OverTime -------- Inherits from :ref:`TSM `. A record of overtime. This is an additional tracking unit, next to :ref:`datamodel-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 :ref:`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 :ref:`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 :ref:`datamodel-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 :ref:`activities ` that are affected. [M2M] .. _datamodel-reporting: Reporting ========= .. _datamodel-timesheet: TimeSheet --------- Inherits from :ref:`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 :ref:`datamodel-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 :ref:`datamodel-timemodel` that was valid for a :ref:`datamodel-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 :ref:`datamodel-user` chooses to be paid out from his/her flextime budget. [timedelta] ``overtime_payout`` Amount of time, the :ref:`datamodel-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. .. _datamodel-reportquery: ReportQuery ----------- Inherits from :ref:`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 :ref:`users ` to limit the report to. [M2M] ``teams`` List of :ref:`teams ` to limit the report to. [M2M] ``clients`` List of :ref:`clients ` to limit the report to. [M2M] ``projects`` List of :ref:`projects ` to limit the report to. [M2M] ``include_sub_projects`` Should children of the projects be included? [boolean] ``tasks`` List of :ref:`tasks ` to limit the report to. [M2M] ``include_sub_tasks`` Should children of the tasks be included? [boolean] ``tags`` List of :ref:`tags ` to limit the report to. [M2M] .. _datamodel-reportsnapshot: ReportSnapshot -------------- Inherits from :ref:`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. .. _datamodel-reviewedreport: ReviewedReport -------------- Inherits from :ref:`TSM `. Combination of :ref:`datamodel-reportquery` and :ref:`datamodel-reportsnapshot` for reports which need to be verified by a supervisor. ``report_query`` Reference to a :ref:`datamodel-reportquery` which will be used before the report is ``verified``. [FK] ``report_snapshot`` Reference to a :ref:`datamodel-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] .. _datamodel-misc: Miscellaneous ============= .. _datamodel-publicholiday: PublicHoliday ------------- Synchronization storage for ical feeds providing public holiday data. ``name`` Name of the holiday (e.g. Christmas) ``date`` [date] .. _datamodel-settings: Settings ======== .. _datamodel-theme: Theme ----- Inherits from :ref:`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.css|background.png``).