#-- 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. #++ # A CostObject is an item that is created as part of the project. These items # contain a collection of work packages. class CostObject < ActiveRecord::Base unloadable belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' belongs_to :project has_many :work_packages, :dependent => :nullify has_many :cost_entries, :through => :work_packages has_many :time_entries, :through => :work_packages include ActiveModel::ForbiddenAttributesProtection acts_as_attachable :after_remove => :attachment_removed acts_as_journalized acts_as_event type: 'cost-objects', title: Proc.new {|o| "#{l(:label_cost_object)} ##{o.id}: #{o.subject}"}, url: Proc.new {|o| {:controller => 'cost_objects', :action => 'show', :id => o.id}} validates_presence_of :subject, :project, :author, :kind, :fixed_date validates_length_of :subject, :maximum => 255 validates_length_of :subject, :minimum => 1 User.before_destroy do |user| CostObject.replace_author_with_deleted_user user end def initialize(attributes = nil) super self.author = User.current if self.new_record? end def copy_from(arg) if !arg.is_a?(Hash) #turn args into an attributes hash if it is not already (which is the case when called from VariableCostObject) arg = (arg.is_a?(CostObject) ? arg : self.class.find(arg)).attributes.dup end arg.delete("id") self.type = arg.delete("type") self.attributes = arg end # Wrap type column to make it usable in views (especially in a select tag) def kind self[:type] end def kind=(type) self[:type] = type end # Assign all the work_packages with +version_id+ to this Cost Object def assign_work_packages_by_version(version_id) version = Version.find_by_id(version_id) return 0 if version.nil? || version.fixed_work_packages.blank? version.fixed_work_packages.each do |work_package| work_package.update_attribute(:cost_object_id, self.id) end return version.fixed_work_packages.size end # Change the Cost Object type to another type. Valid types are # # * FixedCostObject # * VariableCostObject def change_type(to) if [FixedCostObject.name, VariableCostObject.name].include?(to) self.type = to self.save! return CostObject.find(self.id) else return self end end # Amount spent. Virtual accessor that is overriden by subclasses. def spent 0 end # Budget of labor. Virtual accessor that is overriden by subclasses. def labor_budget 0.0 end # Budget of material, i.e. all costs besides labor costs. Virtual accessor that is overriden by subclasses. def material_budget 0.0 end def budget material_budget + labor_budget end # Label of the current type for display in GUI. Virtual accessor that is overriden by subclasses. def type_label return l(:label_cost_object) end # Amount of the budget spent. Expressed as as a percentage whole number def budget_ratio return 0.0 if self.budget.nil? || self.budget == 0.0 return ((self.spent / self.budget) * 100).round end def css_classes return "cost_object" end def self.replace_author_with_deleted_user(user) substitute = DeletedUser.first self.update_all ['author_id = ?', substitute.id], ['author_id = ?', user.id] end def to_s subject end end