Merge pull request #478 from opf/feature/planning_comparison
commit
af20ca70c7
@ -0,0 +1,101 @@ |
|||||||
|
class PlanningComparisonService |
||||||
|
@@journal_sql = <<SQL |
||||||
|
select #{Journal.table_name}.id |
||||||
|
from #{Journal.table_name} |
||||||
|
inner join (select journable_id, max(created_at) as latest_date, max(id) as latest_id |
||||||
|
from #{Journal.table_name} |
||||||
|
where #{Journal.table_name}.created_at <= ? |
||||||
|
and #{Journal.table_name}.journable_type = 'WorkPackage' |
||||||
|
and #{Journal.table_name}.journable_id in (?) |
||||||
|
group by #{Journal.table_name}.journable_id) as latest |
||||||
|
on #{Journal.table_name}.journable_id=latest.journable_id |
||||||
|
where #{Journal.table_name}.created_at=latest.latest_date |
||||||
|
and #{Journal.table_name}.id=latest.latest_id; |
||||||
|
SQL |
||||||
|
@@mapped_attributes = Journal::WorkPackageJournal.journaled_attributes.map{|attribute| "#{Journal::WorkPackageJournal.table_name}.#{attribute}"}.join ',' |
||||||
|
|
||||||
|
@@work_package_select = <<SQL |
||||||
|
Select #{Journal.table_name}.journable_id as id, |
||||||
|
#{Journal.table_name}.created_at as created_at, |
||||||
|
#{Journal.table_name}.created_at as updated_at, |
||||||
|
#{@@mapped_attributes} |
||||||
|
from #{Journal::WorkPackageJournal.table_name} |
||||||
|
left join #{Journal.table_name} |
||||||
|
on #{Journal.table_name}.id = #{Journal::WorkPackageJournal.table_name}.journal_id |
||||||
|
where #{Journal::WorkPackageJournal.table_name}.journal_id in (?) |
||||||
|
SQL |
||||||
|
|
||||||
|
# there is currently no possibility to compare two given dates: |
||||||
|
# the comparison always works on the current date, filters the current workpackages |
||||||
|
# and returns the state of these work_packages at the given time |
||||||
|
# filters are given in the format expected by Query and are just passed through to query |
||||||
|
def self.compare(projects, at_time, filter={}) |
||||||
|
|
||||||
|
# The query uses three steps to find the journalized entries for the filtered workpackages |
||||||
|
# at the given point in time: |
||||||
|
# 1 filter the ids using query |
||||||
|
# 2 find out the latest journal-entries for the given date belonging to the filtered ids |
||||||
|
# 3 fetch the data for these journals from Journal::WorkPackageData |
||||||
|
# 4 fill theses journal-data into a workpackage |
||||||
|
|
||||||
|
# 1 either filter the ids using the given filter or pluck all work_package-ids from the project |
||||||
|
work_package_ids = if filter.has_key? :f |
||||||
|
work_package_scope = WorkPackage.scoped |
||||||
|
.joins(:status) |
||||||
|
.joins(:project) #no idea, why query doesn't provide these joins itself... |
||||||
|
.for_projects(projects) |
||||||
|
.without_deleted |
||||||
|
|
||||||
|
query = Query.new |
||||||
|
query.add_filters(filter[:f], filter[:op], filter[:v]) |
||||||
|
#TODO teach query to fetch only ids |
||||||
|
work_package_scope.with_query(query) |
||||||
|
.pluck(:id) |
||||||
|
else |
||||||
|
WorkPackage.for_projects(projects).pluck(:id) |
||||||
|
end |
||||||
|
|
||||||
|
# 2 fetch latest journal-entries for the given time |
||||||
|
journal_ids = Journal.find_by_sql([@@journal_sql, at_time, work_package_ids]) |
||||||
|
.map(&:id) |
||||||
|
|
||||||
|
# 3&4 fetch the journaled data and make rails think it is actually a work_package |
||||||
|
work_packages = WorkPackage.find_by_sql([@@work_package_select,journal_ids]) |
||||||
|
|
||||||
|
restore_references(work_packages) |
||||||
|
end |
||||||
|
|
||||||
|
protected |
||||||
|
# This is a very crude way to work around n+1-issues, that are |
||||||
|
# introduced by the json/xml-rendering |
||||||
|
# the simple .includes does not work the work due to the find_by_sql |
||||||
|
def self.restore_references(work_packages) |
||||||
|
project_ids, parent_ids, type_ids, status_ids = resolve_reference_ids(work_packages) |
||||||
|
|
||||||
|
projects = Hash[Project.find(project_ids).map {|wp| [wp.id,wp]}] |
||||||
|
types = Hash[Type.find(type_ids).map{|type| [type.id,type]}] |
||||||
|
statuses = Hash[Status.find(status_ids).map{|status| [status.id,status]}] |
||||||
|
|
||||||
|
|
||||||
|
work_packages.each do |wp| |
||||||
|
wp.project = projects[wp.project_id] |
||||||
|
wp.type = types[wp.type_id] |
||||||
|
wp.status = statuses[wp.status_id] |
||||||
|
end |
||||||
|
|
||||||
|
work_packages |
||||||
|
|
||||||
|
end |
||||||
|
|
||||||
|
def self.resolve_reference_ids(work_packages) |
||||||
|
# TODO faster ways to do this without stepping numerous times through the workpackages?! |
||||||
|
# Or simply wait until we finally throw out the redundant references out of the json/xml-rendering??! |
||||||
|
project_ids = work_packages.map(&:project_id).uniq.compact |
||||||
|
type_ids = work_packages.map(&:type_id).uniq.compact |
||||||
|
status_ids = work_packages.map(&:status_id).uniq.compact |
||||||
|
parent_ids = work_packages.map(&:parent_id).uniq.compact |
||||||
|
|
||||||
|
return project_ids, parent_ids, type_ids,status_ids |
||||||
|
|
||||||
|
end |
||||||
|
end |
@ -1,60 +0,0 @@ |
|||||||
#-- copyright |
|
||||||
# OpenProject is a project management system. |
|
||||||
# Copyright (C) 2012-2013 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. |
|
||||||
#++ |
|
||||||
|
|
||||||
Given (/^there are the following work packages(?: in project "([^"]*)")?:$/) do |project_name, table| |
|
||||||
project = get_project(project_name) |
|
||||||
table.map_headers! { |header| header.underscore.gsub(' ', '_') } |
|
||||||
|
|
||||||
table.hashes.each do |type_attributes| |
|
||||||
|
|
||||||
[ |
|
||||||
["author", User], |
|
||||||
["responsible", User], |
|
||||||
["assigned_to", User], |
|
||||||
["type", Type], |
|
||||||
["fixed_version", Version], |
|
||||||
["priority", IssuePriority], |
|
||||||
["status", Status], |
|
||||||
["parent", WorkPackage] |
|
||||||
].each do |key, const| |
|
||||||
if type_attributes[key].present? |
|
||||||
type_attributes[key] = InstanceFinder.find(const, type_attributes[key]) |
|
||||||
else |
|
||||||
type_attributes.delete(key) |
|
||||||
end |
|
||||||
end |
|
||||||
|
|
||||||
# lookup the type by its name and replace it with the type |
|
||||||
# if the cast is ommitted, the contents of type_attributes is interpreted as an int |
|
||||||
unless type_attributes.has_key? :type |
|
||||||
type_attributes[:type] = Type.where(name: type_attributes[:type].to_s).first |
|
||||||
end |
|
||||||
|
|
||||||
factory = FactoryGirl.create(:work_package, type_attributes.merge(:project_id => project.id)) |
|
||||||
end |
|
||||||
end |
|
@ -0,0 +1,94 @@ |
|||||||
|
#-- copyright |
||||||
|
# OpenProject is a project management system. |
||||||
|
# Copyright (C) 2012-2013 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. |
||||||
|
#++ |
||||||
|
|
||||||
|
Given(/^there are the following work packages were added "(.*?)"(?: in project "([^"]*)")?:$/) do |time, project_name, table| |
||||||
|
project = get_project(project_name) |
||||||
|
|
||||||
|
#TODO provide better time support with some gem that can parse this: |
||||||
|
case time |
||||||
|
when "three weeks ago" |
||||||
|
target_time = 3.weeks.ago |
||||||
|
else |
||||||
|
target_time = Time.now |
||||||
|
end |
||||||
|
Timecop.travel(target_time) |
||||||
|
|
||||||
|
create_work_packages_from_table table, project |
||||||
|
|
||||||
|
# Ensure timecop returns after each scenario |
||||||
|
Support::ResetTimecop.reset_after |
||||||
|
end |
||||||
|
|
||||||
|
Given(/^the work package "(.*?)" was changed "(.*?)" to:$/) do |name, time, table| |
||||||
|
table.map_headers! { |header| header.underscore.gsub(' ', '_') } |
||||||
|
|
||||||
|
#TODO provide better time support with some gem that can parse this: |
||||||
|
case time |
||||||
|
when "one week ago" |
||||||
|
target_time = 1.weeks.ago |
||||||
|
when "two weeks ago" |
||||||
|
target_time = 2.weeks.ago |
||||||
|
else |
||||||
|
target_time = Time.now |
||||||
|
end |
||||||
|
Timecop.travel(target_time) |
||||||
|
|
||||||
|
#TODO provide generic support for all possible values. |
||||||
|
work_package = WorkPackage.find_by_subject(name) |
||||||
|
work_package.subject = table.hashes.first[:subject] |
||||||
|
work_package.start_date = table.hashes.first[:start_date] |
||||||
|
work_package.due_date = table.hashes.first[:due_date] |
||||||
|
work_package.save! |
||||||
|
|
||||||
|
# Ensure timecop returns after each scenario |
||||||
|
Support::ResetTimecop.reset_after |
||||||
|
end |
||||||
|
|
||||||
|
When(/^I set the timeline to compare "now" to "(.*?) days ago"$/) do |time| |
||||||
|
steps %Q{ |
||||||
|
When I edit the settings of the current timeline |
||||||
|
} |
||||||
|
|
||||||
|
page.should have_selector("#timeline_options_vertical_planning_elements", :visible => false) |
||||||
|
page.execute_script("jQuery('#timeline_options_comparison_relative').attr('checked', 'checked')") |
||||||
|
page.execute_script("jQuery('#timeline_options_compare_to_relative').val('#{time}')") |
||||||
|
page.execute_script("jQuery('#timeline_options_compare_to_relative_unit').val(0)") |
||||||
|
page.execute_script("jQuery('#content form').submit()") |
||||||
|
end |
||||||
|
|
||||||
|
Then(/^I should see the work package "(.*?)" has not moved$/) do |arg1| |
||||||
|
pending # express the regexp above with the code you wish you had |
||||||
|
end |
||||||
|
|
||||||
|
Then(/^I should see the work package "(.*?)" has moved$/) do |arg1| |
||||||
|
pending # express the regexp above with the code you wish you had |
||||||
|
end |
||||||
|
|
||||||
|
Then(/^I should not see the work package "(.*?)"$/) do |arg1| |
||||||
|
pending # express the regexp above with the code you wish you had |
||||||
|
end |
@ -0,0 +1,81 @@ |
|||||||
|
#-- copyright |
||||||
|
# OpenProject is a project management system. |
||||||
|
# Copyright (C) 2012-2013 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. |
||||||
|
#++ |
||||||
|
|
||||||
|
Feature: Timeline Comparison View Tests |
||||||
|
Background: |
||||||
|
Given there is 1 user with: |
||||||
|
| login | manager | |
||||||
|
And there is a role "manager" |
||||||
|
And the role "manager" may have the following rights: |
||||||
|
| view_timelines | |
||||||
|
| edit_timelines | |
||||||
|
| view_work_packages | |
||||||
|
| edit_work_packages | |
||||||
|
| delete_work_packages | |
||||||
|
| view_reportings | |
||||||
|
| view_project_associations | |
||||||
|
And there is a project named "Volatile Planning" |
||||||
|
And I am working in project "Volatile Planning" |
||||||
|
And the project uses the following modules: |
||||||
|
| timelines | |
||||||
|
And the user "manager" is a "manager" |
||||||
|
And I am already logged in as "manager" |
||||||
|
And there are the following work packages were added "three weeks ago": |
||||||
|
| Subject | Start date | Due date | |
||||||
|
| January | 2014-01-01 | 2014-01-31 | |
||||||
|
| February | 2014-02-01 | 2014-02-28 | |
||||||
|
| March | 2014-03-01 | 2014-03-31 | |
||||||
|
| April | 2014-04-01 | 2014-04-30 | |
||||||
|
And the work package "February" was changed "two weeks ago" to: |
||||||
|
| Subject | Start date | Due date | |
||||||
|
| May | 2014-05-01 | 2014-05-31 | |
||||||
|
And the work package "January" was changed "one week ago" to: |
||||||
|
| Subject | Start date | Due date | |
||||||
|
| February | 2014-02-01 | 2014-02-28 | |
||||||
|
|
||||||
|
@javascript |
||||||
|
Scenario: nine days comparison |
||||||
|
Given I am working in the timeline "Changes" of the project called "Volatile Planning" |
||||||
|
When there is a timeline "Changes" for project "Volatile Planning" |
||||||
|
And I set the timeline to compare "now" to "9 days ago" |
||||||
|
And I go to the page of the timeline "Changes" of the project called "Volatile Planning" |
||||||
|
And I wait for timeline to load table |
||||||
|
Then I should see the work package "May" has not moved |
||||||
|
And I should see the work package "February" has moved |
||||||
|
And I should not see the work package "January" |
||||||
|
|
||||||
|
@javascript |
||||||
|
Scenario: sixteen days comparison |
||||||
|
Given I am working in the timeline "Changes" of the project called "Volatile Planning" |
||||||
|
When there is a timeline "Changes" for project "Volatile Planning" |
||||||
|
And I set the timeline to compare "now" to "16 days ago" |
||||||
|
And I go to the page of the timeline "Changes" of the project called "Volatile Planning" |
||||||
|
And I wait for timeline to load table |
||||||
|
Then I should see the work package "May" has moved |
||||||
|
And I should see the work package "February" has moved |
||||||
|
And I should not see the work package "January" |
@ -0,0 +1,148 @@ |
|||||||
|
#-- copyright |
||||||
|
# OpenProject is a project management system. |
||||||
|
# Copyright (C) 2012-2013 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 "Planning Comparison" do |
||||||
|
|
||||||
|
let (:project){FactoryGirl.create(:project)} |
||||||
|
let (:admin) {FactoryGirl.create(:admin)} |
||||||
|
|
||||||
|
before do |
||||||
|
# query implicitly uses the logged in user to check for allowed work_packages/projects |
||||||
|
User.stub(:current).and_return(admin) |
||||||
|
end |
||||||
|
|
||||||
|
describe "going back in history" do |
||||||
|
let(:journalized_work_package) do |
||||||
|
#TODO are these actually unit-tests?! |
||||||
|
wp = nil |
||||||
|
# create 2 journal-entries, to make sure, that the comparison actually picks up the latest one |
||||||
|
Timecop.travel(2.weeks.ago) do |
||||||
|
wp = FactoryGirl.create(:work_package, project: project, start_date: "01/01/2020", due_date: "01/03/2020") |
||||||
|
wp.save # triggers the journaling and saves the old due_date, creating the baseline for the comparison |
||||||
|
end |
||||||
|
|
||||||
|
Timecop.travel(1.week.ago) do |
||||||
|
wp.reload |
||||||
|
wp.due_date = "01/04/2020" |
||||||
|
wp.save # triggers the journaling and saves the old due_date, creating the baseline for the comparison |
||||||
|
end |
||||||
|
|
||||||
|
wp.reload |
||||||
|
wp.due_date = "01/05/2020" |
||||||
|
wp.save # adds another journal-entry |
||||||
|
wp |
||||||
|
end |
||||||
|
|
||||||
|
before { wp = journalized_work_package } |
||||||
|
|
||||||
|
it "should return the changes as a work_package" do |
||||||
|
# beware of these date-conversions: 1.week.ago does not catch the change, as created_at is stored as a timestamp |
||||||
|
expect(PlanningComparisonService.compare(project, 5.days.ago).size).to eql 1 |
||||||
|
expect(PlanningComparisonService.compare(project, 5.days.ago).first).to be_instance_of WorkPackage |
||||||
|
end |
||||||
|
|
||||||
|
it "should return the old due_date in the comparison" do |
||||||
|
# beware of these date-conversions: 1.week.ago does not catch the change, as created_at is stored as a timestamp |
||||||
|
old_work_package = PlanningComparisonService.compare(project, 5.days.ago).first |
||||||
|
expect(old_work_package.due_date).to eql Date.parse "01/04/2020" |
||||||
|
end |
||||||
|
|
||||||
|
it "should return only the latest change when the workpackage was edited on the same day more than once" do |
||||||
|
Timecop.travel(1.week.ago) do |
||||||
|
journalized_work_package.reload |
||||||
|
journalized_work_package.due_date = "01/05/2020" |
||||||
|
journalized_work_package.save # triggers the journaling and saves the old due_date, creating the baseline for the comparison |
||||||
|
|
||||||
|
journalized_work_package.reload |
||||||
|
journalized_work_package.due_date = "01/07/2020" |
||||||
|
journalized_work_package.save |
||||||
|
|
||||||
|
|
||||||
|
end |
||||||
|
|
||||||
|
old_work_packages = PlanningComparisonService.compare(project, 5.days.ago) |
||||||
|
expect(old_work_packages.size).to eql 1 |
||||||
|
|
||||||
|
expect(old_work_packages.first.due_date).to eql Date.parse "01/07/2020" |
||||||
|
|
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
|
||||||
|
describe "filtering work_packages also applies to the history" do |
||||||
|
let(:assigned_to_user) {FactoryGirl.create(:user)} |
||||||
|
let (:filter) do |
||||||
|
{ f: ["assigned_to_id"], |
||||||
|
op: {"assigned_to_id" => "="}, |
||||||
|
v: {"assigned_to_id" => ["#{assigned_to_user.id}"]} } |
||||||
|
end |
||||||
|
|
||||||
|
let (:work_package) do |
||||||
|
wp = nil |
||||||
|
# create 2 journal-entries, to make sure, that the comparison actually picks up the latest one |
||||||
|
Timecop.travel(1.week.ago) do |
||||||
|
wp = FactoryGirl.create(:work_package, project: project, due_date: "01/03/2020", assigned_to_id: assigned_to_user.id) |
||||||
|
wp.save # triggers the journaling and saves the old due_date, creating the baseline for the comparison |
||||||
|
end |
||||||
|
|
||||||
|
wp.reload |
||||||
|
wp.due_date = "01/05/2020" |
||||||
|
wp.save # adds another journal-entry |
||||||
|
wp |
||||||
|
end |
||||||
|
|
||||||
|
let (:filtered_work_package) do |
||||||
|
other_user = FactoryGirl.create(:user) |
||||||
|
wp = nil |
||||||
|
# create 2 journal-entries, to make sure, that the comparison actually picks up the latest one |
||||||
|
Timecop.travel(1.week.ago) do |
||||||
|
wp = FactoryGirl.create(:work_package, project: project, due_date: "01/03/2020", assigned_to_id: other_user.id) |
||||||
|
wp.save # triggers the journaling and saves the old due_date, creating the baseline for the comparison |
||||||
|
end |
||||||
|
|
||||||
|
wp.reload |
||||||
|
wp.due_date = "01/05/2020" |
||||||
|
wp.save # adds another journal-entry |
||||||
|
wp |
||||||
|
end |
||||||
|
|
||||||
|
before do |
||||||
|
work_package |
||||||
|
filtered_work_package |
||||||
|
end |
||||||
|
|
||||||
|
it "should filter out the work_package assigned to the wrong person" do |
||||||
|
filtered_packages = PlanningComparisonService.compare(project, 5.days.ago, filter) |
||||||
|
expect(filtered_packages).to include work_package |
||||||
|
expect(filtered_packages).not_to include filtered_work_package |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
end |
Loading…
Reference in new issue