Merge pull request #101 from finnlabs/feature/14005_show_costs_attributes_in_overview_tab

[Feature] 14005 show costs attributes in overview tab
pull/6827/head
manwithtwowatches 10 years ago
commit db94a0b080
  1. 38
      app/assets/javascripts/angular/openproject-costs-app.js
  2. 50
      app/assets/javascripts/angular/work_packages/directives/summarized-cost-entries-directive.js
  3. 36
      app/assets/stylesheets/costs/costs.css.sass
  4. 0
      app/assets/stylesheets/costs/costs_legacy.css
  5. 23
      app/views/hooks/costs/_view_work_package_overview_attributes.html.erb
  6. 43
      config/locales/js-de.yml
  7. 43
      config/locales/js-en.yml
  8. 52
      lib/api/v3/cost_objects/cost_object_model.rb
  9. 69
      lib/api/v3/cost_objects/cost_object_representer.rb
  10. 55
      lib/api/v3/cost_types/cost_type_model.rb
  11. 64
      lib/api/v3/cost_types/cost_type_representer.rb
  12. 99
      lib/open_project/costs/attributes_helper.rb
  13. 60
      lib/open_project/costs/engine.rb
  14. 2
      lib/open_project/costs/hooks/work_package_hook.rb
  15. 47
      lib/open_project/costs/hooks/work_packages_overview_attributes.rb
  16. 72
      lib/open_project/costs/hooks/work_packages_show_attributes.rb
  17. 12
      public/templates/work_packages/summarized_cost_entries.html
  18. 51
      spec/lib/api/v3/cost_objects/cost_object_model_spec.rb
  19. 58
      spec/lib/api/v3/cost_objects/cost_object_representer_spec.rb
  20. 53
      spec/lib/api/v3/cost_types/cost_type_model_spec.rb
  21. 58
      spec/lib/api/v3/cost_types/cost_type_representer_spec.rb
  22. 89
      spec/lib/api/v3/work_packages/work_package_representer_spec.rb

@ -0,0 +1,38 @@
//-- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 3.
//
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
// Copyright (C) 2006-2013 Jean-Philippe Lang
// Copyright (C) 2010-2013 the ChiliProject Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// See doc/COPYRIGHT.rdoc for more details.
//++
// main app
var openprojectCostsApp = angular.module('openproject');
openprojectCostsApp.run(['HookService', function(HookService) {
HookService.register('workPackageOverviewAttributes', function(params) {
var isEmpty = params.workPackage.embedded.summarizedCostEntries.length == 0;
return ((params.type == "spentUnits" && !isEmpty) ? "summarized-cost-entries" : undefined);
});
}]);

@ -0,0 +1,50 @@
//-- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 3.
//
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
// Copyright (C) 2006-2013 Jean-Philippe Lang
// Copyright (C) 2010-2013 the ChiliProject Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// See doc/COPYRIGHT.rdoc for more details.
//++
angular.module('openproject.workPackages.directives')
.directive('summarizedCostEntries', ['PathHelper', function(PathHelper) {
return {
restrict: 'E',
templateUrl: '/templates/work_packages/summarized_cost_entries.html',
link: function(scope, element, attributes) {
if (scope.workPackage.embedded.summarizedCostEntries) {
scope.costTypes = scope.workPackage.embedded.summarizedCostEntries;
}
scope.linkToSummary = function(costType) {
var link = PathHelper.staticWorkPackagePath(scope.workPackage.props.id);
link += '/cost_entries?cost_type_id=' + costType.props.id;
link += '&project_id=' + scope.workPackage.props.projectId;
return link;
};
}
};
}]);

@ -0,0 +1,36 @@
/*-- copyright
* OpenProject Backlogs Plugin
*
* Copyright (C)2013 the OpenProject Foundation (OPF)
* Copyright (C)2011 Stephan Eckardt, Tim Felgentreff, Marnen Laibow-Koser, Sandro Munda
* Copyright (C)2010-2011 friflaj
* Copyright (C)2010 Maxime Guilbot, Andrew Vit, Joakim Kolsjö, ibussieres, Daniel Passos, Jason Vasquez, jpic, Emiliano Heyns
* Copyright (C)2009-2010 Mark Maglana
* Copyright (C)2009 Joe Heck, Nate Lowrie
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 3.
*
* OpenProject Backlogs is a derivative work based on ChiliProject Backlogs.
* The copyright follows:
* Copyright (C) 2010-2011 - Emiliano Heyns, Mark Maglana, friflaj
* Copyright (C) 2011 - Jens Ulferts, Gregor Schmidt - Finn GmbH - Berlin, Germany
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* See doc/COPYRIGHT.rdoc for more details.
*/
@import costs/costs_legacy

