Created
August 6, 2010 09:01
-
-
Save stabenfeldt/511065 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Assignment < ActiveRecord::Base | |
# $LOUD_N_CLEAR = true | |
# Counts workdays between two Dates (not Time) | |
def count_weekdays(startdate,stopdate) | |
@workdays = 0 | |
startdate.to_date.upto(stopdate.to_date) do |date| | |
if date.wday.to_s =~ /[0,1,2,3,4]/ | |
@workdays +=1 | |
end | |
end | |
@workdays | |
end | |
# Count hours for the first day, it may not be a full day. | |
def hours_the_first_day(date) | |
logger.debug "The first day is #{date}" if $LOUD_N_CLEAR | |
# If the start- or stop-time are missing time, add it. | |
if self.from.hour == 0 | |
self_from_hour = 8 | |
else | |
self_from_hour = self.from.hour | |
end | |
if self.to.hour == 0 | |
self_to_hour = 8 | |
else | |
self_to_hour = self.to.hour | |
end | |
yr, mon, day, hr, min = ParseDate.parsedate date.to_s | |
firstday_start = Time.utc(yr,mon,day,self_from_hour,self.from.min).to_f # Epoch start of day | |
firstday_stop = Time.utc(yr,mon,day,WORKDAY_STOP).to_f # Same day, at hour #{WORKDAY_STOP} | |
logger.debug "firstday_start = #{firstday_start} - firstday_stop = #{firstday_stop} (#{yr},#{mon},#{day},#{WORKDAY_STOP})" if $LOUD_N_CLEAR | |
unless date.weekend? | |
@hours_total += (firstday_stop-firstday_start)/3600 | |
@hours_total -= 0.5 # LUNCH | |
end | |
logger.debug "hours_the_first_day = #{@hours_total} hours" if $LOUD_N_CLEAR | |
logger.debug "(#{firstday_stop}-#{firstday_start})/3600 - (firstday_stop-firstday_start)/3600" if $LOUD_N_CLEAR | |
end | |
# Used to count hours for the entire assignment | |
def hours_prognosed | |
@hours_total = 0 | |
@assignment_start_day = self.from.to_date.to_s.gsub!('-','').to_i # => 20010101 | |
@assignment_stop_day = self.to.to_date.to_s.gsub!('-','').to_i # => 20010102 | |
# Is the first day also the last day? | |
if self.to.to_date == self.from.to_date | |
last_day(self.to.to_datetime) | |
else | |
hours_the_first_day(self.from) | |
# And go on with the rest until we reach end of assignment | |
next_day = self.from | |
while next_day = next_day.tomorrow | |
if next_day.to_date == self.to.to_date | |
last_day(self.to.to_datetime) | |
break | |
else | |
unless next_day.weekend? | |
@hours_total += WORKDAY_LASTS_FOR_HOURS | |
end | |
end | |
end | |
end | |
@hours_total | |
end | |
# It´s the last day of the assignment, which may be shorter. | |
def last_day(last_date) | |
unless last_date.class.to_s =~ /DateTime/ | |
last_date = last_date.to_datetime | |
end | |
# raise "Input must be DateTime, got #{last_date.class}" unless last_date.class.to_s =~ /(DateTime)/ | |
# If the start- or stop-time are missing time, add it. | |
if self.from.hour == 0 | |
self_from_hour = 8 | |
else | |
self_from_hour = self.from.hour | |
end | |
if self.to.hour == 0 | |
self_to_hour = 8 | |
else | |
self_to_hour = self.to.hour | |
end | |
if last_date.weekend? | |
return # Unless self.count_weekends_too | |
else | |
yr,mon,day,hr,min = ParseDate.parsedate last_date.to_s | |
# raise "last_date: #{last_date}" | |
logger.debug "args: yr,mon,day,hr,min => #{yr},#{mon},#{day},#{hr},#{min}" if $LOUD_N_CLEAR | |
lastday_start = Time.utc(yr,mon,day,WORKDAY_START).to_f # Last day, at 08:00 in Epoch | |
lastday_stop = Time.utc(yr,mon,day,self_to_hour,self.to.min).to_f # Epoch at end of day | |
if $LOUD_N_CLEAR | |
logger.debug "last_day() => WORKDAY_START: #{WORKDAY_START}" | |
logger.debug "last_day() => LASTDAY_START: #{lastday_start} (#{yr},#{mon},#{day},#{WORKDAY_START}) - LASTDAY_STOP = #{lastday_stop} (#{yr},#{mon},#{day},#{hr},#{min})" | |
logger.debug "WOHA! Hold your horses boy! Self.to is #{self.to} last_day is #{last_date.to_s}. Which gives us endpoint at #{Time.at(lastday_stop)}" | |
end | |
@hours_total += (lastday_stop-lastday_start)/3600 | |
@hours_total -= 0.5 # LUNCH | |
end | |
logger.debug "exiting with #{@hours_total} hours_total" if $LOUD_N_CLEAR | |
end | |
def hours_written_last_week | |
last_monday = (Date.today - 7) # Todays´s monday | |
friday = last_monday + 5 | |
# Returns timestamp|hours for given project_id and user_id for the last week | |
query = AchievoProject.connection.execute(" | |
SELECT h.activitydate, sum(time/60) as hours from hours h left | |
JOIN phase ph on h.phaseid=ph.id left | |
JOIN project p on ph.projectid=p.id | |
WHERE h.userid = #{self.person.get_achievo_id} AND p.id = #{self.project_id} | |
AND h.activitydate > date_add(curdate(), INTERVAL -1 month) | |
group by h.activitydate; | |
") | |
return query.fetch_hash["hours"].to_f | |
end | |
def abort_if_assignment_wasnt_last_week | |
# If the assignment ended more than one week ago stop, do nothing. It´s no longer last week. | |
gap = last_monday.to_f - self.to.to_f | |
if gap > (86400*7) | |
logger.debug 'The assignment ended more than a week ago, <<last week>> is way gone.' if $LOUD_N_CLEAR | |
end | |
end | |
def hours_prognosed_last_week | |
@hours_total = 0 | |
if self.to.to_f > self.from.to_f | |
logger.debug "Assignment must have a valid start and end date: #{self.from} => #{self.to}" | |
return | |
end | |
return if abort_if_assignment_wasnt_last_week | |
# If the start- or stop-time are missing time, add it. | |
if self.from.hour == 0 | |
self_from_hour = 8 | |
else | |
self_from_hour = self.from.hour | |
end | |
if self.to.hour == 0 | |
self_to_hour = 8 | |
else | |
self_to_hour = self.to.hour | |
end | |
# Calculations has to start from a monday, find previous. | |
logger.debug "Calculations has to start from a monday, find previous." if $LOUD_N_CLEAR | |
calculation_day = last_monday | |
# Find last monday, 7 days earlier than calculation_day. | |
last_monday = one_week_before(calculation_day) | |
logger.debug "monday 7 days earlier than calculation_day (#{calculation_day.to_date} wday:#{calculation_day.wday}) is #{last_monday.to_date}(#{last_monday.wday})" if $LOUD_N_CLEAR | |
# From calculation_day (The first monday after the week were´re working with) | |
# Find end of the week in question. | |
# Find friday 16 o´clock | |
end_of_week = find_end_of_week(calculation_day) | |
#logger.debug "END_OF_WEEK: #{end_of_week}" if $LOUD_N_CLEAR | |
logger.debug "Looking for friday, end of day. Moving from #{calculation_day.to_date} (#{calculation_day.wday}) towards the end of week (friday) we pass.." if $LOUD_N_CLEAR | |
logger.debug "three days before calculation_day #{calculation_day.to_date} (#{calculation_day.wday}) we got end_of_week #{end_of_week.to_date} (#{end_of_week.wday})" if $LOUD_N_CLEAR | |
# If the project began after monday, count from there. | |
if self.from.to_f >= last_monday.to_f | |
start_of_week = self.from | |
else | |
start_of_week = last_monday | |
end | |
# Does it last till end_of_week? | |
# raise "end_of_week is class :#{end_of_week}" | |
if self.to.to_f < end_of_week.to_time.to_f | |
check_to = self.to.to_date | |
logger.debug "check_to is #{check_to.wday}" if $LOUD_N_CLEAR | |
logger.debug "it lasts till end_of_week - self.to.to_f (#{self.to.to_f}) < end_of_week.to_f (#{end_of_week.to_time.to_f})" if $LOUD_N_CLEAR | |
else | |
check_to = end_of_week.to_date | |
logger.debug "check_to is #{check_to.wday}" | |
logger.debug "it DOES NOT lasts till end_of_week - self.to.to_f [#{self.to}] (#{self.to.to_f}) < end_of_week.to_f (#{end_of_week.to_time.to_f}) [#{end_of_week.to_time}]" if $LOUD_N_CLEAR | |
end | |
# Is the first day also the last day? | |
if self.to.to_date == self.from.to_date | |
last_day(self.to.to_datetime) | |
else | |
hours_the_first_day(start_of_week) | |
if $LOUD_N_CLEAR | |
logger.debug "The first day brought #{@hours_total} hours" | |
logger.debug "Started at #{self.from} -> 16 o clock" | |
logger.debug "working towards end of friday" | |
end | |
# And go on with the rest until end of friday. | |
next_day = start_of_week | |
logger.debug "first day after start-monday: #{next_day} (#{next_day.wday}) - should be thuesday (2): #{next_day.tomorrow} (#{next_day.tomorrow.wday})" if $LOUD_N_CLEAR | |
while next_day = next_day.tomorrow | |
if next_day.to_date.to_s == check_to.to_s | |
logger.debug "hours before last_day: #{@hours_total}" if $LOUD_N_CLEAR | |
last_day(next_day) | |
logger.debug "break, counting last_day. Hours this far: #{@hours_total}" if $LOUD_N_CLEAR | |
break | |
else | |
unless next_day.weekend? | |
@hours_total += WORKDAY_LASTS_FOR_HOURS | |
end | |
logger.debug "hours_prognosed_last_week(): hours_total: #{@hours_total}" if $LOUD_N_CLEAR | |
end | |
end | |
end | |
@hours_total | |
end | |
def hours_in_matrix_on_date(assignment, date) | |
as = Assignment.find(assignment) | |
if date > as.from and date < as.to # date is in the period of time the assignment spans across. | |
7.5 * as.prognos_weight_percentage | |
end | |
end | |
# Given a date-range, number of workdays are returned | |
# TODO: Could be extended to subtract holidays too. | |
def workdays | |
count_weekdays(self.from.to_date,self.to.to_date) | |
end | |
# Returns assignments that were active the previous week for all users. | |
def people_with_active_assignments | |
start_of_previous_week = one_week_before(last_monday) | |
end_of_previous_week = find_end_of_week(start_of_previous_week) | |
@people = [ ] | |
Assignment.all(:conditions => ['assignments.to > ?', end_of_previous_week]).each do |p| | |
@people << p | |
end | |
end | |
# Hours total written in Achievo for project. | |
def hours_written_in_achievo | |
unless self.project_id && self.person_id | |
logger.debug "Assignment is missing project_id or person_id" | |
return | |
end | |
query = AchievoProject.connection.execute(" | |
SELECT p.id, p.name, sum(time)/60 AS allhours, | |
SUM(case when h.activitydate > date_add(curdate(), INTERVAL -1 week) | |
THEN time/60 else 0 end) AS lastweek FROM hours h left | |
JOIN phase ph ON h.phaseid=ph.id left | |
JOIN project p ON ph.projectid=p.id | |
WHERE h.userid = #{self.person.get_achievo_id} AND p.id = #{self.project_id} | |
group by p.id;") | |
return query.fetch_hash["allhours"].to_f | |
end | |
def diff_with_achievo | |
logger.debug "ASSIGNMENT_ID: #{self.id}" if $LOUD_N_CLEAR | |
if self.hours_prognosed.to_f > self.hours_written_in_achievo["lastweek"].to_f | |
self.hours_written_in_achievo["lastweek"].to_f - self.hours_prognosed rescue nil | |
else | |
self.hours_written_in_achievo["lastweek"].to_f - self.hours_prognosed rescue nil | |
end | |
end | |
def prognos_weight_percentage | |
self.prognos_weight.to_f/100.to_f | |
end | |
def include?(date) | |
from.to_date <= date && to.to_date >= date | |
end | |
def full_day?(date) | |
not half_day?(date) | |
end | |
def half_day?(date) | |
return true if to.to_date == date && to.hour == 12 | |
return true if from.to_date == date && from.hour == 13 | |
return false | |
end | |
def first_half?(date) | |
return half_day?(date) && to.to_date == date && to.hour == 12 | |
end | |
def second_half?(date) | |
return half_day?(date) && from.to_date == date && from.hour == 13 | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment