229 lines
8.4 KiB
ERB
229 lines
8.4 KiB
ERB
<fieldset class="tabular">
|
|
<%= error_messages_for 'deliverable' %>
|
|
<div class="box">
|
|
<div class="splitcontentleft">
|
|
<p><%= f.text_field :subject, :required => true %></p>
|
|
<p><%= f.text_area :description,
|
|
:cols => 60,
|
|
:rows => (@deliverable.description.blank? ? 10 : [[10, @deliverable.description.length / 50].max, 100].min),
|
|
:accesskey => accesskey(:edit),
|
|
:class => 'wiki-edit' %></p>
|
|
<p><%= f.text_field :due, :size => 10 %><%= calendar_for('deliverable_due') %></p>
|
|
|
|
<p><%= f.check_box(:project_manager_signoff) %></p>
|
|
<p><%= f.check_box(:client_signoff) %></p>
|
|
</div>
|
|
|
|
<div class="splitcontentright">
|
|
<table>
|
|
|
|
<tr>
|
|
<td>
|
|
<label for="deliverable_type">Fixed Cost</label>
|
|
</td>
|
|
<td>
|
|
<%= check_box(:deliverable, :type, {}, FixedDeliverable.name, HourlyDeliverable.name) %>
|
|
<%= observe_field('deliverable_type', :function => "new Budget.changeType();") %>
|
|
</td>
|
|
<td class="calculation-column">
|
|
</td>
|
|
</tr>
|
|
|
|
<tr class="budget-hourly">
|
|
<td>
|
|
<label for="deliverable_cost_per_hour">Cost per hour</label>
|
|
</td>
|
|
<td>
|
|
<%= text_field :deliverable, :cost_per_hour, :size => 7 %>
|
|
</td>
|
|
<td>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr class="budget-hourly">
|
|
<td>
|
|
<label for="deliverable_total_hours">Total Hours</label>
|
|
</td>
|
|
<td>
|
|
<%= text_field :deliverable, :total_hours, :size => 7 %>
|
|
</td>
|
|
<td class="calculation-column">
|
|
<%= content_tag(:span, 0, :class => "budget-calculation", :id => 'variableCost') %>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr class="budget-fixed" style="display:none;">
|
|
<td>
|
|
<label for="deliverable_fixed_cost">Fixed Bid</label>
|
|
</td>
|
|
<td>
|
|
<%= text_field :deliverable, :fixed_cost, :size => 7 %>
|
|
</td>
|
|
<td class="calculation-column">
|
|
<%= content_tag(:span, 0, :class => "budget-calculation", :id => 'fixedCost') %>
|
|
</td>
|
|
</tr>
|
|
|
|
<%= field_with_budget_observer_and_totals(f, @deliverable, :overhead, :overhead_percent, @settings[:budget_non_billable_overhead]) %>
|
|
<%= field_with_budget_observer_and_totals(f, @deliverable, :materials, :materials_percent, @settings[:budget_materials]) %>
|
|
<%= field_with_budget_observer_and_totals(f, @deliverable, :profit, :profit_percent, @settings[:budget_profit]) %>
|
|
|
|
<tr class="total-budget">
|
|
<td><label>Total Budget:</label></td>
|
|
<td></td>
|
|
<td class="calculation-column">
|
|
<%= content_tag(:span, 0, :id => 'total-budget-calculation', :class => "budget-calculation") %>
|
|
</td>
|
|
</tr>
|
|
|
|
</table>
|
|
<%= f.hidden_field :budget %>
|
|
<%= observe_form('deliverable-form', :function => "new Budget.updateAmounts();", :on => 'blur') %>
|
|
|
|
|
|
</div>
|
|
<script type="text/javascript">new Budget.changeType();</script>
|
|
<script type="text/javascript">new Budget.updateAmounts();</script>
|
|
<script type="text/javascript">
|
|
new PeriodicalExecuter(function() {
|
|
Budget.updateAmounts();
|
|
}, 5);
|
|
</script>
|
|
<div style="clear:both;"> </div>
|
|
|
|
</div>
|
|
<%= mode == :create ? submit_tag(l(:button_create)) : submit_tag(l(:button_update)) %>
|
|
<%= link_to_remote l(:label_preview),
|
|
{ :url => { :controller => 'deliverables', :action => 'preview', :id => @project },
|
|
:method => 'post',
|
|
:update => 'preview',
|
|
:with => "Form.serialize('deliverable-form')",
|
|
:complete => "Element.scrollTo('preview')"
|
|
}, :accesskey => accesskey(:preview) %>
|
|
|
|
<%# Same as `wikitoolbar_for 'deliverable_description'` but without the help link %>
|
|
<%= javascript_include_tag('jstoolbar/jstoolbar') %>
|
|
<%= javascript_include_tag("jstoolbar/lang/jstoolbar-#{current_language}") %>
|
|
<%= javascript_tag("var toolbar = new jsToolBar($('deliverable_description'));toolbar.draw();") %>
|
|
|
|
|
|
<div id="preview" class="wiki"></div>
|
|
</fieldset>
|
|
<% content_for :header_tags do %>
|
|
<script type="text/javascript">
|
|
|
|
var BudgetModule = Class.create();
|
|
|
|
Object.extend(BudgetModule.prototype, {
|
|
initialize: function () {},
|
|
|
|
toAmount: function(value) {
|
|
var amount = value.replace(/[^1234567890.]/ig,'');
|
|
if (amount) {
|
|
return parseFloat(amount);
|
|
} else {
|
|
return 0;
|
|
}
|
|
},
|
|
|
|
updateAmounts: function() {
|
|
if ($('deliverable_type').checked) {
|
|
// Fixed cost
|
|
var cost = Budget.toAmount($('deliverable_fixed_cost').value);
|
|
Budget.updateAmount($('fixedCost'), cost);
|
|
} else {
|
|
// Variable cost
|
|
var perHour = Budget.toAmount($('deliverable_cost_per_hour').value);
|
|
var hours = Budget.toAmount($('deliverable_total_hours').value);
|
|
|
|
var cost = perHour * hours;
|
|
Budget.updateAmount($('variableCost'), cost);
|
|
}
|
|
|
|
|
|
if ($('deliverable_overhead').value.match('%')) {
|
|
var overhead_subtotal = (Budget.toAmount($('deliverable_overhead').value) / 100) * cost;
|
|
} else {
|
|
var overhead_subtotal = Budget.toAmount($('deliverable_overhead').value);
|
|
}
|
|
|
|
if ($('deliverable_materials').value.match('%')) {
|
|
var materials_subtotal = (Budget.toAmount($('deliverable_materials').value) / 100) * cost;
|
|
} else {
|
|
var materials_subtotal = Budget.toAmount($('deliverable_materials').value);
|
|
}
|
|
|
|
// Profit uses labor cost and overhead
|
|
if ($('deliverable_profit').value.match('%')) {
|
|
var profit_subtotal = (Budget.toAmount($('deliverable_profit').value) / 100) * (cost + overhead_subtotal);
|
|
} else {
|
|
var profit_subtotal = Budget.toAmount($('deliverable_profit').value);
|
|
}
|
|
|
|
// Amounts
|
|
Budget.updateAmount($('overhead_subtotal'), overhead_subtotal);
|
|
Budget.updateAmount($('materials_subtotal'), materials_subtotal);
|
|
Budget.updateAmount($('profit_subtotal'), profit_subtotal);
|
|
|
|
var total = cost + overhead_subtotal + materials_subtotal + profit_subtotal;
|
|
$('deliverable_budget').value = total;
|
|
$('total-budget-calculation').innerHTML = Budget.number_to_currency(total);
|
|
},
|
|
|
|
updateAmount: function(element, value) {
|
|
if (element) {
|
|
element.innerHTML = Budget.number_to_currency(value);
|
|
}
|
|
},
|
|
|
|
changeType: function() {
|
|
if ($('deliverable_type').checked) {
|
|
// Fixed
|
|
$$('.budget-hourly').each(function(ele) { ele.hide(); });
|
|
$$('.budget-fixed').each(function(ele) { ele.show(); });
|
|
} else {
|
|
// Variable
|
|
$$('.budget-hourly').each(function(ele) { ele.show(); });
|
|
$$('.budget-fixed').each(function(ele) { ele.hide(); });
|
|
}
|
|
|
|
Budget.updateAmounts();
|
|
},
|
|
|
|
// Rails-like number_to_currency currency formatting
|
|
// http://snippets.dzone.com/posts/show/4646
|
|
number_to_currency: function (number, options) {
|
|
try {
|
|
var options = options || {};
|
|
var precision = options["precision"] || 2;
|
|
var unit = options["unit"] || "$";
|
|
var separator = precision > 0 ? options["separator"] || "." : "";
|
|
var delimiter = options["delimiter"] || ",";
|
|
|
|
var parts = parseFloat(number).toFixed(precision).split('.');
|
|
return unit + Budget.number_with_delimiter(parts[0], delimiter) + separator + parts[1].toString();
|
|
} catch(e) {
|
|
return number
|
|
}
|
|
},
|
|
|
|
number_with_delimiter: function (number, delimiter, separator) {
|
|
try {
|
|
var delimiter = delimiter || ",";
|
|
var separator = separator || ".";
|
|
|
|
var parts = number.toString().split('.');
|
|
parts[0] = parts[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1" + delimiter);
|
|
return parts.join(separator);
|
|
} catch(e) {
|
|
return number
|
|
}
|
|
}
|
|
});
|
|
|
|
Budget = new BudgetModule();
|
|
|
|
|
|
</script>
|
|
<% end %>
|