@ -0,0 +1,23 @@
<%#-- copyright
OpenProject Costs Plugin
Copyright (C) 2009 - 2014 the OpenProject Foundation (OPF)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 3.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
++#%>
<%= javascript_include_tag 'angular/openproject-costs-app.js' %>
<%= javascript_include_tag 'angular/work_packages/directives/summarized-cost-entries-directive.js' %>
<%= stylesheet_link_tag 'costs/costs.css' %>

@ -0,0 +1,43 @@
#-- copyright
# OpenProject Backlogs Plugin
#
# Copyright (C)2013-2014 the OpenProject Foundation (OPF)
# Copyright (C)2011 Stephan Eckardt, Tim Felgentreff, Marnen Laibow-Koser, Sandro Munda
# Copyright (C)2010-2011 friflaj
# Copyright (C)2010 Maxime Guilbot, Andrew Vit, Joakim Kolsjö, ibussieres, Daniel Passos, Jason Vasquez, jpic, Emiliano Heyns
# Copyright (C)2009-2010 Mark Maglana
# Copyright (C)2009 Joe Heck, Nate Lowrie
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License version 3.
#
# OpenProject Backlogs is a derivative work based on ChiliProject Backlogs.
# The copyright follows:
# Copyright (C) 2010-2011 - Emiliano Heyns, Mark Maglana, friflaj
# Copyright (C) 2011 - Jens Ulferts, Gregor Schmidt - Finn GmbH - Berlin, Germany
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
de:
js:
work_packages:
properties:
costObject: "Budget"
spentHours: "Aufgewendete Zeit"
overallCosts: "Gesamtkosten"
spentUnits: "Gebuchte Einheiten"

@ -0,0 +1,43 @@
#-- copyright
# OpenProject Backlogs Plugin
#
# Copyright (C)2013-2014 the OpenProject Foundation (OPF)
# Copyright (C)2011 Stephan Eckardt, Tim Felgentreff, Marnen Laibow-Koser, Sandro Munda
# Copyright (C)2010-2011 friflaj
# Copyright (C)2010 Maxime Guilbot, Andrew Vit, Joakim Kolsjö, ibussieres, Daniel Passos, Jason Vasquez, jpic, Emiliano Heyns
# Copyright (C)2009-2010 Mark Maglana
# Copyright (C)2009 Joe Heck, Nate Lowrie
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License version 3.
#
# OpenProject Backlogs is a derivative work based on ChiliProject Backlogs.
# The copyright follows:
# Copyright (C) 2010-2011 - Emiliano Heyns, Mark Maglana, friflaj
# Copyright (C) 2011 - Jens Ulferts, Gregor Schmidt - Finn GmbH - Berlin, Germany
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
en:
js:
work_packages:
properties:
costObject: "Budget"
spentHours: "Spent time"
overallCosts: "Overall costs"
spentUnits: "Spent units"

@ -0,0 +1,52 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
require 'reform'
require 'reform/form/coercion'
module API
module V3
module CostObjects
class CostObjectModel < Reform::Form
property :project_id, type: Integer
property :author, type: String
property :subject, type: String
property :description, type: String
property :type, type: String
property :fixed_date, type: DateTime
property :created_on, type: DateTime
property :updated_on, type: DateTime
def author
::API::V3::Users::UserModel.new(model.author) unless model.author.nil?
end
end
end
end
end

@ -0,0 +1,69 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
require 'roar/decorator'
require 'roar/representer/json/hal'
module API
module V3
module CostObjects
class CostObjectRepresenter < Roar::Decorator
include Roar::Representer::JSON::HAL
include Roar::Representer::Feature::Hypermedia
include OpenProject::StaticRouting::UrlHelpers
self.as_strategy = API::Utilities::CamelCasingStrategy.new
def initialize(model, options = {}, *expand)
@expand = expand
super(model)
end
property :_type, exec_context: :decorator
property :id, render_nil: true
property :project_id
property :project_name, getter: -> (*) { model.project.try(:name) }
property :subject, render_nil: true
property :description, render_nil: true
property :type, render_nil: true
property :fixed_date, getter: -> (*) { model.created_on.utc.iso8601 }, render_nil: true
property :created_at, getter: -> (*) { model.created_on.utc.iso8601 }, render_nil: true
property :updated_at, getter: -> (*) { model.updated_on.utc.iso8601 }, render_nil: true
property :author, embedded: true, class: ::API::V3::Users::UserModel, decorator: ::API::V3::Users::UserRepresenter, if: -> (*) { !author.nil? }
def _type
'CostObject'
end
end
end
end
end

@ -0,0 +1,55 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
require 'reform'
require 'reform/form/coercion'
module API
module V3
module CostTypes
class CostTypeModel < Reform::Form
def initialize(model, options = {})
@units = options[:units]
super(model)
end
property :id, type: Integer
property :name, type: String
property :unit, type: String
property :unit_plural, type: String
def units
@units ? @units : model.cost_entries.sum(&:units)
end
end
end
end
end

@ -0,0 +1,64 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
require 'roar/decorator'
require 'roar/representer/json/hal'
module API
module V3
module CostTypes
class CostTypeRepresenter < Roar::Decorator
include Roar::Representer::JSON::HAL
include Roar::Representer::Feature::Hypermedia
include OpenProject::StaticRouting::UrlHelpers
self.as_strategy = API::Utilities::CamelCasingStrategy.new
def initialize(model, options = {}, *expand)
@expand = expand
@work_package = options[:work_package]
super(model)
end
property :_type, exec_context: :decorator
property :id, render_nil: true
property :name, render_nil: true
property :units, render_nil: true
property :unit, render_nil: true
property :unit_plural, render_nil: true
def _type
'CostType'
end
end
end
end
end

@ -0,0 +1,99 @@
#-- copyright
# OpenProject Costs Plugin
#
# Copyright (C) 2009 - 2014 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#++
module OpenProject::Costs
class AttributesHelper
def initialize(work_package)
@work_package = work_package
end
def time_entries_sum
@time_entries_sum ||= compute_time_entries_sum
end
def overall_costs
@overall_costs ||= compute_overall_costs
end
def summarized_cost_entries
@summarized_cost_entries ||= compute_summarized_cost_entries
end
private
def compute_time_entries_sum
time_entries.sum(&:hours) if user_allowed_to?(:view_time_entries, :view_own_time_entries)
end
def compute_overall_costs
if material_costs || labor_costs
sum_costs = 0
sum_costs += material_costs if material_costs
sum_costs += labor_costs if labor_costs
else
sum_costs = nil
end
sum_costs
end
def compute_summarized_cost_entries
return {} if cost_entries.blank? || !user_allowed_to?(:view_cost_entries, :view_own_cost_entries)
last_cost_type = ""
cost_entries.sort_by(&:id).each_with_object({}) do |entry, hash|
if entry.cost_type == last_cost_type
hash[last_cost_type][:units] += entry.units
else
last_cost_type = entry.cost_type
hash[last_cost_type] = {}
hash[last_cost_type][:units] = entry.units
hash[last_cost_type][:unit] = entry.cost_type.unit
hash[last_cost_type][:unit_plural] = entry.cost_type.unit_plural
end
end
end
def time_entries
@work_package.time_entries.visible(User.current, @work_package.project)
end
def material_costs
cost_entries_with_rate = cost_entries.select{|c| c.costs_visible_by?(User.current)}
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.current)}
time_entries_with_rate.blank? ? nil : time_entries_with_rate.collect(&:real_costs).sum
end
def cost_entries
@cost_entries ||= @work_package.cost_entries.visible(User.current, @work_package.project)
end
def user_allowed_to?(*privileges)
privileges.inject(false) do |result, privilege|
result || User.current.allowed_to?(privilege, @work_package.project)
end
end
end
end

