Merge pull request #54 from finnlabs/feature/work_package_migration
Feature/work package migrationpull/6827/head
commit
aae1f5aef5
@ -1,3 +1,5 @@ |
||||
* `#2050` Migrate to new data model. |
||||
|
||||
= 5.0.1.pre4 - 2013-07-11 |
||||
|
||||
* Allows for assigning budgets to work_packages |
@ -0,0 +1,33 @@ |
||||
#-- encoding: UTF-8 |
||||
#-- copyright |
||||
# OpenProject is a project management system. |
||||
# |
||||
# Copyright (C) 2012-2013 the OpenProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# See doc/COPYRIGHT.rdoc for more details. |
||||
#++ |
||||
|
||||
class Journal::CostObjectJournal < ActiveRecord::Base |
||||
|
||||
# include ActiveModel::ForbiddenAttributesProtection |
||||
|
||||
self.table_name = "cost_object_journals" |
||||
|
||||
belongs_to :journal |
||||
|
||||
# attr_accessible :project_id, :author_id, :subject, :description, :fixed_date, :created_on |
||||
|
||||
|
||||
@@journaled_attributes = [:project_id, |
||||
:author_id, |
||||
:subject, |
||||
:description, |
||||
:fixed_date] |
||||
|
||||
def journaled_attributes |
||||
attributes.symbolize_keys.select{|k,_| @@journaled_attributes.include? k} |
||||
end |
||||
end |
@ -0,0 +1,34 @@ |
||||
|
||||
#-- encoding: UTF-8 |
||||
#-- copyright |
||||
# OpenProject is a project management system. |
||||
# |
||||
# Copyright (C) 2012-2013 the OpenProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# See doc/COPYRIGHT.rdoc for more details. |
||||
#++ |
||||
|
||||
class Journal::VariableCostObjectJournal < Journal::CostObjectJournal |
||||
|
||||
# include ActiveModel::ForbiddenAttributesProtection |
||||
|
||||
# self.table_name = "cost_object_journals" |
||||
|
||||
# belongs_to :journal |
||||
|
||||
# attr_accessible :type, :id, :project_id, :author_id, :subject, :description, :fixed_date, :created_on |
||||
|
||||
# @@journaled_attributes = [:project_id, |
||||
# :author_id, |
||||
# :subject, |
||||
# :description, |
||||
# :type, |
||||
# :fixed_date] |
||||
|
||||
# def journaled_attributes |
||||
# attributes.symbolize_keys.select{|k,_| @@journaled_attributes.include? k} |
||||
# end |
||||
end |
@ -1,24 +0,0 @@ |
||||
<% if not project.nil? and project.module_enabled? :costs_module %> |
||||
<% |
||||
cost_objects_any = false |
||||
possible_cost_objects = issues.inject(issues.first.project.cost_objects) do |intersect, issue| |
||||
cost_objects_any |= issue.project.cost_objects.any? |
||||
issue.project.cost_objects & intersect |
||||
end |
||||
%> |
||||
<li class="folder"> |
||||
<a href="#" class="submenu"><%= l(:label_cost_object) %></a> |
||||
<ul> |
||||
<% unless possible_cost_objects.empty? -%> |
||||
<% possible_cost_objects.each do |co| -%> |
||||
<li> |
||||
<%= context_menu_link co.subject, {:controller => '/issues', :action => 'bulk_edit', :ids => issues.collect(&:id), 'cost_object_id' => co, :back_url => back}, :method => :post, |
||||
:selected => (@issue && co == @issue.cost_object), :disabled => !can[:edit] %> |
||||
</li> |
||||
<% end -%> |
||||
<% else -%> |
||||
<li><%= l(cost_objects_any ? :notice_cost_object_conflict : :notice_no_cost_objects_available)%></li> |
||||
<% end -%> |
||||
</ul> |
||||
</li> |
||||
<% end %> |
@ -1,4 +1,4 @@ |
||||
<% if @project.module_enabled? :costs_module %> |
||||
<% if @project && @project.module_enabled?(:costs_module) %> |
||||
<hr /> |
||||
<%= li_unless_nil(link_to_if_authorized l(:button_log_costs), {:controller => '/costlog', :action => 'new', :work_package_id => @work_package}, :class => 'icon icon-pieces') %> |
||||
<%= li_unless_nil(link_to_if_authorized l(:button_log_costs), {:controller => '/costlog', :action => 'new', :work_package_id => issue}, :class => 'icon icon-pieces') %> |
||||
<% end %> |
||||
|
@ -1,8 +1,8 @@ |
||||
<% if not @project.nil? and @project.module_enabled? :costs_module %> |
||||
<% if @project && @project.module_enabled?(:costs_module) %> |
||||
<% myselect = select_tag('cost_object_id', |
||||
content_tag('option', l(:label_no_change_option), :value => '') + |
||||
content_tag('option', l(:label_none), :value => 'none') + |
||||
options_from_collection_for_select(CostObject.find_all_by_project_id(@project.id, :order => 'subject ASC'), :id, :subject)) |
||||
%> |
||||
<%= content_tag :p, (content_tag "label", CostObject.model_name.human, :for => 'cost_object_id') + myselect %> |
||||
<% end %> |
||||
<% end %> |
@ -0,0 +1,24 @@ |
||||
<% if @project && @project.module_enabled?(:costs_module) %> |
||||
<% |
||||
cost_objects_any = false |
||||
possible_cost_objects = work_packages.inject(work_packages.first.project.cost_objects) do |intersect, work_package| |
||||
cost_objects_any |= work_package.project.cost_objects.any? |
||||
work_package.project.cost_objects & intersect |
||||
end |
||||
%> |
||||
<li class="folder"> |
||||
<a href="#" class="submenu"><%= l(:label_cost_object) %></a> |
||||
<ul> |
||||
<% unless possible_cost_objects.empty? -%> |
||||
<% possible_cost_objects.each do |co| -%> |
||||
<li> |
||||
<%= context_menu_link co.subject, {:controller => '/work_packages', :action => 'bulk_edit', :ids => work_packages.collect(&:id), 'cost_object_id' => co, :back_url => back}, :method => :post, |
||||
:selected => (issue && co == issue.cost_object), :disabled => !can[:edit] %> |
||||
</li> |
||||
<% end -%> |
||||
<% else -%> |
||||
<li><%= l(cost_objects_any ? :notice_cost_object_conflict : :notice_no_cost_objects_available)%></li> |
||||
<% end -%> |
||||
</ul> |
||||
</li> |
||||
<% end %> |
@ -1,5 +1,5 @@ |
||||
<% if not @project.nil? and @project.module_enabled? :costs_module %> |
||||
<% if @project && @project.module_enabled?(:costs_module) %> |
||||
<p> |
||||
<%= form.select :cost_object_id, CostObject.find_all_by_project_id(@project, :order => 'subject ASC').collect { |d| [d.subject, d.id] }, :include_blank => true%> |
||||
</p> |
||||
<% end %> |
||||
<% end %> |
@ -1,8 +1,8 @@ |
||||
<% if not project.nil? and project.module_enabled? :costs_module %> |
||||
<% if @project && @project.module_enabled?(:costs_module) %> |
||||
<p> |
||||
<label><%= CostObject.model_name.human %></label> |
||||
<%= select_tag('cost_object_id', (@target_project == @project ? content_tag('option', l(:label_no_change_option), :value => '') : "") + |
||||
content_tag('option', l(:label_none), :value => 'none') + |
||||
options_from_collection_for_select(@target_project.cost_objects, :id, :subject)) %> |
||||
</p> |
||||
<% end %> |
||||
<% end %> |
@ -1,25 +1,25 @@ |
||||
<% if @project.module_enabled? :costs_module && @issue%> |
||||
<% if @project.module_enabled?(:costs_module) && issue %> |
||||
<%# Only render this partial, if the plugin is enabled for the current project %> |
||||
<style> |
||||
<%# disables core's spent-time as it is not displayed if the user has just the view_own_time_entries permission %> |
||||
.spent-time { display: none } |
||||
</style> |
||||
|
||||
<% attributes_array = cost_issues_attributes(@issue) %> |
||||
<% attributes_array = cost_work_package_attributes(issue) %> |
||||
<% (0..(attributes_array.size - 1)).step(2) do |i| %> |
||||
<tr> |
||||
<th> |
||||
<%= attributes_array[i].first %>: |
||||
</th> |
||||
<td> |
||||
<%= attributes_array[i].last %> |
||||
<%= attributes_array[i].to_a.last %> |
||||
</td> |
||||
<% if i + 1 < attributes_array.size %> |
||||
<th> |
||||
<%= attributes_array[i + 1].first %>: |
||||
</th> |
||||
<td> |
||||
<%= attributes_array[i + 1].last %> |
||||
<%= attributes_array[i + 1].to_a.last %> |
||||
</td> |
||||
<% end %> |
||||
</tr> |
@ -1,19 +1,19 @@ |
||||
<% content_for :action_menu_main do %> |
||||
<%= li_unless_nil(link_to_if_authorized(l(:button_update), { :controller => '/issues', |
||||
<%= li_unless_nil(link_to_if_authorized(l(:button_update), { :controller => '/work_packages', |
||||
:action => 'edit', |
||||
:id => @issue }, |
||||
:id => work_package }, |
||||
:class => 'edit icon icon-edit', |
||||
:accesskey => accesskey(:edit))) %> |
||||
<%= li_unless_nil(watcher_link(@issue, |
||||
<%= li_unless_nil(watcher_link(work_package, |
||||
User.current, |
||||
{ :class => 'watcher_link', |
||||
:replace => User.current.allowed_to?(:view_issue_watchers, @project) ? ['#watchers', '.watcher_link'] : ['.watcher_link'] })) %> |
||||
:replace => User.current.allowed_to?(:view_work_package_watchers, @project) ? ['#watchers', '.watcher_link'] : ['.watcher_link'] })) %> |
||||
<% end %> |
||||
<% content_for :action_menu_more do %> |
||||
<%= li_unless_nil(link_to_if_authorized l(:button_log_time), {:controller => '/timelog', :action => 'new', :issue_id => @issue}, :class => 'icon icon-time-add') %> |
||||
<%= li_unless_nil(link_to_if_authorized l(:button_log_costs), {:controller => '/costlog', :action => 'new', :issue_id => @issue}, :class => 'icon icon-pieces') %> |
||||
<%= li_unless_nil(link_to_if_authorized l(:button_duplicate), {:controller => '/issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-duplicate') %> |
||||
<%= li_unless_nil(link_to_if_authorized l(:button_copy), {:controller => '/issue_moves', :action => 'new', :id => @issue, :copy_options => {:copy => 't'}}, :class => 'icon icon-copy') %> |
||||
<%= li_unless_nil(link_to_if_authorized l(:button_move), {:controller => '/issue_moves', :action => 'new', :id => @issue}, :class => 'icon icon-move') %> |
||||
<%= li_unless_nil(link_to_if_authorized l(:button_delete), {:controller => '/issues', :action => 'destroy', :id => @issue}, :confirm => (@issue.leaf? ? l(:text_are_you_sure) : l(:text_are_you_sure_with_children)), :method => :post, :class => 'icon icon-del') %> |
||||
<%= li_unless_nil(link_to_if_authorized l(:button_log_time), {:controller => '/timelog', :action => 'new', :work_package_id => work_package}, :class => 'icon icon-time-add') %> |
||||
<%= li_unless_nil(link_to_if_authorized l(:button_log_costs), {:controller => '/costlog', :action => 'new', :work_package_id => work_package}, :class => 'icon icon-pieces') %> |
||||
<%= li_unless_nil(link_to_if_authorized l(:button_duplicate), {:controller => '/work_packages', :action => 'new', :project_id => @project, :copy_from => work_package }, :class => 'icon icon-duplicate') %> |
||||
<%= li_unless_nil(link_to_if_authorized l(:button_copy), {:controller => '/work_package_moves', :action => 'new', :id => work_package, :copy_options => {:copy => 't'}}, :class => 'icon icon-copy') %> |
||||
<%= li_unless_nil(link_to_if_authorized l(:button_move), {:controller => '/work_package_moves', :action => 'new', :id => work_package}, :class => 'icon icon-move') %> |
||||
<%= li_unless_nil(link_to_if_authorized l(:button_delete), {:controller => '/work_packages', :action => 'destroy', :id => work_package}, :confirm => (work_package.leaf? ? l(:text_are_you_sure) : l(:text_are_you_sure_with_children)), :method => :post, :class => 'icon icon-del') %> |
||||
<% end %> |
@ -1,7 +1,7 @@ |
||||
<h2><%= l(:label_confirmation) %></h2> |
||||
|
||||
<%= form_tag do %> |
||||
<%= @issues.collect {|i| hidden_field_tag 'ids[]', i.id } %> |
||||
<%= @work_packages.collect {|i| hidden_field_tag 'ids[]', i.id } %> |
||||
<div class="box"> |
||||
<p><strong><%= |
||||
if @hours > 0 && !@entries.blank? |
@ -0,0 +1,40 @@ |
||||
#-- 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. |
||||
#++ |
||||
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, :null => false |
||||
t.date :fixed_date, :null => false |
||||
t.datetime :created_on |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,5 @@ |
||||
class AddCostObjectIdToWorkPackageJournals < ActiveRecord::Migration |
||||
def change |
||||
add_column :work_package_journals, :cost_object_id, :integer, null: true |
||||
end |
||||
end |
@ -1,4 +1,4 @@ |
||||
# Hooks to attach to the OpenProject action menu. |
||||
class OpenProject::Costs::Hooks::WorkPackageActionMenuHook < Redmine::Hook::ViewListener |
||||
render_on :view_work_package_show_action_menu, :partial => 'hooks/view_work_package_show_action_menu' |
||||
render_on :view_issues_show_action_menu, :partial => 'hooks/view_work_package_show_action_menu' |
||||
end |
||||
|
@ -1,21 +0,0 @@ |
||||
require_dependency 'issue' |
||||
|
||||
class CostsIssueObserver < ActiveRecord::Observer |
||||
unloadable |
||||
observe :issue |
||||
|
||||
def after_update(issue) |
||||
if issue.project_id_changed? |
||||
# TODO: This only works with the global cost_rates |
||||
CostEntry.update_all({:project_id => issue.project_id}, {:work_package_id => issue.id}) |
||||
end |
||||
end |
||||
|
||||
def before_update(issue) |
||||
# FIXME: remove this method once controller_issues_move_before_save is in 0.9-stable |
||||
if issue.project_id_changed? && issue.cost_object_id && !issue.project.cost_object_ids.include?(issue.cost_object_id) |
||||
issue.cost_object = nil |
||||
end |
||||
# true |
||||
end |
||||
end |
@ -1,27 +0,0 @@ |
||||
require 'issue' |
||||
|
||||
module OpenProject::Costs::Patches::IssuePatch |
||||
def self.included(base) # :nodoc: |
||||
base.extend(ClassMethods) |
||||
|
||||
base.send(:include, InstanceMethods) |
||||
|
||||
# Same as typing in the class |
||||
base.class_eval do |
||||
unloadable |
||||
|
||||
belongs_to :cost_object, :inverse_of => :work_packages |
||||
has_many :cost_entries, :foreign_key => :work_package_id, :dependent => :delete_all |
||||
end |
||||
end |
||||
|
||||
module ClassMethods |
||||
|
||||
end |
||||
|
||||
module InstanceMethods |
||||
|
||||
end |
||||
end |
||||
|
||||
Issue.send(:include, OpenProject::Costs::Patches::IssuePatch) |
@ -1,77 +0,0 @@ |
||||
require_dependency 'issues_controller' |
||||
|
||||
module OpenProject::Costs::Patches::IssuesControllerPatch |
||||
def self.included(base) # :nodoc: |
||||
base.send(:include, InstanceMethods) |
||||
|
||||
base.class_eval do |
||||
alias_method_chain :show, :entries |
||||
alias_method_chain :destroy, :entries |
||||
|
||||
helper :issues |
||||
end |
||||
|
||||
end |
||||
|
||||
module InstanceMethods |
||||
# Authorize the user for the requested action |
||||
def show_with_entries |
||||
@cost_entries = @issue.cost_entries.visible(User.current, @issue.project) |
||||
cost_entries_with_rate = @cost_entries.select{|c| c.costs_visible_by?(User.current)} |
||||
@material_costs = cost_entries_with_rate.blank? ? nil : cost_entries_with_rate.collect(&:real_costs).sum |
||||
|
||||
@time_entries = @issue.time_entries.visible(User.current, @issue.project) |
||||
time_entries_with_rate = @time_entries.select{|c| c.costs_visible_by?(User.current)} |
||||
@labor_costs = time_entries_with_rate.blank? ? nil : time_entries_with_rate.collect(&:real_costs).sum |
||||
|
||||
unless @material_costs.nil? && @labor_costs.nil? |
||||
@overall_costs = 0 |
||||
@overall_costs += @material_costs unless @material_costs.nil? |
||||
@overall_costs += @labor_costs unless @labor_costs.nil? |
||||
else |
||||
@overall_costs = nil |
||||
end |
||||
|
||||
show_without_entries |
||||
end |
||||
|
||||
def destroy_with_entries |
||||
@entries = CostEntry.all(:conditions => ['work_package_id IN (?)', @issues]) |
||||
@hours = TimeEntry.sum(:hours, :conditions => ['work_package_id IN (?)', @issues]).to_f |
||||
unless @entries.blank? && @hours == 0 |
||||
case params[:todo] |
||||
when 'destroy' |
||||
# nothing to do |
||||
when 'nullify' |
||||
TimeEntry.update_all('work_package_id = NULL', ['work_package_id IN (?)', @issues]) |
||||
CostEntry.update_all('work_package_id = NULL', ['work_package_id IN (?)', @issues]) |
||||
when 'reassign' |
||||
reassign_to = @project.work_packages.find_by_id(params[:reassign_to_id]) |
||||
if reassign_to.nil? |
||||
flash.now[:error] = l(:error_issue_not_found_in_project) |
||||
return |
||||
else |
||||
TimeEntry.update_all("work_package_id = #{reassign_to.id}", ['work_package_id IN (?)', @issues]) |
||||
CostEntry.update_all("work_package_id = #{reassign_to.id}", ['work_package_id IN (?)', @issues]) |
||||
end |
||||
else |
||||
# display the destroy form if it's a user request |
||||
return unless api_request? |
||||
end |
||||
end |
||||
@issues.each do |issue| |
||||
begin |
||||
issue.reload.destroy |
||||
rescue ::ActiveRecord::RecordNotFound # raised by #reload if issue no longer exists |
||||
# nothing to do, issue was already deleted (eg. by a parent) |
||||
end |
||||
end |
||||
respond_to do |format| |
||||
format.html { redirect_to :action => 'index', :project_id => @project } |
||||
format.api { head :ok } |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
IssuesController.send(:include, OpenProject::Costs::Patches::IssuesControllerPatch) |
@ -1,89 +0,0 @@ |
||||
require_dependency 'issues_helper' |
||||
|
||||
module OpenProject::Costs::Patches::IssuesHelperPatch |
||||
def self.included(base) # :nodoc: |
||||
base.send(:include, InstanceMethods) |
||||
|
||||
# Same as typing in the class |
||||
base.class_eval do |
||||
def summarized_cost_entries(cost_entries, create_link=true) |
||||
last_cost_type = "" |
||||
|
||||
return "-" 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 |
||||
|
||||
str_array = [] |
||||
result.each do |k, v| |
||||
txt = pluralize(v[:units], v[:unit], v[:unit_plural]) |
||||
if create_link |
||||
# TODO why does this have project_id, issue_id and cost_type_id params? |
||||
str_array << link_to(txt, { :controller => '/costlog', |
||||
:action => 'index', |
||||
:project_id => @work_package.project, |
||||
:work_package_id => @work_package, |
||||
:cost_type_id => k }, |
||||
{ :title => k.name }) |
||||
else |
||||
str_array << "<span title=\"#{h(k.name)}\">#{txt}</span>" |
||||
end |
||||
end |
||||
str_array.join(", ").html_safe |
||||
end |
||||
|
||||
def cost_issues_attributes(work_package) |
||||
attributes = [] |
||||
|
||||
object_value = if work_package.cost_object.nil? |
||||
"-" |
||||
else |
||||
link_to_cost_object(work_package.cost_object) |
||||
end |
||||
|
||||
attributes << [CostObject.model_name.human, object_value] |
||||
|
||||
if User.current.allowed_to?(:view_time_entries, @project) || |
||||
User.current.allowed_to?(:view_own_time_entries, @project) |
||||
|
||||
#TODO: put inside controller or model |
||||
summed_hours = @time_entries.sum(&:hours) |
||||
|
||||
value = summed_hours > 0 ? |
||||
link_to(l_hours(summed_hours), issue_time_entries_path(work_package)) : "-" |
||||
|
||||
attributes << [Issue.human_attribute_name(:spent_hours), value] |
||||
end |
||||
|
||||
unless @overall_costs.nil? |
||||
attributes << [Issue.human_attribute_name(:overall_costs), number_to_currency(@overall_costs)] |
||||
end |
||||
|
||||
|
||||
if User.current.allowed_to?(:view_cost_entries, @project) || |
||||
User.current.allowed_to?(:view_own_cost_entries, @project) |
||||
|
||||
attributes << [Issue.human_attribute_name(:spent_units), summarized_cost_entries(@cost_entries)] |
||||
end |
||||
|
||||
attributes |
||||
end |
||||
end |
||||
end |
||||
|
||||
module InstanceMethods |
||||
|
||||
end |
||||
end |
||||
|
||||
IssuesHelper.send(:include, OpenProject::Costs::Patches::IssuesHelperPatch) |
@ -0,0 +1,21 @@ |
||||
require_dependency 'work_package' |
||||
|
||||
class CostsWorkPackageObserver < ActiveRecord::Observer |
||||
unloadable |
||||
observe :work_package |
||||
|
||||
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}) |
||||
end |
||||
end |
||||
|
||||
def before_update(work_package) |
||||
# FIXME: remove this method once controller_work_packages_move_before_save is in 0.9-stable |
||||
if work_package.project_id_changed? && work_package.cost_object_id && !work_package.project.cost_object_ids.include?(work_package.cost_object_id) |
||||
work_package.cost_object = nil |
||||
end |
||||
# true |
||||
end |
||||
end |
@ -1,37 +0,0 @@ |
||||
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') |
||||
|
||||
describe Issue do |
||||
let(:user) { FactoryGirl.create(:admin)} |
||||
let(:role) { FactoryGirl.create(:role) } |
||||
let(:project) do |
||||
project = FactoryGirl.create(:project_with_trackers) |
||||
project.add_member!(user, role) |
||||
project |
||||
end |
||||
|
||||
let(:project2) { FactoryGirl.create(:project_with_trackers) } |
||||
let(:issue) { FactoryGirl.create(:issue, :project => project, |
||||
:tracker => project.trackers.first, |
||||
:author => user) } |
||||
let!(:cost_entry) { FactoryGirl.create(:cost_entry, work_package: issue, 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 |
||||
User.stub!(:current).and_return(user) |
||||
end |
||||
|
||||
it "should update cost entries on move" do |
||||
issue.project_id.should eql project.id |
||||
issue.move_to_project(project2).should_not be_false |
||||
cost_entry.reload.project_id.should eql project2.id |
||||
end |
||||
|
||||
it "should allow to set cost_object to nil" do |
||||
issue.cost_object = cost_object |
||||
issue.save! |
||||
issue.cost_object.should eql cost_object |
||||
|
||||
issue.cost_object = nil |
||||
lambda { issue.save! }.should_not raise_error(ActiveRecord::RecordInvalid) |
||||
end |
||||
end |
@ -0,0 +1,37 @@ |
||||
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') |
||||
|
||||
describe WorkPackage 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 |
||||
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!(:cost_object) { FactoryGirl.create(:cost_object, project: project) } |
||||
|
||||
before(:each) do |
||||
User.stub!(:current).and_return(user) |
||||
end |
||||
|
||||
it "should update cost entries on move" do |
||||
work_package.project_id.should eql project.id |
||||
work_package.move_to_project(project2).should_not be_false |
||||
cost_entry.reload.project_id.should eql project2.id |
||||
end |
||||
|
||||
it "should allow to set cost_object to nil" do |
||||
work_package.cost_object = cost_object |
||||
work_package.save! |
||||
work_package.cost_object.should eql cost_object |
||||
|
||||
work_package.cost_object = nil |
||||
lambda { work_package.save! }.should_not raise_error(ActiveRecord::RecordInvalid) |
||||
end |
||||
end |
Loading…
Reference in new issue