Added ability to define default hourly rates. refs #10617

git-svn-id: https://dev.finn.de/svn/cockpit/trunk@129 7926756e-e54e-46e6-9721-ed318f58905e
pull/6827/head
hjust 15 years ago
parent e8b05659df
commit 78b2179ba2
  1. 30
      app/controllers/hourly_rates_controller.rb
  2. 5
      app/models/default_hourly_rate.rb
  3. 13
      app/models/hourly_rate.rb
  4. 27
      app/views/hourly_rates/_list.rhtml
  5. 25
      app/views/hourly_rates/_list_default.rhtml
  6. 20
      app/views/hourly_rates/_list_project.rhtml
  7. 7
      app/views/hourly_rates/edit.rhtml
  8. 1
      app/views/hourly_rates/show.rhtml
  9. 6
      app/views/users/_rates.rhtml
  10. 4
      lang/en.yml
  11. 66
      lib/user_patch.rb

@ -9,11 +9,11 @@ class HourlyRatesController < ApplicationController
before_filter :find_user, :only => [:show, :edit, :set_rate]
before_filter :find_optional_project, :only => [:show]
before_filter :find_project, :only => [:edit, :set_rate]
before_filter :find_optional_project, :only => [:show, :edit]
before_filter :find_project, :only => [:set_rate]
# #show has its own authorization
before_filter :authorize, :except => [:show]
# #show and #edit have their own authorization
before_filter :authorize, :except => [:show, :edit]
def show
if @project
@ -24,11 +24,14 @@ class HourlyRatesController < ApplicationController
:order => "#{HourlyRate.table_name}.valid_from desc")
else
@rates = HourlyRate.history_for_user(@user, true)
@rates_default = @rates.delete(nil)
render_403 and return if @rates.empty?
end
end
def edit
render_403 and return if @project && !User.current.allowed_to?(:change_rates, @project)
if params[:user].is_a?(Hash)
new_attributes = params[:user][:new_rate_attributes]
existing_attributes = params[:user][:existing_rate_attributes]
@ -41,10 +44,21 @@ class HourlyRatesController < ApplicationController
if request.post? && @user.save
flash[:notice] = l(:notice_successful_update)
redirect_back_or_default(:action => 'show', :id => @user, :project_id => @project)
if @project.nil?
redirect_back_or_default(:action => 'show', :id => @user)
else
redirect_back_or_default(:action => 'show', :id => @user, :project_id => @project)
end
else
@rates = @user.rates.select{|r| r.project_id == @project.id}.sort { |a,b| b.valid_from <=> a.valid_from }
@rates << @user.rates.build({:valid_from => Date.today, :project_id => @project}) if @rates.empty?
if @project.nil?
@rates = DefaultHourlyRate.find(:all,
:conditions => {:user_id => @user},
:order => "#{DefaultHourlyRate.table_name}.valid_from desc")
@rates << @user.default_rates.build({:valid_from => Date.today}) if @rates.empty?
else
@rates = @user.rates.select{|r| r.project_id == @project.id}.sort { |a,b| b.valid_from <=> a.valid_from }
@rates << @user.rates.build({:valid_from => Date.today, :project_id => @project}) if @rates.empty?
end
render :action => "edit", :layout => !request.xhr?
end
end
@ -79,7 +93,7 @@ private
end
def find_optional_project
@project = Project.find(params[:project_id]) unless params[:project_id].blank?
@project = params[:project_id].blank? ? nil : Project.find(params[:project_id])
rescue ActiveRecord::RecordNotFound
render_404
end

@ -0,0 +1,5 @@
class DefaultHourlyRate < Rate
belongs_to :user
end

@ -2,18 +2,23 @@ class HourlyRate < Rate
belongs_to :user
belongs_to :project
def self.history_for_user(user, for_display = true)
def self.history_for_user(usr, for_display = true)
rates = Hash.new
user.projects.each do |project|
usr.projects.each do |project|
next unless (!for_display ||
User.current.allowed_to?(:view_all_rates, project) ||
user == User.current && User.current.allowed_to?(:view_own_rate, project)
usr == User.current && User.current.allowed_to?(:view_own_rate, project)
)
rates[project] = HourlyRate.find(:all,
:conditions => { :user_id => user, :project_id => project },
:conditions => { :user_id => usr, :project_id => project },
:order => "#{HourlyRate.table_name}.valid_from desc")
end
rates[nil] = DefaultHourlyRate.find(:all,
:conditions => { :user_id => usr},
:order => "#{DefaultHourlyRate.table_name}.valid_from desc")
rates
end
end

@ -1,28 +1,3 @@
<% @rates.each_pair do |project, rates| %>
<% @project = project %>
<div class="contextual">
<%= link_to_if_authorized l(:button_update), {:controller => 'hourly_rates', :action => 'edit', :project_id => project, :id => @user}, :class => 'icon icon-edit', :accesskey => accesskey(:edit) %>
</div>
<h3><%=h project.name %></h3>
<% if rates.empty? %>
<p class="nodata"><%= l(:label_no_data) %></p>
<% else %>
<table class="list rates">
<thead><tr>
<th><%= l(:caption_valid_from) %></th>
<th class="currency"><%= l(:caption_rate) %></th>
<th><%= l(:caption_current_rate) %></th>
</tr></thead>
<tbody id="rates_body">
<% current_rate = @user.current_rate(project) %>
<%- rates.each do |rate| -%>
<tr class="<%= cycle('odd', 'even') %>">
<td><%= rate.valid_from %></td>
<td class="currency"><%= number_to_currency(rate.rate) %></td>
<td><%= rate == current_rate ? image_tag('true.png') : "" %></td>
</tr>
<%- end -%>
</tbody>
</table>
<% end %>
<%= render :partial => 'hourly_rates/list_project', :locals => {:rates => rates, :project => project} %>
<% end %>

@ -0,0 +1,25 @@
<div class="contextual">
<%= link_to l(:button_update), {:controller => 'hourly_rates', :action => 'edit', :id => @user}, :class => 'icon icon-edit', :accesskey => accesskey(:edit) %>
</div>
<h3><%= l(:caption_default_rates) %></h3>
<% if @rates_default.blank? %>
<p class="nodata"><%= l(:label_no_data) %></p>
<% else %>
<table class="list rates">
<thead><tr>
<th><%= l(:label_valid_from) %></th>
<th class="currency"><%= l(:label_rate) %></th>
<th><%= l(:caption_current_rate) %></th>
</tr></thead>
<tbody id="rates_body">
<% current_rate = @user.current_default_rate() %>
<%- @rates_default.each do |rate| -%>
<tr class="<%= cycle('odd', 'even') %>">
<td style="padding-right: 1em;"><%= rate.valid_from %></td>
<td class="currency"><%= number_to_currency(rate.rate) %></td>
<td><%= rate == current_rate ? image_tag('true.png') : "" %></td>
</tr>
<%- end -%>
</tbody>
</table>
<% end %>

@ -1,20 +1,30 @@
<%
rates = @rates unless rates
project = @project unless project
%>
<div class="contextual">
<%= link_to_if_authorized l(:button_update), {:controller => 'hourly_rates', :action => 'edit', :project_id => @project, :id => @user}, :class => 'icon icon-edit', :accesskey => accesskey(:edit) %>
<% if project && User.current.allowed_to?({:controller => 'hourly_rates', :action => 'edit'}, project) %>
<%= link_to l(:button_update), {:controller => 'hourly_rates', :action => 'edit', :project_id => project, :id => @user}, :class => 'icon icon-edit', :accesskey => accesskey(:edit) %>
<% end %>
</div>
<h3><%=h @project.name %></h3>
<% if @rates.empty? %>
<h3><%=h project.name %></h3>
<% if rates.empty? %>
<p class="nodata"><%= l(:label_no_data) %></p>
<% else %>
<table class="list rates" style="width:auto">
<table class="list rates">
<thead><tr>
<th><%= l(:label_valid_from) %></th>
<th class="currency"><%= l(:label_rate) %></th>
<th><%= l(:caption_current_rate) %></th>
</tr></thead>
<tbody id="rates_body">
<%- @rates.each do |rate| -%>
<% current_rate = @user.current_rate(project, false) %>
<%- rates.each do |rate| -%>
<tr class="<%= cycle('odd', 'even') %>">
<td style="padding-right: 1em;"><%= rate.valid_from %></td>
<td class="currency"><%= number_to_currency(rate.rate) %></td>
<td><%= rate == current_rate ? image_tag('true.png') : "" %></td>
</tr>
<%- end -%>
</tbody>

@ -1,4 +1,9 @@
<h2><%= l(:caption_rate_history_for, @user.name) %></h2>
<h2><%= @project.nil? ? l(:caption_default_rate_history_for, @user.name) : l(:caption_rate_history_for_project, @user.name, @project.name) %></h2>
<%- default_rate = @user.current_default_rate -%>
<% if default_rate%>
<p><strong><%= l(:label_current_default_rate) %>:</strong> <%= number_to_currency(default_rate.rate)%></p>
<% end %>
<% javascript_tag do -%>
RatesForm = new Subform('<%= escape_javascript(render(:partial => "rate", :object => HourlyRate.new )) %>',<%= @rates.length %>,'rates_body');