@ -103,7 +103,58 @@ module OpenProject::Costs
patches [:WorkPackage, :Project, :Query, :User, :TimeEntry, :Version, :PermittedParams,
:ProjectsController, :ApplicationHelper, :UsersHelper]
assets %w(costs/costs.css costs/costs.js)
extend_api_response(:v3, :work_packages, :work_package) do
include Redmine::I18n
include ActionView::Helpers::NumberHelper
property :cost_object,
exec_context: :decorator,
embedded: true,
class: ::API::V3::CostObjects::CostObjectModel,
decorator: ::API::V3::CostObjects::CostObjectRepresenter,
if: -> (*) { !represented.work_package.cost_object.nil? }
property :spent_hours,
exec_context: :decorator,
if: -> (*) { current_user_allowed_to_view_spent_hours }
property :overall_costs, exec_context: :decorator
property :summarized_cost_entries, embedded: true, exec_context: :decorator
send(:define_method, :cost_object) do
::API::V3::CostObjects::CostObjectModel.new(represented.work_package.cost_object)
end
send(:define_method, :spent_hours) do
self.attributes_helper.time_entries_sum
end
send(:define_method, :current_user_allowed_to_view_spent_hours) do
current_user_allowed_to(:view_time_entries, represented.work_package) ||
current_user_allowed_to(:view_own_time_entries, represented.work_package)
end
send(:define_method, :overall_costs) do
number_to_currency(self.attributes_helper.overall_costs)
end
send(:define_method, :summarized_cost_entries) do
self.attributes_helper.summarized_cost_entries
.map { |s| ::API::V3::CostTypes::CostTypeModel.new(s[0], units: s[1][:units]) }
.map { |c| ::API::V3::CostTypes::CostTypeRepresenter.new(c, work_package: represented.work_package) }
end
send(:define_method, :attributes_helper) do
@attributes_helper ||= OpenProject::Costs::AttributesHelper.new(represented.work_package)
end
end
assets %w(angular/work_packages/directives/summarized-cost-entries-directive.js
angular/openproject-costs-app.js
costs/costs.css
costs/costs.js)
initializer "costs.register_hooks" do
require 'open_project/costs/hooks'
@ -112,6 +163,7 @@ module OpenProject::Costs
require 'open_project/costs/hooks/project_hook'
require 'open_project/costs/hooks/work_package_action_menu'
require 'open_project/costs/hooks/work_packages_show_attributes'
require 'open_project/costs/hooks/work_packages_overview_attributes'
end
initializer 'costs.register_observers' do |app|
@ -125,6 +177,12 @@ module OpenProject::Costs
ActionView::Helpers::NumberHelper.send(:include, OpenProject::Costs::Patches::NumberHelperPatch)
end
# Initializer to combine this engines static assets with the static assets of the hosting site.
# Thanks to http://jbavari.github.io/blog/2013/10/26/rev-up-your-rails-engine-for-static-assets/
initializer "static assets" do |app|
app.middleware.insert_before(::ActionDispatch::Static, ::ActionDispatch::Static, "#{root}/public")
end
config.to_prepare do
# loading the class so that acts_as_journalized gets registered
VariableCostObject

@ -30,6 +30,8 @@ class OpenProject::Costs::Hooks::WorkPackageHook < Redmine::Hook::ViewListener
render_on :view_work_packages_move_bottom, :partial => 'hooks/costs/view_work_packages_move_bottom'
render_on :view_work_package_overview_attributes, partial: 'hooks/costs/view_work_package_overview_attributes'
# Updates the cost object after a move
#
# Context:

@ -0,0 +1,47 @@
#-- copyright
# OpenProject Costs Plugin
#
# Copyright (C) 2009 - 2014 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#++
module OpenProject::Costs::Hooks
class WorkPackagesOverviewHook < Redmine::Hook::ViewListener
def work_packages_overview_attributes(context = {})
project = context[:project]
attributes = context[:attributes]
return unless project && project.module_enabled?(:costs_module)
attributes.reject!{ |attribute| attribute == :spentTime }
attributes << :costObject
attributes << :spentHours if user_allowed_to?(project, :view_time_entries, :view_own_time_entries)
attributes << :overallCosts
attributes << :spentUnits if user_allowed_to?(project, :view_cost_entries, :view_own_cost_entries)
attributes
end
private
def user_allowed_to?(project, *privileges)
privileges.inject(false) do |result, privilege|
result || User.current.allowed_to?(privilege, project)
end
end
end
end

