#-- copyright # OpenProject is an open source project management software. # Copyright (C) 2012-2021 the OpenProject GmbH # # 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 COPYRIGHT and LICENSE files for more details. #++ require 'spec_helper' describe ::Query::Results, 'sums', type: :model do let(:project) do FactoryBot.create(:project).tap do |p| p.work_package_custom_fields << int_cf p.work_package_custom_fields << float_cf end end let(:other_project) do FactoryBot.create(:project).tap do |p| p.work_package_custom_fields << int_cf p.work_package_custom_fields << float_cf end end let!(:work_package1) do FactoryBot.create(:work_package, type: type, project: project, estimated_hours: 5, done_ratio: 10, "custom_field_#{int_cf.id}" => 10, "custom_field_#{float_cf.id}" => 3.414, remaining_hours: 3, story_points: 7) end let!(:work_package2) do FactoryBot.create(:work_package, type: type, project: project, assigned_to: current_user, done_ratio: 50, estimated_hours: 5, "custom_field_#{int_cf.id}" => 10, "custom_field_#{float_cf.id}" => 3.414, remaining_hours: 3, story_points: 7) end let!(:work_package3) do FactoryBot.create(:work_package, type: type, project: project, assigned_to: current_user, responsible: current_user, done_ratio: 50, estimated_hours: 5, "custom_field_#{int_cf.id}" => 10, "custom_field_#{float_cf.id}" => 3.414, remaining_hours: 3, story_points: 7) end let!(:invisible_work_package1) do FactoryBot.create(:work_package, type: type, project: other_project, estimated_hours: 5, "custom_field_#{int_cf.id}" => 10, "custom_field_#{float_cf.id}" => 3.414, remaining_hours: 3, story_points: 7) end let!(:cost_entry1) do FactoryBot.create(:cost_entry, project: project, work_package: work_package1, user: current_user, overridden_costs: 200) end let!(:cost_entry2) do FactoryBot.create(:cost_entry, project: project, work_package: work_package2, user: current_user, overridden_costs: 200) end let!(:time_entry1) do FactoryBot.create(:time_entry, project: project, work_package: work_package1, user: current_user, overridden_costs: 300) end let!(:time_entry2) do FactoryBot.create(:time_entry, project: project, work_package: work_package2, user: current_user, overridden_costs: 300) end let(:int_cf) do FactoryBot.create(:int_wp_custom_field) end let(:float_cf) do FactoryBot.create(:float_wp_custom_field) end let(:type) do FactoryBot.create(:type).tap do |t| t.custom_fields << int_cf t.custom_fields << float_cf end end let(:current_user) do FactoryBot.create(:user, member_in_project: project, member_with_permissions: permissions) end let(:permissions) do %i[view_work_packages view_cost_entries view_time_entries view_cost_rates view_hourly_rates] end let(:group_by) { nil } let(:query) do FactoryBot.build :query, project: project, group_by: group_by end let(:query_results) do ::Query::Results.new query end before do login_as(current_user) end let(:estimated_hours_column) { query.available_columns.detect { |c| c.name.to_s == 'estimated_hours' } } let(:int_cf_column) { query.available_columns.detect { |c| c.name.to_s == "cf_#{int_cf.id}" } } let(:float_cf_column) { query.available_columns.detect { |c| c.name.to_s == "cf_#{float_cf.id}" } } let(:material_costs_column) { query.available_columns.detect { |c| c.name.to_s == "material_costs" } } let(:labor_costs_column) { query.available_columns.detect { |c| c.name.to_s == "labor_costs" } } let(:overall_costs_column) { query.available_columns.detect { |c| c.name.to_s == "overall_costs" } } let(:remaining_hours_column) { query.available_columns.detect { |c| c.name.to_s == "remaining_hours" } } let(:story_points_column) { query.available_columns.detect { |c| c.name.to_s == "story_points" } } describe '#all_total_sums' do it 'is a hash of all summable columns' do expect(query_results.all_total_sums) .to eql(estimated_hours_column => 15.0, int_cf_column => 30, float_cf_column => 10.24, material_costs_column => 400.0, labor_costs_column => 600.0, overall_costs_column => 1000.0, remaining_hours_column => 9.0, story_points_column => 21) end context 'when filtering' do before do query.add_filter('assigned_to_id', '=', [current_user.id.to_s]) end it 'is a hash of all summable columns and includes only the work packages matching the filter' do expect(query_results.all_total_sums) .to eql(estimated_hours_column => 10.0, int_cf_column => 20, float_cf_column => 6.83, material_costs_column => 200.0, labor_costs_column => 300.0, overall_costs_column => 500.0, remaining_hours_column => 6.0, story_points_column => 14) end end end describe '#all_sums_for_group' do context 'grouped by assigned_to' do let(:group_by) { :assigned_to } it 'is a hash of sums grouped by user values (and nil) and grouped columns' do expect(query_results.all_group_sums) .to eql(current_user => { estimated_hours_column => 10.0, int_cf_column => 20, float_cf_column => 6.83, material_costs_column => 200.0, labor_costs_column => 300.0, overall_costs_column => 500.0, remaining_hours_column => 6.0, story_points_column => 14 }, nil => { estimated_hours_column => 5.0, int_cf_column => 10, float_cf_column => 3.41, material_costs_column => 200.0, labor_costs_column => 300.0, overall_costs_column => 500.0, remaining_hours_column => 3.0, story_points_column => 7 }) end context 'when filtering' do before do query.add_filter('responsible_id', '=', [current_user.id.to_s]) end it 'is a hash of sums grouped by user values and grouped columns' do expect(query_results.all_group_sums) .to eql(current_user => { estimated_hours_column => 5.0, int_cf_column => 10, float_cf_column => 3.41, material_costs_column => 0.0, labor_costs_column => 0.0, overall_costs_column => 0.0, story_points_column => 7, remaining_hours_column => 3.0 }) end end end context 'grouped by done_ratio' do let(:group_by) { :done_ratio } it 'is a hash of sums grouped by done_ratio values and grouped columns' do expect(query_results.all_group_sums) .to eql(50 => { estimated_hours_column => 10.0, int_cf_column => 20, float_cf_column => 6.83, material_costs_column => 200.0, labor_costs_column => 300.0, overall_costs_column => 500.0, remaining_hours_column => 6.0, story_points_column => 14 }, 10 => { estimated_hours_column => 5.0, int_cf_column => 10, float_cf_column => 3.41, material_costs_column => 200.0, labor_costs_column => 300.0, overall_costs_column => 500.0, remaining_hours_column => 3.0, story_points_column => 7 }) end context 'when filtering' do before do query.add_filter('responsible_id', '=', [current_user.id.to_s]) end it 'is a hash of sums grouped by done_ratio values and grouped columns' do expect(query_results.all_group_sums) .to eql(50 => { estimated_hours_column => 5.0, int_cf_column => 10, float_cf_column => 3.41, material_costs_column => 0.0, labor_costs_column => 0.0, overall_costs_column => 0.0, story_points_column => 7, remaining_hours_column => 3.0 }) end end end end end