From 6c8dd60912679f4292e4791ceb23b048b5906e05 Mon Sep 17 00:00:00 2001 From: david Date: Tue, 3 Jan 2012 21:11:44 +0000 Subject: [PATCH] Modificado todo git-svn-id: https://192.168.0.254/svn/Rodax.redmine_rodax_crm/trunk@4 ff88604e-da85-c949-a72f-fc3aa3ba3724 --- .../contract_categories_controller.rb | 68 +++++ .../contract_contacts_controller.rb | 56 ++++ .../contract_statuses_controller.rb | 63 +++++ app/controllers/contracts_controller.rb | 247 ++++++++++++++++++ app/controllers/contracts_tasks_controller.rb | 121 +++++++++ app/helpers/contacts_helper.rb | 5 + app/helpers/contract_contacts_helper.rb | 2 + app/helpers/contract_statuses_helper.rb | 2 + app/helpers/contracts_helper.rb | 104 ++++++++ app/models/contact.rb | 10 + app/views/common/_sidebar.html.erb | 4 + app/views/contacts/context_menu.html.erb | 4 +- app/views/contacts/index.html.erb | 2 +- app/views/contacts/show.api.rsb | 16 ++ app/views/contacts/show.html.erb | 4 +- app/views/contract_categories/_form.html.erb | 5 + .../contract_categories/destroy.html.erb | 15 ++ app/views/contract_categories/edit.html.erb | 6 + app/views/contract_categories/index.html.erb | 1 + app/views/contract_categories/new.html.erb | 6 + .../contract_contacts/_contacts.html.erb | 36 +++ app/views/contract_statuses/_form.html.erb | 35 +++ app/views/contract_statuses/edit.html.erb | 6 + app/views/contract_statuses/index.html.erb | 35 +++ app/views/contract_statuses/new.html.erb | 6 + app/views/contracts/_attributes.html.erb | 14 + .../contracts/_contracts_statistics.html.erb | 26 ++ .../contracts/_custom_field_filter.html.erb | 5 + .../contracts/_custom_field_form.html.erb | 3 + app/views/contracts/_form.html.erb | 38 +++ app/views/contracts/_list.html.erb | 54 ++++ .../contracts/_related_contracts.html.erb | 28 ++ app/views/contracts/bulk_edit.html.erb | 80 ++++++ app/views/contracts/context_menu.html.erb | 46 ++++ app/views/contracts/edit.html.erb | 6 + app/views/contracts/index.html.erb | 100 +++++++ app/views/contracts/new.html.erb | 6 + app/views/contracts/show.html.erb | 94 +++++++ app/views/layouts/contacts_base.html.erb | 2 + .../my/blocks/_my_contacts_stats.html.erb | 20 +- app/views/my/blocks/_my_contracts.html.erb | 32 +++ .../projects/_contacts_settings.html.erb | 8 +- .../projects/_contract_statuses.html.erb | 28 ++ .../projects/_contracts_settings.html.erb | 28 ++ app/views/projects/settings.rhtml | 4 + .../_contacts_contract_statuses.html.erb | 34 +++ assets/stylesheets/contacts.css | 24 +- config/locales/en.yml | 37 ++- config/locales/es.yml | 65 ++++- config/routes.rb | 16 ++ db/migrate/034_create_contacts_contracts.rb | 14 + init.rb | 24 +- .../hooks/views_custom_fields_hook.rb | 1 + lib/redmine_contacts/patches/project_patch.rb | 3 + .../contract_categories_controller_test.rb | 8 + .../contract_contacts_controller_test.rb | 8 + .../contract_statuses_controller_test.rb | 8 + test/functional/contracts_controller_test.rb | 8 + 58 files changed, 1713 insertions(+), 18 deletions(-) create mode 100644 app/controllers/contract_categories_controller.rb create mode 100644 app/controllers/contract_contacts_controller.rb create mode 100644 app/controllers/contract_statuses_controller.rb create mode 100644 app/controllers/contracts_controller.rb create mode 100644 app/controllers/contracts_tasks_controller.rb create mode 100644 app/helpers/contract_contacts_helper.rb create mode 100644 app/helpers/contract_statuses_helper.rb create mode 100644 app/helpers/contracts_helper.rb create mode 100644 app/views/contract_categories/_form.html.erb create mode 100644 app/views/contract_categories/destroy.html.erb create mode 100644 app/views/contract_categories/edit.html.erb create mode 100644 app/views/contract_categories/index.html.erb create mode 100644 app/views/contract_categories/new.html.erb create mode 100644 app/views/contract_contacts/_contacts.html.erb create mode 100644 app/views/contract_statuses/_form.html.erb create mode 100644 app/views/contract_statuses/edit.html.erb create mode 100644 app/views/contract_statuses/index.html.erb create mode 100644 app/views/contract_statuses/new.html.erb create mode 100644 app/views/contracts/_attributes.html.erb create mode 100644 app/views/contracts/_contracts_statistics.html.erb create mode 100644 app/views/contracts/_custom_field_filter.html.erb create mode 100644 app/views/contracts/_custom_field_form.html.erb create mode 100644 app/views/contracts/_form.html.erb create mode 100644 app/views/contracts/_list.html.erb create mode 100644 app/views/contracts/_related_contracts.html.erb create mode 100644 app/views/contracts/bulk_edit.html.erb create mode 100644 app/views/contracts/context_menu.html.erb create mode 100644 app/views/contracts/edit.html.erb create mode 100644 app/views/contracts/index.html.erb create mode 100644 app/views/contracts/new.html.erb create mode 100644 app/views/contracts/show.html.erb create mode 100644 app/views/my/blocks/_my_contracts.html.erb create mode 100644 app/views/projects/_contract_statuses.html.erb create mode 100644 app/views/projects/_contracts_settings.html.erb create mode 100644 app/views/settings/_contacts_contract_statuses.html.erb create mode 100644 db/migrate/034_create_contacts_contracts.rb create mode 100644 test/functional/contract_categories_controller_test.rb create mode 100644 test/functional/contract_contacts_controller_test.rb create mode 100644 test/functional/contract_statuses_controller_test.rb create mode 100644 test/functional/contracts_controller_test.rb diff --git a/app/controllers/contract_categories_controller.rb b/app/controllers/contract_categories_controller.rb new file mode 100644 index 0000000..6d1e72e --- /dev/null +++ b/app/controllers/contract_categories_controller.rb @@ -0,0 +1,68 @@ +class ContractCategoriesController < ApplicationController + unloadable + menu_item :settings + model_object ContractCategory + before_filter :find_model_object, :except => :new + before_filter :find_project_from_association, :except => :new + before_filter :find_project_by_project_id, :only => :new + before_filter :authorize + + verify :method => :post, :only => :destroy + + def new + @category = @project.contract_categories.build(params[:category]) + if request.post? + if @category.save + respond_to do |format| + format.html do + flash[:notice] = l(:notice_successful_create) + redirect_to :controller => 'projects', :action => 'settings', :tab => 'contacts', :id => @project + end + format.js do + # IE doesn't support the replace_html rjs method for select box options + render(:update) {|page| page.replace "contract_category_id", + content_tag('select', '' + options_from_collection_for_select(@project.contract_categories, 'id', 'name', @category.id), :id => 'contract_category_id', :name => 'contract[category_id]') + } + end + end + else + respond_to do |format| + format.html + format.js do + render(:update) {|page| page.alert(@category.errors.full_messages.join('\n')) } + end + end + end + end + end + + def edit + if request.post? and @category.update_attributes(params[:category]) + flash[:notice] = l(:notice_successful_update) + redirect_to :controller => 'projects', :action => 'settings', :tab => 'contacts', :id => @project + end + end + + def destroy + @contract_count = @category.contracts.size + if @contract_count == 0 + # No contract assigned to this category + @category.destroy + redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'contacts' + elsif params[:todo] + reassign_to = @project.contract_categories.find_by_id(params[:reassign_to_id]) if params[:todo] == 'reassign' + @category.destroy(reassign_to) + redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'contacts' + end + @categories = @project.contract_categories - [@category] + end + + private + # Wrap ApplicationController's find_model_object method to set + # @category instead of just @contract_category + def find_model_object + super + @category = @object + @project = @category.project + end +end diff --git a/app/controllers/contract_contacts_controller.rb b/app/controllers/contract_contacts_controller.rb new file mode 100644 index 0000000..e0891e4 --- /dev/null +++ b/app/controllers/contract_contacts_controller.rb @@ -0,0 +1,56 @@ +class ContractContactsController < ApplicationController + unloadable + + before_filter :find_project_by_project_id, :authorize + before_filter :find_contact, :only => :delete + before_filter :find_contract + + helper :contracts + + def add + @show_form = "true" + + if params[:contact_id] && request.post? then + find_contact + if !@contract.all_contacts.include?(@contact) + @contract.related_contacts << @contact + @contract.save + end + end + + respond_to do |format| + format.html { redirect_to :back } + format.js do + render :update do |page| + page.replace_html 'contract_contacts', :partial => 'contract_contacts/contacts' + end + end + end + end + + def delete + @contract.related_contacts.delete(@contact) + respond_to do |format| + format.html { redirect_to :back } + format.js do + render :update do |page| + page.replace_html 'contract_contacts', :partial => 'contract_contacts/contacts' + end + end + end + end + + + private + def find_contact + @contact = Contact.find(params[:contact_id]) + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_contract + @contract = Contract.find(params[:contract_id]) + rescue ActiveRecord::RecordNotFound + render_404 + end +end \ No newline at end of file diff --git a/app/controllers/contract_statuses_controller.rb b/app/controllers/contract_statuses_controller.rb new file mode 100644 index 0000000..349fa53 --- /dev/null +++ b/app/controllers/contract_statuses_controller.rb @@ -0,0 +1,63 @@ +class ContractStatusesController < ApplicationController + unloadable + + layout 'admin' + + before_filter :require_admin, :except => :assing_to_project + before_filter :find_project_by_project_id, :authorize, :only => :assing_to_project + + verify :method => :post, :only => [ :destroy, :create, :update, :move ], + :redirect_to => { :action => :index } + + def index + @contract_status_pages, @contract_statuses = paginate :contract_statuses, :per_page => 25, :order => "position" + render :action => "index", :layout => false if request.xhr? + end + + def new + @contract_status = ContractStatus.new + end + + def create + @contract_status = ContractStatus.new(params[:contract_status]) + if @contract_status.save + flash[:notice] = l(:notice_successful_create) + redirect_to :action =>"plugin", :id => "contacts", :controller => "settings", :tab => 'contract_statuses' + else + render :action => 'new' + end + end + + def edit + @contract_status = ContractStatus.find(params[:id]) + end + + def update + @contract_status = ContractStatus.find(params[:id]) + if @contract_status.update_attributes(params[:contract_status]) + flash[:notice] = l(:notice_successful_update) + redirect_to :action =>"plugin", :id => "contacts", :controller => "settings", :tab => 'contract_statuses' + else + render :action => 'edit' + end + end + + def destroy + ContractStatus.find(params[:id]).destroy + redirect_to :action =>"plugin", :id => "contacts", :controller => "settings", :tab => 'contract_statuses' + rescue + flash[:error] = l(:error_unable_delete) + redirect_to :action =>"plugin", :id => "contacts", :controller => "settings", :tab => 'contract_statuses' + end + + def assing_to_project + + if request.put? + @project.contract_statuses = !params[:contract_statuses].blank? ? ContractStatus.find(params[:contract_statuses]) : [] + @project.save + flash[:notice] = l(:notice_successful_update) + end + redirect_to :controller => 'projects', :action => 'settings', :tab => 'contracts', :id => @project + end + +end diff --git a/app/controllers/contracts_controller.rb b/app/controllers/contracts_controller.rb new file mode 100644 index 0000000..453695b --- /dev/null +++ b/app/controllers/contracts_controller.rb @@ -0,0 +1,247 @@ +class ContractsController < ApplicationController + unloadable + + PRICE_TYPE_PULLDOWN = [l(:label_price_fixed_bid), l(:label_price_per_hour)] + + before_filter :find_contract, :only => [:show, :edit, :update, :destroy] + before_filter :find_project_by_project_id, :only => [:new, :create] + before_filter :bulk_find_contracts, :only => [:bulk_update, :bulk_edit, :bulk_destroy, :context_menu] + before_filter :authorize, :except => [:index] + before_filter :find_optional_project, :only => [:index] + # before_filter :find_contracts, :only => :index + before_filter :update_contract_from_params, :only => [:edit, :update] + before_filter :build_new_contract_from_params, :only => [:new, :create] + before_filter :find_contract_attachments, :only => :show + + helper :attachments + helper :contacts + helper :notes + helper :timelog + helper :watchers + helper :custom_fields + include WatchersHelper + include ContractsHelper + + def new + @contract = Contract.new + @contract.contact = Contact.find(params[:contact_id]) if params[:contact_id] + @contract.assigned_to = User.current + end + + def create + @contract = Contract.new(params[:contract]) + # @contract.contacts = [Contact.find(params[:contacts])] + @contract.project = @project + @contract.author = User.current + @contract.init_contract_process(User.current) + if @contract.save + flash[:notice] = l(:notice_successful_create) + redirect_to :action => "show", :id => @contract + else + render :action => "new" + end + end + + def update + @contract.init_contract_process(User.current) + if @contract.update_attributes(params[:contract]) + # @contract.contacts = [Contact.find(params[:contacts])] if params[:contacts] + flash[:notice] = l(:notice_successful_update) + respond_to do |format| + format.html { redirect_to :action => "show", :id => @contract } + format.xml { } + end + else + respond_to do |format| + format.html { render :action => "edit"} + end + end + + end + + def edit + respond_to do |format| + format.html { } + format.xml { } + end + end + + def index + retrieve_contracts_query + params[:status_id] = "o" unless params.has_key?(:status_id) + find_contracts + respond_to do |format| + format.html{ request.xhr? ? render( :partial => "list", :layout => false, :locals => {:contracts => @contracts}) : last_notes } + format.xml { render :xml => @contracts} + format.json { render :text => @contracts.to_json, :layout => false } + end + end + + def show + @note = ContractNote.new + respond_to do |format| + format.html { @contract.viewed } + format.xml { } + end + end + + def destroy + if @contract.destroy + flash[:notice] = l(:notice_successful_delete) + else + flash[:error] = l(:notice_unsuccessful_save) + end + redirect_to :action => "index", :project_id => params[:project_id] + + end + + def context_menu + @contract = @contracts.first if (@contracts.size == 1) + @can = {:edit => User.current.allowed_to?(:edit_contracts, @projects), + :delete => User.current.allowed_to?(:delete_contracts, @projects) + } + + # @back = back_url + render :layout => false + end + + def bulk_destroy + @contracts.each do |contract| + begin + contract.reload.destroy + rescue ::ActiveRecord::RecordNotFound # raised by #reload if issue no longer exists + # nothing to do, issue was already deleted (eg. by a parent) + end + end + respond_to do |format| + format.html { redirect_back_or_default(:action => 'index', :project_id => @project) } + format.api { head :ok } + end + end + + def bulk_edit + @available_statuses = @projects.map(&:contract_statuses).inject{|memo,w| memo & w} + @available_categories = @projects.map(&:contract_categories).inject{|memo,w| memo & w} + @assignables = @projects.map(&:assignable_users).inject{|memo,a| memo & a} + end + + + def bulk_update + unsaved_contract_ids = [] + @contracts.each do |contract| + contract.reload + contract.init_contract_process(User.current) + unless contract.update_attributes(parse_params_for_bulk_contract_attributes(params)) + # Keep unsaved issue ids to display them in flash error + unsaved_contract_ids << contract.id + end + if params[:note] && !params[:note][:content].blank? + note = ContractNote.new(params[:note]) + note.author = User.current + contract.notes << note + end + + end + set_flash_from_bulk_issue_save(@contracts, unsaved_contract_ids) + redirect_back_or_default({:controller => 'contracts', :action => 'index', :project_id => @project}) + + end + + private + + def last_notes(count=5) + # TODO: ????????? ???????? ???? ? ???????? ??? ? ?????? acts-as-noteble + scope = ContractNote.scoped({}) + scope = scope.scoped(:conditions => ["#{Contract.table_name}.project_id = ?", @project.id]) if @project + + @last_notes = scope.visible.find(:all, + :limit => count, + :order => "#{ContractNote.table_name}.created_on DESC") + end + + + def build_new_contract_from_params + end + + def update_contract_from_params + end + + def find_contract_attachments + @contract_attachments = Attachment.find(:all, + :conditions => { :container_type => "Note", :container_id => @contract.notes.map(&:id)}, + :order => "created_on DESC") + end + + + def find_contracts(pages=true) + retrieve_date_range(params[:period].to_s) + + scope = Contract.scoped({}) + scope = scope.scoped(:conditions => ["#{Contract.table_name}.project_id = ?", @project.id]) if @project + scope = scope.scoped(:conditions => ["#{Contract.table_name}.status_id = ?", params[:status_id]]) if (!params[:status_id].blank? && params[:status_id] != "o") + scope = scope.scoped(:conditions => ["#{Contract.table_name}.category_id = ?", params[:category_id]]) if !params[:category_id].blank? + scope = scope.scoped(:conditions => ["#{Contract.table_name}.assigned_to_id = ?", params[:assigned_to_id]]) if !params[:assigned_to_id].blank? + scope = scope.scoped(:conditions => ["#{Contract.table_name}.created_on BETWEEN ? AND ?", @from, @to]) if (@from && @to) + + params[:search].split(' ').collect{ |search_string| scope = scope.live_search(search_string) } if !params[:search].blank? + scope = scope.visible + scope = scope.scoped(:include => :status, :conditions => ["#{ContractStatus.table_name}.is_closed = ?", false]) if (params[:status_id] == "o") + scope = scope.scoped(:order => :status_id) + + + @contracts_count = scope.count + + if pages + @contracts_sum = scope.sum(:price, :group => :currency) + + page_size = params[:page_size].blank? ? 20 : params[:page_size].to_i + @contracts_pages = Paginator.new(self, @contracts_count, page_size, params[:page]) + @offset = @contracts_pages.current.offset + @limit = @contracts_pages.items_per_page + + scope = scope.scoped :limit => @limit, :offset => @offset + @contracts = scope + + fake_name = @contracts.first.price if @contracts.length > 0 #without this patch paging does not work + end + + scope + + end + + # Filter for bulk issue operations + def bulk_find_contracts + @contracts = Contract.find_all_by_id(params[:id] || params[:ids], :include => :project) + raise ActiveRecord::RecordNotFound if @contracts.empty? + if @contracts.detect {|contract| !contract.visible?} + deny_access + return + end + @projects = @contracts.collect(&:project).compact.uniq + @project = @projects.first if @projects.size == 1 + rescue ActiveRecord::RecordNotFound + render_404 + end + + + def find_contract + @contract = Contract.find(params[:id], :include => [:project, :status, :category]) + @project ||= @contract.project + # if !(params[:project_id] == @project.identifier) + # params[:project_id] = @project.identifier + # redirect_to params + # end + rescue ActiveRecord::RecordNotFound + render_404 + end + + def parse_params_for_bulk_contract_attributes(params) + attributes = (params[:contract] || {}).reject {|k,v| v.blank?} + attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'} + attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values] + attributes + end + + + +end diff --git a/app/controllers/contracts_tasks_controller.rb b/app/controllers/contracts_tasks_controller.rb new file mode 100644 index 0000000..3150bed --- /dev/null +++ b/app/controllers/contracts_tasks_controller.rb @@ -0,0 +1,121 @@ +class ContractsTasksController < ApplicationController + unloadable + + before_filter :find_project_by_project_id, :authorize, :except => [:index] + before_filter :find_optional_project, :only => :index + before_filter :find_contract, :except => [:index, :add, :close] + before_filter :find_issue, :except => [:index, :new] + + def index + cond = "(1=1)" + # cond = "issues.assigned_to_id = #{User.current.id}" + cond << " and issues.project_id = #{@project.id}" if @project + cond << " and (issues.assigned_to_id = #{params[:assigned_to]})" unless params[:assigned_to].blank? + + @contracts_issues = Issue.visible.find(:all, + :joins => "INNER JOIN contracts_issues ON issues.id = contracts_issues.issue_id", + # :group => :issue_id, + :conditions => cond, + :order => "issues.due_date") + @users = assigned_to_users + end + + def new + issue = Issue.new + issue.subject = params[:task_subject] + issue.project = @project + issue.tracker_id = params[:task_tracker] + issue.author = User.current + issue.due_date = params[:due_date] + issue.assigned_to_id = params[:assigned_to] + issue.description = params[:task_description] + issue.status = IssueStatus.default + if issue.save + flash[:notice] = l(:notice_successful_add) + @contract.issues << issue + @contract.save + redirect_to :back + return + else + redirect_to :back + end + end + + + def add + @show_form = "true" + + if params[:contract_id] && request.post? then + find_contract + @contract.issues << @issue + @contract.save + end + + respond_to do |format| + format.html { redirect_to :back } + format.js do + render :update do |page| + page.replace_html 'issue_contracts', :partial => 'issues/contracts' + end + end + end + end + + def delete + @issue.contracts.delete(@contract) + respond_to do |format| + format.html { redirect_to :back } + format.js do + render :update do |page| + page.replace_html 'issue_contracts', :partial => 'issues/contracts' + end + end + end + end + + def close + @issue.status = IssueStatus.find(:first, :conditions => { :is_closed => true }) + @issue.save + respond_to do |format| + format.js do + render :update do |page| + page["issue_#{params[:issue_id]}"].visual_effect :fade + end + end + format.html {redirect_to :back } + end + + end + + private + + def find_contract + @contract = Contract.find(params[:contract_id]) + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_issue + @issue = Issue.find(params[:issue_id]) + rescue ActiveRecord::RecordNotFound + render_404 + end + + def assigned_to_users + user_values = [] + project = @project + user_values << ["<< #{l(:label_all)} >>", ""] + user_values << ["<< #{l(:label_me)} >>", User.current.id] if User.current.logged? + if project + user_values += project.users.sort.collect{|s| [s.name, s.id.to_s] } + else + project_ids = Project.all(:conditions => Project.visible_condition(User.current)).collect(&:id) + if project_ids.any? + # members of the user's projects + user_values += User.active.find(:all, :conditions => ["#{User.table_name}.id IN (SELECT DISTINCT user_id FROM members WHERE project_id IN (?))", project_ids]).sort.collect{|s| [s.name, s.id.to_s] } + end + end + end + + +end \ No newline at end of file diff --git a/app/helpers/contacts_helper.rb b/app/helpers/contacts_helper.rb index 968af0f..ba79381 100644 --- a/app/helpers/contacts_helper.rb +++ b/app/helpers/contacts_helper.rb @@ -74,6 +74,11 @@ module ContactsHelper return {:controller => 'deals', :action => 'show', :id => deal.id } end + def contract_url(contract) + return {:controller => 'contracts', :action => 'show', :id => contract.id } + end + + def note_source_url(note_source) polymorphic_url(note_source) # return {:controller => note_source.class.name.pluralize.downcase, :action => 'show', :project_id => @project, :id => note_source.id } diff --git a/app/helpers/contract_contacts_helper.rb b/app/helpers/contract_contacts_helper.rb new file mode 100644 index 0000000..13686d4 --- /dev/null +++ b/app/helpers/contract_contacts_helper.rb @@ -0,0 +1,2 @@ +module ContractContactsHelper +end diff --git a/app/helpers/contract_statuses_helper.rb b/app/helpers/contract_statuses_helper.rb new file mode 100644 index 0000000..b4c38f5 --- /dev/null +++ b/app/helpers/contract_statuses_helper.rb @@ -0,0 +1,2 @@ +module ContractStatusesHelper +end diff --git a/app/helpers/contracts_helper.rb b/app/helpers/contracts_helper.rb new file mode 100644 index 0000000..83a5dfb --- /dev/null +++ b/app/helpers/contracts_helper.rb @@ -0,0 +1,104 @@ +module ContractsHelper + def collection_for_status_select + contract_statuses.collect{|s| [s.name, s.id.to_s]} + end + + def collection_for_currencies_select + [:en, :de, :'en-GB', :ru].each_with_index.collect{|l, index| [I18n.translate(:'number.currency.format.unit', :locale => l), index]} + end + + def contract_status_options_for_select(select="") + options_for_select(collection_for_status_select, select) + end + + def contracts_sum_to_currency(contracts_sum) + contracts_sum.map{|c| content_tag(:span, contract_price_to_currency(c[1], c[0].to_i), :style => "white-space: nowrap;")}.join(' / ') + end + + def contract_price_to_currency(price, currency) + case currency + when 0 + locale = :en + when 1 + locale = :de + when 2 + locale = :'en-GB' + when 3 + locale = :ru + else + end + + !locale.blank? ? number_to_currency(price, :locale => locale.to_sym, :precision => 2) : number_with_delimiter(price, :delimiter => ' ', :precision => 2) + end + + def contract_price(contract) + contract_price_to_currency(contract.price, contract.currency) + end + + def contract_statuses + (!@project.blank? ? @project.contract_statuses : ContractStatus.all(:order => "position")) || [] + end + + def remove_contractor_link(contact) + link_to_remote(image_tag('delete.png'), + :url => {:controller => "contract_contacts", :action => 'delete', :project_id => @project, :contract_id => @contract, :contact_id => contact}, + :method => :delete, + :confirm => l(:text_are_you_sure), + :html => {:class => "delete", :title => l(:button_delete) }) if User.current.allowed_to?(:edit_contracts, @project) + end + + def retrieve_date_range(period) + @from, @to = nil, nil + case period + when 'today' + @from = @to = Date.today + when 'yesterday' + @from = @to = Date.today - 1 + when 'current_week' + @from = Date.today - (Date.today.cwday - 1)%7 + @to = @from + 6 + when 'last_week' + @from = Date.today - 7 - (Date.today.cwday - 1)%7 + @to = @from + 6 + when '7_days' + @from = Date.today - 7 + @to = Date.today + when 'current_month' + @from = Date.civil(Date.today.year, Date.today.month, 1) + @to = (@from >> 1) - 1 + when 'last_month' + @from = Date.civil(Date.today.year, Date.today.month, 1) << 1 + @to = (@from >> 1) - 1 + when '30_days' + @from = Date.today - 30 + @to = Date.today + when 'current_year' + @from = Date.civil(Date.today.year, 1, 1) + @to = Date.civil(Date.today.year, 12, 31) + end + + @from, @to = @from, @to + 1 if (@from && @to) + + end + + def retrieve_contracts_query + # debugger + # params.merge!(session[:contracts_query]) + # session[:contracts_query] = {:project_id => @project.id, :status_id => params[:status_id], :category_id => params[:category_id], :assigned_to_id => params[:assigned_to_id]} + if params[:status_id] || !params[:period].blank? || !params[:category_id].blank? || !params[:assigned_to_id].blank? + session[:contracts_query] = {:project_id => (@project ? @project.id : nil), + :status_id => params[:status_id], + :category_id => params[:category_id], + :period => params[:period], + :assigned_to_id => params[:assigned_to_id]} + else + if api_request? || params[:set_filter] || session[:contracts_query].nil? || session[:contracts_query][:project_id] != (@project ? @project.id : nil) + session[:contracts_query] = {} + else + params.merge!(session[:contracts_query]) + end + end + end + + +end diff --git a/app/models/contact.rb b/app/models/contact.rb index 69edccb..488f7f5 100644 --- a/app/models/contact.rb +++ b/app/models/contact.rb @@ -12,7 +12,9 @@ class Contact < ActiveRecord::Base belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id' has_and_belongs_to_many :issues, :order => "#{Issue.table_name}.due_date", :uniq => true has_many :deals, :order => "#{Deal.table_name}.status_id", :uniq => true + has_many :contracts, :order => "#{Contract.table_name}.status_id", :uniq => true has_and_belongs_to_many :related_deals, :class_name => 'Deal', :order => "#{Deal.table_name}.status_id", :uniq => true + has_and_belongs_to_many :related_contracts, :class_name => 'Contract', :order => "#{Contract.table_name}.status_id", :uniq => true has_and_belongs_to_many :projects, :uniq => true belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' has_one :avatar, :class_name => "Attachment", :as => :container, :conditions => "#{Attachment.table_name}.description = 'avatar'", :dependent => :destroy @@ -87,10 +89,18 @@ class Contact < ActiveRecord::Base def all_deals @all_deals ||= (self.deals + self.related_deals ).uniq.sort!{|x, y| x.status_id <=> y.status_id } end + + def all_contracts + @all_contracts ||= (self.contracts + self.related_contracts ).uniq.sort!{|x, y| x.status_id <=> y.status_id } + end def all_visible_deals(usr=User.current) @all_deals ||= (self.deals.visible(usr) + self.related_deals.visible(usr)).uniq.sort!{|x, y| x.status_id <=> y.status_id } end + + def all_visible_contracts(usr=User.current) + @all_contracts ||= (self.contracts.visible(usr) + self.related_contracts.visible(usr)).uniq.sort!{|x, y| x.status_id <=> y.status_id } + end def self.available_tags(options = {}) name_like = options[:name_like] diff --git a/app/views/common/_sidebar.html.erb b/app/views/common/_sidebar.html.erb index db564f1..b5e4265 100644 --- a/app/views/common/_sidebar.html.erb +++ b/app/views/common/_sidebar.html.erb @@ -7,6 +7,10 @@ <%= link_to l(:label_deal_plural), { :controller => 'deals', :action => 'index', :project_id => @project} %> | <% end %> +<% if !(@project && !authorize_for(:contracts, :index)) %> +<%= link_to l(:label_contract_plural), { :controller => 'contracts', :action => 'index', :project_id => @project} %> + | +<% end %> <% if !(@project && !authorize_for(:contacts_tasks, :index)) %> <%= link_to l(:label_issue_plural), { :controller => 'contacts_tasks', :action => 'index', :project_id => @project} %> diff --git a/app/views/contacts/context_menu.html.erb b/app/views/contacts/context_menu.html.erb index f3e9dc1..de9b674 100644 --- a/app/views/contacts/context_menu.html.erb +++ b/app/views/contacts/context_menu.html.erb @@ -9,7 +9,9 @@ <% if !@project.nil? %>
  • <%= context_menu_link l(:label_deal_new), {:controller => 'deals', :action => 'new', :project_id => @project, :contact_id => @contact}, :class => 'icon-add-deal', :disabled => !@can[:create_deal] %>
  • - <% if @contact.is_company? %> +
  • <%= context_menu_link l(:label_contract_new), {:controller => 'contracts', :action => 'new', :project_id => @project, :contact_id => @contact}, + :class => 'icon-add-contract', :disabled => !@can[:create_contract] %>
  • + <% if @contact.is_company? %>
  • <%= context_menu_link l(:label_add_employee), {:controller => 'contacts', :action => 'new', :project_id => @project, :contact => {:company => @contact.name}}, :class => 'icon-add-employee', :disabled => !@can[:edit] %>
  • <% end %> diff --git a/app/views/contacts/index.html.erb b/app/views/contacts/index.html.erb index f8fba04..554c4ed 100644 --- a/app/views/contacts/index.html.erb +++ b/app/views/contacts/index.html.erb @@ -42,7 +42,7 @@ <%= select_tag :deal_status_id, options_from_collection_for_select(@project.assignable_users, :id, :name), :onchange => "this.form.submit();" %> - + <% end %> diff --git a/app/views/contacts/show.api.rsb b/app/views/contacts/show.api.rsb index 1c22b23..18d3a92 100644 --- a/app/views/contacts/show.api.rsb +++ b/app/views/contacts/show.api.rsb @@ -79,5 +79,21 @@ api.contact do end end if (@contact.related_deals + @contact.deals).present? && User.current.allowed_to?(:view_deals, @project) + api.array :contracts do + (@contact.related_contracts + @contact.contracts).each do |contract| + api.contract do + api.id contract.id + api.price contract.price + api.currency contract.currency + api.price_type contract.price_type + api.name contract.name + api.project(:id => contract.project.id, :name => contract.project.name) + api.status(:id => contract.status.id, :name => contract.status.name) + api.background contract.background + api.created_on contract.created_on + api.updated_on contract.updated_on + end + end + end if (@contact.related_contracts + @contact.contracts).present? && User.current.allowed_to?(:view_contracts, @project) end diff --git a/app/views/contacts/show.html.erb b/app/views/contacts/show.html.erb index 05d86c8..0febbdd 100644 --- a/app/views/contacts/show.html.erb +++ b/app/views/contacts/show.html.erb @@ -64,7 +64,8 @@ @@ -93,6 +94,7 @@ <%= render :partial => 'common/notes_attachments', :object => @contact.notes_attachments %> <%= call_hook(:view_contacts_sidebar_after_notes_attachments, :contact => @contact) %> <%= render :partial => 'deals/related_deals', :object => @contact.all_visible_deals %> + <%= render :partial => 'contracts/related_contracts', :object => @contact.all_visible_contracts %> <%= render :partial => 'employees' %> <% if !@contact.background.blank? %>

    <%= l(:label_contact_background_info) %>

    diff --git a/app/views/contract_categories/_form.html.erb b/app/views/contract_categories/_form.html.erb new file mode 100644 index 0000000..dd4545d --- /dev/null +++ b/app/views/contract_categories/_form.html.erb @@ -0,0 +1,5 @@ +<%= error_messages_for 'category' %> + +
    +

    <%= f.text_field :name, :size => 30, :required => true %>

    +
    \ No newline at end of file diff --git a/app/views/contract_categories/destroy.html.erb b/app/views/contract_categories/destroy.html.erb new file mode 100644 index 0000000..d6848b4 --- /dev/null +++ b/app/views/contract_categories/destroy.html.erb @@ -0,0 +1,15 @@ +

    <%=l(:label_contract_category)%>: <%=h @category.name %>

    + +<% form_tag({}) do %> +
    +

    <%= l(:text_contract_category_destroy_question, @contract_count) %>

    +


    +<% if @categories.size > 0 %> +: +<%= select_tag 'reassign_to_id', options_from_collection_for_select(@categories, 'id', 'name') %>

    +<% end %> +
    + +<%= submit_tag l(:button_apply) %> +<%= link_to l(:button_cancel), :controller => 'projects', :action => 'settings', :id => @project, :tab => 'contacts' %> +<% end %> \ No newline at end of file diff --git a/app/views/contract_categories/edit.html.erb b/app/views/contract_categories/edit.html.erb new file mode 100644 index 0000000..66f9bf7 --- /dev/null +++ b/app/views/contract_categories/edit.html.erb @@ -0,0 +1,6 @@ +

    <%=l(:label_deal_category)%>

    + +<% labelled_form_for :category, @category, :url => { :action => 'edit', :id => @category } do |f| %> +<%= render :partial => 'contract_categories/form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> \ No newline at end of file diff --git a/app/views/contract_categories/index.html.erb b/app/views/contract_categories/index.html.erb new file mode 100644 index 0000000..8664bb2 --- /dev/null +++ b/app/views/contract_categories/index.html.erb @@ -0,0 +1 @@ +

    ContractCategories#index

    diff --git a/app/views/contract_categories/new.html.erb b/app/views/contract_categories/new.html.erb new file mode 100644 index 0000000..158694f --- /dev/null +++ b/app/views/contract_categories/new.html.erb @@ -0,0 +1,6 @@ +

    <%=l(:label_issue_category_new)%>

    + +<% labelled_form_for :category, @category, :url => { :action => 'new', :project_id => @project } do |f| %> +<%= render :partial => 'contract_categories/form', :locals => { :f => f } %> +<%= submit_tag l(:button_create) %> +<% end %> \ No newline at end of file diff --git a/app/views/contract_contacts/_contacts.html.erb b/app/views/contract_contacts/_contacts.html.erb new file mode 100644 index 0000000..316236a --- /dev/null +++ b/app/views/contract_contacts/_contacts.html.erb @@ -0,0 +1,36 @@ +<% if @contract.all_contacts.any? %> +
    +
    + <%= link_to_remote l(:button_add), + :url => {:controller => 'contract_contacts', + :action => 'add', + :project_id => @project, + :contract_id => @contract} if User.current.allowed_to?({:controller => 'contract_contacts', :action => 'add'}, @project) %> + +
    + +

    <%= l(:label_contractor_plural) %>

    + + <% unless !(@show_form == "true") %> + <% form_remote_tag( + :url => {:controller => 'contract_contacts', + :action => 'add', + :contract_id => @contract, + :project_id => @project}, + :method => :post, + :html => {:id => 'add-contact-form'}) do |f| %> +

    + <%= select_tag :contact_id, options_for_select(@project.contacts.sort!{|x, y| x.name <=> y.name }.collect {|m| [m.name, m.id]}), :prompt => "--- #{l(:actionview_instancetag_blank_option)} ---" %> +
    + <%= submit_tag l(:button_add) %> + <%= toggle_link l(:button_cancel), 'add-contact-form'%> +

    + <% end %> + <% end %> + + <%= render :partial => 'common/contact_data', :object => @contract.contact %> + <% @contract.related_contacts.each do |contact| %> + <%= render :partial => 'common/contact_data', :object => contact, :locals => {:actions => remove_contractor_link(contact)} %> + <% end %> +
    +<% end %> \ No newline at end of file diff --git a/app/views/contract_statuses/_form.html.erb b/app/views/contract_statuses/_form.html.erb new file mode 100644 index 0000000..172c9a9 --- /dev/null +++ b/app/views/contract_statuses/_form.html.erb @@ -0,0 +1,35 @@ +<%= error_messages_for 'contract_status' %> + +
    + +

    +<%= text_field 'contract_status', 'name' %>

    + + +

    +<%= text_field 'contract_status', 'color_name', :class => "colorpicker" %> + +

    + + + +

    +<%= check_box 'contract_status', 'is_closed' %>

    + +

    +<%= check_box 'contract_status', 'is_default' %>

    + +<%= call_hook(:view_contract_statuses_form, :contract_status => @contract_status) %> + + +
    + + + +<% content_for :header_tags do %> + <%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %> + <%= stylesheet_link_tag :contacts, :plugin => 'redmine_contacts' %> +<% end %> diff --git a/app/views/contract_statuses/edit.html.erb b/app/views/contract_statuses/edit.html.erb new file mode 100644 index 0000000..57a87c2 --- /dev/null +++ b/app/views/contract_statuses/edit.html.erb @@ -0,0 +1,6 @@ +

    <%= link_to l(:label_contract_status_plural), :controller => 'contract_statuses', :action => 'index' %> » <%=h @contract_status %>

    + +<% form_tag({:action => 'update', :id => @contract_status}, :class => "tabular") do %> + <%= render :partial => 'form' %> + <%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/contract_statuses/index.html.erb b/app/views/contract_statuses/index.html.erb new file mode 100644 index 0000000..0cdf0f3 --- /dev/null +++ b/app/views/contract_statuses/index.html.erb @@ -0,0 +1,35 @@ +
    +<%= link_to l(:label_contract_status_new), {:action => 'new'}, :class => 'icon icon-add' %> +
    + +

    <%=l(:label_contract_status_plural)%>

    + + + + + + + + + + +<% for status in @contract_statuses %> + "> + + + + + + +<% end %> + +
    <%=l(:field_status)%><%=l(:field_is_default)%><%=l(:field_is_closed)%><%=l(:button_sort)%>
    <%= link_to status.name, :action => 'edit', :id => status %><%= checked_image status.is_default? %><%= checked_image status.is_closed? %><%= reorder_links('contract_status', {:action => 'update', :id => status}) %> + <%= link_to(l(:button_delete), { :action => 'destroy', :id => status }, + :method => :post, + :confirm => l(:text_are_you_sure), + :class => 'icon icon-del') %> +
    + +

    <%= pagination_links_full @contract_status_pages %>

    + +<% html_title(l(:label_contract_status_plural)) -%> diff --git a/app/views/contract_statuses/new.html.erb b/app/views/contract_statuses/new.html.erb new file mode 100644 index 0000000..3228fbf --- /dev/null +++ b/app/views/contract_statuses/new.html.erb @@ -0,0 +1,6 @@ +

    <%= link_to l(:label_contract_status_plural), :controller => 'contract_statuses', :action => 'index' %> » <%=l(:label_contract_status_new)%>

    + +<% form_tag({:action => 'create'}, :class => "tabular") do %> + <%= render :partial => 'form' %> + <%= submit_tag l(:button_create) %> +<% end %> diff --git a/app/views/contracts/_attributes.html.erb b/app/views/contracts/_attributes.html.erb new file mode 100644 index 0000000..fa0f8b6 --- /dev/null +++ b/app/views/contracts/_attributes.html.erb @@ -0,0 +1,14 @@ +<% if @contract.custom_values.any? %> +
    + +

    <%= l(:label_contract) %>

    + + <% @contract.custom_values.each do |custom_value| %> + <% if !custom_value.value.blank? %> + + <% end %> + <% end %> +
    <%= custom_value.custom_field.name %>: <%=h show_value(custom_value) %>
    + +
    +<% end %> diff --git a/app/views/contracts/_contracts_statistics.html.erb b/app/views/contracts/_contracts_statistics.html.erb new file mode 100644 index 0000000..9c04f68 --- /dev/null +++ b/app/views/contracts/_contracts_statistics.html.erb @@ -0,0 +1,26 @@ +<% if contract_statuses.any? %> +
    + <% if !(@project && !authorize_for(:sale_funel, :index)) %> +
    + <%= link_to l(:label_sale_funel), {:controller => 'sale_funel', :action => 'index', :project_id => @project} %> +
    + <% end %> +

    <%= l(:label_statistics) %>

    + + <% contract_statuses.each do |contract_status| %> + + + + + <% end %> +
    + > + <%= h "#{contract_status.name}(#{@project ? @project.contracts.count(:conditions => {:status_id => contract_status.id}) : Contract.count(:conditions => {:status_id => contract_status.id})})" %> + + + + <%= @project ? contracts_sum_to_currency(@project.contracts.sum(:price, :conditions => {:status_id => contract_status.id}, :group => :currency)) : contracts_sum_to_currency(Contract.sum(:price, :conditions => {:status_id => contract_status.id}, :group => :currency)) %> + +
    +
    +<% end %> \ No newline at end of file diff --git a/app/views/contracts/_custom_field_filter.html.erb b/app/views/contracts/_custom_field_filter.html.erb new file mode 100644 index 0000000..91c530a --- /dev/null +++ b/app/views/contracts/_custom_field_filter.html.erb @@ -0,0 +1,5 @@ + + available_custom_fields + <%= label_tag l(:label_assigned_to) + " " %> + <%= select_tag :assigned_to_id, options_for_select(Contract.available_users(@project).collect{|u| [u.name, u.id.to_s]}.insert(0, [""]), params[:assigned_to_id]) %> + diff --git a/app/views/contracts/_custom_field_form.html.erb b/app/views/contracts/_custom_field_form.html.erb new file mode 100644 index 0000000..191e09f --- /dev/null +++ b/app/views/contracts/_custom_field_form.html.erb @@ -0,0 +1,3 @@ +

    <%= form.check_box :is_for_all %>

    +

    <%= form.check_box :is_filter %>

    +

    <%= form.check_box :visible, :label => l(:label_contacts_show_in_list) %>

    \ No newline at end of file diff --git a/app/views/contracts/_form.html.erb b/app/views/contracts/_form.html.erb new file mode 100644 index 0000000..0ba7814 --- /dev/null +++ b/app/views/contracts/_form.html.erb @@ -0,0 +1,38 @@ +<%= error_messages_for 'contract' %> +
    +

    <%= f.text_field :name, :label=>l(:field_contract_name), :size => 80, :required => true %>

    + +

    <%= f.text_area :background , :cols => 80, :rows => 8, :class => 'wiki-edit', :label=>l(:field_contract_background) %>

    <%= wikitoolbar_for 'contract_background' %> + + <% if @project.contract_statuses.any? %> +

    <%= f.select :status_id, collection_for_status_select, :include_blank => false, :selected => @contract.status_id.to_s, :label=>l(:field_contact_status) %>

    + <% end %> + <% unless @project.contract_categories.empty? %> +

    <%= f.select :category_id, (@project.contract_categories.collect {|c| [c.name, c.id]}), :include_blank => true %> + <%= prompt_to_remote(image_tag('add.png', :style => 'vertical-align: middle;'), + l(:label_contract_category_new), + 'category[name]', + {:controller => 'contract_categories', :action => 'new', :project_id => @project}, + :title => l(:label_contract_category_new), + :tabindex => 199) if authorize_for('contract_categories', 'new') %>

    + <% end %> +

    + <%= f.select :contact_id, (@project.contacts.visible.collect {|p| [ p.name, p.id ] }), :include_blank => true, :label=>l(:field_contract_contact) %> + <%= link_to image_tag('add.png', :style => 'vertical-align: middle;'), + {:controller => 'contacts', :action => 'new', :project_id => @project}, + :confirm => l(:text_are_you_sure), :title => l(:label_contact_new) if authorize_for('contacts', 'new') %> +

    +

    + <%= f.text_field :price, :label => l(:field_contract_price), :size => 10 %> + <%= select_tag "contract[currency]", options_for_select(collection_for_currencies_select.insert(0, ['', '']), @contract.currency), :include_blank => true %> + +

    + + <% @contract.custom_field_values.each do |value| %> +

    + <%= custom_field_tag_with_label :contract, value %> +

    + <% end -%> + +

    <%= f.select :assigned_to_id, (@project.assignable_users.collect {|m| [m.name, m.id]}), :include_blank => true, :label => l(:label_assigned_to) %>

    +
    diff --git a/app/views/contracts/_list.html.erb b/app/views/contracts/_list.html.erb new file mode 100644 index 0000000..8cf516a --- /dev/null +++ b/app/views/contracts/_list.html.erb @@ -0,0 +1,54 @@ +<% form_tag({}) do -%> + <%= hidden_field_tag 'back_url', url_for(params) %> + <%= hidden_field_tag 'project_id', @project.id if @project %> + <% unless @contracts.empty? %> + + + <% @contracts.each do |contract| %> + + + + + + + + <% end %> + + + + + +
    + <%= check_box_tag "ids[]", contract.id, false, :onclick => "toggleContact(event, this);" %> + + <%= link_to avatar_to(contract, :size => "32"), {:controller => 'contracts', :action => 'show', :id => contract.id}, :id => "avatar" %> + +

    <%= link_to contract.name, :controller => 'contracts', :action => 'show', :id => contract.id %>

    +

    + <%= link_to_source(contract.contact) if contract.contact %> + +

    +
    +
    <%= contract_price(contract) %> + <% if contract.status && contract.project.contract_statuses.any? %> + > + <%= h contract.status %> + + <% end %> +
    +
    + <%= h contract.category %> +
    +
    + + <%= "#{l(:label_total)} (#{@contracts_count}):" %> + <%= contracts_sum_to_currency(@contracts_sum).gsub(' / ', '
    ') %> +
    + <%= contacts_paginator @contracts_pages, :params => {:project_id => params[:project_id]} if @contracts_pages %> + + <% else %> +

    <%=l(:label_no_data)%>

    + <% end %> +<% end %> + +<%= context_menu url_for( {:controller => "contracts", :action => "context_menu"} )%> diff --git a/app/views/contracts/_related_contracts.html.erb b/app/views/contracts/_related_contracts.html.erb new file mode 100644 index 0000000..1f4df75 --- /dev/null +++ b/app/views/contracts/_related_contracts.html.erb @@ -0,0 +1,28 @@ +
    + +
    + <%= link_to_if_authorized l(:label_contract_new), {:controller => 'contracts', :action => 'new', :project_id => @project, :contact_id => @contact} %> +
    + +

    <%= "#{l(:label_contract_plural)}" %> <%= " - #{h number_to_currency(related_contracts.sum{|d| d.price || 0})}" if false %>

    + +<% if related_contracts.any? %> + + <% related_contracts.each do |contract| %> + + + + <% end %> + +<% end %> +
    \ No newline at end of file diff --git a/app/views/contracts/bulk_edit.html.erb b/app/views/contracts/bulk_edit.html.erb new file mode 100644 index 0000000..0b329ef --- /dev/null +++ b/app/views/contracts/bulk_edit.html.erb @@ -0,0 +1,80 @@ +

    <%= l(:label_bulk_edit_selected_contracts) %>

    + + +
    + +
    + + +<% form_tag(:action => 'bulk_update') do %> +<%= @contracts.collect {|i| hidden_field_tag('ids[]', i.id)}.join %> +
    +
    +<%= l(:label_change_properties) %> + +<% if @available_statuses.any? %> +

    + + <%= select_tag('contract[status_id]', content_tag('option', l(:label_no_change_option), :value => '') + + options_from_collection_for_select(@available_statuses, :id, :name)) %> +

    +<% end %> + + +<% if @available_categories.any? %> +

    + + <%= select_tag('contract[category_id]', content_tag('option', l(:label_no_change_option), :value => '') + + content_tag('option', l(:label_none), :value => 'none') + + options_from_collection_for_select(@available_categories, :id, :name)) %> +

    +<% end %> + +

    + + <%= select_tag('contract[assigned_to_id]', content_tag('option', l(:label_no_change_option), :value => '') + + content_tag('option', l(:label_nobody), :value => 'none') + + options_from_collection_for_select(@assignables, :id, :name)) %> +

    +

    + + <%= select_tag "contract[currency]", options_for_select(collection_for_currencies_select.insert(0, ['', '']), '') %> + +

    + + +<% @contracts.first.custom_field_values.each do |value| %> +

    + <% value.value = '' %> + <%= custom_field_tag_with_label :contact, value %> +

    +<% end -%> + +
    + +
    <%= l(:field_notes) %> +<%= text_area_tag 'note[content]', '', :cols => 60, :rows => 10, :class => 'wiki-edit' %> +<%= wikitoolbar_for 'note_content' %> +
    +
    + +

    <%= submit_tag l(:button_submit) %>

    +<% end %> + +<% content_for :header_tags do %> + <%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %> + <%= stylesheet_link_tag :contacts, :plugin => 'redmine_contacts' %> +<% end %> diff --git a/app/views/contracts/context_menu.html.erb b/app/views/contracts/context_menu.html.erb new file mode 100644 index 0000000..9bd8346 --- /dev/null +++ b/app/views/contracts/context_menu.html.erb @@ -0,0 +1,46 @@ + + diff --git a/app/views/contracts/edit.html.erb b/app/views/contracts/edit.html.erb new file mode 100644 index 0000000..03c43fc --- /dev/null +++ b/app/views/contracts/edit.html.erb @@ -0,0 +1,6 @@ +

    <%= l(:label_contract_edit_information) %>

    + +<% labelled_form_for :contract, @contract, :url => {:action => 'update', :id => @contract} do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + <%= submit_tag l(:button_save) -%> +<% end -%> diff --git a/app/views/contracts/index.html.erb b/app/views/contracts/index.html.erb new file mode 100644 index 0000000..a886bf3 --- /dev/null +++ b/app/views/contracts/index.html.erb @@ -0,0 +1,100 @@ +<% content_for(:header_tags) do %> + <%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %> + <%= stylesheet_link_tag :contacts, :plugin => 'redmine_contacts' %> + <%= stylesheet_link_tag :contacts_sidebar, :plugin => 'redmine_contacts' %> + +<% end %> + +<% content_for :sidebar do %> + <%= render :partial => 'common/sidebar' %> + <%= render :partial => 'contracts_statistics' %> + <%= render :partial => 'notes/last_notes', :object => @last_notes %> + <%= render :partial => 'common/recently_viewed' %> + +<% end %> + +
    + <%= link_to_if_authorized l(:label_contract_new), {:controller => 'contracts', :action => 'new', :project_id => @project}, :class => 'icon icon-add' %> +
    + +
    + <% form_tag(params, :id => "query_form") do %> + <%= hidden_field_tag('project_id', @project.to_param) if @project %> + <% no_filters = ((params[:status_id].blank? || params[:status_id] == 'o') && params[:period].blank? && params[:assigned_to_id].blank? && params[:category_id].blank?) %> + +

    + + <%= l(:label_contract_plural) %> + + + + <%= label_tag :search, l(:label_search), :id => "search_overlabel" %> + <%= text_field_tag(:search, params[:search], :autocomplete => "off", :size => "35", :class => "live_search_field", :onfocus => "Element.hide('search_overlabel'); return false;", :onblur => "if (this.value == '') {Element.show('search_overlabel');}" ) %> + + <%= observe_field("search", + :frequency => 2, + :update => 'contact_list', + :url => {:controller => 'contracts', :action => 'index', :project_id => @project }, + :with => "Form.serialize('query_form')") %> + + +

    + + + +
    + <%= l(:label_filter_plural) %> +
    +

    + <% if !contract_statuses.empty? %> + + <%= label_tag l(:label_contract_status) + " " %> + <%= select_tag :status_id, options_for_select(collection_for_status_select.insert(0, [l(:label_open_issues), "o"]).insert(0, [l(:label_all), ""]), params[:status_id]) %> + + <% end %> + + <%= label_tag l(:label_created_on) + " "%> + <%= select_tag 'period', options_for_period_select(params[:period]) %> + + <% if @project && !@project.contract_categories.empty? %> + + <%= label_tag l(:label_contract_category) + " "%> + <%= select_tag 'category_id', options_for_select(@project.contract_categories.collect {|c| [c.name, c.id.to_s]}.insert(0, [""]), params[:category_id]) %> + + <% end %> + + <%= label_tag l(:label_assigned_to) + " " %> + <%= select_tag :assigned_to_id, options_for_select(Contract.available_users(@project).collect{|u| [u.name, u.id.to_s]}.insert(0, [""]), params[:assigned_to_id]) %> + + + + +

    + +
    +
    +

    + + <%= link_to_remote l(:button_apply), + { :url => {}, + :update => "contact_list", + :with => "Form.serialize('query_form')" + }, :class => 'icon icon-checked' %> + + <%= link_to l(:button_clear), + {:project_id => @project, :set_filter => 1 }, + :method => :get, + :update => "contact_list", + :class => 'icon icon-reload' %> +

    + <% end %> + +
    + + +
    + <%= render :partial => 'list' %> +
    + +<% html_title l(:label_contract_plural) %> + diff --git a/app/views/contracts/new.html.erb b/app/views/contracts/new.html.erb new file mode 100644 index 0000000..c4ff47c --- /dev/null +++ b/app/views/contracts/new.html.erb @@ -0,0 +1,6 @@ +

    <%= l(:label_contract_new) %>

    + +<% labelled_form_for :contract, @contract, :url => {:action => 'create', :project_id => @project} do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + <%= submit_tag l(:button_save) -%> +<% end -%> diff --git a/app/views/contracts/show.html.erb b/app/views/contracts/show.html.erb new file mode 100644 index 0000000..fee348a --- /dev/null +++ b/app/views/contracts/show.html.erb @@ -0,0 +1,94 @@ +
    + <% replace_watcher ||= 'watcher' %> + <%= watcher_tag(@contract, User.current, {:id => replace_watcher, :replace => ['watcher','watcher2']}) %> + <%= link_to_if_authorized l(:button_edit), {:controller => 'contracts', :action => 'edit', :id => @contract}, :class => 'icon icon-edit' unless @contract.nil? %> + <%= link_to_if_authorized l(:button_delete), {:controller => 'contracts', :action => 'destroy', :id => @contract}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' unless @contract.nil? %> +
    +

    <%= "#{l(:label_contract)} ##{@contract.id}" %>

    +
    + + + + + + <% if !@contract.price.blank? %> + + <% end %> + + +
    <%= avatar_to(@contract, :size => "64") %> +

    <%= h @contract.contact.name + ": " if @contract.contact %> <%= @contract.name %>

    +

    <%= h @contract.category %>

    + <% if @contract.status && @project.contract_statuses.any? %> +
    + > + <%= h @contract.status %> + + <% if authorize_for('contracts', 'edit') %> + + <%= link_to l(:label_contract_change_status), {}, :onclick => "Element.show('edit_status_form'); Element.hide('contract-status'); return false;", :id => 'edit_status_link' %> + + <% end %> +
    + <% form_tag( {:controller => 'contracts', + :action => 'update', + :project_id => @project, + :id => @contract }, + :multipart => true, + :id => "edit_status_form", + :style => "display:none; size: 100%" ) do %> + <%= select :contract, :status_id, options_for_select(collection_for_status_select, @contract.status_id.to_s), { :include_blank => false } %> + <%= submit_tag l(:button_save) %> + <%= link_to l(:button_cancel), {}, :onclick => "Element.hide('edit_status_form'); Element.show('contract-status'); return false;" %> +
    + + <% end %> + <% end %> +
    +
      +
    • <%= contract_price(@contract) %>
    • +
    +
    + + + <% if authorize_for('notes', 'add_note') %> +
    + <%= render :partial => 'notes/add', :locals => {:note_source => @contract} %> + <% end %> +
    + +
    +

    <%= l(:label_note_plural) %>

    +
    + <%= render :partial => 'notes/note_item', :collection => @contract.notes, :locals => {:note_source => @contract} %> +
    + +
    + +<% content_for :sidebar do %> + <%= render :partial => 'common/sidebar' %> + + <%= render :partial => 'attributes' %> + + <%= render :partial => 'common/responsible_user', :object => @contract %> + <%= render :partial => 'contract_contacts/contacts' %> + <%= render :partial => 'common/notes_attachments', :object => @contract_attachments %> + + <% if !@contract.background.blank? %> +

    <%= l(:label_contact_background_info) %>

    +
    <%= textilizable(@contract, :background) %>
    + <% end %> + + <%= render :partial => 'common/recently_viewed' %> + +<% end %> + +<% html_title "#{l(:label_contract)} ##{@contract.id}: #{@contract.name}" %> + +<% content_for :header_tags do %> + <%= javascript_include_tag :defaults %> + <%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %> + <%= stylesheet_link_tag :contacts, :plugin => 'redmine_contacts' %> + <%= stylesheet_link_tag :contacts_sidebar, :plugin => 'redmine_contacts' %> + +<% end %> \ No newline at end of file diff --git a/app/views/layouts/contacts_base.html.erb b/app/views/layouts/contacts_base.html.erb index 823001f..e105276 100644 --- a/app/views/layouts/contacts_base.html.erb +++ b/app/views/layouts/contacts_base.html.erb @@ -33,6 +33,8 @@ <%= link_to l(:label_contacts_view_all), { :controller => 'contacts', :action => 'index', :project_id => @project} %> | <%= link_to l(:label_deal_plural), { :controller => 'deals', :action => 'index', :project_id => @project} %> + | + <%= link_to l(:label_contract_plural), { :controller => 'contracts', :action => 'index', :project_id => @project} %> <% end %> diff --git a/app/views/my/blocks/_my_contacts_stats.html.erb b/app/views/my/blocks/_my_contacts_stats.html.erb index c6c4294..ac21c6b 100644 --- a/app/views/my/blocks/_my_contacts_stats.html.erb +++ b/app/views/my/blocks/_my_contacts_stats.html.erb @@ -29,7 +29,25 @@ <%= status.count %> <% end %> - + + + <%= l(:label_contracts_created) %> + <%= Contract.count(:conditions => {:author_id => @user.id, :created_on => from..to}) %>Contract.table_name}.price) AS total_sum", + :joins => "JOIN #{ContractStatus.table_name} ON #{Contract.table_name}.status_id = #{ContractStatus.table_name}.id", + :conditions => {:author_id => @user.id, :created_on => from..to}, + :group => "#{ContractStatus.table_name}.name, #{ContractStatus.table_name}.color, #{Contract.table_name}.status_id").each do |status| %> + + > + > + <%= h status.name %> + + + <%= status.count %> + + <% end %> + + + diff --git a/app/views/my/blocks/_my_contracts.html.erb b/app/views/my/blocks/_my_contracts.html.erb new file mode 100644 index 0000000..415048a --- /dev/null +++ b/app/views/my/blocks/_my_contracts.html.erb @@ -0,0 +1,32 @@ +

    <%= l(:label_my_contract_plural) %>

    + +<% contracts = Contract.visible.open.find(:all, :conditions => {:assigned_to_id => User.current.id}, :limit => 20) %> + +
    + +
    + +<% if contracts.length > 0 %> +

    <%= link_to l(:label_contract_view_all), + :controller => 'contracts', + :action => 'index', + :assigned_to_id => User.current.id %>

    +<% end %> + +<% content_for(:header_tags) do %> + <%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %> + <%= stylesheet_link_tag :contacts, :plugin => 'redmine_contacts' %> +<% end %> \ No newline at end of file diff --git a/app/views/projects/_contacts_settings.html.erb b/app/views/projects/_contacts_settings.html.erb index 14ef552..2cea693 100644 --- a/app/views/projects/_contacts_settings.html.erb +++ b/app/views/projects/_contacts_settings.html.erb @@ -2,11 +2,17 @@

    - + <%= hidden_field_tag('contacts_settings[contacts_show_deals_tab]', 0) %> <%= check_box_tag 'contacts_settings[contacts_show_deals_tab]', 1, ContactsSetting[:contacts_show_deals_tab, @project.id].to_i > 0 %>

    +

    + + <%= hidden_field_tag('contacts_settings[contacts_show_contracts_tab]', 0) %> + <%= check_box_tag 'contacts_settings[contacts_show_contracts_tab]', 1, ContactsSetting[:contacts_show_contracts_tab, @project.id].to_i > 0 %> +

    +

    <%= hidden_field_tag('contacts_settings[contacts_show_on_projects_show]', 0) %> diff --git a/app/views/projects/_contract_statuses.html.erb b/app/views/projects/_contract_statuses.html.erb new file mode 100644 index 0000000..ce16282 --- /dev/null +++ b/app/views/projects/_contract_statuses.html.erb @@ -0,0 +1,28 @@ +

    <%= l(:label_contract_status_plural) %>

    + +<% if ContractStatus.all.any? %> + <% form_tag({:controller => "contract_statuses", :action => "assing_to_project", :project_id => @project}, :method => :put, :class => "tabular") do %> + + + + + + + + + <% ContractStatus.all.each do |status| %> + + + + + + + + <% end %> + +
    <%= l(:field_name) %><%=l(:field_is_default)%><%=l(:field_contract_status_is_closed)%><%= l(:field_active) %>
         <%= h(status.name) %><%= checked_image status.is_default? %><%= checked_image status.is_closed? %> + <%= check_box_tag "contract_statuses[]", status.id , @project.contract_statuses.include?(status) %> +
    + <%= submit_tag l(:button_save) %> + <% end %> +<% end %> \ No newline at end of file diff --git a/app/views/projects/_contracts_settings.html.erb b/app/views/projects/_contracts_settings.html.erb new file mode 100644 index 0000000..e5be95b --- /dev/null +++ b/app/views/projects/_contracts_settings.html.erb @@ -0,0 +1,28 @@ +

    <%= l(:label_contract_category_plural) %>

    + +<% if @project.contract_categories.any? %> + + + + + + +<% for category in @project.contract_categories %> + <% unless category.new_record? %> + + + + + <% end %> +<% end %> + +
    <%= l(:field_name) %>
    <%= link_to_if_authorized h(category.name), { :controller => 'contract_categories', :action => 'edit', :id => category } %> + <%= link_to_if_authorized l(:button_delete), {:controller => 'contract_categories', :action => 'destroy', :id => category}, :method => :post, :confirm => l(:text_are_you_sure), :class => 'icon icon-del' %> +
    +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> + +

    <%= link_to_if_authorized l(:label_contract_category_new), :controller => 'contract_categories', :action => 'new', :project_id => @project %>

    + +<%= render :partial => "projects/contract_statuses" %> \ No newline at end of file diff --git a/app/views/projects/settings.rhtml b/app/views/projects/settings.rhtml index 0f055b6..8e47513 100644 --- a/app/views/projects/settings.rhtml +++ b/app/views/projects/settings.rhtml @@ -12,6 +12,10 @@ if @project.module_enabled?(:contacts_module) :action => :manage_contacts, :partial => 'projects/deals_settings', :label => :label_deal_plural }) + tabs.push({ :name => 'contracts', + :action => :manage_contacts, + :partial => 'projects/contracts_settings', + :label => :label_contract_plural }) end diff --git a/app/views/settings/_contacts_contract_statuses.html.erb b/app/views/settings/_contacts_contract_statuses.html.erb new file mode 100644 index 0000000..0e49c1b --- /dev/null +++ b/app/views/settings/_contacts_contract_statuses.html.erb @@ -0,0 +1,34 @@ +
    +<%= link_to l(:label_contract_status_new), {:controller => "contract_statuses", :action => 'new'}, :class => 'icon icon-add' %> +
    + +

    <%=l(:label_contract_status_plural)%>

    + + + + + + + + + + +<% for status in ContractStatus.all( :order => "position") %> + "> + + + + + + +<% end %> + +
    <%=l(:field_status)%><%=l(:field_is_default)%><%=l(:field_contract_status_is_closed)%><%=l(:button_sort)%>
         <%= link_to status.name, :controller => "contract_statuses", :action => 'edit', :id => status %><%= checked_image status.is_default? %><%= checked_image status.is_closed? %><%= reorder_links('contract_status', {:controller => "contract_statuses", :action => 'update', :id => status}) %> + <%= link_to(l(:button_delete), {:controller => "contract_statuses", :action => 'destroy', :id => status }, + :method => :post, + :confirm => l(:text_are_you_sure), + :class => 'icon icon-del') %> +
    + + +<% html_title(l(:label_contract_status_plural)) -%> diff --git a/assets/stylesheets/contacts.css b/assets/stylesheets/contacts.css index aaab715..8c3011e 100644 --- a/assets/stylesheets/contacts.css +++ b/assets/stylesheets/contacts.css @@ -1,5 +1,6 @@ div.contact {background:#f4e9f2; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;} div.deal {background:#edfff2; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;} +div.contract {background:#edfff2; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;} form#add_task_form {background:#ffffff; display: block; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7; width: 92%;} /********************/ @@ -209,6 +210,7 @@ table.contacts.index tr.context-menu-selection h2 { color: #F8F8F8 !important; } table.contacts.index tr.context-menu-selection td { color: #F8F8F8 !important; } table.contacts.index tr.context-menu-selection span.tag a { border: 1px solid #EFEFEF; padding: 2px 3px; } table.contacts.index tr.context-menu-selection span.deal-status { border: 1px solid #EFEFEF; padding: 2px 3px; } +table.contacts.index tr.context-menu-selection span.contract-status { border: 1px solid #EFEFEF; padding: 2px 3px; } table.contacts.index tbody tr:hover { background-color:#ffffdd; } @@ -230,6 +232,7 @@ table.contacts.index th.title {text-align: right;} table.contacts.index th.sum {text-align: left;} table.contacts.deals.index td.avatar {padding: 10px 10px 10px 10px;} +table.contacts.contracts.index td.avatar {padding: 10px 10px 10px 10px;} /*table.contacts.index td.avatar {margin-left: 50px;}*/ @@ -246,6 +249,14 @@ table.contacts.index td.name h1.deal_name { padding: 0; } +table.contacts.index td.name h1.contract_name { + font-size: 16px; + font-weight: normal; + margin: 0; + padding: 0; +} + + table.contacts.index td.name h1.selected { background-color: #ffb;} table.contacts.index td.name h2.selected { background-color: #ffb;} @@ -269,19 +280,21 @@ div.Right td.name div.info { /*Deals*/ -div#deal-status { +div#deal-status, div#contract-status { margin-top: 4px; } -div.deal-sum { +div.deal-sum, div.contract-sum { margin-bottom: 4px; } -table.related_deals td.name h4 { letter-spacing: -1px; margin: 0px 0 4px 0; padding: 0; line-height: 1.1em;} +table.related_contracts td.name h4, table.related_deals td.name h4 { + letter-spacing: -1px; margin: 0px 0 4px 0; padding: 0; line-height: 1.1em; +} div#deal-status span.contextual {float: none; padding-left: 0px;} -span.deal-status { +span.deal-status , span.contract-status { padding: 3px 4px; font-size: 10px; /* display: block;*/ @@ -293,6 +306,7 @@ dt.contact { background-image: url(../images/user_suit.png); } .icon-money-dollar { background-image: url(../images/money_dollar.png); } .icon-add-deal { background-image: url(../images/money.png); } +.icon-add-contract { background-image: url(../images/money.png); } .icon-add-employee { background-image: url(../images/user_suit.png); } .icon-link-break { background-image: url(../../../images/link_break.png); } .icon-call { background-image: url(../images/phone.png); } @@ -316,7 +330,7 @@ div.wiki img.tumbnail { /* NOTE_DATA */ /**************************************************************/ -table.note_data, table.related_deals { +table.note_data, table.related_deals , table.related_contracts { width: 100%; } diff --git a/config/locales/en.yml b/config/locales/en.yml index 3ca6f72..b1b4326 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -191,8 +191,41 @@ en: my_contacts_stats: Contacts statistics label_add_into: Add into label_delete_from: Delete from - label_show_deaks_tab: Show deals tab + label_show_deals_tab: Show deals tab label_show_on_projects_show: Show contacts on projects overview #2.2.1 - label_contacts_show_in_list: Show in list \ No newline at end of file + label_contacts_show_in_list: Show in list + + #2.2.2-rodax + label_contract_category: Categora de contrato + label_contract_category_plural: Categoras de contrato + label_contract_category_new: Nueva categora + text_contract_category_destroy_assignments: Remove category assignments + text_contract_category_destroy_question: "Algunos contratos (%{count}) pertenecen a esta categora. Qu quieres hacer?" + text_contract_category_reassign_to: Reasignar contratos a esta categora + text_contracts_destroy_confirmation: 'Ests seguro de que quieres eliminar los contrato(s) seleccionados?' + label_contract_status_plural: Estados de contrato + label_contract_status: Estado de contrato + field_contract_status_is_closed: Cerrado + label_contract_status_new: Nuevo + label_my_contract_plural: Contratos abiertos asignados a m + label_contract_view_all: Ver todos los contratos + + label_contract_plural: Contratos + label_contract: Contrato + label_contract_new: Nuevo contrato + label_contract_edit_information: Cambiar informacin del contrato + label_contract_change_status: Cambiar estado del contrato + label_contract_pending: Pendiente + label_contract_won: Ganado + label_contract_lost: Perdido + + field_contract_name: Nombre + field_contract_background: Trasfondo + field_contract_contact: Contacto + field_contract_price: Cuenta + + my_contracts: My contracts + label_contracts_created: Contracts created + label_show_contracts_tab: Show contracts tab \ No newline at end of file diff --git a/config/locales/es.yml b/config/locales/es.yml index 0012f49..e0a7c41 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -158,11 +158,66 @@ es: #2.0.3 label_add_contact: Add new contact in project - label_contact: Contact - field_age: Age - label_vcf_import: Import from vCard + label_contact: Contacto + field_age: Edad + label_vcf_import: Importar desde vCard label_mail_from: From - permission_import_contacts: Import contacts + permission_import_contacts: Importar contactos + + #2.1.0 + field_company_name: Company name + label_recently_added_contacts: Recently added contacts + label_created_by_me: Contacts created by me + my_contacts: My contacts + my_deals: My deals + + #2.2.0 + label_note_type_email: Email + label_note_type_call: Call + label_note_type_meeting: Meeting + field_deal_currency: Currency + label_my_contacts_stats: Contacts statistics for this month + label_contacts_created: Contacts created + label_deals_created: Deals created + my_contacts_avatars: My contacts photos + my_contacts_stats: Contacts statistics + label_add_into: Add into + label_delete_from: Delete from + label_show_deals_tab: Show deals tab + label_show_on_projects_show: Show contacts on projects overview + + #2.2.1 + label_contacts_show_in_list: Show in list #2.2.2-rodax - label_contract_plural: Categorías de contratos \ No newline at end of file + label_contract_category: Categoría de contrato + label_contract_category_plural: Categorías de contrato + label_contract_category_new: Nueva categoría + text_contract_category_destroy_assignments: Remove category assignments + text_contract_category_destroy_question: "Algunos contratos (%{count}) pertenecen a esta categoría. ¿Qué quieres hacer?" + text_contract_category_reassign_to: Reasignar contratos a esta categoría + text_contracts_destroy_confirmation: '¿Estás seguro de que quieres eliminar los contrato(s) seleccionados?' + label_contract_status_plural: Estados de contrato + label_contract_status: Estado de contrato + field_contract_status_is_closed: Cerrado + label_contract_status_new: Nuevo + label_my_contract_plural: Contratos abiertos asignados a mí + label_contract_view_all: Ver todos los contratos + + label_contract_plural: Contratos + label_contract: Contrato + label_contract_new: Nuevo contrato + label_contract_edit_information: Cambiar información del contrato + label_contract_change_status: Cambiar estado del contrato + label_contract_pending: Pendiente + label_contract_won: Ganado + label_contract_lost: Perdido + + field_contract_name: Nombre + field_contract_background: Trasfondo + field_contract_contact: Contacto + field_contract_price: Cuenta + + my_contracts: Mis contratos + label_contracts_created: Contractos creados + label_show_contracts_tab: Show contracts tab \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 8f2505c..3377715 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -38,6 +38,11 @@ ActionController::Routing::Routes.draw do |map| categories.connect 'projects/:project_id/deal_categories/new', :action => 'new' end + map.with_options :controller => 'contract_categories' do |categories| + categories.connect 'projects/:project_id/contract_categories/new', :action => 'new' + end + + map.with_options :controller => 'sale_funel' do |sale_funel| sale_funel.connect 'projects/:project_id/sale_funel', :action => 'index' sale_funel.connect 'sale_funel', :action => 'index' @@ -54,6 +59,17 @@ ActionController::Routing::Routes.draw do |map| deals_routes.connect "deals/:id/destroy", :conditions => { :method => :post}, :action => 'destroy', :id => /\d+/ deals_routes.connect "deals/:id/edit", :conditions => { :method => :get }, :action => 'edit', :id => /\d+/ end + + map.with_options :controller => 'contracts' do |contracts_routes| + contracts_routes.connect "contracts", :conditions => { :method => :get }, :action => 'index' + contracts_routes.connect "projects/:project_id/contracts", :action => 'index' + contracts_routes.connect "projects/:project_id/contracts/create", :conditions => { :method => :post }, :action => 'create' + contracts_routes.connect "projects/:project_id/contracts/new", :conditions => { :method => :get }, :action => 'new' + contracts_routes.connect "contracts/:id", :conditions => { :method => :get }, :action => 'show', :id => /\d+/ + contracts_routes.connect "contracts/:id/update", :conditions => { :method => :post }, :action => 'update', :id => /\d+/ + contracts_routes.connect "contracts/:id/destroy", :conditions => { :method => :post}, :action => 'destroy', :id => /\d+/ + contracts_routes.connect "contracts/:id/edit", :conditions => { :method => :get }, :action => 'edit', :id => /\d+/ + end map.with_options :controller => 'notes' do |notes_routes| notes_routes.connect "notes/:note_id", :conditions => { :method => :get }, :action => 'show', :note_id => /\d+/ diff --git a/db/migrate/034_create_contacts_contracts.rb b/db/migrate/034_create_contacts_contracts.rb new file mode 100644 index 0000000..af7a0ba --- /dev/null +++ b/db/migrate/034_create_contacts_contracts.rb @@ -0,0 +1,14 @@ +class CreateContactsContracts < ActiveRecord::Migration + def self.up + create_table :contacts_contracts, :id => false do |t| + t.integer :contract_id + t.integer :contact_id + end + add_index :contacts_contracts, [:contract_id, :contact_id] + + end + + def self.down + drop_table :contacts_contracts + end +end diff --git a/init.rb b/init.rb index 655f8a4..b100dfd 100644 --- a/init.rb +++ b/init.rb @@ -50,11 +50,21 @@ Redmine::Plugin.register :contacts do :deal_contacts => [:add, :delete], :notes => [:add_note, :destroy_note] } + permission :delete_contracts, :contracts => [:destroy, :bulk_destroy] + permission :view_contracts, { + :contracts => [:index, :show, :context_menu], + } + permission :edit_contracts, { + :contracts => [:new, :create, :edit, :update, :add_attachment, :bulk_update, :bulk_edit], + :contract_contacts => [:add, :delete], + } permission :manage_contacts, { :projects => :settings, :contacts_settings => :save, :deal_categories => [:new, :edit, :destroy], - :deal_statuses => [:assing_to_project], :require => :member + :contract_categories => [:new, :edit, :destroy], + :deal_statuses => [:assing_to_project], :require => :member, + :contract_statuses => [:assing_to_project], :require => :member } permission :import_contacts, {} end @@ -65,6 +75,11 @@ Redmine::Plugin.register :contacts do :if => Proc.new{|p| ContactsSetting[:contacts_show_deals_tab, p.id].to_i > 0 }, :param => :project_id + menu :project_menu, :contracts, {:controller => 'contracts', :action => 'index' }, + :caption => :label_contract_plural, + :if => Proc.new{|p| ContactsSetting[:contacts_show_contracts_tab, p.id].to_i > 0 }, + :param => :project_id + menu :application_menu, :contacts, {:controller => 'contacts', :action => 'index'}, :caption => :label_contact_plural, @@ -78,6 +93,12 @@ Redmine::Plugin.register :contacts do :if => Proc.new{User.current.allowed_to?({:controller => 'deals', :action => 'index'}, nil, {:global => true})} + menu :application_menu, :contracts, + {:controller => 'contracts', :action => 'index'}, + :caption => :label_contract_plural, + :param => :project_id, + :if => Proc.new{User.current.allowed_to?({:controller => 'contracts', :action => 'index'}, + nil, {:global => true})} menu :top_menu, :contacts, {:controller => 'contacts', :action => 'index'}, :caption => :contacts_title, :if => Proc.new { User.current.allowed_to?({:controller => 'contacts', :action => 'index'}, nil, {:global => true}) @@ -91,6 +112,7 @@ Redmine::Plugin.register :contacts do Redmine::Search.map do |search| search.register :contacts search.register :deals + search.register :contracts search.register :contact_notes search.register :deal_notes end diff --git a/lib/redmine_contacts/hooks/views_custom_fields_hook.rb b/lib/redmine_contacts/hooks/views_custom_fields_hook.rb index 390f84a..a6bfba2 100644 --- a/lib/redmine_contacts/hooks/views_custom_fields_hook.rb +++ b/lib/redmine_contacts/hooks/views_custom_fields_hook.rb @@ -2,6 +2,7 @@ module RedmineContacts module Hooks class ViewsCustomFieldsHook < Redmine::Hook::ViewListener render_on :view_custom_fields_form_deal_custom_field, :partial => "deals/custom_field_form" + render_on :view_custom_fields_form_contract_custom_field, :partial => "contracts/custom_field_form" end end end diff --git a/lib/redmine_contacts/patches/project_patch.rb b/lib/redmine_contacts/patches/project_patch.rb index bf2dcfb..9e2bff2 100644 --- a/lib/redmine_contacts/patches/project_patch.rb +++ b/lib/redmine_contacts/patches/project_patch.rb @@ -6,8 +6,11 @@ module RedmineContacts unloadable # Send unloadable so it will not be unloaded in development has_and_belongs_to_many :contacts, :order => "last_name, first_name", :uniq => true has_many :deals, :dependent => :delete_all + has_many :contracts, :dependent => :delete_all has_many :deal_categories, :dependent => :delete_all, :order => "#{DealCategory.table_name}.name" + has_many :contract_categories, :dependent => :delete_all, :order => "#{ContractCategory.table_name}.name" has_and_belongs_to_many :deal_statuses, :order => "#{DealStatus.table_name}.position", :uniq => true + has_and_belongs_to_many :contract_statuses, :order => "#{ContractStatus.table_name}.position", :uniq => true end end end diff --git a/test/functional/contract_categories_controller_test.rb b/test/functional/contract_categories_controller_test.rb new file mode 100644 index 0000000..f913212 --- /dev/null +++ b/test/functional/contract_categories_controller_test.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class ContractCategoriesControllerTest < ActionController::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/test/functional/contract_contacts_controller_test.rb b/test/functional/contract_contacts_controller_test.rb new file mode 100644 index 0000000..cc69fe5 --- /dev/null +++ b/test/functional/contract_contacts_controller_test.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class ContractContactsControllerTest < ActionController::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/test/functional/contract_statuses_controller_test.rb b/test/functional/contract_statuses_controller_test.rb new file mode 100644 index 0000000..501be4c --- /dev/null +++ b/test/functional/contract_statuses_controller_test.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class ContractStatusesControllerTest < ActionController::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/test/functional/contracts_controller_test.rb b/test/functional/contracts_controller_test.rb new file mode 100644 index 0000000..789946c --- /dev/null +++ b/test/functional/contracts_controller_test.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class ContractsControllerTest < ActionController::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end