@ -39,93 +39,45 @@ module OpenProject::Costs::Hooks
private
def cost_entries
@work_package.cost_entries.visible(User.current, @work_package.project)
end
def material_costs
cost_entries_with_rate = cost_entries.select{|c| c.costs_visible_by?(User.current)}
cost_entries_with_rate.blank? ? nil : cost_entries_with_rate.collect(&:real_costs).sum
end
def time_entries
@work_package.time_entries.visible(User.current, @work_package.project)
end
def labor_costs
time_entries_with_rate = time_entries.select{|c| c.costs_visible_by?(User.current)}
time_entries_with_rate.blank? ? nil : time_entries_with_rate.collect(&:real_costs).sum
end
def overall_costs
if material_costs || labor_costs
sum_costs = 0
sum_costs += material_costs if material_costs
sum_costs += labor_costs if labor_costs
else
sum_costs = nil
end
sum_costs
end
def cost_work_package_attributes
attributes = []
attributes_helper = OpenProject::Costs::AttributesHelper.new(@work_package)
attributes << work_package_show_table_row(:cost_object) do
@work_package.cost_object ?
link_to_cost_object(@work_package.cost_object) :
empty_element_tag
end
if User.current.allowed_to?(:view_time_entries, @project) ||
User.current.allowed_to?(:view_own_time_entries, @project)
if attributes_helper.time_entries_sum
attributes << work_package_show_table_row(:spent_hours) do
# TODO: put inside controller or model
summed_hours = time_entries.sum(&:hours)
summed_hours = attributes_helper.time_entries_sum
summed_hours > 0 ?
link_to(l_hours(summed_hours), work_package_time_entries_path(@work_package)) :
empty_element_tag
end
end
attributes << work_package_show_table_row(:overall_costs) do
overall_costs.nil? ?
empty_element_tag :
number_to_currency(overall_costs)
attributes_helper.overall_costs ?
number_to_currency(attributes_helper.overall_costs) :
empty_element_tag
end
if User.current.allowed_to?(:view_cost_entries, @project) ||
User.current.allowed_to?(:view_own_cost_entries, @project)
if attributes_helper.summarized_cost_entries
attributes << work_package_show_table_row(:spent_units) do
summarized_cost_entries(cost_entries, @work_package)
summarized_cost_entry_links(attributes_helper.summarized_cost_entries, @work_package)
end
end
attributes
end
def summarized_cost_entries(cost_entries, work_package, create_link=true)
last_cost_type = ""
return empty_element_tag if cost_entries.blank?
result = cost_entries.sort_by(&:id).inject(Hash.new) do |result, entry|
if entry.cost_type == last_cost_type
result[last_cost_type][:units] += entry.units
else
last_cost_type = entry.cost_type
result[last_cost_type] = {}
result[last_cost_type][:units] = entry.units
result[last_cost_type][:unit] = entry.cost_type.unit
result[last_cost_type][:unit_plural] = entry.cost_type.unit_plural
end
result
end
def summarized_cost_entry_links(cost_entries, work_package, create_link=true)
str_array = []
result.each do |k, v|
cost_entries.each do |k, v|
txt = pluralize(v[:units], v[:unit], v[:unit_plural])
if create_link
# TODO why does this have project_id, work_package_id and cost_type_id params?

@ -0,0 +1,12 @@
<span class="costs costTypes" ng-if="costTypes">
<span ng-repeat="costType in costTypes">
<a ng-href="{{ linkToSummary(costType) }}" title="{{ costType.props.name }}">
{{ costType.props.units }}
<span class="unit" ng-switch="costType.props.units">
<span ng-switch-when="1">{{ costType.props.unit }}</span>
<span ng-switch-default>{{ costType.props.unitPlural }}</span>
</span>
</a>
<span ng-if="!$last">-</span>
</span>
</span>

@ -0,0 +1,51 @@
#-- copyright
# OpenProject Costs Plugin
#
# Copyright (C) 2009 - 2014 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#++
require 'spec_helper'
describe ::API::V3::CostObjects::CostObjectModel do
include Capybara::RSpecMatchers
let(:project) { FactoryGirl.build(:project) }
let(:user) { FactoryGirl.build(:user, member_in_project: project) }
let(:cost_object) { FactoryGirl.build(:cost_object,
author: user,
project: project,
updated_on: Date.today) }
subject(:model) { ::API::V3::CostObjects::CostObjectModel.new(cost_object) }
describe 'attributes' do
it { expect(subject.project_id).to eq(cost_object.project_id) }
it { expect(subject.author.id).to eq(cost_object.author_id) }
it { expect(subject.subject).to eq(cost_object.subject) }
it { expect(subject.description).to eq(cost_object.description) }
it { expect(subject.type).to eq(cost_object.type) }
it { expect(subject.fixed_date).to eq(cost_object.fixed_date) }
it { expect(subject.created_on).to eq(cost_object.created_on) }
it { expect(subject.updated_on).to eq(cost_object.updated_on) }
end
end

