backlog 0.21.3 → 0.22.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,16 @@
1
+ == 0.22.0 2008-02-14
2
+
3
+ === Features
4
+
5
+ * Added report for displaying all work records relating to tasks in a backlog for a given time period.
6
+ * Aded ability to look at other users weekly work sheets.
7
+ Used in the Work Lock Notification mail.
8
+
9
+ === Fixes
10
+
11
+ * Fixed filtering of other users work records in weekly work sheet.
12
+ * Changed to display full name instead of login in weekly work sheet.
13
+
1
14
  == 0.21.3 2008-02-13
2
15
 
3
16
  === Features
data/Rakefile CHANGED
@@ -34,7 +34,7 @@ Hoe.new("backlog", APP::VERSION) do |p|
34
34
  p.url = 'http://rubyforge.org/projects/backlog/'
35
35
  p.extra_deps = [['rails', '>= 1.2.4'], ['gruff', '>= 0.2.9'], ['rmagick', '= 1.15.12'],
36
36
  ['postgres', '>= 0.7.9'], ['slave', '>= 1.2.1']]
37
- p.rsync_args = "-acuv --delete --exclude=wiki*"
37
+ p.rsync_args = "-acv --delete --exclude=wiki*"
38
38
  end
39
39
 
40
40
  desc 'Release the application to RubyForge'
@@ -174,6 +174,13 @@ class BacklogsController < ApplicationController
174
174
  render :text => 'alert("Updated sort order");'
175
175
  end
176
176
 
177
+ def works
178
+ backlog = Backlog.find(params[:id])
179
+ @report_filter = ReportFilter.new(params[:report_filter])
180
+ @works = Work.paginate :conditions => ["completed_at BETWEEN ? AND ? AND task_id IN (SELECT id FROM tasks t where t.backlog_id = ?)", @report_filter.start_on, @report_filter.end_on, backlog.id], :page => params[:page]
181
+ render :template => '/works/list'
182
+ end
183
+
177
184
  private
178
185
 
179
186
  def load_tasks(backlog)
@@ -61,8 +61,8 @@ class WorkLocksController < ApplicationController
61
61
  user_subscribers = current_user.work_lock_subscribers
62
62
  notify_users = (work_account_subscribers + user_subscribers).uniq
63
63
  notify_users.each do |user|
64
- week_url = url_for :controller => 'works', :action => :weekly_work_sheet_by_work_account, :year => @year, :week => @week
65
- spreadsheet_url = url_for :controller => 'works', :action => :timeliste, :year => @year, :week => @week
64
+ week_url = url_for :controller => 'works', :action => :weekly_work_sheet_by_work_account, :year => @year, :week => @week, :user_id => current_user.id
65
+ spreadsheet_url = url_for :controller => 'works', :action => :timeliste, :year => @year, :week => @week, :user_id => current_user.id
66
66
  WorkLockNotify.deliver_lock(user, current_user, @week, week_url, spreadsheet_url)
67
67
  end
68
68
  back_or_redirect_to :controller => 'works', :action => :weekly_work_sheet, :year => @year, :week => @week
@@ -156,7 +156,8 @@ class WorksController < ApplicationController
156
156
  def weekly_work_sheet_by_work_account
157
157
  @year = (params[:year] && params[:year].to_i) || Date.today.year
158
158
  @week = (params[:week] && params[:week].to_i) || Date.today.cweek
159
- @work_accounts = Work.works_for_week_by_work_account(@year, @week)
159
+ @user = params[:user_id] ? User.find(params[:user_id]) : current_user
160
+ @work_accounts = Work.works_for_week_by_work_account(@year, @week, @user)
160
161
  @first_date = Date.commercial(@year, @week, 1)
161
162
  @last_date = @first_date + 6
162
163
  @lock = WorkLock.find(:first, :conditions => ['user_id = ? AND start_on <= ? AND end_on >= ?', current_user.id, @first_date, @last_date])
@@ -8,6 +8,7 @@ class Backlog < ActiveRecord::Base
8
8
  validates_inclusion_of :enable_users, :in => [true, false], :allow_nil => true, :message => ActiveRecord::Errors.default_error_messages[:blank]
9
9
 
