Compare commits
14
Commits
4178-skinning
...
v0.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
437909b621 | ||
|
|
720da2c554 | ||
|
|
620eaa262f | ||
|
|
a3e1aa277f | ||
|
|
25436910fb | ||
|
|
6924b32048 | ||
|
|
b83696f49a | ||
|
|
8906639273 | ||
|
|
dfcc31c83e | ||
|
|
fa12fcd129 | ||
|
|
82d46bd12a | ||
|
|
a2b810a4d8 | ||
|
|
c17e8eaf1b | ||
|
|
e734430deb |
@@ -10,8 +10,8 @@ module ContractsHelper
|
||||
extra_css_class = options[:class] || ''
|
||||
|
||||
if total > 0 || spent > 0
|
||||
content_tag(:td, h(number_to_currency(spent, :unit => '')), :class => 'spent-amount ' + extra_css_class) +
|
||||
content_tag(:td, h(number_to_currency(total, :unit => '')), :class => 'total-amount white ' + extra_css_class)
|
||||
content_tag(:td, h(format_value_field_for_contracts(spent)), :class => 'spent-amount ' + extra_css_class) +
|
||||
content_tag(:td, h(format_value_field_for_contracts(total)), :class => 'total-amount white ' + extra_css_class)
|
||||
else
|
||||
content_tag(:td, '----', :colspan => '2', :class => 'no-value ' + extra_css_class)
|
||||
end
|
||||
@@ -75,6 +75,14 @@ module ContractsHelper
|
||||
|
||||
def format_payment_terms(value)
|
||||
return '' if value.blank?
|
||||
return l(Contract::PaymentTerms[value.to_sym])
|
||||
return h(value.name)
|
||||
end
|
||||
|
||||
def format_deliverable_value_fields(value)
|
||||
number_with_precision(value, :precision => Deliverable::ViewPrecision, :delimiter => '')
|
||||
end
|
||||
|
||||
def format_value_field_for_contracts(value)
|
||||
number_with_precision(value, :precision => Contract::ViewPrecision, :delimiter => ',')
|
||||
end
|
||||
end
|
||||
|
||||
+10
-14
@@ -1,9 +1,12 @@
|
||||
class Contract < ActiveRecord::Base
|
||||
unloadable
|
||||
|
||||
ViewPrecision = 0
|
||||
|
||||
# Associations
|
||||
belongs_to :project
|
||||
belongs_to :account_executive, :class_name => 'User', :foreign_key => 'account_executive_id'
|
||||
belongs_to :payment_term, :class_name => "PaymentTerm", :foreign_key => "payment_term_id"
|
||||
has_many :deliverables, :dependent => :destroy
|
||||
|
||||
# Validations
|
||||
@@ -24,12 +27,14 @@ class Contract < ActiveRecord::Base
|
||||
attr_accessible :billable_rate
|
||||
attr_accessible :discount
|
||||
attr_accessible :discount_note
|
||||
attr_accessible :payment_terms
|
||||
attr_accessible :payment_term_id
|
||||
attr_accessible :client_ap_contact_information
|
||||
attr_accessible :po_number
|
||||
attr_accessible :client_point_of_contact
|
||||
attr_accessible :details
|
||||
|
||||
named_scope :by_name, {:order => "#{Contract.table_name}.name ASC"}
|
||||
|
||||
[:status, :contract_type,
|
||||
:fixed_spent, :fixed_budget,
|
||||
:markup_spent, :markup_budget,
|
||||
@@ -91,19 +96,6 @@ class Contract < ActiveRecord::Base
|
||||
end
|
||||
alias_method :profit_spent, :profit_left
|
||||
|
||||
PaymentTerms = {
|
||||
:net_0 => :text_payment_terms_net_0,
|
||||
:net_15 => :text_payment_terms_net_15,
|
||||
:net_30 => :text_payment_terms_net_30,
|
||||
:net_45 => :text_payment_terms_net_45
|
||||
}
|
||||
|
||||
def payment_terms_for_select
|
||||
PaymentTerms.collect {|value, label|
|
||||
[l(label), value.to_s]
|
||||
}
|
||||
end
|
||||
|
||||
def after_initialize
|
||||
self.executed = false unless self.executed.present?
|
||||
end
|
||||
@@ -114,6 +106,10 @@ class Contract < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
def to_s
|
||||
name
|
||||
end
|
||||
|
||||
if Rails.env.test?
|
||||
generator_for :name, :method => :next_name
|
||||
generator_for :executed => true
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
class Deliverable < ActiveRecord::Base
|
||||
unloadable
|
||||
|
||||
ViewPrecision = 2
|
||||
|
||||
# Associations
|
||||
belongs_to :contract
|
||||
belongs_to :manager, :class_name => 'User', :foreign_key => 'manager_id'
|
||||
@@ -18,10 +20,18 @@ class Deliverable < ActiveRecord::Base
|
||||
|
||||
# Accessors
|
||||
|
||||
delegate :name, :to => :contract, :prefix => true, :allow_nil => true
|
||||
|
||||
named_scope :by_title, {:order => "#{Deliverable.table_name}.title ASC"}
|
||||
|
||||
def short_type
|
||||
''
|
||||
end
|
||||
|
||||
def to_s
|
||||
title
|
||||
end
|
||||
|
||||
def to_underscore
|
||||
self.class.to_s.underscore
|
||||
end
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
class PaymentTerm < Enumeration
|
||||
unloadable
|
||||
|
||||
has_many :contracts, :foreign_key => 'payment_term_id'
|
||||
|
||||
OptionName = :enumeration_payment_term
|
||||
|
||||
def option_name
|
||||
OptionName
|
||||
end
|
||||
|
||||
def objects_count
|
||||
contracts.count
|
||||
end
|
||||
|
||||
def transfer_relations(to)
|
||||
contracts.update_all("payment_term_id = #{to.id}")
|
||||
end
|
||||
end
|
||||
@@ -18,7 +18,7 @@
|
||||
<% end %>
|
||||
|
||||
<% form.inputs :name => l(:text_account_legend) do %>
|
||||
<%= form.input :payment_terms, :as => :select, :collection => resource.payment_terms_for_select %>
|
||||
<%= form.input :payment_term %>
|
||||
<%= form.input :po_number %>
|
||||
<%= form.input :client_ap_contact_information, :input_html => {:class => 'wiki-edit', :rows => '5'} %>
|
||||
<%= form.input :client_point_of_contact, :input_html => {:class => 'wiki-edit', :rows => '5'} %>
|
||||
|
||||
@@ -10,3 +10,4 @@
|
||||
<%= render :partial => 'form', :object => form, :locals => {:cancel_path => contract_path(@project, resource)} %>
|
||||
<% end %>
|
||||
|
||||
<% html_title "#{l(:text_contracts)} - #{h(l(:text_edit_contract_name, :name => resource.name))}" %>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<td class="id"><%= link_to(h(contract.id), contract_path(@project, contract)) %></td>
|
||||
<td class="name"><%= link_to(h(contract.name), contract_path(@project, contract)) %></td>
|
||||
<td class="account-executive"><%= h contract.account_executive.name %></td>
|
||||
<td class="total-budget"><%= h(number_to_currency(contract.total_budget)) %></td>
|
||||
<td class="total-budget"><%= h(format_value_field_for_contracts(contract.total_budget)) %></td>
|
||||
<td class="end-date"><%= h format_date(contract.end_date) %></td>
|
||||
<% end %>
|
||||
<% end %>
|
||||
@@ -48,3 +48,5 @@
|
||||
<p>TODO: Release 5 (Contract Status)</p>
|
||||
|
||||
</div>
|
||||
|
||||
<% html_title "#{l(:text_contracts)}" %>
|
||||
|
||||
@@ -3,3 +3,5 @@
|
||||
<% semantic_form_for resource, :html => {:class => 'tabular'} do |form| %>
|
||||
<%= render :partial => 'form', :object => form, :locals => {:cancel_path => contracts_path} %>
|
||||
<% end %>
|
||||
|
||||
<% html_title "#{l(:text_new_contract)}" %>
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
</table>
|
||||
|
||||
<table class="right">
|
||||
<%= show_budget_field(resource, :labor_spent, :labor_budget, :html_options => {:class => 'contract-labor'}, :label_html_options => {:width => '49%'}) %>
|
||||
<%= show_budget_field(resource, :overhead_spent, :overhead_budget, :html_options => {:class => 'contract-overhead'}) %>
|
||||
<%= show_budget_field(resource, :total_spent, :total_budget, :html_options => {:class => 'contract-total'}) %>
|
||||
<%= show_budget_field(resource, :labor_spent, :labor_budget, :format => :format_value_field_for_contracts, :html_options => {:class => 'contract-labor'}, :label_html_options => {:width => '49%'}) %>
|
||||
<%= show_budget_field(resource, :overhead_spent, :overhead_budget, :format => :format_value_field_for_contracts, :html_options => {:class => 'contract-overhead'}) %>
|
||||
<%= show_budget_field(resource, :total_spent, :total_budget, :format => :format_value_field_for_contracts, :html_options => {:class => 'contract-total'}) %>
|
||||
</table>
|
||||
|
||||
<div class="clear"></div>
|
||||
@@ -33,7 +33,7 @@
|
||||
<%= show_field(resource, :client_point_of_contact, :format => :textilizable, :raw => true, :html_options => {:class => 'contract-client-point-of-contact padd'}, :label_html_options => {:width => '25%'}) %>
|
||||
<%= show_field(resource, :executed, :html_options => {:class => 'contract-executed'}) %>
|
||||
<%= show_field(resource, :discount_note, :format => :textilizable, :raw => true, :html_options => {:class => 'contract-discount-note'}) %>
|
||||
<%= show_field(resource, :payment_terms, :format => :format_payment_terms, :html_options => {:class => 'contract-payment-terms'}) %>
|
||||
<%= show_field(resource, :payment_term, :format => :format_payment_terms, :html_options => {:class => 'contract-payment-terms'}) %>
|
||||
<%= show_field(resource, :client_ap_contact_information, :format => :textilizable, :raw => true, :html_options => {:class => 'contract-client-ap-contact-information'}) %>
|
||||
<%= show_field(resource, :po_number, :html_options => {:class => 'contract-po-number'}) %>
|
||||
<%= show_field(resource, :details, :format => :textilizable, :raw => true, :html_options => {:class => 'contract-details'}) %>
|
||||
@@ -41,12 +41,12 @@
|
||||
</div>
|
||||
|
||||
<table class="finance">
|
||||
<%= show_budget_field(resource, :labor_spent, :labor_budget, :html_options => {:class => 'contract-labor'}, :label_html_options => {:width => '46%'}) %>
|
||||
<%= show_budget_field(resource, :overhead_spent, :overhead_budget, :html_options => {:class => 'contract-overhead'}) %>
|
||||
<%= show_budget_field(resource, :fixed_spent, :fixed_budget, :html_options => {:class => 'contract-fixed'}) %>
|
||||
<%= show_budget_field(resource, :markup_spent, :markup_budget, :html_options => {:class => 'contract-markup'}) %>
|
||||
<%= show_budget_field(resource, :profit_spent, :profit_budget, :html_options => {:class => 'contract-profit'}) %>
|
||||
<%= show_budget_field(resource, :discount_spent, :discount_budget, :html_options => {:class => 'contract-discount'}) %>
|
||||
<%= show_budget_field(resource, :labor_spent, :labor_budget, :format => :format_value_field_for_contracts, :html_options => {:class => 'contract-labor'}, :label_html_options => {:width => '46%'}) %>
|
||||
<%= show_budget_field(resource, :overhead_spent, :overhead_budget, :format => :format_value_field_for_contracts, :html_options => {:class => 'contract-overhead'}) %>
|
||||
<%= show_budget_field(resource, :fixed_spent, :fixed_budget, :format => :format_value_field_for_contracts, :html_options => {:class => 'contract-fixed'}) %>
|
||||
<%= show_budget_field(resource, :markup_spent, :markup_budget, :format => :format_value_field_for_contracts, :html_options => {:class => 'contract-markup'}) %>
|
||||
<%= show_budget_field(resource, :profit_spent, :profit_budget, :format => :format_value_field_for_contracts, :html_options => {:class => 'contract-profit'}) %>
|
||||
<%= show_budget_field(resource, :discount_spent, :discount_budget, :format => :format_value_field_for_contracts, :html_options => {:class => 'contract-discount'}) %>
|
||||
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
@@ -54,7 +54,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<%= show_budget_field(resource, :total_spent, :total_budget, :html_options => {:class => 'contract-total'}) %>
|
||||
<%= show_budget_field(resource, :total_spent, :total_budget, :format => :format_value_field_for_contracts, :html_options => {:class => 'contract-total'}) %>
|
||||
<%= show_field(resource, :billable_rate, :format => :format_hourly_rate, :html_options => {:class => 'contract-billable-rate total'}) %>
|
||||
|
||||
<%= show_budget_field(resource, :estimated_hour_spent, :estimated_hour_budget, :format => :l_hours, :html_options => {:class => 'contract-estimated-hour total'}) %>
|
||||
@@ -148,28 +148,28 @@
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="l"><a href="#"><strong>Labor</strong></a></td>
|
||||
<td><%= h(deliverable.labor_budget_spent) %></td>
|
||||
<td><%= h(deliverable.labor_budget_total) %></td>
|
||||
<td><%= h(format_value_field_for_contracts(deliverable.labor_budget_spent)) %></td>
|
||||
<td><%= h(format_value_field_for_contracts(deliverable.labor_budget_total)) %></td>
|
||||
<td> TODO: Release 2 / TODO hrs </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="l"><a href="#"><strong>Overhead</strong></a></td>
|
||||
<td><%= h(deliverable.overhead_spent) %></td>
|
||||
<td><%= h(deliverable.overhead_budget_total) %></td>
|
||||
<td><%= h(format_value_field_for_contracts(deliverable.overhead_spent)) %></td>
|
||||
<td><%= h(format_value_field_for_contracts(deliverable.overhead_budget_total)) %></td>
|
||||
<td> TODO: Release 2 / TODO hrs </td>
|
||||
</tr>
|
||||
<%# TODO: Release 2, Fixed %>
|
||||
<%# TODO: Release 2, Markup %>
|
||||
<tr>
|
||||
<td class="l">Profit</td>
|
||||
<td><%= h(deliverable.profit_left) %></td>
|
||||
<td><%= h(deliverable.profit_budget) %></td>
|
||||
<td><%= h(format_value_field_for_contracts(deliverable.profit_left)) %></td>
|
||||
<td><%= h(format_value_field_for_contracts(deliverable.profit_budget)) %></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="total">
|
||||
<td class="l"><strong>Total:</strong></td>
|
||||
<td><strong><%= h(deliverable.total_spent) %></strong></td>
|
||||
<td><strong><%= h(deliverable.total) %></strong></td>
|
||||
<td><strong><%= h(format_value_field_for_contracts(deliverable.total_spent)) %></strong></td>
|
||||
<td><strong><%= h(format_value_field_for_contracts(deliverable.total)) %></strong></td>
|
||||
<td><strong>TODO: Release 2</strong></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -292,3 +292,5 @@
|
||||
-->
|
||||
|
||||
<p>TODO: Release 2+, history</p>
|
||||
|
||||
<% html_title "#{l(:text_contracts)} - #{h(resource.name)}" %>
|
||||
|
||||
@@ -37,11 +37,11 @@
|
||||
</td>
|
||||
<td>
|
||||
<p class="inline-hints"><%= labor_budget.label(:hours, l(:text_short_hours)) %></p>
|
||||
<%= labor_budget.text_field(:hours, :size => 10) %>
|
||||
<%= labor_budget.text_field(:hours, :value => format_deliverable_value_fields(labor_budget.object.hours), :size => 10) %>
|
||||
</td>
|
||||
<td>
|
||||
<p class="inline-hints"><%= labor_budget.label(:budget, l(:text_dollar_sign)) %></p>
|
||||
<%= labor_budget.text_field(:budget, :size => 10) %>
|
||||
<%= labor_budget.text_field(:budget, :value => format_deliverable_value_fields(labor_budget.object.budget), :size => 10) %>
|
||||
</td>
|
||||
<%# TODO: Green Add button for multiple records %>
|
||||
<td>
|
||||
@@ -64,11 +64,11 @@
|
||||
</td>
|
||||
<td>
|
||||
<p class="inline-hints"><%= overhead_budget.label(:hours, l(:text_short_hours)) %></p>
|
||||
<%= overhead_budget.text_field(:hours, :size => 10) %>
|
||||
<%= overhead_budget.text_field(:hours, :value => format_deliverable_value_fields(overhead_budget.object.hours),:size => 10) %>
|
||||
</td>
|
||||
<td>
|
||||
<p class="inline-hints"><%= overhead_budget.label(:budget, l(:text_dollar_sign)) %></p>
|
||||
<%= overhead_budget.text_field(:budget, :size => 10) %>
|
||||
<%= overhead_budget.text_field(:budget, :value => format_deliverable_value_fields(overhead_budget.object.budget), :size => 10) %>
|
||||
</td>
|
||||
<%# TODO: Green Add button for multiple records %>
|
||||
<td>
|
||||
|
||||
@@ -5,3 +5,5 @@
|
||||
<% semantic_form_for [@project, @contract, setup_nested_deliverable_records(resource)], :url => contract_deliverable_path(@project, @contract, resource), :html => {:class => 'deliverable tabular'} do |form| %>
|
||||
<%= render :partial => 'form', :object => form, :locals => {:cancel_path => contract_path(@project, @contract)} %>
|
||||
<% end %>
|
||||
|
||||
<% html_title "#{l(:field_deliverable_plural)} - #{h(l(:text_edit_deliverable_title, :title => resource.title))}" %>
|
||||
|
||||
@@ -5,3 +5,5 @@
|
||||
<% semantic_form_for [@project, @contract, setup_nested_deliverable_records(resource)], :url => contract_deliverables_path(@project, @contract), :html => {:class => 'deliverable tabular'} do |form| %>
|
||||
<%= render :partial => 'form', :object => form, :locals => {:cancel_path => contract_path(@project, @contract)} %>
|
||||
<% end %>
|
||||
|
||||
<% html_title "#{l(:field_deliverable_plural)} - #{l(:text_new_deliverable)}" %>
|
||||
|
||||
@@ -13,14 +13,10 @@ en:
|
||||
field_discount: "Discount"
|
||||
field_discount_hint: "$, %"
|
||||
field_discount_note: "Discounts Notes"
|
||||
field_payment_terms: "Payment Terms"
|
||||
field_payment_term: "Payment Terms"
|
||||
field_client_ap_contact_information: "AP Contact Info"
|
||||
field_po_number: "PO Number"
|
||||
field_details: "Details"
|
||||
text_payment_terms_net_0: "Net 0"
|
||||
text_payment_terms_net_15: "Net 15"
|
||||
text_payment_terms_net_30: "Net 30"
|
||||
text_payment_terms_net_45: "Net 45"
|
||||
button_add_new: Add New
|
||||
text_new_deliverable: New Deliverable
|
||||
text_edit_deliverable_title: "Edit {{title}}"
|
||||
@@ -60,4 +56,7 @@ en:
|
||||
text_account_legend: "Account Management"
|
||||
text_deliverable_details_legend: "Deliverable Details"
|
||||
text_save_contract: "Save Contract"
|
||||
|
||||
enumeration_payment_term: "Payment Terms"
|
||||
field_deliverable_title: "Deliverable"
|
||||
field_contract_name: "Contract"
|
||||
field_contract: "Contract"
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
class AddPaymentTermIdToContracts < ActiveRecord::Migration
|
||||
def self.up
|
||||
add_column :contracts, :payment_term_id, :integer
|
||||
end
|
||||
|
||||
def self.down
|
||||
remove_column :contracts, :payment_term_id
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
class RemovePaymentTermsFromContracts < ActiveRecord::Migration
|
||||
def self.up
|
||||
remove_column :contracts, :payment_terms
|
||||
end
|
||||
|
||||
def self.down
|
||||
add_column :contracts, :payment_terms, :string
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,14 @@
|
||||
class PopulatePaymentTerms < ActiveRecord::Migration
|
||||
def self.up
|
||||
[0, 15, 30, 45, 60, 75, 90].each_with_index do |days, index|
|
||||
name = "Net #{days}"
|
||||
unless PaymentTerm.find_by_name(name)
|
||||
PaymentTerm.create!(:name => name, :position => index + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.down
|
||||
# No-op
|
||||
end
|
||||
end
|
||||
@@ -44,7 +44,6 @@ end
|
||||
|
||||
require 'dispatcher'
|
||||
Dispatcher.to_prepare :redmine_contracts do
|
||||
|
||||
gem 'inherited_resources', :version => '1.0.6'
|
||||
require_dependency 'inherited_resources'
|
||||
require_dependency 'inherited_resources/base'
|
||||
@@ -58,11 +57,25 @@ Dispatcher.to_prepare :redmine_contracts do
|
||||
|
||||
Formtastic::SemanticFormBuilder.all_fields_required_by_default = false
|
||||
Formtastic::SemanticFormBuilder.required_string = "<span class='required'> *</span>"
|
||||
|
||||
require_dependency 'payment_term' # Load so Enumeration will pick up the subclass in dev
|
||||
|
||||
require_dependency 'project'
|
||||
Project.send(:include, RedmineContracts::Patches::ProjectPatch)
|
||||
require_dependency 'issue'
|
||||
Issue.send(:include, RedmineContracts::Patches::IssuePatch)
|
||||
require_dependency 'query'
|
||||
unless Query.included_modules.include? RedmineContracts::Patches::QueryPatch
|
||||
Query.send(:include, RedmineContracts::Patches::QueryPatch)
|
||||
end
|
||||
|
||||
unless Query.available_columns.collect(&:name).include?(:deliverable_title)
|
||||
Query.add_available_column(QueryColumn.new(:deliverable_title, :sortable => "#{Deliverable.table_name}.title"))
|
||||
end
|
||||
|
||||
unless Query.available_columns.collect(&:name).include?(:contract_name)
|
||||
Query.add_available_column(QueryColumn.new(:contract_name, :sortable => "#{Contract.table_name}.name"))
|
||||
end
|
||||
end
|
||||
|
||||
require 'redmine_contracts/hooks/view_layouts_base_html_head_hook'
|
||||
@@ -72,3 +85,4 @@ require 'redmine_contracts/hooks/controller_issues_edit_before_save_hook'
|
||||
require 'redmine_contracts/hooks/view_issues_bulk_edit_details_bottom_hook'
|
||||
require 'redmine_contracts/hooks/controller_issues_bulk_edit_before_save_hook'
|
||||
require 'redmine_contracts/hooks/helper_issues_show_detail_after_setting_hook'
|
||||
require 'redmine_contracts/hooks/controller_timelog_available_criterias_hook'
|
||||
|
||||
@@ -29,7 +29,9 @@ module RedmineContracts
|
||||
end
|
||||
|
||||
# * old_data - YAML string of deliverables to migrate
|
||||
def self.migrate(old_data)
|
||||
def self.migrate(old_data, options={})
|
||||
@contract_rate = options[:contract_rate] ? options[:contract_rate].to_f : 150.0
|
||||
|
||||
@@data = YAML.load(old_data)
|
||||
|
||||
# Map old deliverable ids to the new ones
|
||||
@@ -43,31 +45,33 @@ module RedmineContracts
|
||||
:end_date => old_deliverable['due'],
|
||||
:notes => old_deliverable['description']
|
||||
)
|
||||
deliverable.type = old_deliverable['type']
|
||||
# All deliverables are converted over to FixedDeliverable
|
||||
deliverable.type = 'FixedDeliverable'
|
||||
project = Project.find(old_deliverable['project_id'])
|
||||
contract = Contract.find_by_project_id(project.id)
|
||||
contract ||= create_new_contract(old_deliverable)
|
||||
|
||||
deliverable.contract = contract
|
||||
deliverable.manager = project.users.first
|
||||
|
||||
deliverable.total = old_deliverable['budget']
|
||||
|
||||
case old_deliverable['type']
|
||||
when 'FixedDeliverable'
|
||||
@total = deliverable.total = old_deliverable['fixed_cost']
|
||||
@total_cost = old_deliverable['fixed_cost']
|
||||
when 'HourlyDeliverable'
|
||||
@total = old_deliverable['total_hours'].to_f * old_deliverable['cost_per_hour'].to_f
|
||||
@total_cost = old_deliverable['total_hours'].to_f * old_deliverable['cost_per_hour'].to_f
|
||||
|
||||
if old_deliverable['total_hours'].present? || old_deliverable['cost_per_hour'].present?
|
||||
deliverable.labor_budgets << LaborBudget.new(:deliverable => deliverable,
|
||||
:budget => @total,
|
||||
:budget => @total_cost,
|
||||
:hours => old_deliverable['total_hours'])
|
||||
end
|
||||
else
|
||||
@total = 0
|
||||
@total_cost = 0
|
||||
end
|
||||
|
||||
convert_overhead(deliverable, old_deliverable, @total)
|
||||
convert_materials(deliverable, old_deliverable, @total)
|
||||
convert_overhead(deliverable, old_deliverable, @total_cost)
|
||||
convert_materials(deliverable, old_deliverable, @total_cost)
|
||||
append_old_deliverable_to_notes(old_deliverable, deliverable)
|
||||
|
||||
deliverable.save!
|
||||
@@ -106,6 +110,7 @@ module RedmineContracts
|
||||
c.account_executive = project.users.first
|
||||
c.start_date ||= Date.today
|
||||
c.end_date ||= Date.today
|
||||
c.billable_rate = @contract_rate
|
||||
end
|
||||
|
||||
contract.save!
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
module RedmineContracts
|
||||
module Hooks
|
||||
class ControllerTimelogAvailableCriteriasHook < Redmine::Hook::ViewListener
|
||||
def controller_timelog_available_criterias(context={})
|
||||
context[:available_criterias]["deliverable_id"] = {
|
||||
:sql => "#{Issue.table_name}.deliverable_id",
|
||||
:klass => Deliverable,
|
||||
:label => :field_deliverable
|
||||
}
|
||||
context[:available_criterias]["contract_id"] = {
|
||||
:sql => "(SELECT deliverable.contract_id FROM #{Deliverable.table_name} deliverable WHERE deliverable.id = issues.deliverable_id)",
|
||||
:klass => Contract,
|
||||
:label => :field_contract
|
||||
}
|
||||
return ''
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -8,6 +8,9 @@ module RedmineContracts
|
||||
base.class_eval do
|
||||
unloadable
|
||||
belongs_to :deliverable
|
||||
|
||||
delegate :title, :to => :deliverable, :prefix => true, :allow_nil => true
|
||||
delegate :contract_name, :to => :deliverable, :allow_nil => true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ module RedmineContracts
|
||||
base.send(:include, InstanceMethods)
|
||||
base.class_eval do
|
||||
unloadable
|
||||
|
||||
has_many :contracts
|
||||
has_many :deliverables, :through => :contracts
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
module RedmineContracts
|
||||
module Patches
|
||||
module QueryPatch
|
||||
def self.included(base)
|
||||
base.extend(ClassMethods)
|
||||
|
||||
base.send(:include, InstanceMethods)
|
||||
base.class_eval do
|
||||
unloadable
|
||||
|
||||
alias_method_chain :available_filters, :deliverable
|
||||
alias_method_chain :available_filters, :contract
|
||||
|
||||
alias_method_chain :sql_for_field, :contract
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
# TODO: Should have an API on the Redmine core for this
|
||||
def available_filters_with_deliverable
|
||||
@available_filters = available_filters_without_deliverable
|
||||
|
||||
if project
|
||||
deliverable_filters = {
|
||||
"deliverable_id" => {
|
||||
:type => :list_optional,
|
||||
:order => 15,
|
||||
:values => project.deliverables.by_title.collect { |d| [d.title, d.id.to_s] }
|
||||
}
|
||||
}
|
||||
return @available_filters.merge(deliverable_filters)
|
||||
else
|
||||
return @available_filters
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# TODO: Should have an API on the Redmine core for this
|
||||
def available_filters_with_contract
|
||||
@available_filters = available_filters_without_contract
|
||||
|
||||
if project
|
||||
contract_filters = {
|
||||
"contract_id" => {
|
||||
:type => :list_optional,
|
||||
:order => 16,
|
||||
:values => project.contracts.by_name.collect { |d| [d.name, d.id.to_s] }
|
||||
}
|
||||
}
|
||||
return @available_filters.merge(contract_filters)
|
||||
else
|
||||
return @available_filters
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def sql_for_field_with_contract(field, operator, value, db_table, db_field, is_custom_filter=false)
|
||||
if field != "contract_id"
|
||||
return sql_for_field_without_contract(field, operator, value, db_table, db_field, is_custom_filter)
|
||||
else
|
||||
# Contracts > Deliverables > Issue
|
||||
case operator
|
||||
when "="
|
||||
contracts = value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",")
|
||||
inner_select = "(SELECT id from deliverables where deliverables.contract_id IN (#{contracts}))"
|
||||
sql = "#{Issue.table_name}.deliverable_id IN (#{inner_select})"
|
||||
when "!"
|
||||
contracts = value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",")
|
||||
inner_select = "(SELECT id from deliverables where deliverables.contract_id IN (#{contracts}))"
|
||||
sql = "(#{Issue.table_name}.deliverable_id IS NULL OR #{Issue.table_name}.deliverable_id NOT IN (#{inner_select}))"
|
||||
when "!*"
|
||||
# If it doesn't have a deliverable, it can't have a contract
|
||||
sql = "#{Issue.table_name}.deliverable_id IS NULL"
|
||||
when "*"
|
||||
# If it has a deliverable, it must have a contract
|
||||
sql = "#{Issue.table_name}.deliverable_id IS NOT NULL"
|
||||
end
|
||||
|
||||
return sql
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,10 +1,13 @@
|
||||
namespace :redmine_contracts do
|
||||
desc "Migrate data from the budget_plugin to redmine_contracts"
|
||||
task :budget_migration => :environment do
|
||||
options = {}
|
||||
options[:contract_rate] = ENV['contract_rate']
|
||||
|
||||
RedmineContracts::BudgetPluginMigration.check_for_installed_budget_plugin
|
||||
data = RedmineContracts::BudgetPluginMigration.export_data
|
||||
RedmineContracts::BudgetPluginMigration.rename_old_tables
|
||||
RedmineContracts::BudgetPluginMigration.migrate_contracts
|
||||
RedmineContracts::BudgetPluginMigration.migrate(data)
|
||||
RedmineContracts::BudgetPluginMigration.migrate(data, options)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -35,8 +35,8 @@ class BudgetPluginMigrationTest < ActionController::IntegrationTest
|
||||
should "create a new Deliverable for each old Deliverable" do
|
||||
|
||||
assert_difference("Deliverable.count", 3) do
|
||||
assert_difference("HourlyDeliverable.count", 2) do
|
||||
assert_difference("FixedDeliverable.count", 1) do
|
||||
assert_difference("HourlyDeliverable.count", 0) do
|
||||
assert_difference("FixedDeliverable.count", 3) do
|
||||
RedmineContracts::BudgetPluginMigration.migrate(@data)
|
||||
end
|
||||
end
|
||||
@@ -53,6 +53,22 @@ class BudgetPluginMigrationTest < ActionController::IntegrationTest
|
||||
assert_equal 2, @project_two.reload.contracts.first.deliverables.count
|
||||
end
|
||||
|
||||
context "on new Contracts" do
|
||||
should "default the contract billable rate to $150" do
|
||||
RedmineContracts::BudgetPluginMigration.migrate(@data)
|
||||
|
||||
assert_equal 150, @project_one.reload.contracts.first.billable_rate
|
||||
assert_equal 150, @project_two.reload.contracts.first.billable_rate
|
||||
end
|
||||
|
||||
should "allow overriding the contract billable rate" do
|
||||
RedmineContracts::BudgetPluginMigration.migrate(@data, :contract_rate => '100.50')
|
||||
|
||||
assert_equal 100.5, @project_one.reload.contracts.first.billable_rate
|
||||
assert_equal 100.5, @project_two.reload.contracts.first.billable_rate
|
||||
end
|
||||
end
|
||||
|
||||
should "enable the contracts plugin for each project with a contract" do
|
||||
@no_deliverables = Project.generate!(:enabled_modules => [])
|
||||
RedmineContracts::BudgetPluginMigration.migrate(@data)
|
||||
@@ -136,15 +152,28 @@ class BudgetPluginMigrationTest < ActionController::IntegrationTest
|
||||
end
|
||||
|
||||
context "converting Fixed Deliverables" do
|
||||
should "convert fixed_cost to total" do
|
||||
should "convert the budget field to total" do
|
||||
RedmineContracts::BudgetPluginMigration.migrate(@data)
|
||||
|
||||
d = FixedDeliverable.find_by_title("Version 1.0")
|
||||
assert_equal 30_000, d.total
|
||||
assert_equal 93_000, d.total
|
||||
end
|
||||
end
|
||||
|
||||
context "converting Hourly Deliverables" do
|
||||
should "convert over into Fixed Deliverables" do
|
||||
assert_difference("FixedDeliverable.count",3) do
|
||||
RedmineContracts::BudgetPluginMigration.migrate(@data)
|
||||
end
|
||||
end
|
||||
|
||||
should "convert the old 'budget' field into the total" do
|
||||
RedmineContracts::BudgetPluginMigration.migrate(@data)
|
||||
|
||||
assert_equal 5600, FixedDeliverable.find_by_title("Deliverable One").total
|
||||
assert_equal 900, FixedDeliverable.find_by_title("Deliverable 2").total
|
||||
end
|
||||
|
||||
should "create a new Labor Budget" do
|
||||
assert_difference("LaborBudget.count", 2) do
|
||||
RedmineContracts::BudgetPluginMigration.migrate(@data)
|
||||
|
||||
@@ -5,7 +5,7 @@ class ContractsDeleteTest < ActionController::IntegrationTest
|
||||
|
||||
def setup
|
||||
@project = Project.generate!(:identifier => 'main')
|
||||
@contract = Contract.generate!(:project => @project, :name => 'A Contract', :payment_terms => 'net_15')
|
||||
@contract = Contract.generate!(:project => @project, :name => 'A Contract')
|
||||
end
|
||||
|
||||
should "allow admins to delete the contract" do
|
||||
|
||||
@@ -8,7 +8,7 @@ class ContractsEditTest < ActionController::IntegrationTest
|
||||
@account_executive = User.generate!
|
||||
@role = Role.generate!
|
||||
User.add_to_project(@account_executive, @project, @role)
|
||||
@contract = Contract.generate!(:project => @project, :name => 'A Contract', :payment_terms => 'net_15', :account_executive => @account_executive)
|
||||
@contract = Contract.generate!(:project => @project, :name => 'A Contract', :account_executive => @account_executive)
|
||||
end
|
||||
|
||||
should "allow any user to edit the contract" do
|
||||
@@ -23,9 +23,7 @@ class ContractsEditTest < ActionController::IntegrationTest
|
||||
assert_select "h2", :text => /#{@contract.name}/
|
||||
assert_select "form#edit_contract_#{@contract.id}.contract" do
|
||||
assert_select "input[value=?]", /#{@contract.name}/
|
||||
assert_select "select#contract_payment_terms" do
|
||||
assert_select "option[selected=selected][value=net_15]"
|
||||
end
|
||||
assert_select "select#contract_payment_term_id"
|
||||
end
|
||||
|
||||
fill_in "Name", :with => 'An updated name'
|
||||
|
||||
@@ -5,6 +5,8 @@ class ContractsNewTest < ActionController::IntegrationTest
|
||||
|
||||
def setup
|
||||
@project = Project.generate!(:identifier => 'main')
|
||||
PaymentTerm.generate!(:type => 'PaymentTerm', :name => 'Net 15')
|
||||
PaymentTerm.generate!(:type => 'PaymentTerm', :name => 'Net 30')
|
||||
end
|
||||
|
||||
should "allow any user to open the new contracts form" do
|
||||
@@ -40,7 +42,7 @@ class ContractsNewTest < ActionController::IntegrationTest
|
||||
assert_equal @account_executive, @contract.account_executive
|
||||
assert_equal '2010-01-01', @contract.start_date.to_s
|
||||
assert_equal '2010-12-31', @contract.end_date.to_s
|
||||
assert_equal 'net_30', @contract.payment_terms
|
||||
assert_equal 'Net 30', @contract.payment_term.name
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -119,7 +119,7 @@ class ContractsShowTest < ActionController::IntegrationTest
|
||||
|
||||
visit_contract_page(@contract)
|
||||
assert_select "table#deliverables" do
|
||||
assert_select "td.labor", :text => /4,200.50/
|
||||
assert_select "td.labor", :text => /4,201/
|
||||
end
|
||||
|
||||
end
|
||||
@@ -137,7 +137,7 @@ class ContractsShowTest < ActionController::IntegrationTest
|
||||
|
||||
visit_contract_page(@contract)
|
||||
assert_select "table#deliverables" do
|
||||
assert_select "td.overhead", :text => /4,200.50/
|
||||
assert_select "td.overhead", :text => /4,201/
|
||||
end
|
||||
|
||||
end
|
||||
@@ -171,7 +171,7 @@ class ContractsShowTest < ActionController::IntegrationTest
|
||||
|
||||
visit_contract_page(@contract)
|
||||
assert_select "table#deliverables" do
|
||||
assert_select "td.labor", :text => /1,000.00/
|
||||
assert_select "td.labor", :text => /1,000/
|
||||
end
|
||||
|
||||
end
|
||||
@@ -205,7 +205,7 @@ class ContractsShowTest < ActionController::IntegrationTest
|
||||
|
||||
visit_contract_page(@contract)
|
||||
assert_select "table#deliverables" do
|
||||
assert_select "td.overhead", :text => /2,000.00/
|
||||
assert_select "td.overhead", :text => /2,000/
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -5,7 +5,7 @@ class DeliverablesDeleteTest < ActionController::IntegrationTest
|
||||
|
||||
def setup
|
||||
@project = Project.generate!(:identifier => 'main')
|
||||
@contract = Contract.generate!(:project => @project, :name => 'A Contract', :payment_terms => 'net_15')
|
||||
@contract = Contract.generate!(:project => @project, :name => 'A Contract')
|
||||
@manager = User.generate!
|
||||
@deliverable = FixedDeliverable.generate!(:contract => @contract, :manager => @manager)
|
||||
end
|
||||
|
||||
@@ -5,7 +5,7 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
||||
|
||||
def setup
|
||||
@project = Project.generate!(:identifier => 'main')
|
||||
@contract = Contract.generate!(:project => @project, :name => 'A Contract', :payment_terms => 'net_15')
|
||||
@contract = Contract.generate!(:project => @project, :name => 'A Contract')
|
||||
@manager = User.generate!
|
||||
@role = Role.generate!
|
||||
User.add_to_project(@manager, @project, @role)
|
||||
|
||||
@@ -3,7 +3,7 @@ require 'test_helper'
|
||||
class OverheadPluginIntegrationTest < ActionController::IntegrationTest
|
||||
def setup
|
||||
@project = Project.generate!(:identifier => 'main')
|
||||
@contract = Contract.generate!(:project => @project, :name => 'A Contract', :payment_terms => 'net_15')
|
||||
@contract = Contract.generate!(:project => @project, :name => 'A Contract')
|
||||
@manager = User.generate!
|
||||
@role = Role.generate!
|
||||
User.add_to_project(@manager, @project, @role)
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
require 'test_helper'
|
||||
require 'performance_test_help'
|
||||
|
||||
# Performance logs
|
||||
#
|
||||
class ContractShowTest < ActionController::PerformanceTest
|
||||
def setup
|
||||
@project = Project.generate!(:identifier => 'main').reload
|
||||
@contract = Contract.generate!(:project => @project)
|
||||
@manager = User.generate!(:login => 'user', :password => 'password', :password_confirmation => 'password')
|
||||
@role = Role.generate!
|
||||
User.add_to_project(@manager, @project, @role)
|
||||
@fixed_deliverable = FixedDeliverable.generate!(:contract => @contract, :manager => @manager, :title => 'The Title')
|
||||
@hourly_deliverable = HourlyDeliverable.generate!(:contract => @contract, :manager => @manager, :title => 'An Hourly')
|
||||
|
||||
configure_overhead_plugin
|
||||
100.times do
|
||||
generate_issues_and_time_entries_for_deliverable(@hourly_deliverable, @project)
|
||||
generate_issues_and_time_entries_for_deliverable(@fixed_deliverable, @project)
|
||||
end
|
||||
|
||||
# Load the app
|
||||
login_as 'user', 'password'
|
||||
visit_contracts_for_project(@project)
|
||||
end
|
||||
|
||||
def test_contract_show
|
||||
click_link @contract.id
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_issues_and_time_entries_for_deliverable(deliverable, project)
|
||||
@issue1 = Issue.generate_for_project!(project)
|
||||
@time_entry1 = TimeEntry.generate!(:issue => @issue1,
|
||||
:project => project,
|
||||
:activity => @billable_activity,
|
||||
:spent_on => Date.today,
|
||||
:hours => 10,
|
||||
:user => @manager)
|
||||
@time_entry2 = TimeEntry.generate!(:issue => @issue1,
|
||||
:project => project,
|
||||
:activity => @non_billable_activity,
|
||||
:spent_on => Date.today,
|
||||
:hours => 20,
|
||||
:user => @manager)
|
||||
deliverable.issues << @issue1
|
||||
|
||||
end
|
||||
end
|
||||
@@ -3,6 +3,7 @@ require File.dirname(__FILE__) + '/../test_helper'
|
||||
class ContractTest < ActiveSupport::TestCase
|
||||
should_belong_to :account_executive
|
||||
should_belong_to :project
|
||||
should_belong_to :payment_term
|
||||
should_have_many :deliverables
|
||||
|
||||
should_validate_presence_of :name
|
||||
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
require File.dirname(__FILE__) + '/../../../../test_helper'
|
||||
|
||||
class RedmineContracts::Hooks::ControllerTimelogAvailableCriteriasTest < ActionController::TestCase
|
||||
include Redmine::Hook::Helper
|
||||
|
||||
def controller
|
||||
@controller ||= ApplicationController.new
|
||||
@controller.response ||= ActionController::TestResponse.new
|
||||
@controller
|
||||
end
|
||||
|
||||
def request
|
||||
@request ||= ActionController::TestRequest.new
|
||||
end
|
||||
|
||||
def hook(args={})
|
||||
call_hook :controller_timelog_available_criterias, args
|
||||
end
|
||||
|
||||
def context
|
||||
@context ||= {
|
||||
:available_criterias => {"existing" => {:label => 'existing'}}
|
||||
}
|
||||
end
|
||||
|
||||
context "#controller_timelog_available_criterias" do
|
||||
should "return an empty string" do
|
||||
@response.body = hook(context)
|
||||
assert @response.body.blank?
|
||||
end
|
||||
|
||||
context "Deliverables" do
|
||||
should "add a deliverable_id to the available criterias" do
|
||||
@response.body = hook(context)
|
||||
assert context[:available_criterias]['deliverable_id']
|
||||
end
|
||||
|
||||
should "add the deliverable sql to the available criterias" do
|
||||
@response.body = hook(context)
|
||||
assert "issues.deliverable_id", context[:available_criterias]['deliverable_id'][:sql]
|
||||
end
|
||||
|
||||
should "add the deliverable Class to the available criterias" do
|
||||
@response.body = hook(context)
|
||||
assert Deliverable, context[:available_criterias]['deliverable_id'][:klass]
|
||||
end
|
||||
|
||||
should "add the deliverable label to the available criterias" do
|
||||
@response.body = hook(context)
|
||||
assert :field_deliverable, context[:available_criterias]['deliverable_id'][:label]
|
||||
end
|
||||
end
|
||||
|
||||
context "Contracts" do
|
||||
should "add a contract_id to the available criterias" do
|
||||
@response.body = hook(context)
|
||||
assert context[:available_criterias]['contract_id']
|
||||
end
|
||||
|
||||
should "add the contact sql to the available criterias" do
|
||||
@response.body = hook(context)
|
||||
assert "issues.deliverable_id", context[:available_criterias]['contract_id'][:sql]
|
||||
end
|
||||
|
||||
should "add the deliverable Class to the available criterias" do
|
||||
@response.body = hook(context)
|
||||
assert Contract, context[:available_criterias]['contract_id'][:klass]
|
||||
end
|
||||
|
||||
should "add the deliverable label to the available criterias" do
|
||||
@response.body = hook(context)
|
||||
assert :field_contract, context[:available_criterias]['contract_id'][:label]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -5,5 +5,6 @@ class RedmineContracts::Patches::ProjectTest < ActionController::TestCase
|
||||
context "Project" do
|
||||
subject { Project.new }
|
||||
should_have_many :contracts
|
||||
should_have_many :deliverables
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
require File.dirname(__FILE__) + '/../../../../test_helper'
|
||||
|
||||
class RedmineContracts::Patches::QueryTest < ActionController::TestCase
|
||||
|
||||
context "Query" do
|
||||
subject {Query.new}
|
||||
|
||||
context "#available_filters with project" do
|
||||
setup do
|
||||
@query = Query.new
|
||||
@query.project = @project = Project.generate!
|
||||
@contract = Contract.generate!(:project => @project, :name => 'A Contract')
|
||||
@manager = User.generate!
|
||||
@deliverable1 = FixedDeliverable.generate!(:contract => @contract, :manager => @manager, :title => 'One')
|
||||
@deliverable2 = FixedDeliverable.generate!(:contract => @contract, :manager => @manager, :title => 'Two')
|
||||
end
|
||||
|
||||
should "add a deliverable_id filter" do
|
||||
filters = @query.available_filters
|
||||
|
||||
assert filters.keys.include?("deliverable_id")
|
||||
|
||||
deliverable_filter = filters["deliverable_id"]
|
||||
assert_equal :list_optional, deliverable_filter[:type]
|
||||
assert_equal [
|
||||
["One", @deliverable1.id.to_s],
|
||||
["Two", @deliverable2.id.to_s]
|
||||
], deliverable_filter[:values]
|
||||
end
|
||||
|
||||
should "add a contract_id filter" do
|
||||
filters = @query.available_filters
|
||||
|
||||
assert filters.keys.include?("contract_id")
|
||||
|
||||
contract_filter = filters["contract_id"]
|
||||
assert_equal :list_optional, contract_filter[:type]
|
||||
assert_equal [["A Contract", @contract.id.to_s]], contract_filter[:values]
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: Dragons in this test
|
||||
context "#sql_for_field_with_contract" do
|
||||
context "for contract_id fields" do
|
||||
setup do
|
||||
@query = Query.new
|
||||
end
|
||||
|
||||
context "with the equal operator" do
|
||||
should "return the SQL snippet for checking for deliverables on the specific contracts" do
|
||||
sql = @query.send(:sql_for_field, 'contract_id', '=', ['1','2'], '', '')
|
||||
assert_equal "issues.deliverable_id IN ((SELECT id from deliverables where deliverables.contract_id IN ('1','2')))", sql
|
||||
end
|
||||
end
|
||||
|
||||
context "with is not operator" do
|
||||
should "return the SQL snippet for checking for null deliverables or deliverables no on the specific contracts" do
|
||||
sql = @query.send(:sql_for_field, 'contract_id', '!', ['1','2'], '', '')
|
||||
assert_equal "(issues.deliverable_id IS NULL OR issues.deliverable_id NOT IN ((SELECT id from deliverables where deliverables.contract_id IN ('1','2'))))", sql
|
||||
end
|
||||
end
|
||||
|
||||
context "with none operator" do
|
||||
should "return the SQL snippet for checking for null deliverables" do
|
||||
sql = @query.send(:sql_for_field, 'contract_id', '!*', '', '', '')
|
||||
assert_equal "issues.deliverable_id IS NULL", sql
|
||||
end
|
||||
end
|
||||
|
||||
context "with all operator" do
|
||||
should "return the SQL snippet for checking for not null deliverables" do
|
||||
sql = @query.send(:sql_for_field, 'contract_id', '*', '', '', '')
|
||||
assert_equal "issues.deliverable_id IS NOT NULL", sql
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,40 @@
|
||||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
|
||||
class PaymentTermTest < ActiveSupport::TestCase
|
||||
include Redmine::I18n
|
||||
|
||||
should_have_many(:contracts)
|
||||
|
||||
should "be a subclass of Enumeration" do
|
||||
assert_equal Enumeration, PaymentTerm.superclass
|
||||
end
|
||||
|
||||
context "#option_name" do
|
||||
should "be Payment Terms" do
|
||||
assert_equal "Payment Terms", l(PaymentTerm.new.option_name)
|
||||
end
|
||||
end
|
||||
|
||||
context "#objects_count" do
|
||||
should "count the number of contracts with this payment term" do
|
||||
@payment_term = PaymentTerm.generate!(:type => 'PaymentTerm')
|
||||
Contract.generate!(:payment_term => @payment_term)
|
||||
Contract.generate!(:payment_term => @payment_term)
|
||||
|
||||
assert_equal 2, @payment_term.objects_count
|
||||
end
|
||||
end
|
||||
|
||||
context "#transfer_relations" do
|
||||
should "update all contracts to use a new PaymentTerm" do
|
||||
@old_payment_term = PaymentTerm.generate!(:type => 'PaymentTerm')
|
||||
@new_payment_term = PaymentTerm.generate!(:type => 'PaymentTerm')
|
||||
@contract1 = Contract.generate!(:payment_term => @old_payment_term)
|
||||
@contract2 = Contract.generate!(:payment_term => @old_payment_term)
|
||||
|
||||
@old_payment_term.transfer_relations(@new_payment_term)
|
||||
assert_equal @new_payment_term, @contract1.reload.payment_term
|
||||
assert_equal @new_payment_term, @contract2.reload.payment_term
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user