From 8fc89025aac83f860ac1d2a3d57629c18d73b633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20G=C3=BCnther?= Date: Wed, 20 Jul 2016 16:15:41 +0200 Subject: [PATCH] [23662] Fix display of cost sums (#247) * Fix display of cost sums * specify sums of costs to be displayed as currency --- lib/open_project/costs/engine.rb | 58 +++++++++++ spec/features/costs_table_sums.rb | 92 ++++++++++++++++++ .../work_package_sums_representer_spec.rb | 97 +++++++++++++++++++ 3 files changed, 247 insertions(+) create mode 100644 spec/features/costs_table_sums.rb create mode 100644 spec/lib/api/v3/work_packages/work_package_sums_representer_spec.rb diff --git a/lib/open_project/costs/engine.rb b/lib/open_project/costs/engine.rb index be159dad54..29e5bfaa26 100644 --- a/lib/open_project/costs/engine.rb +++ b/lib/open_project/costs/engine.rb @@ -259,6 +259,64 @@ module OpenProject::Costs } end + extend_api_response(:v3, :work_packages, :schema, :work_package_sums_schema) do + schema :overall_costs, + type: 'String', + required: false, + writable: false, + show_if: -> (*) { + ::Setting.work_package_list_summable_columns.include?('overall_costs') + } + schema :labor_costs, + type: 'String', + required: false, + writable: false, + show_if: -> (*) { + ::Setting.work_package_list_summable_columns.include?('labor_costs') + } + schema :material_costs, + type: 'String', + required: false, + writable: false, + show_if: -> (*) { + ::Setting.work_package_list_summable_columns.include?('material_costs') + } + end + + extend_api_response(:v3, :work_packages, :work_package_sums) do + include ActionView::Helpers::NumberHelper + + property :overall_costs, + exec_context: :decorator, + getter: -> (*) { + number_to_currency(represented.overall_costs) + + }, + if: -> (*) { + ::Setting.work_package_list_summable_columns.include?('overall_costs') + } + + property :labor_costs, + exec_context: :decorator, + getter: -> (*) { + number_to_currency(represented.labor_costs) + + }, + if: -> (*) { + ::Setting.work_package_list_summable_columns.include?('labor_costs') + } + + property :material_costs, + exec_context: :decorator, + getter: -> (*) { + number_to_currency(represented.material_costs) + }, + if: -> (*) { + ::Setting.work_package_list_summable_columns.include?('material_costs') + } + + end + add_api_representer_cache_key(:v3, :work_packages, :schema, :work_package_schema) do if represented.project.module_enabled?('costs_module') ['costs_enabled'] diff --git a/spec/features/costs_table_sums.rb b/spec/features/costs_table_sums.rb new file mode 100644 index 0000000000..f3faf94add --- /dev/null +++ b/spec/features/costs_table_sums.rb @@ -0,0 +1,92 @@ +#-- 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 File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') + +describe 'Work Package table cost sums', type: :feature, js: true do + let(:project) { work_package.project } + let(:user) { FactoryGirl.create :user, + member_in_project: project, + member_through_role: role } + let(:role) { FactoryGirl.create :role, permissions: [:view_own_hourly_rate, + :view_work_packages, + :view_work_packages, + :view_own_time_entries, + :view_own_cost_entries, + :view_cost_rates, + :log_costs] } + let(:work_package) {FactoryGirl.create :work_package } + let(:hourly_rate) { FactoryGirl.create :default_hourly_rate, user: user, + rate: 1.00 } + let!(:time_entry) { FactoryGirl.create :time_entry, user: user, + work_package: work_package, + project: project, + hours: 1.50 } + let(:cost_type) { + type = FactoryGirl.create :cost_type, name: 'Translations' + FactoryGirl.create :cost_rate, cost_type: type, + rate: 1.00 + type + } + let!(:cost_entry) { FactoryGirl.create :cost_entry, work_package: work_package, + project: project, + units: 2.50, + cost_type: cost_type, + user: user } + let(:wp_table) { ::Pages::WorkPackagesTable.new(project) } + let!(:query) do + query = FactoryGirl.build(:query, user: user, project: project) + query.column_names = %w(subject overall_costs material_costs overall_costs) + + query.save! + query + end + + before do + login_as(user) + allow(Setting).to receive(:work_package_list_summable_columns).and_return(summable) + + wp_table.visit_query(query) + wp_table.expect_work_package_listed(work_package) + + # Trigger action from action menu dropdown + wp_table.click_setting_item 'Display sums' + expect(page).to have_selector('tr.sum.group.all') + end + + context 'when summing enabled' do + let(:summable) { %w(overall_costs labor_costs material_costs) } + + it 'shows the sums' do + within('tr.sum.group.all') do + expect(page).to have_selector('.wp-table--cell-span', text: '2.50 EUR', count: 3) + expect(page).to have_selector('.wp-table--cell-span', text: '-', count: 1) + end + end + end + context 'when summing disabled' do + let(:summable) { [] } + + it 'does not show the sums' do + within('tr.sum.group.all') do + expect(page).to have_selector('.wp-table--cell-span', text: '-', count: 4) + end + end + end +end diff --git a/spec/lib/api/v3/work_packages/work_package_sums_representer_spec.rb b/spec/lib/api/v3/work_packages/work_package_sums_representer_spec.rb new file mode 100644 index 0000000000..5ce09432df --- /dev/null +++ b/spec/lib/api/v3/work_packages/work_package_sums_representer_spec.rb @@ -0,0 +1,97 @@ +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2015 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::WorkPackageSumsRepresenter do + let(:sums) { double 'sums', material_costs: 5, labor_costs: 10, overall_costs: 15 } + let(:schema) { double 'schema', available_custom_fields: [] } + let(:representer) { + described_class.create_class(schema).new(sums) + } + let(:summable_columns) { [] } + + before do + allow(Setting) + .to receive(:work_package_list_summable_columns) + .and_return(summable_columns) + end + + subject { representer.to_json } + + context 'materialCosts' do + context 'with it being configured to be summable' do + let(:summable_columns) { ['material_costs'] } + + it 'is represented' do + expected = "5.00 EUR" + expect(subject).to be_json_eql(expected.to_json).at_path('materialCosts') + end + end + + context 'without it being configured to be summable' do + it 'is not represented when the summable setting does not list it' do + expect(subject).to_not have_json_path('materialCosts') + end + end + end + + context 'laborCosts' do + context 'with it being configured to be summable' do + let(:summable_columns) { ['labor_costs'] } + + it 'is represented' do + expected = "10.00 EUR" + expect(subject).to be_json_eql(expected.to_json).at_path('laborCosts') + end + end + + context 'without it being configured to be summable' do + it 'is not represented when the summable setting does not list it' do + expect(subject).to_not have_json_path('laborCosts') + end + end + end + + context 'overallCosts' do + context 'with it being configured to be summable' do + let(:summable_columns) { ['overall_costs'] } + + it 'is represented' do + expected = "15.00 EUR" + expect(subject).to be_json_eql(expected.to_json).at_path('overallCosts') + end + end + + context 'without it being configured to be summable' do + it 'is not represented when the summable setting does not list it' do + expect(subject).to_not have_json_path('overallCosts') + end + end + end +end