e9_crm 0.1.10 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|