e9_crm 0.1.10 → 0.1.11
Sign up to get free protection for your applications and to get access to all the features.
- data/app/controllers/e9_crm/contacts_controller.rb +29 -10
- data/app/controllers/e9_crm/deals_controller.rb +0 -1
- data/app/controllers/e9_crm/email_templates.controller.rb +10 -0
- data/app/helpers/e9_crm/base_helper.rb +2 -0
- data/app/helpers/e9_crm/campaigns_helper.rb +7 -2
- data/app/helpers/e9_crm/contacts_helper.rb +7 -1
- data/app/models/company.rb +1 -0
- data/app/models/contact.rb +4 -1
- data/app/models/deal.rb +40 -30
- data/app/models/email_template.rb +4 -0
- data/app/models/sales_campaign.rb +1 -1
- data/app/views/e9_crm/campaigns/_table.html.haml +3 -0
- data/app/views/e9_crm/campaigns/reports.html.haml +0 -2
- data/app/views/e9_crm/contacts/_details.html.haml +4 -1
- data/app/views/e9_crm/contacts/_form_inner.html.haml +8 -2
- data/app/views/e9_crm/contacts/_index_sidebar.html.haml +13 -7
- data/app/views/e9_crm/contacts/_sidebar.html.haml +7 -7
- data/app/views/e9_crm/contacts/_table.html.haml +3 -0
- data/app/views/e9_crm/contacts/_who.html.haml +1 -1
- data/app/views/e9_crm/contacts/index.html.haml +0 -1
- data/app/views/e9_crm/contacts/show.html.haml +3 -1
- data/app/views/e9_crm/deals/_leads_table.html.haml +3 -0
- data/app/views/e9_crm/deals/_reports_table.html.haml +12 -12
- data/app/views/e9_crm/deals/_table.html.haml +3 -0
- data/app/views/e9_crm/email_templates/_form_inner.html.haml +1 -1
- data/app/views/e9_crm/page_views/_table.html.haml +3 -0
- data/app/views/e9_crm/resources/_table.html.haml +3 -0
- data/app/views/e9_crm/resources/index.html.haml +0 -2
- data/app/views/e9_crm/sales_campaigns/_form_inner.html.haml +1 -2
- data/config/locales/e9.en.yml +1 -1
- data/config/locales/en.yml +6 -3
- data/e9_crm.gemspec +2 -2
- data/lib/e9_crm/version.rb +1 -1
- data/lib/generators/e9_crm/templates/migration.rb +1 -0
- metadata +4 -12
- data/app/views/e9_crm/campaign_groups/_footer.html.haml +0 -0
- data/app/views/e9_crm/campaigns/_footer.html.haml +0 -0
- data/app/views/e9_crm/campaigns/_reports_table.html.haml +0 -31
- data/app/views/e9_crm/deals/_footer.html.haml +0 -0
- data/app/views/e9_crm/email_templates/_footer.html.haml +0 -0
- data/app/views/e9_crm/menu_options/_footer.html.haml +0 -0
- data/app/views/e9_crm/offers/_footer.html.haml +0 -0
- data/app/views/e9_crm/resources/_footer.html.haml +0 -1
@@ -11,17 +11,23 @@ class E9Crm::ContactsController < E9Crm::ResourcesController
|
|
11
11
|
before_filter :determine_title, :only => :index
|
12
12
|
before_filter :load_contact_ids, :only => :index
|
13
13
|
before_filter :build_nested_associations, :only => [:new, :edit]
|
14
|
+
before_filter :set_tag_instructions_scope
|
14
15
|
|
15
16
|
has_scope :search, :by_title, :by_company, :only => :index
|
16
17
|
has_scope :tagged, :only => :index, :type => :array
|
18
|
+
has_scope :by_company, :as => :company, :only => :index
|
17
19
|
|
18
20
|
# record attributes templates js
|
19
21
|
skip_before_filter :authenticate_user!, :filter_access_filter, :only => :templates
|
20
22
|
before_filter :build_resource, :only => :templates
|
21
|
-
caches_action :templates
|
23
|
+
#caches_action :templates
|
22
24
|
|
25
|
+
# NOTE for some reason create! { redirect } is trying to redirect on failure
|
23
26
|
def create
|
24
|
-
create!
|
27
|
+
create! do |success, failure|
|
28
|
+
success.html { redirect_to resource_path }
|
29
|
+
failure.html { render :new }
|
30
|
+
end
|
25
31
|
end
|
26
32
|
|
27
33
|
def update
|
@@ -36,7 +42,7 @@ class E9Crm::ContactsController < E9Crm::ResourcesController
|
|
36
42
|
#
|
37
43
|
def load_contact_ids
|
38
44
|
@contact_ids ||= begin
|
39
|
-
contact_id_sql = end_of_association_chain.scoped.select('contacts.id').to_sql
|
45
|
+
contact_id_sql = end_of_association_chain.scoped.ok_to_email.select('contacts.id').to_sql
|
40
46
|
Contact.connection.send(:select_values, contact_id_sql, 'Contact ID Load')
|
41
47
|
end
|
42
48
|
end
|
@@ -46,22 +52,35 @@ class E9Crm::ContactsController < E9Crm::ResourcesController
|
|
46
52
|
#
|
47
53
|
def determine_title
|
48
54
|
params.delete(:search) if params[:search].blank?
|
49
|
-
|
50
|
-
@index_title
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
55
|
+
|
56
|
+
@index_title = 'Contacts'.tap do |t|
|
57
|
+
if params[:search]
|
58
|
+
t << " matching \"#{params[:search]}\""
|
59
|
+
end
|
60
|
+
if params[:tagged]
|
61
|
+
t << " tagged #{params[:tagged].map {|t| "\"#{t}\"" }.join(' or ')}"
|
62
|
+
end
|
63
|
+
if params[:company] =~ /\d+/ && company = Company.find_by_id(params[:company])
|
64
|
+
t << " in company \"#{company.name}\""
|
65
|
+
end
|
56
66
|
end
|
57
67
|
end
|
58
68
|
|
69
|
+
# we don't need @index_title in the breadcrumb here (too long)
|
70
|
+
def add_index_breadcrumb
|
71
|
+
add_breadcrumb! e9_t(:index_title), collection_path
|
72
|
+
end
|
73
|
+
|
59
74
|
def collection_scope
|
60
75
|
#TODO fix eager loading, which totally breaks because of the left outer joins in search
|
61
76
|
#super.includes(:users => :subscriptions)
|
62
77
|
scope = super
|
63
78
|
end
|
64
79
|
|
80
|
+
def set_tag_instructions_scope
|
81
|
+
@tag_instructions_scope = 'activerecord.attributes.contact'
|
82
|
+
end
|
83
|
+
|
65
84
|
def build_nested_associations
|
66
85
|
object = params[:id] ? resource : build_resource
|
67
86
|
object.build_all_record_attributes
|
@@ -2,4 +2,14 @@ class E9Crm::EmailTemplatesController < E9Crm::ResourcesController
|
|
2
2
|
defaults
|
3
3
|
include E9Rails::Controllers::Orderable
|
4
4
|
self.should_paginate_index = false
|
5
|
+
|
6
|
+
protected
|
7
|
+
|
8
|
+
def default_ordered_on
|
9
|
+
'name'
|
10
|
+
end
|
11
|
+
|
12
|
+
def default_ordered_dir
|
13
|
+
'ASC'
|
14
|
+
end
|
5
15
|
end
|
@@ -101,6 +101,8 @@ module E9Crm::BaseHelper
|
|
101
101
|
)
|
102
102
|
end
|
103
103
|
|
104
|
+
# tries to build an associated resource, looking to the assocatiaon's model for a method
|
105
|
+
# named "%{association_name}_build_parameters}" first for any default params
|
104
106
|
def build_associated_resource(association_name)
|
105
107
|
params_method = "#{association_name}_build_parameters"
|
106
108
|
build_params = resource_class.send(params_method) if resource_class.respond_to?(params_method)
|
@@ -3,12 +3,17 @@ module E9Crm::CampaignsHelper
|
|
3
3
|
Money === val && val || 'n/a'
|
4
4
|
end
|
5
5
|
|
6
|
+
def no_money
|
7
|
+
@_no_money ||= Money.new(0)
|
8
|
+
end
|
9
|
+
|
6
10
|
def display_campaign_code(val)
|
7
11
|
val && "?#{E9Crm.query_param}=#{val}" || 'n/a'
|
8
12
|
end
|
9
13
|
|
10
|
-
def display_campaign_type(val)
|
11
|
-
val[/(.*)Campaign/, 1]
|
14
|
+
def display_campaign_type(val = '')
|
15
|
+
retv = val[/(.*)Campaign/, 1]
|
16
|
+
retv == 'No' ? 'No Campaign' : retv
|
12
17
|
end
|
13
18
|
|
14
19
|
def campaign_type_select_options(with_all_option = true)
|
@@ -9,6 +9,12 @@ module E9Crm::ContactsHelper
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
+
def company_select_options
|
13
|
+
options = Company.select('name', 'id').ordered.all.map {|c| [c.name, c.id] }
|
14
|
+
options.unshift(['Any Company', nil])
|
15
|
+
options_for_select(options, params[:company])
|
16
|
+
end
|
17
|
+
|
12
18
|
def link_to_google(query, opts = {})
|
13
19
|
return unless query.present?
|
14
20
|
|
@@ -75,7 +81,7 @@ module E9Crm::ContactsHelper
|
|
75
81
|
def records_table_field_map_for_contact
|
76
82
|
{
|
77
83
|
:fields => {
|
78
|
-
:avatar => proc {|r| "<img src=\"#{r.avatar_url}\" alt=\"Avatar for #{r.name}\" />".html_safe
|
84
|
+
:avatar => proc {|r| link_to("<img src=\"#{r.avatar_url}\" alt=\"Avatar for #{r.name}\" />".html_safe, contact_path(r)) },
|
79
85
|
:details => proc {|r| render('details', :record => r) }
|
80
86
|
},
|
81
87
|
|
data/app/models/company.rb
CHANGED
data/app/models/contact.rb
CHANGED
@@ -154,6 +154,7 @@ class Contact < ActiveRecord::Base
|
|
154
154
|
scope :contacts, lambda { where(:status => Status::Contact) }
|
155
155
|
scope :ordered, lambda { order(arel_table[:first_name].asc) }
|
156
156
|
|
157
|
+
scope :ok_to_email, lambda { where(:ok_to_email => true) }
|
157
158
|
scope :by_title, lambda {|val| where(:title => val) }
|
158
159
|
scope :by_company, lambda {|val| where(:company_id => val) }
|
159
160
|
scope :tagged, lambda {|tags|
|
@@ -164,6 +165,7 @@ class Contact < ActiveRecord::Base
|
|
164
165
|
end
|
165
166
|
}
|
166
167
|
|
168
|
+
# NOTE for future restriction?
|
167
169
|
scope :deal_owners, lambda { scoped }
|
168
170
|
|
169
171
|
def self.available_to_deal(deal)
|
@@ -317,7 +319,8 @@ class Contact < ActiveRecord::Base
|
|
317
319
|
|
318
320
|
def ensure_no_associated_deals
|
319
321
|
unless self.associated_deals.empty?
|
320
|
-
|
322
|
+
errors.add(:associated_deals, :delete_restricted)
|
323
|
+
false
|
321
324
|
end
|
322
325
|
end
|
323
326
|
|
data/app/models/deal.rb
CHANGED
@@ -38,6 +38,7 @@ class Deal < ActiveRecord::Base
|
|
38
38
|
|
39
39
|
# denormalize campaign code and offer name columns
|
40
40
|
before_save :ensure_denormalized_columns
|
41
|
+
before_save :ensure_associated_campaign
|
41
42
|
|
42
43
|
# If a lead with no user, find the user by email or create it, then if mailing_lists
|
43
44
|
# were passed, assign the user those mailing lists
|
@@ -52,21 +53,30 @@ class Deal < ActiveRecord::Base
|
|
52
53
|
|
53
54
|
attr_accessor :mailing_list_ids
|
54
55
|
|
56
|
+
#
|
57
|
+
# reports is technically a deal scope, but actually returns campaigns
|
58
|
+
# and a selection of relevant pseudo columns.
|
59
|
+
#
|
60
|
+
# NOTE reports probably should be a campaign scope? It doesn't really seem
|
61
|
+
# to matter. The resultset is neither Deals nor Campaigns, anyway, but
|
62
|
+
# a selection of calculated columns aggregated from data from both tables.
|
63
|
+
#
|
55
64
|
scope :reports, lambda {
|
56
|
-
|
57
|
-
campaigns.
|
58
|
-
campaigns.
|
59
|
-
campaigns.
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
65
|
+
selects = <<-SQL.gsub(/\s+/, ' ')
|
66
|
+
campaigns.type campaign_type,
|
67
|
+
campaigns.name campaign_name,
|
68
|
+
campaigns.new_visits new_visits,
|
69
|
+
campaigns.repeat_visits repeat_visits,
|
70
|
+
|
71
|
+
deals.closed_at closed_at,
|
72
|
+
deals.created_at created_at,
|
73
|
+
|
74
|
+
campaign_groups.name campaign_group,
|
75
|
+
SUM(IF(deals.status != 'lead',1,0)) deal_count,
|
76
|
+
COUNT(deals.id) lead_count,
|
77
|
+
SUM(IF(deals.status='won',1,0)) won_deal_count,
|
78
|
+
SUM(IF(deals.status='won',deals.value,0)) total_value,
|
79
|
+
AVG(IF(deals.status='won',deals.value,NULL)) average_value,
|
70
80
|
SUM(CASE campaigns.type
|
71
81
|
WHEN "AdvertisingCampaign"
|
72
82
|
THEN dated_costs.cost
|
@@ -77,8 +87,7 @@ class Deal < ActiveRecord::Base
|
|
77
87
|
campaigns.affiliate_fee
|
78
88
|
ELSE
|
79
89
|
0
|
80
|
-
END)
|
81
|
-
|
90
|
+
END) total_cost,
|
82
91
|
SUM(CASE campaigns.type
|
83
92
|
WHEN "AdvertisingCampaign"
|
84
93
|
THEN dated_costs.cost
|
@@ -89,31 +98,28 @@ class Deal < ActiveRecord::Base
|
|
89
98
|
campaigns.affiliate_fee
|
90
99
|
ELSE
|
91
100
|
0
|
92
|
-
END) / SUM(IF(deals.status='won',1,0))
|
93
|
-
|
101
|
+
END) / SUM(IF(deals.status='won',1,0)) average_cost,
|
94
102
|
FLOOR(AVG(
|
95
103
|
DATEDIFF(
|
96
104
|
deals.closed_at,
|
97
|
-
deals.created_at)))
|
105
|
+
deals.created_at))) average_elapsed
|
106
|
+
SQL
|
98
107
|
|
99
|
-
|
108
|
+
joins = <<-SQL.gsub(/\s+/, ' ')
|
109
|
+
RIGHT JOIN campaigns
|
110
|
+
ON deals.campaign_id = campaigns.id
|
100
111
|
|
101
|
-
|
102
|
-
|
103
|
-
ON deals.campaign_id = dated_costs.costable_id
|
112
|
+
LEFT JOIN dated_costs
|
113
|
+
ON campaigns.id = dated_costs.costable_id
|
104
114
|
AND dated_costs.costable_type = "Campaign"
|
105
115
|
|
106
|
-
LEFT
|
107
|
-
ON campaigns.id = deals.campaign_id
|
108
|
-
|
109
|
-
LEFT OUTER JOIN campaign_groups
|
116
|
+
LEFT JOIN campaign_groups
|
110
117
|
ON campaign_groups.id = campaigns.campaign_group_id
|
111
|
-
|
118
|
+
SQL
|
112
119
|
|
113
|
-
select(
|
120
|
+
select(selects).joins(joins).group('campaigns.id')
|
114
121
|
}
|
115
122
|
|
116
|
-
|
117
123
|
validate do |record|
|
118
124
|
return unless record.status_changed?
|
119
125
|
|
@@ -223,6 +229,10 @@ class Deal < ActiveRecord::Base
|
|
223
229
|
self.offer_name ||= offer.name if offer.present?
|
224
230
|
end
|
225
231
|
|
232
|
+
def ensure_associated_campaign
|
233
|
+
self.campaign ||= Campaign.default
|
234
|
+
end
|
235
|
+
|
226
236
|
def get_name_and_email_from_user
|
227
237
|
if lead? && user.present?
|
228
238
|
self.lead_email = user.email
|
@@ -4,4 +4,8 @@
|
|
4
4
|
class EmailTemplate < Email
|
5
5
|
# TODO the email class hierarchy needs a major refactoring, it's backwards and convoluted
|
6
6
|
before_save :generate_html_body_from_text_body
|
7
|
+
|
8
|
+
validates :text_body, :presence => true
|
9
|
+
validates :subject, :presence => true
|
10
|
+
validates :from_email, :presence => true, :email => { :allow_blank => true }
|
7
11
|
end
|
@@ -6,7 +6,7 @@ class SalesCampaign < Campaign
|
|
6
6
|
money_columns :sales_fee
|
7
7
|
|
8
8
|
belongs_to :sales_person, :class_name => 'Contact'
|
9
|
-
validates :sales_person, :presence =>
|
9
|
+
validates :sales_person, :presence => { :if => lambda {|x| x.type == 'SalesCampaign' } }
|
10
10
|
|
11
11
|
##
|
12
12
|
# The sum cost of this campaign
|
@@ -7,9 +7,12 @@
|
|
7
7
|
|
8
8
|
- if record.users.any?
|
9
9
|
.contact-emails
|
10
|
+
- unless record.ok_to_email?
|
11
|
+
.contact-email-warning
|
12
|
+
= resource_humanize(:not_ok_to_email)
|
10
13
|
- record.users.each do |user|
|
11
14
|
.contact-email
|
12
|
-
|
15
|
+
-#= '* ' if contact_user_subscribed_to_newsletter?(user)
|
13
16
|
= link_to(user.email, "mailto:#{user.email}")
|
14
17
|
= "(#{user.options.type})" if user.options.type
|
15
18
|
= "(primary)" if user.primary?
|
@@ -1,9 +1,15 @@
|
|
1
|
-
|
1
|
+
%fieldset.nested-associations
|
2
|
+
%legend= f.label(:users)
|
3
|
+
= render_record_attribute_association(:users, f)
|
4
|
+
= link_to_add_record_attribute(:users)
|
5
|
+
.field.checkbox
|
6
|
+
= f.label :ok_to_email
|
7
|
+
= f.check_box :ok_to_email
|
2
8
|
|
3
9
|
%fieldset.contact-standard-fields
|
4
10
|
%legend= e9_t(:form_legend_standard)
|
5
11
|
.field
|
6
|
-
= f.label :first_name
|
12
|
+
= f.label :first_name, nil, :class => :req
|
7
13
|
= f.text_field :first_name
|
8
14
|
.field
|
9
15
|
= f.label :last_name
|
@@ -3,8 +3,9 @@
|
|
3
3
|
= link_to_collection(Company)
|
4
4
|
|
5
5
|
-# Email actions (template, newsletter)
|
6
|
-
|
7
|
-
|
6
|
+
-#- etag, ntag = contact_email_template_select_tag, contact_newsletter_select_tag
|
7
|
+
-#- if [etag, ntag].any?(&:present?)
|
8
|
+
- if (etag = contact_newsletter_select_tag).present?
|
8
9
|
%fieldset
|
9
10
|
%legend= e9_t(:email_actions_legend)
|
10
11
|
- if etag
|
@@ -12,11 +13,11 @@
|
|
12
13
|
= etag
|
13
14
|
= hidden_field_tag 'uids', @contact_ids.join(','), :id => 'contact_email_uids'
|
14
15
|
= submit_tag e9_t(:send_email_template), :name => nil
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
-#- if ntag
|
17
|
+
-#= form_tag send_email_admin_user_email_path('__ID__'), :method => :put, :id => 'contact_newsletter_form', 'data-confirm' => e9_t(:contact_newsletter_confirmation, :count => collection.length), 'data-empty' => e9_t(:no_contacts_notification), 'data-count' => @contact_ids.length do
|
18
|
+
-#= ntag
|
19
|
+
-#= hidden_field_tag 'uids', @contact_ids.join(','), :id => 'contact_newsletter_uids'
|
20
|
+
-#= submit_tag e9_t(:send_email_newsletter), :name => nil
|
20
21
|
|
21
22
|
-# Search filter options
|
22
23
|
%fieldset
|
@@ -25,6 +26,11 @@
|
|
25
26
|
= label_tag 'contact_search_field', t(:search)
|
26
27
|
= text_field_tag 'search', params[:search], :id => 'contact_search_field'
|
27
28
|
= submit_tag t(:go), :name => nil
|
29
|
+
|
30
|
+
= form_tag(resource_class, :method => :get, :class => 'scope-selects') do
|
31
|
+
%select{:name => 'company'}
|
32
|
+
= company_select_options
|
33
|
+
|
28
34
|
= render 'tag_table'
|
29
35
|
.actions
|
30
36
|
= submit_tag t(:clear), :name => nil, :id => 'contact_search_clear'
|
@@ -1,9 +1,3 @@
|
|
1
|
-
- if resource.phone_number_attributes.any?
|
2
|
-
.contact-phone-numbers
|
3
|
-
%label= Contact.human_attribute_name(:phone_number_attributes)
|
4
|
-
- resource.phone_number_attributes.each do |phone_number_attribute|
|
5
|
-
.contact-phone-number= phone_number_attribute
|
6
|
-
|
7
1
|
- if resource.users.any?
|
8
2
|
.contact-emails
|
9
3
|
%label= Contact.human_attribute_name(:users)
|
@@ -14,6 +8,12 @@
|
|
14
8
|
= "(#{user.options.type})" if user.options.type
|
15
9
|
= "(primary)" if user.primary?
|
16
10
|
|
11
|
+
- if resource.phone_number_attributes.any?
|
12
|
+
.contact-phone-numbers
|
13
|
+
%label= Contact.human_attribute_name(:phone_number_attributes)
|
14
|
+
- resource.phone_number_attributes.each do |phone_number_attribute|
|
15
|
+
.contact-phone-number= phone_number_attribute
|
16
|
+
|
17
17
|
- if resource.instant_messaging_handle_attributes.any?
|
18
18
|
.contact-im-handles
|
19
19
|
%label= Contact.human_attribute_name(:instant_messaging_handle_attributes)
|
@@ -25,7 +25,7 @@
|
|
25
25
|
%label= Contact.human_attribute_name(:website_attributes)
|
26
26
|
- resource.website_attributes.each do |website_attribute|
|
27
27
|
.contact-website
|
28
|
-
=
|
28
|
+
= link_to(website_attribute.to_s, website_attribute.to_s, :rel => "external nofollow")
|
29
29
|
|
30
30
|
- if resource.address_attributes.any?
|
31
31
|
.contact-addresses
|
@@ -1,6 +1,8 @@
|
|
1
1
|
.contact-body
|
2
2
|
= title resource.name
|
3
|
-
|
3
|
+
.contact-photo
|
4
|
+
%img{:src => resource.avatar_url, :alt => "Avatar for #{resource.name}"}
|
5
|
+
= render 'who', :record => resource, :hide_name => true
|
4
6
|
.contact-links.actions
|
5
7
|
= link_to_edit_resource(resource)
|
6
8
|
= google_search_link(resource.name)
|
@@ -32,3 +32,6 @@
|
|
32
32
|
= link_to_show_resource(record.contacts.first)
|
33
33
|
= link_to 'Create Deal', edit_deal_path(record)
|
34
34
|
= link_to 'Delete Lead', record, :method => :delete, :remote => true, :confirm => I18n.t("#{resource_class.i18n_scope}.links.confirm_destroy")
|
35
|
+
|
36
|
+
- if @controller.should_paginate_index
|
37
|
+
= will_paginate collection
|
@@ -25,11 +25,11 @@
|
|
25
25
|
- collection.each do |record|
|
26
26
|
%tr{:id => "ids_#{record.id}", :class => cycle('odd', 'even')}
|
27
27
|
%td.record-campaign-type
|
28
|
-
= record.campaign_type
|
28
|
+
= display_campaign_type(record.campaign_type)
|
29
29
|
%td.record-campaign-name
|
30
|
-
= record.campaign_name
|
30
|
+
= record.campaign_name || 'n/a'
|
31
31
|
%td.record-campaign-group
|
32
|
-
= record.campaign_group
|
32
|
+
= record.campaign_group || 'n/a'
|
33
33
|
%td.record-new-visits
|
34
34
|
- dat[:new_visits] << record.new_visits
|
35
35
|
= record.new_visits
|
@@ -47,16 +47,16 @@
|
|
47
47
|
= record.won_deal_count.to_i
|
48
48
|
%td.record-total-value
|
49
49
|
- dat[:total_value] << record.total_value
|
50
|
-
= record.total_value
|
50
|
+
= record.total_value || no_money
|
51
51
|
%td.record-averate-value
|
52
52
|
- dat[:average_value] << record.average_value
|
53
|
-
= record.average_value
|
53
|
+
= record.average_value || no_money
|
54
54
|
%td.record-total-cost
|
55
55
|
- dat[:total_cost] << record.total_cost
|
56
|
-
= record.total_cost
|
56
|
+
= record.total_cost || no_money
|
57
57
|
%td.record-average-cost
|
58
58
|
- dat[:average_cost] << record.average_cost
|
59
|
-
= record.average_cost
|
59
|
+
= record.average_cost || no_money
|
60
60
|
%td.record-average-elapsed
|
61
61
|
- dat[:average_elapsed] << record.average_elapsed
|
62
62
|
= record.average_elapsed && "%s days" % record.average_elapsed || 'n/a'
|
@@ -75,12 +75,12 @@
|
|
75
75
|
%td.record-won-deal-count
|
76
76
|
= dat[:won_deal_count].sum.to_i
|
77
77
|
%td.record-total-value
|
78
|
-
= dat[:total_value].
|
79
|
-
%td.record-
|
80
|
-
= dat[:average_value].average
|
78
|
+
= dat[:total_value].compact.sum.to_money
|
79
|
+
%td.record-average-value
|
80
|
+
= dat[:average_value].compact.average.to_money
|
81
81
|
%td.record-total-cost
|
82
|
-
= dat[:total_cost].compact.sum
|
82
|
+
= dat[:total_cost].compact.sum.to_money
|
83
83
|
%td.record-average-cost
|
84
|
-
= dat[:average_cost].compact.average
|
84
|
+
= dat[:average_cost].compact.average.to_money
|
85
85
|
%td.record-average-elapsed
|
86
86
|
= "%s days" % dat[:average_elapsed].compact.average
|
@@ -3,9 +3,8 @@
|
|
3
3
|
%fieldset
|
4
4
|
%legend= e9_t(:salesperson_information_legend, :scope => 'e9_crm.campaigns')
|
5
5
|
.field
|
6
|
-
= f.label :sales_person_id
|
6
|
+
= f.label :sales_person_id, nil, :class => (f.object.type == 'SalesCampaign' ? :req : nil)
|
7
7
|
= f.collection_select :sales_person_id, Contact.sales_persons.ordered.all, :id, :name, :prompt => true
|
8
8
|
.field
|
9
9
|
= help_label f, :sales_fee
|
10
10
|
= f.text_field :sales_fee
|
11
|
-
|
data/config/locales/e9.en.yml
CHANGED
@@ -16,7 +16,7 @@ en:
|
|
16
16
|
send_email_template: Send Email
|
17
17
|
send_email_newsletter: Send Newsletter
|
18
18
|
contact_newsletter_confirmation: "The system will send the newsletter to all of the selected contacts (%{count}) if they are subscribed to receieve email. Are you sure you want to proceed?"
|
19
|
-
no_contacts_notification: "
|
19
|
+
no_contacts_notification: "Either you have selected no contacts, or all of those selected are opted out of bulk email. Please correct this and try again."
|
20
20
|
email_actions_legend: Email Actions
|
21
21
|
search_options_legend: Search Filters
|
22
22
|
contact_merges:
|
data/config/locales/en.yml
CHANGED
@@ -42,6 +42,7 @@ en:
|
|
42
42
|
code:
|
43
43
|
invalid: "%{attribute} must be comprised of letters and numbers only."
|
44
44
|
contact:
|
45
|
+
delete_restricted: "This contact is related to leads and/or deals and can not be deleted."
|
45
46
|
attributes:
|
46
47
|
users:
|
47
48
|
taken: "Two or more of the login accounts entered share a duplicate email."
|
@@ -49,7 +50,7 @@ en:
|
|
49
50
|
contact_email:
|
50
51
|
attributes:
|
51
52
|
contact_ids:
|
52
|
-
blank: "
|
53
|
+
blank: "Either you have selected no contacts, or all of those selected are opted out of bulk email. Please correct this and try again."
|
53
54
|
user_ids:
|
54
55
|
blank: "None of the contacts selected are configured with primary emails. Please correct this and try again."
|
55
56
|
deal:
|
@@ -78,7 +79,7 @@ en:
|
|
78
79
|
menu_options: Menu Option
|
79
80
|
new_content_subscription_offer: New Content Subscription Offer
|
80
81
|
newsletter_subscription_offer: Newsletter Subscription Offer
|
81
|
-
no_campaign:
|
82
|
+
no_campaign: No Campaign
|
82
83
|
offer: Offer
|
83
84
|
page_view: Page View
|
84
85
|
phone_number_attrubute: Phone
|
@@ -101,9 +102,11 @@ en:
|
|
101
102
|
users: Email Addresses
|
102
103
|
address_attributes: Addresses
|
103
104
|
instant_messaging_handle_attributes: IM Handles
|
104
|
-
|
105
|
+
phone_number_attributes: Phone Numbers
|
105
106
|
website_attributes: Websites
|
106
107
|
info: Background Information
|
108
|
+
not_ok_to_email: "This contact will not receive bulk email."
|
109
|
+
tag_instructions: "Tags are words or phrases that describe or categorize this contact.\n\nWhen searching a particular tag, the system will show all contacts with that tag."
|
107
110
|
company:
|
108
111
|
info: Background Information
|
109
112
|
deal:
|
data/e9_crm.gemspec
CHANGED
@@ -23,8 +23,8 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.add_dependency("inherited_resources", "~> 1.1.2")
|
24
24
|
s.add_dependency("has_scope")
|
25
25
|
s.add_dependency("money")
|
26
|
-
s.add_dependency("e9_rails", "~> 0.0.
|
27
|
-
s.add_dependency("e9_tags", "~> 0.0.
|
26
|
+
s.add_dependency("e9_rails", "~> 0.0.16")
|
27
|
+
s.add_dependency("e9_tags", "~> 0.0.12")
|
28
28
|
s.add_dependency("will_paginate")
|
29
29
|
s.add_dependency("kramdown", "~> 0.13")
|
30
30
|
end
|
data/lib/e9_crm/version.rb
CHANGED
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: e9_crm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.1.
|
5
|
+
version: 0.1.11
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Travis Cox
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-05-
|
13
|
+
date: 2011-05-27 00:00:00 -04:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -65,7 +65,7 @@ dependencies:
|
|
65
65
|
requirements:
|
66
66
|
- - ~>
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 0.0.
|
68
|
+
version: 0.0.16
|
69
69
|
type: :runtime
|
70
70
|
version_requirements: *id005
|
71
71
|
- !ruby/object:Gem::Dependency
|
@@ -76,7 +76,7 @@ dependencies:
|
|
76
76
|
requirements:
|
77
77
|
- - ~>
|
78
78
|
- !ruby/object:Gem::Version
|
79
|
-
version: 0.0.
|
79
|
+
version: 0.0.12
|
80
80
|
type: :runtime
|
81
81
|
version_requirements: *id006
|
82
82
|
- !ruby/object:Gem::Dependency
|
@@ -216,13 +216,10 @@ files:
|
|
216
216
|
- app/views/e9_crm/advertising_campaigns/_form_inner.html.haml
|
217
217
|
- app/views/e9_crm/advertising_campaigns/costs.html.haml
|
218
218
|
- app/views/e9_crm/affiliate_campaigns/_form_inner.html.haml
|
219
|
-
- app/views/e9_crm/campaign_groups/_footer.html.haml
|
220
219
|
- app/views/e9_crm/campaign_groups/_form_inner.html.haml
|
221
220
|
- app/views/e9_crm/campaign_groups/_header.html.haml
|
222
|
-
- app/views/e9_crm/campaigns/_footer.html.haml
|
223
221
|
- app/views/e9_crm/campaigns/_form_inner.html.haml
|
224
222
|
- app/views/e9_crm/campaigns/_header.html.haml
|
225
|
-
- app/views/e9_crm/campaigns/_reports_table.html.haml
|
226
223
|
- app/views/e9_crm/campaigns/_table.html.haml
|
227
224
|
- app/views/e9_crm/campaigns/reports.html.haml
|
228
225
|
- app/views/e9_crm/companies/_form_inner.html.haml
|
@@ -259,7 +256,6 @@ files:
|
|
259
256
|
- app/views/e9_crm/dated_costs/new.html.haml
|
260
257
|
- app/views/e9_crm/dated_costs/show.html.haml
|
261
258
|
- app/views/e9_crm/dated_costs/update.js.erb
|
262
|
-
- app/views/e9_crm/deals/_footer.html.haml
|
263
259
|
- app/views/e9_crm/deals/_form_inner.html.haml
|
264
260
|
- app/views/e9_crm/deals/_header.html.haml
|
265
261
|
- app/views/e9_crm/deals/_leads_header.html.haml
|
@@ -272,7 +268,6 @@ files:
|
|
272
268
|
- app/views/e9_crm/deals/reports.html.haml
|
273
269
|
- app/views/e9_crm/deals/reports.js.erb
|
274
270
|
- app/views/e9_crm/email_campaigns/_form_inner.html.haml
|
275
|
-
- app/views/e9_crm/email_templates/_footer.html.haml
|
276
271
|
- app/views/e9_crm/email_templates/_form_inner.html.haml
|
277
272
|
- app/views/e9_crm/email_templates/_header.html.haml
|
278
273
|
- app/views/e9_crm/file_download_offers/_form.html.haml
|
@@ -280,12 +275,10 @@ files:
|
|
280
275
|
- app/views/e9_crm/leads/_form.html.haml
|
281
276
|
- app/views/e9_crm/leads/create.js.erb
|
282
277
|
- app/views/e9_crm/leads/new.html.haml
|
283
|
-
- app/views/e9_crm/menu_options/_footer.html.haml
|
284
278
|
- app/views/e9_crm/menu_options/_form_inner.html.haml
|
285
279
|
- app/views/e9_crm/menu_options/_header.html.haml
|
286
280
|
- app/views/e9_crm/new_content_subscription_offers/_form_inner.html.haml
|
287
281
|
- app/views/e9_crm/newsletter_subscription_offers/_form_inner.html.haml
|
288
|
-
- app/views/e9_crm/offers/_footer.html.haml
|
289
282
|
- app/views/e9_crm/offers/_form_inner.html.haml
|
290
283
|
- app/views/e9_crm/offers/_header.html.haml
|
291
284
|
- app/views/e9_crm/offers/_offer.html.haml
|
@@ -300,7 +293,6 @@ files:
|
|
300
293
|
- app/views/e9_crm/record_attributes/_templates.js.erb
|
301
294
|
- app/views/e9_crm/record_attributes/_user.html.haml
|
302
295
|
- app/views/e9_crm/record_attributes/_website_attribute.html.haml
|
303
|
-
- app/views/e9_crm/resources/_footer.html.haml
|
304
296
|
- app/views/e9_crm/resources/_form.html.haml
|
305
297
|
- app/views/e9_crm/resources/_form_inner.html.haml
|
306
298
|
- app/views/e9_crm/resources/_header.html.haml
|
File without changes
|
File without changes
|
@@ -1,31 +0,0 @@
|
|
1
|
-
%table.records
|
2
|
-
%thead
|
3
|
-
%tr
|
4
|
-
%th= orderable_column_link(:type)
|
5
|
-
%th= orderable_column_link(:name)
|
6
|
-
%th= orderable_column_link('campaign_group.name', :campaign_group)
|
7
|
-
%th= orderable_column_link(:new_visits)
|
8
|
-
%th= orderable_column_link(:repeat_visits)
|
9
|
-
%th= orderable_column_link(:deals_count)
|
10
|
-
%th= orderable_column_link(:won_deals_count)
|
11
|
-
%tbody
|
12
|
-
- if collection.empty?
|
13
|
-
%tr
|
14
|
-
%td{:colspan => 5}= e9_t(:no_records_text)
|
15
|
-
- else
|
16
|
-
- collection.each do |record|
|
17
|
-
%tr{:id => "ids_#{record.id}", :class => cycle('odd', 'even')}
|
18
|
-
%td.record-type
|
19
|
-
= record.type[/(.*)Campaign/, 1]
|
20
|
-
%td.record-name
|
21
|
-
= record.name
|
22
|
-
%td.record-campaign-group
|
23
|
-
= record.campaign_group || e9_t(:no_group, :scope => 'e9_crm.campaigns')
|
24
|
-
%td.record-new-visits
|
25
|
-
= record.new_visits
|
26
|
-
%td.record-repeat-visits
|
27
|
-
= record.repeat_visits
|
28
|
-
%td.record-deals-count
|
29
|
-
= record.deals_count
|
30
|
-
%td.record-won-deals-count
|
31
|
-
= record.won_deals_count
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -1 +0,0 @@
|
|
1
|
-
= will_paginate collection
|