@ -3,6 +3,7 @@
<% if @project %>
<%= render :partial => 'list_project' %>
<% else %>
<%= render :partial => 'list_default' %>
<%= render :partial => 'list' %>
<% end %>

@ -1,6 +1,10 @@
<h2><%= l(:caption_rate_history) %></h2>
<%
@rates = HourlyRate.history_for_user(@user)
@rates_default = @rates.delete(nil)
%>
<% @rates = HourlyRate.history_for_user(@user) %>
<%= render :partial => 'hourly_rates/list_default' %>
<%= render :partial => 'hourly_rates/list' %>
<% content_for :header_tags do %>

@ -47,6 +47,7 @@ label_valid_from: "Valid from"
label_fixed_date: "Fixed date"
label_rate: "Rate"
label_rate_plural: "Rates"
label_current_default_rate: "Current default rate"
label_include_deleted: "Include deleted"
label_deleted_cost_types: "Deleted Cost Types"
@ -76,6 +77,8 @@ caption_current_rate: "Current Rate"
caption_rate: "Rate"
caption_rate_history: "Rate History"
caption_rate_history_for: "Rate History for %s"
caption_rate_history_for_project: "Rate History for %s in Project %s"
caption_default_rate_history_for: "Default Rate History for %s"
caption_budget_ratio: "Spent Budget"
caption_labor_budget: "Labor Budget"
caption_material_budget: "Material Budget"
@ -91,6 +94,7 @@ caption_default: "Default"
caption_deleted_at: "Deleted on"
caption_set_rate: "Set Current Rate"
caption_valid_from: "Valid from"
caption_default_rates: "Default Rates"
field_cost_type: "Cost type"
field_unit_price: "Unit price"

@ -12,6 +12,8 @@ module UserPatch
base.class_eval do
unloadable
has_many :rates, :class_name => 'HourlyRate'
has_many :default_rates, :class_name => 'DefaultHourlyRate'
after_update :save_rates
end
@ -22,38 +24,49 @@ module UserPatch
end
module InstanceMethods
def current_rate(project_id)
rate_at(Date.today, project_id)
def current_rate(project_id, include_default = true)
rate_at(Date.today, project_id, include_default)
end
def rate_at(date, project_id)
HourlyRate.find(:first, :conditions => [ "user_id = ? and project_id = ? and valid_from <= ?", id, project_id, date], :order => "valid_from DESC")
def rate_at(date, project_id, include_default = true)
rate = HourlyRate.find(:first, :conditions => [ "user_id = ? and project_id = ? and valid_from <= ?", id, project_id, date], :order => "valid_from DESC")
rate ||= default_rate_at(date) if include_default
rate
end
def current_default_rate()
default_rate_at(Date.today)
end
def default_rate_at(date)
DefaultHourlyRate.find(:first, :conditions => [ "user_id = ? and valid_from <= ?", id, date], :order => "valid_from DESC")
end
def add_rates(project, rate_attributes)
# set project to nil to set the default rates
return unless rate_attributes
rate_attributes.each do |index, attributes|
attributes[:rate] = Rate.clean_currency(attributes[:rate])
attributes[:project] = project
rates.build(attributes) if attributes[:rate].to_f > 0
if project.nil?
default_rates.build(attributes) if attributes[:rate].to_f > 0
else
attributes[:project] = project
rates.build(attributes) if attributes[:rate].to_f > 0
end
end
end
def set_existing_rates (project, rate_attributes)
rates.reject(&:new_record?).reject{|r| r.project_id != project.id}.each do |rate|
attributes = rate_attributes[rate.id.to_s]
has_rate = false
if attributes && attributes[:rate]
attributes[:rate] = Rate.clean_currency(attributes[:rate])
has_rate = attributes[:rate].to_f > 0
if project.nil?
default_rates.reject(&:new_record?).each do |rate|
update_rate(rate, rate_attributes, false)
end
if has_rate
rate.attributes = attributes
else
rates.delete(rate)
else
rates.reject{|r| r.new_record? || r.project_id != project.id}.each do |rate|
update_rate(rate, rate_attributes, true)
end
end
end
@ -64,5 +77,22 @@ module UserPatch
end
end
private
def update_rate(rate, rate_attributes, project_rate = true)
attributes = rate_attributes[rate.id.to_s] if rate_attributes
has_rate = false
if attributes && attributes[:rate]
attributes[:rate] = Rate.clean_currency(attributes[:rate])
has_rate = attributes[:rate].to_f > 0
end
if has_rate
rate.attributes = attributes
else
project_rate ? rates.delete(rate) : default_rates.delete(rate)
end
end
end
end

Loading…
Cancel
Save