10
10
  belongs_to :work_account
11
+ belongs_to :customer
11
12
  has_many :tasks, :order => 'period_id, position', :dependent => :destroy
12
13
  has_many :unplanned_tasks, :class_name => 'Task', :conditions => 'period_id IS NULL', :order => 'position'
13
14
 
@@ -0,0 +1,15 @@
1
+ class ReportFilter
2
+ attr_reader :start_on
3
+ attr_reader :end_on
4
+
5
+ def initialize(attributes)
6
+ if attributes
7
+ attributes = attributes.clone
8
+ @start_on = Date.parse attributes.delete(:start_on) || Date.local(2007, 01, 01)
9
+ end_on_param = attributes.delete(:end_on)
10
+ @end_on = end_on_param && end_on_param.size > 0 ? Date.parse(end_on_param) : Date.today
11
+ raise "Unknown parameters: #{attributes.inspect}" unless attributes.empty?
12
+ end
13
+ end
14
+
15
+ end
data/app/models/work.rb CHANGED
@@ -5,6 +5,7 @@ class Work < ActiveRecord::Base
5
5
  belongs_to :task
6
6
  belongs_to :user
7
7
  belongs_to :work_account
8
+ belongs_to :customer
8
9
 
9
10
  validates_associated :task
10
11
  validates_presence_of :work_account
@@ -53,7 +54,7 @@ class Work < ActiveRecord::Base
53
54
  def self.works_for_week_by_work_account(year, week_no, user = current_user)
54
55
  first_date = Date.commercial(year, week_no, 1)
55
56
  last_date = first_date + 6
