Initial Redmine tooling and local plugin forks
This commit is contained in:
@@ -0,0 +1,269 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# This file is a part of Redmine CRM (redmine_contacts) plugin,
|
||||
# customer relationship management plugin for Redmine
|
||||
#
|
||||
# Copyright (C) 2010-2018 RedmineUP
|
||||
# http://www.redmineup.com/
|
||||
#
|
||||
# redmine_contacts is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# redmine_contacts is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
module ContactsHelper
|
||||
|
||||
def contact_tabs(contact)
|
||||
contact_tabs = []
|
||||
contact_tabs << {:name => 'notes', :partial => 'contacts/notes', :label => l(:label_crm_note_plural)} if contact.visible?
|
||||
contact_tabs << {:name => 'contacts', :partial => 'company_contacts', :label => l(:label_contact_plural) + (contact.company_contacts.visible.count > 0 ? " (#{contact.company_contacts.count})" : "")} if contact.is_company?
|
||||
contact_tabs << {:name => 'deals', :partial => 'deals/related_deals', :label => l(:label_deal_plural) + (contact.all_visible_deals.size > 0 ? " (#{contact.all_visible_deals.size})" : "") } if User.current.allowed_to?(:add_deals, @project)
|
||||
contact_tabs
|
||||
end
|
||||
|
||||
def settings_contacts_tabs
|
||||
ret = [
|
||||
{:name => 'general', :partial => 'settings/contacts/contacts_general', :label => :label_general},
|
||||
{:name => 'money', :partial => 'settings/contacts/money', :label => :label_crm_money_settings},
|
||||
{:name => 'tags', :partial => 'settings/contacts/contacts_tags', :label => :label_crm_tags_plural},
|
||||
{:name => 'deal_statuses', :partial => 'settings/contacts/contacts_deal_statuses', :label => :label_crm_deal_status_plural},
|
||||
]
|
||||
ret.push({:name => 'hidden', :partial => 'settings/contacts/contacts_hidden', :label => :label_crm_contacts_hidden}) if params[:hidden]
|
||||
ret
|
||||
end
|
||||
|
||||
def collection_for_visibility_select
|
||||
[[l(:label_crm_contacts_visibility_project), Contact::VISIBILITY_PROJECT],
|
||||
[l(:label_crm_contacts_visibility_public), Contact::VISIBILITY_PUBLIC],
|
||||
[l(:label_crm_contacts_visibility_private), Contact::VISIBILITY_PRIVATE]]
|
||||
end
|
||||
|
||||
def contact_list_styles_for_select
|
||||
list_styles = [[l(:label_crm_list_excerpt), "list_excerpt"]]
|
||||
list_styles += [[l(:label_crm_list_list), "list"],
|
||||
[l(:label_crm_list_cards), "list_cards"]]
|
||||
end
|
||||
|
||||
def contacts_list_style
|
||||
list_styles = contact_list_styles_for_select.map(&:last)
|
||||
if params[:contacts_list_style].blank?
|
||||
list_style = list_styles.include?(session[:contacts_list_style]) ? session[:contacts_list_style] : RedmineContacts.default_list_style
|
||||
else
|
||||
list_style = list_styles.include?(params[:contacts_list_style]) ? params[:contacts_list_style] : RedmineContacts.default_list_style
|
||||
end
|
||||
session[:contacts_list_style] = list_style
|
||||
end
|
||||
|
||||
def authorized_for_permission?(permission, project, global = false)
|
||||
User.current.allowed_to?(permission, project, :global => global)
|
||||
end
|
||||
|
||||
def render_contact_projects_hierarchy(projects)
|
||||
s = ''
|
||||
project_tree(projects) do |project, level|
|
||||
s << "<ul>"
|
||||
name_prefix = (level > 0 ? (' ' * 2 * level + '» ') : '')
|
||||
s << "<li id='project_#{project.id}'>" + name_prefix + link_to_project(project)
|
||||
|
||||
s += ' ' + link_to(image_tag('delete.png'),
|
||||
contact_contacts_project_path(@contact, :id => project.id, :project_id => @project.id),
|
||||
:remote => true,
|
||||
:method => :delete,
|
||||
:style => "vertical-align: middle",
|
||||
:class => "delete",
|
||||
:title => l(:button_delete)) if (projects.size > 1 && User.current.allowed_to?(:edit_contacts, project))
|
||||
s << "</li>"
|
||||
|
||||
s << "</ul>"
|
||||
end
|
||||
s.html_safe
|
||||
end
|
||||
|
||||
def contact_to_vcard(contact)
|
||||
return false unless ContactsSetting.vcard?
|
||||
|
||||
card = Vcard::Vcard::Maker.make2 do |maker|
|
||||
|
||||
maker.add_name do |name|
|
||||
name.prefix = ''
|
||||
name.given = contact.first_name.to_s
|
||||
name.family = contact.last_name.to_s
|
||||
name.additional = contact.middle_name.to_s
|
||||
end
|
||||
|
||||
maker.add_addr do |addr|
|
||||
addr.preferred = true
|
||||
addr.street = contact.street1.to_s.gsub("\r\n"," ").gsub("\n"," ")
|
||||
addr.locality = contact.city.to_s
|
||||
addr.region = contact.region.to_s
|
||||
addr.postalcode = contact.postcode.to_s
|
||||
addr.country = contact.country.to_s
|
||||
addr.location = 'business'
|
||||
end
|
||||
|
||||
maker.title = contact.job_title.to_s
|
||||
maker.org = contact.company.to_s
|
||||
maker.birthday = contact.birthday.to_date unless contact.birthday.blank?
|
||||
maker.add_note(contact.background.to_s.gsub("\r\n"," ").gsub("\n", ' '))
|
||||
|
||||
maker.add_url(contact.website.to_s)
|
||||
|
||||
contact.phones.each { |phone| maker.add_tel(phone) }
|
||||
contact.emails.each { |email| maker.add_email(email) }
|
||||
end
|
||||
avatar = contact.attachments.find_by_description('avatar')
|
||||
card = card.encode.sub("END:VCARD", "PHOTO;BASE64:" + "\n " + [File.open(avatar.diskfile).read].pack('m').to_s.gsub(/[ \n]/, '').scan(/.{1,76}/).join("\n ") + "\nEND:VCARD") if avatar && avatar.readable?
|
||||
|
||||
card.to_s
|
||||
|
||||
end
|
||||
def contacts_to_vcard(contacts)
|
||||
return "" unless User.current.allowed_to?(:export_contacts, @project, :global => true)
|
||||
contacts.map{|c| contact_to_vcard(c) }.join("\r\n")
|
||||
end
|
||||
|
||||
def contacts_to_xls(contacts)
|
||||
return "" unless User.current.allowed_to?(:export_contacts, @project, :global => true)
|
||||
require 'spreadsheet'
|
||||
|
||||
Spreadsheet.client_encoding = 'UTF-8'
|
||||
book = Spreadsheet::Workbook.new
|
||||
sheet = book.create_worksheet
|
||||
headers = [ "#",
|
||||
l(:field_is_company),
|
||||
l(:field_contact_first_name),
|
||||
l(:field_contact_middle_name),
|
||||
l(:field_contact_last_name),
|
||||
l(:field_contact_job_title),
|
||||
l(:field_contact_company),
|
||||
l(:field_contact_phone),
|
||||
l(:field_contact_email),
|
||||
l(:label_crm_address),
|
||||
l(:label_crm_city),
|
||||
l(:label_crm_postcode),
|
||||
l(:label_crm_region),
|
||||
l(:label_crm_country),
|
||||
l(:field_contact_skype),
|
||||
l(:field_contact_website),
|
||||
l(:field_birthday),
|
||||
l(:field_contact_tag_names),
|
||||
l(:label_crm_assigned_to),
|
||||
l(:field_contact_background),
|
||||
l(:field_created_on),
|
||||
l(:field_updated_on)
|
||||
]
|
||||
custom_fields = ContactCustomField.order('LOWER(name)')
|
||||
custom_fields.each { |f| headers << f.name }
|
||||
idx = 0
|
||||
row = sheet.row(idx)
|
||||
row.replace headers
|
||||
|
||||
contacts.each do |contact|
|
||||
idx += 1
|
||||
row = sheet.row(idx)
|
||||
fields = [contact.id,
|
||||
contact.is_company ? 1 : 0,
|
||||
contact.first_name,
|
||||
contact.middle_name,
|
||||
contact.last_name,
|
||||
contact.job_title,
|
||||
contact.company,
|
||||
contact.phone,
|
||||
contact.email,
|
||||
contact.address.to_s.gsub("\r\n"," ").gsub("\n", ' '),
|
||||
contact.city,
|
||||
contact.postcode,
|
||||
contact.region,
|
||||
contact.country,
|
||||
contact.skype_name,
|
||||
contact.website,
|
||||
format_date(contact.birthday),
|
||||
contact.tag_list.to_s,
|
||||
contact.assigned_to ? contact.assigned_to.name : "",
|
||||
contact.background.to_s.gsub("\r\n"," ").gsub("\n", ' '),
|
||||
format_date(contact.created_on),
|
||||
format_date(contact.updated_on)
|
||||
]
|
||||
contact.custom_field_values.sort_by{|v| v.custom_field.name.downcase}.each {|custom_value| fields << RedmineContacts::CSVUtils.csv_custom_value(custom_value) }
|
||||
row.replace fields
|
||||
end
|
||||
|
||||
xls_stream = StringIO.new('')
|
||||
book.write(xls_stream)
|
||||
|
||||
return xls_stream.string
|
||||
end
|
||||
|
||||
def mail_macro(contact, message)
|
||||
message = message.gsub(/%%NAME%%/, contact.first_name)
|
||||
message = message.gsub(/%%FULL_NAME%%/, contact.name)
|
||||
message = message.gsub(/%%COMPANY%%/, contact.company) if contact.company
|
||||
message = message.gsub(/%%LAST_NAME%%/, contact.last_name) if contact.last_name
|
||||
message = message.gsub(/%%MIDDLE_NAME%%/, contact.middle_name) if contact.middle_name
|
||||
message = message.gsub(/%%DATE%%/, format_date(Date.today.to_s))
|
||||
|
||||
contact.custom_field_values.each do |value|
|
||||
message = message.gsub(/%%#{value.custom_field.name}%%/, value.value.to_s)
|
||||
end
|
||||
message
|
||||
end
|
||||
|
||||
def set_flash_from_bulk_contact_save(contacts, unsaved_contact_ids)
|
||||
if unsaved_contact_ids.empty?
|
||||
flash[:notice] = l(:notice_successful_update) unless contacts.empty?
|
||||
else
|
||||
flash[:error] = l(:notice_failed_to_save_contacts,
|
||||
:count => unsaved_contact_ids.size,
|
||||
:total => contacts.size,
|
||||
:ids => '#' + unsaved_contact_ids.join(', #'))
|
||||
end
|
||||
end
|
||||
|
||||
def render_contact_tabs(tabs)
|
||||
if tabs.any?
|
||||
render :partial => 'common/contact_tabs', :locals => {:tabs => tabs}
|
||||
else
|
||||
content_tag 'p', l(:label_no_data), :class => "nodata"
|
||||
end
|
||||
end
|
||||
|
||||
def importer_link
|
||||
project_contact_imports_path
|
||||
end
|
||||
|
||||
def importer_show_link(importer, project)
|
||||
project_contact_import_path(:id => importer, :project_id => project)
|
||||
end
|
||||
|
||||
def importer_settings_link(importer, project)
|
||||
settings_project_contact_import_path(:id => importer, :project => project)
|
||||
end
|
||||
|
||||
def importer_run_link(importer, project)
|
||||
run_project_contact_import_path(:id => importer, :project_id => project, :format => 'js')
|
||||
end
|
||||
|
||||
def importer_link_to_object(contact)
|
||||
link_to "#{contact.first_name} #{contact.last_name}", contact_path(contact)
|
||||
end
|
||||
|
||||
def _project_contacts_path(project, *args)
|
||||
if project
|
||||
project_contacts_path(project, *args)
|
||||
else
|
||||
contacts_path(*args)
|
||||
end
|
||||
end
|
||||
def deals_link_to_remove_fields(name, f, options={})
|
||||
f.hidden_field(:_destroy) + link_to_function(name, "remove_order_fields(this); tooglePriceField()", options)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,24 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# This file is a part of Redmine CRM (redmine_contacts) plugin,
|
||||
# customer relationship management plugin for Redmine
|
||||
#
|
||||
# Copyright (C) 2010-2018 RedmineUP
|
||||
# http://www.redmineup.com/
|
||||
#
|
||||
# redmine_contacts is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# redmine_contacts is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
module ContactsMoneyHelper
|
||||
# Will be depricated
|
||||
end
|
||||
@@ -0,0 +1,94 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# This file is a part of Redmine CRM (redmine_contacts) plugin,
|
||||
# customer relationship management plugin for Redmine
|
||||
#
|
||||
# Copyright (C) 2010-2018 RedmineUP
|
||||
# http://www.redmineup.com/
|
||||
#
|
||||
# redmine_contacts is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# redmine_contacts is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
module CrmQueriesHelper
|
||||
|
||||
def retrieve_crm_query(object_type)
|
||||
query_class = Object.const_get("#{object_type.camelcase}Query")
|
||||
if !params[:query_id].blank?
|
||||
cond = "project_id IS NULL"
|
||||
cond << " OR project_id = #{@project.id}" if @project
|
||||
@query = query_class.where(cond).find(params[:query_id])
|
||||
raise ::Unauthorized unless @query.visible?
|
||||
@query.project = @project
|
||||
session["#{object_type}_query".to_sym] = {:id => @query.id, :project_id => @query.project_id}
|
||||
sort_clear
|
||||
elsif api_request? || params[:set_filter] || session["#{object_type}_query".to_sym].nil? || session["#{object_type}_query".to_sym][:project_id] != (@project ? @project.id : nil)
|
||||
# Give it a name, required to be valid
|
||||
@query = query_class.new(:name => "_")
|
||||
@query.project = @project
|
||||
@query.build_from_params(params)
|
||||
session["#{object_type}_query".to_sym] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names}
|
||||
else
|
||||
# retrieve from session
|
||||
@query = query_class.find(session["#{object_type}_query".to_sym][:id]) if session["#{object_type}_query".to_sym][:id]
|
||||
@query ||= query_class.new(:name => "_", :filters => session["#{object_type}_query".to_sym][:filters], :group_by => session["#{object_type}_query".to_sym][:group_by], :column_names => session["#{object_type}_query".to_sym][:column_names])
|
||||
@query.project = @project
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def retrieve_crm_calendar(options = {})
|
||||
if params[:year] and params[:year].to_i > 1900
|
||||
@year = params[:year].to_i
|
||||
if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13
|
||||
@month = params[:month].to_i
|
||||
end
|
||||
end
|
||||
@year ||= Date.today.year
|
||||
@month ||= Date.today.month
|
||||
|
||||
@calendar = RedmineContacts::Helpers::CrmCalendar.new(Date.civil(@year, @month, 1), options)
|
||||
end
|
||||
|
||||
def sidebar_crm_queries(query_class)
|
||||
unless @sidebar_queries
|
||||
@sidebar_queries = query_class.visible.
|
||||
where(@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id]).
|
||||
order("#{query_class.table_name}.name ASC")
|
||||
end
|
||||
@sidebar_queries
|
||||
end
|
||||
|
||||
def crm_query_links(title, queries, object_type)
|
||||
# links to #index on contacts/show
|
||||
return '' unless queries.any?
|
||||
url_params = controller_name == "#{object_type}s" ? {:controller => "#{object_type}s", :action => 'index', :project_id => @project} : params
|
||||
content_tag('h3', title) + "\n" +
|
||||
content_tag('ul',
|
||||
queries.collect {|query|
|
||||
css = 'query'
|
||||
css << ' selected' if query == @query
|
||||
content_tag('li', link_to(query.name, url_params.merge(:query_id => query), :class => css))
|
||||
}.join("\n").html_safe,
|
||||
:class => 'queries'
|
||||
) + "\n"
|
||||
end
|
||||
|
||||
def render_sidebar_crm_queries(object_type)
|
||||
query_class = Object.const_get("#{object_type.camelcase}Query")
|
||||
out = ''.html_safe
|
||||
out << crm_query_links(l(:label_my_queries), sidebar_crm_queries(query_class).select(&:is_private?), object_type)
|
||||
out << crm_query_links(l(:label_query_plural), sidebar_crm_queries(query_class).reject(&:is_private?), object_type)
|
||||
out
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,185 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# This file is a part of Redmine CRM (redmine_contacts) plugin,
|
||||
# customer relationship management plugin for Redmine
|
||||
#
|
||||
# Copyright (C) 2010-2018 RedmineUP
|
||||
# http://www.redmineup.com/
|
||||
#
|
||||
# redmine_contacts is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# redmine_contacts is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
module DealsHelper
|
||||
include ContactsHelper
|
||||
def collection_for_status_select
|
||||
deal_statuses.collect{|s| [s.name, s.id.to_s]}
|
||||
end
|
||||
|
||||
def deal_status_options_for_select(select="")
|
||||
options_for_select(collection_for_status_select, select)
|
||||
end
|
||||
|
||||
def deal_statuses
|
||||
(!@project.blank? ? @project.deal_statuses : DealStatus.order("#{DealStatus.table_name}.status_type, #{DealStatus.table_name}.position")) || []
|
||||
end
|
||||
|
||||
def deal_status_url(status_id, options={})
|
||||
{:controller => 'deals',
|
||||
:action => 'index',
|
||||
:set_filter => 1,
|
||||
:project_id => @project,
|
||||
:fields => [:status_id],
|
||||
:values => {:status_id => [status_id]},
|
||||
:operators => {:status_id => '='}}.merge(options)
|
||||
end
|
||||
|
||||
def pipeline_status_tag(deal_status, count, index)
|
||||
total = @processor.scope.count
|
||||
width ||= 20 if deal_status.is_won?
|
||||
width ||= 40 if deal_status.is_lost?
|
||||
width ||= (100 - 20) * (count.to_f / total.to_f) + 20
|
||||
width_style = index == 0 ? "" : "width: #{width}%"
|
||||
status_tag = content_tag(:span, deal_status.name)
|
||||
content_tag(:span, status_tag, :class => "tag-label-color", :style => "background-color:#{deal_status.color_name};color:white; #{width_style}")
|
||||
end
|
||||
|
||||
def remove_contractor_link(contact)
|
||||
link_to(image_tag('delete.png'),
|
||||
{:controller => "deal_contacts", :action => 'delete', :project_id => @project, :deal_id => @deal, :contact_id => contact},
|
||||
:remote => true,
|
||||
:method => :delete,
|
||||
:data => {:confirm => l(:text_are_you_sure)},
|
||||
:class => "delete", :title => l(:button_delete)) if User.current.allowed_to?(:edit_deals, @project)
|
||||
end
|
||||
|
||||
def link_to_deal(deal)
|
||||
link_to deal.name, deal_path(deal)
|
||||
end
|
||||
|
||||
def deal_list_styles_for_select
|
||||
[[l(:label_crm_list_excerpt), "list_excerpt"],
|
||||
[l(:label_crm_list_list), "list"],
|
||||
[l(:label_crm_list_board), "list_board"],
|
||||
[l(:label_calendar), "crm_calendars/crm_calendar"],
|
||||
[l(:label_crm_pipeline), "list_pipeline"]]
|
||||
end
|
||||
|
||||
def deals_list_style
|
||||
list_styles = deal_list_styles_for_select.map(&:last)
|
||||
if params[:deals_list_style].blank?
|
||||
list_style = list_styles.include?(session[:deals_list_style]) ? session[:deals_list_style] : RedmineContacts.default_list_style.gsub("list_cards", "list_board")
|
||||
else
|
||||
list_style = list_styles.include?(params[:deals_list_style]) ? params[:deals_list_style] : RedmineContacts.default_list_style.gsub("list_cards", "list_board")
|
||||
end
|
||||
session[:deals_list_style] = list_style
|
||||
end
|
||||
|
||||
def retrieve_deals_query
|
||||
if params[:status_id] || !params[:period].blank? || !params[:category_id].blank? || !params[:assigned_to_id].blank?
|
||||
session[:deals_query] = {:project_id => (@project ? @project.id : nil),
|
||||
:status_id => params[:status_id],
|
||||
:category_id => params[:category_id],
|
||||
:period => params[:period],
|
||||
:assigned_to_id => params[:assigned_to_id]}
|
||||
else
|
||||
if api_request? || params[:set_filter] || session[:deals_query].nil? || session[:deals_query][:project_id] != (@project ? @project.id : nil)
|
||||
session[:deals_query] = {}
|
||||
else
|
||||
params.merge!(session[:deals_query])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def pipeline_prices(scope)
|
||||
prices_collection_by_currency(scope.group_by(&:currency).map{|k,v| [k, v.inject(0) { |sum, x| sum + x.price.to_f } ] }).join(' / ').html_safe
|
||||
end
|
||||
|
||||
def deals_to_csv(deals)
|
||||
return "" unless User.current.allowed_to?(:export_contacts, @project, :global => true)
|
||||
decimal_separator = l(:general_csv_decimal_separator)
|
||||
encoding = 'utf-8'
|
||||
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
|
||||
# csv header fields
|
||||
headers = [ "#",
|
||||
l(:field_name, :locale => :en),
|
||||
l(:field_background, :locale => :en),
|
||||
l(:field_currency, :locale => :en),
|
||||
l(:field_price, :locale => :en),
|
||||
l(:label_crm_probability, :locale => :en),
|
||||
l(:label_crm_expected_revenue, :locale => :en),
|
||||
l(:field_due_date, :locale => :en),
|
||||
l(:field_author, :locale => :en),
|
||||
l(:field_assigned_to, :locale => :en),
|
||||
l(:field_status, :locale => :en),
|
||||
l(:field_contact, :locale => :en),
|
||||
l(:field_category, :locale => :en),
|
||||
l(:field_created_on, :locale => :en),
|
||||
l(:field_updated_on, :locale => :en)
|
||||
]
|
||||
|
||||
custom_fields = DealCustomField.order(:name)
|
||||
custom_fields.each {|f| headers << f.name}
|
||||
csv << headers.collect {|c| Redmine::CodesetUtil.from_utf8(c.to_s, encoding) }
|
||||
# csv lines
|
||||
deals.each do |deal|
|
||||
fields = [deal.id,
|
||||
deal.name,
|
||||
deal.background,
|
||||
deal.currency,
|
||||
deal.price,
|
||||
deal.probability,
|
||||
deal.expected_revenue,
|
||||
format_date(deal.due_date),
|
||||
deal.author,
|
||||
deal.assigned_to,
|
||||
deal.status,
|
||||
deal.contact,
|
||||
deal.category,
|
||||
format_date(deal.created_on),
|
||||
format_date(deal.updated_on)
|
||||
]
|
||||
deal.custom_field_values.sort_by{|v| v.custom_field.name}.each {|custom_value| fields << RedmineContacts::CSVUtils.csv_custom_value(custom_value) }
|
||||
csv << fields.collect {|c| Redmine::CodesetUtil.from_utf8(c.to_s, encoding) }
|
||||
end
|
||||
end
|
||||
export
|
||||
end
|
||||
|
||||
def importer_link
|
||||
project_deal_imports_path
|
||||
end
|
||||
|
||||
def importer_show_link(importer, project)
|
||||
project_deal_import_path(:id => importer, :project_id => project)
|
||||
end
|
||||
|
||||
def importer_settings_link(importer, project)
|
||||
settings_project_deal_import_path(:id => importer, :project => project)
|
||||
end
|
||||
|
||||
def importer_run_link(importer, project)
|
||||
run_project_deal_import_path(:id => importer, :project_id => project, :format => 'js')
|
||||
end
|
||||
|
||||
def importer_link_to_object(deal)
|
||||
link_to deal.name, deal_path(deal)
|
||||
end
|
||||
|
||||
def _project_deals_path(project, *args)
|
||||
if project
|
||||
project_deals_path(project, *args)
|
||||
else
|
||||
deals_path(*args)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,132 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# This file is a part of Redmine CRM (redmine_contacts) plugin,
|
||||
# customer relationship management plugin for Redmine
|
||||
#
|
||||
# Copyright (C) 2010-2018 RedmineUP
|
||||
# http://www.redmineup.com/
|
||||
#
|
||||
# redmine_contacts is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# redmine_contacts is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with redmine_contacts. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
module NotesHelper
|
||||
include ContactsHelper
|
||||
|
||||
def collection_for_note_types_select
|
||||
note_types = [[l(:label_crm_note), '']] + [:label_crm_note_type_email, :label_crm_note_type_call, :label_crm_note_type_meeting].each_with_index.collect{|type, i| [l(type), i]}
|
||||
context = {:note_types => note_types}
|
||||
call_hook(:helper_notes_note_type_label, context)
|
||||
context[:note_types]
|
||||
end
|
||||
|
||||
def authoring_note(created, author, options={})
|
||||
return "<span class=\"author\">#{l(options[:label] || :label_crm_added_by)} #{link_to_user(author).to_s}</span>".html_safe if created.blank?
|
||||
if RedmineContacts.settings[:note_authoring_time]
|
||||
('<span class="author">' + l(options[:label] || :label_crm_added_by) + ' ' +
|
||||
link_to_user(author).to_s + ', ' +
|
||||
format_time(created).to_s + '</span>').html_safe
|
||||
else
|
||||
authoring(created, author, options={})
|
||||
end
|
||||
end
|
||||
|
||||
def add_note_url(note_source, project=nil)
|
||||
{:controller => 'notes', :action => 'create', :source_id => note_source, :source_type => note_source.class.name, :project_id => project}
|
||||
end
|
||||
|
||||
def contacts_thumbnails(obj, options={})
|
||||
return false if !obj || !obj.respond_to?(:attachments)
|
||||
options[:size] = options[:size].to_s || "100"
|
||||
size = options[:size]
|
||||
options[:size] = options[:size] + "x" + options[:size]
|
||||
# options[:max_width] = size
|
||||
# options[:max_heght] = size
|
||||
max_file_size = options[:max_file_size] || 300.kilobytes
|
||||
options[:class] = "thumbnail"
|
||||
|
||||
s = ""
|
||||
# TODO: Regexp does not work
|
||||
images = obj.attachments.select{|att| att.thumbnailable?}
|
||||
images = images.select{|att| att.filename.match(options[:regexp])} if options[:regexp]
|
||||
images.each do |att_file|
|
||||
attachment_url = url_for :controller => 'attachments', :action => 'download', :id => att_file, :filename => att_file.filename
|
||||
contacts_thumbnail_url = url_for(:controller => 'attachments',
|
||||
:action => 'contacts_thumbnail',
|
||||
:id => att_file,
|
||||
:size => size)
|
||||
|
||||
image_url = Redmine::Thumbnail.convert_available? ? contacts_thumbnail_url : attachment_url
|
||||
s << link_to(image_tag(image_url, options), attachment_url, {:title => att_file.filename}) if (att_file.filesize < max_file_size || Redmine::Thumbnail.convert_available?)
|
||||
end
|
||||
s.html_safe
|
||||
end
|
||||
|
||||
def auto_contacts_thumbnails(obj)
|
||||
s = ""
|
||||
max_file_size = Setting.plugin_redmine_contacts[:max_contacts_thumbnail_file_size].to_i.kilobytes if !Setting.plugin_redmine_contacts[:max_contacts_thumbnail_file_size].blank?
|
||||
s << contacts_thumbnails(obj, {:size => 100, :max_file_size => max_file_size}) if Setting.plugin_redmine_contacts[:auto_contacts_thumbnails]
|
||||
s = content_tag(:p, s.html_safe, :class => "thumbnail") if !s.blank?
|
||||
s.html_safe
|
||||
end
|
||||
|
||||
def note_content(note)
|
||||
s = ''
|
||||
if note.content.length > Note.cut_length
|
||||
if ActiveRecord::VERSION::MAJOR >= 4
|
||||
s << truncate(note.content, :length => Note.cut_length) { link_to "#{l(:label_crm_note_read_more)}", note_path(:id => note, :project_id => @project) }
|
||||
else
|
||||
s << textilizable(truncate(note.content, :length => Note.cut_length,
|
||||
:omission => "... \"#{l(:label_crm_note_read_more)}\":#{url_for(:controller => 'notes',
|
||||
:action => 'show',
|
||||
:project_id => @project,
|
||||
:id => note)}"))
|
||||
end
|
||||
else
|
||||
s << textilizable(note, :content)
|
||||
end
|
||||
s.html_safe
|
||||
end
|
||||
|
||||
def notes_to_csv(notes)
|
||||
decimal_separator = l(:general_csv_decimal_separator)
|
||||
encoding = l(:general_csv_encoding)
|
||||
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
|
||||
# csv header fields
|
||||
headers = [ "#",
|
||||
l(:field_type, :locale => :en),
|
||||
l(:label_date, :locale => :en),
|
||||
l(:field_author, :locale => :en),
|
||||
l(:field_content, :locale => :en)
|
||||
]
|
||||
# Export project custom fields if project is given
|
||||
# otherwise export custom fields marked as "For all projects"
|
||||
custom_fields = NoteCustomField.order(:name)
|
||||
custom_fields.each {|f| headers << f.name}
|
||||
# Description in the last column
|
||||
csv << headers.collect {|c| Redmine::CodesetUtil.from_utf8(c.to_s, encoding) }
|
||||
# csv lines
|
||||
notes.each do |note|
|
||||
fields = [note.id,
|
||||
note.type_id,
|
||||
format_time(note.created_on),
|
||||
note.author.name,
|
||||
note.content
|
||||
]
|
||||
custom_fields.each {|f| fields << RedmineContacts::CSVUtils.csv_custom_value(note.custom_value_for(f)) }
|
||||
csv << fields.collect {|c| Redmine::CodesetUtil.from_utf8(c.to_s, encoding) }
|
||||
end
|
||||
end
|
||||
export
|
||||
end
|
||||
|
||||
end
|
||||
Reference in New Issue
Block a user