backlog 0.21.3 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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