Created
May 14, 2009 10:25
-
-
Save susieyy/111608 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# redmine-budget-plugin / init.rb | |
require 'redmine' | |
# Budget requires the Rate plugin | |
begin | |
require 'rate' unless Object.const_defined?('Rate') | |
rescue LoadError | |
# rate_plugin is not installed | |
raise Exception.new("ERROR: The Rate plugin is not installed. Please install the Rate plugin from https://projects.littlestreamsoftware.com/projects/redmine-rate") | |
end | |
# Patches to the Redmine core. | |
require 'dispatcher' | |
require 'issue_patch' | |
require 'query_patch' | |
Dispatcher.to_prepare do | |
Issue.send(:include, IssuePatch) | |
Query.send(:include, QueryPatch) | |
end | |
# Hooks | |
require_dependency 'budget_issue_hook' | |
require_dependency 'budget_project_hook' | |
Redmine::Plugin.register :budget_plugin do | |
name 'Budget' | |
author 'Eric Davis' | |
description 'Budget is a plugin to manage the set of deliverables for each project, automatically calculating key performance indicators.' | |
url 'https://projects.littlestreamsoftware.com/projects/redmine-budget' | |
author_url 'http://www.littlestreamsoftware.com' | |
version '0.2.0' | |
requires_redmine :version_or_higher => '0.8.0' | |
settings :default => { | |
'budget_nonbillable_overhead' => '', | |
'budget_materials' => '', | |
'budget_profit' => '' | |
}, :partial => 'settings/budget_settings' | |
project_module :budget_module do | |
permission :view_budget, { :deliverables => [:index, :issues]} | |
permission :manage_budget, { :deliverables => [:new, :edit, :create, :update, :destroy, :preview, :bulk_assign_issues]} | |
end | |
menu :project_menu, :budget, {:controller => "deliverables", :action => 'index'}, :caption => :budget_title | |
end | |
# redmine-budget-plugin / lib / budget_project_hook.rb | |
class BudgetProjectHook < Redmine::Hook::ViewListener | |
def model_project_copy_before_save(context = {}) | |
source = context[:source_project] | |
destination = context[:destination_project] | |
if source.module_enabled?(:budget_module) | |
Deliverable.find(:all, :conditions => {:project_id => source.id}).each do |source_deliverable| | |
destination_deliverable = source_deliverable.class.new # STI classes | |
# Copy attribute except for the ones that have wrapped | |
# accessors, use read/write attribute for them | |
destination_deliverable.attributes = source_deliverable.attributes.except("project_id", "profit", "materials", "overhead") | |
destination_deliverable.write_attribute(:profit, source_deliverable.read_attribute(:profit)) | |
destination_deliverable.write_attribute(:profit_percent, source_deliverable.read_attribute(:profit_percent)) | |
destination_deliverable.write_attribute(:materials, source_deliverable.read_attribute(:materials)) | |
destination_deliverable.write_attribute(:materials_percent, source_deliverable.read_attribute(:materials_percent)) | |
destination_deliverable.write_attribute(:overhead, source_deliverable.read_attribute(:overhead)) | |
destination_deliverable.write_attribute(:overhead_percent, source_deliverable.read_attribute(:overhead_percent)) | |
destination_deliverable.project = destination | |
destination_deliverable.save # Need to save here because there is no relation on project to deliverable | |
end | |
end | |
end | |
end | |
# redmine-budget-plugin / lib / budget_issue_hook.rb | |
# Hooks to attach to the Redmine Issues. | |
class BudgetIssueHook < Redmine::Hook::ViewListener | |
# Renders the Deliverable subject | |
# | |
# Context: | |
# * :issue => Issue being rendered | |
# | |
def view_issues_show_details_bottom(context = { }) | |
if context[:project].module_enabled?('budget_module') | |
data = "<td><b>Deliverable :</b></td><td>#{html_escape context[:issue].deliverable.subject unless context[:issue].deliverable.nil?}</td>" | |
return "<tr>#{data}<td></td></tr>" | |
else | |
return '' | |
end | |
end | |
# Renders a select tag with all the Deliverables | |
# | |
# Context: | |
# * :form => Edit form | |
# * :project => Current project | |
# | |
def view_issues_form_details_bottom(context = { }) | |
if context[:project].module_enabled?('budget_module') | |
select = context[:form].select :deliverable_id, Deliverable.find_all_by_project_id(context[:project], :order => 'subject ASC').collect { |d| [d.subject, d.id] }, :include_blank => true | |
return "<p>#{select}</p>" | |
else | |
return '' | |
end | |
end | |
# Renders a select tag with all the Deliverables for the bulk edit page | |
# | |
# Context: | |
# * :project => Current project | |
# | |
def view_issues_bulk_edit_details_bottom(context = { }) | |
if context[:project].module_enabled?('budget_module') | |
select = select_tag('deliverable_id', | |
content_tag('option', l(:label_no_change_option), :value => '') + | |
content_tag('option', l(:label_none), :value => 'none') + | |
options_from_collection_for_select(Deliverable.find_all_by_project_id(context[:project].id, :order => 'subject ASC'), :id, :subject)) | |
return content_tag(:p, "<label>#{l(:field_deliverable)}: " + select + "</label>") | |
else | |
return '' | |
end | |
end | |
# Saves the Deliverable assignment to the issue | |
# | |
# Context: | |
# * :issue => Issue being saved | |
# * :params => HTML parameters | |
# | |
def controller_issues_bulk_edit_before_save(context = { }) | |
case true | |
when context[:params][:deliverable_id].blank? | |
# Do nothing | |
when context[:params][:deliverable_id] == 'none' | |
# Unassign deliverable | |
context[:issue].deliverable = nil | |
else | |
context[:issue].deliverable = Deliverable.find(context[:params][:deliverable_id]) | |
end | |
return '' | |
end | |
# Deliverable changes for the journal use the Deliverable subject | |
# instead of the id | |
# | |
# Context: | |
# * :detail => Detail about the journal change | |
# | |
def helper_issues_show_detail_after_setting(context = { }) | |
# TODO Later: Overwritting the caller is bad juju | |
if context[:detail].prop_key == 'deliverable_id' | |
d = Deliverable.find_by_id(context[:detail].value) | |
context[:detail].value = d.subject unless d.nil? || d.subject.nil? | |
d = Deliverable.find_by_id(context[:detail].old_value) | |
context[:detail].old_value = d.subject unless d.nil? || d.subject.nil? | |
end | |
'' | |
end | |
end | |
# redmine-budget-plugin / lib / issue_patch.rb | |
require_dependency 'issue' | |
# Patches Redmine's Issues dynamically. Adds a relationship | |
# Issue +belongs_to+ to Deliverable | |
module IssuePatch | |
def self.included(base) # :nodoc: | |
base.extend(ClassMethods) | |
base.send(:include, InstanceMethods) | |
# Same as typing in the class | |
base.class_eval do | |
unloadable # Send unloadable so it will not be unloaded in development | |
belongs_to :deliverable | |
end | |
end | |
module ClassMethods | |
end | |
module InstanceMethods | |
# Wraps the association to get the Deliverable subject. Needed for the | |
# Query and filtering | |
def deliverable_subject | |
unless self.deliverable.nil? | |
return self.deliverable.subject | |
end | |
end | |
end | |
end | |
# redmine-budget-plugin / lib / query_patch.rb | |
require_dependency 'query' | |
# Patches Redmine's Queries dynamically, adding the Deliverable | |
# to the available query columns | |
module QueryPatch | |
def self.included(base) # :nodoc: | |
base.extend(ClassMethods) | |
base.send(:include, InstanceMethods) | |
# Same as typing in the class | |
base.class_eval do | |
unloadable # Send unloadable so it will not be unloaded in development | |
base.add_available_column(QueryColumn.new(:deliverable_subject, :sortable => "#{Deliverable.table_name}.subject")) | |
alias_method :redmine_available_filters, :available_filters | |
alias_method :available_filters, :budget_available_filters | |
end | |
end | |
module ClassMethods | |
# Setter for +available_columns+ that isn't provided by the core. | |
def available_columns=(v) | |
self.available_columns = (v) | |
end | |
# Method to add a column to the +available_columns+ that isn't provided by the core. | |
def add_available_column(column) | |
self.available_columns << (column) | |
end | |
end | |
module InstanceMethods | |
# Wrapper around the +available_filters+ to add a new Deliverable filter | |
def budget_available_filters | |
@available_filters = redmine_available_filters | |
if project | |
budget_filters = { "deliverable_id" => { :type => :list_optional, :order => 14, | |
:values => Deliverable.find(:all, :conditions => ["project_id IN (?)", project], :order => 'subject ASC').collect { |d| [d.subject, d.id.to_s]} | |
}} | |
else | |
budget_filters = { } | |
end | |
return @available_filters.merge(budget_filters) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment