Normalise syntax with Rubocop

Signed-off-by: Alex Coles <alex@alexbcoles.com>
pull/6827/head
Alex Coles 9 years ago
parent 16fb352d8d
commit ccb4268793
  1. 31
      app/controllers/cost_objects_controller.rb
  2. 26
      app/controllers/cost_types_controller.rb
  3. 44
      app/controllers/costlog_controller.rb
  4. 24
      app/controllers/hourly_rates_controller.rb
  5. 38
      app/helpers/cost_objects_helper.rb
  6. 26
      app/helpers/costlog_helper.rb
  7. 8
      app/models/activity/cost_object_activity_provider.rb
  8. 18
      app/models/cost_entry.rb
  9. 28
      app/models/cost_object.rb
  10. 14
      app/models/cost_rate.rb
  11. 14
      app/models/cost_type.rb
  12. 2
      app/models/costs_work_package_observer.rb
  13. 16
      app/models/default_hourly_rate.rb
  14. 8
      app/models/default_hourly_rate_observer.rb
  15. 17
      app/models/entry.rb
  16. 2
      app/models/fixed_cost_object.rb
  17. 25
      app/models/hourly_rate.rb
  18. 2
      app/models/journal/cost_object_journal.rb
  19. 11
      app/models/labor_budget_item.rb
  20. 5
      app/models/material_budget_item.rb
  21. 1
      app/models/rate.rb
  22. 12
      app/models/rate_observer.rb
  23. 22
      app/models/variable_cost_object.rb
  24. 30
      config/routes.rb
  25. 149
      db/migrate/20121022124254_aggregated_costs_migrations.rb
  26. 5
      db/migrate/20130916094369_legacy_issues_costs_data_to_work_packages.rb
  27. 12
      db/migrate/20130918084158_add_cost_object_journals.rb
  28. 4
      db/migrate/20130918160542_add_journal_columns_to_time_entry_journals.rb
  29. 9
      db/migrate/20130918180542_legacy_variable_cost_object_journal_data.rb
  30. 32
      features/step_definitions/cost_object_steps.rb
  31. 79
      features/step_definitions/cost_steps.rb
  32. 32
      features/step_definitions/cost_type_steps.rb
  33. 2
      features/step_definitions/disabled_scenarios.rb
  34. 12
      features/step_definitions/hourly_rates_steps.rb
  35. 2
      features/support/path.rb
  36. 2
      lib/open_project/costs.rb
  37. 5
      lib/open_project/costs/attributes_helper.rb
  38. 51
      lib/open_project/costs/engine.rb
  39. 5
      lib/open_project/costs/hooks/project_hook.rb
  40. 12
      lib/open_project/costs/hooks/work_package_hook.rb
  41. 18
      lib/open_project/costs/hooks/work_packages_show_attributes.rb
  42. 2
      lib/open_project/costs/patches/application_helper_patch.rb
  43. 15
      lib/open_project/costs/patches/permitted_params_patch.rb
  44. 1
      lib/open_project/costs/patches/project_patch.rb
  45. 1
      lib/open_project/costs/patches/projects_controller_patch.rb
  46. 12
      lib/open_project/costs/patches/query_patch.rb
  47. 11
      lib/open_project/costs/patches/role_patch.rb
  48. 16
      lib/open_project/costs/patches/time_entry_patch.rb
  49. 21
      lib/open_project/costs/patches/user_patch.rb
  50. 4
      lib/open_project/costs/patches/users_helper_patch.rb
  51. 21
      lib/open_project/costs/patches/work_package_patch.rb
  52. 1
      lib/open_project/costs/patches/work_package_schema_patch.rb
  53. 9
      lib/open_project/costs/patches/work_packages_helper_patch.rb
  54. 2
      lib/open_project/costs/version.rb
  55. 25
      openproject-costs.gemspec
  56. 300
      spec/controllers/costlog_controller_spec.rb
  57. 16
      spec/controllers/hourly_rates_controller_spec.rb
  58. 3
      spec/controllers/work_packages_bulk_controller_spec.rb
  59. 6
      spec/factories/cost_entry_factory.rb
  60. 6
      spec/factories/cost_object_factory.rb
  61. 6
      spec/factories/cost_type_factory.rb
  62. 4
      spec/factories/variable_cost_object_factory.rb
  63. 2
      spec/features/hourly_rates_feature.rb
  64. 13
      spec/helpers/cost_objects_helper_spec.rb
  65. 22
      spec/lib/api/v3/budgets/budget_representer_spec.rb
  66. 4
      spec/lib/api/v3/cost_entries/work_package_costs_by_type_representer_spec.rb
  67. 1
      spec/lib/api/v3/path_helper_spec.rb
  68. 93
      spec/lib/api/v3/work_packages/work_package_representer_spec.rb
  69. 4
      spec/lib/api/v3/work_packages/work_package_schema_representer_spec.rb
  70. 122
      spec/models/cost_entry_spec.rb
  71. 18
      spec/models/cost_type_spec.rb
  72. 10
      spec/models/default_hourly_rate_spec.rb
  73. 10
      spec/models/hourly_rate_spec.rb
  74. 50
      spec/models/labor_budget_item_spec.rb
  75. 171
      spec/models/permitted_params_spec.rb
  76. 28
      spec/models/rate_spec.rb
  77. 80
      spec/models/time_entry_spec.rb
  78. 72
      spec/models/user_deletion_spec.rb
  79. 59
      spec/models/user_spec.rb
  80. 8
      spec/models/variable_cost_object_spec.rb
  81. 50
      spec/models/work_package/ask_before_destruction_spec.rb
  82. 20
      spec/models/work_package_spec.rb
  83. 14
      spec/requests/api/work_packages/work_package_form_resource_spec.rb
  84. 8
      spec/requests/api/work_packages/work_package_resource_spec.rb
  85. 73
      spec/routing/cost_objects_routing_spec.rb
  86. 60
      spec/routing/cost_types_routing_spec.rb
  87. 58
      spec/routing/costlog_routing_spec.rb
  88. 50
      spec/routing/hourly_rates_routing_spec.rb
  89. 4
      spec/spec_helper.rb

@ -18,7 +18,6 @@
#++
class CostObjectsController < ApplicationController
before_filter :find_cost_object, only: [:show, :edit, :update, :copy]
before_filter :find_cost_objects, only: :destroy
before_filter :find_project, only: [
@ -32,7 +31,7 @@ class CostObjectsController < ApplicationController
# unrestricted actions
:index,
:update_material_budget_item, :update_labor_budget_item
]
]
helper :sort
include SortHelper
@ -52,31 +51,30 @@ class CostObjectsController < ApplicationController
def index
respond_to do |format|
format.html { }
format.html do end
format.csv { limit = Setting.work_packages_export_limit.to_i }
end
sort_columns = {'id' => "#{CostObject.table_name}.id",
'subject' => "#{CostObject.table_name}.subject",
'fixed_date' => "#{CostObject.table_name}.fixed_date"
sort_columns = { 'id' => "#{CostObject.table_name}.id",
'subject' => "#{CostObject.table_name}.subject",
'fixed_date' => "#{CostObject.table_name}.fixed_date"
}
sort_init "id", "desc"
sort_init 'id', 'desc'
sort_update sort_columns
condition = Project.allowed_to_condition(User.current,
:view_cost_objects,
project: @project)
@cost_objects = CostObject.order(sort_clause)
.includes(:project, :author)
.where(condition)
.page(page_param)
.per_page(per_page_param)
.includes(:project, :author)
.where(condition)
.page(page_param)
.per_page(per_page_param)
respond_to do |format|
format.html { render action: 'index', layout: !request.xhr? }
format.html do render action: 'index', layout: !request.xhr? end
format.csv { send_data(cost_objects_to_csv(@cost_objects), type: 'text/csv; header=present', filename: 'export.csv') }
end
end
@ -148,7 +146,6 @@ class CostObjectsController < ApplicationController
# Please remove code where necessary
# check whether this method is needed at all
@cost_object.attributes = permitted_params.cost_object if params[:cost_object]
end
def update
@ -156,7 +153,6 @@ class CostObjectsController < ApplicationController
# something as a starting point for separating the two
# Please go ahead and start removing code where necessary
# TODO: use better way to prevent mass assignment errors
params[:cost_object].delete(:kind)
@cost_object.attributes = permitted_params.cost_object if params[:cost_object]
@ -166,7 +162,7 @@ class CostObjectsController < ApplicationController
render_attachment_warning_if_needed(@cost_object)
flash[:notice] = l(:notice_successful_update)
redirect_to(params[:back_to] || {action: 'show', id: @cost_object})
redirect_to(params[:back_to] || { action: 'show', id: @cost_object })
else
render action: 'edit'
end
@ -222,7 +218,8 @@ class CostObjectsController < ApplicationController
end
end
private
private
def create_cost_object(kind)
case kind
when FixedCostObject.name

@ -18,7 +18,6 @@
#++
class CostTypesController < ApplicationController
# Allow only admins here
before_filter :require_admin
before_filter :find_cost_type, only: [:edit, :update, :set_rate, :destroy, :restore]
@ -31,9 +30,9 @@ class CostTypesController < ApplicationController
def index
sort_init 'name', 'asc'
sort_columns = { "name" => "#{CostType.table_name}.name",
"unit" => "#{CostType.table_name}.unit",
"unit_plural" => "#{CostType.table_name}.unit_plural" }
sort_columns = { 'name' => "#{CostType.table_name}.name",
'unit' => "#{CostType.table_name}.unit",
'unit_plural' => "#{CostType.table_name}.unit_plural" }
sort_update sort_columns
@cost_types = CostType.find :all, order: sort_clause
@ -50,7 +49,7 @@ class CostTypesController < ApplicationController
end
def edit
render action: "edit", layout: !request.xhr?
render action: 'edit', layout: !request.xhr?
end
def update
@ -60,7 +59,7 @@ class CostTypesController < ApplicationController
flash[:notice] = l(:notice_successful_update)
redirect_back_or_default(action: 'index')
else
render action: "edit", layout: !request.xhr?
render action: 'edit', layout: !request.xhr?
end
rescue ActiveRecord::StaleObjectError
# Optimistic locking exception
@ -68,11 +67,11 @@ class CostTypesController < ApplicationController
end
def new
@cost_type = CostType.new()
@cost_type = CostType.new
@cost_type.rates.build({valid_from: Date.today}) if @cost_type.rates.empty?
@cost_type.rates.build(valid_from: Date.today) if @cost_type.rates.empty?
render action: "edit", layout: !request.xhr?
render action: 'edit', layout: !request.xhr?
end
def create
@ -82,8 +81,8 @@ class CostTypesController < ApplicationController
flash[:notice] = l(:notice_successful_update)
redirect_back_or_default(action: 'index')
else
@cost_type.rates.build({valid_from: Date.today}) if @cost_type.rates.empty?
render action: "edit", layout: !request.xhr?
@cost_type.rates.build(valid_from: Date.today) if @cost_type.rates.empty?
render action: 'edit', layout: !request.xhr?
end
rescue ActiveRecord::StaleObjectError
# Optimistic locking exception
@ -132,7 +131,8 @@ class CostTypesController < ApplicationController
end
end
private
private
def find_cost_type
@cost_type = CostType.find(params[:id])
rescue ActiveRecord::RecordNotFound
@ -140,6 +140,6 @@ private
end
def default_breadcrumb
CostType.model_name.human(count:2)
CostType.model_name.human(count: 2)
end
end

@ -18,17 +18,16 @@
#++
class CostlogController < ApplicationController
menu_item :work_packages
before_filter :find_project, :authorize, only: [:edit,
:new,
:create,
:update,
:destroy]
:new,
:create,
:update,
:destroy]
before_filter :find_associated_objects, only: [:create,
:update]
:update]
before_filter :find_optional_project, only: [:report,
:index]
:index]
helper :sort
include SortHelper
@ -52,14 +51,14 @@ class CostlogController < ApplicationController
elsif @work_package.nil?
cond << @project.project_condition(Setting.display_subprojects_work_packages?)
else
root_cond = "#{WorkPackage.table_name}.root_id #{(@work_package.root_id.nil?) ? "IS NULL" : "= #{@work_package.root_id}"}"
root_cond = "#{WorkPackage.table_name}.root_id #{(@work_package.root_id.nil?) ? 'IS NULL' : "= #{@work_package.root_id}"}"
cond << "#{root_cond} AND #{WorkPackage.table_name}.lft >= #{@work_package.lft} AND #{WorkPackage.table_name}.rgt <= #{@work_package.rgt}"
end
cond << Project.allowed_to_condition(User.current, :view_cost_entries, project: @project)
if @cost_type
cond << ["#{CostEntry.table_name}.cost_type_id = ?", @cost_type.id ]
cond << ["#{CostEntry.table_name}.cost_type_id = ?", @cost_type.id]
end
retrieve_date_range
@ -67,11 +66,11 @@ class CostlogController < ApplicationController
respond_to do |format|
format.html {
@entries = CostEntry.includes(:project, :cost_type, :user, {work_package: :type})
.where(cond.conditions)
.order(sort_clause)
.page(page_param)
.per_page(per_page_param)
@entries = CostEntry.includes(:project, :cost_type, :user, work_package: :type)
.where(cond.conditions)
.order(sort_clause)
.page(page_param)
.per_page(per_page_param)
render layout: !request.xhr?
}
@ -123,7 +122,7 @@ class CostlogController < ApplicationController
end
end
verify method: :delete, only: :destroy, render: {nothing: true, status: :method_not_allowed }
verify method: :delete, only: :destroy, render: { nothing: true, status: :method_not_allowed }
def destroy
render_404 and return unless @cost_entry
render_403 and return unless @cost_entry.editable_by?(User.current)
@ -143,11 +142,12 @@ class CostlogController < ApplicationController
@cost_type = CostType.find(params[:cost_type_id]) unless params[:cost_type_id].empty?
if request.xhr?
render partial: "cost_type_unit_plural", layout: false
render partial: 'cost_type_unit_plural', layout: false
end
end
private
private
def find_project
# copied from timelog_controller.rb
if params[:id]
@ -205,7 +205,8 @@ private
def retrieve_date_range
# Mostly copied from timelog_controller.rb
@free_period = false
@from, @to = nil, nil
@from = nil
@to = nil
if params[:period_type] == '1' || (params[:period_type].nil? && !params[:period].nil?)
case params[:period].to_s
@ -214,10 +215,10 @@ private
when 'yesterday'
@from = @to = Date.today - 1
when 'current_week'
@from = Date.today - (Date.today.cwday - 1)%7
@from = Date.today - (Date.today.cwday - 1) % 7
@to = @from + 6
when 'last_week'
@from = Date.today - 7 - (Date.today.cwday - 1)%7
@from = Date.today - 7 - (Date.today.cwday - 1) % 7
@to = @from + 6
when '7_days'
@from = Date.today - 7
@ -239,13 +240,12 @@ private
begin; @from = params[:from].to_s.to_date unless params[:from].blank?; rescue; end
begin; @to = params[:to].to_s.to_date unless params[:to].blank?; rescue; end
@free_period = true
else
# default
end
@from, @to = @to, @from if @from && @to && @from > @to
@from ||= (CostEntry.minimum(:spent_on, include: [:project, :user], conditions: Project.allowed_to_condition(User.current, :view_cost_entries)) || Date.today) - 1
@to ||= (CostEntry.maximum(:spent_on, include: [:project, :user], conditions: Project.allowed_to_condition(User.current, :view_cost_entries)) || Date.today)
@to ||= (CostEntry.maximum(:spent_on, include: [:project, :user], conditions: Project.allowed_to_condition(User.current, :view_cost_entries)) || Date.today)
end
def new_default_cost_entry

@ -18,7 +18,6 @@
#++
class HourlyRatesController < ApplicationController
helper :users
helper :sort
include SortHelper
@ -39,8 +38,8 @@ class HourlyRatesController < ApplicationController
return deny_access unless User.current.allowed_to?(:view_hourly_rates, @project, for: @user)
@rates = HourlyRate.all(
conditions: { user_id: @user, project_id: @project },
order: "#{HourlyRate.table_name}.valid_from desc")
conditions: { user_id: @user, project_id: @project },
order: "#{HourlyRate.table_name}.valid_from desc")
else
@rates = HourlyRate.history_for_user(@user, true)
@rates_default = @rates.delete(nil)
@ -60,15 +59,15 @@ class HourlyRatesController < ApplicationController
if @project.nil?
@rates = DefaultHourlyRate.all(
conditions: {user_id: @user},
conditions: { user_id: @user },
order: "#{DefaultHourlyRate.table_name}.valid_from desc")
@rates << @user.default_rates.build({valid_from: Date.today}) if @rates.empty?
@rates << @user.default_rates.build(valid_from: Date.today) if @rates.empty?
else
@rates = @user.rates.select{|r| r.project_id == @project.id}.sort { |a,b| b.valid_from <=> a.valid_from }
@rates << @user.rates.build({valid_from: Date.today, project: @project}) if @rates.empty?
@rates = @user.rates.select { |r| r.project_id == @project.id }.sort { |a, b| b.valid_from <=> a.valid_from }
@rates << @user.rates.build(valid_from: Date.today, project: @project) if @rates.empty?
end
render action: "edit", layout: !request.xhr?
render action: 'edit', layout: !request.xhr?
end
def update
@ -101,12 +100,12 @@ class HourlyRatesController < ApplicationController
else
if @project.nil?
@rates = @user.default_rates
@rates << @user.default_rates.build({valid_from: Date.today}) if @rates.empty?
@rates << @user.default_rates.build(valid_from: Date.today) if @rates.empty?
else
@rates = @user.rates.select{|r| r.project_id == @project.id}.sort { |a,b| b.valid_from <=> a.valid_from }
@rates << @user.rates.build({valid_from: Date.today, project: @project}) if @rates.empty?
@rates = @user.rates.select { |r| r.project_id == @project.id }.sort { |a, b| b.valid_from <=> a.valid_from }
@rates << @user.rates.build(valid_from: Date.today, project: @project) if @rates.empty?
end
render action: "edit", layout: !request.xhr?
render action: 'edit', layout: !request.xhr?
end
end
@ -167,5 +166,4 @@ class HourlyRatesController < ApplicationController
rescue ActiveRecord::RecordNotFound
render_404
end
end

@ -25,25 +25,25 @@ module CostObjectsHelper
# Check if the current user is allowed to manage the budget. Based on Role
# permissions.
def allowed_management?
return User.current.allowed_to?(:edit_cost_objects, @project)
User.current.allowed_to?(:edit_cost_objects, @project)
end
def cost_objects_to_csv(cost_objects)
CSV.generate(col_sep: l(:general_csv_separator)) do |csv|
# csv header fields
headers = [ "#",
Project.model_name.human,
CostObject.human_attribute_name(:subject),
CostObject.human_attribute_name(:author),
CostObject.human_attribute_name(:fixed_date),
VariableCostObject.human_attribute_name(:material_budget),
VariableCostObject.human_attribute_name(:labor_budget),
CostObject.human_attribute_name(:spent),
CostObject.human_attribute_name(:created_on),
CostObject.human_attribute_name(:updated_on),
CostObject.human_attribute_name(:description)
]
csv << headers.collect {|c| begin; c.to_s.encode('UTF-8'); rescue; c.to_s; end }
headers = ['#',
Project.model_name.human,
CostObject.human_attribute_name(:subject),
CostObject.human_attribute_name(:author),
CostObject.human_attribute_name(:fixed_date),
VariableCostObject.human_attribute_name(:material_budget),
VariableCostObject.human_attribute_name(:labor_budget),
CostObject.human_attribute_name(:spent),
CostObject.human_attribute_name(:created_on),
CostObject.human_attribute_name(:updated_on),
CostObject.human_attribute_name(:description)
]
csv << headers.collect { |c| begin; c.to_s.encode('UTF-8'); rescue; c.to_s; end }
# csv lines
cost_objects.each do |cost_object|
fields = [cost_object.id,
@ -51,14 +51,14 @@ module CostObjectsHelper
cost_object.subject,
cost_object.author.name,
format_date(cost_object.fixed_date),
cost_object.kind == "VariableCostObject" ? number_to_currency(cost_object.material_budget) : "",
cost_object.kind == "VariableCostObject" ? number_to_currency(cost_object.labor_budget) : "",
cost_object.kind == "VariableCostObject" ? number_to_currency(cost_object.spent) : "",
cost_object.kind == 'VariableCostObject' ? number_to_currency(cost_object.material_budget) : '',
cost_object.kind == 'VariableCostObject' ? number_to_currency(cost_object.labor_budget) : '',
cost_object.kind == 'VariableCostObject' ? number_to_currency(cost_object.spent) : '',
format_time(cost_object.created_on),
format_time(cost_object.updated_on),
cost_object.description
]
csv << fields.collect {|c| begin; c.to_s.encode('UTF-8'); rescue; c.to_s; end }
]
csv << fields.collect { |c| begin; c.to_s.encode('UTF-8'); rescue; c.to_s; end }
end
end
end

@ -22,8 +22,8 @@ module CostlogHelper
def render_costlog_breadcrumb
links = []
links << link_to(l(:label_project_all), {project_id: nil, work_package_id: nil})
links << link_to(h(@project), {project_id: @project, work_package_id: nil}) if @project
links << link_to(l(:label_project_all), project_id: nil, work_package_id: nil)
links << link_to(h(@project), project_id: @project, work_package_id: nil) if @project
links << link_to_work_package(@work_package, subject: false) if @work_package
breadcrumb links
end
@ -36,33 +36,33 @@ module CostlogHelper
cost_types.sort
end
collection = []
collection << [ "--- #{l(:actionview_instancetag_blank_option)} ---", '' ] unless cost_types.detect(&:is_default?)
cost_types.each { |t| collection << [t.name, t.id] }
collection << ["--- #{l(:actionview_instancetag_blank_option)} ---", ''] unless cost_types.detect(&:is_default?)
cost_types.each do |t| collection << [t.name, t.id] end
collection
end
def user_collection_for_select_options(options = {})
def user_collection_for_select_options(_options = {})
users = @project.possible_assignees
collection = []
users.each { |u| collection << [u.name, u.id] }
users.each do |u| collection << [u.name, u.id] end
collection
end
def extended_progress_bar(pcts, options={})
def extended_progress_bar(pcts, options = {})
return progress_bar(pcts, options) unless pcts.is_a?(Numeric) && pcts > 100
width = options[:width] || '100px;'
legend = options[:legend] || ''
content_tag('table',
content_tag('tr',
content_tag('td', '', style: "width: #{((100.0 / pcts) * 100).round}%;", class: 'closed') +
content_tag('td', '', style: "width: #{100.0 - ((100.0 / pcts) * 100).round}%;", class: 'exceeded')
), class: 'progress', style: "width: #{width};") +
content_tag('tr',
content_tag('td', '', style: "width: #{((100.0 / pcts) * 100).round}%;", class: 'closed') +
content_tag('td', '', style: "width: #{100.0 - ((100.0 / pcts) * 100).round}%;", class: 'exceeded')
), class: 'progress', style: "width: #{width};") +
content_tag('p', legend, class: 'pourcent')
end
def clean_currency(value)
return nil if value.nil? || value == ""
return nil if value.nil? || value == ''
value = value.strip
value.gsub!(l(:currency_delimiter), '') if value.include?(l(:currency_delimiter)) && value.include?(l(:currency_separator))
@ -72,7 +72,7 @@ module CostlogHelper
def to_currency_with_empty(rate)
rate.nil? ?
"0.0" :
'0.0' :
number_to_currency(rate.rate)
end
end

@ -28,19 +28,19 @@ class Activity::CostObjectActivityProvider < Activity::BaseActivityProvider
]
end
def event_type(event, activity)
def event_type(_event, _activity)
'cost_object'
end
def event_title(event, activity)
def event_title(event, _activity)
"#{l(:label_cost_object)} ##{event['journable_id']}: #{event['cost_object_subject']}"
end
def event_path(event, activity)
def event_path(event, _activity)
url_helpers.cost_object_path(url_helper_parameter(event))
end
def event_url(event, activity)
def event_url(event, _activity)
url_helpers.cost_object_url(url_helper_parameter(event))
end