56
- works = find(:all, :conditions => "completed_at IS NOT NULL AND completed_at BETWEEN '#{first_date.to_time.iso8601}' AND '#{(last_date+1).to_time.iso8601}'", :order => 'completed_at, started_at')
57
+ works = find(:all, :conditions => "user_id #{user ? " = #{user.id}" : "IS NULL"} AND completed_at IS NOT NULL AND completed_at BETWEEN '#{first_date.to_time.iso8601}' AND '#{(last_date+1).to_time.iso8601}'", :order => 'completed_at, started_at')
57
58
  result = {}
58
59
  works.each do |work|
59
60
  day_of_week = work.completed_at.to_date.cwday - 1
@@ -79,7 +80,7 @@ class Work < ActiveRecord::Base
79
80
  works.map{|w| w.work_account}.uniq.each do |work_account|
80
81
  totals_per_work_account[work_account.id] = [[], []]
81
82
  (0..6).each do |day|
82
- works_for_day = works.select {|work| (work.work_account == work_account) && (work.completed_at.to_date == (first + day)) && (work.user_id.nil? || (user && work.user_id == user.id)) }
83
+ works_for_day = works.select {|work| (work.work_account == work_account) && (work.completed_at.to_date == (first + day)) && ((user.nil? && work.user_id.nil?) || (user && work.user_id == user.id)) }
83
84
  invoice_works_for_day = works_for_day.select {|work| work.invoice? }
84
85
  internal_works_for_day = works_for_day.select {|work| !work.invoice? }
85
86
 
@@ -1,3 +1,4 @@
1
1
  <%=image_link_to 'arrow_up.png', l(:backlogs), :action => :list %>
2
2
  <%=image_detour_to('clipboard.png', l(:edit), :controller => 'backlogs', :action => :edit, :id => @backlog) unless controller.action_name == 'edit' %>
3
+ <%=image_detour_to('hammer.png', l(:work), :controller => 'backlogs', :action => :works, :id => @backlog) %>
3
4
  <%=detour_to(image_tag(url_for("add.png"), :alt => l(:add_task), :title => l(:add_task), :class => 'image-submit'), :controller => 'tasks', :action => 'new', :task => {:backlog_id => @backlog.id} ) %>
@@ -3,6 +3,51 @@
3
3
  <% if @period %>
4
4
  <%=render :partial => '/periods/title' %>
5
5
  <% end %>
6
+
7
+ <% if @report_filter %>
8
+ <% form_for :report_filter do |f| %>
9
+ <p><label for="report_filter_start_on"><%=l :start_on%></label>
10
+ <%=f.text_field 'start_on', :size => 16, :value => @report_filter.start_on ? @report_filter.start_on.strftime('%Y-%m-%d') : nil %>
11
+ <button id="trigger1">...</button>
12
+ <script type="text/javascript">//<![CDATA[
13
+ Zapatec.Calendar.setup({
14
+ firstDay : 1,
15
+ showOthers : true,
16
+ showsTime : true,
17
+ step : 1,
18
+ electric : false,
19
+ inputField : "report_filter_start_on",
20
+ button : "trigger1",
21
+ ifFormat : "%Y-%m-%d",
22
+ daFormat : "%Y/%m/%d",
23
+ timeInterval : 15
24
+ });
25
+ //]]></script>
26
+
27
+ <label for="report_filter_end_on"><%=l :completed_at%></label>
28
+ <%=f.text_field 'end_on', :size => 16, :value => (@report_filter.end_on && @report_filter.end_on.strftime('%Y-%m-%d')) %>
29
+ <button id="trigger2">...</button>
30
+ <script type="text/javascript">//<![CDATA[
31
+ Zapatec.Calendar.setup({
32
+ firstDay : 1,
33
+ showOthers : true,
34
+ showsTime : true,
35
+ step : 1,
36
+ electric : false,
37
+ inputField : "report_filter_end_on",
38
+ button : "trigger2",
39
+ ifFormat : "%Y-%m-%d",
40
+ daFormat : "%Y/%m/%d",
41
+ timeInterval : 15
42
+ });
43
+ //]]></script>
44
+ <%=submit_tag l(:search) %>
45
+ </p>
46
+
47
+ <% end %>
48
+ <% end %>
49
+
50
+
6
51
  <table>
7
52
  <tr>
8
53
  <th><%=l :task %></th>
@@ -1,4 +1,4 @@
1
- <% @page_title = l(:weekly_work_sheet) + " " + @week.to_s + (user? ? " for #{user.login}" : '')%>
1
+ <% @page_title = l(:weekly_work_sheet) + " " + @week.to_s + (@user ? " for #{@user.name}" : '')%>
2
2
 
3
3
  <div id="spotlight">
4
4
  <% columns = 2 %>
@@ -1,7 +1,7 @@
1
1
  # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2
- one:
2
+ light_control:
3
3
  id: 1
4
4
  name: LightControl
5
- two:
5
+ m2m_server:
6
6
  id: 2
7
7
  name: M2M Server
@@ -4,7 +4,7 @@ first:
4
4
  task_id: 1
5
5
  started_at: 2007-06-12T13:35:00
6
6
  completed_at: 2007-06-12T14:35:00
7
- hours: 40.0
7
+ hours: 30.0
8
8
  work_account_id: 1
9
9
  started:
10
10
  id: 2
@@ -175,7 +175,7 @@ class TasksControllerTest < Test::Unit::TestCase
175
175
 
176
176
  def test_end_work
177
177
  before = Task.find(1)
178
- assert_equal 80, before.total_done
178
+ assert_equal 70, before.total_done
179
179
 
180
180
  post :end_work, :id => 1, :work => {:work_started_at_time => (Time.now - 3600).strftime('%H:%M')}
181
181
  assert_response :redirect
@@ -187,7 +187,7 @@ class TasksControllerTest < Test::Unit::TestCase
187
187
  'estimate[todo]' => 1
188
188
 
189
189
  after = Task.find(1)
190
- assert_equal 80, after.total_done
190
+ assert_equal 70, after.total_done
191
191
  end
192
192
 
193
193
  def test_move_to__subtask_to_top
@@ -215,4 +215,14 @@ class TasksControllerTest < Test::Unit::TestCase
215
215
  assert after.work_started?
216
216
  end
217
217
 
218
+ def test_start_work_xhr
219
+ # raise "This test fails alone, but not with other tests..."
220
+ task_id = tasks(:first).id
221
+
222
+ xhr :post, :start_work, :id => task_id
223
+
224
+ after = Task.find(task_id)
225
+ assert after.work_started?
226
+ end
227
+
218
228
  end
@@ -13,7 +13,7 @@ class WorkAccountsControllerTest < Test::Unit::TestCase
13
13
  @response = ActionController::TestResponse.new
14
14
  @request.session[:user_id] = 1000001
15
15
 
16
- @first_id = work_accounts(:one).id
16
+ @first_id = work_accounts(:light_control).id
17
17
  end
18
18
 
19
19
  def test_index
@@ -5,10 +5,15 @@ class WorkTest < Test::Unit::TestCase
5
5
  include UserSystem
6
6
 
7
7
  main_scenario
8
+
9
+ def teardown
10
+ Thread.current[:user] = nil
11
+ end
8
12
 
9
13
  def test_work_totals_for_week
14
+ Thread.current[:user] = users(:tesla)
10
15
  # Week 24 is from
11
- work_totals = Work.work_totals_for_week(2007, 24, 1000001)
16
+ work_totals = Work.work_totals_for_week(2007, 24, users(:tesla))
12
17
  assert_equal 1, work_totals.size
13
18
  assert_equal Array, work_totals[1].class
14
19
  assert_equal 2, work_totals[1].size
@@ -16,6 +21,23 @@ class WorkTest < Test::Unit::TestCase
16
21
  assert_equal Array, work_totals[1][1].class
17
22
  assert_equal 0, work_totals[1][1][0]
18
23
  assert_equal 40, work_totals[1][1][1]
24
+ assert_equal 8, work_totals[1][1][2]
25
+ assert_equal 0, work_totals[1][1][3]
26
+ assert_equal 0, work_totals[1][1][4]
27
+ assert_equal 0, work_totals[1][1][5]
28
+ assert_equal 0, work_totals[1][1][6]
29
+ end
30
+
31
+ def test_work_totals_for_week_anonymously
32
+ # Week 24 is from
33
+ work_totals = Work.work_totals_for_week(2007, 24, nil)
34
+ assert_equal 1, work_totals.size
35
+ assert_equal Array, work_totals[1].class
36
+ assert_equal 2, work_totals[1].size
37
+ assert_equal Array, work_totals[1][0].class
38
+ assert_equal Array, work_totals[1][1].class
39
+ assert_equal 0, work_totals[1][1][0]
40
+ assert_equal 30, work_totals[1][1][1]
19
41
  assert_equal 0, work_totals[1][1][2]
20
42
  assert_equal 0, work_totals[1][1][3]
21
43
  assert_equal 0, work_totals[1][1][4]
@@ -27,14 +49,24 @@ class WorkTest < Test::Unit::TestCase
27
49
  Thread.current[:user] = users(:tesla)
28
50
  assert_equal 1, Work.find_work_for_day(Date.parse('2007-06-12')).size
29
51
  end
30
-
52
+
53
+ def test_works_for_week_by_work_account
54
+ Thread.current[:user] = users(:tesla)
55
+ work_totals = Work.works_for_week_by_work_account(2007, 24, users(:tesla))
56
+ assert_equal({work_accounts(:light_control) => [nil, BigDecimal('40'), BigDecimal('8'), nil, nil, nil, nil]}, work_totals)
57
+ end
58
+
59
+ def test_works_for_week_by_work_account_anonymous
60
+ work_totals = Work.works_for_week_by_work_account(2007, 24, nil)
61
+ assert_equal({work_accounts(:light_control) => [nil, BigDecimal('30'), nil, nil, nil, nil, nil]}, work_totals)
62
+ end
63
+
31
64
  private
32
65
 
33
66
  # TODO (uwe): This method should be removed
34
67
  # It is here only because ClassTableInheritanceInRails broke reading fixtures by name
35
68
  def users(login)
36
69
  super(login)
37
- end
38
-
70
+ end
39
71
 
40
72
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: backlog
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.21.3
4
+ version: 0.22.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Uwe Kubosch
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-02-13 00:00:00 +01:00
12
+ date: 2008-02-14 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -246,6 +246,7 @@ files:
246
246
  - app/models/user.rb
247
247
  - app/models/configuration.rb
248
248
  - app/models/chart.rb
249
+ - app/models/report_filter.rb
249
250
  - app/models/group.rb
250
251
  - app/models/work_lock_subscription.rb
251
252
  - app/models/backlog.rb