bookyt_projects 0.18.2 → 0.18.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,7 +2,6 @@ class Activity < ActiveRecord::Base
2
2
  # Associations
3
3
  belongs_to :project
4
4
  belongs_to :person
5
- belongs_to :work_day
6
5
  validates :project, :presence => true, :allow_blank => false
7
6
  validates :person, :presence => true, :allow_blank => false
8
7
 
@@ -14,8 +13,6 @@ class Activity < ActiveRecord::Base
14
13
 
15
14
  validates_date :date, :allow_nil => false, :allow_blank => false
16
15
 
17
- before_save :create_work_day
18
-
19
16
  def duration=(value)
20
17
  if value.match(/:/)
21
18
  hours, minutes = value.split(':')
@@ -29,12 +26,12 @@ class Activity < ActiveRecord::Base
29
26
  "%s: %0.2fh" % [project.name, duration]
30
27
  end
31
28
 
32
- private
33
-
34
- def create_work_day
35
- work_day = WorkDay.where(:person_id => person_id, :date => date).first
36
- work_day ||= WorkDay.create(:person_id => person_id, :date => date)
29
+ # Work day
30
+ belongs_to :work_day, :autosave => true
31
+ before_save :update_work_day
37
32
 
38
- self.work_day = work_day
33
+ private
34
+ def update_work_day
35
+ WorkDay.create_or_update_upto(self.person, date)
39
36
  end
40
37
  end
@@ -4,6 +4,7 @@ module BookytProjects
4
4
 
5
5
  included do
6
6
  has_many :activities, :foreign_key => :person_id
7
+ has_many :work_days, :foreign_key => :person_id
7
8
  end
8
9
 
9
10
  module InstanceMethods
@@ -1,27 +1,42 @@
1
1
  class WorkDay < ActiveRecord::Base
2
-
2
+ # Associations
3
3
  belongs_to :person
4
+ validates :person, :presence => true
5
+
4
6
  has_many :activities
5
7
 
6
- before_create :current_daily_workload
8
+ # Order
9
+ default_scope order(:date)
7
10
 
8
- def current_daily_workload
9
- unless person && person.employments.current && person.employments.current.daily_workload
10
- self.daily_workload = 0.0
11
- else
12
- self.daily_workload = person.employments.current(self.date).daily_workload
13
- end
11
+ # Calculations
12
+ default_scope select('work_days.*, hours_worked - hours_due AS overtime')
13
+
14
+ def self.create_or_update(person, date)
15
+ work_day = person.work_days.where(:date => date).first
16
+ work_day ||= person.work_days.build(:date => date)
17
+
18
+ work_day.update_hours
19
+
20
+ work_day.save
21
+ end
22
+
23
+ def update_hours
24
+ self.hours_due = calculate_hours_due
25
+ self.hours_worked = calculate_hours_worked
14
26
  end
15
27
 
16
- def self.create_for_current_employment(employee)
17
- if employee.employments.current
18
- workdays = WorkDay.where(:person_id => employee.id)
19
- start_date = workdays.last.date unless workdays.empty?
20
- start_date ||= employee.employments.current.duration_from
28
+ def self.create_or_update_upto(person, end_date)
29
+ # Guard
30
+ if latest_work_day = person.work_days.last
31
+ start_date = latest_work_day.date
32
+ else
33
+ start_date = end_date
34
+ end
21
35
 
22
- (start_date..Date.today).each do |date|
23
- WorkDay.create(:person => employee, :date => date)
24
- end if workdays.last && (workdays.last.date < start_date)
36
+ (start_date..end_date).each do |date|
37
+ transaction do
38
+ self.create_or_update(person, date)
39
+ end
25
40
  end
26
41
  end
27
42
 
@@ -33,35 +48,34 @@ class WorkDay < ActiveRecord::Base
33
48
  # params:
34
49
  # :employee: Employee to build WorkDay instances for
35
50
  # :range: Date range giving first and last day
36
- def self.for_range(employee, range)
51
+ def self.build_or_update(employee, date)
37
52
  self.create_for_current_employment(employee)
38
-
39
- range.inject([]) do |out, day|
53
+ range.collect do |day|
40
54
  work_day = WorkDay.where(:person_id => employee.id, :date => day).first
41
55
  work_day ||= WorkDay.create(:person => employee, :date => day)
42
- out << work_day
43
-
44
- out
45
56
  end
46
57
  end
47
58
 
48
- # Get WorkDay instances for a month
59
+ # Get employment
49
60
  #