@ -18,14 +18,13 @@
#++
class CostEntry < ActiveRecord::Base
belongs_to :project
belongs_to :work_package
belongs_to :user
include ::OpenProject::Costs::DeletedUserFallback
belongs_to :cost_type
belongs_to :cost_object
belongs_to :rate, class_name: "CostRate"
belongs_to :rate, class_name: 'CostRate'
include ActiveModel::ForbiddenAttributesProtection
@ -47,7 +46,7 @@ class CostEntry < ActiveRecord::Base
scope :on_work_packages, ->(work_packages) { where(work_package_id: work_packages) }
def self.visible_condition(user, project)
%Q{ (#{Project.allowed_to_condition(user, :view_cost_entries, project: project)} OR
%{ (#{Project.allowed_to_condition(user, :view_cost_entries, project: project)} OR
(#{Project.allowed_to_condition(user, :view_own_cost_entries, project: project)} AND #{CostEntry.table_name}.user_id = #{user.id})) }
end
@ -56,12 +55,12 @@ class CostEntry < ActiveRecord::Base
view_cost_entries = CostEntry.visible_condition((args.first || User.current), args[1])
{ include: [:project, :user],
conditions: [view_cost_entries, view_cost_rates].join(" AND ")
conditions: [view_cost_entries, view_cost_rates].join(' AND ')
}
}
def after_initialize
if new_record? && self.cost_type.nil?
if new_record? && cost_type.nil?
if default_cost_type = CostType.default
self.cost_type_id = default_cost_type.id
end
@ -110,7 +109,7 @@ class CostEntry < ActiveRecord::Base
def real_costs
# This methods returns the actual assigned costs of the entry
self.overridden_costs || self.costs || self.calculated_costs
overridden_costs || costs || calculated_costs
end
def calculated_costs(rate_attr = nil)
@ -128,20 +127,19 @@ class CostEntry < ActiveRecord::Base
return
end
self.costs = self.calculated_costs(rate_attr)
self.costs = calculated_costs(rate_attr)
self.rate = rate_attr
end
def update_costs!(rate_attr = nil)
self.update_costs(rate_attr)
update_costs(rate_attr)
self.save!
end
def current_rate
self.cost_type.rate_at(self.spent_on)
cost_type.rate_at(self.spent_on)
end
# Returns true if the cost entry can be edited by usr, otherwise false
def editable_by?(usr)
usr.allowed_to?(:edit_cost_entries, project) ||

@ -20,7 +20,6 @@
# A CostObject is an item that is created as part of the project. These items
# contain a collection of work packages.
class CostObject < ActiveRecord::Base
belongs_to :author, class_name: 'User', foreign_key: 'author_id'
belongs_to :project
has_many :work_packages, dependent: :nullify
@ -35,9 +34,8 @@ class CostObject < ActiveRecord::Base
acts_as_journalized
acts_as_event type: 'cost-objects',
title: Proc.new {|o| "#{l(:label_cost_object)} ##{o.id}: #{o.subject}"},
url: Proc.new {|o| {controller: 'cost_objects', action: 'show', id: o.id}}
title: Proc.new { |o| "#{l(:label_cost_object)} ##{o.id}: #{o.subject}" },
url: Proc.new { |o| { controller: 'cost_objects', action: 'show', id: o.id } }
validates_presence_of :subject, :project, :author, :kind, :fixed_date
validates_length_of :subject, maximum: 255
@ -54,11 +52,11 @@ class CostObject < ActiveRecord::Base
def copy_from(arg)
if !arg.is_a?(Hash)
#turn args into an attributes hash if it is not already (which is the case when called from VariableCostObject)
# turn args into an attributes hash if it is not already (which is the case when called from VariableCostObject)
arg = (arg.is_a?(CostObject) ? arg : self.class.find(arg)).attributes.dup
end
arg.delete("id")
self.type = arg.delete("type")
arg.delete('id')
self.type = arg.delete('type')
self.attributes = arg
end
@ -77,10 +75,10 @@ class CostObject < ActiveRecord::Base
return 0 if version.nil? || version.fixed_work_packages.blank?
version.fixed_work_packages.each do |work_package|
work_package.update_attribute(:cost_object_id, self.id)
work_package.update_attribute(:cost_object_id, id)
end
return version.fixed_work_packages.size
version.fixed_work_packages.size
end
# Change the Cost Object type to another type. Valid types are
@ -91,7 +89,7 @@ class CostObject < ActiveRecord::Base
if [FixedCostObject.name, VariableCostObject.name].include?(to)
self.type = to
self.save!
return CostObject.find(self.id)
return CostObject.find(id)
else
return self
end
@ -118,23 +116,23 @@ class CostObject < ActiveRecord::Base
# Label of the current type for display in GUI. Virtual accessor that is overriden by subclasses.
def type_label
return l(:label_cost_object)
l(:label_cost_object)
end
# Amount of the budget spent. Expressed as as a percentage whole number
def budget_ratio
return 0.0 if self.budget.nil? || self.budget == 0.0
return ((self.spent / self.budget) * 100).round
return 0.0 if budget.nil? || budget == 0.0
((spent / budget) * 100).round
end
def css_classes
return "cost_object"
'cost_object'
end
def self.replace_author_with_deleted_user(user)
substitute = DeletedUser.first
self.update_all ['author_id = ?', substitute.id], ['author_id = ?', user.id]
update_all ['author_id = ?', substitute.id], ['author_id = ?', user.id]
end
def to_s

@ -23,23 +23,23 @@ class CostRate < Rate
validates_uniqueness_of :valid_from, scope: :cost_type_id
validate :change_of_cost_type_only_on_first_creation
def previous(reference_date = self.valid_from)
def previous(reference_date = valid_from)
# This might return a default rate
self.cost_type.rate_at(reference_date - 1)
cost_type.rate_at(reference_date - 1)
end
def next(reference_date = self.valid_from)
def next(reference_date = valid_from)
CostRate.find(
:first,
conditions: [ "cost_type_id = ? and valid_from > ?",
self.cost_type_id, reference_date],
order: "valid_from ASC"
conditions: ['cost_type_id = ? and valid_from > ?',
cost_type_id, reference_date],
order: 'valid_from ASC'
)
end
private
def change_of_cost_type_only_on_first_creation
errors.add :cost_type_id, :invalid if cost_type_id_changed? && ! self.new_record?
errors.add :cost_type_id, :invalid if cost_type_id_changed? && !self.new_record?
end
end

@ -20,7 +20,7 @@
class CostType < ActiveRecord::Base
has_many :material_budget_items
has_many :cost_entries, dependent: :destroy
has_many :rates, class_name: "CostRate", foreign_key: "cost_type_id", dependent: :destroy
has_many :rates, class_name: 'CostRate', foreign_key: 'cost_type_id', dependent: :destroy
validates_presence_of :name, :unit, :unit_plural
validates_uniqueness_of :name
@ -33,7 +33,7 @@ class CostType < ActiveRecord::Base
# finds the default CostType
def self.default
result = CostType.find(:first, conditions: { default: true})
result = CostType.find(:first, conditions: { default: true })
result ||= CostType.find(:first)
result
rescue ActiveRecord::RecordNotFound
@ -41,7 +41,7 @@ class CostType < ActiveRecord::Base
end
def is_default?
self.default
default
end
def <=>(cost_type)
@ -53,7 +53,7 @@ class CostType < ActiveRecord::Base
end
def rate_at(date)
CostRate.find(:first, conditions: [ "cost_type_id = ? and valid_from <= ?", id, date], order: "valid_from DESC")
CostRate.find(:first, conditions: ['cost_type_id = ? and valid_from <= ?', id, date], order: 'valid_from DESC')
rescue ActiveRecord::RecordNotFound
return nil
end
@ -67,7 +67,7 @@ class CostType < ActiveRecord::Base
end
def new_rate_attributes=(rate_attributes)
rate_attributes.each do |index, attributes|
rate_attributes.each do |_index, attributes|
attributes[:rate] = Rate.clean_currency(attributes[:rate])
rates.build(attributes)
end
@ -92,8 +92,6 @@ class CostType < ActiveRecord::Base
end
def save_rates
rates.each do |rate|
rate.save!
end
rates.each(&:save!)
end
end

@ -23,7 +23,7 @@ class CostsWorkPackageObserver < ActiveRecord::Observer
def after_update(work_package)
if work_package.project_id_changed?
# TODO: This only works with the global cost_rates
CostEntry.update_all({project_id: work_package.project_id}, {work_package_id: work_package.id})
CostEntry.update_all({ project_id: work_package.project_id }, work_package_id: work_package.id)
end
end
end

@ -23,25 +23,25 @@ class DefaultHourlyRate < Rate
validate :change_of_user_only_on_first_creation
before_save :convert_valid_from_to_date
def next(reference_date = self.valid_from)
def next(reference_date = valid_from)
DefaultHourlyRate.find(
:first,
conditions: [ "user_id = ? and valid_from > ?",
self.user_id, reference_date],
order: "valid_from ASC"
conditions: ['user_id = ? and valid_from > ?',
user_id, reference_date],
order: 'valid_from ASC'
)
end
def previous(reference_date = self.valid_from)
self.user.default_rate_at(reference_date - 1)
def previous(reference_date = valid_from)
user.default_rate_at(reference_date - 1)
end
def self.at_for_user(date, user_id)
user_id = user_id.id if user_id.is_a?(User)
find(:first,
conditions: [ "user_id = ? and valid_from <= ?", user_id, date],
order: "valid_from DESC")
conditions: ['user_id = ? and valid_from <= ?', user_id, date],
order: 'valid_from DESC')
end
private

@ -43,18 +43,18 @@ class DefaultHourlyRateObserver < ActiveRecord::Observer
(date1, date2) = order_dates(date1, date2)
# This gets an array of all the ids of the DefaultHourlyRates
default_rates = DefaultHourlyRate.find(:all, select: :id).inject([]){|r,d|r<<d.id}
default_rates = DefaultHourlyRate.find(:all, select: :id).inject([]) { |r, d| r << d.id }
if date1.nil? || date2.nil?
# we have only one date, query >=
conditions = [
"user_id = ? AND (rate_id IN (?) OR rate_id IS NULL) AND spent_on >= ?",
'user_id = ? AND (rate_id IN (?) OR rate_id IS NULL) AND spent_on >= ?',
@rate.user_id, default_rates, date1 || date2
]
else
# we have two dates, query between
conditions = [
"user_id = ? AND (rate_id IN (?) OR rate_id IS NULL) AND spent_on BETWEEN ? AND ?",
'user_id = ? AND (rate_id IN (?) OR rate_id IS NULL) AND spent_on BETWEEN ? AND ?',
@rate.user_id, default_rates, date1, date2 - 1
]
end
@ -100,6 +100,6 @@ class DefaultHourlyRateObserver < ActiveRecord::Observer
def after_destroy(rate)
o = Methods.new(rate)
o.update_entries(TimeEntry.find(:all, conditions: {rate_id: rate.id}))
o.update_entries(TimeEntry.find(:all, conditions: { rate_id: rate.id }))
end
end

@ -18,7 +18,7 @@
#++
module Entry
[TimeEntry, CostEntry].each { |e| e.send :include, self }
[TimeEntry, CostEntry].each do |e| e.send :include, self end
class Delegator < ActiveRecord::Base
self.abstract_class = true
@ -28,7 +28,8 @@ module Entry
end
def calculate(type, *args)
a, b = TimeEntry.calculate(type, *args), CostEntry.calculate(type, *args)
a = TimeEntry.calculate(type, *args)
b = CostEntry.calculate(type, *args)
case type
when :sum, :count then a + b
when :avg then (a + b) / 2
@ -43,17 +44,21 @@ module Entry
end
undef_method :create, :update, :delete, :destroy, :new, :update_counters,
:increment_counter, :decrement_counter
:increment_counter, :decrement_counter
%w[update_all destroy_all delete_all].each do |meth|
define_method(meth) { |*args| send_all(meth, *args) }
end
private
def find_initial(options) find_one :find_initial, options end
def find_last(options) find_one :find_last, options end
def find_initial(options) find_one :find_initial, options end
def find_last(options) find_one :find_last, options end
def find_every(options) find_many :find_every, options end
def find_from_ids(args, options) find_many :find_from_ids, options end
def find_from_ids(_args, options) find_many :find_from_ids, options end
def find_one(*args)
TimeEntry.send(*args) || CostEntry.send(*args)

@ -20,6 +20,6 @@
class FixedCostObject < CostObject
# Label of the current type for display in GUI.
def type_label
return l(:label_fixed_cost_object)
l(:label_fixed_cost_object)
end
end

@ -22,25 +22,24 @@ class HourlyRate < Rate
validates_presence_of :user_id, :project_id, :valid_from
validate :change_of_user_only_on_first_creation
def previous(reference_date = self.valid_from)
def previous(reference_date = valid_from)
# This might return a default rate
self.user.rate_at(reference_date - 1, self.project)
user.rate_at(reference_date - 1, project)
end
def next(reference_date = self.valid_from)
def next(reference_date = valid_from)
HourlyRate.find(
:first,
conditions: [ "user_id = ? and project_id = ? and valid_from > ?",
self.user_id, self.project_id, reference_date],
order: "valid_from ASC"
conditions: ['user_id = ? and project_id = ? and valid_from > ?',
user_id, project_id, reference_date],
order: 'valid_from ASC'
)
end
def self.history_for_user(usr, check_permissions = true)
rates = Hash.new
Project.has_module(:costs_module).active.visible.each do |project|
next if (check_permissions && !User.current.allowed_to?(:view_hourly_rates, project, {for_user: usr}))
next if check_permissions && !User.current.allowed_to?(:view_hourly_rates, project, for_user: usr)
rates[project] = HourlyRate.find(:all,
conditions: { user_id: usr, project_id: project },
@ -49,7 +48,7 @@ class HourlyRate < Rate
# FIXME: What permissions to apply here?
rates[nil] = DefaultHourlyRate.find(:all,
conditions: { user_id: usr},
conditions: { user_id: usr },
order: "#{DefaultHourlyRate.table_name}.valid_from desc")
rates
@ -60,14 +59,14 @@ class HourlyRate < Rate
unless project.nil?
rate = find(:first,
conditions: [ "user_id = ? and project_id = ? and valid_from <= ?", user_id, project, date],
order: "valid_from DESC")
conditions: ['user_id = ? and project_id = ? and valid_from <= ?', user_id, project, date],
order: 'valid_from DESC')
if rate.nil?
project = Project.find(project) unless project.is_a?(Project)
rate = find(:first,
conditions: [ "user_id = ? and project_id in (?) and valid_from <= ?", user_id, project.ancestors.to_a, date],
conditions: ['user_id = ? and project_id in (?) and valid_from <= ?', user_id, project.ancestors.to_a, date],
include: :project,
order: "projects.lft DESC, valid_from DESC")
order: 'projects.lft DESC, valid_from DESC')
end
end
rate ||= DefaultHourlyRate.at_for_user(date, user_id) if include_default

@ -18,5 +18,5 @@
#++
class Journal::CostObjectJournal < Journal::BaseJournal
self.table_name = "cost_object_journals"
self.table_name = 'cost_object_journals'
end

@ -18,7 +18,6 @@
#++
class LaborBudgetItem < ActiveRecord::Base
belongs_to :cost_object
belongs_to :user
include ::OpenProject::Costs::DeletedUserFallback
@ -32,22 +31,22 @@ class LaborBudgetItem < ActiveRecord::Base
# user_id correctness is ensured in VariableCostObject#*_labor_budget_item_attributes=
def self.visible_condition(user, project)
%Q{ (#{Project.allowed_to_condition(user,
:view_hourly_rates,
project: project)} OR
%{ (#{Project.allowed_to_condition(user,
:view_hourly_rates,
project: project)} OR
(#{Project.allowed_to_condition(user,
:view_own_hourly_rate,
project: project)} AND #{LaborBudgetItem.table_name}.user_id = #{user.id})) }
end
scope :visible_costs, lambda{|*args|
{ include: [{cost_object: :project}, :user],
{ include: [{ cost_object: :project }, :user],
conditions: LaborBudgetItem.visible_condition((args.first || User.current), args[1])
}
}
def costs
self.budget || self.calculated_costs
budget || calculated_costs
end
def calculated_costs(fixed_date = cost_object.fixed_date, project_id = cost_object.project_id)

@ -18,7 +18,6 @@
#++
class MaterialBudgetItem < ActiveRecord::Base
belongs_to :cost_object
belongs_to :cost_type
@ -34,13 +33,13 @@ class MaterialBudgetItem < ActiveRecord::Base
end
scope :visible_costs, lambda{|*args|
{ include: [{cost_object: :project}],
{ include: [{ cost_object: :project }],
conditions: MaterialBudgetItem.visible_condition((args.first || User.current), args[1])
}
}
def costs
self.budget || self.calculated_costs
budget || calculated_costs
end
def calculated_costs(fixed_date = cost_object.fixed_date)

@ -39,7 +39,6 @@ class Rate < ActiveRecord::Base
end
end
private
def convert_valid_from_to_date

@ -96,18 +96,18 @@ class RateObserver < ActiveRecord::Observer
(date1, date2) = order_dates(date1, date2)
# This gets an array of all the ids of the DefaultHourlyRates
default_rates = DefaultHourlyRate.find(:all, select: :id).inject([]){|r,d|r<<d.id}
default_rates = DefaultHourlyRate.find(:all, select: :id).inject([]) { |r, d| r << d.id }
if date1.nil? || date2.nil?
# we have only one date, query >=
conditions = [
"user_id = ? AND project_id IN (?) AND (rate_id IN (?) OR rate_id IS NULL) AND spent_on >= ?",
'user_id = ? AND project_id IN (?) AND (rate_id IN (?) OR rate_id IS NULL) AND spent_on >= ?',
@rate.user_id, @rate.project.descendants.to_a, default_rates, date1 || date2
]
else
# we have two dates, query between
conditions = [
"user_id = ? AND project_id IN (?) AND (rate_id IN (?) OR rate_id IS NULL) AND spent_on BETWEEN ? AND ?",
'user_id = ? AND project_id IN (?) AND (rate_id IN (?) OR rate_id IS NULL) AND spent_on BETWEEN ? AND ?',
@rate.user_id, @rate.project.descendants.to_a, default_rates, date1, date2
]
end
@ -126,13 +126,13 @@ class RateObserver < ActiveRecord::Observer
if date1.nil? || date2.nil?
# we have only one date, query >=
conditions = [
"user_id = ? AND project_id IN (?) AND rate_id = ? AND spent_on >= ?",
'user_id = ? AND project_id IN (?) AND rate_id = ? AND spent_on >= ?',
@rate.user_id, @rate.project.descendants.to_a, @rate.id, date1 || date2
]
else
# we have two dates, query between
conditions = [
"user_id = ? AND project_id IN (?) AND rate_id = ? AND spent_on BETWEEN ? AND ?",
'user_id = ? AND project_id IN (?) AND rate_id = ? AND spent_on BETWEEN ? AND ?',
@rate.user_id, @rate.project.descendants.to_a, @rate.id, date1, date2
]
end
@ -191,6 +191,6 @@ class RateObserver < ActiveRecord::Observer
def after_destroy(rate)
entry_class = rate.is_a?(HourlyRate) ? TimeEntry : CostEntry
entry_class.find(:all, conditions: {rate_id: rate.id}).each{|e| e.update_costs!}
entry_class.find(:all, conditions: { rate_id: rate.id }).each(&:update_costs!)
end
end

@ -18,7 +18,6 @@
#++
class VariableCostObject < CostObject
has_many :material_budget_items, include: :cost_type,
foreign_key: 'cost_object_id',
dependent: :destroy,
@ -34,7 +33,6 @@ class VariableCostObject < CostObject
after_update :save_material_budget_items
after_update :save_labor_budget_items
# override acts_as_journalized method
def activity_type
self.class.superclass.plural_name
@ -50,15 +48,15 @@ class VariableCostObject < CostObject
# Label of the current cost_object type for display in GUI.
def type_label
return l(:label_variable_cost_object)
l(:label_variable_cost_object)
end
def material_budget
@material_budget ||= material_budget_items.visible_costs.inject(BigDecimal.new("0.0000")){|sum, i| sum += i.costs}
@material_budget ||= material_budget_items.visible_costs.inject(BigDecimal.new('0.0000')) { |sum, i| sum += i.costs }
end
def labor_budget
@labor_budget ||= labor_budget_items.visible_costs.inject(BigDecimal.new("0.0000")){|sum, i| sum += i.costs}
@labor_budget ||= labor_budget_items.visible_costs.inject(BigDecimal.new('0.0000')) { |sum, i| sum += i.costs }
end
def spent
@ -68,9 +66,9 @@ class VariableCostObject < CostObject
def spent_material
@spent_material ||= begin
if cost_entries.blank?
BigDecimal.new("0.0000")
BigDecimal.new('0.0000')
else
cost_entries.visible_costs(User.current, self.project).sum("CASE
cost_entries.visible_costs(User.current, project).sum("CASE
WHEN #{CostEntry.table_name}.overridden_costs IS NULL THEN
#{CostEntry.table_name}.costs
ELSE
@ -82,9 +80,9 @@ class VariableCostObject < CostObject
def spent_labor
@spent_labor ||= begin
if time_entries.blank?
BigDecimal.new("0.0000")
BigDecimal.new('0.0000')
else
time_entries.visible_costs(User.current, self.project).sum("CASE
time_entries.visible_costs(User.current, project).sum("CASE
WHEN #{TimeEntry.table_name}.overridden_costs IS NULL THEN
#{TimeEntry.table_name}.costs
ELSE
@ -94,7 +92,7 @@ class VariableCostObject < CostObject
end
def new_material_budget_item_attributes=(material_budget_item_attributes)
material_budget_item_attributes.each do |index, attributes|
material_budget_item_attributes.each do |_index, attributes|
material_budget_items.build(attributes) if attributes[:units].to_i > 0
end
end
@ -121,7 +119,7 @@ class VariableCostObject < CostObject
end
def new_labor_budget_item_attributes=(labor_budget_item_attributes)
labor_budget_item_attributes.each do |index, attributes|
labor_budget_item_attributes.each do |_index, attributes|
if attributes[:hours].to_i > 0 &&
attributes[:user_id].to_i > 0 &&
project.possible_assignees.map(&:id).include?(attributes[:user_id].to_i)
@ -148,7 +146,7 @@ class VariableCostObject < CostObject
def save_labor_budget_items
labor_budget_items.each do |labor_budget_item|
labor_budget_item.save(validate:false)
labor_budget_item.save(validate: false)
end
end
end

@ -18,32 +18,30 @@
#++
OpenProject::Application.routes.draw do
scope 'projects/:project_id', as: 'projects' do
resources :cost_entries, controller: 'costlog', only: [:new, :create]
scope 'projects/:project_id', :as => 'projects' do
resources :cost_entries, :controller => 'costlog', :only => [:new, :create]
resources :cost_objects, :only => [:new, :create, :index] do
post :update_labor_budget_item, :on => :collection
post :update_material_budget_item, :on => :collection
resources :cost_objects, only: [:new, :create, :index] do
post :update_labor_budget_item, on: :collection
post :update_material_budget_item, on: :collection
end
resources :hourly_rates, :only => [:show, :edit, :update] do
post :set_rate, :on => :member
resources :hourly_rates, only: [:show, :edit, :update] do
post :set_rate, on: :member
end
end
scope 'work_packages/:work_package_id', :as => 'work_packages' do
resources :cost_entries, :controller => 'costlog', :only => [:new, :index]
scope 'work_packages/:work_package_id', as: 'work_packages' do
resources :cost_entries, controller: 'costlog', only: [:new, :index]
end
resources :cost_entries, :controller => 'costlog', :only => [:edit, :update, :destroy]
resources :cost_entries, controller: 'costlog', only: [:edit, :update, :destroy]
resources :cost_objects, :only => [:show, :update, :destroy, :edit] do
get :copy, :on => :member
resources :cost_objects, only: [:show, :update, :destroy, :edit] do
get :copy, on: :member
end
resources :cost_types, :only => [:index, :new, :edit, :update, :create, :destroy] do
resources :cost_types, only: [:index, :new, :edit, :update, :create, :destroy] do
member do
# TODO: check if this can be replaced with update method
put :set_rate
@ -52,5 +50,5 @@ OpenProject::Application.routes.draw do
end
# TODO: this is a duplicate from a route defined under project/:project_id, check whether we really want to do that
resources :hourly_rates, :only => [:edit, :update]
resources :hourly_rates, only: [:edit, :update]
end

@ -17,12 +17,11 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#++
require Rails.root.join("db","migrate","migration_utils","migration_squasher").to_s
require Rails.root.join("db","migrate","migration_utils","setting_renamer").to_s
require Rails.root.join('db', 'migrate', 'migration_utils', 'migration_squasher').to_s
require Rails.root.join('db', 'migrate', 'migration_utils', 'setting_renamer').to_s
require 'open_project/plugins/migration_mapping'
# This migration aggregates the migrations detailed in MIGRATION_FILES
class AggregatedCostsMigrations < ActiveRecord::Migration
def initialize(*)
super
@issues_table_exists = ActiveRecord::Base.connection.tables.include? 'issues'
@ -54,108 +53,108 @@ class AggregatedCostsMigrations < ActiveRecord::Migration
20121022124253_remove_group_user_enhancements.rb
MIGRATIONS
OLD_PLUGIN_NAME = "redmine_costs"
OLD_PLUGIN_NAME = 'redmine_costs'
def up
migration_names = OpenProject::Plugins::MigrationMapping.migration_files_to_migration_names(MIGRATION_FILES, OLD_PLUGIN_NAME)
Migration::MigrationSquasher.squash(migration_names) do
create_table "cost_entries" do |t|
t.integer "user_id", :null => false
t.integer "project_id", :null => false
t.integer "issue_id", :null => false
t.integer "cost_type_id", :null => false
t.float "units", :null => false
t.date "spent_on", :null => false
t.datetime "created_on", :null => false
t.datetime "updated_on", :null => false
t.string "comments", :null => false
t.boolean "blocked", :default => false, :null => false
t.decimal "overridden_costs", :precision => 15, :scale => 4
t.decimal "costs", :precision => 15, :scale => 4
t.integer "rate_id"
t.integer "tyear", :null => false
t.integer "tmonth", :null => false
t.integer "tweek", :null => false
create_table 'cost_entries' do |t|
t.integer 'user_id', null: false
t.integer 'project_id', null: false
t.integer 'issue_id', null: false
t.integer 'cost_type_id', null: false
t.float 'units', null: false
t.date 'spent_on', null: false
t.datetime 'created_on', null: false
t.datetime 'updated_on', null: false
t.string 'comments', null: false
t.boolean 'blocked', default: false, null: false
t.decimal 'overridden_costs', precision: 15, scale: 4
t.decimal 'costs', precision: 15, scale: 4
t.integer 'rate_id'
t.integer 'tyear', null: false
t.integer 'tmonth', null: false
t.integer 'tweek', null: false
end
create_table "cost_objects" do |t|
t.integer "project_id", :null => false
t.integer "author_id", :null => false
t.string "subject", :null => false
t.text "description", :null => false
t.string "type", :null => false
t.boolean "project_manager_signoff", :default => false, :null => false
t.boolean "client_signoff", :default => false, :null => false
t.date "fixed_date", :null => false
t.datetime "created_on"
t.datetime "updated_on"
create_table 'cost_objects' do |t|
t.integer 'project_id', null: false
t.integer 'author_id', null: false
t.string 'subject', null: false
t.text 'description', null: false
t.string 'type', null: false
t.boolean 'project_manager_signoff', default: false, null: false
t.boolean 'client_signoff', default: false, null: false
t.date 'fixed_date', null: false
t.datetime 'created_on'
t.datetime 'updated_on'
end
create_table "cost_types" do |t|
t.string "name", :null => false
t.string "unit", :null => false
t.string "unit_plural", :null => false
t.boolean "default", :default => false, :null => false
t.datetime "deleted_at"
create_table 'cost_types' do |t|
t.string 'name', null: false
t.string 'unit', null: false
t.string 'unit_plural', null: false
t.boolean 'default', default: false, null: false
t.datetime 'deleted_at'
end
create_table "labor_budget_items" do |t|
t.integer "cost_object_id", :null => false
t.float "hours", :null => false
t.integer "user_id"
t.string "comments", :default => "", :null => false
t.decimal "budget", :precision => 15, :scale => 4
create_table 'labor_budget_items' do |t|
t.integer 'cost_object_id', null: false
t.float 'hours', null: false
t.integer 'user_id'
t.string 'comments', default: '', null: false
t.decimal 'budget', precision: 15, scale: 4
end
create_table "material_budget_items" do |t|
t.integer "cost_object_id", :null => false
t.float "units", :null => false
t.integer "cost_type_id"
t.string "comments", :default => "", :null => false
t.decimal "budget", :precision => 15, :scale => 4
create_table 'material_budget_items' do |t|
t.integer 'cost_object_id', null: false
t.float 'units', null: false
t.integer 'cost_type_id'
t.string 'comments', default: '', null: false
t.decimal 'budget', precision: 15, scale: 4
end
create_table "rates" do |t|
t.date "valid_from", :null => false
t.decimal "rate", :precision => 15, :scale => 4, :null => false
t.string "type", :null => false
t.integer "project_id"
t.integer "user_id"
t.integer "cost_type_id"
create_table 'rates' do |t|
t.date 'valid_from', null: false
t.decimal 'rate', precision: 15, scale: 4, null: false
t.string 'type', null: false
t.integer 'project_id'
t.integer 'user_id'
t.integer 'cost_type_id'
end
if @issues_table_exists
change_table "issues" do |t|
t.column :cost_object_id, :integer, :null => true
change_table 'issues' do |t|
t.column :cost_object_id, :integer, null: true
end
end
change_table "time_entries" do |t|
t.decimal "overridden_costs", :precision => 15, :scale => 4
t.decimal "costs", :precision => 15, :scale => 4
t.integer "rate_id"
change_table 'time_entries' do |t|
t.decimal 'overridden_costs', precision: 15, scale: 4
t.decimal 'costs', precision: 15, scale: 4
t.integer 'rate_id'
end
TimeEntry.reset_column_information
Migration::SettingRenamer.rename("plugin_redmine_costs","plugin_openproject_costs")
Migration::SettingRenamer.rename('plugin_redmine_costs', 'plugin_openproject_costs')
end
end
def down
drop_table "cost_entries"
drop_table "cost_objects"
drop_table "cost_queries"
drop_table "cost_types"
drop_table "labor_budget_items"
drop_table "material_budget_items"
drop_table "rates"
drop_table 'cost_entries'
drop_table 'cost_objects'
drop_table 'cost_queries'
drop_table 'cost_types'
drop_table 'labor_budget_items'
drop_table 'material_budget_items'
drop_table 'rates'
if @issues_table_exists
remove_column :issues, :cost_object_id
end
change_table "time_entries" do |t|
t.remove_column "overridden_costs"
t.remove_column "costs"
t.remove_column "rate_id"
change_table 'time_entries' do |t|
t.remove_column 'overridden_costs'
t.remove_column 'costs'
t.remove_column 'rate_id'
end
TimeEntry.reset_column_information
end

@ -17,10 +17,9 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#++
require Rails.root.join("db","migrate","migration_utils","utils").to_s
require Rails.root.join('db', 'migrate', 'migration_utils', 'utils').to_s
class LegacyIssuesCostsDataToWorkPackages < ActiveRecord::Migration
def up
return unless migration_applicable?
@ -49,6 +48,6 @@ class LegacyIssuesCostsDataToWorkPackages < ActiveRecord::Migration
def migration_applicable?
ActiveRecord::Base.connection.table_exists?('legacy_issues') &&
ActiveRecord::Base.connection.columns('legacy_issues').map(&:name).include?('cost_object_id')
ActiveRecord::Base.connection.columns('legacy_issues').map(&:name).include?('cost_object_id')
end
end

@ -19,12 +19,12 @@
class AddCostObjectJournals < ActiveRecord::Migration
def change
create_table :cost_object_journals do |t|
t.integer :journal_id, :null => false
t.integer :project_id, :null => false
t.integer :author_id, :null => false
t.string :subject, :null => false
t.text :description
t.date :fixed_date, :null => false
t.integer :journal_id, null: false
t.integer :project_id, null: false
t.integer :author_id, null: false
t.string :subject, null: false
t.text :description
t.date :fixed_date, null: false
t.datetime :created_on
end
end

@ -19,8 +19,8 @@
class AddJournalColumnsToTimeEntryJournals < ActiveRecord::Migration
def change
add_column :time_entry_journals, :overridden_costs, :decimal, :precision => 15, :scale => 2, :null => true
add_column :time_entry_journals, :costs, :decimal, :precision => 15, :scale => 2, :null => true
add_column :time_entry_journals, :overridden_costs, :decimal, precision: 15, scale: 2, null: true
add_column :time_entry_journals, :costs, :decimal, precision: 15, scale: 2, null: true
add_column :time_entry_journals, :rate_id, :integer
Journal::TimeEntryJournal.reset_column_information
end

@ -38,10 +38,9 @@
#++
#
require Rails.root.join("db","migrate","migration_utils","legacy_journal_migrator").to_s
require Rails.root.join('db', 'migrate', 'migration_utils', 'legacy_journal_migrator').to_s
class LegacyVariableCostObjectJournalData < ActiveRecord::Migration
def up
migrator.run
end
@ -51,10 +50,8 @@ class LegacyVariableCostObjectJournalData < ActiveRecord::Migration
end
def migrator
@migrator ||= Migration::LegacyJournalMigrator.new "VariableCostObjectJournal", "cost_object_journals" do
self.journable_class = "CostObject"
@migrator ||= Migration::LegacyJournalMigrator.new 'VariableCostObjectJournal', 'cost_object_journals' do
self.journable_class = 'CostObject'
end
end
end

@ -18,10 +18,9 @@
#++
When(/^I create a budget with the following:$/) do |table|
rows = table.rows_hash
steps %Q{And I toggle the "Budgets" submenu
steps %{And I toggle the "Budgets" submenu
And I follow "New budget" within "#main-menu"
And I fill in "Subject" with "#{rows['subject']}"}
@ -33,24 +32,23 @@ When(/^I create the budget$/) do
end
When(/^I setup a budget with the following:$/) do |table|
rows = table.rows_hash
steps %Q{And I toggle the "Budgets" submenu
steps %{And I toggle the "Budgets" submenu
And I follow "New budget" within "#main-menu"
And I fill in "Subject" with "#{rows['subject']}"}
end
When(/^I (?:create|update) (?:a|the) (labor|material) item in row (\d+) with the following:$/) do | type, row_nr, table|
When(/^I (?:create|update) (?:a|the) (labor|material) item in row (\d+) with the following:$/) do |type, row_nr, table|
rows = table.rows_hash
unit = (type == 'labor') ? 'hours' : 'units'
page.find("##{type}_budget_items_body tr:nth-child(#{row_nr}) .units input").set(rows[unit])
page.find("##{type}_budget_items_body tr:nth-child(#{row_nr}) .comment input").set(rows['comment'])
if type == 'labor'
if type == 'labor'
page.find(:xpath, "//tbody[@id='#{type}_budget_items_body']/tr[#{row_nr}]//option[contains(., '#{rows['user']}')]").select_option
end
end
# Here's why we need the following ugly hack of waiting two seconds.
#
@ -81,23 +79,23 @@ When(/^I (?:create|update) (?:a|the) (labor|material) item in row (\d+) with the
sleep 2
end
When(/^I add a new (labor|material) item$/) do | type|
steps %Q{ When I click on "Add planned costs" within "fieldset##{type}_budget_items_fieldset" }
When(/^I add a new (labor|material) item$/) do |type|
steps %{ When I click on "Add planned costs" within "fieldset##{type}_budget_items_fieldset" }
end
Then (/^the planned (labor|material) costs in row (\d+) should be (.+)$/) do | type, row_nr, amount|
steps %Q{ Then I should see #{amount} within "##{type}_budget_items_body tr:nth-child(#{row_nr}) td.currency" }
Then (/^the planned (labor|material) costs in row (\d+) should be (.+)$/) do |type, row_nr, amount|
steps %{ Then I should see #{amount} within "##{type}_budget_items_body tr:nth-child(#{row_nr}) td.currency" }
end
Then (/^the stored planned (labor|material) costs in row (\d+) should be (.+)$/) do | type, row_nr, amount|
steps %Q{ Then I should see #{amount} within ".grid-content:first-child .#{type}_budget_items.list tr:nth-child(#{row_nr}) td.currency" }
Then (/^the stored planned (labor|material) costs in row (\d+) should be (.+)$/) do |type, row_nr, amount|
steps %{ Then I should see #{amount} within ".grid-content:first-child .#{type}_budget_items.list tr:nth-child(#{row_nr}) td.currency" }
end
Then (/^the stored total planned (labor|material) costs should be (.+)$/) do | type, amount|
steps %Q{ Then I should see #{amount} within ".grid-content:first-child .#{type}_budget_items.list tr:last-child td.currency" }
Then (/^the stored total planned (labor|material) costs should be (.+)$/) do |type, amount|
steps %{ Then I should see #{amount} within ".grid-content:first-child .#{type}_budget_items.list tr:last-child td.currency" }
end
Then (/^I should be able to update the budget "(.+)"$/) do | budget |
steps %Q{ Then I should be on the show page for the budget "#{budget}"
Then (/^I should be able to update the budget "(.+)"$/) do |budget|
steps %{ Then I should be on the show page for the budget "#{budget}"
And I should see "Update" within "div#update" }
end

@ -27,27 +27,26 @@ Given /^the project "([^\"]+)" has (\d+) [Cc]ost(?: )?[Ee]ntr(?:ies|y)$/ do |pro
end
end
Given /^there (?:is|are) (\d+) (default )?hourly rate[s]? with the following:$/ do |num, is_default, table|
Given /^there (?:is|are) (\d+) (default )?hourly rate[s]? with the following:$/ do |_num, is_default, table|
if is_default
hr = FactoryGirl.create(:default_hourly_rate)
else
hr = FactoryGirl.create(:hourly_rate)
end
send_table_to_object(hr, table, {
user: Proc.new do |rate, value|
unless rate.project.nil? || User.find_by_login(value).projects.include?(rate.project)
Rate.update_all({ project_id: User.find_by_login(value).projects(order: "id ASC").last.id },
{ id: rate.id })
end
Rate.update_all({ user_id: User.find_by_login(value).id },
{ id: rate.id })
end,
valid_from: Proc.new do |rate, value|
# This works for definitions like "2 years ago"
number, time_unit, tempus = value.split
time = number.to_i.send(time_unit.to_sym).send(tempus.to_sym)
rate.update_attribute :valid_from, time
end })
send_table_to_object(hr, table, user: Proc.new do |rate, value|
unless rate.project.nil? || User.find_by_login(value).projects.include?(rate.project)
Rate.update_all({ project_id: User.find_by_login(value).projects(order: 'id ASC').last.id },
id: rate.id)
end
Rate.update_all({ user_id: User.find_by_login(value).id },
id: rate.id)
end,
valid_from: Proc.new do |rate, value|
# This works for definitions like "2 years ago"
number, time_unit, tempus = value.split
time = number.to_i.send(time_unit.to_sym).send(tempus.to_sym)
rate.update_attribute :valid_from, time
end)
end
Given /^the [Uu]ser "([^\"]*)" has (\d+) [Cc]ost(?: )?[Ee]ntr(?:ies|y)$/ do |user, count|
@ -78,21 +77,21 @@ end
Given /^the work package "([^\"]+)" has (\d+) [Cc]ost(?: )?[Ee]ntr(?:ies|y) with the following:$/ do |work_package, count, table|
i = WorkPackage.find(:last, conditions: ["subject = '#{work_package}'"])
as_admin count do
ce = FactoryGirl.build(:cost_entry, spent_on: (table.rows_hash["date"] ? table.rows_hash["date"].to_date : Date.today),
units: table.rows_hash["units"],
project: i.project,
work_package: i,
user: User.find_by_login(table.rows_hash["user"]),
comments: "lorem")
ce = FactoryGirl.build(:cost_entry, spent_on: (table.rows_hash['date'] ? table.rows_hash['date'].to_date : Date.today),
units: table.rows_hash['units'],
project: i.project,
work_package: i,
user: User.find_by_login(table.rows_hash['user']),
comments: 'lorem')
ce.cost_type = CostType.find_by_name(table.rows_hash["cost type"]) if table.rows_hash["cost type"]
ce.cost_type = CostType.find_by_name(table.rows_hash['cost type']) if table.rows_hash['cost type']
ce.save!
end
end
Given /^there is a standard cost control project named "([^\"]*)"$/ do |name|
steps %Q{
steps %{
Given there is 1 project with the following:
| Name | #{name} |
| Identifier | #{name.gsub(' ', '_').downcase} |
@ -142,23 +141,23 @@ Given /^users have times and the cost type "([^\"]*)" logged on the work package
i = WorkPackage.find(:last, conditions: ["subject = '#{work_package}'"])
raise "No such work_package: #{work_package}" unless i
table.rows_hash.collect do |k,v|
table.rows_hash.collect do |k, v|
user = k.split.first
if k.end_with? "hours"
steps %Q{
if k.end_with? 'hours'
steps %{
And the issue "#{work_package}" has 1 time entry with the following:
| hours | #{v} |
| user | #{user} |
}
elsif k.end_with? "units"
steps %Q{
elsif k.end_with? 'units'
steps %{
And the issue "#{work_package}" has 1 cost entry with the following:
| units | #{v} |
| user | #{user} |
| cost type | #{cost_type} |
}
elsif k.end_with? "rate"
steps %Q{
elsif k.end_with? 'rate'
steps %{
And the user "#{user}" has:
| default rate | #{v} |
}
@ -174,29 +173,29 @@ Given /^there is a (?:variable cost object|budget) with the following:$/ do |tab
table_hash = table.rows_hash
cost_object.created_on = table_hash.has_key?("created_on") ?
eval(table_hash["created_on"]) :
cost_object.created_on = table_hash.has_key?('created_on') ?
eval(table_hash['created_on']) :
Time.now
cost_object.fixed_date = cost_object.created_on.to_date
cost_object.project = (Project.find_by_identifier(table_hash["project"]) || Project.find_by_name(table_hash ["project"])) if table_hash.has_key? "project"
cost_object.author = User.find_by_login(table_hash["author"]) || cost_object.project.members.first.principal
cost_object.subject = table_hash["subject"] if table_hash.has_key? "subject"
cost_object.project = (Project.find_by_identifier(table_hash['project']) || Project.find_by_name(table_hash ['project'])) if table_hash.has_key? 'project'
cost_object.author = User.find_by_login(table_hash['author']) || cost_object.project.members.first.principal
cost_object.subject = table_hash['subject'] if table_hash.has_key? 'subject'
cost_object.save!
cost_object.journals.first.update_attribute(:created_at, eval(table_hash["created_on"])) if table_hash.has_key?("created_on")
cost_object.journals.first.update_attribute(:created_at, eval(table_hash['created_on'])) if table_hash.has_key?('created_on')
end
Given /^I update the variable cost object "([^"]*)" with the following:$/ do |subject, table|
cost_object = VariableCostObject.find_by_subject(subject)
cost_object.subject = table.rows_hash["subject"]
cost_object.subject = table.rows_hash['subject']
cost_object.save!
end
Given /^the (?:variable cost object|budget) "(.+)" has the following labor items:$/ do |subject, table|
cost_object = VariableCostObject.find_by_subject(subject)
table.hashes.each do | hash |
table.hashes.each do |hash|
user = User.find_by_login(hash['user']) || User.find_by_name(hash['user']) || cost_object.project.members.first.principal
FactoryGirl.create(:labor_budget_item, user: user, cost_object: cost_object, comments: hash['comment'], hours: hash['hours'])
end
@ -205,7 +204,7 @@ end
Given /^the (?:variable cost object|budget) "(.+)" has the following material items:$/ do |subject, table|
cost_object = VariableCostObject.find_by_subject(subject)
table.hashes.each do | hash |
table.hashes.each do |hash|
cost_type = CostType.find_by_name(hash['cost_type']) || Cost_type.first
FactoryGirl.create(:material_budget_item, cost_type: cost_type, cost_object: cost_object, comments: hash['comment'], units: hash['units'])
end

@ -19,17 +19,16 @@
Given /^there is 1 cost type with the following:$/ do |table|
ct = FactoryGirl.build(:cost_type)
send_table_to_object(ct, table, {
cost_rate: Proc.new do |o,v|
FactoryGirl.create(:cost_rate, rate: v,
cost_type: o)
end,
name: Proc.new do |o,v|
o.name = v
o.unit = v
o.unit_plural = "#{v}s"
o.save!
end})
send_table_to_object(ct, table, cost_rate: Proc.new do |o, v|
FactoryGirl.create(:cost_rate, rate: v,
cost_type: o)
end,
name: Proc.new do |o, v|
o.name = v
o.unit = v
o.unit_plural = "#{v}s"
o.save!
end)
end
When(/^I delete the cost type "(.*?)"$/) do |name|
@ -61,19 +60,18 @@ When /^I expect to click "([^"]*)" on a confirmation box saying "([^"]*)"$/ do |
document.cookie = msg
return #{retval}
}")
@expected_message = message.gsub("\\n", "\n")
@expected_message = message.gsub('\\n', "\n")
end
When /^the confirmation box should have been displayed$/ do
assert page.evaluate_script('document.cookie').include?(@expected_message),
"Expected confirm box with message: '#{@expected_message}'" +
" got: '#{page.evaluate_script('document.cookie')}'"
" got: '#{page.evaluate_script('document.cookie')}'"
end
Then(/^the cost type "(.*?)" should not be listed on the index page$/) do |name|
if has_css?(".cost_types")
within ".cost_types" do
if has_css?('.cost_types')
within '.cost_types' do
should_not have_link(name)
end
end
@ -84,7 +82,7 @@ Then(/^the cost type "(.*?)" should be listed as deleted on the index page$/) do
click_link(I18n.t(:button_apply))
within ".deleted_cost_types" do
within '.deleted_cost_types' do
should have_text(name)
end
end

@ -17,4 +17,4 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#++
ScenarioDisabler.disable(feature: "Logging time on work package update", scenario: "Logging time")
ScenarioDisabler.disable(feature: 'Logging time on work package update', scenario: 'Logging time')

@ -20,10 +20,10 @@
Given(/^there is an hourly rate with the following:$/) do |table|
table_hash = table.rows_hash
rate = FactoryGirl.create(:hourly_rate,
valid_from: eval(table_hash[:valid_from]),
user: User.find_by_login(table_hash[:user]),
project: Project.find_by_name(table_hash[:project]),
rate: table_hash[:rate].to_i)
valid_from: eval(table_hash[:valid_from]),
user: User.find_by_login(table_hash[:user]),
project: Project.find_by_name(table_hash[:project]),
rate: table_hash[:rate].to_i)
end
When(/^I set the hourly rate of user "(.*?)" to "(.*?)"$/) do |arg1, arg2|
@ -34,6 +34,6 @@ When(/^I set the hourly rate of user "(.*?)" to "(.*?)"$/) do |arg1, arg2|
end
end
Then(/^I should see (\d+) hourly rate[s]?$/) do |arg1|
page.should have_css("tbody#rates_body tr", count: $1)
Then(/^I should see (\d+) hourly rate[s]?$/) do |_arg1|
page.should have_css('tbody#rates_body tr', count: $1)
end

@ -30,7 +30,7 @@ module CostNavigationHelpers
budget = CostObject.find_by_subject($1)
"/cost_objects/#{budget.id}"
when /^the index page (?:of|for) cost types$/
"/cost_types"
'/cost_types'
when /^the hourly rates page of user "(.*)" of the project called "(.*)"/
user = User.find_by_login($1)
"/projects/#{$2}/hourly_rates/#{user.id}"

@ -19,6 +19,6 @@
module OpenProject
module Costs
require "open_project/costs/engine"
require 'open_project/costs/engine'
end
end

@ -19,7 +19,6 @@
module OpenProject::Costs
class AttributesHelper
def initialize(work_package, user = User.current)
@work_package = work_package
@user = user
@ -55,12 +54,12 @@ module OpenProject::Costs
end
def material_costs
cost_entries_with_rate = cost_entries.select{|c| c.costs_visible_by?(@user)}
cost_entries_with_rate = cost_entries.select { |c| c.costs_visible_by?(@user) }
cost_entries_with_rate.blank? ? nil : cost_entries_with_rate.collect(&:real_costs).sum
end
def labor_costs
time_entries_with_rate = time_entries.select{|c| c.costs_visible_by?(@user)}
time_entries_with_rate = time_entries.select { |c| c.costs_visible_by?(@user) }
time_entries_with_rate.blank? ? nil : time_entries_with_rate.collect(&:real_costs).sum
end

@ -28,40 +28,39 @@ module OpenProject::Costs
register 'openproject-costs',
author_url: 'http://finn.de',
requires_openproject: '>= 4.0.0',
settings: { default: { 'costs_currency' => 'EUR','costs_currency_format' => '%n %u' },
partial: 'settings/openproject_costs' } do
settings: { default: { 'costs_currency' => 'EUR', 'costs_currency_format' => '%n %u' },
partial: 'settings/openproject_costs' } do
project_module :costs_module do
permission :view_own_hourly_rate, {}
permission :view_hourly_rates, {}
permission :edit_own_hourly_rate, {hourly_rates: [:set_rate, :edit, :update]},
require: :member
permission :edit_hourly_rates, {hourly_rates: [:set_rate, :edit, :update]},
require: :member
permission :edit_own_hourly_rate, { hourly_rates: [:set_rate, :edit, :update] },
require: :member
permission :edit_hourly_rates, { hourly_rates: [:set_rate, :edit, :update] },
require: :member
permission :view_cost_rates, {} # cost item values
permission :log_own_costs, { costlog: [:new, :create] },
require: :loggedin
permission :log_costs, {costlog: [:new, :create]},
require: :member
require: :loggedin
permission :log_costs, { costlog: [:new, :create] },
require: :member
permission :edit_own_cost_entries, {costlog: [:edit, :update, :destroy]},
require: :loggedin
permission :edit_cost_entries, {costlog: [:edit, :update, :destroy]},
require: :member
permission :edit_own_cost_entries, { costlog: [:edit, :update, :destroy] },
require: :loggedin
permission :edit_cost_entries, { costlog: [:edit, :update, :destroy] },
require: :member
permission :view_cost_objects, {cost_objects: [:index, :show]}
permission :view_cost_objects, { cost_objects: [:index, :show] }
permission :view_cost_entries, { cost_objects: [:index, :show], costlog: [:index] }
permission :view_own_cost_entries, { cost_objects: [:index, :show], costlog: [:index] }
permission :edit_cost_objects, {cost_objects: [:index, :show, :edit, :update, :destroy, :new, :create, :copy]}
permission :edit_cost_objects, { cost_objects: [:index, :show, :edit, :update, :destroy, :new, :create, :copy] }
end
# register additional permissions for the time log
project_module :time_tracking do
permission :view_own_time_entries, {timelog: [:index, :report]}
permission :view_own_time_entries, { timelog: [:index, :report] }
end
# Menu extensions
@ -181,8 +180,8 @@ module OpenProject::Costs
embed_as: ::API::V3::CostEntries::WorkPackageCostsByTypeRepresenter,
show_if: -> (*) {
represented.costs_enabled? &&
(current_user_allowed_to(:view_cost_entries, context: represented.project) ||
current_user_allowed_to(:view_own_cost_entries, context: represented.project))
(current_user_allowed_to(:view_cost_entries, context: represented.project) ||
current_user_allowed_to(:view_own_cost_entries, context: represented.project))
}
property :spent_time,
@ -195,7 +194,7 @@ module OpenProject::Costs
if: -> (_) { user_has_time_entry_permissions? }
send(:define_method, :overall_costs) do
number_to_currency(self.attributes_helper.overall_costs)
number_to_currency(attributes_helper.overall_costs)
end
send(:define_method, :attributes_helper) do
@ -257,8 +256,8 @@ module OpenProject::Costs
value_representer: ::API::V3::Budgets::BudgetRepresenter,
link_factory: -> (budget) {
{
href: api_v3_paths.budget(budget.id),
title: budget.subject
href: api_v3_paths.budget(budget.id),
title: budget.subject
}
},
show_if: -> (*) {
@ -271,7 +270,7 @@ module OpenProject::Costs
work_packages/cost_object.html
work_packages/summarized_cost_entries.html)
initializer "costs.register_hooks" do
initializer 'costs.register_hooks' do
require 'open_project/costs/hooks'
require 'open_project/costs/hooks/activity_hook'
require 'open_project/costs/hooks/work_package_hook'
@ -280,7 +279,7 @@ module OpenProject::Costs
require 'open_project/costs/hooks/work_packages_show_attributes'
end
initializer 'costs.register_observers' do |app|
initializer 'costs.register_observers' do |_app|
# Observers
ActiveRecord::Base.observers.push :rate_observer, :default_hourly_rate_observer, :costs_work_package_observer
end
@ -290,7 +289,7 @@ module OpenProject::Costs
app.config.plugins_to_test_paths << root
end
initializer 'costs.patch_number_helper' do |app|
initializer 'costs.patch_number_helper' do |_app|
# we have to do the patching in the initializer to make sure we only do this once in development
# since the NumberHelper is not unloaded
ActionView::Helpers::NumberHelper.send(:include, OpenProject::Costs::Patches::NumberHelperPatch)
@ -305,7 +304,7 @@ module OpenProject::Costs
PermittedParams.permit(:new_work_package, :cost_object_id)
end
config.to_prepare do |app|
config.to_prepare do |_app|
NonStupidDigestAssets.whitelist << /work_packages\/.*\.html/
end
end

@ -18,16 +18,15 @@
#++
class OpenProject::Costs::Hooks::ProjectHook < Redmine::Hook::ViewListener
# Renders up to two additional table headers to the membership setting
#
# Context:
# * :project => Current project
#
def view_projects_settings_members_table_header(context={})
def view_projects_settings_members_table_header(context = {})
return unless context[:project] && context[:project].module_enabled?(:costs_module)
result = ""
result = ''
user = User.current
project = context[:project]

@ -36,16 +36,16 @@ class OpenProject::Costs::Hooks::WorkPackageHook < Redmine::Hook::ViewListener
# * work_package => WorkPackage to move
# * target_project => Target of the move
# * copy => true, if the work_packages are copied rather than moved
def controller_work_packages_move_before_save(context={})
def controller_work_packages_move_before_save(context = {})
# FIXME: In case of copy==true, this will break stuff if the original work_package is saved
cost_object_id = context[:params] && context[:params][:cost_object_id]
case cost_object_id
when "" # a.k.a "(No change)"
when '' # a.k.a "(No change)"
# cost objects HAVE to be changed if move is performed across project boundaries
# as the are project specific
context[:work_package].cost_object_id = nil unless (context[:work_package].project == context[:target_project])
when "none"
when 'none'
context[:work_package].cost_object_id = nil
else
context[:work_package].cost_object_id = cost_object_id
@ -58,7 +58,7 @@ class OpenProject::Costs::Hooks::WorkPackageHook < Redmine::Hook::ViewListener
# * :work_package => WorkPackage being saved
# * :params => HTML parameters
#
def controller_work_packages_bulk_edit_before_save(context = { })
def controller_work_packages_bulk_edit_before_save(context = {})
case true
when context[:params][:cost_object_id].blank?
@ -70,7 +70,7 @@ class OpenProject::Costs::Hooks::WorkPackageHook < Redmine::Hook::ViewListener
context[:work_package].cost_object = CostObject.find(context[:params][:cost_object_id])
end
return ''
''
end
# Cost Object changes for the journal use the Cost Object subject
@ -79,7 +79,7 @@ class OpenProject::Costs::Hooks::WorkPackageHook < Redmine::Hook::ViewListener
# Context:
# * :detail => Detail about the journal change
#
def helper_work_packages_show_detail_after_setting(context = { })
def helper_work_packages_show_detail_after_setting(context = {})
# FIXME: Overwritting the caller is bad juju
if (context[:detail].prop_key == 'cost_object_id')
if context[:detail].value.to_i.to_s == context[:detail].value.to_s

@ -42,28 +42,28 @@ module OpenProject::Costs::Hooks
attributes_helper = OpenProject::Costs::AttributesHelper.new(@work_package)
attributes << work_package_show_table_row(:cost_object) do
attributes << work_package_show_table_row(:cost_object) {
@work_package.cost_object ?
link_to_cost_object(@work_package.cost_object) :
empty_element_tag
end
}
attributes << work_package_show_table_row(:overall_costs) do
attributes << work_package_show_table_row(:overall_costs) {
attributes_helper.overall_costs ?
number_to_currency(attributes_helper.overall_costs) :
empty_element_tag
end
}
if attributes_helper.summarized_cost_entries
attributes << work_package_show_table_row(:spent_units) do
attributes << work_package_show_table_row(:spent_units) {
summarized_cost_entry_links(attributes_helper.summarized_cost_entries, @work_package)
end
}
end
attributes
end
def summarized_cost_entry_links(cost_entries, work_package, create_link=true)
def summarized_cost_entry_links(cost_entries, work_package, create_link = true)
str_array = []
cost_entries.each do |cost_type, units|
txt = pluralize(units, cost_type.unit, cost_type.unit_plural)
@ -74,12 +74,12 @@ module OpenProject::Costs::Hooks
project_id: work_package.project,
work_package_id: work_package,
cost_type_id: cost_type },
{ title: cost_type.name })
title: cost_type.name)
else
str_array << "<span title=\"#{h(cost_type.name)}\">#{txt}</span>"
end
end
str_array.join(", ").html_safe
str_array.join(', ').html_safe
end
end
end

@ -21,7 +21,7 @@ module OpenProject::Costs::Patches::ApplicationHelperPatch
def self.included(base) # :nodoc:
# Same as typing in the class
base.class_eval do
def link_to_cost_object(cost_object, options={})
def link_to_cost_object(cost_object, options = {})
title = nil
subject = nil
if options[:subject] == false

@ -19,7 +19,6 @@
module OpenProject::Costs::Patches::PermittedParamsPatch
def self.included(base) # :nodoc:
base.send(:include, InstanceMethods)
end
@ -35,10 +34,10 @@ module OpenProject::Costs::Patches::PermittedParamsPatch
params.require(:cost_object).permit(:subject,
:description,
:fixed_date,
{new_material_budget_item_attributes: [:units, :cost_type_id, :comments, :budget]},
{new_labor_budget_item_attributes: [:hours, :user_id, :comments, :budget]},
{existing_material_budget_item_attributes: [:units, :cost_type_id, :comments, :budget]},
{existing_labor_budget_item_attributes: [:hours, :user_id, :comments, :budget]})
{ new_material_budget_item_attributes: [:units, :cost_type_id, :comments, :budget] },
{ new_labor_budget_item_attributes: [:hours, :user_id, :comments, :budget] },
{ existing_material_budget_item_attributes: [:units, :cost_type_id, :comments, :budget] },
existing_labor_budget_item_attributes: [:hours, :user_id, :comments, :budget])
end
def cost_type
@ -47,12 +46,12 @@ module OpenProject::Costs::Patches::PermittedParamsPatch
:unit_plural,
:default,
{ new_rate_attributes: [:valid_from, :rate] },
{ existing_rate_attributes: [:valid_from, :rate] })
existing_rate_attributes: [:valid_from, :rate])
end
def user_rates
params.require(:user).permit({ new_rate_attributes: [:valid_from, :rate],
existing_rate_attributes: [:valid_from, :rate] })
params.require(:user).permit(new_rate_attributes: [:valid_from, :rate],
existing_rate_attributes: [:valid_from, :rate])
end
end
end

@ -23,7 +23,6 @@ module OpenProject::Costs::Patches::ProjectPatch
base.include(InstanceMethods)
base.class_eval do
has_many :cost_objects, dependent: :destroy
has_many :rates, class_name: 'HourlyRate'

@ -24,7 +24,6 @@ module OpenProject::Costs::Patches::ProjectsControllerPatch
base.class_eval do
before_filter :own_total_hours, only: [:show]
end
end
module InstanceMethods

@ -58,7 +58,6 @@ module OpenProject::Costs::Patches::QueryPatch
end
module ClassMethods
# Setter for +available_columns+ that isn't provided by the core.
def available_columns=(v)
self.available_columns = (v)
@ -66,28 +65,27 @@ module OpenProject::Costs::Patches::QueryPatch
# Method to add a column to the +available_columns+ that isn't provided by the core.
def add_available_column(column)
self.available_columns << (column)
available_columns << (column)
end
end
module InstanceMethods
# Wrapper around the +available_filters+ to add a new Cost Object filter
def available_work_package_filters_with_costs
@available_filters = available_work_package_filters_without_costs
if project && project.module_enabled?(:costs_module)
openproject_costs_filters = {
"cost_object_id" => {
'cost_object_id' => {
type: :list_optional,
order: 14,
values: CostObject.all(conditions: ["project_id IN (?)", project], order: 'subject ASC').collect { |d| [d.subject, d.id.to_s]}
values: CostObject.all(conditions: ['project_id IN (?)', project], order: 'subject ASC').collect { |d| [d.subject, d.id.to_s] }
},
}
else
openproject_costs_filters = { }
openproject_costs_filters = {}
end
return @available_filters.merge(openproject_costs_filters)
@available_filters.merge(openproject_costs_filters)
end
end
end

@ -23,7 +23,6 @@ module OpenProject::Costs::Patches::RolePatch
# Same as typing in the class
base.class_eval do
alias_method_chain :allowed_to?, :inheritance
end
end
@ -37,7 +36,7 @@ module OpenProject::Costs::Patches::RolePatch
allowed_to_with_caching(action)
end
private
private
def allowed_to_with_caching(action)
@allowed_to_with_inheritance ||= {}
@ -63,7 +62,7 @@ module OpenProject::Costs::Patches::RolePatch
return if permission.blank?
(permission.inherited_by + [permission]).map(&:name).detect {|parent| allowed_inherited_permissions.include? parent}
(permission.inherited_by + [permission]).map(&:name).detect { |parent| allowed_inherited_permissions.include? parent }
end
end
@ -71,16 +70,16 @@ module OpenProject::Costs::Patches::RolePatch
def allowed_inherited_permissions
@allowed_inherited_permissions ||= begin
all_permissions = allowed_permissions || []
(all_permissions | allowed_permissions.collect do |sym|
(all_permissions | allowed_permissions.collect { |sym|
p = Redmine::AccessControl.permission(sym)
p ? p.inherits.collect(&:name) : []
end.flatten).uniq
}.flatten).uniq
end
end
def allowed_inherited_actions
@actions_allowed_inherited ||= begin
allowed_inherited_permissions.inject({}){|actions, p| actions[p] = Redmine::AccessControl.allowed_actions(p); actions}
allowed_inherited_permissions.inject({}) { |actions, p| actions[p] = Redmine::AccessControl.allowed_actions(p); actions }
end
end
end

@ -26,8 +26,7 @@ module OpenProject::Costs::Patches::TimeEntryPatch
# Same as typing in the class t.update_costs
base.class_eval do
belongs_to :rate, conditions: {type: ["HourlyRate", "DefaultHourlyRate"]}, class_name: "Rate"
belongs_to :rate, conditions: { type: ['HourlyRate', 'DefaultHourlyRate'] }, class_name: 'Rate'
attr_protected :costs, :rate_id
scope :visible, lambda{|*args|
@ -39,7 +38,7 @@ module OpenProject::Costs::Patches::TimeEntryPatch
before_save :update_costs
def self.visible_condition(user, project)
%Q{ (#{Project.allowed_to_condition(user, :view_time_entries, project: project)} OR
%{ (#{Project.allowed_to_condition(user, :view_time_entries, project: project)} OR
(#{Project.allowed_to_condition(user, :view_own_time_entries, project: project)} AND #{TimeEntry.table_name}.user_id = #{user.id})) }
end
@ -47,17 +46,15 @@ module OpenProject::Costs::Patches::TimeEntryPatch
user = args.first || User.current
project = args[1]
view_hourly_rates = %Q{ (#{Project.allowed_to_condition(user, :view_hourly_rates, project: project)} OR
view_hourly_rates = %{ (#{Project.allowed_to_condition(user, :view_hourly_rates, project: project)} OR
(#{Project.allowed_to_condition(user, :view_own_hourly_rate, project: project)} AND #{TimeEntry.table_name}.user_id = #{user.id})) }
view_time_entries = TimeEntry.visible_condition(user, project)
{ include: [:project, :user],
conditions: [view_time_entries, view_hourly_rates].join(" AND ")
conditions: [view_time_entries, view_hourly_rates].join(' AND ')
}
}
end
end
module ClassMethods
@ -78,7 +75,6 @@ module OpenProject::Costs::Patches::TimeEntryPatch
end
module InstanceMethods
def real_costs
# This methods returns the actual assigned costs of the entry
overridden_costs || costs || calculated_costs
@ -104,12 +100,12 @@ module OpenProject::Costs::Patches::TimeEntryPatch
end
def update_costs!(rate_attr = nil)
self.update_costs(rate_attr)
update_costs(rate_attr)
self.save!
end
def current_rate
self.user.rate_at(self.spent_on, self.project_id)
user.rate_at(spent_on, project_id)
end
def visible_by?(usr)

@ -22,7 +22,6 @@ module OpenProject::Costs::Patches::UserPatch
base.send(:include, InstanceMethods)
base.class_eval do
has_many :rates, class_name: 'HourlyRate'
has_many :default_rates, class_name: 'DefaultHourlyRate'
@ -36,8 +35,8 @@ module OpenProject::Costs::Patches::UserPatch
conditions: Project.allowed_to_condition(self, permission, project: projects)).map(&:id)
ids.empty? ?
"1=0" :
"(#{Project.table_name}.id in (#{ids.join(", ")}))"
'1=0' :
"(#{Project.table_name}.id in (#{ids.join(', ')}))"
end
def current_rate(project = nil, include_default = true)
@ -46,16 +45,16 @@ module OpenProject::Costs::Patches::UserPatch
# kept for backwards compatibility
def rate_at(date, project = nil, include_default = true)
::HourlyRate.at_date_for_user_in_project(date, self.id, project, include_default)
::HourlyRate.at_date_for_user_in_project(date, id, project, include_default)
end
def current_default_rate()
::DefaultHourlyRate.at_for_user(Date.today, self.id)
def current_default_rate
::DefaultHourlyRate.at_for_user(Date.today, id)
end
# kept for backwards compatibility
def default_rate_at(date)
::DefaultHourlyRate.at_for_user(date, self.id)
::DefaultHourlyRate.at_for_user(date, id)
end
def add_rates(project, rate_attributes)
@ -63,7 +62,7 @@ module OpenProject::Costs::Patches::UserPatch
return unless rate_attributes
rate_attributes.each do |index, attributes|
rate_attributes.each do |_index, attributes|
attributes[:rate] = Rate.clean_currency(attributes[:rate])
if project.nil?
@ -75,13 +74,13 @@ module OpenProject::Costs::Patches::UserPatch
end
end
def set_existing_rates (project, rates_attributes)
def set_existing_rates(project, rates_attributes)
if project.nil?
default_rates.reject(&:new_record?).each do |rate|
update_rate(rate, rates_attributes[rate.id.to_s], false)
end
else
rates.reject{|r| r.new_record? || r.project_id != project.id}.each do |rate|
rates.reject { |r| r.new_record? || r.project_id != project.id }.each do |rate|
update_rate(rate, rates_attributes[rate.id.to_s], true)
end
end
@ -93,8 +92,8 @@ module OpenProject::Costs::Patches::UserPatch
end
end
private
private
def update_rate(rate, attributes, project_rate = true)
if attributes && attributes[:rate].present?
attributes[:rate] = Rate.clean_currency(attributes[:rate])

@ -32,8 +32,8 @@ module OpenProject::Costs::Patches::UsersHelperPatch
def user_settings_tabs_with_rate_tab
# Core defined data
tabs = user_settings_tabs_without_rate_tab
tabs << { name: 'rates', partial: 'users/rates', label: :caption_rate_history}
return tabs
tabs << { name: 'rates', partial: 'users/rates', label: :caption_rate_history }
tabs
end
end
end

@ -25,7 +25,6 @@ module OpenProject::Costs::Patches::WorkPackagePatch
# Same as typing in the class
base.class_eval do
belongs_to :cost_object, inverse_of: :work_packages
has_many :cost_entries, dependent: :delete_all
@ -44,16 +43,14 @@ module OpenProject::Costs::Patches::WorkPackagePatch
associated_to_ask_before_destruction CostEntry,
->(work_packages) { CostEntry.on_work_packages(work_packages).count > 0 },
self.method(:cleanup_cost_entries_before_destruction_of)
method(:cleanup_cost_entries_before_destruction_of)
end
end
module ClassMethods
protected
def cleanup_cost_entries_before_destruction_of(work_packages, user, to_do = { action: 'destroy'} )
def cleanup_cost_entries_before_destruction_of(work_packages, user, to_do = { action: 'destroy' })
return false unless to_do.present?
case to_do[:action]
@ -68,8 +65,8 @@ module OpenProject::Costs::Patches::WorkPackagePatch
false
when 'reassign'
reassign_to = WorkPackage.includes(:project)
.where(Project.allowed_to_condition(user, :edit_cost_entries))
.find_by_id(to_do[:reassign_to_id])
.where(Project.allowed_to_condition(user, :edit_cost_entries))
.find_by_id(to_do[:reassign_to_id])
if reassign_to.nil?
Array(work_packages).each do |wp|
@ -106,7 +103,7 @@ module OpenProject::Costs::Patches::WorkPackagePatch
end
def material_costs
@material_costs ||= cost_entries.visible_costs(User.current, self.project).sum("CASE
@material_costs ||= cost_entries.visible_costs(User.current, project).sum("CASE
WHEN #{CostEntry.table_name}.overridden_costs IS NULL THEN
#{CostEntry.table_name}.costs
ELSE
@ -114,7 +111,7 @@ module OpenProject::Costs::Patches::WorkPackagePatch
end
def labor_costs
@labor_costs ||= time_entries.visible_costs(User.current, self.project).sum("CASE
@labor_costs ||= time_entries.visible_costs(User.current, project).sum("CASE
WHEN #{TimeEntry.table_name}.overridden_costs IS NULL THEN
#{TimeEntry.table_name}.costs
ELSE
@ -128,8 +125,8 @@ module OpenProject::Costs::Patches::WorkPackagePatch
# Wraps the association to get the Cost Object subject. Needed for the
# Query and filtering
def cost_object_subject
unless self.cost_object.nil?
return self.cost_object.subject
unless cost_object.nil?
return cost_object.subject
end
end
@ -140,4 +137,4 @@ module OpenProject::Costs::Patches::WorkPackagePatch
end
end
WorkPackage::SAFE_ATTRIBUTES << "cost_object_id" if WorkPackage.const_defined? "SAFE_ATTRIBUTES"
WorkPackage::SAFE_ATTRIBUTES << 'cost_object_id' if WorkPackage.const_defined? 'SAFE_ATTRIBUTES'

@ -38,7 +38,6 @@ require_dependency 'api/v3/work_packages/schema/work_package_schema'
module OpenProject::Costs::Patches::WorkPackageSchemaPatch
def self.included(base)
base.class_eval do
include InstanceMethods
extend ClassMethods
end

@ -20,7 +20,6 @@
module OpenProject::Costs::Patches::WorkPackagesHelperPatch
def self.included(base)
base.class_eval do
def work_package_form_all_middle_attributes_with_costs(form, work_package, locals = {})
attributes = work_package_form_all_middle_attributes_without_costs(form, work_package, locals)
@ -31,20 +30,18 @@ module OpenProject::Costs::Patches::WorkPackagesHelperPatch
attributes.compact
end
def work_package_form_budget_attribute(form, work_package, locals)
field = work_package_form_field do
def work_package_form_budget_attribute(form, _work_package, _locals)
field = work_package_form_field {
options = CostObject.find_all_by_project_id(@project, order: 'subject ASC').collect { |d| [d.subject, d.id] }
form.select(:cost_object_id, options, include_blank: true)
end
}
WorkPackagesHelper::WorkPackageAttribute.new(:cost_object_id, field)
end
alias_method_chain :work_package_form_all_middle_attributes, :costs
end
end
end
WorkPackagesHelper.send(:include, OpenProject::Costs::Patches::WorkPackagesHelperPatch)

@ -19,6 +19,6 @@
module OpenProject
module Costs
VERSION = "4.3.0"
VERSION = '4.3.0'
end
end

@ -1,24 +1,23 @@
$:.push File.expand_path("../lib", __FILE__)
$:.push File.expand_path('../lib', __FILE__)
# Maintain your gem's version:
require "open_project/costs/version"
require 'open_project/costs/version'
# Describe your gem and declare its dependencies:
Gem::Specification.new do |s|
s.name = "openproject-costs"
s.name = 'openproject-costs'
s.version = OpenProject::Costs::VERSION
s.authors = "Finn GmbH"
s.email = "info@finn.de"
s.homepage = "https://www.openproject.org/projects/costs-plugin"
s.summary = "OpenProject Costs"
s.description = "This Plugin adds features for planning and tracking costs of projects."
s.license = "GPLv3"
s.authors = 'Finn GmbH'
s.email = 'info@finn.de'
s.homepage = 'https://www.openproject.org/projects/costs-plugin'
s.summary = 'OpenProject Costs'
s.description = 'This Plugin adds features for planning and tracking costs of projects.'
s.license = 'GPLv3'
s.files = Dir["{app,config,db,lib,doc}/**/*", "README.md"]
s.test_files = Dir["spec/**/*"]
s.files = Dir['{app,config,db,lib,doc}/**/*', 'README.md']
s.test_files = Dir['spec/**/*']
s.add_dependency 'rails', '~> 4.0.13'
s.add_development_dependency "factory_girl_rails", "~> 4.0"
s.add_development_dependency 'factory_girl_rails', '~> 4.0'
end

@ -17,30 +17,34 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#++
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper.rb")
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
describe CostlogController, type: :controller do
include Cost::PluginSpecHelper
let (:project) { FactoryGirl.create(:project_with_types) }
let (:work_package) { FactoryGirl.create(:work_package, project: project,
author: user,
type: project.types.first) }
let (:work_package) {
FactoryGirl.create(:work_package, project: project,
author: user,
type: project.types.first)
}
let (:user) { FactoryGirl.create(:user) }
let (:user2) { FactoryGirl.create(:user) }
let (:controller) { FactoryGirl.build(:role, permissions: [:log_costs, :edit_cost_entries]) }
let (:cost_type) { FactoryGirl.build(:cost_type) }
let (:cost_entry) { FactoryGirl.build(:cost_entry, work_package: work_package,
project: project,
spent_on: Date.today,
overridden_costs: 400,
units: 100,
user: user,
comments: "") }
let (:cost_entry) {
FactoryGirl.build(:cost_entry, work_package: work_package,
project: project,
spent_on: Date.today,
overridden_costs: 400,
units: 100,
user: user,
comments: '')
}
let(:work_package_status) { FactoryGirl.create(:work_package_status, is_default: true) }
def grant_current_user_permissions user, permissions
def grant_current_user_permissions(user, permissions)
member = FactoryGirl.build(:member, project: project,
principal: user)
principal: user)
member.roles << FactoryGirl.build(:role, permissions: permissions)
member.principal = user
member.save!
@ -52,7 +56,7 @@ describe CostlogController, type: :controller do
allow(@controller.flash).to receive(:sweep)
end
shared_examples_for "assigns" do
shared_examples_for 'assigns' do
it { expect(assigns(:cost_entry).project).to eq(expected_project) }
it { expect(assigns(:cost_entry).work_package).to eq(expected_work_package) }
it { expect(assigns(:cost_entry).user).to eq(expected_user) }
@ -71,8 +75,8 @@ describe CostlogController, type: :controller do
User.current = nil
end
describe "GET new" do
let(:params) { { "work_package_id" => work_package.id.to_s } }
describe 'GET new' do
let(:params) { { 'work_package_id' => work_package.id.to_s } }
let(:expected_project) { project }
let(:expected_work_package) { work_package }
@ -82,17 +86,17 @@ describe CostlogController, type: :controller do
let(:expected_overridden_costs) { nil }
let(:expected_units) { nil }
shared_examples_for "successful new" do
shared_examples_for 'successful new' do
before do
get :new, params
end
it { expect(response).to be_success }
it_should_behave_like "assigns"
it_should_behave_like 'assigns'
it { expect(response).to render_template('edit') }
end
shared_examples_for "forbidden new" do
shared_examples_for 'forbidden new' do
before do
get :new, params
end
@ -100,12 +104,12 @@ describe CostlogController, type: :controller do
it { expect(response.response_code).to eq(403) }
end
describe "WHEN user allowed to create new cost_entry" do
describe 'WHEN user allowed to create new cost_entry' do
before do
grant_current_user_permissions user, [:log_costs]
end
it_should_behave_like "successful new"
it_should_behave_like 'successful new'
end
describe "WHEN user allowed to create new cost_entry
@ -119,34 +123,34 @@ describe CostlogController, type: :controller do
grant_current_user_permissions user, [:log_costs]
end
it_should_behave_like "successful new"
it_should_behave_like 'successful new'
end
describe "WHEN user is allowed to create new own cost_entry" do
describe 'WHEN user is allowed to create new own cost_entry' do
before do
grant_current_user_permissions user, [:log_own_costs]
end
it_should_behave_like "successful new"
it_should_behave_like 'successful new'
end
describe "WHEN user is not allowed to create new cost_entries" do
describe 'WHEN user is not allowed to create new cost_entries' do
before do
grant_current_user_permissions user, []
end
it_should_behave_like "forbidden new"
it_should_behave_like 'forbidden new'
end
end
describe "GET edit" do
let(:params) { { "id" => cost_entry.id.to_s } }
describe 'GET edit' do
let(:params) { { 'id' => cost_entry.id.to_s } }
before do
cost_entry.save(validate: false)
end
shared_examples_for "successful edit" do
shared_examples_for 'successful edit' do
before do
get :edit, params
end
@ -157,7 +161,7 @@ describe CostlogController, type: :controller do
it { expect(response).to render_template('edit') }
end
shared_examples_for "forbidden edit" do
shared_examples_for 'forbidden edit' do
before do
get :edit, params
end
@ -165,12 +169,12 @@ describe CostlogController, type: :controller do
it { expect(response.response_code).to eq(403) }
end
describe "WHEN the user is allowed to edit cost_entries" do
describe 'WHEN the user is allowed to edit cost_entries' do
before do
grant_current_user_permissions user, [:edit_cost_entries]
end
it_should_behave_like "successful edit"
it_should_behave_like 'successful edit'
end
describe "WHEN the user is allowed to edit cost_entries
@ -182,15 +186,15 @@ describe CostlogController, type: :controller do
cost_entry.save(validate: false)
end
it_should_behave_like "successful edit"
it_should_behave_like 'successful edit'
end
describe "WHEN the user is allowed to edit own cost_entries" do
describe 'WHEN the user is allowed to edit own cost_entries' do
before do
grant_current_user_permissions user, [:edit_own_cost_entries]
end
it_should_behave_like "successful edit"
it_should_behave_like 'successful edit'
end
describe "WHEN the user is allowed to edit own cost_entries
@ -202,15 +206,15 @@ describe CostlogController, type: :controller do
cost_entry.save(validate: false)
end
it_should_behave_like "forbidden edit"
it_should_behave_like 'forbidden edit'
end
describe "WHEN the user is not allowed to edit cost_entries" do
describe 'WHEN the user is not allowed to edit cost_entries' do
before do
grant_current_user_permissions user, []
end
it_should_behave_like "forbidden edit"
it_should_behave_like 'forbidden edit'
end
describe "WHEN the user is allowed to edit cost_entries
@ -220,12 +224,12 @@ describe CostlogController, type: :controller do
cost_entry.project = FactoryGirl.create(:project_with_types)
cost_entry.work_package = FactoryGirl.create(:work_package, project: cost_entry.project,
type: cost_entry.project.types.first,
author: user)
type: cost_entry.project.types.first,
author: user)
cost_entry.save!
end
it_should_behave_like "forbidden edit"
it_should_behave_like 'forbidden edit'
end
describe "WHEN the user is allowed to edit cost_entries
@ -233,7 +237,7 @@ describe CostlogController, type: :controller do
before do
grant_current_user_permissions user, [:edit_cost_entries]
params["id"] = (cost_entry.id + 1).to_s
params['id'] = (cost_entry.id + 1).to_s
get :edit, params
end
@ -242,15 +246,17 @@ describe CostlogController, type: :controller do
end
end
describe "POST create" do
let (:params) { { "project_id" => project.id.to_s,
"cost_entry" => { "user_id" => user.id.to_s,
"work_package_id" => (work_package.present? ? work_package.id.to_s : "") ,
"units" => units.to_s,
"cost_type_id" => (cost_type.present? ? cost_type.id.to_s : "" ),
"comments" => "lorem",
"spent_on" => date.to_s,
"overridden_costs" => overridden_costs.to_s } } }
describe 'POST create' do
let (:params) {
{ 'project_id' => project.id.to_s,
'cost_entry' => { 'user_id' => user.id.to_s,
'work_package_id' => (work_package.present? ? work_package.id.to_s : ''),
'units' => units.to_s,
'cost_type_id' => (cost_type.present? ? cost_type.id.to_s : ''),
'comments' => 'lorem',
'spent_on' => date.to_s,
'overridden_costs' => overridden_costs.to_s } }
}
let(:expected_project) { project }
let(:expected_work_package) { work_package }
let(:expected_user) { user }
@ -260,7 +266,7 @@ describe CostlogController, type: :controller do
let(:expected_units) { units }
let(:user2) { FactoryGirl.create(:user) }
let(:date) { "2012-04-03".to_date }
let(:date) { '2012-04-03'.to_date }
let(:overridden_costs) { 500.00 }
let(:units) { 5.0 }
@ -268,30 +274,29 @@ describe CostlogController, type: :controller do
cost_type.save! if cost_type.present?
end
shared_examples_for "successful create" do
shared_examples_for 'successful create' do
before do
post :create, params
end
# is this really usefull, shouldn't it redirect to the creating work_package by default?
it { expect(response).to redirect_to(controller: "costlog", action: "index", project_id: project) }
it { expect(response).to redirect_to(controller: 'costlog', action: 'index', project_id: project) }
it { expect(assigns(:cost_entry)).not_to be_new_record }
it_should_behave_like "assigns"
it_should_behave_like 'assigns'
it { expect(flash[:notice]).to eql I18n.t(:notice_successful_create) }
end
shared_examples_for "invalid create" do
shared_examples_for 'invalid create' do
before do
post :create, params
end
it { expect(response).to be_success }
it_should_behave_like "assigns"
it_should_behave_like 'assigns'
it { expect(flash[:notice]).to be_nil }
end
shared_examples_for "forbidden create" do
shared_examples_for 'forbidden create' do
before do
post :create, params
end
@ -299,20 +304,20 @@ describe CostlogController, type: :controller do
it { expect(response.response_code).to eq(403) }
end
describe "WHEN the user is allowed to create cost_entries" do
describe 'WHEN the user is allowed to create cost_entries' do
before do
grant_current_user_permissions user, [:log_costs]
end
it_should_behave_like "successful create"
it_should_behave_like 'successful create'
end
describe "WHEN the user is allowed to create own cost_entries" do
describe 'WHEN the user is allowed to create own cost_entries' do
before do
grant_current_user_permissions user, [:log_own_costs]
end
it_should_behave_like "successful create"
it_should_behave_like 'successful create'
end
describe "WHEN the user is allowed to create cost_entries
@ -322,174 +327,166 @@ describe CostlogController, type: :controller do
before do
grant_current_user_permissions user, [:log_costs]
params["cost_entry"].delete("spent_on")
params['cost_entry'].delete('spent_on')
end
it_should_behave_like "successful create"
it_should_behave_like 'successful create'
end
describe "WHEN the user is allowed to create cost_entries
WHEN a non existing cost_type_id is specified
WHEN no default cost_type is defined" do
let(:expected_cost_type) { nil }
before do
grant_current_user_permissions user, [:log_costs]
params["cost_entry"]["cost_type_id"] = (cost_type.id + 1).to_s
params['cost_entry']['cost_type_id'] = (cost_type.id + 1).to_s
end
it_should_behave_like "invalid create"
it_should_behave_like 'invalid create'
end
describe "WHEN the user is allowed to create cost_entries
WHEN a non existing cost_type_id is specified
WHEN a default cost_type is defined" do
let(:expected_cost_type) { nil }
before do
FactoryGirl.create(:cost_type, default: true)
grant_current_user_permissions user, [:log_costs]
params["cost_entry"]["cost_type_id"] = 1
params['cost_entry']['cost_type_id'] = 1
end
it_should_behave_like "invalid create"
it_should_behave_like 'invalid create'
end
describe "WHEN the user is allowed to create cost_entries
WHEN no cost_type is specified
WHEN a default cost_type is defined" do
let(:expected_cost_type) { nil }
before do
FactoryGirl.create(:cost_type, default: true)
grant_current_user_permissions user, [:log_costs]
params["cost_entry"].delete("cost_type_id")
params['cost_entry'].delete('cost_type_id')
end
it_should_behave_like "invalid create"
it_should_behave_like 'invalid create'
end
describe "WHEN the user is allowed to create cost_entries
WHEN no cost_type is specified
WHEN no default cost_type is defined" do
let(:expected_cost_type) { nil }
before do
grant_current_user_permissions user, [:log_costs]
params["cost_entry"].delete("cost_type_id")
params['cost_entry'].delete('cost_type_id')
end
it_should_behave_like "invalid create"
it_should_behave_like 'invalid create'
end
describe "WHEN the user is allowed to create cost_entries
WHEN the cost_type id provided belongs to an inactive cost_type" do
before do
grant_current_user_permissions user, [:log_costs]
cost_type.deleted_at = Date.today
cost_type.save!
end
it_should_behave_like "invalid create"
it_should_behave_like 'invalid create'
end
describe "WHEN the user is allowed to create cost_entries
WHEN the user is allowed to log cost for someone else and is doing so
WHEN the other user is a member of the project" do
before do
grant_current_user_permissions user, []
grant_current_user_permissions user2, [:log_costs]
params["cost_entry"]["user_id"] = user.id.to_s
params['cost_entry']['user_id'] = user.id.to_s
end
it_should_behave_like "successful create"
it_should_behave_like 'successful create'
end
describe "WHEN the user is allowed to create cost_entries
WHEN the user is allowed to log cost for someone else and is doing so
WHEN the other user isn't a member of the project" do
before do
grant_current_user_permissions user2, [:log_costs]
params["cost_entry"]["user_id"] = user.id.to_s
params['cost_entry']['user_id'] = user.id.to_s
end
it_should_behave_like "invalid create"
it_should_behave_like 'invalid create'
end
describe "WHEN the user is allowed to create cost_entries
WHEN the id of an work_package not included in the provided project is provided" do
let(:project2) { FactoryGirl.create(:project_with_types) }
let(:work_package2) { FactoryGirl.create(:work_package, project: project2,
type: project2.types.first,
author: user) }
let(:work_package2) {
FactoryGirl.create(:work_package, project: project2,
type: project2.types.first,
author: user)
}
let(:expected_work_package) { work_package2 }
before do
grant_current_user_permissions user, [:log_costs]
params["cost_entry"]["work_package_id"] = work_package2.id
params['cost_entry']['work_package_id'] = work_package2.id
end
it_should_behave_like "invalid create"
it_should_behave_like 'invalid create'
end
describe "WHEN the user is allowed to create cost_entries
WHEN no work_package_id is provided" do
let(:expected_work_package) { nil }
before do
grant_current_user_permissions user, [:log_costs]
params["cost_entry"].delete("work_package_id")
params['cost_entry'].delete('work_package_id')
end
it_should_behave_like "invalid create"
it_should_behave_like 'invalid create'
end
describe "WHEN the user is allowed to create own cost_entries
WHEN the user is trying to log costs for somebody else" do
before do
grant_current_user_permissions user2, [:log_own_costs]
params["cost_entry"]["user_id"] = user.id
params['cost_entry']['user_id'] = user.id
end
it_should_behave_like "forbidden create"
it_should_behave_like 'forbidden create'
end
describe "WHEN the user is not allowed to create cost_entries" do
describe 'WHEN the user is not allowed to create cost_entries' do
before do
grant_current_user_permissions user, []
end
it_should_behave_like "forbidden create"
it_should_behave_like 'forbidden create'
end
end
describe "PUT update" do
let(:params) { { "id" => cost_entry.id.to_s,
"cost_entry" => { "comments" => "lorem",
"work_package_id" => cost_entry.work_package.id.to_s,
"units" => cost_entry.units.to_s,
"spent_on" => cost_entry.spent_on.to_s,
"user_id" => cost_entry.user.id.to_s,
"cost_type_id" => cost_entry.cost_type.id.to_s } } }
describe 'PUT update' do
let(:params) {
{ 'id' => cost_entry.id.to_s,
'cost_entry' => { 'comments' => 'lorem',
'work_package_id' => cost_entry.work_package.id.to_s,
'units' => cost_entry.units.to_s,
'spent_on' => cost_entry.spent_on.to_s,
'user_id' => cost_entry.user.id.to_s,
'cost_type_id' => cost_entry.cost_type.id.to_s } }
}
before do
cost_entry.save(validate: false)
@ -503,27 +500,27 @@ describe CostlogController, type: :controller do
let(:expected_overridden_costs) { cost_entry.overridden_costs }
let(:expected_spent_on) { cost_entry.spent_on }
shared_examples_for "successful update" do
shared_examples_for 'successful update' do
before do
put :update, params
end
it { expect(response).to redirect_to(controller: "costlog", action: "index", project_id: project) }
it { expect(response).to redirect_to(controller: 'costlog', action: 'index', project_id: project) }
it { expect(assigns(:cost_entry)).to eq(cost_entry) }
it_should_behave_like "assigns"
it_should_behave_like 'assigns'
it { expect(assigns(:cost_entry)).not_to be_changed }
it { expect(flash[:notice]).to eql I18n.t(:notice_successful_update) }
end
shared_examples_for "invalid update" do
shared_examples_for 'invalid update' do
before { put :update, params }
it_should_behave_like "assigns"
it_should_behave_like 'assigns'
it { expect(response).to be_success }
it { expect(flash[:notice]).to be_nil }
end
shared_examples_for "forbidden update" do
shared_examples_for 'forbidden update' do
before do
put :update, params
end
@ -539,10 +536,11 @@ describe CostlogController, type: :controller do
cost_type
overridden_costs
spent_on" do
let(:expected_work_package) { FactoryGirl.create(:work_package, project: project,
type: project.types.first,
author: user) }
let(:expected_work_package) {
FactoryGirl.create(:work_package, project: project,
type: project.types.first,
author: user)
}
let(:expected_user) { FactoryGirl.create(:user) }
let(:expected_spent_on) { cost_entry.spent_on + 4.days }
let(:expected_units) { cost_entry.units + 20 }
@ -553,25 +551,24 @@ describe CostlogController, type: :controller do
grant_current_user_permissions expected_user, []
grant_current_user_permissions user, [:edit_cost_entries]
params["cost_entry"]["work_package_id"] = expected_work_package.id.to_s
params["cost_entry"]["user_id"] = expected_user.id.to_s
params["cost_entry"]["spent_on"] = expected_spent_on.to_s
params["cost_entry"]["units"] = expected_units.to_s
params["cost_entry"]["cost_type_id"] = expected_cost_type.id.to_s
params["cost_entry"]["overridden_costs"] = expected_overridden_costs.to_s
params['cost_entry']['work_package_id'] = expected_work_package.id.to_s
params['cost_entry']['user_id'] = expected_user.id.to_s
params['cost_entry']['spent_on'] = expected_spent_on.to_s
params['cost_entry']['units'] = expected_units.to_s
params['cost_entry']['cost_type_id'] = expected_cost_type.id.to_s
params['cost_entry']['overridden_costs'] = expected_overridden_costs.to_s
end
it_should_behave_like "successful update"
it_should_behave_like 'successful update'
end
describe "WHEN the user is allowed to update cost_entries
WHEN updating nothing" do
before do
grant_current_user_permissions user, [:edit_cost_entries]
end
it_should_behave_like "successful update"
it_should_behave_like 'successful update'
end
describe "WHEN the user is allowed ot update own cost_entries
@ -581,121 +578,114 @@ describe CostlogController, type: :controller do
before do
grant_current_user_permissions user, [:edit_own_cost_entries]
params["cost_entry"]["units"] = expected_units.to_s
params['cost_entry']['units'] = expected_units.to_s
end
it_should_behave_like "successful update"
it_should_behave_like 'successful update'
end
describe "WHEN the user is allowed to update cost_entries
WHEN updating the user
WHEN the new user isn't a member of the project" do
let(:user2) { FactoryGirl.create(:user) }
let(:expected_user) { user2 }
before do
grant_current_user_permissions user, [:edit_cost_entries]
params["cost_entry"]["user_id"] = user2.id.to_s
params['cost_entry']['user_id'] = user2.id.to_s
end
it_should_behave_like "invalid update"
it_should_behave_like 'invalid update'
end
describe "WHEN the user is allowed to update cost_entries
WHEN updating the work_package
WHEN the new work_package isn't an work_package of the current project" do
let(:project2) { FactoryGirl.create(:project_with_types) }
let(:work_package2) { FactoryGirl.create(:work_package, project: project2,
type: project2.types.first) }
let(:work_package2) {
FactoryGirl.create(:work_package, project: project2,
type: project2.types.first)
}
let(:expected_work_package) { work_package2 }
before do
grant_current_user_permissions user, [:edit_cost_entries]
params["cost_entry"]["work_package_id"] = work_package2.id.to_s
params['cost_entry']['work_package_id'] = work_package2.id.to_s
end
it_should_behave_like "invalid update"
it_should_behave_like 'invalid update'
end
describe "WHEN the user is allowed to update cost_entries
WHEN updating the work_package
WHEN the new work_package_id isn't existing" do
let(:expected_work_package) { nil }
before do
grant_current_user_permissions user, [:edit_cost_entries]
params["cost_entry"]["work_package_id"] = (work_package.id + 1).to_s
params['cost_entry']['work_package_id'] = (work_package.id + 1).to_s
end
it_should_behave_like "invalid update"
it_should_behave_like 'invalid update'
end
describe "WHEN the user is allowed to update cost_entries
WHEN updating the cost_type
WHEN the new cost_type is deleted" do
let(:expected_cost_type) { FactoryGirl.create(:cost_type, deleted_at: Date.today) }
before do
grant_current_user_permissions user, [:edit_cost_entries]
params["cost_entry"]["cost_type_id"] = expected_cost_type.id.to_s
params['cost_entry']['cost_type_id'] = expected_cost_type.id.to_s
end
it_should_behave_like "invalid update"
it_should_behave_like 'invalid update'
end
describe "WHEN the user is allowed to update cost_entries
WHEN updating the cost_type
WHEN the new cost_type doesn't exist" do
let(:expected_cost_type) { nil }
before do
grant_current_user_permissions user, [:edit_cost_entries]
params["cost_entry"]["cost_type_id"] = "1"
params['cost_entry']['cost_type_id'] = '1'
end
it_should_behave_like "invalid update"
it_should_behave_like 'invalid update'
end
describe "WHEN the user is allowed to update own cost_entries and not all
WHEN updating own cost entry
WHEN updating the user" do
let(:user3) { FactoryGirl.create(:user) }
before do
grant_current_user_permissions user, [:edit_own_cost_entries]
params["cost_entry"]["user_id"] = user3.id
params['cost_entry']['user_id'] = user3.id
end
it_should_behave_like "forbidden update"
it_should_behave_like 'forbidden update'
end
describe "WHEN the user is allowed to update own cost_entries and not all
WHEN updating foreign cost_entry
WHEN updating someting" do
let(:user3) { FactoryGirl.create(:user) }
before do
grant_current_user_permissions user3, [:edit_own_cost_entries]
params["cost_entry"]["units"] = (cost_entry.units + 20).to_s
params['cost_entry']['units'] = (cost_entry.units + 20).to_s
end
it_should_behave_like "forbidden update"
it_should_behave_like 'forbidden update'
end
end
end

@ -17,19 +17,19 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#++
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper.rb")
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
describe HourlyRatesController do
let(:user) { FactoryGirl.create(:user) }
let(:admin) { FactoryGirl.create(:admin) }
let(:default_rate) { FactoryGirl.create(:default_hourly_rate, user: user) }
describe "PUT update" do
describe "WHEN trying to update with an invalid rate value" do
describe 'PUT update' do
describe 'WHEN trying to update with an invalid rate value' do
let(:params) {
{
id: user.id,
user: {"existing_rate_attributes" => {"#{default_rate.id}" => {"valid_from" => "#{default_rate.valid_from}", "rate" => "2d5" }}}
user: { 'existing_rate_attributes' => { "#{default_rate.id}" => { 'valid_from' => "#{default_rate.valid_from}", 'rate' => '2d5' } } }
}
}
before do
@ -38,12 +38,12 @@ describe HourlyRatesController do
end
end
it "should render the edit template" do
expect(response).to render_template("edit")
it 'should render the edit template' do
expect(response).to render_template('edit')
end
it "should display an error message" do
expect(assigns(:user).default_rates.first.errors.messages[:rate].first).to eq("is not a number")
it 'should display an error message' do
expect(assigns(:user).default_rates.first.errors.messages[:rate].first).to eq('is not a number')
end
end
end

@ -32,12 +32,11 @@ describe WorkPackages::BulkController, type: :controller do
describe '#update' do
context 'when a cost report is assigned' do
before { put :update, ids: [work_package.id], work_package: {cost_object_id: cost_object.id} }
before do put :update, ids: [work_package.id], work_package: { cost_object_id: cost_object.id } end
subject { work_package.reload.cost_object.try :id }
it { is_expected.to eq(cost_object.id) }
end
end
end

@ -20,13 +20,13 @@
FactoryGirl.define do
factory :cost_entry do
project
user { FactoryGirl.create(:user, member_in_project: project)}
work_package { FactoryGirl.create(:work_package, project: project) }
user do FactoryGirl.create(:user, member_in_project: project)end
work_package do FactoryGirl.create(:work_package, project: project) end
cost_type
spent_on Date.today
units 1
comments ''
created_on { Time.now }
created_on do Time.now end
updated_on { Time.now }
end
end

@ -19,9 +19,9 @@
FactoryGirl.define do
factory :cost_object do
subject "Some Cost Object"
description "Some costs"
kind "VariableCostObject"
subject 'Some Cost Object'
description 'Some costs'
kind 'VariableCostObject'
project
fixed_date Date.today
created_on 3.days.ago

@ -19,9 +19,9 @@
FactoryGirl.define do
factory :cost_type do
sequence(:name) { |n| "ct no. #{n}" }
unit "singular_unit"
unit_plural "plural_unit"
sequence(:name) do |n| "ct no. #{n}" end
unit 'singular_unit'
unit_plural 'plural_unit'
trait :deleted do
deleted_at Time.now

@ -20,8 +20,8 @@
FactoryGirl.define do
factory :variable_cost_object do
association :project, factory: :project
sequence(:subject) { |n| "Cost Object No. #{n}" }
sequence(:description) { |n| "I am a Cost Object No. #{n}" }
sequence(:subject) do |n| "Cost Object No. #{n}" end
sequence(:description) do |n| "I am a Cost Object No. #{n}" end
association :author, factory: :user
fixed_date Time.now
end

@ -17,7 +17,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#++
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper.rb")
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
describe 'hourly rates', type: :feature, js: true do
let(:user) { FactoryGirl.create :admin }

@ -24,9 +24,8 @@ describe CostObjectsHelper, type: :helper do
let(:cost_object) { FactoryGirl.build(:cost_object, project: project) }
describe '#cost_objects_to_csv' do
describe "WITH a list of one cost object" do
it "should output the cost objects attributes" do
describe 'WITH a list of one cost object' do
it 'should output the cost objects attributes' do
expected = [cost_object.id,
cost_object.project.name,
cost_object.subject,
@ -38,13 +37,13 @@ describe CostObjectsHelper, type: :helper do
helper.format_time(cost_object.created_on),
helper.format_time(cost_object.updated_on),
cost_object.description
].join(I18n.t(:general_csv_separator))
].join(I18n.t(:general_csv_separator))
expect(cost_objects_to_csv([cost_object]).include?(expected)).to be_truthy
end
it "should start with a header explaining the fields" do
expected = ["#",
it 'should start with a header explaining the fields' do
expected = ['#',
Project.model_name.human,
CostObject.human_attribute_name(:subject),
CostObject.human_attribute_name(:author),
@ -55,7 +54,7 @@ describe CostObjectsHelper, type: :helper do
CostObject.human_attribute_name(:created_on),
CostObject.human_attribute_name(:updated_on),
CostObject.human_attribute_name(:description)
].join(I18n.t(:general_csv_separator))
].join(I18n.t(:general_csv_separator))
expect(cost_objects_to_csv([cost_object]).start_with?(expected)).to be_truthy
end

@ -21,15 +21,19 @@ require 'spec_helper'
describe ::API::V3::Budgets::BudgetRepresenter do
let(:project) { FactoryGirl.build(:project, id: 999) }
let(:user) { FactoryGirl.build(:user,
member_in_project: project,
created_on: 1.day.ago,
updated_on: Date.today) }
let(:budget) { FactoryGirl.build(:cost_object,
author: user,
project: project,
created_on: 1.day.ago,
updated_on: Date.today) }
let(:user) {
FactoryGirl.build(:user,
member_in_project: project,
created_on: 1.day.ago,
updated_on: Date.today)
}
let(:budget) {
FactoryGirl.build(:cost_object,
author: user,
project: project,
created_on: 1.day.ago,
updated_on: Date.today)
}
let(:representer) { described_class.new(budget) }

@ -74,10 +74,10 @@ describe ::API::V3::CostEntries::WorkPackageCostsByTypeRepresenter do
it 'aggregates the units' do
elements = JSON.parse(subject)['_embedded']['elements']
units_by_type = elements.inject({}) do |hash, entry|
units_by_type = elements.inject({}) { |hash, entry|
hash[entry['_links']['costType']['href']] = entry['spentUnits']
hash
end
}
expect(units_by_type[api_v3_paths.cost_type cost_type_A.id]).to eql 2.0
expect(units_by_type[api_v3_paths.cost_type cost_type_B.id]).to eql 6.0

@ -49,7 +49,6 @@ describe ::API::V3::Utilities::PathHelper do
it { is_expected.to eql('/api/v3/work_packages/42/summarized_costs_by_type') }
end
describe '#cost_type' do
subject { helper.cost_type 42 }

@ -23,40 +23,51 @@ describe ::API::V3::WorkPackages::WorkPackageRepresenter do
include API::V3::Utilities::PathHelper
let(:project) { FactoryGirl.create(:project) }
let(:role) { FactoryGirl.create(:role, permissions: [:view_time_entries,
:view_cost_entries,
:view_cost_rates,
:view_work_packages]) }
let(:own_time_entries_role) { FactoryGirl.create(:role, permissions: [:view_time_entries,
:view_cost_entries,
:view_cost_rates,
:view_work_packages]) }
let(:user) { FactoryGirl.create(:user,
member_in_project: project,
member_through_role: role) }
let(:role) {
FactoryGirl.create(:role, permissions: [:view_time_entries,
:view_cost_entries,
:view_cost_rates,
:view_work_packages])
}
let(:own_time_entries_role) {
FactoryGirl.create(:role, permissions: [:view_time_entries,
:view_cost_entries,
:view_cost_rates,
:view_work_packages])
}
let(:user) {
FactoryGirl.create(:user,
member_in_project: project,
member_through_role: role)
}
let(:cost_object) { FactoryGirl.create(:cost_object, project: project) }
let(:cost_entry_1) { FactoryGirl.create(:cost_entry,
work_package: work_package,
project: project,
units: 3,
spent_on: Date.today,
user: user,
comments: "Entry 1") }
let(:cost_entry_2) { FactoryGirl.create(:cost_entry,
work_package: work_package,
project: project,
units: 3,
spent_on: Date.today,
user: user,
comments: "Entry 2") }
let(:work_package) { FactoryGirl.create(:work_package,
project_id: project.id,
cost_object: cost_object) }
let(:cost_entry_1) {
FactoryGirl.create(:cost_entry,
work_package: work_package,
project: project,
units: 3,
spent_on: Date.today,
user: user,
comments: 'Entry 1')
}
let(:cost_entry_2) {
FactoryGirl.create(:cost_entry,
work_package: work_package,
project: project,
units: 3,
spent_on: Date.today,
user: user,
comments: 'Entry 2')
}
let(:work_package) {
FactoryGirl.create(:work_package,
project_id: project.id,
cost_object: cost_object)
}
let(:representer) { described_class.new(work_package, current_user: user) }
before(:each) do
allow(User).to receive(:current).and_return user
end
@ -108,7 +119,7 @@ describe ::API::V3::WorkPackages::WorkPackageRepresenter do
hours: 1.0)
}
before { time_entry }
before do time_entry end
it { is_expected.to be_json_eql('PT1H'.to_json).at_path('spentTime') }
end
@ -121,7 +132,7 @@ describe ::API::V3::WorkPackages::WorkPackageRepresenter do
hours: 42.5)
}
before { time_entry }
before do time_entry end
it { is_expected.to be_json_eql('P1DT18H30M'.to_json).at_path('spentTime') }
end
@ -135,12 +146,16 @@ describe ::API::V3::WorkPackages::WorkPackageRepresenter do
end
context 'only view_own_time_entries permission' do
let(:own_time_entries_role) { FactoryGirl.create(:role, permissions: [:view_own_time_entries,
:view_work_packages]) }
let(:own_time_entries_role) {
FactoryGirl.create(:role, permissions: [:view_own_time_entries,
:view_work_packages])
}
let(:user2) { FactoryGirl.create(:user,
member_in_project: project,
member_through_role: own_time_entries_role) }
let(:user2) {
FactoryGirl.create(:user,
member_in_project: project,
member_through_role: own_time_entries_role)
}
let!(:own_time_entry) {
FactoryGirl.create(:time_entry,
@ -185,7 +200,7 @@ describe ::API::V3::WorkPackages::WorkPackageRepresenter do
allow(user).to receive(:allowed_to?).and_return false
allow(user).to receive(:allowed_to?).with(:view_time_entries,
cost_object.project)
.and_return true
.and_return true
is_expected.to have_json_path('_links/timeEntries/href')
end
@ -194,7 +209,7 @@ describe ::API::V3::WorkPackages::WorkPackageRepresenter do
allow(user).to receive(:allowed_to?).and_return false
allow(user).to receive(:allowed_to?).with(:view_own_time_entries,
cost_object.project)
.and_return true
.and_return true
is_expected.to have_json_path('_links/timeEntries/href')
end

@ -49,7 +49,7 @@ describe ::API::V3::WorkPackages::Schema::WorkPackageSchemaRepresenter do
let(:embedded) { true }
context 'when no values are allowed' do
before { allow(schema).to receive(allowed_values_method).and_return([]) }
before do allow(schema).to receive(allowed_values_method).and_return([]) end
it_behaves_like 'links to and embeds allowed values directly' do
let(:path) { json_path }
@ -60,7 +60,7 @@ describe ::API::V3::WorkPackages::Schema::WorkPackageSchemaRepresenter do
context 'when values are allowed' do
let(:values) { FactoryGirl.build_stubbed_list(factory, 3) }
before { allow(schema).to receive(allowed_values_method).and_return(values) }
before do allow(schema).to receive(allowed_values_method).and_return(values) end
it_behaves_like 'links to and embeds allowed values directly' do
let(:path) { json_path }

@ -24,34 +24,38 @@ describe CostEntry, type: :model do
let(:project) { FactoryGirl.create(:project_with_types) }
let(:project2) { FactoryGirl.create(:project_with_types) }
let(:work_package) { FactoryGirl.create(:work_package, project: project,
type: project.types.first,
author: user) }
let(:work_package2) { FactoryGirl.create(:work_package, project: project2,
type: project2.types.first,
author: user) }
let(:work_package) {
FactoryGirl.create(:work_package, project: project,
type: project.types.first,
author: user)
}
let(:work_package2) {
FactoryGirl.create(:work_package, project: project2,
type: project2.types.first,
author: user)
}
let(:user) { FactoryGirl.create(:user) }
let(:user2) { FactoryGirl.create(:user) }
let(:klass) { CostEntry }
let(:cost_entry) do
member
FactoryGirl.build(:cost_entry, cost_type: cost_type,
project: project,
work_package: work_package,
spent_on: date,
units: units,
user: user,
comments: "lorem")
project: project,
work_package: work_package,
spent_on: date,
units: units,
user: user,
comments: 'lorem')
end
let(:cost_entry2) do
FactoryGirl.build(:cost_entry, cost_type: cost_type,
project: project,
work_package: work_package,
spent_on: date,
units: units,
user: user,
comments: "lorem")
project: project,
work_package: work_package,
spent_on: date,
units: units,
user: user,
comments: 'lorem')
end
let(:cost_type) do
@ -63,20 +67,28 @@ describe CostEntry, type: :model do
cost_type.reload
cost_type
end
let(:first_rate) { FactoryGirl.build(:cost_rate, valid_from: 6.days.ago,
rate: 10.0) }
let(:second_rate) { FactoryGirl.build(:cost_rate, valid_from: 4.days.ago,
rate: 100.0) }
let(:third_rate) { FactoryGirl.build(:cost_rate, valid_from: 2.days.ago,
rate: 1000.0) }
let(:member) { FactoryGirl.create(:member, project: project,
roles: [role],
principal: user) }
let(:first_rate) {
FactoryGirl.build(:cost_rate, valid_from: 6.days.ago,
rate: 10.0)
}
let(:second_rate) {
FactoryGirl.build(:cost_rate, valid_from: 4.days.ago,
rate: 100.0)
}
let(:third_rate) {
FactoryGirl.build(:cost_rate, valid_from: 2.days.ago,
rate: 1000.0)
}
let(:member) {
FactoryGirl.create(:member, project: project,
roles: [role],
principal: user)
}
let(:role) { FactoryGirl.create(:role, permissions: []) }
let(:units) { 5.0 }
let(:date) { Date.today }
describe "class" do
describe 'class' do
describe '#visible' do
describe "WHEN having the view_cost_entries permission
WHEN querying for a project
@ -128,18 +140,20 @@ describe CostEntry, type: :model do
end
end
describe "instance" do
describe 'instance' do
describe '#costs' do
let(:fourth_rate) { FactoryGirl.build(:cost_rate, valid_from: 1.days.ago,
rate: 10000.0,
cost_type: cost_type) }
let(:fourth_rate) {
FactoryGirl.build(:cost_rate, valid_from: 1.days.ago,
rate: 10000.0,
cost_type: cost_type)
}
describe "WHEN updating the number of units" do
describe 'WHEN updating the number of units' do
before do
cost_entry.spent_on = first_rate.valid_from + 1.day
end
it "should update costs" do
it 'should update costs' do
(0..5).each do |units|
cost_entry.units = units
cost_entry.save!
@ -148,7 +162,7 @@ describe CostEntry, type: :model do
end
end
describe "WHEN a new rate is added at the end" do
describe 'WHEN a new rate is added at the end' do
before do
cost_entry.save!
fourth_rate.save!
@ -158,7 +172,7 @@ describe CostEntry, type: :model do
it { expect(cost_entry.costs).to eq(fourth_rate.rate * cost_entry.units) }
end
describe "WHEN a new rate is added for the future" do
describe 'WHEN a new rate is added for the future' do
before do
cost_entry.save!
fourth_rate.valid_from = 1.day.from_now
@ -169,7 +183,7 @@ describe CostEntry, type: :model do
it { expect(cost_entry.costs).to eq(third_rate.rate * cost_entry.units) }
end
describe "WHEN a new rate is added in between" do
describe 'WHEN a new rate is added in between' do
before do
cost_entry.save!
fourth_rate.valid_from = 3.days.ago
@ -180,7 +194,7 @@ describe CostEntry, type: :model do
it { expect(cost_entry.costs).to eq(third_rate.rate * cost_entry.units) }
end
describe "WHEN a rate is destroyed" do
describe 'WHEN a rate is destroyed' do
before do
cost_entry.save!
third_rate.destroy
@ -200,24 +214,24 @@ describe CostEntry, type: :model do
it { expect(cost_entry.costs).to eq(cost_entry.units * first_rate.rate) }
end
describe "WHEN spent on is changed" do
describe 'WHEN spent on is changed' do
before do
cost_type.save!
cost_entry.save!
end
it "should take the then active rate to calculate" do
it 'should take the then active rate to calculate' do
(5.days.ago.to_date..Date.today).each do |time|
cost_entry.spent_on = time
cost_entry.save!
expect(cost_entry.costs).to eq(cost_entry.units * CostRate.first(conditions: ["cost_type_id = ? AND valid_from <= ?", cost_entry.cost_type.id, cost_entry.spent_on], order: "valid_from DESC").rate)
expect(cost_entry.costs).to eq(cost_entry.units * CostRate.first(conditions: ['cost_type_id = ? AND valid_from <= ?', cost_entry.cost_type.id, cost_entry.spent_on], order: 'valid_from DESC').rate)
end
end
end
end
describe '#overridden_costs' do
describe "WHEN overridden costs are seet" do
describe 'WHEN overridden costs are seet' do
let(:value) { rand(500) }
before do
@ -229,7 +243,7 @@ describe CostEntry, type: :model do
end
describe '#real_costs' do
describe "WHEN overrridden cost are set" do
describe 'WHEN overrridden cost are set' do
let(:value) { rand(500) }
before do
@ -245,15 +259,15 @@ describe CostEntry, type: :model do
cost_entry.save!
end
it{ expect(cost_entry).to be_valid }
it { expect(cost_entry).to be_valid }
describe "WHEN no cost_type is provided" do
describe 'WHEN no cost_type is provided' do
before { cost_entry.cost_type = nil }
it { expect(cost_entry).not_to be_valid }
end
describe "WHEN no project is provided" do
describe 'WHEN no project is provided' do
before do
cost_entry.project = nil
# unfortunately the project get's set to the work_package's project if no project is provided
@ -264,31 +278,31 @@ describe CostEntry, type: :model do
it { expect(cost_entry).not_to be_valid }
end
describe "WHEN no work_package is provided" do
describe 'WHEN no work_package is provided' do
before { cost_entry.work_package = nil }
it { expect(cost_entry).not_to be_valid }
end
describe "WHEN the work_package is not in the project" do
describe 'WHEN the work_package is not in the project' do
before { cost_entry.work_package = work_package2 }
it { expect(cost_entry).not_to be_valid }
end
describe "WHEN no units are provided" do
describe 'WHEN no units are provided' do
before { cost_entry.units = nil }
it { expect(cost_entry).not_to be_valid }
end
describe "WHEN no spent_on is provided" do
describe 'WHEN no spent_on is provided' do
before { cost_entry.spent_on = nil }
it { expect(cost_entry).not_to be_valid }
end
describe "WHEN no user is provided" do
describe 'WHEN no user is provided' do
before { cost_entry.user = nil }
it { expect(cost_entry).not_to be_valid }
@ -311,7 +325,7 @@ describe CostEntry, type: :model do
it { expect(cost_entry).not_to be_valid }
end
describe "WHEN the cost_type is deleted" do
describe 'WHEN the cost_type is deleted' do
before { cost_type.deleted_at = Date.new }
it { expect(cost_entry).not_to be_valid }
@ -319,7 +333,7 @@ describe CostEntry, type: :model do
end
describe '#user' do
describe "WHEN a non existing user is provided (i.e. the user has been deleted)" do
describe 'WHEN a non existing user is provided (i.e. the user has been deleted)' do
before do
cost_entry.save!
user.destroy
@ -328,7 +342,7 @@ describe CostEntry, type: :model do
it { expect(cost_entry.reload.user).to eq(DeletedUser.first) }
end
describe "WHEN an existing user is provided" do
describe 'WHEN an existing user is provided' do
it { expect(cost_entry.user).to eq(user) }
end
end

@ -17,13 +17,15 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#++
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper.rb")
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
describe CostType, type: :model do
let(:klass) { CostType }
let(:cost_type) { klass.new name: "ct1",
unit: "singular",
unit_plural: "plural" }
let(:cost_type) {
klass.new name: 'ct1',
unit: 'singular',
unit_plural: 'plural'
}
before do
# as the spec_helper loads fixtures and they are probably needed by other tests
# we delete them here so they do not interfere.
@ -32,9 +34,9 @@ describe CostType, type: :model do
CostType.destroy_all
end
describe "class" do
describe "active" do
describe "WHEN a CostType instance is deleted" do
describe 'class' do
describe 'active' do
describe 'WHEN a CostType instance is deleted' do
before do
cost_type.deleted_at = Time.now
cost_type.save!
@ -43,7 +45,7 @@ describe CostType, type: :model do
it { expect(klass.active.size).to eq(0) }
end
describe "WHEN a CostType instance is not deleted" do
describe 'WHEN a CostType instance is not deleted' do
before do
cost_type.save!
end

@ -22,11 +22,13 @@ require File.dirname(__FILE__) + '/../spec_helper'
describe DefaultHourlyRate, type: :model do
let(:project) { FactoryGirl.create(:project) }
let(:user) { FactoryGirl.create(:user) }
let(:rate) { FactoryGirl.build(:default_hourly_rate, project: project,
user: user) }
let(:rate) {
FactoryGirl.build(:default_hourly_rate, project: project,
user: user)
}
describe '#user' do
describe "WHEN an existing user is provided" do
describe 'WHEN an existing user is provided' do
before do
rate.user = user
rate.save!
@ -35,7 +37,7 @@ describe DefaultHourlyRate, type: :model do
it { expect(rate.user).to eq(user) }
end
describe "WHEN a non existing user is provided (i.e. the user is deleted)" do
describe 'WHEN a non existing user is provided (i.e. the user is deleted)' do
before do
rate.user = user
rate.save!

@ -22,11 +22,13 @@ require File.dirname(__FILE__) + '/../spec_helper'
describe HourlyRate, type: :model do
let(:project) { FactoryGirl.create(:project) }
let(:user) { FactoryGirl.create(:user) }
let(:rate) { FactoryGirl.build(:hourly_rate, project: project,
user: user) }
let(:rate) {
FactoryGirl.build(:hourly_rate, project: project,
user: user)
}
describe '#user' do
describe "WHEN an existing user is provided" do
describe 'WHEN an existing user is provided' do
before do
rate.user = user
rate.save!
@ -35,7 +37,7 @@ describe HourlyRate, type: :model do
it { expect(rate.user).to eq(user) }
end
describe "WHEN a non existing user is provided (i.e. the user is deleted)" do
describe 'WHEN a non existing user is provided (i.e. the user is deleted)' do
before do
rate.user = user
rate.save!

@ -25,17 +25,19 @@ describe LaborBudgetItem, type: :model do
let(:cost_object) { FactoryGirl.build(:variable_cost_object, project: project) }
let(:user) { FactoryGirl.create(:user) }
let(:user2) { FactoryGirl.create(:user) }
let(:rate) { FactoryGirl.create(:hourly_rate, user: user,
valid_from: Date.today - 4.days,
rate: 400.0,
project: project) }
let(:rate) {
FactoryGirl.create(:hourly_rate, user: user,
valid_from: Date.today - 4.days,
rate: 400.0,
project: project)
}
let(:project) { FactoryGirl.create(:valid_project) }
let(:project2) { FactoryGirl.create(:valid_project) }
describe '#calculated_costs' do
let(:default_costs) { "0.0".to_f }
let(:default_costs) { '0.0'.to_f }
describe "WHEN no user is associated" do
describe 'WHEN no user is associated' do
before do
item.user = nil
end
@ -43,7 +45,7 @@ describe LaborBudgetItem, type: :model do
it { expect(item.calculated_costs).to eq(default_costs) }
end
describe "WHEN no hours are defined" do
describe 'WHEN no hours are defined' do
before do
item.hours = nil
end
@ -51,7 +53,7 @@ describe LaborBudgetItem, type: :model do
it { expect(item.calculated_costs).to eq(default_costs) }
end
describe "WHEN user, hours and rate are defined" do
describe 'WHEN user, hours and rate are defined' do
before do
project.save!
item.hours = 5.0
@ -80,7 +82,7 @@ describe LaborBudgetItem, type: :model do
end
describe '#user' do
describe "WHEN an existing user is provided" do
describe 'WHEN an existing user is provided' do
before do
item.save!
item.reload
@ -91,7 +93,7 @@ describe LaborBudgetItem, type: :model do
it { expect(item.user).to eq(user) }
end
describe "WHEN a non existing user is provided (i.e. the user has been deleted)" do
describe 'WHEN a non existing user is provided (i.e. the user has been deleted)' do
before do
item.save!
item.reload
@ -106,51 +108,51 @@ describe LaborBudgetItem, type: :model do
end
describe '#valid?' do
describe "WHEN hours, cost_object and user are provided" do
it "should be valid" do
describe 'WHEN hours, cost_object and user are provided' do
it 'should be valid' do
expect(item).to be_valid
end
end
describe "WHEN no hours are provided" do
describe 'WHEN no hours are provided' do
before do
item.hours = nil
end
it "should not be valid" do
it 'should not be valid' do
expect(item).not_to be_valid
expect(item.errors[:hours]).to eq([I18n.t('activerecord.errors.messages.not_a_number')])
end
end
describe "WHEN hours are provided as nontransformable string" do
describe 'WHEN hours are provided as nontransformable string' do
before do
item.hours = "test"
item.hours = 'test'
end
it "should not be valid" do
it 'should not be valid' do
expect(item).not_to be_valid
expect(item.errors[:hours]).to eq([I18n.t('activerecord.errors.messages.not_a_number')])
end
end
describe "WHEN no cost_object is provided" do
describe 'WHEN no cost_object is provided' do
before do
item.cost_object = nil
end
it "should not be valid" do
it 'should not be valid' do
expect(item).not_to be_valid
expect(item.errors[:cost_object]).to eq([I18n.t('activerecord.errors.messages.blank')])
end
end
describe "WHEN no user is provided" do
describe 'WHEN no user is provided' do
before do
item.user = nil
end
it "should not be valid" do
it 'should not be valid' do
expect(item).not_to be_valid
expect(item.errors[:user]).to eq([I18n.t('activerecord.errors.messages.blank')])
end
@ -159,12 +161,11 @@ describe LaborBudgetItem, type: :model do
describe '#costs_visible_by?' do
before do
project.enabled_module_names = project.enabled_module_names << "costs_module"
project.enabled_module_names = project.enabled_module_names << 'costs_module'
end
describe "WHEN the item is assigned to the user
WHEN the user has the view_own_hourly_rate permission" do
before do
is_member(project, user, [:view_own_hourly_rate])
@ -176,7 +177,6 @@ describe LaborBudgetItem, type: :model do
describe "WHEN the item is assigned to the user
WHEN the user lacks permissions" do
before do
is_member(project, user, [])
@ -188,7 +188,6 @@ describe LaborBudgetItem, type: :model do
describe "WHEN the item is assigned to another user
WHEN the user has the view_hourly_rates permission" do
before do
is_member(project, user2, [:view_hourly_rates])
@ -200,7 +199,6 @@ describe LaborBudgetItem, type: :model do
describe "WHEN the item is assigned to another user
WHEN the user has the view_hourly_rates permission in another project" do
before do
is_member(project2, user2, [:view_hourly_rates])

@ -23,60 +23,60 @@ describe PermittedParams, type: :model do
let(:user) { FactoryGirl.build(:user) }
describe '#cost_entry' do
it "should return comments" do
params = ActionController::Parameters.new(cost_entry: { "comments" => "blubs" } )
it 'should return comments' do
params = ActionController::Parameters.new(cost_entry: { 'comments' => 'blubs' })
expect(PermittedParams.new(params, user).cost_entry).to eq({ "comments" => "blubs" })
expect(PermittedParams.new(params, user).cost_entry).to eq({ 'comments' => 'blubs' })
end
it "should return units" do
params = ActionController::Parameters.new(cost_entry: { "units" => "5.0" } )
it 'should return units' do
params = ActionController::Parameters.new(cost_entry: { 'units' => '5.0' })
expect(PermittedParams.new(params, user).cost_entry).to eq({ "units" => "5.0" })
expect(PermittedParams.new(params, user).cost_entry).to eq({ 'units' => '5.0' })
end
it "should return overridden_costs" do
params = ActionController::Parameters.new(cost_entry: { "overridden_costs" => "5.0" } )
it 'should return overridden_costs' do
params = ActionController::Parameters.new(cost_entry: { 'overridden_costs' => '5.0' })
expect(PermittedParams.new(params, user).cost_entry).to eq({ "overridden_costs" => "5.0" })
expect(PermittedParams.new(params, user).cost_entry).to eq({ 'overridden_costs' => '5.0' })
end
it "should return spent_on" do
params = ActionController::Parameters.new(cost_entry: { "spent_on" => Date.today.to_s } )
it 'should return spent_on' do
params = ActionController::Parameters.new(cost_entry: { 'spent_on' => Date.today.to_s })
expect(PermittedParams.new(params, user).cost_entry).to eq({ "spent_on" => Date.today.to_s })
expect(PermittedParams.new(params, user).cost_entry).to eq({ 'spent_on' => Date.today.to_s })
end
it "should not return project_id" do
params = ActionController::Parameters.new(cost_entry: { "project_id" => 42 } )
it 'should not return project_id' do
params = ActionController::Parameters.new(cost_entry: { 'project_id' => 42 })
expect(PermittedParams.new(params, user).cost_entry).to eq({ })
expect(PermittedParams.new(params, user).cost_entry).to eq({})
end
end
describe '#cost_object' do
it "should return comments" do
params = ActionController::Parameters.new(cost_object: { "subject" => "subject_test" } )
it 'should return comments' do
params = ActionController::Parameters.new(cost_object: { 'subject' => 'subject_test' })
expect(PermittedParams.new(params, user).cost_object).to eq({ "subject" => "subject_test" })
expect(PermittedParams.new(params, user).cost_object).to eq({ 'subject' => 'subject_test' })
end
it "should return description" do
params = ActionController::Parameters.new(cost_object: { "description" => "description_test" } )
it 'should return description' do
params = ActionController::Parameters.new(cost_object: { 'description' => 'description_test' })
expect(PermittedParams.new(params, user).cost_object).to eq({ "description" => "description_test" })
expect(PermittedParams.new(params, user).cost_object).to eq({ 'description' => 'description_test' })
end
it "should return fixed_date" do
params = ActionController::Parameters.new(cost_object: { "fixed_date" => "2013-05-06" } )
it 'should return fixed_date' do
params = ActionController::Parameters.new(cost_object: { 'fixed_date' => '2013-05-06' })
expect(PermittedParams.new(params, user).cost_object).to eq({ "fixed_date" => "2013-05-06" })
expect(PermittedParams.new(params, user).cost_object).to eq({ 'fixed_date' => '2013-05-06' })
end
it "should not return project_id" do
params = ActionController::Parameters.new(cost_object: { "project_id" => 42 } )
it 'should not return project_id' do
params = ActionController::Parameters.new(cost_object: { 'project_id' => 42 })
expect(PermittedParams.new(params, user).cost_object).to eq({ })
expect(PermittedParams.new(params, user).cost_object).to eq({})
end
context 'with budget item params' do
@ -85,13 +85,13 @@ describe PermittedParams, type: :model do
context 'of an existing material budget item' do
let(:budget_item_params) do
{"existing_material_budget_item_attributes" => {"1" => {
"units" => "100.0",
"cost_type_id" => "1",
"comments" => "First package",
"budget" => "5,000.00"
}
}}
{ 'existing_material_budget_item_attributes' => { '1' => {
'units' => '100.0',
'cost_type_id' => '1',
'comments' => 'First package',
'budget' => '5,000.00'
}
} }
end
it { is_expected.to eq(budget_item_params) }
@ -99,12 +99,12 @@ describe PermittedParams, type: :model do
context 'of a new material budget item' do
let(:budget_item_params) do
{"new_material_budget_item_attributes" => {"1" => {
"units" => "20",
"cost_type_id" => "2",
"comments" => "Macbooks",
"budget" => "52,000.00"
}}}
{ 'new_material_budget_item_attributes' => { '1' => {
'units' => '20',
'cost_type_id' => '2',
'comments' => 'Macbooks',
'budget' => '52,000.00'
} } }
end
it { is_expected.to eq(budget_item_params) }
@ -112,12 +112,12 @@ describe PermittedParams, type: :model do
context 'of an existing labor budget item' do
let(:budget_item_params) do
{"existing_labor_budget_item_attributes" => {"1" => {
"hours" => "20.0",
"user_id" => "1",
"comments" => "App Setup",
"budget" => "2000.00"
}}}
{ 'existing_labor_budget_item_attributes' => { '1' => {
'hours' => '20.0',
'user_id' => '1',
'comments' => 'App Setup',
'budget' => '2000.00'
} } }
end
it { is_expected.to eq(budget_item_params) }
@ -125,12 +125,12 @@ describe PermittedParams, type: :model do
context 'of a new labor budget item' do
let(:budget_item_params) do
{"new_labor_budget_item_attributes" => {"1" => {
"hours" => "5.0",
"user_id" => "2",
"comments" => "Overhead",
"budget" => "400"
}}}
{ 'new_labor_budget_item_attributes' => { '1' => {
'hours' => '5.0',
'user_id' => '2',
'comments' => 'Overhead',
'budget' => '400'
} } }
end
it { is_expected.to eq(budget_item_params) }
@ -139,71 +139,70 @@ describe PermittedParams, type: :model do
end
describe '#cost_type' do
it "should return name" do
params = ActionController::Parameters.new(cost_type: { "name" => "name_test" } )
it 'should return name' do
params = ActionController::Parameters.new(cost_type: { 'name' => 'name_test' })
expect(PermittedParams.new(params, user).cost_type).to eq({ "name" => "name_test" })
expect(PermittedParams.new(params, user).cost_type).to eq({ 'name' => 'name_test' })
end
it "should return unit" do
params = ActionController::Parameters.new(cost_type: { "unit" => "unit_test" } )
it 'should return unit' do
params = ActionController::Parameters.new(cost_type: { 'unit' => 'unit_test' })
expect(PermittedParams.new(params, user).cost_type).to eq({ "unit" => "unit_test" })
expect(PermittedParams.new(params, user).cost_type).to eq({ 'unit' => 'unit_test' })
end
it "should return unit_plural" do
params = ActionController::Parameters.new(cost_type: { "unit_plural" => "unit_plural_test" } )
it 'should return unit_plural' do
params = ActionController::Parameters.new(cost_type: { 'unit_plural' => 'unit_plural_test' })
expect(PermittedParams.new(params, user).cost_type).to eq({ "unit_plural" => "unit_plural_test" })
expect(PermittedParams.new(params, user).cost_type).to eq({ 'unit_plural' => 'unit_plural_test' })
end
it "should return default" do
params = ActionController::Parameters.new(cost_type: { "default" => 7 } )
it 'should return default' do
params = ActionController::Parameters.new(cost_type: { 'default' => 7 })
expect(PermittedParams.new(params, user).cost_type).to eq({ "default" => 7 })
expect(PermittedParams.new(params, user).cost_type).to eq({ 'default' => 7 })
end
it "should return new_rate_attributes" do
params = ActionController::Parameters.new(cost_type: { "new_rate_attributes" => { "0" => { "valid_from" => "2013-05-08", "rate" => "5002" }, "1" => { "valid_from" => "2013-05-10", "rate" => "5004" } } } )
it 'should return new_rate_attributes' do
params = ActionController::Parameters.new(cost_type: { 'new_rate_attributes' => { '0' => { 'valid_from' => '2013-05-08', 'rate' => '5002' }, '1' => { 'valid_from' => '2013-05-10', 'rate' => '5004' } } })
expect(PermittedParams.new(params, user).cost_type).to eq({ "new_rate_attributes" => { "0" => { "valid_from" => "2013-05-08", "rate" => "5002" }, "1" => { "valid_from" => "2013-05-10", "rate" => "5004" } } })
expect(PermittedParams.new(params, user).cost_type).to eq({ 'new_rate_attributes' => { '0' => { 'valid_from' => '2013-05-08', 'rate' => '5002' }, '1' => { 'valid_from' => '2013-05-10', 'rate' => '5004' } } })
end
it "should return existing_rate_attributes" do
params = ActionController::Parameters.new(cost_type: { "existing_rate_attributes" => { "9" => { "valid_from" => "2013-05-05", "rate" => "50.0" } } } )
it 'should return existing_rate_attributes' do
params = ActionController::Parameters.new(cost_type: { 'existing_rate_attributes' => { '9' => { 'valid_from' => '2013-05-05', 'rate' => '50.0' } } })
expect(PermittedParams.new(params, user).cost_type).to eq({ "existing_rate_attributes" => { "9" => { "valid_from" => "2013-05-05", "rate" => "50.0" } } })
expect(PermittedParams.new(params, user).cost_type).to eq({ 'existing_rate_attributes' => { '9' => { 'valid_from' => '2013-05-05', 'rate' => '50.0' } } })
end
it "should not return project_id" do
params = ActionController::Parameters.new(cost_type: { "project_id" => 42 } )
it 'should not return project_id' do
params = ActionController::Parameters.new(cost_type: { 'project_id' => 42 })
expect(PermittedParams.new(params, user).cost_type).to eq({ })
expect(PermittedParams.new(params, user).cost_type).to eq({})
end
end
describe '#user_rates' do
it "should return new_rate_attributes" do
params = ActionController::Parameters.new(user: { "new_rate_attributes" => { "0" => { "valid_from" => "2013-05-08", "rate" => "5002" },
"1" => { "valid_from" => "2013-05-10", "rate" => "5004" } } } )
it 'should return new_rate_attributes' do
params = ActionController::Parameters.new(user: { 'new_rate_attributes' => { '0' => { 'valid_from' => '2013-05-08', 'rate' => '5002' },
'1' => { 'valid_from' => '2013-05-10', 'rate' => '5004' } } })
expect(PermittedParams.new(params, user).user_rates).to eq({ "new_rate_attributes" => { "0" => { "valid_from" => "2013-05-08", "rate" => "5002" },
"1" => { "valid_from" => "2013-05-10", "rate" => "5004" } } })
expect(PermittedParams.new(params, user).user_rates).to eq({ 'new_rate_attributes' => { '0' => { 'valid_from' => '2013-05-08', 'rate' => '5002' },
'1' => { 'valid_from' => '2013-05-10', 'rate' => '5004' } } })
end
it "should return existing_rate_attributes" do
params = ActionController::Parameters.new(user: { "existing_rate_attributes" => { "0" => { "valid_from" => "2013-05-08", "rate" => "5002" },
"1" => { "valid_from" => "2013-05-10", "rate" => "5004" } } } )
it 'should return existing_rate_attributes' do
params = ActionController::Parameters.new(user: { 'existing_rate_attributes' => { '0' => { 'valid_from' => '2013-05-08', 'rate' => '5002' },
'1' => { 'valid_from' => '2013-05-10', 'rate' => '5004' } } })
expect(PermittedParams.new(params, user).user_rates).to eq({ "existing_rate_attributes" => { "0" => { "valid_from" => "2013-05-08", "rate" => "5002" },
"1" => { "valid_from" => "2013-05-10", "rate" => "5004" } } })
expect(PermittedParams.new(params, user).user_rates).to eq({ 'existing_rate_attributes' => { '0' => { 'valid_from' => '2013-05-08', 'rate' => '5002' },
'1' => { 'valid_from' => '2013-05-10', 'rate' => '5004' } } })
end
end
describe '#new_work_package' do
it "should permit cost_object_id" do
hash = { "cost_object_id" => "1" }
it 'should permit cost_object_id' do
hash = { 'cost_object_id' => '1' }
params = ActionController::Parameters.new(work_package: hash)

@ -23,29 +23,29 @@ describe Rate, type: :model do
let(:rate) { FactoryGirl.build(:rate) }
describe '#valid?' do
describe "WHEN no rate is supplied" do
describe 'WHEN no rate is supplied' do
before do
rate.rate = nil
end
it "should not be valid" do
it 'should not be valid' do
expect(rate).not_to be_valid
expect(rate.errors[:rate]).to eq([I18n.t('activerecord.errors.messages.not_a_number')])
end
end
describe "WHEN no number is supplied" do
describe 'WHEN no number is supplied' do
before do
rate.rate = "test"
rate.rate = 'test'
end
it "should not be valid" do
it 'should not be valid' do
expect(rate).not_to be_valid
expect(rate.errors[:rate]).to eq([I18n.t('activerecord.errors.messages.not_a_number')])
end
end
describe "WHEN a rate is supplied" do
describe 'WHEN a rate is supplied' do
before do
rate.rate = 5.0
end
@ -53,7 +53,7 @@ describe Rate, type: :model do
it { expect(rate).to be_valid }
end
describe "WHEN a date is supplied" do
describe 'WHEN a date is supplied' do
before do
rate.valid_from = Date.today
end
@ -61,31 +61,31 @@ describe Rate, type: :model do
it { expect(rate).to be_valid }
end
describe "WHEN a transformable string is supplied for date" do
describe 'WHEN a transformable string is supplied for date' do
before do
rate.valid_from = "2012-03-04"
rate.valid_from = '2012-03-04'
end
it { expect(rate).to be_valid }
end
describe "WHEN a nontransformable string is supplied for date" do
describe 'WHEN a nontransformable string is supplied for date' do
before do
rate.valid_from = "2012-02-30"
rate.valid_from = '2012-02-30'
end
it "should not be valid" do
it 'should not be valid' do
expect(rate).not_to be_valid
expect(rate.errors[:valid_from]).to eq([I18n.t('activerecord.errors.messages.not_a_date')])
end
end
describe "WHEN no value is supplied for date" do
describe 'WHEN no value is supplied for date' do
before do
rate.valid_from = nil
end
it "should not be valid" do
it 'should not be valid' do
expect(rate).not_to be_valid
expect(rate.errors[:valid_from]).to eq([I18n.t('activerecord.errors.messages.not_a_date')])
end

@ -23,12 +23,16 @@ describe TimeEntry, type: :model do
include Cost::PluginSpecHelper
let(:project) { FactoryGirl.create(:project_with_types, is_public: false) }
let(:project2) { FactoryGirl.create(:project_with_types, is_public: false) }
let(:work_package) { FactoryGirl.create(:work_package, project: project,
type: project.types.first,
author: user) }
let(:work_package2) { FactoryGirl.create(:work_package, project: project2,
type: project2.types.first,
author: user2) }
let(:work_package) {
FactoryGirl.create(:work_package, project: project,
type: project.types.first,
author: user)
}
let(:work_package2) {
FactoryGirl.create(:work_package, project: project2,
type: project2.types.first,
author: user2)
}
let(:user) { FactoryGirl.create(:user) }
let(:user2) { FactoryGirl.create(:user) }
let(:date) { Date.today }
@ -42,26 +46,25 @@ describe TimeEntry, type: :model do
let(:hours) { 5.0 }
let(:time_entry) do
FactoryGirl.create(:time_entry, project: project,
work_package: work_package,
spent_on: date,
hours: hours,
user: user,
rate: hourly_one,
comments: "lorem")
work_package: work_package,
spent_on: date,
hours: hours,
user: user,
rate: hourly_one,
comments: 'lorem')
end
let(:time_entry2) do
FactoryGirl.create(:time_entry, project: project,
work_package: work_package,
spent_on: date,
hours: hours,
user: user,
rate: hourly_one,
comments: "lorem")
work_package: work_package,
spent_on: date,
hours: hours,
user: user,
rate: hourly_one,
comments: 'lorem')
end
it "should always prefer overridden_costs" do
it 'should always prefer overridden_costs' do
allow(User).to receive(:current).and_return(user)
value = rand(500)
@ -71,13 +74,13 @@ describe TimeEntry, type: :model do
time_entry.save!
end
describe "given rate" do
describe 'given rate' do
before(:each) do
allow(User).to receive(:current).and_return(user)
@default_example = time_entry2
end
it "should return the current costs depending on the number of hours" do
it 'should return the current costs depending on the number of hours' do
(0..100).each do |hours|
time_entry.hours = hours
time_entry.save!
@ -85,7 +88,7 @@ describe TimeEntry, type: :model do
end
end
it "should update cost if a new rate is added at the end" do
it 'should update cost if a new rate is added at the end' do
time_entry.user = User.current
time_entry.spent_on = Time.now
time_entry.hours = 1
@ -102,7 +105,7 @@ describe TimeEntry, type: :model do
expect(time_entry.costs).to eq(hourly.rate)
end
it "should update cost if a new rate is added in between" do
it 'should update cost if a new rate is added in between' do
time_entry.user = User.current
time_entry.spent_on = 3.days.ago.to_date
time_entry.hours = 1
@ -119,7 +122,7 @@ describe TimeEntry, type: :model do
expect(time_entry.costs).to eq(hourly.rate)
end
it "should update cost if a spent_on changes" do
it 'should update cost if a spent_on changes' do
time_entry.hours = 1
(5.days.ago.to_date..Date.today).each do |time|
time_entry.spent_on = time.to_date
@ -128,7 +131,7 @@ describe TimeEntry, type: :model do
end
end
it "should update cost if a rate is removed" do
it 'should update cost if a rate is removed' do
time_entry.spent_on = hourly_one.valid_from
time_entry.hours = 1
time_entry.save!
@ -141,7 +144,7 @@ describe TimeEntry, type: :model do
expect(time_entry.costs).to eq(hourly_five.rate)
end
it "should be able to change order of rates (sorted by valid_from)" do
it 'should be able to change order of rates (sorted by valid_from)' do
time_entry.spent_on = hourly_one.valid_from
time_entry.save!
expect(time_entry.rate).to eq(hourly_one)
@ -150,16 +153,15 @@ describe TimeEntry, type: :model do
time_entry.reload
expect(time_entry.rate).to eq(hourly_three)
end
end
describe "default rate" do
describe 'default rate' do
before(:each) do
allow(User).to receive(:current).and_return(user)
@default_example = time_entry2
end
it "should return the current costs depending on the number of hours" do
it 'should return the current costs depending on the number of hours' do
(0..100).each do |hours|
@default_example.hours = hours
@default_example.save!
@ -167,7 +169,7 @@ describe TimeEntry, type: :model do
end
end
it "should update cost if a new rate is added at the end" do
it 'should update cost if a new rate is added at the end' do
@default_example.user = user2
@default_example.spent_on = Time.now.to_date
@default_example.hours = 1
@ -183,7 +185,7 @@ describe TimeEntry, type: :model do
expect(@default_example.costs).to eq(hourly.rate)
end
it "should update cost if a new rate is added in between" do
it 'should update cost if a new rate is added in between' do
@default_example.user = user2
@default_example.spent_on = 3.days.ago.to_date
@default_example.hours = 1
@ -199,7 +201,7 @@ describe TimeEntry, type: :model do
expect(@default_example.costs).to eq(hourly.rate)
end
it "should update cost if a spent_on changes" do
it 'should update cost if a spent_on changes' do
@default_example.hours = 1
(5.days.ago.to_date..Date.today).each do |time|
@default_example.spent_on = time.to_date
@ -208,7 +210,7 @@ describe TimeEntry, type: :model do
end
end
it "should update cost if a rate is removed" do
it 'should update cost if a rate is removed' do
@default_example.spent_on = default_hourly_one.valid_from
@default_example.hours = 1
@default_example.save!
@ -221,7 +223,7 @@ describe TimeEntry, type: :model do
expect(@default_example.costs).to eq(default_hourly_five.rate)
end
it "shoud be able to switch between default hourly rate and hourly rate" do
it 'shoud be able to switch between default hourly rate and hourly rate' do
@default_example.user = user2
@default_example.rate = default_hourly_one
@default_example.save!
@ -244,12 +246,11 @@ describe TimeEntry, type: :model do
describe '#costs_visible_by?' do
before do
project.enabled_module_names = project.enabled_module_names << "costs_module"
project.enabled_module_names = project.enabled_module_names << 'costs_module'
end
describe "WHEN the time_entry is assigned to the user
WHEN the user has the view_own_hourly_rate permission" do
before do
is_member(project, user, [:view_own_hourly_rate])
@ -261,7 +262,6 @@ describe TimeEntry, type: :model do
describe "WHEN the time_entry is assigned to the user
WHEN the user lacks permissions" do
before do
is_member(project, user, [])
@ -273,7 +273,6 @@ describe TimeEntry, type: :model do
describe "WHEN the time_entry is assigned to another user
WHEN the user has the view_hourly_rates permission" do
before do
is_member(project, user2, [:view_hourly_rates])
@ -285,7 +284,6 @@ describe TimeEntry, type: :model do
describe "WHEN the time_entry is assigned to another user
WHEN the user has the view_hourly_rates permission in another project" do
before do
is_member(project2, user2, [:view_hourly_rates])
@ -297,7 +295,7 @@ describe TimeEntry, type: :model do
end
end
describe "class" do
describe 'class' do
describe '#visible' do
describe "WHEN having the view_time_entries permission
WHEN querying for a project

@ -19,7 +19,7 @@
require File.dirname(__FILE__) + '/../spec_helper'
describe User, "#destroy", type: :model do
describe User, '#destroy', type: :model do
let(:user) { FactoryGirl.create(:user) }
let(:user2) { FactoryGirl.create(:user) }
let(:substitute_user) { DeletedUser.first }
@ -34,18 +34,18 @@ describe User, "#destroy", type: :model do
User.current = nil
end
shared_examples_for "costs updated journalized associated object" do
shared_examples_for 'costs updated journalized associated object' do
before do
User.current = user2
associations.each do |association|
associated_instance.send(association.to_s + "=", user2)
associated_instance.send(association.to_s + '=', user2)
end
associated_instance.save!
User.current = user # in order to have the content journal created by the user
associated_instance.reload
associations.each do |association|
associated_instance.send(association.to_s + "=", user)
associated_instance.send(association.to_s + '=', user)
end
associated_instance.save!
@ -54,37 +54,37 @@ describe User, "#destroy", type: :model do
end
it { expect(associated_class.find_by_id(associated_instance.id)).to eq(associated_instance) }
it "should replace the user on all associations" do
it 'should replace the user on all associations' do
associations.each do |association|
expect(associated_instance.send(association)).to eq(substitute_user)
end
end
it { expect(associated_instance.journals.first.user).to eq(user2) }
it "should update first journal changed_data" do
it 'should update first journal changed_data' do
associations.each do |association|
expect(associated_instance.journals.first.changed_data["#{association}_id".to_sym].last).to eq(user2.id)
end
end
it { expect(associated_instance.journals.last.user).to eq(substitute_user) }
it "should update second journal changed_data" do
it 'should update second journal changed_data' do
associations.each do |association|
expect(associated_instance.journals.last.changed_data["#{association}_id".to_sym].last).to eq(substitute_user.id)
end
end
end
shared_examples_for "costs created journalized associated object" do
shared_examples_for 'costs created journalized associated object' do
before do
User.current = user # in order to have the content journal created by the user
associations.each do |association|
associated_instance.send(association.to_s + "=", user)
associated_instance.send(association.to_s + '=', user)
end
associated_instance.save!
User.current = user2
associated_instance.reload
associations.each do |association|
associated_instance.send(association.to_s + "=", user2)
associated_instance.send(association.to_s + '=', user2)
end
associated_instance.save!
@ -93,19 +93,19 @@ describe User, "#destroy", type: :model do
end
it { expect(associated_class.find_by_id(associated_instance.id)).to eq(associated_instance) }
it "should keep the current user on all associations" do
it 'should keep the current user on all associations' do
associations.each do |association|
expect(associated_instance.send(association)).to eq(user2)
end
end
it { expect(associated_instance.journals.first.user).to eq(substitute_user) }
it "should update the first journal" do
it 'should update the first journal' do
associations.each do |association|
expect(associated_instance.journals.first.changed_data["#{association}_id".to_sym].last).to eq(substitute_user.id)
end
end
it { expect(associated_instance.journals.last.user).to eq(user2) }
it "should update the last journal" do
it 'should update the last journal' do
associations.each do |association|
expect(associated_instance.journals.last.changed_data["#{association}_id".to_sym].first).to eq(substitute_user.id)
expect(associated_instance.journals.last.changed_data["#{association}_id".to_sym].last).to eq(user2.id)
@ -113,23 +113,23 @@ describe User, "#destroy", type: :model do
end
end
describe "WHEN the user updated a cost object" do
describe 'WHEN the user updated a cost object' do
let(:associations) { [:author] }
let(:associated_instance) { FactoryGirl.build(:variable_cost_object) }
let(:associated_class) { CostObject }
it_should_behave_like "costs updated journalized associated object"
it_should_behave_like 'costs updated journalized associated object'
end
describe "WHEN the user created a cost object" do
describe 'WHEN the user created a cost object' do
let(:associations) { [:author] }
let(:associated_instance) { FactoryGirl.build(:variable_cost_object) }
let(:associated_class) { CostObject }
it_should_behave_like "costs created journalized associated object"
it_should_behave_like 'costs created journalized associated object'
end
describe "WHEN the user has a labor_budget_item associated" do
describe 'WHEN the user has a labor_budget_item associated' do
let(:item) { FactoryGirl.build(:labor_budget_item, user: user) }
before do
@ -142,19 +142,21 @@ describe User, "#destroy", type: :model do
it { expect(item.user_id).to eq(user.id) }
end
describe "WHEN the user has a cost entry" do
describe 'WHEN the user has a cost entry' do
let(:work_package) { FactoryGirl.create(:work_package) }
let(:entry) { FactoryGirl.build(:cost_entry, user: user,
project: work_package.project,
units: 100.0,
spent_on: Date.today,
work_package: work_package,
comments: "") }
let(:entry) {
FactoryGirl.build(:cost_entry, user: user,
project: work_package.project,
units: 100.0,
spent_on: Date.today,
work_package: work_package,
comments: '')
}
before do
FactoryGirl.create(:member, project: work_package.project,
user: user,
roles: [FactoryGirl.build(:role)])
user: user,
roles: [FactoryGirl.build(:role)])
entry.save!
user.destroy
@ -165,9 +167,11 @@ describe User, "#destroy", type: :model do
it { expect(entry.user_id).to eq(user.id) }
end
describe "WHEN the user is assigned an hourly rate" do
let(:hourly_rate) { FactoryGirl.build(:hourly_rate, user: user,
project: project) }
describe 'WHEN the user is assigned an hourly rate' do
let(:hourly_rate) {
FactoryGirl.build(:hourly_rate, user: user,
project: project)
}
before do
hourly_rate.save!
@ -178,9 +182,11 @@ describe User, "#destroy", type: :model do
it { expect(hourly_rate.reload.user_id).to eq(user.id) }
end
describe "WHEN the user is assigned a default hourly rate" do
let(:default_hourly_rate) { FactoryGirl.build(:default_hourly_rate, user: user,
project: project) }
describe 'WHEN the user is assigned a default hourly rate' do
let(:default_hourly_rate) {
FactoryGirl.build(:default_hourly_rate, user: user,
project: project)
}
before do
default_hourly_rate.save!

@ -25,12 +25,14 @@ describe User, type: :model do
let(:user) { FactoryGirl.build(:user) }
let(:project) { FactoryGirl.build(:valid_project) }
let(:project2) { FactoryGirl.build(:valid_project) }
let(:project_hourly_rate) { FactoryGirl.build(:hourly_rate, user: user,
project: project) }
let(:project_hourly_rate) {
FactoryGirl.build(:hourly_rate, user: user,
project: project)
}
let(:default_hourly_rate) { FactoryGirl.build(:default_hourly_rate, user: user) }
describe '#allowed_to' do
describe "WITH querying for a non existent permission" do
describe 'WITH querying for a non existent permission' do
it { expect(user.allowed_to?(:bogus_permission, project)).to be_falsey }
end
end
@ -46,11 +48,10 @@ describe User, type: :model do
describe "WHEN user has the permission in one project
WHEN not requesting for a specific project" do
before do
is_member(project, user, [permission])
end
it "should return a sql condition where the project id the user has the permission in is enforced" do
it 'should return a sql condition where the project id the user has the permission in is enforced' do
expect(user.allowed_to_condition_with_project_id(permission)).to eq("(projects.id in (#{project.id}))")
end
end
@ -62,7 +63,7 @@ describe User, type: :model do
is_member(project2, user, [permission])
end
it "should return a sql condition where all the project ids the user has the permission in is enforced" do
it 'should return a sql condition where all the project ids the user has the permission in is enforced' do
# as order is not guaranteed and in fact does not matter
# we have to check for both valid options
valid_conditions = ["(projects.id in (#{project.id}, #{project2.id}))",
@ -78,8 +79,8 @@ describe User, type: :model do
user.save!
end
it "should return a neutral (for an or operation) sql condition" do
expect(user.allowed_to_condition_with_project_id(permission)).to eq("1=0")
it 'should return a neutral (for an or operation) sql condition' do
expect(user.allowed_to_condition_with_project_id(permission)).to eq('1=0')
end
end
@ -90,7 +91,7 @@ describe User, type: :model do
is_member(project2, user, [permission])
end
it "should return a sql condition where all the project ids the user has the permission in is enforced" do
it 'should return a sql condition where all the project ids the user has the permission in is enforced' do
expect(user.allowed_to_condition_with_project_id(permission, project)).to eq("(projects.id in (#{project.id}))")
end
end
@ -104,9 +105,10 @@ describe User, type: :model do
describe "WHEN providing a project
WHEN providing attributes for an existing rate in the project" do
let(:new_attributes) { { project_hourly_rate.id.to_s => { valid_from: (Date.today + 1.day).to_s,
rate: (project_hourly_rate.rate + 5).to_s } } }
let(:new_attributes) {
{ project_hourly_rate.id.to_s => { valid_from: (Date.today + 1.day).to_s,
rate: (project_hourly_rate.rate + 5).to_s } }
}
before do
project_hourly_rate.save!
@ -115,24 +117,25 @@ describe User, type: :model do
user.set_existing_rates(project, new_attributes)
end
it "should update the rate" do
expect(user.rates.detect{ |r| r.id == project_hourly_rate.id }.rate).to eq(new_attributes[project_hourly_rate.id.to_s][:rate].to_i)
it 'should update the rate' do
expect(user.rates.detect { |r| r.id == project_hourly_rate.id }.rate).to eq(new_attributes[project_hourly_rate.id.to_s][:rate].to_i)
end
it "should update valid_from" do
expect(user.rates.detect{ |r| r.id == project_hourly_rate.id }.valid_from).to eq(new_attributes[project_hourly_rate.id.to_s][:valid_from].to_date)
it 'should update valid_from' do
expect(user.rates.detect { |r| r.id == project_hourly_rate.id }.valid_from).to eq(new_attributes[project_hourly_rate.id.to_s][:valid_from].to_date)
end
it "should not create a rate" do
it 'should not create a rate' do
expect(user.rates.size).to eq(1)
end
end
describe "WHEN providing a project
WHEN providing attributes for an existing rate in another project" do
let(:new_attributes) { { project_hourly_rate.id.to_s => { valid_from: (Date.today + 1.day).to_s,
rate: (project_hourly_rate.rate + 5).to_s } } }
let(:new_attributes) {
{ project_hourly_rate.id.to_s => { valid_from: (Date.today + 1.day).to_s,
rate: (project_hourly_rate.rate + 5).to_s } }
}
before do
project_hourly_rate.save!
@ -143,22 +146,21 @@ describe User, type: :model do
user.set_existing_rates(project2, new_attributes)
end
it "should not update the rate" do
expect(user.rates.detect{ |r| r.id == project_hourly_rate.id }.rate).to eq(@original_rate)
it 'should not update the rate' do
expect(user.rates.detect { |r| r.id == project_hourly_rate.id }.rate).to eq(@original_rate)
end
it "should not update valid_from" do
expect(user.rates.detect{ |r| r.id == project_hourly_rate.id }.valid_from).to eq(@original_valid_from)
it 'should not update valid_from' do
expect(user.rates.detect { |r| r.id == project_hourly_rate.id }.valid_from).to eq(@original_valid_from)
end
it "should not create a rate" do
it 'should not create a rate' do
expect(user.rates.size).to eq(1)
end
end
describe "WHEN providing a project
WHEN not providing attributes" do
before do
project_hourly_rate.save!
user.rates(true)
@ -166,14 +168,13 @@ describe User, type: :model do
user.set_existing_rates(project, {})
end
it "should delete the hourly rate" do
it 'should delete the hourly rate' do
expect(user.rates(true)).to be_empty
end
end
describe "WHEN not providing a project
WHEN not providing attributes" do
before do
default_hourly_rate.save!
user.default_rates(true)
@ -181,7 +182,7 @@ describe User, type: :model do
user.set_existing_rates(nil, {})
end
it "should delete the default hourly rate" do
it 'should delete the default hourly rate' do
expect(user.default_rates(true)).to be_empty
end
end

@ -29,8 +29,8 @@ describe VariableCostObject, type: :model do
before do
allow(User).to receive(:current).and_return(user)
@variable_cost_object = FactoryGirl.create(:variable_cost_object , project: project,
author: user)
@variable_cost_object = FactoryGirl.create(:variable_cost_object, project: project,
author: user)
@initial_journal = @variable_cost_object.journals.first
@recreated_journal = @variable_cost_object.recreate_initial_journal!
@ -39,7 +39,7 @@ describe VariableCostObject, type: :model do
it { expect(@initial_journal).to be_identical(@recreated_journal) }
end
describe "initialization" do
describe 'initialization' do
let(:cost_object) { VariableCostObject.new }
before do
@ -49,7 +49,7 @@ describe VariableCostObject, type: :model do
it { expect(cost_object.author).to eq(user) }
end
describe "destroy" do
describe 'destroy' do
let(:work_package) { FactoryGirl.create(:work_package) }
before do

@ -20,10 +20,14 @@
require 'spec_helper'
describe WorkPackage, type: :model do
let(:work_package) { FactoryGirl.create(:work_package, project: project,
status: status) }
let(:work_package2) { FactoryGirl.create(:work_package, project: project2,
status: status) }
let(:work_package) {
FactoryGirl.create(:work_package, project: project,
status: status)
}
let(:work_package2) {
FactoryGirl.create(:work_package, project: project2,
status: status)
}
let(:user) { FactoryGirl.create(:user) }
let(:type) { FactoryGirl.create(:type_standard) }
@ -31,20 +35,28 @@ describe WorkPackage, type: :model do
let(:project2) { FactoryGirl.create(:project, types: [type]) }
let(:role) { FactoryGirl.create(:role) }
let(:role2) { FactoryGirl.create(:role) }
let(:member) { FactoryGirl.create(:member, principal: user,
roles: [role]) }
let(:member2) { FactoryGirl.create(:member, principal: user,
roles: [role2],
project: work_package2.project) }
let(:member) {
FactoryGirl.create(:member, principal: user,
roles: [role])
}
let(:member2) {
FactoryGirl.create(:member, principal: user,
roles: [role2],
project: work_package2.project)
}
let(:status) { FactoryGirl.create(:status) }
let(:priority) { FactoryGirl.create(:priority) }
let(:cost_type) { FactoryGirl.create(:cost_type) }
let(:cost_entry) { FactoryGirl.build(:cost_entry, work_package: work_package,
project: work_package.project,
cost_type: cost_type) }
let(:cost_entry2) { FactoryGirl.build(:cost_entry, work_package: work_package2,
project: work_package2.project,
cost_type: cost_type) }
let(:cost_entry) {
FactoryGirl.build(:cost_entry, work_package: work_package,
project: work_package.project,
cost_type: cost_type)
}
let(:cost_entry2) {
FactoryGirl.build(:cost_entry, work_package: work_package2,
project: work_package2.project,
cost_type: cost_type)
}
describe '#cleanup_action_required_before_destructing?' do
describe 'w/ the work package having a cost entry' do
@ -53,7 +65,7 @@ describe WorkPackage, type: :model do
cost_entry.save!
end
it "should be true" do
it 'should be true' do
expect(WorkPackage.cleanup_action_required_before_destructing?(work_package)).to be_truthy
end
end
@ -65,7 +77,7 @@ describe WorkPackage, type: :model do
cost_entry2.save!
end
it "should be true" do
it 'should be true' do
expect(WorkPackage.cleanup_action_required_before_destructing?([work_package, work_package2])).to be_truthy
end
end
@ -75,7 +87,7 @@ describe WorkPackage, type: :model do
work_package
end
it "should be false" do
it 'should be false' do
expect(WorkPackage.cleanup_action_required_before_destructing?(work_package)).to be_falsey
end
end
@ -98,7 +110,7 @@ describe WorkPackage, type: :model do
work_package
end
it "should be empty" do
it 'should be empty' do
expect(WorkPackage.associated_classes_to_address_before_destruction_of(work_package)).to be_empty
end
end

@ -23,29 +23,31 @@ describe WorkPackage, type: :model do
let(:user) { FactoryGirl.create(:admin) }
let(:role) { FactoryGirl.create(:role) }
let(:project) do
project = FactoryGirl.create(:project_with_types)
project.add_member!(user, role)
project
project = FactoryGirl.create(:project_with_types)
project.add_member!(user, role)
project
end
let(:project2) { FactoryGirl.create(:project_with_types, types: project.types) }
let(:work_package) { FactoryGirl.create(:work_package, project: project,
type: project.types.first,
author: user) }
let!(:cost_entry) { FactoryGirl.create(:cost_entry, work_package: work_package, project: project, units: 3, spent_on: Date.today, user: user, comments: "test entry") }
let(:work_package) {
FactoryGirl.create(:work_package, project: project,
type: project.types.first,
author: user)
}
let!(:cost_entry) { FactoryGirl.create(:cost_entry, work_package: work_package, project: project, units: 3, spent_on: Date.today, user: user, comments: 'test entry') }
let!(:cost_object) { FactoryGirl.create(:cost_object, project: project) }
before(:each) do
allow(User).to receive(:current).and_return(user)
end
it "should update cost entries on move" do
it 'should update cost entries on move' do
expect(work_package.project_id).to eql project.id
expect(work_package.move_to_project(project2)).not_to be_falsey
expect(cost_entry.reload.project_id).to eql project2.id
end
it "should allow to set cost_object to nil" do
it 'should allow to set cost_object to nil' do
work_package.cost_object = cost_object
work_package.save!
expect(work_package.cost_object).to eql cost_object

@ -42,8 +42,8 @@ describe 'API v3 Work package form resource', type: :request do
let(:post_path) { api_v3_paths.work_package_form work_package.id }
let(:valid_params) do
{
_type: 'WorkPackage',
lockVersion: work_package.lock_version
_type: 'WorkPackage',
lockVersion: work_package.lock_version
}
end
@ -64,7 +64,7 @@ describe 'API v3 Work package form resource', type: :request do
shared_examples_for 'having no errors' do
it {
expect(subject.body).to be_json_eql({}.to_json)
.at_path('_embedded/validationErrors')
.at_path('_embedded/validationErrors')
}
end
@ -86,8 +86,8 @@ describe 'API v3 Work package form resource', type: :request do
context 'filled' do
let(:valid_params) do
{
_type: 'WorkPackage',
lockVersion: work_package.lock_version
_type: 'WorkPackage',
lockVersion: work_package.lock_version
}
end
@ -110,9 +110,9 @@ describe 'API v3 Work package form resource', type: :request do
it 'should list the budgets' do
expect(subject.body).to be_json_eql(budget_link.to_json)
.at_path("#{links_path}/allowedValues/1/href")
.at_path("#{links_path}/allowedValues/1/href")
expect(subject.body).to be_json_eql(other_budget_link.to_json)
.at_path("#{links_path}/allowedValues/0/href")
.at_path("#{links_path}/allowedValues/0/href")
end
end

@ -52,8 +52,8 @@ describe 'API v3 Work package resource', type: :request do
let(:patch_path) { api_v3_paths.work_package work_package.id }
let(:valid_params) do
{
_type: 'WorkPackage',
lockVersion: work_package.lock_version
_type: 'WorkPackage',
lockVersion: work_package.lock_version
}
end
@ -73,7 +73,7 @@ describe 'API v3 Work package resource', type: :request do
let(:budget_parameter) { { _links: { costObject: { href: budget_link } } } }
let(:params) { valid_params.merge(budget_parameter) }
before { allow(User).to receive(:current).and_return current_user }
before do allow(User).to receive(:current).and_return current_user end
context 'valid' do
include_context 'patch request'
@ -82,7 +82,7 @@ describe 'API v3 Work package resource', type: :request do
it 'should respond with the work package and its new budget' do
expect(subject.body).to be_json_eql(target_budget.subject.to_json)
.at_path('_embedded/costObject/subject')
.at_path('_embedded/costObject/subject')
end
end

@ -20,34 +20,51 @@
require 'spec_helper'
describe CostObjectsController, type: :routing do
describe "routing" do
it { expect(get('/projects/blubs/cost_objects/new')).to route_to(controller: 'cost_objects',
action: 'new',
project_id: 'blubs') }
it { expect(post('/projects/blubs/cost_objects')).to route_to(controller: 'cost_objects',
action: 'create',
project_id: 'blubs') }
it { expect(get('/projects/blubs/cost_objects')).to route_to(controller: 'cost_objects',
action: 'index',
project_id: 'blubs') }
it { expect(get('/cost_objects/5')).to route_to(controller: 'cost_objects',
action: 'show',
id: '5') }
it { expect(put('/cost_objects/5')).to route_to(controller: 'cost_objects',
action: 'update',
id: '5') }
it { expect(delete('/cost_objects/5')).to route_to(controller: 'cost_objects',
action: 'destroy',
id: '5') }
it { expect(post('/projects/42/cost_objects/update_material_budget_item')).to route_to(controller: 'cost_objects',
action: 'update_material_budget_item',
project_id: '42') }
it { expect(post('/projects/42/cost_objects/update_labor_budget_item')).to route_to(controller: 'cost_objects',
action: 'update_labor_budget_item',
project_id: '42') }
it { expect(get('/cost_objects/5/copy')).to route_to(controller: 'cost_objects',
describe 'routing' do
it {
expect(get('/projects/blubs/cost_objects/new')).to route_to(controller: 'cost_objects',
action: 'new',
project_id: 'blubs')
}
it {
expect(post('/projects/blubs/cost_objects')).to route_to(controller: 'cost_objects',
action: 'create',
project_id: 'blubs')
}
it {
expect(get('/projects/blubs/cost_objects')).to route_to(controller: 'cost_objects',
action: 'index',
project_id: 'blubs')
}
it {
expect(get('/cost_objects/5')).to route_to(controller: 'cost_objects',
action: 'show',
id: '5')
}
it {
expect(put('/cost_objects/5')).to route_to(controller: 'cost_objects',
action: 'update',
id: '5')
}
it {
expect(delete('/cost_objects/5')).to route_to(controller: 'cost_objects',
action: 'destroy',
id: '5')
}
it {
expect(post('/projects/42/cost_objects/update_material_budget_item')).to route_to(controller: 'cost_objects',
action: 'update_material_budget_item',
project_id: '42')
}
it {
expect(post('/projects/42/cost_objects/update_labor_budget_item')).to route_to(controller: 'cost_objects',
action: 'update_labor_budget_item',
project_id: '42')
}
it {
expect(get('/cost_objects/5/copy')).to route_to(controller: 'cost_objects',
action: 'copy',
id: '5') }
id: '5')
}
end
end

@ -20,34 +20,50 @@
require 'spec_helper'
describe CostTypesController, type: :routing do
describe "routing" do
it { expect(get('/cost_types')).to route_to(controller: 'cost_types',
action: 'index') }
describe 'routing' do
it {
expect(get('/cost_types')).to route_to(controller: 'cost_types',
action: 'index')
}
it { expect(post('/cost_types')).to route_to(controller: 'cost_types',
action: 'create') }
it {
expect(post('/cost_types')).to route_to(controller: 'cost_types',
action: 'create')
}
it { expect(get('/cost_types/new')).to route_to(controller: 'cost_types',
action: 'new') }
it {
expect(get('/cost_types/new')).to route_to(controller: 'cost_types',
action: 'new')
}
it { expect(get('/cost_types/5/edit')).to route_to(controller: 'cost_types',
action: 'edit',
id: '5') }
it {
expect(get('/cost_types/5/edit')).to route_to(controller: 'cost_types',
action: 'edit',
id: '5')
}
it { expect(put('/cost_types/5')).to route_to(controller: 'cost_types',
action: 'update',
id: '5') }
it {
expect(put('/cost_types/5')).to route_to(controller: 'cost_types',
action: 'update',
id: '5')
}
it { expect(put('/cost_types/5/set_rate')).to route_to(controller: 'cost_types',
action: 'set_rate',
id: '5') }
it {
expect(put('/cost_types/5/set_rate')).to route_to(controller: 'cost_types',
action: 'set_rate',
id: '5')
}
it { expect(delete('/cost_types/5')).to route_to(controller: 'cost_types',
action: 'destroy',
id: '5') }
it {
expect(delete('/cost_types/5')).to route_to(controller: 'cost_types',
action: 'destroy',
id: '5')
}
it { expect(patch('/cost_types/5/restore')).to route_to(controller: 'cost_types',
action: 'restore',
id: '5') }
it {
expect(patch('/cost_types/5/restore')).to route_to(controller: 'cost_types',
action: 'restore',
id: '5')
}
end
end

@ -20,33 +20,47 @@
require 'spec_helper'
describe CostlogController, type: :routing do
describe "routing" do
it { expect(get('/work_packages/5/cost_entries')).to route_to(controller: 'costlog',
action: 'index',
work_package_id: '5') }
describe 'routing' do
it {
expect(get('/work_packages/5/cost_entries')).to route_to(controller: 'costlog',
action: 'index',
work_package_id: '5')
}
it { expect(get('/projects/blubs/cost_entries/new')).to route_to(controller: 'costlog',
action: 'new',
project_id: 'blubs') }
it {
expect(get('/projects/blubs/cost_entries/new')).to route_to(controller: 'costlog',
action: 'new',
project_id: 'blubs')
}
it { expect(post('/projects/blubs/cost_entries')).to route_to(controller: 'costlog',
action: 'create',
project_id: 'blubs') }
it {
expect(post('/projects/blubs/cost_entries')).to route_to(controller: 'costlog',
action: 'create',
project_id: 'blubs')
}
it { expect(get('/work_packages/5/cost_entries/new')).to route_to(controller: 'costlog',
action: 'new',
work_package_id: '5') }
it {
expect(get('/work_packages/5/cost_entries/new')).to route_to(controller: 'costlog',
action: 'new',
work_package_id: '5')
}
it { expect(get('/cost_entries/5/edit')).to route_to(controller: 'costlog',
action: 'edit',
id: '5') }
it {
expect(get('/cost_entries/5/edit')).to route_to(controller: 'costlog',
action: 'edit',
id: '5')
}
it { expect(put('/cost_entries/5')).to route_to(controller: 'costlog',
action: 'update',
id: '5') }
it {
expect(put('/cost_entries/5')).to route_to(controller: 'costlog',
action: 'update',
id: '5')
}
it { expect(delete('/cost_entries/5')).to route_to(controller: 'costlog',
action: 'destroy',
id: '5') }
it {
expect(delete('/cost_entries/5')).to route_to(controller: 'costlog',
action: 'destroy',
id: '5')
}
end
end

@ -20,29 +20,39 @@
require 'spec_helper'
describe HourlyRatesController, type: :routing do
describe "routing" do
it { expect(get('/projects/blubs/hourly_rates/5')).to route_to(controller: 'hourly_rates',
action: 'show',
project_id: 'blubs',
id: '5') }
describe 'routing' do
it {
expect(get('/projects/blubs/hourly_rates/5')).to route_to(controller: 'hourly_rates',
action: 'show',
project_id: 'blubs',
id: '5')
}
it { expect(get('/projects/blubs/hourly_rates/5/edit')).to route_to(controller: 'hourly_rates',
action: 'edit',
project_id: 'blubs',
id: '5') }
it {
expect(get('/projects/blubs/hourly_rates/5/edit')).to route_to(controller: 'hourly_rates',
action: 'edit',
project_id: 'blubs',
id: '5')
}
it { expect(get('/hourly_rates/5/edit')).to route_to(controller: 'hourly_rates',
action: 'edit',
id: '5') }
it {
expect(get('/hourly_rates/5/edit')).to route_to(controller: 'hourly_rates',
action: 'edit',
id: '5')
}
it { expect(put('/projects/blubs/hourly_rates/5')).to route_to(controller: 'hourly_rates',
action: 'update',
project_id: 'blubs',
id: '5') }
it {
expect(put('/projects/blubs/hourly_rates/5')).to route_to(controller: 'hourly_rates',
action: 'update',
project_id: 'blubs',
id: '5')
}
it { expect(post('/projects/blubs/hourly_rates/5/set_rate')).to route_to(controller: 'hourly_rates',
action: 'set_rate',
project_id: 'blubs',
id: '5') }
it {
expect(post('/projects/blubs/hourly_rates/5/set_rate')).to route_to(controller: 'hourly_rates',
action: 'set_rate',
project_id: 'blubs',
id: '5')
}
end
end

@ -18,6 +18,6 @@
#++
# -- load spec_helper from OpenProject core
require "spec_helper"
require 'spec_helper'
require File.join(File.dirname(__FILE__), "plugin_spec_helper")
require File.join(File.dirname(__FILE__), 'plugin_spec_helper')

Loading…
Cancel
Save