@ -0,0 +1,58 @@
#-- copyright
# OpenProject Costs Plugin
#
# Copyright (C) 2009 - 2014 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#++
require 'spec_helper'
describe ::API::V3::CostObjects::CostObjectRepresenter 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(:cost_object) { FactoryGirl.build(:cost_object,
author: user,
project: project,
created_on: 1.day.ago,
updated_on: Date.today) }
let(:representer) { described_class.new(model) }
let(:model) { ::API::V3::CostObjects::CostObjectModel.new(cost_object) }
context 'generation' do
subject(:generated) { representer.to_json }
it { should include_json('CostObject'.to_json).at_path('_type') }
describe 'cost_object' do
it { should have_json_path('id') }
it { should have_json_path('description') }
it { should have_json_path('projectId') }
it { should have_json_path('projectName') }
it { should have_json_path('subject') }
it { should have_json_path('type') }
it { should have_json_path('createdAt') }
it { should have_json_path('updatedAt') }
end
end
end

@ -0,0 +1,53 @@
#-- copyright
# OpenProject Costs Plugin
#
# Copyright (C) 2009 - 2014 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#++
require 'spec_helper'
describe ::API::V3::CostTypes::CostTypeModel do
include Capybara::RSpecMatchers
let(:project) { FactoryGirl.build(:project) }
let(:user) { FactoryGirl.build(:user, member_in_project: project) }
let(:cost_type) { FactoryGirl.build(:cost_type) }
let!(:cost_entry) { FactoryGirl.build(:cost_entry,
work_package: nil,
project: project,
units: 3,
spent_on: Date.today,
user: user,
comments: "Entry 1") }
subject(:model) { ::API::V3::CostTypes::CostTypeModel.new(cost_type) }
describe 'attributes' do
it { expect(subject.name).to eq(cost_type.name) }
it { expect(subject.unit).to eq(cost_type.unit) }
it { expect(subject.unit_plural).to eq(cost_type.unit_plural) }
it { expect(subject.units).to eq(cost_type.cost_entries.sum(&:units)) }
describe 'units' do
subject(:model) { ::API::V3::CostTypes::CostTypeModel.new(cost_type, units: 42) }
it { expect(subject.units).to eq(42) }
end
end
end

@ -0,0 +1,58 @@
#-- copyright
# OpenProject Costs Plugin
#
# Copyright (C) 2009 - 2014 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#++
require 'spec_helper'
describe ::API::V3::CostTypes::CostTypeRepresenter 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(:work_package) { FactoryGirl.build(:work_package,
project: project) }
let(:cost_type) { FactoryGirl.build(:cost_type) }
let!(:cost_entry) { FactoryGirl.build(:cost_entry,
work_package: nil,
project: project,
units: 3,
spent_on: Date.today,
user: user,
comments: "Entry 1") }
let(:representer) { described_class.new(model, work_package: work_package) }
let(:model) { ::API::V3::CostTypes::CostTypeModel.new(cost_type) }
context 'generation' do
subject(:generated) { representer.to_json }
it { should include_json('CostType'.to_json).at_path('_type') }
describe 'cost_type' do
it { should have_json_path('id') }
it { should have_json_path('name') }
it { should have_json_path('units') }
it { should have_json_path('unit') }
it { should have_json_path('unitPlural') }
end
end
end

@ -0,0 +1,89 @@
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
require 'spec_helper'
describe ::API::V3::WorkPackages::WorkPackageRepresenter do
let(:project) { FactoryGirl.create(:project) }
let(:role) { FactoryGirl.create(:role, permissions: [:view_time_entries,
:view_cost_entries,
:view_cost_rates]) }
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(:model) { ::API::V3::WorkPackages::WorkPackageModel.new(work_package: work_package) }
let(:representer) { described_class.new(model, current_user: user) }
before(:each) do
allow(User).to receive(:current).and_return user
end
describe 'generation' do
before do
cost_entry_1
cost_entry_2
end
subject(:generated) { representer.to_json }
describe 'work_package' do
it { should_not have_json_path('spentTime') }
it { should have_json_path('spentHours') }
it { should have_json_path('overallCosts') }
describe 'embedded' do
it { should have_json_path('_embedded/costObject') }
it { should have_json_path('_embedded/summarizedCostEntries') }
end
end
end
end
Loading…
Cancel
Save