50
- # params:
51
- # :employee: Employee to build WorkDay instances for
52
- # :date_in_month: Any day in the requested month. Uses today by default.
53
- def self.for_month(employee, date_in_month = nil)
54
- # Assume today if no date given
55
- date_in_month ||= Date.today
56
-
57
- start_date = date_in_month.beginning_of_month
58
- end_date = date_in_month.end_of_month
61
+ # Lookup the employment for this day.
62
+ def employment
63
+ person.employments.current(self.date)
64
+ end
59
65
 
60
- self.for_range(employee, start_date..end_date)
66
+ # Get daily workload
67
+ #
68
+ # Lookup daily workload for person. Returns 0.0 if no
69
+ # employment is specified.
70
+ def daily_workload
71
+ employment.try(:daily_workload) || 0.0
61
72
  end
62
73
 
63
74
  # Working hours for this day
64
- def hours_due
75
+ #
76
+ # Saturday and sunday are off, uses daily workload for
77
+ # all other days.
78
+ def calculate_hours_due
65
79
  case date.wday
66
80
  when 6, 0
67
81
  # Saturday and sunday are off
@@ -76,18 +90,12 @@ class WorkDay < ActiveRecord::Base
76
90
  #
77
91
  # Calculates hours worked by summing up duration of all logged
78
92
  # activities.
79
- def hours_worked
80
- activities.where(:date => date).to_a.sum(&:duration)
81
- end
82
-
83
- # Overtime
84
- #
85
- # Simply substract hours_due from hours_worked.
86
- def overtime
87
- hours_worked - hours_due
93
+ def calculate_hours_worked
94
+ activities.where(:date => date).sum('duration')
88
95
  end
89
96
 
97
+ # Calculate accumulated overtime
90
98
  def overall_overtime
91
- WorkDay.where(:person_id => person.id).where('date <= ?', date).to_a.sum(&:overtime)
99
+ WorkDay.where('date <= ?', date).sum('hours_worked - hours_due')
92
100
  end
93
101
  end
@@ -5,9 +5,9 @@
5
5
  %th.number= t_attr :overtime, Activity
6
6
  %th.number= t_attr :overall_overtime, Activity
7
7
 
8
- - overall_overtime = 0
9
- - WorkDay.for_month(@employee).each do |day|
10
- - overall_overtime += day.overtime
8
+ - WorkDay.create_or_update_upto(@employee, Date.today.end_of_month)
9
+ - range = Date.today.beginning_of_month..Date.today.end_of_month
10
+ - @employee.work_days.where(:date => range).each do |day|
11
11
  - tr_params = {:class => work_day_classes(day)}
12
12
  - tr_params.merge!(:rel => 'popover', 'data-content' => h(render 'timesheets/activities_popover', :activities => day.activities), 'data-original-title' => 'Aktivitäten', 'data-html' => 'true') unless day.activities.empty?
13
13
  %tr{tr_params}
@@ -0,0 +1,5 @@
1
+ class AddHoursDueToActivities < ActiveRecord::Migration
2
+ def change
3
+ add_column :activities, :hours_due, :decimal, :precision => 10, :scale => 2
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ class ChangeMaterializedColumnsInWorkDays < ActiveRecord::Migration
2
+ def up
3
+ add_column :work_days, :hours_due, :decimal, :precision => 10, :scale => 2
4
+ add_column :work_days, :hours_worked, :decimal, :precision => 10, :scale => 2
5
+
6
+ remove_column :work_days, :daily_workload
7
+ end
8
+ end
@@ -1,3 +1,3 @@
1
1
  module BookytPos
2
- VERSION = '0.18.2'
2
+ VERSION = '0.18.3'
3
3
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bookyt_projects
3
3
  version: !ruby/object:Gem::Version
4
- hash: 83
4
+ hash: 81
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 18
9
- - 2
10
- version: 0.18.2
9
+ - 3
10
+ version: 0.18.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Roman Simecek (CyT)
@@ -145,6 +145,8 @@ files:
145
145
  - db/migrate/20120118131814_create_work_days.rb
146
146
  - db/migrate/20120118140839_add_activities_to_work_day.rb
147
147
  - db/migrate/20120119081136_add_indices_to_activities.rb
148
+ - db/migrate/20120119102801_add_hours_due_to_activities.rb
149
+ - db/migrate/20120119111230_change_materialized_columns_in_work_days.rb
148
150
  - lib/bookyt_projects.rb
149
151
  - lib/bookyt_projects/navigation.rb
150
152
  - lib/bookyt_projects/railtie.rb