Initial Redmine tooling and local plugin forks

This commit is contained in:
Jason Thistlethwaite
2026-04-24 22:01:18 +00:00
commit 9f682af0eb
683 changed files with 56878 additions and 0 deletions
@@ -0,0 +1,10 @@
<%= raw @companies.map {|company| {
'id' => company.id,
'name' => company.name,
'avatar' => avatar_to(company, :size => 16),
'email' => company.primary_email,
'label' => company.name,
'value' => company.name
}
}.to_json
%>
@@ -0,0 +1,11 @@
<%= raw @contacts.map {|contact| {
'id' => contact.id,
'text' => contact.name_with_company,
'name' => contact.name,
'avatar' => avatar_to(contact, :size => 16),
'company' => contact.is_company ? "" : contact.company.to_s,
'email' => contact.primary_email,
'value' => contact.id
}
}.to_json
%>
@@ -0,0 +1,4 @@
<%= raw @tags.collect {|tag|
tag.name
}.to_json
%>
@@ -0,0 +1,9 @@
<%= raw @deals.map {|deal| {
'id' => deal.id,
'label' => "#{deal.full_name} (#{deal.info})",
'text' => "#{deal.name} (#{deal.info})",
'avatar' => avatar_to(deal, :size => 16),
'value' => deal.id
}
}.to_json
%>
@@ -0,0 +1,8 @@
<p class="address">
<label><%= l(:label_crm_address) %></label>
<%= f.text_field :street1, :no_label => true, :placeholder => l(:label_crm_street1), :style => "width:90%;" -%></p>
<p class="address street2"><%= f.text_field :street2, :no_label => true, :placeholder => l(:label_crm_street2) -%></p>
<p class="address city"><%= f.text_field :city, :no_label => true, :placeholder => l(:label_crm_city) -%> </p>
<p class="address region"><%= f.text_field :region, :no_label => true, :placeholder => l(:label_crm_region) -%></p>
<p class="address postcode"><%= f.text_field :postcode, :no_label => true, :placeholder => l(:label_crm_postcode), :size => 12 -%></p>
<p class="address country"><%= f.select :country_code, countries_options_for_select(f.object.country_code), :no_label => true, :placeholder => l(:label_crm_country), :include_blank => true -%></p>
@@ -0,0 +1,17 @@
<% actions ||= "" %>
<table class="note_data" id="contact_data_<%= contact_data.id %>">
<tr>
<td class="avatar"><%= link_to avatar_to(contact_data, :size => "32"), note_source_url(contact_data), :id => "avatar" %></td>
<td class="name">
<h4 class="contacts_header">
<%= link_to contact_data.name, note_source_url(contact_data) %>
</h4>
<%= contact_data.info %>
</td>
<% if !actions.blank? %>
<td>
<%= actions %>
</td>
<% end %>
</tr>
</table>
@@ -0,0 +1,29 @@
<% selected_tab = params[:tab] ? params[:tab].to_s : tabs.first[:name] %>
<div class="tabs">
<ul>
<% tabs.each do |tab| -%>
<li><%= link_to tab[:label], tabs_contact_path(@contact, :tab => tab[:name]),
:id => "tab-#{tab[:name]}",
:class => (tab[:name] != selected_tab ? 'tab-header' : 'selected tab-header'),
:data => { :name => tab[:name], :partial => tab[:partial], :project_id => @project},
:onclick => "showContactTab('#{tab[:name]}'); this.blur(); return false;" %></li>
<% end -%>
</ul>
<div class="tabs-buttons" style="display:none;">
<button class="tab-left" onclick="moveTabLeft(this);"></button>
<button class="tab-right" onclick="moveTabRight(this);"></button>
</div>
</div>
<% tabs.each do |tab| %>
<% selected = tab[:name] == selected_tab %>
<div class='tab-placeholder tab-content <%= 'active loaded' if selected %>' id='tab-placeholder-<%= tab[:name] %>' style='<%= "display: block" if selected %>'>
<%= render(:partial => tab[:partial]) if selected %>
</div>
<% end %>
<script type='text/javascript'>
$(document).ready(displayTabsButtons);
$(window).resize(displayTabsButtons);
$(document).ready(function(){ setupDeferredTabs('<%= load_tab_contact_path(@contact) %>') });
</script>
@@ -0,0 +1,9 @@
<script type="text/javascript">
var field_formats = ['contact', 'company'];
var contact_filter_urls = {
'company': "<%= auto_complete_contacts_path(:project_id => (ContactsSetting.cross_project_contacts? ? nil : @project), :is_company => true) %>",
'contact': "<%= auto_complete_contacts_path(:project_id => (ContactsSetting.cross_project_contacts? ? nil : @project)) %>"
};
field_formats.push('deal');
contact_filter_urls['deal'] = '<%= auto_complete_deals_path(:project_id => (ContactsSetting.cross_project_contacts? ? nil : @project)) %>';
</script>
@@ -0,0 +1,4 @@
<% if notes_attachments.any? %>
<h3><%= l(:label_attachment_plural) %></h3>
<%= render :partial => 'attachments/links', :locals => {:attachments => notes_attachments, :options => {}} %>
<% end %>
@@ -0,0 +1,4 @@
<h3><%= l(:label_crm_recently_viewed) %></h3>
<div id="recently_viewed">
<%= render :partial => 'common/contact_data', :collection => RecentlyViewed.includes(:viewed).last(5).map(&:viewed).select{|v| !v.blank? && v.visible?} %>
</div>
@@ -0,0 +1,10 @@
<% if responsible_user.assigned_to %>
<h3><%= l(:label_crm_assigned_to) %></h3>
<div id="responsible_user">
<ul>
<li>
<%= (avatar(responsible_user.assigned_to, :size => "16").to_s + link_to_user(responsible_user.assigned_to, :class => 'user').to_s).html_safe %>
</li>
</ul>
</div>
<% end %>
@@ -0,0 +1,15 @@
<%= call_hook(:view_contacts_sidebar_top) %>
<h3><%= l(:label_crm_module_plural) %></h3>
<% if User.current.allowed_to?(:view_contacts, @project, :global => true) %>
<%= link_to l(:label_contact_plural), { :controller => 'contacts', :action => 'index', :project_id => @project, :set_filter => 1} %>
|
<% end %>
<% if User.current.allowed_to?(:view_deals, @project, :global => true) %>
<%= link_to l(:label_deal_plural), { :controller => 'deals', :action => 'index', :project_id => @project, :set_filter => 1} %>
|
<% end %>
<%= link_to l(:label_crm_note_plural), { :controller => 'contacts', :action => 'contacts_notes', :project_id => @project} %>
<%= call_hook(:view_contacts_sidebar_bottom) %>
@@ -0,0 +1,74 @@
<div id="attributes" class="attributes">
<div class="contextual">
<%- if ContactsSetting.vcard? -%>
<%= link_to 'vCard', contact_path(@contact, :format => :vcf) %>
<%- end -%>
</div>
<h3><%= if !@contact.is_company then l(:label_contact) else l(:label_crm_company) end %></h3>
<table class="contact sidebar attributes vcard">
<%= call_hook(:view_contacts_sidebar_attributes_top) %>
<tr>
<th class = "name"><%= l(:field_contact_name) %>:</th><td class="name fn <%= "org" if @contact.is_company %>"><%= h @contact.name(:firstname_middlename_lastname) %></td>
</tr>
<% if !@contact.job_title.blank? %>
<tr> <th class = "job_title"><%= !@contact.is_company ? l(:field_contact_job_title) : l(:field_company_field) %>:</th><td class="job_title title"><%= h @contact.job_title %></td></tr>
<% end %>
<% if !@contact.is_company %>
<tr><th class = "company"><%=l(:field_contact_company)%>:</th><td class="company org"><%= h @contact.company %></td></tr>
<% end %>
<tr>
<th class = "address"><%= l(:field_contact_address) %>:</th>
<% unless @contact.address.blank? %>
<td class="address adr">
<%= @contact.post_address.gsub("\n", "<br/>").html_safe %>
<br>
<%= link_to l(:label_crm_show_on_map), "http://maps.google.com/maps?f=q&q=#{@contact.address}+(#{@contact.name})&ie=UTF8&om=1"%>
</td>
<% end %>
</tr>
<tr class = "tel">
<th class = "phone"><%= l(:field_contact_phone) %>:</th>
<td class = "phones">
<% @contact.phones.each do |phone| %>
<span class="value"><%= h phone %> <br></span>
<% end %>
</td>
</tr>
<tr class = "emails">
<th><%= l(:field_contact_email) %>:</th>
<td>
<% @contact.emails.each do |email| %>
<span class="email"><%= mail_to email %> <br></span>
<% end %>
</td>
</tr>
<tr>
<th class = "website"><%= l(:field_contact_website) %>:</th>
<td class="website url"><%= link_to @contact.website, @contact.website_address, :class => 'external' %></td>
</tr>
<% if !@contact.skype_name.blank? %>
<tr>
<th class = "skype"><%= l(:field_contact_skype) %>:</th>
<td class="skype"><%= skype_to @contact.skype_name %></td>
</tr>
<% end %>
<% if !@contact.birthday.blank? %>
<tr> <th class = "birthday"><%= l(:field_birthday) %>:</th><td class="birthday bday" title=<%= "#{format_date(@contact.birthday)}" %>><%= "#{@contact.birthday.day} #{t('date.month_names')[@contact.birthday.month]}"%></td> </tr>
<tr> <th class = "age"><%= l(:field_age) %>:</th><td class="ega"><%= @contact.age %></td> </tr>
<% end %>
<% @contact.custom_field_values.compact.each do |custom_value| %>
<% if !custom_value.value.blank? %>
<tr> <th class = "custom_field"><%= custom_value.custom_field.name%>:</th><td> <%= simple_format_without_paragraph(h(show_value(custom_value))) %></td> </tr>
<% end %>
<% end %>
<% if @contact.assigned_to %>
<tr><th class="author"><%=l(:label_crm_assigned_to)%>:</th><td class="author"><%= avatar(@contact.assigned_to, :size => "14") %><%= link_to_user(@contact.assigned_to) %></td></tr>
<% end %>
<%= call_hook(:view_contacts_sidebar_attributes_bottom) %>
</table>
</div>
@@ -0,0 +1,13 @@
<% @company_contacts = @contact.company_contacts.visible.uniq %>
<% if @contact.is_company %>
<div id="company_contacts">
<div class="contextual">
<%= link_to_if_authorized l(:label_crm_add_contact), {:controller => 'contacts', :action => 'new', :project_id => @project, :contact => {:company => @contact.name}} %>
</div>
<h3><%= l(:label_contact_plural) %></h3>
<%= render :partial => 'common/contact_data', :collection => @company_contacts %>
<div style="clear:both;"> </div>
</div>
<% end %>
@@ -0,0 +1,36 @@
<div class="contact card">
<table class="subject_header">
<tr>
<td class="avatar"><%= contact_tag(contact_card, :type => "avatar", :size => 64) %></td>
<td class="name" style="vertical-align: top;">
<h2><%= contact_tag(contact_card, :type => "plain") %> </h2>
<p>
<%= h contact_card.job_title %>
<% if !contact_card.is_company %>
<%= " #{l(:label_crm_at_company)} " unless (contact_card.job_title.blank? or contact_card.company.blank?) %>
<% if contact_card.contact_company %>
<%= link_to contact_card.contact_company.name, {:controller => 'contacts', :action => 'show', :project_id => contact_card.contact_company.project(@project), :id => contact_card.contact_company.id } %>
<% else %>
<%= h contact_card.company %>
<% end %>
<% end %>
</p>
</td>
</tr>
<tr>
<td colspan="2" style="padding-left: 10px;">
<% if contact_card.phones.any? %>
<p class="phone icon icon-phone"><%= contact_card.phones.first %></p>
<% end %>
<% if contact_card.emails.any? %>
<p class="email icon icon-email"><%= mail_to contact_card.emails.first %></p>
<% end %>
<%= tag_links(contact_card.tag_list) %>
</td>
</tr>
</table>
</div>
@@ -0,0 +1,4 @@
<p><%= form.check_box :is_filter %></p>
<% if (@custom_field.respond_to?(:format) && @custom_field.format.searchable_supported) || !@custom_field.respond_to?(:format) %>
<p><%= form.check_box :searchable %></p>
<% end %>
+105
View File
@@ -0,0 +1,105 @@
<%= back_url_hidden_field_tag %>
<%= error_messages_for 'contact' %>
<div class = "box tabular" id="contact_data">
<script type="text/javascript" charset="utf-8">
function togglePerson(element) {
if (element.checked) {
$('#person_data').hide();
$('#job_title label').get(0).innerHTML ='<%= l(:field_company_field) %>';
$('#first_name label').get(0).innerHTML='<%= l(:field_company_name) %>' + '<span class="required"> *</span>';
} else {
$('#person_data').show();
$('#job_title label').get(0).innerHTML ='<%= l(:field_contact_job_title) %>';
$('#first_name label').get(0).innerHTML='<%= l(:field_contact_first_name) %>' + '<span class="required"> *</span>';
}
}
</script>
<p class="avatar extended" id="watchers">
<%= avatar_to(@contact, :size => "64", :style => "vertical-align: middle;") %>
<%= link_to image_tag('delete.png'), {:controller => 'attachments', :action => 'destroy', :id => @contact.avatar},
:data => {:confirm => l(:text_are_you_sure)},
:method => :delete,
:class => 'delete',
:style => "vertical-align: middle;",
:title => l(:button_delete) unless @contact.avatar.blank? %>
</p>
<p class="extended">
<%= label_tag l(:field_contact_avatar) %>
<span id="attachments_fields"></span>
<span class="add_attachment">
<%= file_field_tag 'dummy_file',
:size => 30,
:id => nil,
:class => 'file_selector',
:multiple => true,
:onchange => 'uploadAvatar(this);',
:data => {
:max_file_size => Setting.attachment_max_size.to_i.kilobytes,
:max_file_size_message => l(:error_attachment_too_big, :max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)),
:max_concurrent_uploads => Redmine::Configuration['max_concurrent_ajax_uploads'].to_i,
:upload_path => uploads_path(:format => 'js'),
:description_placeholder => l(:label_optional_description)
} %>
</span>
</p>
<p><%= f.check_box(:is_company, :label => l(:field_contact_is_company), :onclick => "togglePerson(this)" ) %></p>
<p id="first_name"><%= f.text_field :first_name, :label => !@contact.is_company ? l(:field_contact_first_name) : l(:field_company_name), :required => true, :style => "width:90%;" %></p>
<div id="person_data" style="<%= 'display: none;' if @contact.is_company %>">
<p><%= f.text_field :middle_name, :label=>l(:field_contact_middle_name) %></p>
<p><%= f.text_field :last_name, :label=>l(:field_contact_last_name), :id => 'contact_last_name' %></p>
<p><%= f.text_field :company, :label=>l(:field_contact_company) -%></p>
<%= javascript_tag "observeAutocompleteField('contact_company', '#{escape_javascript auto_complete_companies_path}')" %>
<p class="extended"><%= f.text_field :birthday, :size => 12 %><%= calendar_for('contact_birthday') %> </p>
</div>
<p id="job_title"><%= f.text_field :job_title, :label => !@contact.is_company ? l(:field_contact_job_title) : l(:field_company_field) %></p>
<% @contact.build_address if @contact.address.blank? %>
<%= f.fields_for(:address) do |a| %>
<span class="extended">
<%= render :partial => 'common/address_form', :locals => {:f => a} %>
</span>
<% end %>
<div id="phones_fields">
<p>
<%= f.text_field :phone, :label=>l(:field_contact_phone), :style => "width:90%;" -%>
<br>
<em class="info"><%= l(:text_comma_separated) %></em>
</p>
</div>
<p>
<%= f.text_field 'email', :label=>l(:field_contact_email), :style => "width:90%;" -%>
<br>
<em class="info"><%= l(:text_comma_separated) %></em>
</p>
<p class="extended"><%= f.text_field 'website', :label=>l(:field_contact_website) -%></p>
<p class="extended"><%= f.text_field 'skype_name', :label=>l(:field_contact_skype) -%></p>
<% @contact.custom_field_values.each do |value| %>
<p class="<%= "extended" unless value.custom_field.is_required? %>">
<%= custom_field_tag_with_label :contact, value %>
</p>
<% end -%>
<p class="extended notes"><%= f.text_area :background , :cols => 80, :rows => 8, :class => 'wiki-edit', :label=>l(:field_contact_background) %></p>
<%= wikitoolbar_for 'contact_background' %>
<p class="extended">
<%= label_tag l(:label_crm_tags_plural) %>
<%= render :partial => "contacts_tags/tags_form" %>
</p>
<% if @project %>
<p class="extended"><%= f.select :assigned_to_id, (@project.assignable_users.collect {|m| [m.name, m.id]}), :include_blank => true, :label => l(:label_crm_assigned_to) %></p>
<% end %>
<p class="extended"><%= f.select :visibility, collection_for_visibility_select, :include_blank => false, :label => l(:label_crm_contacts_visibility) %></p>
<p id="show_details_link" style="display: none;"><%= link_to l(:label_crm_show_details), "javascript:void(0);", :onclick => "$('#contact_data .extended').show();" %></p>
</div>
@@ -0,0 +1,24 @@
<div id="tags_data">
<%= tag_links(@contact.tag_list) %>
<% if authorize_for('contacts', 'update') %>
<span class="contextual">
<%= link_to l(:label_crm_edit_tags), {}, :onclick => "$('#edit_tags_form').show(); $('#tags_data').hide(); return false;", :id => 'edit_tags_link' %>
</span>
<% end %>
</div>
<div id="edit_tags_form" style="display:none;">
<%= form_tag( {:controller => 'contacts',
:action => 'update',
:project_id => @project,
:id => @contact },
:method => :put,
:multipart => true ) do %>
<%= render :partial => "contacts_tags/tags_form" %>
<%= submit_tag l(:button_save), :class => "button-small" %>
<%= link_to l(:button_cancel), {}, :onclick => "$('#edit_tags_form').hide(); $('#tags_data').show(); return false;" %>
<% end %>
</div>
@@ -0,0 +1,44 @@
<%= form_tag({}, :data => {:cm_url => context_menu_contacts_path}) do %>
<%= hidden_field_tag 'back_url', url_for(params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params) %>
<%= hidden_field_tag 'project_id', @project.id if @project %>
<div class="autoscroll">
<table class="list contacts">
<thead>
<tr>
<th class="checkbox hide-when-print">
<%= link_to image_tag('toggle_check.png'), {}, :onclick => 'toggleCRMIssuesSelection(this); return false;',
:title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}" %>
</th>
<% @query.columns.each do |column| %>
<%= Redmine::VERSION.to_s >= '3.4' || RedmineContacts.unstable_branch? ? column_header(@query, column) : column_header(column) %>
<% end %>
</tr>
</thead>
<% previous_group = false %>
<tbody>
<% @contacts.each do |contact| -%>
<% if @query.grouped? && (group = @query.group_by_column.value(contact)) != previous_group %>
<% reset_cycle %>
<tr class="group open">
<td colspan="<%= @query.columns.size + 2 %>">
<span class="expander" onclick="toggleRowGroup(this);">&nbsp;</span>
<%= group.blank? ? l(:label_none) : column_content(@query.group_by_column, contact) %> <span class="count">(<%= @contact_count_by_group[group] %>)</span>
<%= link_to_function("#{l(:button_collapse_all)}/#{l(:button_expand_all)}", "toggleAllRowGroups(this)", :class => 'toggle-all') %>
</td>
</tr>
<% previous_group = group %>
<% end %>
<tr id="contact-<%= h(contact.id) %>" class="contact <%= 'company' if contact.is_company %> hascontextmenu <%= cycle('odd', 'even') %>">
<td class="checkbox hide-when-print"><%= check_box_tag("selected_contacts[]", contact.id, false, :id => nil) %></td>
<% @query.columns.each do |column| %><%= content_tag 'td', column_content(column, contact), :class => column.css_classes %><% end %>
</tr>
<% end %>
</tbody>
</table>
</div>
<% end %>
@@ -0,0 +1,51 @@
<%= form_tag({}, :data => {:cm_url => context_menu_contacts_path}) do %>
<%= hidden_field_tag 'back_url', url_for(params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params) %>
<%= hidden_field_tag 'project_id', @project.id if @project %>
<div class="splitcontentleft">
<% i = 0 %>
<% split_on = (@contacts.size / 2.0).ceil - 1 %>
<% @contacts.each do |contact| %>
<% @contact = contact %>
<div class="contact card">
<table class="subject_header">
<tr>
<td class="avatar"><%= contact_tag(contact, :type => "avatar", :size => 64) %></td>
<td class="name" style="vertical-align: top;">
<h2><%= contact_tag(contact, :type => "plain") %> </h2>
<p>
<%= h contact.job_title %>
<% if !contact.is_company %>
<%= " #{l(:label_crm_at_company)} " unless (contact.job_title.blank? or contact.company.blank?) %>
<% if contact.contact_company %>
<%= link_to contact.contact_company.name, {:controller => 'contacts', :action => 'show', :project_id => contact.contact_company.project(@project), :id => contact.contact_company.id } %>
<% else %>
<%= h contact.company %>
<% end %>
<% end %>
</p>
<% if contact.phones.any? %>
<p class="phone icon icon-phone"><%= contact.phones.first %></p>
<% end %>
<% if contact.emails.any? %>
<p class="email icon icon-email"><%= mail_to contact.emails.first %></p>
<% end %>
<%= tag_links(contact.tag_list) %>
</td>
</tr>
</table>
</div>
<% if i == split_on -%>
</div><div class="splitcontentright">
<% end -%>
<% i += 1 -%>
<% end -%>
</div>
<div style="clear:both;"> </div>
<% end %>
@@ -0,0 +1,54 @@
<%= form_tag({}, :data => {:cm_url => context_menu_contacts_path}) do %>
<%= hidden_field_tag 'back_url', url_for(params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params) %>
<%= hidden_field_tag 'project_id', @project.id if @project %>
<div class="autoscroll">
<table class="contacts index">
<tbody>
<% previous_group = false %>
<% @contacts.each do |contact| %>
<% if @query.grouped? && (group = @query.group_by_column.value(contact)) != previous_group %>
<% reset_cycle %>
<tr class="group open">
<td colspan="<%= @query.columns.size + 2 %>">
<span class="expander" onclick="toggleRowGroup(this);">&nbsp;</span>
<%= group.blank? ? 'None' : column_content(@query.group_by_column, contact) %> <span class="count">(<%= @contact_count_by_group[group] %>)</span>
<%= link_to_function("#{l(:button_collapse_all)}/#{l(:button_expand_all)}", "toggleAllRowGroups(this)", :class => 'toggle-all') %>
</td>
</tr>
<% previous_group = group %>
<% end %>
<tr class="hascontextmenu <%= cycle('odd', 'even') %> ">
<td class="checkbox">
<%= check_box_tag "selected_contacts[]", contact.id, false, :onclick => "toggleContact(event, this);" %>
</td>
<td class="avatar">
<%= link_to avatar_to(contact, :size => "32"), contact_path(contact, :project_id => @project), :id => "avatar" %>
</td>
<td class="name">
<h1><%= link_to contact.name, contact_path(contact, :project_id => @project) %></h1>
<p>
<%= link_to contact.website, contact.website_address, :class => 'external', :only_path => true unless !contact.is_company %>
<%= mail_to contact.emails.first unless contact.is_company%>
<div><%= contact.phones.first %></div>
</p>
</td>
<td class="info">
<div class="title_and_company" >
<%= contact.job_title %>
<% if !contact.is_company %>
<%= " #{l(:label_crm_at_company)} " unless (contact.job_title.blank? or contact.company.blank?) %>
<%= contact.company %>
<% end %>
</div>
<div class="tags">
<%= tag_links(contact.tag_list) %>
<%# tag_links(RedmineCrm::TagList.from(contact.cached_tag_list)) %>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<% end %>
@@ -0,0 +1,37 @@
<script type="text/javascript">
jQuery(function($) {
// when the #search field changes
var duplicates = function() {
var form = $("#contact_form"); // grab the form wrapping the search bar.
var url = '<%= escape_javascript(url_for({:controller => "contacts_duplicates", :action => "duplicates", :project_id => @project, :contact_id => @contact})) %>';
var formData = form.serialize();
$.get(url, formData, function(data) { // perform an AJAX get, the trailing function is what happens on successful get.
$("#duplicates").html(data); // replace the "results" div with the result of action taken
});
}
$("#contact_first_name").observe_field(2, duplicates);
$("#contact_middle_name").observe_field(2, duplicates);
$("#contact_last_name").observe_field(2, duplicates);
});
</script>
<%# observe_field("contact_first_name",
:frequency => 1,
:update => 'duplicates',
:url => {:controller => 'contacts_duplicates', :action => 'duplicates', :project_id => @project, :contact_id => @contact},
:with => "$('contact_form').serialize()") %>
<%# observe_field("contact_middle_name",
:frequency => 1,
:update => 'duplicates',
:url => {:controller => 'contacts_duplicates', :action => 'duplicates', :project_id => @project, :contact_id => @contact},
:with => "$('contact_form').serialize()") %>
<%# observe_field("contact_last_name",
:frequency => 1,
:update => 'duplicates',
:url => {:controller => 'contacts_duplicates', :action => 'duplicates', :project_id => @project, :contact_id => @contact},
:with => "$('contact_form').serialize()") %>
@@ -0,0 +1,15 @@
<h3 class="title"><%=l(:label_crm_contact_new)%></h3>
<%= labelled_form_for @contact, :url => project_contacts_path(@project), :remote => true do |f| %>
<%= hidden_field_tag :contact_field_name, params[:contact_field_name] %>
<%= hidden_field_tag :contacts_is_company, params[:contacts_is_company] %>
<%= render :partial => 'contacts/form', :locals => { :f => f } %>
<p class="buttons">
<%= submit_tag l(:button_create), :name => nil %>
<%= submit_tag l(:button_cancel), :name => nil, :onclick => "hideModal(this);", :type => 'button' %>
</p>
<% end %>
<% content_for :header_tags do %>
<%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %>
<% end %>
@@ -0,0 +1,29 @@
<%
extend Redmine::Pagination
source_id_cond = @contact.is_company ? Contact.visible.where(:company => @contact.first_name).map(&:id) << @contact.id : @contact.id
@note = Note.new(:created_on => Time.now)
scope = Note.where({:source_id => source_id_cond, :source_type => 'Contact'}).includes(:attachments).order("#{Note.table_name}.created_on DESC")
@notes_pages = Redmine::Pagination::Paginator.new(scope.count, 20, params['page'])
@notes = scope.limit(20).offset(@notes_pages.offset)
%>
<% if authorize_for(:notes, :create) %>
<div class="add-note hide-when-print">
<%= render :partial => 'notes/add', :locals => {:note_source => @contact} %>
</div>
<% end %>
<% if @contact.is_public? || authorize_for(:notes, :show) %>
<div id="comments">
<div id="notes">
<%= render :partial => 'notes/note_item', :collection => @notes, :locals => {:show_info => @contact.is_company, :note_source => @contact} %>
<span class="pagination"> <%= pagination_links_full @notes_pages %> </span>
</div>
</div>
<% other_formats_links do |f| %>
<% filtered_params = params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params %>
<%= f.link_to 'Atom', :url => filtered_params.merge(:key => User.current.rss_key) %>
<% end %>
<% end %>
@@ -0,0 +1,10 @@
<div id="tags_data">
<span class="tags">
<%= render :partial => 'contacts/tags_item', :collection => tag_list, :locals => {:is_note => false} %>
</span>
<% if editable && authorize_for('contacts', 'update') %>
<span class="contextual">
<%= link_to l(:label_crm_edit_tags), {}, :onclick => "$('#edit_tags_form').show(); $('#tags_data').hide(); return false;", :id => 'edit_tags_link' %>
</span>
<% end %>
</div>
@@ -0,0 +1,7 @@
<div id="tags">
<span id="single_tags">
<h3><%= l(:label_crm_tags_plural) %></h3>
<span class="tag_list"><%= safe_join(tags_cloud.map{|tag| tag_link(tag.name, :count => tag.count)}, ContactsSetting.monochrome_tags? ? ', ' : ' ').html_safe %></span>
</span>
</div>
@@ -0,0 +1,19 @@
<%
html_options = {:id => "tag_#{tags_item.id}",
:style => "background-color: #{tags_item.color_name}"}
taggable_type ||= 'contacts'
tag_url = {:controller => taggable_type,
:action => 'index',
:set_filter => 1,
:fields => [:tags],
:values => {:tags => [tags_item.name]},
:operators => {:tags => '='}}
%>
<span class="tag" >
<%- if !is_note -%>
<%= link_to tags_item.name + "#{"(" + tags_item.count.to_s + ")" if tags_item.count > 0}", {:project_id => @project}.merge!(tag_url), html_options %>
<%- else -%>
<%= link_to tags_item.name, {:controller => "contacts", :action => "contacts_notes", :project_id => @project, :tag => tags_item.name}, html_options %>
<%- end -%>
</span>
@@ -0,0 +1,130 @@
<h2><%= l(:label_crm_bulk_edit_selected_contacts) %></h2>
<div class="box" id="duplicates">
<ul>
<% @contacts.each do |contact| %>
<li>
<%= avatar_to contact, :size => "16" %>
<%= link_to_source contact %>,
<%= h contact.job_title %>
<%= " #{l(:label_crm_at_company)} " unless (contact.job_title.blank? or contact.company.blank?) %>
<% if contact.contact_company %>
<%= link_to contact.contact_company.name, {:controller => 'contacts', :action => 'show', :id => contact.contact_company.id } %>
<% else %>
<%= h contact.company %>
<% end %>
<%= "(#{l(:field_contact_tag_names)}: #{contact.tag_list})" if contact.tags.any? %>
</li>
<% end %>
</ul>
</div>
<%= form_tag(:action => 'bulk_update', :project_id => @project) do %>
<%= @contacts.collect {|i| hidden_field_tag('ids[]', i.id)}.join.html_safe %>
<div class="box tabular">
<fieldset class="attributes">
<legend><%= l(:label_change_properties) %></legend>
<div class="splitcontentleft">
<p>
<label><%= l(:field_company) %></label>
<%= text_field_tag('contact[company]', '') %>
<%= javascript_tag "observeAutocompleteField('contact_company', '#{escape_javascript auto_complete_companies_path(:project_id => @project)}')" %>
</p>
<% @custom_fields.each do |custom_field| %>
<p><label><%= h(custom_field.name) %></label> <%= custom_field_tag_for_bulk_edit('contact', custom_field, @projects) %></p>
<% end %>
<p>
<label><%= l(:label_crm_assigned_to) %></label>
<%= select_tag('contact[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)) %>
</p>
<p>
<label><%= l(:label_crm_contacts_visibility) %></label>
<%= select_tag 'contact[visibility]', options_for_select(collection_for_visibility_select) %>
</p>
</div>
<div class="splitcontentright">
<p>
<label><%= l(:field_contact_job_title) %>/<%= l(:field_company_field) %></label>
<%= text_field_tag('contact[job_title]', '') %>
</p>
<p class="address city">
<label><%= l(:label_crm_city) %></label>
<%= text_field_tag 'contact[address_attributes][city]' -%>
</p>
<p class="address region">
<label><%= l(:label_crm_region) %></label>
<%= text_field_tag 'contact[address_attributes][region]' -%>
</p>
<p class="address country">
<label><%= l(:label_crm_country) %></label>
<%= select_tag 'contact[address_attributes][country_code]', options_for_select(l(:label_crm_countries).map{|k, v| [v, k]}), :include_blank => true -%>
</p>
</div>
</fieldset>
<fieldset class="attributes">
<legend><%= l(:label_crm_tags_plural) %></legend>
<div class="splitcontentleft">
<p id="add_tags" class="contacts-tags-edit">
<label><%= l(:field_add_tags) %></label>
<%= text_field_tag 'add_tag_list', '', :size => 10, :class => "hol" %><%= tagsedit_with_source_for("#add_tag_list", auto_complete_contact_tags_path(:project_id => @project)) %>
</p>
</div>
<div class="splitcontentright">
<p id="delete_tags" class="contacts-tags-edit">
<label><%= l(:field_delete_tags) %></label>
<%= text_field_tag 'delete_tag_list', '', :label => :field_contact_tag_names, :size => 10, :class => "hol" %><%= tagsedit_with_source_for("#delete_tag_list", auto_complete_contact_tags_path(:project_id => @project)) %>
</p>
</div>
</fieldset>
<% if @add_projects.any? %>
<fieldset class="attributes">
<legend><%= l(:label_project_plural) %></legend>
<div class="splitcontentleft">
<p>
<label><%= l(:label_crm_add_into) %></label>
<%= select_tag 'add_projects_list[]', content_tag('option', l(:label_no_change_option), :value => '', :selected => 'selected') + project_tree_options_for_select(@add_projects), :multiple => false %>
</p>
</div>
<div class="splitcontentright">
<p>
<label><%= l(:label_crm_delete_from) %></label>
<%= select_tag 'delete_projects_list[]', content_tag('option', l(:label_no_change_option), :value => '', :selected => 'selected') + project_tree_options_for_select(@add_projects), :multiple => false %>
</p>
</div>
</fieldset>
<% end %>
<fieldset><legend><%= l(:field_notes) %></legend>
<%= text_area_tag 'note[content]', '', :cols => 60, :rows => 10, :class => 'wiki-edit' %>
<%= wikitoolbar_for 'note_content' %>
</fieldset>
</div>
<p><%= submit_tag l(:button_submit) %></p>
<% end %>
@@ -0,0 +1,64 @@
<% filtered_params = params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params %>
<div class="filters">
<% if !@tag %>
<%= form_tag(filtered_params, :id => "query_form", :method => :get) do %>
<%= hidden_field_tag('project_id', @project.to_param) if @project %>
<h2>
<span class="scope_title">
<%= l(:label_crm_contact_all_note_plural) %>
</span>
<span class="live_search">
<%= text_field_tag(:search_note, params[:search_note], :autocomplete => "off", :class => "live_search_field", :placeholder => l(:label_crm_contact_search) ) %>
<script type="text/javascript">
jQuery(function($) {
// when the #search field changes
$("#search_note").observe_field(2, function() {
var form = $("#query_form"); // grab the form wrapping the search bar.
var url = form.attr("action");
var formData = form.serialize();
$.get(url, formData, function(data) { // perform an AJAX get, the trailing function is what happens on successful get.
$("#contacts_notes").html(data); // replace the "results" div with the result of action taken
});
});
});
</script>
</span>
</h2>
<% end %>
<% else %>
<h2 class="scope_title"><%= "#{l(:label_crm_contact_tag)}(#{@notes_pages.item_count}): #{tag_links(@tag)}".html_safe %> </h2>
<% end %>
</div>
<div id="contacts_notes">
<%= render :partial => 'notes/notes_list' %>
</div>
<% other_formats_links do |f| %>
<%= f.link_to 'Atom', :url => filtered_params.merge(:key => User.current.rss_key) %>
<%= f.link_to 'CSV', :url => filtered_params %>
<% end %>
<% content_for :sidebar do %>
<%= render :partial => 'common/sidebar' %>
<h3><%= l(:label_crm_note_plural) %></h3>
<div id="note_types">
<% collection_for_note_types_select.each do |note_type| %>
<%= radio_button_tag "note_type", note_type[1], filtered_params[:type_id].to_s == note_type[1].to_s, {:onchange => "document.location='#{url_for(filtered_params.merge(:type_id => note_type[1]))}';", :id => "note_type_#{note_type[1]}" }%>
<%= label_tag "note_type_#{note_type[1]}", note_type[0] %>
<br>
<% end %>
</div>
<h3><%= l(:label_crm_tags_plural) %></h3>
<div id="tags">
<span class="tag_list"><%= @tags.map{|tag| content_tag(:span, link_to(tag.name, {:controller => "contacts", :action => "contacts_notes", :project_id => @project, :tag => tag.name}), {}.merge(ContactsSetting.monochrome_tags? ? {:class => "tag-label"} : {:class => "tag-label-color", :style => "background-color: #{tag_color(tag.name)}"}))}.join(' ').html_safe %></span>
</div>
<%= render :partial => 'common/recently_viewed' %>
<% end %>
<% content_for(:header_tags) do %>
<%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %>
<%= stylesheet_link_tag :contacts_sidebar, :plugin => 'redmine_contacts' %>
<% end %>
@@ -0,0 +1,35 @@
<ul>
<%= call_hook(:view_contacts_context_menu_start, {:contacts => @contacts, :can => @can, :back => @back }) %>
<% unless @contact.nil? %>
<li><%= context_menu_link l(:button_edit), {:controller => 'contacts', :action => 'edit', :id => @contact, :project_id => @project}, :class => 'icon-edit', :disabled => !@can[:edit] %></li>
<% if User.current.logged? %>
<li><%= watcher_link(@contact, User.current) %></li>
<% end %>
<% if !@project.nil? %>
<li><%= context_menu_link l(:label_crm_deal_new), {:controller => 'deals', :action => 'new', :project_id => @project, :contact_id => @contact},
:class => 'icon-add-deal', :disabled => !@can[:create_deal] %></li>
<% if @contact.is_company? %>
<li><%= context_menu_link l(:label_crm_add_contact), {:controller => 'contacts', :action => 'new', :project_id => @project, :contact => {:company => @contact.name}},
:class => 'icon-company-contact', :disabled => !@can[:create] %></li>
<% end %>
<% end %>
<% else %>
<li><%= context_menu_link l(:button_edit), {:controller => 'contacts', :action => 'bulk_edit', :ids => @contacts.collect(&:id)},
:class => 'icon-edit', :disabled => !@can[:edit] %></li>
<% end %>
<li><%= context_menu_link l(:label_crm_send_mail), {:controller => 'contacts', :action => 'edit_mails', :ids => @contacts.collect(&:id), :project_id => @project}, :class => 'icon-email', :disabled => !@can[:send_mails] %></li>
<%= call_hook(:view_contacts_context_menu_before_delete, {:contacts => @contacts, :can => @can, :back => @back }) %>
<li><%= context_menu_link l(:button_delete), {:controller => 'contacts', :action => 'bulk_destroy', :ids => @contacts.collect(&:id), :project_id => @project},
:method => :delete, :data => {:confirm => l(:text_are_you_sure)}, :class => 'icon-del', :disabled => !@can[:delete] %></li>
<% if !@contact && Redmine::VERSION.to_s >= '3.3' %>
<li>
<%= context_menu_link l(:button_filter), _project_contacts_path(@project, :set_filter => 1, :ids => @contacts.map(&:id).join(',')),
:class => 'icon-list' %>
</li>
<% end %>
<%= call_hook(:view_contacts_context_menu_end, {:contacts => @contacts, :can => @can, :back => @back }) %>
</ul>
@@ -0,0 +1,13 @@
hideModal();
<% field_id = params[:contact_field_name].to_s.gsub("[", "_").gsub("]", "") -%>
$('select#<%= field_id %>')
.append($("<option></option>")
.attr("value",'<%= @contact.id %>')
.attr("selected",'selected')
.text('<%= @contact.name %>'));
$('input#<%= field_id %>').val('<%= @contact.id %>');
$('#<%= field_id %>_selected_contact').text('<%= @contact.name %>');
$('#<%= field_id %>_selected_contact').show();
$('#<%= field_id %>_selected_contact').scrollTop( 0 );
$('input#<%= field_id %>').hide();
$('#<%= field_id %>_edit_link').show();
+28
View File
@@ -0,0 +1,28 @@
<div class="contextual">
<%= link_to_if_authorized l(:label_crm_merge_duplicate_plural), {:controller => 'contacts_duplicates', :action => 'index', :project_id => @project, :contact_id => @contact}, :class => 'icon icon-merge' unless @contact.new_record? %>
</div>
<h2><%= l(:label_crm_contact_edit_information) %></h2>
<%= labelled_form_for :contact, @contact,
:url => {:action => 'update', :project_id => @project, :id => @contact},
:html => { :multipart => true, :method => :put, :id => "contact_form" } do |f| %>
<%= render :partial => 'form', :locals => {:f => f} %>
<%= render :partial => 'name_observer' %>
<%= submit_tag l(:button_save) -%>
<% end -%>
<% content_for :sidebar do %>
<%= render :partial => 'common/sidebar' %>
<%= render :partial => 'contacts_duplicates/duplicates' %>
<div id="contact_projects">
<%= render :partial => 'contacts_projects/related' %>
</div>
<% end %>
<% content_for :header_tags do %>
<%= javascript_include_tag 'attachments' %>
<%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %>
<%= stylesheet_link_tag :contacts_sidebar, :plugin => 'redmine_contacts' %>
<%= robot_exclusion_tag %>
<% end %>
@@ -0,0 +1,64 @@
<h2><%= l(:label_crm_bulk_send_mail_selected_contacts) %></h2>
<div class="box" id="duplicates">
<ul>
<% @contacts.each do |contact| %>
<li>
<%= avatar_to contact, :size => "16" %>
<%= link_to_source contact %>
<%= "(#{contact.job_title}) " unless contact.job_title.blank? %>
- <%= contact.emails.first %>
</li>
<% end %>
</ul>
</div>
<%= form_for(:email_message, :url => {:action => 'send_mails', :project_id => @project}, :html => {:multipart => true, :id => 'message-form'}) do %>
<%= @contacts.collect {|i| hidden_field_tag('ids[]', i.id)}.join.html_safe %>
<div class="box tabular">
<p>
<label><%= l(:field_mail_from) %></label>
<%= text_field_tag('from', "#{User.current.name} <#{User.current.mail}>", :style => "width: 98%;") %>
<%= link_to "#{l(:label_crm_contacts_cc)}/#{l(:label_crm_contacts_bcc)}", '#' , :onclick => "$('#mail_cc').show();$(this).hide();" %>
</p>
<span id="mail_cc" style="display:none;">
<p>
<label><%= l(:label_crm_contacts_cc) %></label>
<%= text_field_tag('cc', '', :style => "width: 98%;") %>
</p>
<p>
<label><%= l(:label_crm_contacts_bcc) %></label>
<%= text_field_tag('bcc', '', :style => "width: 98%;") %>
</p>
</span>
<p>
<label><%= l(:field_subject) %></label>
<%= text_field_tag('subject', '', :id => "subject", :style => "width: 98%;") %>
</p>
<p>
<label><%= l(:field_message) %></label>
<%= text_area_tag 'message-content', '', :cols => 60, :rows => 10, :class => 'wiki-edit' %>
<em class="info"><%= l(:text_email_macros, :macro => "%%NAME%%, %%LAST_NAME%%, %%MIDDLE_NAME%%, %%FULL_NAME%%, %%COMPANY%%, %%DATE%%, %%[Custom field]%%") %></em>
</p>
<%= wikitoolbar_for 'message-content' %>
<p id="attachments_form"><%= label_tag('attachments[1][file]', l(:label_attachment_plural))%><%= render :partial => 'attachments/form' %></p>
</div>
<p>
<%= submit_tag l(:button_submit) %>
<%= preview_link({ :controller => 'contacts', :action => 'preview_email' }, 'message-form') %>
</p>
<% end %>
<div id="preview" class="wiki"></div>
<% content_for :header_tags do %>
<%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %>
<% end %>
@@ -0,0 +1,53 @@
api.array :contacts, api_meta(:total_count => @contacts_count, :offset => @offset, :limit => @limit) do
@contacts.each do |contact|
api.contact do
api.id contact.id
api.avatar(:attachment_id => contact.avatar.id) if contact.avatar
api.is_company contact.is_company
api.first_name contact.first_name
api.last_name contact.last_name
api.middle_name contact.middle_name
api.company contact.company
api.website contact.website
api.skype_name contact.skype_name
api.birthday contact.birthday
api.job_title contact.job_title
api.background contact.background
api.author(:id => contact.author_id, :name => contact.author.name) unless contact.author.nil?
api.assigned_to(:id => contact.assigned_to_id, :name => contact.assigned_to.name) unless contact.assigned_to.nil?
api.address do
api.full_address contact.address
api.street contact.street1
api.city contact.city
api.region contact.region
api.country contact.country
api.country_code contact.address.country_code unless contact.address.blank?
api.postcode contact.postcode
end
api.array :phones do
contact.phones.each do |phone|
api.phone do
api.number phone
end
end
end if contact.phones.any?
api.array :emails do
contact.emails.each do |email|
api.email do
api.address email
end
end
end if contact.emails.any?
api.tag_list contact.tag_list
render_api_custom_values contact.custom_field_values, api
api.created_on contact.created_on
api.updated_on contact.updated_on
end
end
end
+203
View File
@@ -0,0 +1,203 @@
<% filtered_params = params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params %>
<div class="contextual">
<% if !@query.new_record? && @query.editable_by?(User.current) %>
<%= link_to l(:button_contacts_edit_query), edit_crm_query_path(@query, :object_type => "contact"), :class => 'icon icon-edit' %>
<%= link_to l(:button_contacts_delete_query), crm_query_path(@query, :object_type => "contact"), :data => {:confirm => l(:text_are_you_sure)}, :method => :delete, :class => 'icon icon-del' %>
<% end %>
<%= link_to_if_authorized l(:label_crm_contact_new), {:controller => 'contacts', :action => 'new', :project_id => @project}, :class => 'icon icon-add' %>
<%= link_to_if_authorized l(:label_crm_import), {:controller => 'contact_imports', :action => 'new', :project_id => @project}, :class => 'icon icon-import', :id => 'import_from_csv' %>
<%= call_hook(:view_contacts_action_menu) %>
</div>
<% html_title(@query.new_record? ? l(:label_contact_plural) : @query.name) %>
<%= form_tag({ :controller => 'contacts', :action => 'index', :project_id => @project }, :method => :get, :id => 'query_form') do %>
<script type="text/javascript">
jQuery(function($) {
// when the #search field changes
$("#search").observe_field(2, function() {
var form = $("#query_form"); // grab the form wrapping the search bar.
var url = form.attr("action");
form.find('[name="c[]"] option').each(function(i, elem){
$(elem).attr('selected', true)
})
var formData = form.serialize();
form.find('[name="c[]"] option').each(function(i, elem){
$(elem).attr('selected', false)
})
$.get(url, formData, function(data) { // perform an AJAX get, the trailing function is what happens on successful get.
$("#contact_list").html(data); // replace the "results" div with the result of action taken
});
});
});
</script>
<h2 class="contacts_header">
<span id='scope_header' class="scope_title">
<%= @query.new_record? ? l(:label_contact_plural) : h(@query.name) %>
</span>
<span class="live_search">
<%= text_field_tag(:search, params[:search], :autocomplete => "off", :class => "live_search_field", :placeholder => l(:label_crm_contact_search) ) %>
</span>
<span class="tags">
<%= tag_links(@filter_tags) %>
</span>
</h2>
<%= hidden_field_tag 'set_filter', '1' %>
<%= hidden_field_tag 'object_type', 'contact' %>
<div id="query_form_content" class="hide-when-print">
<fieldset id="filters" class="collapsible <%= @query.new_record? ? "" : "collapsed" %>">
<legend onclick="toggleFieldset(this);"><%= l(:label_filter_plural) %></legend>
<div style="<%= @query.new_record? ? "" : "display: none;" %>">
<%= render :partial => 'queries/filters', :locals => {:query => @query} %>
</div>
</fieldset>
<fieldset class="collapsible collapsed">
<legend onclick="toggleFieldset(this);"><%= l(:label_options) %></legend>
<div style="display: none;">
<table>
<tr style="<%= 'display: none;' if contacts_list_style != 'list' %>">
<td><%= l(:field_column_names) %></td>
<td><%= render_query_columns_selection(@query) %></td>
</tr>
<tr>
<% if contacts_list_style != 'list_cards' %>
<td><label for='group_by'><%= l(:field_group_by) %></label></td>
<td><%= select_tag('group_by', options_for_select([[]] + @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]}, @query.group_by)) %></td>
<% end -%>
<% if contacts_list_style != 'list' %>
<td><label for='sort'><%= l(:label_sort) %></label></td>
<td><%= select_tag('sort',
options_for_select(
[[]] +
[[l(:field_contact_job_title), "job_title"],
[l(:field_contact_company), "company"],
[l(:field_created_on), "created_on:desc"],
[l(:field_updated_on), "updated_on:desc"]],
params[:sort])
) %></td>
<% end %>
</tr>
<tr>
<td><label for='contacts_list_style'><%= l(:label_crm_list_partial_style) %></label></td>
<td><%= select_tag('contacts_list_style', options_for_select(contact_list_styles_for_select, contacts_list_style)) %></td>
</tr>
</table>
</div>
</fieldset>
</div>
<p class="buttons hide-when-print">
<%= link_to_function l(:button_apply), 'submit_query_form("query_form")', :class => 'icon icon-checked' %>
<%= link_to l(:button_clear), { :set_filter => 1, :project_id => @project }, :class => 'icon icon-reload' %>
<% if @query.new_record? && User.current.allowed_to?(:save_contacts_queries, @project, :global => true) %>
<%= link_to_function l(:button_save),
"$('#query_form').attr('action', '#{ @project ? new_project_crm_query_path(@project) : new_crm_query_path }'); submit_query_form('query_form')",
:class => 'icon icon-save' %>
<% end %>
</p>
<% end %>
<%= error_messages_for 'query' %>
<% if @query.valid? %>
<div id="contact_list">
<% if @contacts.empty? %>
<p class="nodata"><%= l(:label_no_data) %></p>
<% else %>
<%= render :partial => contacts_list_style %>
<span class="pagination"><%= pagination_links_full @contacts_pages, @contacts_count %></span>
<% end %>
</div>
<% if User.current.allowed_to?(:export_contacts, @project, :global => true) %>
<% other_formats_links do |f| %>
<%= f.link_to 'Atom', :url => filtered_params.merge(:key => User.current.rss_key) %>
<% if contacts_list_style == 'list' %>
<%= f.link_to 'CSV', :url => filtered_params, :onclick => "showModal('csv-export-options', '350px'); return false;" %>
<% else %>
<%= f.link_to 'CSV', :url => filtered_params %>
<% end %>
<%- if ContactsSetting.vcard? -%>
<%= f.link_to 'VCF', :url => filtered_params %>
<%- end -%>
<%- if ContactsSetting.spreadsheet? -%>
<%= f.link_to 'XLS', :url => filtered_params %>
<%- end -%>
<% end %>
<div id="csv-export-options" style="display:none;">
<h3 class="title">
<%= l(:label_export_options, :export_format => 'CSV') %>
</h3>
<%= form_tag({:controller => 'contacts',
:action => 'index',
:project_id => @project,
:format => 'csv'},
:method => :get,
:id => 'csv-export-form') do %>
<% columns_name = 'c[]' %>
<% if Redmine::VERSION::STRING > '3.2.1' %>
<%= query_as_hidden_field_tags(@query) %>
<% if Redmine::VERSION::STRING < '3.4' %>
<%= hidden_field_tag 'sort', @sort_criteria.to_param, :id => nil %>
<% columns_name = 'csv[columns]' %>
<% end %>
<% elsif Redmine::VERSION::STRING < '3.2' %>
<% columns_name = 'columns' %>
<% end %>
<p>
<label>
<%= radio_button_tag columns_name, '', true %>
<%= l(:description_selected_columns) %>
</label>
<br />
<label>
<%= radio_button_tag columns_name, 'all_inline' %>
<%= l(:description_all_columns) %>
</label>
</p>
<p class="buttons">
<%= submit_tag l(:button_export),
:name => nil,
:onclick => "hideModal(this);" %>
<%= submit_tag l(:button_cancel),
:name => nil,
:onclick => "hideModal(this);",
:type => 'button' %>
</p>
<% end %>
</div>
<% end %>
<% end %>
<% content_for :sidebar do %>
<%= render :partial => 'common/sidebar' %>
<%= render :partial => 'tags_cloud', :object => @tags %>
<%= render_sidebar_crm_queries('contact') %>
<%= render :partial => 'notes/last_notes', :object => @last_notes %>
<%= render :partial => 'common/recently_viewed' %>
<%= call_hook(:view_contacts_sidebar_contacts_list_bottom) %>
<% end %>
<% content_for(:header_tags) do %>
<%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %>
<%= stylesheet_link_tag :contacts_sidebar, :plugin => 'redmine_contacts' %>
<%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => l(:label_contact_plural)) %>
<% end %>
<% if Redmine::VERSION.to_s >= '3.4' || RedmineContacts.unstable_branch? %>
<%= context_menu %>
<% else %>
<%= context_menu url_for( {:controller => "contacts", :action => "context_menu"} ) %>
<% end %>
@@ -0,0 +1,5 @@
<%
@tab = params[:tab_name]
@partial = params[:partial]
%>
$('#tab-placeholder-<%= @tab %>').html("<%= j(render :partial => @partial) %>")
+23
View File
@@ -0,0 +1,23 @@
<h2><%= l(:label_crm_contact_new) %></h2>
<%= labelled_form_for :contact, @contact, :url => {:action => 'create', :project_id => @project}, :html => { :multipart => true, :id => 'contact_form'} do |f| %>
<%= render :partial => 'form', :locals => {:f => f} %>
<%= render :partial => 'name_observer' %>
<%= submit_tag l(:button_save) -%>
<%= submit_tag l(:button_create_and_continue), :name => 'continue' %>
<% end -%>
<% content_for :sidebar do %>
<%= render :partial => 'common/sidebar' %>
<%= render :partial => 'contacts_duplicates/duplicates' %>
<%= render :partial => 'contacts_vcf/load' %>
<% end %>
<% content_for :header_tags do %>
<%= javascript_include_tag 'attachments' %>
<%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %>
<%= stylesheet_link_tag :contacts_sidebar, :plugin => 'redmine_contacts' %>
<%= robot_exclusion_tag %>
<% end %>
@@ -0,0 +1,9 @@
$('#ajax-modal').html('<%= escape_javascript(render :partial => 'contacts/new_modal') %>');
$('#ajax-modal #contact_data .extended').hide();
$('#ajax-modal #contact_data #show_details_link').show();
showModal('ajax-modal', '800px');
$('#new_contact').submit( function(event) {
$('.file_selector').val('');
event.preventDefault();
});
@@ -0,0 +1,110 @@
api.contact do
api.id @contact.id
api.avatar(:attachment_id => @contact.avatar.id) if @contact.avatar
api.is_company @contact.is_company
api.first_name @contact.first_name
api.last_name @contact.last_name
api.middle_name @contact.middle_name
api.company @contact.company
api.website @contact.website
api.skype_name @contact.skype_name
api.birthday @contact.birthday
api.job_title @contact.job_title
api.background @contact.background
api.author(:id => @contact.author_id, :name => @contact.author.name) unless @contact.author.nil?
api.assigned_to(:id => @contact.assigned_to_id, :name => @contact.assigned_to.name) unless @contact.assigned_to.nil?
api.address do
api.full_address @contact.address
api.street @contact.street1
api.city @contact.city
api.region @contact.region
api.country @contact.country
api.country_code @contact.address.country_code unless @contact.address.blank?
api.postcode @contact.postcode
end
api.array :phones do
@contact.phones.each do |phone|
api.phone do
api.number phone
end
end
end if @contact.phones.any?
api.array :emails do
@contact.emails.each do |email|
api.email do
api.address email
end
end
end if @contact.emails.any?
api.tag_list @contact.tag_list
render_api_custom_values @contact.custom_field_values, api
api.created_on @contact.created_on
api.updated_on @contact.updated_on
api.array :projects do
@contact.projects.each do |project|
api.project(:id => project.id, :name => project.name)
end
end if @contact.projects.present?
if authorize_for(:notes, :show)
api.array :notes do
@contact.notes.each do |note|
api.note do
api.id note.id
api.content note.content
api.type_id note.type_id
api.author(:id => note.author_id, :name => note.author.name) unless note.author.nil?
api.created_on note.created_on
api.updated_on note.updated_on
end
end
end if include_in_api_response?('notes') && @contact.notes.present? && User.current.allowed_to?(:view_contacts, @project)
end
api.array :contacts do
@contact.company_contacts.each do |contact|
api.contact(:id => contact.id, :name => contact.name )
end
end if include_in_api_response?('contacts') && @contact.company_contacts.present?
api.array :deals do
(@contact.related_deals + @contact.deals).each do |deal|
api.deal do
api.id deal.id
api.price deal.price
api.currency deal.currency
api.price_type deal.price_type
api.name deal.name
api.project(:id => deal.project.id, :name => deal.project.name)
api.status(:id => deal.status.id, :name => deal.status.name)
api.background deal.background
api.created_on deal.created_on
api.updated_on deal.updated_on
end
end
end if include_in_api_response?('deals') && (@contact.related_deals + @contact.deals).present? && User.current.allowed_to?(:view_deals, @project)
if authorize_for(:issues, :show)
api.array :issues do
@contact.issues.each do |issue|
api.issue do
api.id issue.id
api.subject issue.subject
api.status(:id => issue.status_id, :name => issue.status.name) unless issue.status.nil?
api.due_date issue.due_date
api.created_on issue.created_on
api.updated_on issue.updated_on
end
end
end if include_in_api_response?('issues') && @contact.issues.present? && User.current.allowed_to?(:view_issues, @project)
end
call_hook(:api_contacts_show)
end
+86
View File
@@ -0,0 +1,86 @@
<%= error_messages_for 'contact', 'note' %>
<% html_title "#{l(:label_contact)} ##{@contact.id}: #{@contact.name}" %>
<div class="contextual">
<%= call_hook(:view_contacts_before_actions, :contact => @contact, :project => @project) %>
<%= link_to l(:label_profile), user_path(@contact.redmine_user), :class => 'icon icon-user' unless @contact.redmine_user.blank? %>
<%= link_to(l(:button_create), {:controller => 'users', :action => 'new_from_contact', :contact_id => @contact.id, :id => 'current'}, :class => 'icon icon-user') if (User.current.admin? && @contact.redmine_user.blank? && !@contact.email.blank?) %>
<%= link_to_if_authorized l(:label_crm_send_mail), {:controller => 'contacts', :action => 'edit_mails', :ids => [@contact.id], :project_id => @project}, :class => 'icon icon-email' unless @contact.primary_email.blank? %>
<%= watcher_link(@contact, User.current) %>
<%= link_to l(:button_edit), {:controller => 'contacts', :action => 'edit', :project_id => @project, :id => @contact}, :class => 'icon icon-edit' if @contact.editable? %>
<%= link_to l(:button_delete), {:controller => 'contacts', :action => 'destroy', :project_id => @project, :id => @contact}, :data => {:confirm => l(:text_are_you_sure)}, :method => :delete, :class => 'icon icon-del' if @contact.deletable? %>
<%= call_hook(:view_contacts_after_actions, :contact => @contact, :project => @project) %>
</div>
<h2><%= !@contact.is_company ? l(:label_contact) : l(:label_crm_company) %> #<%= @contact.id %></h2>
<div class="contact details<%= ' private' if @contact.is_private? %>">
<table class="subject_header">
<tr>
<td class="avatar"><%= avatar_to(@contact, :size => "64", :full_size => true) %></td>
<td class="name" style="vertical-align: top;">
<h1><%= h @contact.name %></h1>
<% if !@contact.is_company %>
<p>
<%= h @contact.job_title %>
<%= " #{l(:label_crm_at_company)} " unless (@contact.job_title.blank? or @contact.company.blank?) %>
<% if @contact.contact_company %>
<%= link_to @contact.contact_company.name, {:controller => 'contacts', :action => 'show', :project_id => @contact.contact_company.project(@project), :id => @contact.contact_company.id } %>
<% else %>
<%= h @contact.company %>
<% end %>
</p>
<% end %>
<%= render :partial => 'form_tags', :object => @contact.tags, :locals => {:editable => true} %>
</td>
<% if @contact.phones.any? || @contact.emails.any? %>
<td class="subject_info">
<ul>
<% if @contact.phones.any? %>
<li class="phone icon icon-phone"><%= @contact.phones.first %></li>
<% end %>
<% if @contact.emails.any? %>
<li class="email icon icon-email"><%= mail_to @contact.emails.first %></li>
<% end %>
</ul>
</td>
<% end %>
</tr>
</table>
<%= call_hook(:view_contacts_show_details_bottom, :contact => @contact) %>
</div>
<%= render_contact_tabs contact_tabs(@contact) %>
<% content_for :sidebar do %>
<%= render :partial => 'common/sidebar' %>
<%= render :partial => 'attributes' %>
<%= call_hook(:view_contacts_sidebar_after_attributes, :contact => @contact) %>
<%= render :partial => 'contacts_issues/issues', :locals => {:contact => @contact, :issues => @contact_issues} %>
<%= call_hook(:view_contacts_sidebar_after_tasks, :contact => @contact) %>
<%= render :partial => 'common/notes_attachments', :object => @contact.notes_attachments %>
<%= call_hook(:view_contacts_sidebar_after_notes_attachments, :contact => @contact) %>
<% if !@contact.background.blank? %>
<h3><%= l(:label_crm_background_info) %></h3>
<div class="wiki"><%= textilizable(@contact, :background) %></div>
<% end %>
<div id="contact_projects">
<%= render :partial => 'contacts_projects/related' %>
</div>
<%= render :partial => 'common/recently_viewed' %>
<% end %>
<% content_for :header_tags do %>
<%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %>
<%= stylesheet_link_tag :contacts_sidebar, :plugin => 'redmine_contacts' %>
<%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@contact.name} - ##{@contact.id}") %>
<% end %>
@@ -0,0 +1,23 @@
<div id="duplicates">
<% if @contact.duplicates.any? %>
<% if !@contact.new_record? %>
<div class="contextual">
<%= link_to_if_authorized l(:label_crm_merge_duplicate_plural), {:controller => 'contacts_duplicates', :action => 'index', :project_id => @project, :contact_id => @contact} %>
</div>
<% end %>
<h3><%= l(:label_crm_duplicate_plural) %></h3>
<ul class="box">
<% @contact.duplicates.each do |contact| %>
<li>
<%= avatar_to contact, :size => "16" %>
<%= link_to_source contact %>
<%= "(#{contact.job_title}) " unless contact.job_title.blank? %>
</li>
<% end %>
</ul>
<% end %>
</div>
@@ -0,0 +1,8 @@
<% @contacts.each do |contact| %>
<li>
<%= radio_button_tag "duplicate_id", contact.id %>
<%= avatar_to contact, :size => "16" %>
<%= link_to_source contact %>
<%= "(#{contact.job_title}) " unless contact.job_title.blank? %>
</li>
<% end %>
@@ -0,0 +1,54 @@
<%= breadcrumb link_to(@contact.name, note_source_url(@contact)) %>
<div class="contact_data_header">
<table class="note_data">
<tr>
<td class="avatar"><%= link_to avatar_to(@contact, :size => "32"), note_source_url(@contact), :id => "avatar" %> </td>
<td class="name">
<h2 class="note_title">
<%= l(:label_crm_duplicate_for_plural) %>: <%= @contact.name %>
</h2>
<p>
<%= h @contact.job_title %>
<%= " #{l(:label_crm_at_company)} " unless (@contact.job_title.blank? or @contact.company.blank?) %>
<% if @contact.is_company && @contact.contact_company %>
<%= link_to @contact.contact_company.name, note_source_url(@contact.contact_company) %>
<% else %>
<%= h @contact.company %>
<% end %>
</p>
</td>
</tr>
</table>
</div>
<%= form_tag({:controller => 'contacts_duplicates', :action => 'merge', :project_id => @project, :contact_id => @contact}) do %>
<div class="box" id="duplicates">
<%= text_field_tag(:principal_search, params[:topic_search] , :autocomplete => "off", :placeholder => l(:label_crm_contact_search) ) %>
<%= javascript_tag "observeSearchfield('principal_search', 'contact_duplicates', '#{escape_javascript contacts_duplicates_search_path(:contact_id => @contact, :by_email => true)}')" %>
<%= content_tag('div', l(:notice_merged_warning), :class => "flash warning") %>
<ul id="contact_duplicates">
<%= render :partial => 'list' %>
</ul>
</div>
<%= submit_tag l(:label_crm_merge_duplicate_plural) %>
<% end %>
<% html_title "#{l(:label_crm_duplicate_plural)} #{@contact.name}" %>
<% content_for :sidebar do %>
<%= render :partial => 'common/sidebar' %>
<%= render :partial => 'common/recently_viewed' %>
<% end %>
<% 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 %>
@@ -0,0 +1,6 @@
<% content_for :header_tags do %>
<%= select2_assets %>
<%= stylesheet_link_tag(:contacts, :plugin => 'redmine_contacts') %>
<%= javascript_include_tag(:contacts_select2, :plugin => 'redmine_contacts') %>
<%= javascript_include_tag(:contacts, :plugin => 'redmine_contacts') %>
<% end %>
@@ -0,0 +1,35 @@
<%= fields_for "issue" do |ff| %>
<%= label_tag 'task_subject', l(:field_subject)%> <br>
<%= ff.text_field :subject %>
<p>
<%= label_tag :assigned_to_id, l(:field_assigned_to)%> <br>
<%= ff.select :assigned_to_id, @project.assignable_users.collect {|m| [m.name, m.id]}, :selected => User.current.id, :include_blank => true %>
</p>
<%= label_tag 'due_date', l(:field_due_date)%> <br>
<%= ff.text_field :due_date, :value => Date.today, :size => 12 %><%= calendar_for('issue_due_date') %><br>
<p>
<%= label_tag :description, l(:field_description)%> <br>
<%= ff.text_area :description, :value => "", :rows => 6, :class => 'wiki-edit' , :style => "width: 98%;" %><br>
</p>
<% if @project.issue_categories.any? %>
<p>
<%= label_tag :category_id, l(:field_category)%> <br>
<%= ff.select :category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true %>
</p>
<% end %>
<p>
<%= label_tag :tracker_id, l(:field_tracker)%> <br>
<%= ff.select :tracker_id, @project.trackers.collect {|t| [t.name, t.id]} %>
</p>
<% end %>
<br>
<hr>
<br>
<%= submit_tag l(:button_add), :class => "button-small" %>
@@ -0,0 +1,45 @@
<% if !@issue.blank? && User.current.allowed_to?(:view_contacts, @project) %>
<div id="issue_contacts">
<% if User.current.allowed_to?(:manage_contact_issue_relations, @project) %>
<div class="contextual">
<%= link_to l(:button_add),
{:controller => 'contacts_issues', :action => 'new', :issue_id => @issue},
:remote => true,
:method => 'get' %>
</div>
<% end %>
<h3><%= l(:label_contact_plural) %> </h3>
<ul>
<% @issue.contacts.order_by_name.visible.each do |contact| %>
<li id="contact_<%= contact.id%>">
<%= contact_tag(contact) %>
<%= "(#{contact.job_title}) " unless contact.job_title.blank? %>
<% if User.current.allowed_to?(:delete_contacts, @project) %>
<%= link_to(image_tag('delete.png'),
{ :controller => 'contacts_issues',
:action => 'delete',
:issue_id => @issue,
:project_id => @project,
:id => contact.id},
:remote => true,
:method => :delete,
:data => {:confirm => l(:text_are_you_sure)},
:class => "delete",
:title => l(:button_delete) ) %>
<% end %>
</li>
<% end %>
</ul>
</div>
<% end %>
@@ -0,0 +1,11 @@
<tr id=<%="contact_issue_#{issue_item.id}"%>>
<td class="done_checkbox">
<%= check_box_tag :close, '', issue_item.closed?, :disabled => (issue_item.assigned_to != User.current) || issue_item.closed?, :onclick => "$(this).attr('disabled', 'disabled'); $('#contact_issue_#{issue_item.id}').css('text-decoration', 'line-through');$.post('#{url_for({:controller => "contacts_issues", :action => "close", :issue_id => issue_item.id})}');".html_safe unless Setting.plugin_redmine_contacts[:one_click_close] %>
</td>
<td class="issue_item_subject">
<%= link_to(issue_item.subject, {:controller => :issues, :action => :show, :id => issue_item}, :class => "issue status-#{issue_item.status_id} priority-#{issue_item.priority_id} #{'closed' if issue_item.closed?}") %>
<%= avatar(issue_item.assigned_to, :size => "14", :title => issue_item.assigned_to.name).to_s.html_safe if issue_item.assigned_to %>
</td>
<td style="vertical-align: top; text-align: right;"><%= format_date(issue_item.due_date) %></td>
</tr>
@@ -0,0 +1,35 @@
<div id="contact_issues" class="contact-issues">
<div class="contextual">
<%= link_to l(:label_issue_new), {}, :onclick => "$('#add_issue').show(); $('#add_issue_link').hide(); return false;", :id => 'add_issue_link' if User.current.allowed_to?(:add_issues, @project) && User.current.allowed_to?(:manage_contact_issue_relations, @project) %>
</div>
<h3><%= @contact_issues_count > 0 ? link_to("#{l(:label_issue_plural)} (#{@contact_issues_count})", {:controller => 'issues',
:action => 'index',
:set_filter => 1,
:f => [:contacts, :status_id],
:v => {:contacts => [@contact.id]},
:op => {:contacts => '=', :status_id => '*'}}) : "#{l(:label_issue_plural)} (#{@contact_issues_count})" %> </h3>
<%= error_messages_for 'issue' %>
<% if User.current.allowed_to?(:add_issues, @project) %>
<div id="add_issue" style="display:none;">
<%= form_tag({ :controller => "contacts_issues", :action => "create_issue", :project_id => @project, :id => contact}, :multipart => true, :id => "add_issue_form") do %>
<%= render :partial => 'contacts_issues/attributes' %>
<%= link_to l(:button_cancel), {}, :onclick => "$('#add_issue').hide(); $('#add_issue_link').show(); return false;" %>
<% end %>
</div>
<% end %>
<% if issues.any? %>
<table style="width:100%">
<%= render :partial => 'contacts_issues/issue_item', :collection => issues %>
</table>
<% end %>
</div>
@@ -0,0 +1,27 @@
<h3 class="title"><%= l(:label_crm_add_contact_plural) %></h3>
<%= form_tag({:controller => 'contacts_issues',
:action => 'create',
:issue_id => @issue,
:project_id => @project},
:remote => true,
:method => :post,
:id => 'add-contact-form') do %>
<p><%= label_tag 'contact_search', l(:label_crm_search_for_contact) %>:<%= text_field_tag 'contact_search', nil, :placeholder => l(:label_crm_contact_search) %></p>
<%= javascript_tag "observeSearchfield('contact_search', 'contacts_for_issue', '#{escape_javascript url_for(:controller => 'contacts_issues',
:action => 'autocomplete_for_contact', :project_id => @project, :issue_id => @issue, :cross_project_contacts => ContactsSetting.cross_project_contacts? ? '1' : '0')}')" %>
<div id="contacts_for_issue">
<%= contacts_check_box_tags 'contacts_issue[contact_ids][]', Contact.includes(:avatar).by_project(ContactsSetting.cross_project_contacts? ? nil : @project).visible.first(100) - @issue.contacts %>
</div>
<p class="buttons">
<%= submit_tag l(:button_add), :name => nil, :onclick => "hideModal(this);" %>
<%= submit_tag l(:button_cancel), :name => nil, :onclick => "hideModal(this);", :type => 'button' %>
</p>
<% end %>
<% content_for :header_tags do %>
<%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %>
<% end %>
@@ -0,0 +1 @@
<%= contacts_check_box_tags 'contacts_issue[contact_ids][]', @contacts %>
@@ -0,0 +1,5 @@
<% if RedmineContacts.settings[:show_closed_issues] %>
$('#contact_issue_<%= params[:issue_id] %> td.task_item_subject a').toggleClass('closed');
<% else %>
$('#contact_issue_<%= params[:issue_id] %>').effect('fade', {}, 1000);
<% end %>
@@ -0,0 +1,2 @@
$('#ajax-modal').html('<%= escape_javascript(render :partial => 'contacts_issues/new_modal') %>');
$('#issue_contacts').html('<%= escape_javascript(render :partial => 'contacts_issues/contacts') %>');
@@ -0,0 +1 @@
$('#issue_contacts #contact_<%= @contact.id %>').effect('fade');
@@ -0,0 +1,3 @@
$('#ajax-modal').html('<%= escape_javascript(render :partial => 'contacts_issues/new_modal') %>');
showModal('ajax-modal', '400px');
$('#ajax-modal').addClass('new-contacts-issue');
@@ -0,0 +1 @@
<%= textilizable(@params[:message], :only_path => false).gsub(/&para;/, '').html_safe %>
@@ -0,0 +1 @@
<%= @params[:message] %>
@@ -0,0 +1,22 @@
<div class="contextual">
<%= link_to l(:button_add), new_contact_contacts_project_path(@contact, :project_id => @project),
:remote => true if User.current.allowed_to?(:edit_contacts, @project)%>
</div>
<h3><%= l(:label_project_plural) %> </h3>
<% unless !(@show_form == "true") %>
<%= form_tag(contact_contacts_projects_path(@contact, :project_id => @project),
:remote => true,
:method => :post,
:id => 'add-project-form') do %>
<p><%= select_tag :id, project_tree_options_for_select(Project.allowed_to(:edit_contacts).order(:lft).all), :prompt => "--- #{l(:actionview_instancetag_blank_option)} ---" %>
<%= submit_tag l(:button_add), :class => "button-small" %>
<%= link_to l(:button_cancel), {}, :onclick => "$('#add-project-form').hide(); return false;" %>
</p>
<% end %>
<% end %>
<%= render_contact_projects_hierarchy @contact.projects %>
@@ -0,0 +1 @@
$('#contact_projects').html('<%= escape_javascript(render :partial => "contacts_projects/related") %>')
@@ -0,0 +1,3 @@
<span class="contacts-tags-edit">
<%= text_field_tag 'contact[tag_list]', "#{@contact.tags.map(&:name).join(',').html_safe}", :size => 10, :class => 'hidden', :id => "allowSpacesTags" %><%= tagsedit_with_source_for('#allowSpacesTags', auto_complete_contact_tags_path(:project_id => @project)) %>
</span>
@@ -0,0 +1,12 @@
<ul>
<% if @tag -%>
<li><%= link_to l(:button_edit), edit_contacts_tag_path(@tag),
:class => 'icon-edit' %></li>
<% else %>
<li><%= link_to l(:label_crm_megre_tags), merge_contacts_tags_path(:ids => @tags.collect(&:id)),
:class => 'icon-merge' %></li>
<% end %>
<li><%= link_to l(:button_delete), contacts_tags_path(:ids => @tags.collect(&:id), :back_url => @back),
:method => :delete, :data => {:confirm => l(:text_are_you_sure)}, :class => 'icon-del' %></li>
</ul>
@@ -0,0 +1,12 @@
<h2><%= link_to l(:contacts_title), {:controller => 'settings', :action => 'plugin', :id => 'redmine_contacts', :tab => "tags"} %> &#187; <%=h (l(:label_tag) + ": " + @tag.name) %></h2>
<%= form_tag(contacts_tag_path(@tag), :class => "tabular", :method => :put) do %>
<%= error_messages_for 'tag' %>
<div class="box">
<p>
<%= label_tag("tag_name", l(:field_name)) %>
<%= text_field 'tag', 'name' %>
</p>
</div>
<%= submit_tag l(:button_save) %>
<% end %>
@@ -0,0 +1,9 @@
api.array :tags, api_meta(:total_count => @tags.count) do
@tags.each do |tag|
api.tag do
api.id tag.id
api.name tag.name
api.color tag_color(tag.name)
end
end
end
@@ -0,0 +1,14 @@
<h2><%= link_to l(:label_crm_tags_plural), {:controller => 'settings', :action => 'plugin', :id => 'redmine_contacts', :tab => "tags"} %> &#187; <%= l(:label_crm_megre_tags) %></h2>
<%= form_tag(merge_contacts_tags_path(:ids => @tags.map(&:id)), :class => "tabular") do %>
<%= error_messages_for 'tag' %>
<div class="box">
<p>
<label for="tag_name"><%=l(:label_crm_tags_plural)%></label>
<%= tag_links(@tags.map(&:name)) %>
</p>
<p><label for="tag_name"><%=l(:field_name)%></label>
<%= text_field 'tag', 'name', :value => @tags.first.name %></p>
</div>
<%= submit_tag l(:button_save) %>
<% end %>
@@ -0,0 +1,16 @@
<%- if ContactsSetting.vcard? -%>
<h3><%= l(:label_crm_import) %></h3>
<span id='import_link'>
<%= link_to l(:label_crm_vcf_import), {}, :onclick => "$('#import_link').toggle(); $('#import_file').toggle(); return false;" %>
</span>
<%= form_tag({:controller => :contacts_vcf, :action => :load, :project_id => @project}, :multipart => true ) do %>
<span id='import_file' style="display:none;">
<%= file_field_tag 'contact_vcf', :size => 30, :id => nil, :onchange => "this.form.submit()" -%>
<small>
<%= link_to l(:button_cancel), {}, :onclick => "$('#import_link').toggle(); $('#import_file').toggle(); return false;" %>
</small>
</span>
<% end %>
<%- end -%>
@@ -0,0 +1,10 @@
<p style="float:right;">
<%= link_to_previous_month(@year, @month) %> | <%= link_to_next_month(@year, @month) %>
</p>
<p class="buttons">
<%= label_tag('month', l(:label_month)) %>
<%= select_month(@month, :prefix => "month", :discard_type => true) %>
<%= label_tag('year', l(:label_year)) %>
<%= select_year(@year, :prefix => "year", :discard_type => true) %>
</p>
@@ -0,0 +1,21 @@
<table class="cal">
<thead>
<tr><th scope="col" title="<%= l(:label_week) %>" class="week-number"></th><% 7.times do |i| %><th scope="col"><%= day_name( (@calendar.first_wday+i)%7 ) %></th><% end %></tr>
</thead>
<tbody>
<tr>
<% day = @calendar.startdt
while day <= @calendar.enddt %>
<%= ("<td class='week-number' title='#{ l(:label_week) }'>#{(day+(11-day.cwday)%7).cweek}</td>".html_safe) if day.cwday == @calendar.first_wday %>
<td class="<%= day.month==@calendar.month ? 'even' : 'odd' %><%= ' today' if Date.today == day %>" data-date="<%= day.to_date.to_s %>">
<p class="day-num"><%= day.day %></p>
<% @calendar.events_on(day).each do |i| %>
<%= render :partial => "crm_calendars/#{i.class.name.downcase}_calendar_event", :locals => {:event => i, :day => day} %>
<% end %>
</td>
<%= '</tr><tr>'.html_safe if day.cwday==@calendar.last_wday and day!=@calendar.enddt %>
<% day = day + 1
end %>
</tr>
</tbody>
</table>
@@ -0,0 +1,5 @@
<div class="issue deal" data-id="<%= event.id %>">
<%= h("#{event.project} -") unless @project && @project == event.project %>
<%= link_to "#{event.price_to_s} #{event.name}", deal_path(event), :class => "icon icon-add-deal" %>
<span class="contact"><%= event.contact.name if event.contact %></span>
</div>
@@ -0,0 +1,6 @@
<h2><%= l(:label_query) %></h2>
<%= form_tag(crm_query_path(@query, :object_type => @object_type), :onsubmit => 'selectAllOptions("selected_columns");', :method => :put) do %>
<%= render :partial => 'queries/form', :locals => {:query => @query} %>
<%= submit_tag l(:button_save) %>
<% end %>
@@ -0,0 +1,10 @@
api.array :queries, api_meta(:total_count => @query_count, :offset => @offset, :limit => @limit) do
@queries.each do |query|
api.query do
api.id query.id
api.name query.name
api.is_public query.is_public?
api.project_id query.project_id
end
end
end
@@ -0,0 +1,25 @@
<div class="contextual">
<%= link_to_if_authorized l(:label_query_new), new_project_crm_query_path(:project_id => @project, :object_type => @object_type), :class => 'icon icon-add' %>
</div>
<h2><%= l(:label_query_plural) %></h2>
<% if @queries.empty? %>
<p><i><%=l(:label_no_data)%></i></p>
<% else %>
<table class="list">
<% @queries.each do |query| %>
<tr class="<%= cycle('odd', 'even') %>">
<td class="name">
<%= link_to h(query.name), :controller => "#{@object_type}s", :action => 'index', :project_id => @project, :query_id => query %>
</td>
<td class="buttons">
<% if query.editable_by?(User.current) %>
<%= link_to l(:button_edit), edit_crm_query_path(query), :class => 'icon icon-edit' %>
<%= delete_link crm_query_path(query) %>
<% end %>
</td>
</tr>
<% end %>
</table>
<% end %>
@@ -0,0 +1,6 @@
<h2><%= l(:label_query_new) %></h2>
<%= form_tag(@project ? project_crm_queries_path(@project, :object_type => @object_type) : crm_queries_path(:object_type => @object_type), :onsubmit => 'selectAllOptions("selected_columns");') do %>
<%= render :partial => 'queries/form', :locals => {:query => @query} %>
<%= submit_tag l(:button_save) %>
<% end %>
@@ -0,0 +1,5 @@
<%= error_messages_for 'category' %>
<div class="box tabular">
<p><%= f.text_field :name, :size => 30, :required => true %></p>
</div>
@@ -0,0 +1,15 @@
<h2><%=l(:label_crm_deal_category)%>: <%=h @category.name %></h2>
<%= form_tag(deal_category_path(@category), :method => :delete) do %>
<div class="box">
<p><strong><%= l(:text_deal_category_destroy_question, @deal_count) %></strong></p>
<p><label><%= radio_button_tag 'todo', 'nullify', true %> <%= l(:text_deal_category_destroy_assignments) %></label><br />
<% if @categories.size > 0 %>
<label><%= radio_button_tag 'todo', 'reassign', false %> <%= l(:text_deal_category_reassign_to) %></label>:
<%= select_tag 'reassign_to_id', options_from_collection_for_select(@categories, 'id', 'name') %></p>
<% end %>
</div>
<%= submit_tag l(:button_apply) %>
<%= link_to l(:button_cancel), :controller => 'projects', :action => 'settings', :id => @project, :tab => 'contacts' %>
<% end %>
@@ -0,0 +1,6 @@
<h2><%=l(:label_crm_deal_category)%></h2>
<%= labelled_form_for @category, :as => :category, :url => deal_category_url(@category), :html => {:method => :put} do |f| %>
<%= render :partial => 'deal_categories/form', :locals => { :f => f } %>
<%= submit_tag l(:button_save) %>
<% end %>
@@ -0,0 +1,8 @@
api.array :deal_categories, api_meta(:total_count => @categories.count) do
@categories.each do |category|
api.category do
api.id category.id
api.name category.name
end
end
end
@@ -0,0 +1,6 @@
<h2><%=l(:label_issue_category_new)%></h2>
<%= labelled_form_for @category, :as => :category, :url => project_deal_categories_path(@project) do |f| %>
<%= render :partial => 'deal_categories/form', :locals => { :f => f } %>
<%= submit_tag l(:button_create) %>
<% end %>
@@ -0,0 +1,19 @@
<% if @deal.all_contacts.any? %>
<div id="deal_contacts">
<div class="contextual">
<%= link_to l(:button_add),
{:controller => 'deal_contacts',
:action => 'search',
:project_id => @project,
:deal_id => @deal},
:remote => true if User.current.allowed_to?({:controller => 'deal_contacts', :action => 'add'}, @project) %>
</div>
<h3><%= l(:label_crm_contractor_plural) %></h3>
<%= render :partial => 'common/contact_data', :object => @deal.contact if @deal.contact %>
<% @deal.related_contacts.each do |contact| %>
<%= render :partial => 'common/contact_data', :object => contact, :locals => {:actions => remove_contractor_link(contact)} %>
<% end %>
</div>
<% end %>
@@ -0,0 +1,23 @@
<h3 class="title"><%= l(:label_crm_add_contact_plural) %></h3>
<%= form_tag({:controller => 'deal_contacts',
:action => 'add',
:deal_id => @deal,
:project_id => @project},
:remote => true,
:method => :post,
:id => 'add-contact-form',
:class => 'select-users') do |f| %>
<p><%= label_tag 'contact_search', l(:label_crm_search_for_contact) %>:<%= text_field_tag 'contact_search', nil, :placeholder => l(:label_crm_contact_search) %></p>
<%= javascript_tag "observeSearchfield('contact_search', 'contacts_for_issue', '#{ escape_javascript url_for(:controller => :deal_contacts, :action => :autocomplete, :deal_id => @deal, :project_id => @project) }')" %>
<div id="contacts_for_issue" >
<%= contacts_check_box_tags('contact_id[]', @contacts) %>
</div>
<p class="buttons">
<%= submit_tag l(:button_add), :name => nil, :onclick => "hideModal(this);" %>
<%= submit_tag l(:button_cancel), :name => nil, :onclick => "hideModal(this);", :type => 'button' %>
</p>
<% end %>
@@ -0,0 +1 @@
$('#deal_contacts').html('<%= escape_javascript(render :partial => "deal_contacts/contacts") %>');
@@ -0,0 +1 @@
<%= contacts_check_box_tags 'contact_id[]', @contacts %>
@@ -0,0 +1 @@
$('#contact_data_<%= params[:contact_id] %>').effect('fade', {}, 1000);
@@ -0,0 +1,4 @@
var modal = $('#ajax-modal');
modal.html('<%= escape_javascript(render :partial => 'deal_contacts/new_modal') %>');
showModal('ajax-modal', '400px');
modal.addClass('new-contact');
@@ -0,0 +1,40 @@
<%= error_messages_for 'deal_status' %>
<div class="box tabular">
<!--[form:deal_status]-->
<p><label for="deal_status_name"><%=l(:field_name)%><span class="required"> *</span></label>
<%= text_field 'deal_status', 'name' %></p>
<p><label for="tag_color"><%=l(:field_color)%></label>
<%= text_field 'deal_status', 'color_name', :class => "colorpicker" %>
<!--[eoform:optvalue]-->
</p>
<script>
$(function() {
//use this method to add new colors to pallete
//$.fn.colorPicker.addColors(['000', '000', 'fff', 'fff']);
$('#deal_status_color_name').colorPicker();
});
</script>
<p><label for="deal_status_status_type"><%=l(:label_crm_deal_status_type)%></label>
<%= select_tag 'deal_status[status_type]', options_for_select([[l(:label_open_issues), DealStatus::OPEN_STATUS], [l(:label_crm_deal_status_won), DealStatus::WON_STATUS], [l(:label_crm_deal_status_lost), DealStatus::LOST_STATUS]], @deal_status.status_type) %>
<p><label for="deal_status_is_default"><%=l(:field_is_default)%></label>
<%= check_box 'deal_status', 'is_default' %></p>
<%= call_hook(:view_deal_statuses_form, :deal_status => @deal_status) %>
<!--[eoform:deal_status]-->
</div>
<% content_for :header_tags do %>
<%= javascript_include_tag :contacts, :plugin => 'redmine_contacts' %>
<%= javascript_include_tag :"jquery.colorPicker.min.js", :plugin => 'redmine_contacts' %>
<%= stylesheet_link_tag :"colorPicker.css", :plugin => 'redmine_contacts' %>
<% end %>
@@ -0,0 +1,6 @@
<h2><%= link_to l(:label_crm_deal_status_plural), :controller => 'deal_statuses', :action => 'index' %> &#187; <%=h @deal_status %></h2>
<%= form_tag({:action => 'update', :id => @deal_status}, :class => "tabular", :method => :put) do %>
<%= render :partial => 'form' %>
<%= submit_tag l(:button_save) %>
<% end %>
@@ -0,0 +1,12 @@
api.array :deal_statuses, api_meta(:total_count => @deal_statuses.count) do
@deal_statuses.each do |deal_status|
api.deal_status do
api.id deal_status.id
api.name deal_status.name
api.position deal_status.position
api.is_default deal_status.is_default
api.status_type deal_status.status_type
api.color deal_status.color
end
end
end
@@ -0,0 +1,30 @@
<div class="contextual">
<%= link_to l(:label_crm_deal_status_new), {:action => 'new'}, :class => 'icon icon-add' %>
</div>
<h2><%=l(:label_crm_deal_status_plural)%></h2>
<table class="list">
<thead><tr>
<th><%=l(:field_status)%></th>
<th><%=l(:field_is_default)%></th>
<th><%=l(:label_crm_deal_status_type)%></th>
<th><%=l(:button_sort)%></th>
<th></th>
</tr></thead>
<tbody>
<% for status in @deal_statuses %>
<tr class="<%= cycle("odd", "even") %>">
<td class="name"><%= link_to status.name, :action => 'edit', :id => status %></td>
<td align="center"><%= checked_image status.is_default? %></td>
<td align="center"><%= status.status_type_name %></td>
<td align="center" style="width:15%;"><%= reorder_links('deal_status', {:action => 'update', :id => status}, :put) %></td>
<td class="buttons">
<%= delete_link deal_status_path(status) %>
</td>
</tr>
<% end unless @deal_statuses.blank? %>
</tbody>
</table>
<% html_title(l(:label_crm_deal_status_plural)) -%>
@@ -0,0 +1,6 @@
<h2><%= link_to l(:label_crm_deal_status_plural), :controller => 'deal_statuses', :action => 'index' %> &#187; <%=l(:label_crm_deal_status_new)%></h2>
<%= form_tag({:action => 'create'}, :class => "tabular") do %>
<%= render :partial => 'form' %>
<%= submit_tag l(:button_create) %>
<% end %>
@@ -0,0 +1,14 @@
<% if @deal.custom_field_values.any? %>
<div id="attributes">
<h3><%= l(:label_deal) %></h3>
<table class="attributes">
<% @deal.custom_field_values.each do |custom_value| %>
<% if !custom_value.value.blank? %>
<tr> <th class = "custom_field"><%= custom_value.custom_field.name %>:</th><td> <%=h show_value(custom_value) %></td> </tr>
<% end %>
<% end %>
</table>
</div>
<% end %>
@@ -0,0 +1,7 @@
<tr>
<% deal_statuses.each do |deal_status| %>
<th style="width: <%= 100/deal_statuses.size %>%;">
<%= "#{deal_status.name} (#{@deals_scope.where(:status_id => deal_status.id).count})"%>
</th>
<% end %>
</tr>
@@ -0,0 +1,7 @@
<tr>
<% deal_statuses.each do |deal_status| %>
<th style="width: <%= 100/deal_statuses.size %>%;" data-id="<%= deal_status.id %>">
<%= prices_collection_by_currency(@deals_scope.group(:currency).where(:status_id => deal_status.id).sum(:price), :hide_zeros => true).join('<br/>').html_safe %>
</th>
<% end %>
</tr>
@@ -0,0 +1,5 @@
<p><%= form.check_box :is_filter %></p>
<p><%= form.check_box :visible, :label => l(:label_crm_contacts_show_in_list) %></p>
<% if (@custom_field.respond_to?(:format) && @custom_field.format.searchable_supported) || !@custom_field.respond_to?(:format) %>
<p><%= form.check_box :searchable %></p>
<% end %>
@@ -0,0 +1,24 @@
<% if deal_statuses.any? %>
<div id="deals_statistics">
<div class="contextual">
<%= link_to l(:label_crm_sales_funnel), {:controller => 'deals', :action => 'index', :project_id => @project, :deals_list_style => 'list_pipeline'} %>
</div>
<h3><%= l(:label_crm_statistics) %></h3>
<table class="deals_statistics">
<% deal_statuses.each do |deal_status| %>
<tr>
<td>
<span class="tag-label-color" style=<%= "background-color:#{deal_status.color_name};color:white;" %> >
<%= link_to "#{deal_status.name}(#{@project ? @project.deals.visible.with_status(deal_status.id).count : Deal.visible.with_status(deal_status.id).count})".html_safe, deal_status_url(deal_status.id, :project_id => @project) %>
</span>
</td>
<td>
<strong>
<%= prices_collection_by_currency(Deal.by_project(@project).visible.where(:status_id => deal_status.id).group(:currency).sum(:price), :hide_zeros => true).join(' / ').html_safe %>
</strong>
</td>
</tr>
<% end %>
</table>
</div>
<% end %>
@@ -0,0 +1,68 @@
<%= labelled_fields_for :deal, @deal do |f| %>
<%= call_hook(:view_deals_form_details_top, {:deal => @deal, :form => f }) %>
<p><%= f.text_field :name, :label=>l(:field_deal_name), :size => 80, :required => true %></p>
<p><%= f.select :project_id, project_tree_options_for_select(Deal.allowed_target_projects, :selected => @deal.project), {:required => true}, :onchange => "updateCustomForm('#{escape_javascript update_form_deals_path(:id => @deal, :format => 'js')}', '#deal_form')" %></p>
<p class = "notes"><%= f.text_area :background , :cols => 80, :rows => 8, :class => 'wiki-edit', :label=>l(:field_deal_background) %></p> <%= wikitoolbar_for 'deal_background' %>
<div id="attributes" class="attributes">
<div class="splitcontentleft">
<% if @project.deal_statuses.any? %>
<p><%= f.select :status_id, collection_for_status_select, :include_blank => false, :label=>l(:field_contact_status) %></p>
<% end %>
<p>
<%= label_tag :deal_contact_id, RedmineContacts.companies_select ? l(:label_crm_company) : l(:label_contact)%>
<%= select_contact_tag('deal[contact_id]',
@deal.contact,
:include_blank => true,
:add_contact => true,
:is_company => RedmineContacts.companies_select) %>
</p>
<p>
<% if RedmineContacts.products_plugin_installed? %>
<%= f.text_field :price, :label => l(:field_deal_price), :size => 10, :disabled => @deal.lines.present? %>
<% else %>
<%= f.text_field :price, :label => l(:field_deal_price), :size => 10 %>
<% end %>
<%= select_tag "deal[currency]", options_for_select(collection_for_currencies_select(ContactsSetting.default_currency, ContactsSetting.major_currencies), @deal.currency), :include_blank => true, :style => "width: initial;"
%>
</p>
<p><%= f.select :assigned_to_id, (@project.assignable_users.collect {|m| [m.name, m.id]}), :include_blank => true, :label => l(:label_crm_assigned_to) %></p>
</div>
<div class="splitcontentright">
<% unless @project.deal_categories.empty? %>
<p><%= f.select :category_id, (@project.deal_categories.collect {|c| [c.name, c.id]}), :include_blank => true %></p>
<% end %>
<p><%= f.select :probability, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }), :label => l(:label_crm_probability), :include_blank => true %></p>
<p><%= f.text_field :due_date, :label => l(:field_due_date), :size => 12 %><%= calendar_for('deal_due_date') %></p>
</div>
</div>
<div style="clear:both;"> </div>
<% custom_field_values = @deal.custom_field_values %>
<div class="splitcontent">
<div class="splitcontentleft">
<% i = 0 %>
<% split_on = (custom_field_values.size / 2.0).ceil - 1 %>
<% custom_field_values.each do |value| %>
<p><%= custom_field_tag_with_label :deal, value, :required => value.custom_field.is_required? %></p>
<% if i == split_on -%>
</div><div class="splitcontentright">
<% end -%>
<% i += 1 -%>
<% end -%>
</div>
</div>
<% if RedmineContacts.products_plugin_installed? %>
<p class="<%= 'hol' if @deal.lines.present? %>">
<%= label_tag l(:label_deal_items) %>
<span><%= link_to('Add new', 'javascript:void(0)', :onclick => 'toogleDealItems(this); return false;', :class => 'icon icon-add') %></span>
<p>
<%= field_set_tag(l(:label_deal_items), :class => "deal_items #{'hol' unless @deal.lines.present?}") do %>
<%= render :partial =>'shared/new_product_line', :locals => { :form => f, :parent_object => @deal} %>
<% end %>
<% end %>
<%= call_hook(:view_deals_form_details_bottom, {:deal => @deal, :form => f }) %>
<% end %>
@@ -0,0 +1,45 @@
<% product = f.object.product %>
<tr class="line fields sortable-line" id="line-<%= f.object.id %>" >
<% unless product.blank? %>
<td class="product-image"><%= product_tag(product, :size => 32, :type => 'image') %></td>
<% end %>
<td class="item" colspan="<%= product.blank? ? 2 : 1 %>">
<%= product_tag(product, :type => 'plain') unless product.blank? %>
<%= f.hidden_field :product_id %>
<% if !product.blank? && f.object.description.blank? %>
<br>
<em class="info"><%= link_to_function "(#{l(:label_products_add_description)})", "$(this).hide(); $(this).parent().next().show(); return false;" %></em>
<% end %>
<%= f.text_area :description, :no_label => true, :rows => f.object.description.blank? ? 2 : [f.object.description.lines.count, 2].max, :onkeyup => "activateTextAreaResize(this);", :style => "width:99%; #{(product.blank? || !f.object.description.blank?) ? "" : "display:none;"}" -%>
</td>
<% f.object.custom_field_values.each do |cf| %>
<td><%= custom_field_tag("order[lines_attributes][#{f.index}]", cf) %></td>
<% end %>
<td class="quantity"><%= f.text_field :quantity, :no_label => true, :size => 6, :onkeyup => 'updateTotal(this)' %></td>
<td class="price"><%= f.text_field :price, :no_label => true, :size => 8, :onkeyup => 'updateTotal(this)' %></td>
<% if !ContactsSetting.disable_taxes? || (f.object.container.respond_to?(:has_taxes?) && f.object.container.has_taxes?) %>
<td class="tax">
<% line_tax = (f.object.new_record? && f.object.tax.blank?) ? ContactsSetting.default_tax : f.object.tax %>
<%= check_box_tag :show_tax, "1", false, :onclick=>"$(this).hide(); $(this).parent().find('.tax-fields').show(); $(this).next().find('input').focus(); return false;" if line_tax.blank? || line_tax == 0 %>
<span class="tax-fields" style="white-space: nowrap; <%= line_tax.blank? || line_tax == 0 ? "display:none;" : "" %>"><%= f.text_field :tax, :no_label => true, :size => 5, :value => line_tax %>&nbsp;%
</span>
</td>
<% end %>
<td class="discount">
<%= check_box_tag :show_discount, "1", false, :onclick=>"$(this).hide(); $(this).parent().find('.discount-fields').show(); $(this).next().find('input').focus(); return false;" if f.object.discount.to_i == 0 %>
<span class="discount-fields" style="white-space: nowrap; <%= f.object.discount.to_i == 0 ? "display:none;" : "" %>">
<%= f.text_field :discount, :no_label => true, :size => 5, :style => f.object.discount.to_i == 0 ? "display:none;" : "", :onkeyup => 'updateTotal(this)', :class => "discount-fields" %>&nbsp;%
</span>
</td>
<td class="total"><%= format("%.2f\n", f.object.total) if f.object.price && f.object.quantity %></td>
<td>
<%= deals_link_to_remove_fields "", f, :class => "icon icon-del" %>
</td>
<%= f.hidden_field :position, :class => 'position' %>
</tr>
<script type="text/javascript">
tooglePriceField();
</script>
@@ -0,0 +1,71 @@
<%= form_tag({}, :data => {:cm_url => context_menu_deals_path}) do -%>
<%= hidden_field_tag 'back_url', url_for(params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params), :id => nil %>
<div class="autoscroll">
<table class="list deals issues contacts">
<thead>
<tr>
<th class="checkbox hide-when-print">
<%= link_to image_tag('toggle_check.png'), {},
:onclick => 'toggleCRMIssuesSelection(this); return false;',
:title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}" %>
</th>
<%= sort_header_tag('id', :caption => '#', :default_order => 'desc') %>
<% @query.inline_columns.each do |column| %>
<%= Redmine::VERSION.to_s >= '3.4' || RedmineContacts.unstable_branch? ? column_header(@query, column) : column_header(column) %>
<% end %>
</tr>
</thead>
<% previous_group = false %>
<tbody>
<% @deals.each do |deal| -%>
<% if @query.grouped? && (group = @query.group_by_column.value(deal)) != previous_group %>
<% reset_cycle %>
<tr class="group open">
<td colspan="<%= @query.inline_columns.size + 2 %>">
<span class="expander" onclick="toggleRowGroup(this);">&nbsp;</span>
<%= group.blank? ? l(:label_none) : column_content(@query.group_by_column, deal) %> <span class="count"><%= @deal_count_by_group[group] %></span>
<%= link_to_function("#{l(:button_collapse_all)}/#{l(:button_expand_all)}",
"toggleAllRowGroups(this)", :class => 'toggle-all') %>
</td>
</tr>
<% previous_group = group %>
<% end %>
<tr id="deal-<%= deal.id %>" class="hascontextmenu <%= cycle('odd', 'even') %>">
<td class="checkbox hide-when-print"><%= check_box_tag("ids[]", deal.id, false, :id => nil) %></td>
<td class="id"><%= link_to deal.id, deal_path(deal) %></td>
<%= raw @query.inline_columns.map {|column| "<td class=\"#{column.css_classes}\">#{column_content(column, deal)}</td>"}.join %>
</tr>
<% @query.block_columns.each do |column|
if (text = column_content(column, deal)) && text.present? -%>
<tr class="<%= current_cycle %>">
<td colspan="<%= @query.inline_columns.size + 1 %>" class="<%= column.css_classes %>"><%= text %></td>
</tr>
<% end -%>
<% end -%>
<% end -%>
<tr class="total">
<th colspan="<%= @query.inline_columns.size + 2 %>">
<table class="contacts deals index total">
<tbody>
<tr class="total">
<% if @deal_weighted_amount.map{|k, v| v.to_i > 0}.any? %>
<th class="title"><%= l(:label_crm_expected_revenue) %>:</th>
<th class="sum deals-sum">
<%= prices_collection_by_currency(@deal_weighted_amount, :hide_zeros => true).join('<br/>').html_safe %>
</th>
<% end %>
<th class="title"><%= "#{l(:label_total)} (#{@deals_count}):" %></th>
<th class="sum deals-sum">
<%= prices_collection_by_currency(@deal_amount, :hide_zeros => true).join('<br/>').html_safe %>
</th>
</tr>
</tbody>
</table>
</th>
</tr>
</tbody>
</table>
</div>
<% end -%>
@@ -0,0 +1,104 @@
<% if deal_statuses.any? %>
<% if User.current.allowed_to?(:edit_deals, @project) %>
<script>
$(function() {
$(".deal-status-col").droppable({
activeClass: 'droppable-active',
hoverClass: 'droppable-hover',
accept: '.deal-card',
tolerance: 'pointer',
drop: function (event, ui) {
ui.draggable.prependTo(this);
$.ajax({
url: '<%= escape_javascript deals_path %>/' + ui.draggable.data('id'),
type: 'PUT',
dataType : "script",
data: {
deal: {status_id: $(this).data("id")},
status_id: $("#operators_status_id").val()
},
success: function(data){
}
});
}
});
$(".deal-card").draggable({
containmentType: "parent",
helper: "clone",
start: function (event, ui) {
$(ui.helper).addClass("draggable-active")
}
});
// $(".deal-status-col" ).sortable({
// connectWith: ".deal-status-col",
// placeholder: "sortable-placeholder",
// receive: function (event, ui) {
// var deal_id = ui.item.data('id');
// var status_id = $(this).data("id");
// $.ajax({
// url: '<%= escape_javascript deals_path %>/' + deal_id + '.json',
// dataType : "json",
// type: 'PUT',
// data: {deal: {status_id: status_id}}
// });
// }
// }).disableSelection();
});
</script>
<% end %>
<%= form_tag({}, :data => {:cm_url => context_menu_deals_path}) do -%>
<%= hidden_field_tag 'back_url', url_for(params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params) %>
<%= hidden_field_tag 'project_id', @project.id if @project %>
<% board_statuses = params[:status_id] == 'o' ? deal_statuses.open : deal_statuses %>
<div class="autoscroll">
<table class="list deal-board ">
<thead class="deals_counts">
<%= render :partial => 'board_deals_counts' %>
</thead>
<tr style="text-align: center;white-space: nowrap;" class="deal <%= cycle('odd', 'even') %>">
<% board_statuses.each do |deal_status| %>
<td class="deal-status-col <%='open' if deal_status.is_open? %> <%='won' if deal_status.is_won? %> <%='lost' if deal_status.is_lost? %> <%='closed' if deal_status.is_closed? %>" data-id="<%= deal_status.id %>">
<% @deals.where(:status_id => deal_status.id).order("#{Deal.table_name}.updated_on DESC").each do |deal| %>
<div class="deal-card" data-id="<%= deal.id %>">
<p class="amount">
<strong><%= deal.price_to_s %></strong>
<%= content_tag(:span, " (#{deal.probability}%)" ) if deal.probability %>
</p>
<p class="name" ><%= link_to deal.name, deal_path(deal) %></p>
<% if deal.contact %>
<p class="info">
<span class="contact"><%= contact_tag(deal.contact) %></span>
</p>
<% end %>
</div>
<% end %>
</td>
<% end %>
</tr>
<thead class="total">
<%= render :partial => 'board_total' %>
<!-- <tr>
<% board_statuses.each do |deal_status| %>
<th style="width: <%= 100/board_statuses.size %>%;" data-id="<%= deal_status.id %>">
<%= prices_collection_by_currency(@deals_scope.group(:currency).where(:status_id => deal_status.id).sum(:price), :hide_zeros => true).join('<br/>').html_safe %>
</th>
<% end %>
</tr> -->
</thead>
</table>
</div>
<% end %>
<% else %>
<p class="nodata"><%= l(:text_crm_no_deal_statuses_in_project) %></p>
<% end %>
@@ -0,0 +1,71 @@
<%= form_tag({}, :data => {:cm_url => context_menu_deals_path}) do -%>
<%= hidden_field_tag 'back_url', url_for(params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params) %>
<%= hidden_field_tag 'project_id', @project.id if @project %>
<div class="autoscroll">
<table class="contacts deals index">
<tbody>
<% previous_group = false %>
<% @deals.each do |deal| %>
<% if @query.grouped? && (group = @query.group_by_column.value(deal)) != previous_group %>
<% reset_cycle %>
<tr class="group open">
<td colspan="<%= @query.columns.size + 2 %>">
<span class="expander" onclick="toggleRowGroup(this);">&nbsp;</span>
<%= group.blank? ? 'None' : column_content(@query.group_by_column, deal) %> <span class="count">(<%= @deal_count_by_group[group] %>)</span>
<%= link_to_function("#{l(:button_collapse_all)}/#{l(:button_expand_all)}", "toggleAllRowGroups(this)", :class => 'toggle-all') %>
</td>
</tr>
<% previous_group = group %>
<% end %>
<tr class="hascontextmenu <%= deal.status_id %> <%= cycle('odd', 'even') %> ">
<td class="checkbox">
<%= check_box_tag "ids[]", deal.id, false, :onclick => "toggleContact(event, this);" %>
</td>
<td class="avatar">
<%= link_to avatar_to(deal, :size => "32"), {:controller => 'deals', :action => 'show', :id => deal.id}, :id => "avatar" %>
</td>
<td class="name">
<h1 class="deal_name"><%= link_to deal.name, :controller => 'deals', :action => 'show', :id => deal.id %></h1>
<p>
<%= link_to_source(deal.contact) if deal.contact %>
</p>
</td>
<td class="info">
<div class="deal-sum"><strong><%= deal.price_to_s %></strong>
<%= content_tag(:span, " (#{deal.probability}%)" ) if deal.probability %>
<% if deal.status && deal.project.deal_statuses.any? %>
<%= deal_status_tag(deal.status) %>
<% end %>
</div>
<div class="description" >
<%= h deal.category %><%= " (#{format_date(deal.due_date)})" if deal.due_date %>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>
<table class="contacts deals index total">
<tbody>
<tr class="total">
<% if @deal_weighted_amount.map{|k, v| v.to_i > 0}.any? %>
<th class="title"><%= l(:label_crm_expected_revenue) %>:</th>
<th class="sum deals-sum">
<%= prices_collection_by_currency(@deal_weighted_amount, :hide_zeros => true).join('<br/>').html_safe %>
</th>
<% end %>
<th class="title"><%= "#{l(:label_total)} (#{@deals_count}):" %></th>
<th class="sum deals-sum">
<%= prices_collection_by_currency(@deal_amount, :hide_zeros => true).join('<br/>').html_safe %>
</th>
</tr>
</tbody>
</table>
</div>
<% end %>
@@ -0,0 +1,45 @@
<% if deal_statuses.any? %>
<% @deals = @query.results_scope(
:include => [{:contact => [:avatar, :projects, :address]}, :author]
)
@processor = DealsPipelineProcessor.new(@deals) %>
<div class="autoscroll">
<table class="list sales-funnel">
<thead>
<tr>
<th><%= h l(:label_crm_deal_status) %></th>
<th><%= h l(:label_crm_count) %></th>
<th><%= h l(:label_total) %></th>
</tr>
</thead>
<% deal_statuses.each_with_index do |deal_status, index| %>
<% status_scope = @processor.deals_for_status(deal_status) %>
<tr class="deal_status_type-<%= deal_status.status_type %>">
<td class="sales-funnel index_<%= deal_status.is_lost? ? 1 : index.to_s %>" >
<%= pipeline_status_tag(deal_status, status_scope.count, index) %>
</td>
<td class="count">
<strong>
<%= h status_scope.size %>
</strong>
</td>
<td class="total">
<strong>
<%= pipeline_prices(status_scope) %>
</strong>
</td>
</tr>
<% end %>
<tr class="total">
<th colspan="2" class="title" style="text-align: right;"> <%= "#{l(:label_total)} (#{@processor.count}):" %> </th>
<th class="sum" style="text-align: right;">
<%= pipeline_prices(@processor.scope) %>
</th>
</tr>
</table>
</div>
<% else %>
<p class="nodata"><%= l(:text_crm_no_deal_statuses_in_project) %></p>
<% end %>
@@ -0,0 +1,29 @@
<% show_info = true if show_info.nil? %>
<% show_author = true if !show_author.nil? %>
<div id=<%="note_#{process_item.id}"%>>
<table class="note_data">
<tr>
<% if show_info %>
<% if show_author %>
<td class="avatar"><%= link_to avatar(process_item.author, :size => "32"), note_source_url(process_item.deal), :id => "avatar" %></td>
<% else %>
<td class="avatar"><%= link_to avatar_to(process_item.deal, :size => "32"), note_source_url(process_item.deal), :id => "avatar" %></td>
<% end %>
<% end %>
<td class="name">
<h4>
<%# note_type_icon(process_item) %>
<%= link_to_source(process_item.deal) + "," if show_info %>
<%= authoring_note process_item.created_at, process_item.author %>
</h4>
<div class="wiki note">
<%= deal_status_tag(process_item.from) + " &rarr; ".html_safe if process_item.from %><%= deal_status_tag(process_item.to) if process_item.to %>
</div>
</td>
</tr>
</table>
</div>
@@ -0,0 +1,28 @@
<% @deals = @contact.all_visible_deals %>
<div id="deals">
<div class="contextual">
<%= link_to_if_authorized l(:label_crm_deal_new), {:controller => 'deals', :action => 'new', :project_id => @project, :contact_id => @contact} %>
</div>
<h3><%= "#{l(:label_deal_plural)}" %> <%= " - #{prices_collection_by_currency(@deals.select{|d| d.open? && !d.price.blank?}.group_by(&:currency).map{|k, v| [k, v.sum(&:price)]}).join(' / ')}".html_safe if @deals.detect{|d| d.open? && !d.price.blank?} %></h3>
<% if @deals.any? %>
<table class="related_deals">
<% @deals.each do |deal| %>
<tr class="deal">
<td class="name" style="vertical-align: top;">
<p>
<%= deal_status_tag(deal.status) if deal.status %>
<%= link_to "#{deal.name}", deal_path(deal) %> -
<%= deal.price_to_s %>
</p>
</td>
</tr>
<% end %>
</table>
<% end %>
</div>

Some files were not shown because too many files have changed in this diff Show More