diff --git a/app/models/rate.rb b/app/models/rate.rb index 2540200..c8c0a29 100644 --- a/app/models/rate.rb +++ b/app/models/rate.rb @@ -100,4 +100,9 @@ class Rate < ActiveRecord::Base raise Rate::InvalidParameterException.new("date must be a valid Date string (e.g. YYYY-MM-DD)") end end + + if Rails.env.test? + public + generator_for :date_in_effect => Date.today + end end diff --git a/config/locales/en.yml b/config/locales/en.yml index 0c2ed3a..f8c9ed7 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -7,3 +7,4 @@ en: rate_error_user_not_found: User not found rate_label_set_rate: Set Rate rate_label_default: Default Rate + rate_cost: Cost diff --git a/init.rb b/init.rb index 165f46e..4720b83 100644 --- a/init.rb +++ b/init.rb @@ -31,7 +31,9 @@ Redmine::Plugin.register :redmine_rate do permission :view_rate, { } end +require 'redmine_rate/hooks/timesheet_hook_helper' require 'redmine_rate/hooks/plugin_timesheet_views_timesheets_time_entry_row_class_hook' require 'redmine_rate/hooks/plugin_timesheet_views_timesheet_group_header_hook' require 'redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_hook' require 'redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_sum_hook' +require 'redmine_rate/hooks/plugin_timesheet_view_timesheets_report_header_tags_hook' diff --git a/lib/redmine_rate/hooks/plugin_timesheet_view_timesheets_report_header_tags_hook.rb b/lib/redmine_rate/hooks/plugin_timesheet_view_timesheets_report_header_tags_hook.rb new file mode 100644 index 0000000..8113526 --- /dev/null +++ b/lib/redmine_rate/hooks/plugin_timesheet_view_timesheets_report_header_tags_hook.rb @@ -0,0 +1,11 @@ +module RedmineRate + module Hooks + class PluginTimesheetViewTimesheetsReportHeaderTagsHook < Redmine::Hook::ViewListener + def plugin_timesheet_view_timesheets_report_header_tags(context={}) + return content_tag(:style, + 'tr.missing-rate td.cost { color: red; }', + :type => 'text/css') + end + end + end +end diff --git a/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_group_header_hook.rb b/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_group_header_hook.rb index 8edde5b..3cd739c 100644 --- a/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_group_header_hook.rb +++ b/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_group_header_hook.rb @@ -2,7 +2,7 @@ module RedmineRate module Hooks class PluginTimesheetViewsTimesheetGroupHeaderHook < Redmine::Hook::ViewListener def plugin_timesheet_views_timesheet_group_header(context={}) - return '' + return content_tag(:th, l(:rate_cost), :width => '8%') end end end diff --git a/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_hook.rb b/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_hook.rb index 4254428..e99d57d 100644 --- a/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_hook.rb +++ b/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_hook.rb @@ -1,9 +1,18 @@ module RedmineRate module Hooks class PluginTimesheetViewsTimesheetTimeEntryHook < Redmine::Hook::ViewListener + include TimesheetHookHelper + def plugin_timesheet_views_timesheet_time_entry(context={}) - return '' + cost = cost_item(context[:time_entry]) + if cost + td_cell(number_to_currency(cost)) + else + td_cell(' ') + end + end + end end end diff --git a/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_sum_hook.rb b/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_sum_hook.rb index 67f57a1..5ad9108 100644 --- a/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_sum_hook.rb +++ b/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_sum_hook.rb @@ -1,8 +1,16 @@ module RedmineRate module Hooks class PluginTimesheetViewsTimesheetTimeEntrySumHook < Redmine::Hook::ViewListener + include TimesheetHookHelper + def plugin_timesheet_views_timesheet_time_entry_sum(context={}) - return '' + time_entries = context[:time_entries] + costs = time_entries.collect {|time_entry| cost_item(time_entry)}.compact.sum + if costs >= 0 + return td_cell(number_to_currency(costs)) + else + return td_cell(' ') + end end end end diff --git a/lib/redmine_rate/hooks/plugin_timesheet_views_timesheets_time_entry_row_class_hook.rb b/lib/redmine_rate/hooks/plugin_timesheet_views_timesheets_time_entry_row_class_hook.rb index 0b4ea33..af953ce 100644 --- a/lib/redmine_rate/hooks/plugin_timesheet_views_timesheets_time_entry_row_class_hook.rb +++ b/lib/redmine_rate/hooks/plugin_timesheet_views_timesheets_time_entry_row_class_hook.rb @@ -1,8 +1,20 @@ module RedmineRate module Hooks class PluginTimesheetViewsTimesheetsTimeEntryRowClassHook < Redmine::Hook::ViewListener + include TimesheetHookHelper + def plugin_timesheet_views_timesheets_time_entry_row_class(context={}) - return '' + time_entry = context[:time_entry] + return "" unless time_entry + + cost = cost_item(time_entry) + return "" unless cost # Permissions + + if cost && cost <= 0 + return "missing-rate" + else + return "" + end end end end diff --git a/lib/redmine_rate/hooks/timesheet_hook_helper.rb b/lib/redmine_rate/hooks/timesheet_hook_helper.rb new file mode 100644 index 0000000..6f7aa2d --- /dev/null +++ b/lib/redmine_rate/hooks/timesheet_hook_helper.rb @@ -0,0 +1,14 @@ +module TimesheetHookHelper + # Returns the cost of a time entry, checking user permissions + def cost_item(time_entry) + if User.current.logged? && (User.current.allowed_to?(:view_rate, time_entry.project) || User.current.admin?) + return time_entry.cost + else + return nil + end + end + + def td_cell(html) + return content_tag(:td, html, :align => 'right', :class => 'cost') + end +end diff --git a/test/unit/lib/redmine_rate/hooks/plugin_timesheet_view_timesheets_report_header_tags_hook_test.rb b/test/unit/lib/redmine_rate/hooks/plugin_timesheet_view_timesheets_report_header_tags_hook_test.rb new file mode 100644 index 0000000..cedbc5f --- /dev/null +++ b/test/unit/lib/redmine_rate/hooks/plugin_timesheet_view_timesheets_report_header_tags_hook_test.rb @@ -0,0 +1,26 @@ +require File.dirname(__FILE__) + '/../../../../test_helper' + +class RedmineRate::Hooks::PluginTimesheetViewTimesheetsReportHeaderTagsTest < ActionController::TestCase + include Redmine::Hook::Helper + + def controller + @controller ||= ApplicationController.new + @controller.response ||= ActionController::TestResponse.new + @controller + end + + def request + @request ||= ActionController::TestRequest.new + end + + def hook(args={}) + call_hook :plugin_timesheet_view_timesheets_report_header_tags, args + end + + context "#plugin_timesheet_view_timesheets_report_header_tags" do + should "return a css string" do + @response.body = hook + assert_select "style", :text => /missing-rate/ + end + end +end diff --git a/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_group_header_hook_test.rb b/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_group_header_hook_test.rb index 30d51f6..5b2f633 100644 --- a/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_group_header_hook_test.rb +++ b/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_group_header_hook_test.rb @@ -18,9 +18,9 @@ class RedmineRate::Hooks::PluginTimesheetViewsTimesheetGroupHeaderTest < ActionC end context "#plugin_timesheet_views_timesheet_group_header" do - should "return an empty string" do + should "render the cost table header" do @response.body = hook - assert @response.body.blank? + assert_select "th", :text => "Cost" end end end diff --git a/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_hook_test.rb b/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_hook_test.rb index 3dcfb94..e924055 100644 --- a/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_hook_test.rb +++ b/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_hook_test.rb @@ -18,9 +18,30 @@ class RedmineRate::Hooks::PluginTimesheetViewsTimesheetTimeEntryTest < ActionCon end context "#plugin_timesheet_views_timesheet_time_entry" do - should "return an empty string" do - @response.body = hook - assert @response.body.blank? + context "for users with view rate permission" do + should "render a cost cell showing the cost for the time entry" do + User.current = User.generate!(:admin => true) + rate = Rate.generate!(:amount => 100) + time_entry = TimeEntry.generate!(:hours => 2, :rate => rate) + + @response.body = hook(:time_entry => time_entry) + + assert_select 'td', :text => "$200.00" + + end end + + context "for users without view rate permission" do + should "render an empty cost cell" do + User.current = nil + rate = Rate.generate!(:amount => 100) + time_entry = TimeEntry.generate!(:hours => 2, :rate => rate) + + @response.body = hook(:time_entry => time_entry) + + assert_select 'td', :text => ' ' + + end + end end end diff --git a/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_sum_hook_test.rb b/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_sum_hook_test.rb index 7b714ae..3659b9b 100644 --- a/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_sum_hook_test.rb +++ b/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_sum_hook_test.rb @@ -18,9 +18,31 @@ class RedmineRate::Hooks::PluginTimesheetViewsTimesheetTimeEntrySumTest < Action end context "#plugin_timesheet_views_timesheet_time_entry_sum" do - should "return an empty string" do - @response.body = hook - assert @response.body.blank? + context "for users with view rate permission" do + should "render a cost cell showing the total cost for the time entries" do + User.current = User.generate!(:admin => true) + rate = Rate.generate!(:amount => 100) + time_entry1 = TimeEntry.generate!(:hours => 2, :rate => rate) + time_entry2 = TimeEntry.generate!(:hours => 10, :rate => rate) + + @response.body = hook(:time_entries => [time_entry1, time_entry2]) + + assert_select 'td', :text => "$1,200.00" + + end end + + context "for users without view rate permission" do + should "render an empty cost cell" do + User.current = nil + rate = Rate.generate!(:amount => 100) + time_entry = TimeEntry.generate!(:hours => 2, :rate => rate) + + @response.body = hook(:time_entries => [time_entry]) + + assert_select 'td', :text => '$0.00' + + end + end end end diff --git a/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheets_time_entry_row_class_hook_test.rb b/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheets_time_entry_row_class_hook_test.rb index 57c5ac6..97dec90 100644 --- a/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheets_time_entry_row_class_hook_test.rb +++ b/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheets_time_entry_row_class_hook_test.rb @@ -18,9 +18,43 @@ class RedmineRate::Hooks::PluginTimesheetViewsTimesheetsTimeEntryRowClassTest < end context "#plugin_timesheet_views_timesheets_time_entry_row_class" do - should "return an empty string" do - @response.body = hook - assert @response.body.blank? + context "for users with view rate permission" do + setup do + User.current = User.generate!(:admin => true) + end + + should "render a missing rate css class if the time entry has no cost" do + time_entry = TimeEntry.generate!(:hours => 2, :rate => nil) + + assert_equal "missing-rate", hook(:time_entry => time_entry) + end + + should "render nothing if the time entry has a cost" do + rate = Rate.generate!(:amount => 100) + time_entry = TimeEntry.generate!(:hours => 2, :rate => rate) + + assert_equal "", hook(:time_entry => time_entry) + end end + + context "for users without view rate permission" do + setup do + User.current = nil + end + + should "render nothing if the time entry has no cost" do + time_entry = TimeEntry.generate!(:hours => 2, :rate => nil) + + assert_equal "", hook(:time_entry => time_entry) + end + + should "render nothing if the time entry has a cost" do + rate = Rate.generate!(:amount => 100) + time_entry = TimeEntry.generate!(:hours => 2, :rate => rate) + + assert_equal "", hook(:time_entry => time_entry) + end + end + end end