Merge branch '4477-fixed-expenses'
This commit is contained in:
@@ -3,6 +3,7 @@ module ContractsHelper
|
||||
returning(deliverable) do |d|
|
||||
d.labor_budgets.build if d.labor_budgets.empty?
|
||||
d.overhead_budgets.build if d.overhead_budgets.empty?
|
||||
d.fixed_budgets.build if d.fixed_budgets.empty?
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
+20
-2
@@ -36,8 +36,6 @@ class Contract < ActiveRecord::Base
|
||||
named_scope :by_name, {:order => "#{Contract.table_name}.name ASC"}
|
||||
|
||||
[:status, :contract_type,
|
||||
:fixed_spent, :fixed_budget,
|
||||
:markup_spent, :markup_budget,
|
||||
:discount_spent, :discount_budget
|
||||
].each do |mthd|
|
||||
define_method(mthd) { "TODO in later release" }
|
||||
@@ -96,6 +94,26 @@ class Contract < ActiveRecord::Base
|
||||
end
|
||||
alias_method :profit_spent, :profit_left
|
||||
|
||||
# OPTIMIZE: N+1
|
||||
def fixed_budget
|
||||
deliverables.inject(0) {|total, deliverable| total += deliverable.fixed_budget_total }
|
||||
end
|
||||
|
||||
# OPTIMIZE: N+1
|
||||
def fixed_spent
|
||||
deliverables.inject(0) {|total, deliverable| total += deliverable.fixed_budget_total_spent }
|
||||
end
|
||||
|
||||
# OPTIMIZE: N+1
|
||||
def fixed_markup_budget
|
||||
deliverables.inject(0) {|total, deliverable| total += deliverable.fixed_markup_budget_total }
|
||||
end
|
||||
|
||||
# OPTIMIZE: N+1
|
||||
def fixed_markup_spent
|
||||
deliverables.inject(0) {|total, deliverable| total += deliverable.fixed_markup_budget_total_spent }
|
||||
end
|
||||
|
||||
def after_initialize
|
||||
self.executed = false unless self.executed.present?
|
||||
end
|
||||
|
||||
@@ -8,10 +8,12 @@ class Deliverable < ActiveRecord::Base
|
||||
belongs_to :manager, :class_name => 'User', :foreign_key => 'manager_id'
|
||||
has_many :labor_budgets
|
||||
has_many :overhead_budgets
|
||||
has_many :fixed_budgets
|
||||
has_many :issues
|
||||
|
||||
accepts_nested_attributes_for :labor_budgets
|
||||
accepts_nested_attributes_for :overhead_budgets
|
||||
accepts_nested_attributes_for :fixed_budgets
|
||||
|
||||
# Validations
|
||||
validates_presence_of :title
|
||||
@@ -86,6 +88,24 @@ class Deliverable < ActiveRecord::Base
|
||||
issues.inject(0) {|total, issue| total += issue.spent_hours }
|
||||
end
|
||||
|
||||
def fixed_budget_total(date=nil)
|
||||
fixed_budgets.sum(:budget)
|
||||
end
|
||||
|
||||
def fixed_budget_total_spent(date=nil)
|
||||
fixed_budgets.paid.sum(:budget)
|
||||
end
|
||||
|
||||
# OPTIMIZE: N+1
|
||||
def fixed_markup_budget_total(date=nil)
|
||||
fixed_budgets.inject(0) {|total, fixed_budget| total += fixed_budget.markup_value }
|
||||
end
|
||||
|
||||
# OPTIMIZE: N+1
|
||||
def fixed_markup_budget_total_spent(date=nil)
|
||||
fixed_budgets.paid.inject(0) {|total, fixed_budget| total += fixed_budget.markup_value }
|
||||
end
|
||||
|
||||
def filter_by_date(date=nil, &block)
|
||||
block.call
|
||||
end
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
class FixedBudget < ActiveRecord::Base
|
||||
unloadable
|
||||
|
||||
# Associations
|
||||
belongs_to :deliverable
|
||||
|
||||
# Validations
|
||||
|
||||
# Accessors
|
||||
def budget=(v)
|
||||
if v.is_a? String
|
||||
write_attribute(:budget, v.gsub(/[$ ,]/, ''))
|
||||
else
|
||||
write_attribute(:budget, v)
|
||||
end
|
||||
end
|
||||
|
||||
named_scope :by_period, lambda {|date|
|
||||
if date
|
||||
{
|
||||
:conditions => {:year => date.year, :month => date.month}
|
||||
}
|
||||
end
|
||||
}
|
||||
|
||||
named_scope :paid, {:conditions => {:paid => true}}
|
||||
|
||||
def markup_value
|
||||
return 0 if budget.blank? || markup.blank?
|
||||
|
||||
case
|
||||
when percent_markup?
|
||||
percent = markup.gsub('%','').to_f
|
||||
return budget.to_f * (percent / 100)
|
||||
when straight_markup?
|
||||
markup.gsub('$','').gsub(',','').to_f
|
||||
else
|
||||
0 # Invalid markup
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def budget_spent
|
||||
if paid?
|
||||
budget
|
||||
else
|
||||
0
|
||||
end
|
||||
end
|
||||
|
||||
def percent_markup?
|
||||
markup && markup.match(/%/)
|
||||
end
|
||||
|
||||
def straight_markup?
|
||||
markup && markup.match(/\$/)
|
||||
end
|
||||
|
||||
# Is this a blank budget item. Retainers will create blank ones when
|
||||
# they are copied. (RetainerDeliverable#create_budgets_for_periods)
|
||||
def blank_record?
|
||||
return true if new_record?
|
||||
return title.blank? && budget.blank? && markup.blank?
|
||||
end
|
||||
end
|
||||
@@ -23,14 +23,14 @@ class FixedDeliverable < Deliverable
|
||||
# The amount of profit that is budgeted for this deliverable.
|
||||
# Profit = Total - ( Labor + Overhead + Fixed + Markup )
|
||||
def profit_budget(date=nil)
|
||||
budgets = labor_budget_total(date) + overhead_budget_total(date)
|
||||
budgets = labor_budget_total(date) + overhead_budget_total(date) + fixed_budget_total(date) + fixed_markup_budget_total(date)
|
||||
(total(date) || 0.0) - budgets
|
||||
end
|
||||
|
||||
# The amount of money remaining after expenses have been taken out
|
||||
# Profit left = Total - Labor spent - Overhead spent
|
||||
# Profit left = Total - Labor spent - Overhead spent - Fixed - Markup
|
||||
def profit_left(date=nil)
|
||||
total_spent(date) - labor_budget_spent(date) - overhead_spent(date)
|
||||
total_spent(date) - labor_budget_spent(date) - overhead_spent(date) - fixed_budget_total_spent(date) - fixed_markup_budget_total_spent(date)
|
||||
end
|
||||
|
||||
# Hardcoded value used as a wrapper for the old Budget plugin API.
|
||||
|
||||
@@ -14,12 +14,14 @@ class HourlyDeliverable < Deliverable
|
||||
'H'
|
||||
end
|
||||
|
||||
# Total = ( Labor Hours * Billing Rate ) + ( Fixed + Markup )
|
||||
def total(date=nil)
|
||||
return 0 if contract.nil?
|
||||
return 0 if contract.billable_rate.blank?
|
||||
return 0 if labor_budgets.count == 0 && overhead_budgets.count == 0
|
||||
|
||||
return contract.billable_rate * labor_budget_hours(date)
|
||||
fixed_budget_amount = fixed_budget_total(date) + fixed_markup_budget_total(date)
|
||||
return (contract.billable_rate * labor_budget_hours(date)) + fixed_budget_amount
|
||||
end
|
||||
|
||||
# Total amount to be billed on the deliverable, using the total time logged
|
||||
@@ -50,13 +52,13 @@ class HourlyDeliverable < Deliverable
|
||||
# The amount of profit that is budgeted for this deliverable
|
||||
# Profit = Total - ( Labor + Overhead + Fixed + Markup )
|
||||
def profit_budget(date=nil)
|
||||
budgets = labor_budget_total(date) + overhead_budget_total(date)
|
||||
budgets = labor_budget_total(date) + overhead_budget_total(date) + fixed_budget_total(date) + fixed_markup_budget_total(date)
|
||||
(total(date) || 0.0) - budgets
|
||||
end
|
||||
|
||||
# The amount of money remaining after expenses have been taken out
|
||||
# Profit left = Total - Labor spent - Overhead spent
|
||||
# Profit left = Total - Labor spent - Overhead spent - Fixed - Markup
|
||||
def profit_left(date=nil)
|
||||
total_spent(date) - labor_budget_spent(date) - overhead_spent(date)
|
||||
total_spent(date) - labor_budget_spent(date) - overhead_spent(date) - fixed_budget_total_spent(date) - fixed_markup_budget_total_spent(date)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -94,6 +94,12 @@ class RetainerDeliverable < HourlyDeliverable
|
||||
budgets
|
||||
end
|
||||
|
||||
def fixed_budgets_for_date(date)
|
||||
budgets = fixed_budgets.all(:conditions => {:year => date.year, :month => date.month})
|
||||
budgets = [fixed_budgets.build(:year => date.year, :month => date.month)] if budgets.empty?
|
||||
budgets
|
||||
end
|
||||
|
||||
def labor_budget_total(date=nil)
|
||||
case scope_date_status(date)
|
||||
when :in
|
||||
@@ -127,6 +133,55 @@ class RetainerDeliverable < HourlyDeliverable
|
||||
end
|
||||
end
|
||||
|
||||
def fixed_budget_total(date=nil)
|
||||
case scope_date_status(date)
|
||||
when :in
|
||||
fixed_budgets.sum(:budget, :conditions => {:year => date.year, :month => date.month})
|
||||
when :out
|
||||
0
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def fixed_budget_total_spent(date=nil)
|
||||
case scope_date_status(date)
|
||||
when :in
|
||||
fixed_budgets.paid.sum(:budget, :conditions => {:year => date.year, :month => date.month})
|
||||
when :out
|
||||
0
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def fixed_markup_budget_total(date=nil)
|
||||
case scope_date_status(date)
|
||||
when :in
|
||||
fixed_budgets.
|
||||
all(:conditions => {:year => date.year, :month => date.month}).
|
||||
inject(0) {|total, fixed_budget| total += fixed_budget.markup_value }
|
||||
when :out
|
||||
0
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def fixed_markup_budget_total_spent(date=nil)
|
||||
case scope_date_status(date)
|
||||
when :in
|
||||
fixed_budgets.
|
||||
paid.
|
||||
all(:conditions => {:year => date.year, :month => date.month}).
|
||||
inject(0) {|total, fixed_budget| total += fixed_budget.markup_value }
|
||||
when :out
|
||||
0
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def total_spent(date=nil)
|
||||
case scope_date_status(date)
|
||||
when :in
|
||||
@@ -231,10 +286,16 @@ class RetainerDeliverable < HourlyDeliverable
|
||||
undated_overhead_budgets.each do |template_budget|
|
||||
overhead_budgets.create(template_budget.attributes.merge(:year => month.year, :month => month.month))
|
||||
end
|
||||
|
||||
undated_fixed_budgets = fixed_budgets.all(:conditions => ["#{FixedBudget.table_name}.year IS NULL AND #{FixedBudget.table_name}.month IS NULL"])
|
||||
undated_fixed_budgets.each do |template_budget|
|
||||
fixed_budgets.create(template_budget.attributes.merge(:year => month.year, :month => month.month))
|
||||
end
|
||||
end
|
||||
# Destroy origional un-dated budgets
|
||||
labor_budgets.all(:conditions => ["#{LaborBudget.table_name}.year IS NULL AND #{LaborBudget.table_name}.month IS NULL"]).collect(&:destroy)
|
||||
overhead_budgets.all(:conditions => ["#{OverheadBudget.table_name}.year IS NULL AND #{OverheadBudget.table_name}.month IS NULL"]).collect(&:destroy)
|
||||
fixed_budgets.all(:conditions => ["#{FixedBudget.table_name}.year IS NULL AND #{FixedBudget.table_name}.month IS NULL"]).collect(&:destroy)
|
||||
end
|
||||
|
||||
def check_for_extended_period
|
||||
@@ -281,6 +342,17 @@ class RetainerDeliverable < HourlyDeliverable
|
||||
end
|
||||
end
|
||||
|
||||
fixed_budgets.all.each do |fixed_budget|
|
||||
# Purge un-dated budgets, should not be saved at all
|
||||
fixed_budget.destroy unless fixed_budget.year.present?
|
||||
fixed_budget.destroy unless fixed_budget.month.present?
|
||||
|
||||
# Purge budgets outside the new beginning/ending range
|
||||
unless (beginning_date..ending_date).to_a.include?(Date.new(fixed_budget.year, fixed_budget.month, 1))
|
||||
fixed_budget.destroy
|
||||
end
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
@@ -290,9 +362,10 @@ class RetainerDeliverable < HourlyDeliverable
|
||||
old_end_date = end_date_change[0]
|
||||
last_labor_budgets = labor_budgets.all(:conditions => {:year => old_end_date.year, :month => old_end_date.month})
|
||||
last_overhead_budgets = overhead_budgets.all(:conditions => {:year => old_end_date.year, :month => old_end_date.month})
|
||||
|
||||
last_fixed_budgets = fixed_budgets.all(:conditions => {:year => old_end_date.year, :month => old_end_date.month})
|
||||
|
||||
months_after_date(old_end_date.end_of_month.to_date).each do |new_period|
|
||||
create_budgets_for_new_period(new_period, last_labor_budgets, last_overhead_budgets)
|
||||
create_budgets_for_new_period(new_period, last_labor_budgets, last_overhead_budgets, last_fixed_budgets)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -302,14 +375,15 @@ class RetainerDeliverable < HourlyDeliverable
|
||||
old_start_date = start_date_change[0]
|
||||
first_labor_budgets = labor_budgets.all(:conditions => {:year => old_start_date.year, :month => old_start_date.month})
|
||||
first_overhead_budgets = overhead_budgets.all(:conditions => {:year => old_start_date.year, :month => old_start_date.month})
|
||||
first_fixed_budgets = fixed_budgets.all(:conditions => {:year => old_start_date.year, :month => old_start_date.month})
|
||||
|
||||
months_before_date(old_start_date.beginning_of_month.to_date).each do |new_period|
|
||||
create_budgets_for_new_period(new_period, first_labor_budgets, first_overhead_budgets)
|
||||
create_budgets_for_new_period(new_period, first_labor_budgets, first_overhead_budgets, first_fixed_budgets)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def create_budgets_for_new_period(new_period, labor_budgets_to_copy, overhead_budgets_to_copy)
|
||||
def create_budgets_for_new_period(new_period, labor_budgets_to_copy, overhead_budgets_to_copy, fixed_budgets_to_copy)
|
||||
labor_budgets_to_copy.each do |labor_budget_to_copy|
|
||||
create_new_labor_budget_based_on_existing_budget(labor_budget_to_copy, 'year' => new_period.year, 'month' => new_period.month)
|
||||
end
|
||||
@@ -317,6 +391,10 @@ class RetainerDeliverable < HourlyDeliverable
|
||||
overhead_budgets_to_copy.each do |overhead_budget_to_copy|
|
||||
create_new_overhead_budget_based_on_existing_budget(overhead_budget_to_copy, 'year' => new_period.year, 'month' => new_period.month)
|
||||
end
|
||||
|
||||
fixed_budgets_to_copy.each do |fixed_budget_to_copy|
|
||||
create_new_fixed_budget_based_on_existing_budget(fixed_budget_to_copy, 'year' => new_period.year, 'month' => new_period.month)
|
||||
end
|
||||
end
|
||||
|
||||
def create_new_labor_budget_based_on_existing_budget(existing_labor_budget, attributes={})
|
||||
@@ -327,6 +405,10 @@ class RetainerDeliverable < HourlyDeliverable
|
||||
overhead_budgets.create(existing_overhead_budget.attributes.except('id').merge(attributes))
|
||||
end
|
||||
|
||||
def create_new_fixed_budget_based_on_existing_budget(existing_fixed_budget, attributes={})
|
||||
fixed_budgets.create(existing_fixed_budget.attributes.except('id').merge(attributes))
|
||||
end
|
||||
|
||||
def scope_date_status(date)
|
||||
if date
|
||||
if within_date_range?(date)
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<%= 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, :fixed_markup_spent, :fixed_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'}) %>
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
<td width="15%" class="manager"><%= h deliverable.manager.try(:name) %></td>
|
||||
<%= format_budget_for_deliverable(deliverable, deliverable.labor_budget_spent, deliverable.labor_budget_total, :class => 'labor') %>
|
||||
<%= format_budget_for_deliverable(deliverable, deliverable.overhead_spent, deliverable.overhead_budget_total, :class => 'overhead') %>
|
||||
<%= format_budget_for_deliverable(deliverable, 0, 0) %><%# TODO: Release 2, Fixed Budgets %>
|
||||
<%= format_budget_for_deliverable(deliverable, deliverable.fixed_budget_total_spent, deliverable.fixed_budget_total, :class => 'fixed') %>
|
||||
<% end %>
|
||||
|
||||
<tr id="deliverable_details_<%= h(deliverable.id) %>" class="ign">
|
||||
|
||||
@@ -62,8 +62,24 @@
|
||||
<td class="overhead_budget_total"><%= h(format_value_field_for_contracts(deliverable.overhead_budget_total(validated_period))) %></td>
|
||||
<td> TODO: Release 2 / TODO hrs </td>
|
||||
</tr>
|
||||
<%# TODO: Release 2, Fixed %>
|
||||
<%# TODO: Release 2, Markup %>
|
||||
|
||||
<% deliverable.fixed_budgets.by_period(period).each do |fixed_budget| %>
|
||||
<% next if fixed_budget.blank_record? %>
|
||||
<tr id="fixed_budget_<%= fixed_budget.id %>">
|
||||
<td class="l fixed_title" title="<%= h(fixed_budget.description) %>"><%= h(fixed_budget.title) %></td>
|
||||
<td class="fixed_budget_spent"><%= h(format_value_field_for_contracts(fixed_budget.budget_spent)) %></td>
|
||||
<td class="fixed_budget_total"><%= h(format_value_field_for_contracts(fixed_budget.budget)) %></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
||||
<tr>
|
||||
<td class="l"><%= l(:field_markup) %></td>
|
||||
<td class="fixed_markup_budget_spent"><%= h(format_value_field_for_contracts(deliverable.fixed_markup_budget_total_spent(period))) %></td>
|
||||
<td class="fixed_markup_budget_total"><%= h(format_value_field_for_contracts(deliverable.fixed_markup_budget_total(period))) %></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="l">Profit</td>
|
||||
<td><%= h(format_value_field_for_contracts(deliverable.profit_left(validated_period))) %></td>
|
||||
|
||||
@@ -62,6 +62,46 @@
|
||||
</table>
|
||||
</li>
|
||||
|
||||
<li class="numeric optional">
|
||||
<div id="deliverable-fixed" class="fixed-item-form">
|
||||
<label for="contract_discount">Fixed</label>
|
||||
|
||||
<% form.fields_for :fixed_budgets, fixed_budgets do |fixed_budget| %>
|
||||
<%= fixed_budget.hidden_field(:year) %>
|
||||
<%= fixed_budget.hidden_field(:month) %>
|
||||
|
||||
<p class="inline-hints" style="display:none;"><%= fixed_budget.label(:title, l(:field_title))%></p>
|
||||
<%= fixed_budget.text_field(:title) %>
|
||||
|
||||
<p class="inline-hints">
|
||||
<%= fixed_budget.label(:budget, l(:field_budget), :style => 'display: none;')%> <%# Hidden label :| %>
|
||||
<%= l(:text_dollar_sign) %>
|
||||
</p>
|
||||
<%= fixed_budget.text_field(:budget) %>
|
||||
|
||||
<p class="inline-hints">
|
||||
<%= fixed_budget.label(:markup, l(:field_markup), :style => 'display: none;')%> <%# Hidden label :| %>
|
||||
<%= l(:field_discount_hint) %>
|
||||
</p>
|
||||
<%= fixed_budget.text_field(:markup) %>
|
||||
|
||||
<p class="inline-hints">
|
||||
<%= fixed_budget.label(:paid, l(:field_paid), :style => 'display: none;') %><%# Hidden label :| %>
|
||||
<%= l(:field_paid) %>
|
||||
</p>
|
||||
<%= fixed_budget.check_box(:paid) %>
|
||||
|
||||
<p class="inline-hints" style="display:none;"><%= fixed_budget.label(:description, l(:field_description), :for => "fixed-description#{fixed_budget.object.object_id}")%></p>
|
||||
<%= fixed_budget.text_area(:description, :class => 'wiki-edit', :rows => '5', :id => "fixed-description#{fixed_budget.object.object_id}") %>
|
||||
<%= wikitoolbar_for "fixed-description#{fixed_budget.object.object_id}" %>
|
||||
|
||||
<p>Todo: Add button (Release 3)</p>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
<%= form.input :total, :input_html => {:size => 10}, :wrapper_html => {:class => 'deliverable_total_input'}, :hint => l(:text_dollar_sign) %>
|
||||
|
||||
<% end %>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<%= javascript_tag("var i18nChangedPeriodMessage = '#{l(:text_changed_period_message)}'") %>
|
||||
|
||||
<div class="box tabular">
|
||||
<% form.inputs :name => l(:text_deliverable_details_legend) do %>
|
||||
<% form.inputs :name => l(:text_deliverable_details_legend), :id => 'deliverable-details' do %>
|
||||
<%# Used by jquery to check if this is a new or existing record %>
|
||||
<%= hidden_field_tag('deliverable_id', h(resource.id), :id => 'deliverable_stored_id') %>
|
||||
<%= form.input :title, :required => true %>
|
||||
@@ -40,13 +40,13 @@
|
||||
<% if resource.retainer? && resource.respond_to?(:months) %>
|
||||
<% if resource.months.present? %>
|
||||
<% resource.months.each do |month| %>
|
||||
<%= render :partial => 'finance_form', :locals => {:form => form, :labor_budgets => resource.labor_budgets_for_date(month), :overhead_budgets => resource.overhead_budgets_for_date(month), :label => l(:text_deliverable_finances_date, :date => month.strftime("%B, %Y")), :fieldset_class => 'date-' + month.strftime('%Y-%m') } %>
|
||||
<%= render :partial => 'finance_form', :locals => {:form => form, :labor_budgets => resource.labor_budgets_for_date(month), :overhead_budgets => resource.overhead_budgets_for_date(month), :fixed_budgets => resource.fixed_budgets_for_date(month), :label => l(:text_deliverable_finances_date, :date => month.strftime("%B, %Y")), :fieldset_class => 'date-' + month.strftime('%Y-%m') } %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= content_tag(:p, l(:text_missing_period), :class => 'nodata') %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= render :partial => 'finance_form', :locals => {:form => form, :labor_budgets => resource.labor_budgets, :overhead_budgets => resource.overhead_budgets, :label => l(:text_deliverable_finances), :fieldset_class => '' } %>
|
||||
<%= render :partial => 'finance_form', :locals => {:form => form, :labor_budgets => resource.labor_budgets, :overhead_budgets => resource.overhead_budgets, :fixed_budgets => resource.fixed_budgets, :label => l(:text_deliverable_finances), :fieldset_class => '' } %>
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -40,8 +40,8 @@ en:
|
||||
field_fixed_spent: "Fixed"
|
||||
field_labor_budget: "Labor"
|
||||
field_labor_spent: "Labor"
|
||||
field_markup_budget: "Markup"
|
||||
field_markup_spent: "Markup"
|
||||
field_fixed_markup_budget: "Markup"
|
||||
field_fixed_markup_spent: "Markup"
|
||||
field_overhead_budget: "Overhead"
|
||||
field_overhead_spent: "Overhead"
|
||||
field_profit_budget: "Profit"
|
||||
@@ -70,4 +70,6 @@ en:
|
||||
text_flash_deliverable_created: "Deliverable: {{name}} was successfully created."
|
||||
text_flash_deliverable_updated: "Deliverable: {{name}} was successfully updated."
|
||||
text_flash_deliverable_destroyed: "Deliverable: {{name}} was successfully destroyed."
|
||||
|
||||
field_budget: Budget
|
||||
field_markup: Markup
|
||||
field_paid: Paid
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
class CreateFixedBudgets < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :fixed_budgets do |t|
|
||||
t.string :title
|
||||
t.decimal :budget, :precision => 15, :scale => 4
|
||||
t.string :markup
|
||||
t.text :description
|
||||
t.references :deliverable
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
add_index :fixed_budgets, :deliverable_id
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :fixed_budgets
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,14 @@
|
||||
class AddYearAndMonthToFixedBudgets < ActiveRecord::Migration
|
||||
def self.up
|
||||
add_column :fixed_budgets, :year, :integer
|
||||
add_index :fixed_budgets, :year
|
||||
|
||||
add_column :fixed_budgets, :month, :integer
|
||||
add_index :fixed_budgets, :month
|
||||
end
|
||||
|
||||
def self.down
|
||||
remove_column :fixed_budgets, :year
|
||||
remove_column :fixed_budgets, :month
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,10 @@
|
||||
class AddPaidToFixedBudgets < ActiveRecord::Migration
|
||||
def self.up
|
||||
add_column :fixed_budgets, :paid, :boolean
|
||||
add_index :fixed_budgets, :paid
|
||||
end
|
||||
|
||||
def self.down
|
||||
remove_column :fixed_budgets, :paid
|
||||
end
|
||||
end
|
||||
@@ -210,6 +210,79 @@ class ContractsShowTest < ActionController::IntegrationTest
|
||||
|
||||
end
|
||||
|
||||
should "show the total fixed budget for a Deliverable" do
|
||||
@manager = User.generate!
|
||||
|
||||
@deliverable1 = FixedDeliverable.generate!(:contract => @contract, :manager => @manager)
|
||||
|
||||
FixedBudget.generate!(:deliverable => @deliverable1, :budget => '$1,000', :markup => '$100')
|
||||
FixedBudget.generate!(:deliverable => @deliverable1, :budget => '$2,000', :markup => '200%')
|
||||
|
||||
visit_contract_page(@contract)
|
||||
assert_select "table#deliverables" do
|
||||
assert_select "td.fixed", :text => /3,000/
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
should "show the total fixed budget spent for a Deliverable" do
|
||||
@manager = User.generate!
|
||||
|
||||
@deliverable1 = FixedDeliverable.generate!(:contract => @contract, :manager => @manager)
|
||||
|
||||
FixedBudget.generate!(:deliverable => @deliverable1, :budget => '$1,000', :markup => '$100', :paid => true)
|
||||
FixedBudget.generate!(:deliverable => @deliverable1, :budget => '$2,000', :markup => '200%')
|
||||
|
||||
visit_contract_page(@contract)
|
||||
assert_select "table#deliverables" do
|
||||
assert_select "td.fixed.spent-amount", :text => /1,000/
|
||||
end
|
||||
end
|
||||
|
||||
should "show each fixed budget item in the details for the Deliverable" do
|
||||
@manager = User.generate!
|
||||
|
||||
@deliverable1 = FixedDeliverable.generate!(:contract => @contract, :manager => @manager)
|
||||
|
||||
@budget1 = FixedBudget.generate!(:deliverable => @deliverable1, :title => 'Item 1', :budget => '$1,000', :markup => '$100', :paid => true)
|
||||
@budget2 = FixedBudget.generate!(:deliverable => @deliverable1, :title => 'Item 2', :budget => '$2,000', :markup => '200%')
|
||||
|
||||
visit_contract_page(@contract)
|
||||
assert_select "table#deliverables" do
|
||||
assert_select "#deliverable_details_#{@deliverable1.id}" do
|
||||
assert_select "tr#fixed_budget_#{@budget1.id}" do
|
||||
assert_select 'td.fixed_title', :text => /#{@budget1.title}/
|
||||
assert_select 'td.fixed_budget_spent', :text => '1,000'
|
||||
assert_select 'td.fixed_budget_total', :text => '1,000'
|
||||
end
|
||||
|
||||
assert_select "tr#fixed_budget_#{@budget2.id}" do
|
||||
assert_select 'td.fixed_title', :text => /#{@budget2.title}/
|
||||
assert_select 'td.fixed_budget_spent', :text => '0'
|
||||
assert_select 'td.fixed_budget_total', :text => '2,000'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
should "show the total fixed markup budget in the details for the Deliverable" do
|
||||
@manager = User.generate!
|
||||
|
||||
@deliverable1 = FixedDeliverable.generate!(:contract => @contract, :manager => @manager)
|
||||
|
||||
@budget1 = FixedBudget.generate!(:deliverable => @deliverable1, :title => 'Item 1', :budget => '$1,000', :markup => '$100', :paid => true)
|
||||
@budget2 = FixedBudget.generate!(:deliverable => @deliverable1, :title => 'Item 2', :budget => '$2,000', :markup => '200%')
|
||||
|
||||
visit_contract_page(@contract)
|
||||
assert_select "table#deliverables" do
|
||||
assert_select "#deliverable_details_#{@deliverable1.id}" do
|
||||
assert_select 'td.fixed_markup_budget_spent', :text => '100'
|
||||
assert_select 'td.fixed_markup_budget_total', :text => '4,100'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
should "show the current period for a Retainer" do
|
||||
today_mock = Date.new(2010,2,15)
|
||||
Date.stubs(:today).returns(today_mock)
|
||||
|
||||
@@ -27,10 +27,11 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
||||
assert_select "select#fixed_deliverable_type", :count => 0 # Not editable
|
||||
assert js("jQuery('#fixed_deliverable_total_input').is(':visible')"), "Total is hidden when it should be visible"
|
||||
|
||||
|
||||
fill_in "Title", :with => 'An updated title'
|
||||
check "Feature Sign Off"
|
||||
check "Warranty Sign Off"
|
||||
within("#deliverable-details") do
|
||||
fill_in "Title", :with => 'An updated title'
|
||||
check "Feature Sign Off"
|
||||
check "Warranty Sign Off"
|
||||
end
|
||||
click_button "Save"
|
||||
|
||||
assert_response :success
|
||||
@@ -56,9 +57,11 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
||||
assert_select "select#hourly_deliverable_type", :count => 0 # Not editable
|
||||
assert js("jQuery('#hourly_deliverable_total_input').is(':hidden')"), "Total is visible when it should be hidden"
|
||||
|
||||
fill_in "Title", :with => 'An updated title'
|
||||
check "Feature Sign Off"
|
||||
check "Warranty Sign Off"
|
||||
within("#deliverable-details") do
|
||||
fill_in "Title", :with => 'An updated title'
|
||||
check "Feature Sign Off"
|
||||
check "Warranty Sign Off"
|
||||
end
|
||||
|
||||
within("#deliverable-labor") do
|
||||
fill_in "hrs", :with => '20'
|
||||
@@ -95,6 +98,8 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
||||
@retainer_deliverable = RetainerDeliverable.spawn(:contract => @contract, :manager => @manager, :title => "Retainer")
|
||||
@retainer_deliverable.labor_budgets << @labor_budget = LaborBudget.spawn(:deliverable => @retainer_deliverable, :budget => 1000, :hours => 10)
|
||||
@retainer_deliverable.overhead_budgets << @overhead_budget = OverheadBudget.spawn(:deliverable => @retainer_deliverable, :budget => 1000, :hours => 10)
|
||||
@retainer_deliverable.fixed_budgets << @fixed_budget = FixedBudget.spawn(:deliverable => @retainer_deliverable, :title => 'Printing supplies', :budget => 100, :markup => 0)
|
||||
|
||||
@retainer_deliverable.start_date = '2010-01-01'
|
||||
@retainer_deliverable.end_date = '2010-12-31'
|
||||
@retainer_deliverable.save!
|
||||
@@ -117,6 +122,13 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
||||
fill_in "hrs", :with => '100'
|
||||
fill_in "$", :with => '100'
|
||||
end
|
||||
|
||||
within "#deliverable-fixed" do
|
||||
fill_in "title", :with => 'Flight to NYC'
|
||||
fill_in "budget", :with => '$600'
|
||||
fill_in "markup", :with => '50%'
|
||||
fill_in "description", :with => 'Need to fly to NYC for the week'
|
||||
end
|
||||
end
|
||||
|
||||
click_button "Save"
|
||||
@@ -157,6 +169,24 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
||||
end
|
||||
end
|
||||
|
||||
@fixed_budgets = @retainer_deliverable.reload.fixed_budgets
|
||||
assert_equal 12, @fixed_budgets.length
|
||||
@fixed_budgets.each do |fixed_budget|
|
||||
if fixed_budget.year == 2010 && fixed_budget.month == 1
|
||||
|
||||
# Specific month's budget updated?
|
||||
assert_equal 600, fixed_budget.budget
|
||||
assert_equal '50%', fixed_budget.markup
|
||||
assert_equal 300, fixed_budget.markup_value
|
||||
|
||||
else
|
||||
|
||||
assert_equal 100, fixed_budget.budget
|
||||
assert_equal '0', fixed_budget.markup
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
should "allow extending a Retainer's start and end months" do
|
||||
@@ -175,6 +205,7 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
||||
@retainer_deliverable.labor_budgets << @labor_budget = LaborBudget.spawn(:deliverable => @retainer_deliverable, :budget => labor_budget_amount_2, :hours => labor_budget_hours_2)
|
||||
@retainer_deliverable.overhead_budgets << @overhead_budget = OverheadBudget.spawn(:deliverable => @retainer_deliverable, :budget => overhead_budget_amount_1, :hours => overhead_budget_hours_1)
|
||||
@retainer_deliverable.overhead_budgets << @overhead_budget = OverheadBudget.spawn(:deliverable => @retainer_deliverable, :budget => overhead_budget_amount_2, :hours => overhead_budget_hours_2)
|
||||
@retainer_deliverable.fixed_budgets << @fixed_budget = FixedBudget.spawn(:deliverable => @retainer_deliverable, :title => 'Printing supplies', :budget => 100, :markup => 0)
|
||||
@retainer_deliverable.start_date = '2010-01-01'
|
||||
@retainer_deliverable.end_date = '2010-12-31'
|
||||
@retainer_deliverable.save!
|
||||
@@ -256,6 +287,17 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
||||
assert [overhead_budget_amount_1, overhead_budget_amount_2].include?(overhead_budget.budget), "Extended overhead budget dollars not matching template budget"
|
||||
end
|
||||
|
||||
@fixed_budgets = @retainer_deliverable.reload.fixed_budgets
|
||||
assert_equal 36, @fixed_budgets.length # 36 months * 1 record
|
||||
|
||||
@fixed_budgets_for_2009 = @fixed_budgets.select {|l| l.year == 2009 }
|
||||
@fixed_budgets_for_2010 = @fixed_budgets.select {|l| l.year == 2010 }
|
||||
@fixed_budgets_for_2011 = @fixed_budgets.select {|l| l.year == 2011 }
|
||||
|
||||
assert_equal 12, @fixed_budgets_for_2009.length
|
||||
assert_equal 12, @fixed_budgets_for_2010.length
|
||||
assert_equal 12, @fixed_budgets_for_2011.length
|
||||
|
||||
end
|
||||
|
||||
should "allow shrinking a Retainer's start and end months" do
|
||||
@@ -264,6 +306,7 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
||||
@retainer_deliverable.labor_budgets << @labor_budget = LaborBudget.spawn(:deliverable => @retainer_deliverable, :budget => 2000, :hours => 20)
|
||||
@retainer_deliverable.overhead_budgets << @overhead_budget = OverheadBudget.spawn(:deliverable => @retainer_deliverable, :budget => 1000, :hours => 10)
|
||||
@retainer_deliverable.overhead_budgets << @overhead_budget = OverheadBudget.spawn(:deliverable => @retainer_deliverable, :budget => 2000, :hours => 20)
|
||||
@retainer_deliverable.fixed_budgets << @fixed_budget = FixedBudget.spawn(:deliverable => @retainer_deliverable, :title => 'Printing supplies', :budget => 100, :markup => 0)
|
||||
@retainer_deliverable.start_date = '2010-01-01'
|
||||
@retainer_deliverable.end_date = '2010-12-31'
|
||||
@retainer_deliverable.save!
|
||||
@@ -293,6 +336,9 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
||||
@overhead_budgets = @retainer_deliverable.reload.overhead_budgets
|
||||
assert_equal 12, @overhead_budgets.length # 6 months * 2 records
|
||||
|
||||
@fixed_budgets = @retainer_deliverable.reload.fixed_budgets
|
||||
assert_equal 6, @fixed_budgets.length # 6 months * 1 records
|
||||
|
||||
end
|
||||
|
||||
should "allow editing a Retainer's start and end months inside the current period" do
|
||||
@@ -346,7 +392,7 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
||||
assert_response :success
|
||||
assert_template 'deliverables/edit'
|
||||
|
||||
# Should show 6 inputs:
|
||||
# Should show inputs:
|
||||
# * labor hidden year
|
||||
# * labor hidden month
|
||||
# * labor hours
|
||||
@@ -355,9 +401,17 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
||||
# * overhead hidden month
|
||||
# * overhead hours
|
||||
# * overhead amount
|
||||
# * fixed hidden year
|
||||
# * fixed hidden month
|
||||
# * fixed title
|
||||
# * fixed budget
|
||||
# * fixed markup
|
||||
# * fixed paid checkbox
|
||||
# * fixed paid hidden field
|
||||
# * total (hidden)
|
||||
assert_select ".date-2010-01" do
|
||||
assert_select "input", :count => 9
|
||||
assert_select "input", :count => 16
|
||||
assert_select "textarea.wiki-edit", :count => 1 # Fixed description
|
||||
end
|
||||
|
||||
|
||||
@@ -371,6 +425,14 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
||||
fill_in "hrs", :with => '100'
|
||||
fill_in "$", :with => '100'
|
||||
end
|
||||
|
||||
within "#deliverable-fixed" do
|
||||
fill_in "title", :with => 'Flight to NYC'
|
||||
fill_in "budget", :with => '$600'
|
||||
fill_in "markup", :with => '50%'
|
||||
fill_in "description", :with => 'Need to fly to NYC for the week'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
click_button "Save"
|
||||
@@ -386,5 +448,8 @@ class DeliverablesEditTest < ActionController::IntegrationTest
|
||||
assert_equal 3, @retainer_deliverable.overhead_budgets.count
|
||||
assert_equal [100, nil, nil], @retainer_deliverable.overhead_budgets.collect(&:hours)
|
||||
assert_equal [100, nil, nil], @retainer_deliverable.overhead_budgets.collect(&:budget)
|
||||
|
||||
assert_equal 3, @retainer_deliverable.fixed_budgets.count
|
||||
assert_equal [600, nil, nil], @retainer_deliverable.fixed_budgets.collect(&:budget)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -50,12 +50,15 @@ class DeliverablesNewTest < ActionController::IntegrationTest
|
||||
click_link 'Add New'
|
||||
assert_response :success
|
||||
|
||||
fill_in "Title", :with => 'A New Deliverable'
|
||||
select "Fixed", :from => "Type"
|
||||
select @manager.name, :from => "Manager"
|
||||
fill_in "Start", :with => '2010-01-01'
|
||||
fill_in "End Date", :with => '2010-12-31'
|
||||
fill_in "Notes", :with => 'Some notes on the deliverable'
|
||||
within("#deliverable-details") do
|
||||
fill_in "Title", :with => 'A New Deliverable'
|
||||
select "Fixed", :from => "Type"
|
||||
select @manager.name, :from => "Manager"
|
||||
fill_in "Start", :with => '2010-01-01'
|
||||
fill_in "End Date", :with => '2010-12-31'
|
||||
fill_in "Notes", :with => 'Some notes on the deliverable'
|
||||
end
|
||||
|
||||
fill_in "Total", :with => '1,000.00'
|
||||
# TODO: webrat can't trigger DOM events so it can't appear
|
||||
# assert js("jQuery('#deliverable_total').is(':visible')"), "Total is hidden when it should be visible"
|
||||
@@ -84,12 +87,14 @@ class DeliverablesNewTest < ActionController::IntegrationTest
|
||||
click_link 'Add New'
|
||||
assert_response :success
|
||||
|
||||
fill_in "Title", :with => 'A New Deliverable'
|
||||
select "Hourly", :from => "Type"
|
||||
select @manager.name, :from => "Manager"
|
||||
fill_in "Start", :with => '2010-01-01'
|
||||
fill_in "End Date", :with => '2010-12-31'
|
||||
fill_in "Notes", :with => 'Some notes on the deliverable'
|
||||
within("#deliverable-details") do
|
||||
fill_in "Title", :with => 'A New Deliverable'
|
||||
select "Hourly", :from => "Type"
|
||||
select @manager.name, :from => "Manager"
|
||||
fill_in "Start", :with => '2010-01-01'
|
||||
fill_in "End Date", :with => '2010-12-31'
|
||||
fill_in "Notes", :with => 'Some notes on the deliverable'
|
||||
end
|
||||
fill_in "Total", :with => '1,000.00'
|
||||
|
||||
# # Hide and clear the total
|
||||
@@ -120,13 +125,15 @@ class DeliverablesNewTest < ActionController::IntegrationTest
|
||||
click_link 'Add New'
|
||||
assert_response :success
|
||||
|
||||
fill_in "Title", :with => 'A New Deliverable'
|
||||
select "Retainer", :from => "Type"
|
||||
select @manager.name, :from => "Manager"
|
||||
fill_in "Start", :with => '2010-01-01'
|
||||
fill_in "End Date", :with => '2010-12-31'
|
||||
fill_in "Notes", :with => 'Some notes on the deliverable'
|
||||
|
||||
within("#deliverable-details") do
|
||||
fill_in "Title", :with => 'A New Deliverable'
|
||||
select "Retainer", :from => "Type"
|
||||
select @manager.name, :from => "Manager"
|
||||
fill_in "Start", :with => '2010-01-01'
|
||||
fill_in "End Date", :with => '2010-12-31'
|
||||
fill_in "Notes", :with => 'Some notes on the deliverable'
|
||||
end
|
||||
|
||||
within("#deliverable-labor") do
|
||||
fill_in "hrs", :with => '20'
|
||||
fill_in "$", :with => '$2,000'
|
||||
@@ -193,12 +200,14 @@ class DeliverablesNewTest < ActionController::IntegrationTest
|
||||
click_link 'Add New'
|
||||
assert_response :success
|
||||
|
||||
fill_in "Title", :with => 'A New Deliverable'
|
||||
select "Hourly", :from => "Type"
|
||||
select @manager.name, :from => "Manager"
|
||||
fill_in "Start", :with => '2010-01-01'
|
||||
fill_in "End Date", :with => '2010-12-31'
|
||||
fill_in "Notes", :with => 'Some notes on the deliverable'
|
||||
within("#deliverable-details") do
|
||||
fill_in "Title", :with => 'A New Deliverable'
|
||||
select "Hourly", :from => "Type"
|
||||
select @manager.name, :from => "Manager"
|
||||
fill_in "Start", :with => '2010-01-01'
|
||||
fill_in "End Date", :with => '2010-12-31'
|
||||
fill_in "Notes", :with => 'Some notes on the deliverable'
|
||||
end
|
||||
|
||||
within("#deliverable-labor") do
|
||||
fill_in "hrs", :with => '20'
|
||||
@@ -210,6 +219,13 @@ class DeliverablesNewTest < ActionController::IntegrationTest
|
||||
fill_in "$", :with => '$1,000'
|
||||
end
|
||||
|
||||
within("#deliverable-fixed") do
|
||||
fill_in "title", :with => 'Flight to NYC'
|
||||
fill_in "budget", :with => '$600'
|
||||
fill_in "markup", :with => '50%'
|
||||
fill_in "description", :with => 'Need to fly to NYC for the week'
|
||||
end
|
||||
|
||||
click_button "Save"
|
||||
|
||||
assert_response :success
|
||||
@@ -226,6 +242,14 @@ class DeliverablesNewTest < ActionController::IntegrationTest
|
||||
@overhead_budget = @deliverable.overhead_budgets.first
|
||||
assert_equal 10, @overhead_budget.hours
|
||||
assert_equal 1000.0, @overhead_budget.budget
|
||||
|
||||
assert_equal 1, @deliverable.fixed_budgets.count
|
||||
@fixed_budget = @deliverable.fixed_budgets.first
|
||||
assert_equal "Flight to NYC", @fixed_budget.title
|
||||
assert_equal 600, @fixed_budget.budget
|
||||
assert_equal "50%", @fixed_budget.markup
|
||||
assert_equal 300, @fixed_budget.markup_value # 600 * 50%
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -247,11 +247,62 @@ class ContractTest < ActiveSupport::TestCase
|
||||
TimeEntry.generate!(:hours => 4, :issue => @issue2, :project => @project,
|
||||
:activity => @non_billable_activity,
|
||||
:user => @manager)
|
||||
@deliverable_2.fixed_budgets << FixedBudget.spawn(:budget => 200, :markup => '$100', :paid => true)
|
||||
|
||||
assert_equal 875, @deliverable_1.profit_left
|
||||
assert_equal 1125, @deliverable_2.profit_left
|
||||
assert_equal 2000, contract.profit_left
|
||||
assert_equal 825, @deliverable_2.profit_left
|
||||
assert_equal 1700, contract.profit_left
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "#fixed_budget" do
|
||||
should "sum all fixed budget amounts on the Deliverables" do
|
||||
contract = Contract.generate!
|
||||
contract.deliverables << @deliverable_1 = FixedDeliverable.generate!
|
||||
FixedBudget.generate!(:deliverable => @deliverable_1, :budget => '$1,000')
|
||||
contract.deliverables << @deliverable_2 = HourlyDeliverable.generate!
|
||||
FixedBudget.generate!(:deliverable => @deliverable_2, :budget => '$2,000')
|
||||
|
||||
assert_equal 3000, contract.fixed_budget
|
||||
end
|
||||
end
|
||||
|
||||
context "#fixed_spent" do
|
||||
should "sum all fixed budget amounts on the Deliverables which are paid" do
|
||||
contract = Contract.generate!
|
||||
contract.deliverables << @deliverable_1 = FixedDeliverable.generate!
|
||||
FixedBudget.generate!(:deliverable => @deliverable_1, :budget => '$1,000', :paid => true)
|
||||
contract.deliverables << @deliverable_2 = HourlyDeliverable.generate!
|
||||
FixedBudget.generate!(:deliverable => @deliverable_2, :budget => '$2,000')
|
||||
|
||||
assert_equal 1000, contract.fixed_spent
|
||||
end
|
||||
end
|
||||
|
||||
context "#fixed_markup_budget" do
|
||||
should "sum all fixed budget markup values on the Deliverables" do
|
||||
contract = Contract.generate!
|
||||
contract.deliverables << @deliverable_1 = FixedDeliverable.generate!
|
||||
FixedBudget.generate!(:deliverable => @deliverable_1, :budget => '$1,000', :markup => '$100')
|
||||
contract.deliverables << @deliverable_2 = HourlyDeliverable.generate!
|
||||
FixedBudget.generate!(:deliverable => @deliverable_2, :budget => '$2,000', :markup => '200%')
|
||||
|
||||
assert_equal (100) + (2.00 * 2000), contract.fixed_markup_budget
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "#fixed_markup_spent" do
|
||||
should "sum all fixed budget markup values on the Deliverables which are paid" do
|
||||
contract = Contract.generate!
|
||||
contract.deliverables << @deliverable_1 = FixedDeliverable.generate!
|
||||
FixedBudget.generate!(:deliverable => @deliverable_1, :budget => '$1,000', :markup => '$100', :paid => true)
|
||||
contract.deliverables << @deliverable_2 = HourlyDeliverable.generate!
|
||||
FixedBudget.generate!(:deliverable => @deliverable_2, :budget => '$2,000', :markup => '200%')
|
||||
|
||||
assert_equal (100) + (0), contract.fixed_markup_spent
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -5,6 +5,7 @@ class DeliverableTest < ActiveSupport::TestCase
|
||||
should_belong_to :manager
|
||||
should_have_many :labor_budgets
|
||||
should_have_many :overhead_budgets
|
||||
should_have_many :fixed_budgets
|
||||
should_have_many :issues
|
||||
|
||||
should_validate_presence_of :title
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
|
||||
class FixedBudgetTest < ActiveSupport::TestCase
|
||||
should_belong_to :deliverable
|
||||
|
||||
context "#markup_value" do
|
||||
setup do
|
||||
@fixed_budget = FixedBudget.new(:budget => 1000)
|
||||
end
|
||||
|
||||
context "with no markup" do
|
||||
should "be 0" do
|
||||
assert_equal nil, @fixed_budget.markup
|
||||
assert_equal 0, @fixed_budget.markup_value
|
||||
end
|
||||
end
|
||||
|
||||
context "with a % markup" do
|
||||
should "equal the budget times the %" do
|
||||
@fixed_budget.markup = '50%'
|
||||
assert_equal 500, @fixed_budget.markup_value
|
||||
end
|
||||
end
|
||||
|
||||
context "with a $ markup" do
|
||||
should "equal the $ markup (straight markup)" do
|
||||
@fixed_budget.markup = '$4,000.57'
|
||||
assert_equal 4000.57, @fixed_budget.markup_value
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -13,8 +13,9 @@ class FixedDeliverableTest < ActiveSupport::TestCase
|
||||
LaborBudget.generate!(:deliverable => deliverable, :budget => 200)
|
||||
LaborBudget.generate!(:deliverable => deliverable, :budget => 200)
|
||||
OverheadBudget.generate!(:deliverable => deliverable, :budget => 200)
|
||||
FixedBudget.generate!(:deliverable => deliverable, :budget => '$100', :markup => '50%') # $50 markup
|
||||
|
||||
assert_equal 400, deliverable.profit_budget
|
||||
assert_equal 400 - 150, deliverable.profit_budget
|
||||
end
|
||||
|
||||
should "be 0 if there is no total" do
|
||||
|
||||
@@ -20,13 +20,14 @@ class HourlyDeliverableTest < ActiveSupport::TestCase
|
||||
assert_equal 0, d.total
|
||||
end
|
||||
|
||||
should "multiply the total number of labor budget hours by the contract billable rate" do
|
||||
should "multiply the total number of labor budget hours by the contract billable rate and add the fixed budget and markup" do
|
||||
contract = Contract.generate!(:billable_rate => 100.0)
|
||||
d = HourlyDeliverable.generate!(:contract => contract)
|
||||
d.labor_budgets << LaborBudget.generate!(:hours => 10)
|
||||
d.overhead_budgets << OverheadBudget.generate!(:hours => 20)
|
||||
d.fixed_budgets << FixedBudget.generate!(:budget => '$100', :markup => '50%') # $50 markup
|
||||
|
||||
assert_equal 100.0 * 10, d.total
|
||||
assert_equal (100.0 * 10) + (100 + 50), d.total
|
||||
end
|
||||
end
|
||||
|
||||
@@ -86,9 +87,10 @@ class HourlyDeliverableTest < ActiveSupport::TestCase
|
||||
LaborBudget.generate!(:deliverable => @deliverable, :hours => 5, :budget => 250)
|
||||
LaborBudget.generate!(:deliverable => @deliverable, :hours => 5, :budget => 250)
|
||||
OverheadBudget.generate!(:deliverable => @deliverable, :hours => 3, :budget => 225)
|
||||
FixedBudget.generate!(:deliverable => @deliverable, :budget => '$100', :markup => '50%') # $50 markup
|
||||
|
||||
assert_equal 1500, @deliverable.total
|
||||
assert_equal 1500 - (225 + 250 + 250), @deliverable.profit_budget
|
||||
assert_equal 1650, @deliverable.total # has the FixedBudget items added to the total also
|
||||
assert_equal 1650 - (225 + 250 + 250 + 100 + 50), @deliverable.profit_budget
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -476,4 +476,152 @@ class RetainerDeliverableTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "#fixed_budget_total" do
|
||||
setup do
|
||||
@contract = Contract.generate!(:billable_rate => 100)
|
||||
@deliverable = RetainerDeliverable.generate!(:start_date => '2010-01-01', :end_date => '2010-03-31', :contract => @contract)
|
||||
@deliverable.fixed_budgets << FixedBudget.spawn(:budget => 1000)
|
||||
@deliverable.fixed_budgets << FixedBudget.spawn(:budget => 2000)
|
||||
@deliverable.save!
|
||||
|
||||
assert_equal 3000 * 3, @deliverable.fixed_budget_total
|
||||
end
|
||||
|
||||
context "with a empty period" do
|
||||
should "use all periods" do
|
||||
assert_equal 9000, @deliverable.fixed_budget_total(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context "with a period out of the retainer range" do
|
||||
should "filter the records" do
|
||||
assert_equal 0, @deliverable.fixed_budget_total(Date.new(2011,1,1))
|
||||
end
|
||||
end
|
||||
|
||||
context "with an invalid period" do
|
||||
should "return 0" do
|
||||
assert_equal 0, @deliverable.fixed_budget_total('1')
|
||||
end
|
||||
end
|
||||
|
||||
context "with a period in the retainer range" do
|
||||
should "filter the records" do
|
||||
assert_equal 3000, @deliverable.fixed_budget_total(Date.new(2010,2,1))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "#fixed_budget_total_spent" do
|
||||
setup do
|
||||
@contract = Contract.generate!(:billable_rate => 100)
|
||||
@deliverable = RetainerDeliverable.generate!(:start_date => '2010-01-01', :end_date => '2010-03-31', :contract => @contract)
|
||||
@deliverable.fixed_budgets << FixedBudget.spawn(:budget => 1000, :paid => true)
|
||||
@deliverable.fixed_budgets << FixedBudget.spawn(:budget => 2000)
|
||||
@deliverable.save!
|
||||
|
||||
assert_equal 1000 * 3, @deliverable.fixed_budget_total_spent
|
||||
end
|
||||
|
||||
context "with a empty period" do
|
||||
should "use all periods" do
|
||||
assert_equal 3000, @deliverable.fixed_budget_total_spent(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context "with a period out of the retainer range" do
|
||||
should "filter the records" do
|
||||
assert_equal 0, @deliverable.fixed_budget_total_spent(Date.new(2011,1,1))
|
||||
end
|
||||
end
|
||||
|
||||
context "with an invalid period" do
|
||||
should "return 0" do
|
||||
assert_equal 0, @deliverable.fixed_budget_total_spent('1')
|
||||
end
|
||||
end
|
||||
|
||||
context "with a period in the retainer range" do
|
||||
should "filter the records" do
|
||||
assert_equal 1000, @deliverable.fixed_budget_total_spent(Date.new(2010,2,1))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "#fixed_markup_budget_total" do
|
||||
setup do
|
||||
@contract = Contract.generate!(:billable_rate => 100)
|
||||
@deliverable = RetainerDeliverable.generate!(:start_date => '2010-01-01', :end_date => '2010-03-31', :contract => @contract)
|
||||
@deliverable.fixed_budgets << FixedBudget.spawn(:budget => 1000, :markup => '50%')
|
||||
@deliverable.fixed_budgets << FixedBudget.spawn(:budget => 2000, :markup => '$1000')
|
||||
@deliverable.save!
|
||||
|
||||
assert_equal (500 + 1000) * 3, @deliverable.fixed_markup_budget_total
|
||||
end
|
||||
|
||||
context "with a empty period" do
|
||||
should "use all periods" do
|
||||
assert_equal 4500, @deliverable.fixed_markup_budget_total(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context "with a period out of the retainer range" do
|
||||
should "filter the records" do
|
||||
assert_equal 0, @deliverable.fixed_markup_budget_total(Date.new(2011,1,1))
|
||||
end
|
||||
end
|
||||
|
||||
context "with an invalid period" do
|
||||
should "return 0" do
|
||||
assert_equal 0, @deliverable.fixed_markup_budget_total('1')
|
||||
end
|
||||
end
|
||||
|
||||
context "with a period in the retainer range" do
|
||||
should "filter the records" do
|
||||
assert_equal 1500, @deliverable.fixed_markup_budget_total(Date.new(2010,2,1))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "#fixed_markup_budget_total_spent" do
|
||||
setup do
|
||||
@contract = Contract.generate!(:billable_rate => 100)
|
||||
@deliverable = RetainerDeliverable.generate!(:start_date => '2010-01-01', :end_date => '2010-03-31', :contract => @contract)
|
||||
@deliverable.fixed_budgets << FixedBudget.spawn(:budget => 1000, :markup => '50%', :paid => true)
|
||||
@deliverable.fixed_budgets << FixedBudget.spawn(:budget => 2000, :markup => '$1000')
|
||||
@deliverable.save!
|
||||
|
||||
assert_equal (500) * 3, @deliverable.fixed_markup_budget_total_spent
|
||||
end
|
||||
|
||||
context "with a empty period" do
|
||||
should "use all periods" do
|
||||
assert_equal 1500, @deliverable.fixed_markup_budget_total_spent(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context "with a period out of the retainer range" do
|
||||
should "filter the records" do
|
||||
assert_equal 0, @deliverable.fixed_markup_budget_total_spent(Date.new(2011,1,1))
|
||||
end
|
||||
end
|
||||
|
||||
context "with an invalid period" do
|
||||
should "return 0" do
|
||||
assert_equal 0, @deliverable.fixed_markup_budget_total_spent('1')
|
||||
end
|
||||
end
|
||||
|
||||
context "with a period in the retainer range" do
|
||||
should "filter the records" do
|
||||
assert_equal 500, @deliverable.fixed_markup_budget_total_spent(Date.new(2010,2,1))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user