e9_crm 0.1.26 → 0.1.27
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/base_controller.rb +1 -1
- data/app/controllers/e9_crm/campaigns_controller.rb +1 -1
- data/app/controllers/e9_crm/leads_controller.rb +0 -1
- data/app/controllers/e9_crm/page_views_controller.rb +57 -8
- data/app/controllers/e9_crm/resources_controller.rb +1 -0
- data/app/controllers/e9_crm/visits_controller.rb +60 -0
- data/app/helpers/e9_crm/contacts_helper.rb +2 -9
- data/app/helpers/e9_crm/page_views_helper.rb +45 -0
- data/app/models/campaign.rb +23 -23
- data/app/models/contact.rb +17 -4
- data/app/models/page_view.rb +3 -20
- data/app/models/tracking_cookie.rb +16 -0
- data/app/views/e9_crm/affiliate_campaigns/_form_inner.html.haml +2 -1
- data/app/views/e9_crm/campaigns/_reports_table.html.haml +3 -3
- data/app/views/e9_crm/campaigns/_table.html.haml +1 -1
- data/app/views/e9_crm/campaigns/reports.js.erb +1 -1
- data/app/views/e9_crm/contacts/_sidebar_email_form.html.haml +7 -5
- data/app/views/e9_crm/contacts/index.html.haml +1 -1
- data/app/views/e9_crm/contacts/show.html.haml +1 -0
- data/app/views/e9_crm/dated_costs/index.html.haml +1 -3
- data/app/views/e9_crm/deals/_leads_table.html.haml +3 -0
- data/app/views/e9_crm/deals/_table.html.haml +3 -0
- data/app/views/e9_crm/deals/leads.js.erb +1 -1
- data/app/views/e9_crm/deals/show.html.haml +14 -5
- data/app/views/e9_crm/page_views/_header.html.haml +15 -0
- data/app/views/e9_crm/page_views/_table.html.haml +6 -6
- data/app/views/e9_crm/resources/index.html.haml +0 -3
- data/app/views/e9_crm/resources/index.js.erb +1 -1
- data/app/views/e9_crm/sales_campaigns/_form_inner.html.haml +2 -1
- data/app/views/e9_crm/visits/_header.html.haml +3 -0
- data/app/views/e9_crm/visits/_table.html.haml +27 -0
- data/config/locales/e9.en.yml +19 -12
- data/config/routes.rb +8 -16
- data/e9_crm.gemspec +0 -8
- data/lib/e9_crm/controller.rb +27 -12
- data/lib/e9_crm/model.rb +6 -5
- data/lib/e9_crm/rack/email_campaign_auto_completer.rb +29 -0
- data/lib/e9_crm/rails_extensions.rb +0 -33
- data/lib/e9_crm/tracking_controller.rb +3 -5
- data/lib/e9_crm/version.rb +1 -1
- data/lib/e9_crm.rb +7 -5
- metadata +48 -165
- data/app/controllers/e9_crm/email_templates.controller.rb +0 -46
- data/app/models/email_template.rb +0 -27
- data/app/views/e9_crm/email_templates/_form_inner.html.haml +0 -12
- data/app/views/e9_crm/email_templates/_header.html.haml +0 -7
- data/app/views/e9_crm/email_templates/select.html.haml +0 -5
- data/lib/e9_crm/email.rb +0 -18
@@ -32,7 +32,7 @@ class E9Crm::CampaignsController < E9Crm::ResourcesController
|
|
32
32
|
|
33
33
|
has_scope :of_group, :as => :group, :only => :reports
|
34
34
|
|
35
|
-
has_scope :type, :only => :reports do |_, scope, value|
|
35
|
+
has_scope :type, :only => [:reports, :index] do |_, scope, value|
|
36
36
|
scope.of_type("#{value}_campaign".classify)
|
37
37
|
end
|
38
38
|
|
@@ -3,7 +3,6 @@ class E9Crm::LeadsController < ApplicationController
|
|
3
3
|
# rather it handles only public side lead creation
|
4
4
|
|
5
5
|
# TODO these should all be included in e9_base
|
6
|
-
include E9Rails::Helpers::ResourceLinks
|
7
6
|
include E9Rails::Helpers::Title
|
8
7
|
include E9Rails::Helpers::Translation
|
9
8
|
include E9Rails::Helpers::ResourceErrorMessages
|
@@ -1,7 +1,8 @@
|
|
1
1
|
class E9Crm::PageViewsController < E9Crm::ResourcesController
|
2
2
|
defaults :resource_class => PageView
|
3
|
-
|
4
|
-
|
3
|
+
include E9::Controllers::Orderable
|
4
|
+
|
5
|
+
actions :index
|
5
6
|
|
6
7
|
# NOTE association chain is prepended to ensure parent is loaded so other
|
7
8
|
# before filters can use collection_path, etc. Is there a better solution
|
@@ -9,13 +10,61 @@ class E9Crm::PageViewsController < E9Crm::ResourcesController
|
|
9
10
|
#
|
10
11
|
prepend_before_filter :association_chain
|
11
12
|
|
12
|
-
|
13
|
+
before_filter :find_contact
|
14
|
+
|
15
|
+
has_scope :campaign, :only => :index do |_, scope, value|
|
16
|
+
scope.where(:campaign_id => value)
|
17
|
+
end
|
18
|
+
|
19
|
+
has_scope :contact, :only => :index do |_, scope, value|
|
20
|
+
scope.joins(:user => :contact).merge(Contact.where(:id => value))
|
21
|
+
end
|
22
|
+
|
23
|
+
has_scope :new_visits, :only => :index, do |_, scope, value|
|
24
|
+
scope.new_visits(E9.true_value?(value))
|
25
|
+
end
|
26
|
+
|
27
|
+
has_scope :month, :only => :index do |controller, scope, value|
|
28
|
+
scope.for_time_range(value, :in => :month)
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
13
32
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
33
|
+
def collection_scope
|
34
|
+
scope = end_of_association_chain
|
35
|
+
|
36
|
+
unless params[:contact]
|
37
|
+
join_sql = <<-SQL
|
38
|
+
LEFT OUTER JOIN tracking_cookies
|
39
|
+
ON tracking_cookies.id = page_views.tracking_cookie_id
|
40
|
+
LEFT OUTER JOIN users
|
41
|
+
ON users.id = tracking_cookies.user_id
|
42
|
+
LEFT OUTER JOIN contacts
|
43
|
+
ON contacts.id = users.contact_id
|
44
|
+
SQL
|
45
|
+
|
46
|
+
scope = scope.joins(join_sql)
|
47
|
+
end
|
48
|
+
|
49
|
+
sel_sql = <<-SQL
|
50
|
+
page_views.*,
|
51
|
+
IF(contacts.id,CONCAT_WS(' ', contacts.first_name, contacts.last_name),'(Unknown)') contact_name,
|
52
|
+
contacts.id as contact_id
|
53
|
+
SQL
|
54
|
+
|
55
|
+
scope.select(sel_sql)
|
56
|
+
end
|
57
|
+
|
58
|
+
def collection
|
59
|
+
get_collection_ivar || begin
|
60
|
+
total_entries = collection_scope.except(:order).count
|
61
|
+
objects = collection_scope.includes(:campaign).paginate(pagination_parameters.merge(:total_entries => total_entries))
|
62
|
+
|
63
|
+
set_collection_ivar objects
|
19
64
|
end
|
20
65
|
end
|
66
|
+
|
67
|
+
def find_contact
|
68
|
+
@contact ||= params[:contact] && Contact.find_by_id(params[:contact])
|
69
|
+
end
|
21
70
|
end
|
@@ -2,6 +2,7 @@ class E9Crm::ResourcesController < E9Crm::BaseController
|
|
2
2
|
inherit_resources
|
3
3
|
|
4
4
|
include E9Rails::Helpers::ResourceErrorMessages
|
5
|
+
include E9::Controllers::InheritableViews
|
5
6
|
|
6
7
|
# NOTE depending on e9_base pagination (which should eventually use this module)
|
7
8
|
#include E9Rails::Helpers::Pagination
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class E9Crm::VisitsController < E9Crm::ResourcesController
|
2
|
+
defaults :resource_class => PageView, :collection_name => :page_views
|
3
|
+
belongs_to :campaign
|
4
|
+
include E9::Controllers::Orderable
|
5
|
+
|
6
|
+
actions :index
|
7
|
+
|
8
|
+
# NOTE association chain is prepended to ensure parent is loaded so other
|
9
|
+
# before filters can use collection_path, etc. Is there a better solution
|
10
|
+
# for this?
|
11
|
+
#
|
12
|
+
prepend_before_filter :association_chain
|
13
|
+
|
14
|
+
before_filter :determine_title, :only => :index
|
15
|
+
|
16
|
+
has_scope :visits, :default => 'true' do |_, scope, _|
|
17
|
+
sel_sql = <<-SQL
|
18
|
+
page_views.*,
|
19
|
+
IF(contacts.id,CONCAT_WS(' ', contacts.first_name, contacts.last_name),'(Unknown)') contact_name,
|
20
|
+
contacts.id as contact_id,
|
21
|
+
count(distinct(if(page_views.new_visit=1,IFNULL(page_views.session,1),null))) as new_visits,
|
22
|
+
count(distinct(if(page_views.new_visit=1,null,IFNULL(page_views.session,1)))) as repeat_visits
|
23
|
+
SQL
|
24
|
+
|
25
|
+
join_sql = <<-SQL
|
26
|
+
LEFT OUTER JOIN tracking_cookies
|
27
|
+
ON tracking_cookies.id = page_views.tracking_cookie_id
|
28
|
+
LEFT OUTER JOIN users
|
29
|
+
ON users.id = tracking_cookies.user_id
|
30
|
+
LEFT OUTER JOIN contacts
|
31
|
+
ON contacts.id = users.contact_id
|
32
|
+
SQL
|
33
|
+
|
34
|
+
scope.select(sel_sql).joins(join_sql).group('contact_id')
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
def collection
|
40
|
+
get_collection_ivar || begin
|
41
|
+
set_collection_ivar end_of_association_chain.paginate(pagination_parameters)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def default_ordered_dir
|
46
|
+
'ASC'
|
47
|
+
end
|
48
|
+
|
49
|
+
def default_ordered_on
|
50
|
+
'contact_name'
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_index_breadcrumb
|
54
|
+
add_breadcrumb! e9_t(:breadcrumb_title)
|
55
|
+
end
|
56
|
+
|
57
|
+
def determine_title
|
58
|
+
@index_title = e9_t(:index_title, :parent => parent.name)
|
59
|
+
end
|
60
|
+
end
|
@@ -62,16 +62,9 @@ module E9Crm::ContactsHelper
|
|
62
62
|
tags.map {|tag| link_to_contact_search(:tagged, [tag], tag) }.join(', ').html_safe
|
63
63
|
end
|
64
64
|
|
65
|
-
def contact_newsletter_select_tag
|
66
|
-
options = UserEmail.pending.order('name').map {|e| [e.name, e.id] }
|
67
|
-
#select_tag 'eid', options_for_select( options.presence || [['n/a', nil]] )
|
68
|
-
select_tag 'eid', options_for_select(options) if options.present?
|
69
|
-
end
|
70
|
-
|
71
65
|
def contact_email_template_select_tag
|
72
|
-
options =
|
73
|
-
|
74
|
-
select_tag 'etid', options_for_select(options) if options.present?
|
66
|
+
options = UserEmail.bulk_sendable.order('name').map {|e| [e.name, e.id] }
|
67
|
+
select_tag 'email_id', options_for_select(options) if options.present?
|
75
68
|
end
|
76
69
|
|
77
70
|
def contact_user_subscribed_to_newsletter?(user)
|
@@ -1,2 +1,47 @@
|
|
1
1
|
module E9Crm::PageViewsHelper
|
2
|
+
def page_view_campaign_select_options
|
3
|
+
@_page_view_campaign_select_options ||= begin
|
4
|
+
opts = Campaign.all.map {|campaign| [campaign.name, campaign.id] }
|
5
|
+
opts.unshift ['Any', nil]
|
6
|
+
options_for_select(opts)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def page_view_new_visit_select_options
|
11
|
+
options_for_select([
|
12
|
+
['Any', nil],
|
13
|
+
['New Visits', true],
|
14
|
+
['Repeat Visits', false]
|
15
|
+
])
|
16
|
+
end
|
17
|
+
|
18
|
+
def page_view_date_select_options(options = {})
|
19
|
+
@_first_date ||= PageView.order(:created_at).first.try(:created_at) || Date.today
|
20
|
+
|
21
|
+
date, cdate = @_first_date, Date.today
|
22
|
+
|
23
|
+
sel_options = []
|
24
|
+
|
25
|
+
if options[:type] == :until
|
26
|
+
prefix = 'Up to '
|
27
|
+
label = prefix + ' Now'
|
28
|
+
elsif options[:type] == :in_month
|
29
|
+
prefix = 'Closed in '
|
30
|
+
label = 'Since Inception'
|
31
|
+
else
|
32
|
+
prefix = 'Since '
|
33
|
+
label = prefix + ' Inception'
|
34
|
+
end
|
35
|
+
|
36
|
+
begin
|
37
|
+
sel_options << [date.strftime("#{prefix}%B %Y"), date.strftime('%Y/%m')]
|
38
|
+
date += 1.month
|
39
|
+
end while date.year <= cdate.year && date.month <= cdate.month
|
40
|
+
|
41
|
+
sel_options.reverse!
|
42
|
+
|
43
|
+
sel_options.unshift([label, nil])
|
44
|
+
|
45
|
+
options_for_select(sel_options)
|
46
|
+
end
|
2
47
|
end
|
data/app/models/campaign.rb
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
#
|
6
6
|
class Campaign < ActiveRecord::Base
|
7
7
|
include E9Rails::ActiveRecord::STI
|
8
|
+
include E9::ActiveRecord::AttributeSearchable
|
8
9
|
|
9
10
|
belongs_to :campaign_group
|
10
11
|
|
@@ -14,7 +15,10 @@ class Campaign < ActiveRecord::Base
|
|
14
15
|
has_many :pending_deals, :class_name => 'Deal', :conditions => ['deals.status = ?', Deal::Status::Pending]
|
15
16
|
has_many :leads, :class_name => 'Deal', :conditions => ['deals.status = ?', Deal::Status::Lead]
|
16
17
|
has_many :non_leads, :class_name => 'Deal', :conditions => ['deals.status != ?', Deal::Status::Lead]
|
18
|
+
|
17
19
|
has_many :page_views, :inverse_of => :campaign, :dependent => :nullify
|
20
|
+
has_many :new_page_views, :class_name => 'PageView', :conditions => ['page_views.new_visit = ?', true]
|
21
|
+
has_many :repeat_page_views, :class_name => 'PageView', :conditions => ['page_views.new_visit = ?', false]
|
18
22
|
|
19
23
|
# only advertising campaigns use this association
|
20
24
|
has_many :dated_costs, :as => :costable
|
@@ -58,8 +62,8 @@ class Campaign < ActiveRecord::Base
|
|
58
62
|
SUM(costs.total) /
|
59
63
|
SUM(IF(deals.status='won',1,0)) average_cost,
|
60
64
|
|
61
|
-
rv.count
|
62
|
-
nv.count
|
65
|
+
IFNULL(rv.count, 0) repeat_visits,
|
66
|
+
IFNULL(nv.count, 0) new_visits,
|
63
67
|
|
64
68
|
SUM(DATEDIFF(
|
65
69
|
deals.closed_at,
|
@@ -70,36 +74,36 @@ class Campaign < ActiveRecord::Base
|
|
70
74
|
deals.created_at)) average_elapsed
|
71
75
|
SQL
|
72
76
|
|
73
|
-
select(selects)
|
74
|
-
|
77
|
+
select(selects).
|
78
|
+
joins(
|
75
79
|
'LEFT OUTER JOIN deals ' +
|
76
80
|
'ON deals.campaign_id = campaigns.id ' +
|
77
|
-
"#{ 'AND ' + Deal.for_time_range_conditions(*args, options).to_sql if args.present?}")
|
78
|
-
|
81
|
+
"#{ 'AND ' + Deal.for_time_range_conditions(*args, options).to_sql if args.present?}").
|
82
|
+
joins(
|
79
83
|
'LEFT OUTER JOIN ( ' +
|
80
84
|
'SELECT SUM(cost) total, costable_id dc_cid ' +
|
81
85
|
'FROM dated_costs ' +
|
82
86
|
'WHERE costable_type="Campaign" ' +
|
83
87
|
"#{ 'AND ' + DatedCost.for_time_range_conditions(*args, options).to_sql if args.present?}" +
|
84
88
|
' GROUP BY dc_cid) costs ' +
|
85
|
-
'ON costs.dc_cid = campaigns.id')
|
86
|
-
|
89
|
+
'ON costs.dc_cid = campaigns.id').
|
90
|
+
joins(
|
87
91
|
'LEFT OUTER JOIN ( ' +
|
88
92
|
'SELECT COUNT(DISTINCT session) count, campaign_id nv_cid ' +
|
89
93
|
'FROM page_views ' +
|
90
94
|
'WHERE page_views.new_visit = 1 ' +
|
91
95
|
"#{ 'AND ' + PageView.for_time_range_conditions(*args, options).to_sql if args.present?}" +
|
92
96
|
' GROUP BY nv_cid ) nv ' +
|
93
|
-
'ON nv.nv_cid = campaigns.id')
|
94
|
-
|
97
|
+
'ON nv.nv_cid = campaigns.id').
|
98
|
+
joins(
|
95
99
|
'LEFT OUTER JOIN ( ' +
|
96
100
|
'SELECT COUNT(DISTINCT session) count, campaign_id rv_cid ' +
|
97
101
|
'FROM page_views ' +
|
98
102
|
'WHERE page_views.new_visit = 0 ' +
|
99
103
|
"#{ 'AND ' + PageView.for_time_range_conditions(*args, options).to_sql if args.present?}" +
|
100
104
|
' GROUP BY rv_cid ) rv ' +
|
101
|
-
'ON rv.rv_cid = campaigns.id')
|
102
|
-
|
105
|
+
'ON rv.rv_cid = campaigns.id').
|
106
|
+
group('campaigns.id')
|
103
107
|
}
|
104
108
|
|
105
109
|
def self.default
|
@@ -111,24 +115,20 @@ class Campaign < ActiveRecord::Base
|
|
111
115
|
class_eval("def #{money_column}; (r = read_attribute(:#{money_column})) && Money.new(r) end")
|
112
116
|
end
|
113
117
|
|
114
|
-
|
115
|
-
|
116
|
-
end
|
117
|
-
|
118
|
-
def new_visit_session_count
|
119
|
-
page_views.new_visits.group(:session).count.keys.length
|
118
|
+
def new_visit_count
|
119
|
+
new_visits.group(:session).count.keys.length
|
120
120
|
end
|
121
121
|
|
122
122
|
def new_visit_page_view_count
|
123
|
-
|
123
|
+
new_visits.group(:session).count.values.sum
|
124
124
|
end
|
125
125
|
|
126
|
-
def
|
127
|
-
|
126
|
+
def repeat_visit_count
|
127
|
+
repeat_visits.group(:session).count.keys.length
|
128
128
|
end
|
129
129
|
|
130
130
|
def repeat_visit_page_view_count
|
131
|
-
|
131
|
+
repeat_visits.group(:session).count.values.sum
|
132
132
|
end
|
133
133
|
|
134
134
|
##
|
@@ -140,7 +140,7 @@ class Campaign < ActiveRecord::Base
|
|
140
140
|
end
|
141
141
|
|
142
142
|
def to_s
|
143
|
-
name.tap {|n| n << " (#{code})" if code.present? }
|
143
|
+
name.dup.tap {|n| n << " (#{code})" if code.present? }
|
144
144
|
end
|
145
145
|
|
146
146
|
def to_liquid
|
data/app/models/contact.rb
CHANGED
@@ -18,6 +18,13 @@ class Contact < ActiveRecord::Base
|
|
18
18
|
has_many :owned_deals, :class_name => 'Deal', :dependent => :restrict
|
19
19
|
has_and_belongs_to_many :associated_deals, :class_name => 'Deal'
|
20
20
|
|
21
|
+
has_many :campaigns_as_salesperson, :class_name => "SalesCampaign", :inverse_of => :sales_person, :foreign_key => 'sales_person_id'
|
22
|
+
has_many :campaigns_as_affiliate, :class_name => "AffiliateCampaign", :inverse_of => :affiliate, :foreign_key => 'affiliate_id'
|
23
|
+
|
24
|
+
def page_views
|
25
|
+
PageView.by_users(user_ids)
|
26
|
+
end
|
27
|
+
|
21
28
|
has_many :users, :inverse_of => :contact do
|
22
29
|
|
23
30
|
##
|
@@ -91,10 +98,6 @@ class Contact < ActiveRecord::Base
|
|
91
98
|
|
92
99
|
delegate :email, :to => :primary_user, :allow_nil => true
|
93
100
|
|
94
|
-
def page_views
|
95
|
-
PageView.by_user(users)
|
96
|
-
end
|
97
|
-
|
98
101
|
has_record_attributes :users,
|
99
102
|
:phone_number_attributes,
|
100
103
|
:instant_messaging_handle_attributes,
|
@@ -204,6 +207,12 @@ class Contact < ActiveRecord::Base
|
|
204
207
|
end
|
205
208
|
delegate :name, :to => :company, :prefix => true, :allow_nil => true
|
206
209
|
|
210
|
+
def name_with_email
|
211
|
+
retv = name.dup
|
212
|
+
retv << " (#{email})" if email.present?
|
213
|
+
retv
|
214
|
+
end
|
215
|
+
|
207
216
|
##
|
208
217
|
# Helper to concatenate a Contact's full name
|
209
218
|
#
|
@@ -232,7 +241,10 @@ class Contact < ActiveRecord::Base
|
|
232
241
|
|
233
242
|
def merge_destructive_and_destroy!(other)
|
234
243
|
other.users.clear_primary!
|
244
|
+
self.owned_deals |= other.owned_deals
|
235
245
|
self.associated_deals |= other.associated_deals
|
246
|
+
self.campaigns_as_salesperson |= other.campaigns_as_salesperson
|
247
|
+
self.campaigns_as_affiliate |= other.campaigns_as_affiliate
|
236
248
|
self.users |= other.users
|
237
249
|
self.website_attributes |= other.website_attributes
|
238
250
|
self.address_attributes |= other.address_attributes
|
@@ -240,6 +252,7 @@ class Contact < ActiveRecord::Base
|
|
240
252
|
self.instant_messaging_handle_attributes |= other.instant_messaging_handle_attributes
|
241
253
|
|
242
254
|
other.associated_deals.clear
|
255
|
+
other.reload
|
243
256
|
other.destroy
|
244
257
|
end
|
245
258
|
|
data/app/models/page_view.rb
CHANGED
@@ -21,30 +21,13 @@ class PageView < ActiveRecord::Base
|
|
21
21
|
belongs_to :campaign, :inverse_of => :page_views
|
22
22
|
has_one :user, :through => :tracking_cookie
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
#after_create :increment_campaign_visit_cache, :if => '!!should_cache'
|
27
|
-
|
28
|
-
scope :by_user, lambda {|*users|
|
29
|
-
users.flatten!
|
30
|
-
users.map! &:to_param
|
31
|
-
joins(:tracking_cookie).where(TrackingCookie.arel_table[:user_id].send *(users.length == 1 ? [:eq, users.pop] : [:in, users]))
|
32
|
-
}
|
33
|
-
|
34
|
-
scope :by_campaign, lambda {|*campaigns|
|
35
|
-
campaigns.flatten!
|
36
|
-
campaigns.map! &:to_param
|
37
|
-
where(arel_table[:campaign_id].send *(campaigns.length == 1 ? [:eq, campaigns.pop] : [:in, campaigns]))
|
24
|
+
scope :by_users, lambda {|*users|
|
25
|
+
joins(:tracking_cookie) & TrackingCookie.for_users(users)
|
38
26
|
}
|
39
27
|
|
40
28
|
scope :new_visits, lambda {|v=true| where(:new_visit => v) }
|
41
29
|
scope :repeat_visits, lambda { new_visits(false) }
|
42
30
|
|
43
31
|
delegate :name, :code, :to => :campaign, :prefix => true, :allow_nil => true
|
44
|
-
|
45
|
-
protected
|
46
|
-
|
47
|
-
#def increment_campaign_visit_cache
|
48
|
-
#Campaign.increment_counter(new_visit ? :new_visits : :repeat_visits, campaign_id)
|
49
|
-
#end
|
32
|
+
delegate :contact, :to => :user, :allow_nil => true
|
50
33
|
end
|
@@ -45,6 +45,22 @@ class TrackingCookie < ActiveRecord::Base
|
|
45
45
|
has_many :page_views
|
46
46
|
after_save :generate_hid, :on => :create
|
47
47
|
|
48
|
+
scope :for_users, lambda {|*users|
|
49
|
+
users.flatten!
|
50
|
+
users.map!(&:to_param)
|
51
|
+
users.compact!
|
52
|
+
|
53
|
+
if users.length == 1
|
54
|
+
where arel_table[:user_id].eq(users.first)
|
55
|
+
else
|
56
|
+
where arel_table[:user_id].in(users)
|
57
|
+
end
|
58
|
+
}
|
59
|
+
|
60
|
+
scope :for_user, lambda {|user|
|
61
|
+
where arel_table[:user_id].in(users.flatten.map(&:to_param))
|
62
|
+
}
|
63
|
+
|
48
64
|
protected
|
49
65
|
|
50
66
|
def generate_hid
|
@@ -4,8 +4,9 @@
|
|
4
4
|
%legend= e9_t(:affiliate_information_legend, :scope => 'e9_crm.campaigns')
|
5
5
|
.field
|
6
6
|
= f.label :affiliate, :class => :req, :for => 'campaign_affiliate_id'
|
7
|
-
|
7
|
+
|
8
8
|
- contact = f.object.affiliate
|
9
|
+
%input.contact-autocomplete{:type => 'text', :style => contact.blank? && '' || 'display:none'}
|
9
10
|
.contact-select{:style => contact.blank? && 'display:none' || ''}
|
10
11
|
%span.content= contact.try(:name)
|
11
12
|
%input{:type => :hidden, :name => "#{resource_instance_name}[affiliate_id]", :value => contact.try(:id)}
|
@@ -83,13 +83,13 @@
|
|
83
83
|
- total_value = dat[:total_value].compact.sum
|
84
84
|
= m(total_value)
|
85
85
|
%td.record-average-value.num
|
86
|
-
= m(total_value.to_f / won_deal_count)
|
86
|
+
= won_deal_count.zero? ? 'n/a' : m(total_value.to_f / won_deal_count)
|
87
87
|
%td.record-total-cost.num
|
88
88
|
- total_cost = dat[:total_cost].compact.sum
|
89
89
|
= m(total_cost)
|
90
90
|
%td.record-average-cost.num
|
91
|
-
= m(total_cost.to_f / won_deal_count)
|
91
|
+
= won_deal_count.zero? ? 'n/a' : m(total_cost.to_f / won_deal_count)
|
92
92
|
%td.record-average-elapsed.num
|
93
93
|
- total_elapsed = dat[:total_elapsed].compact.sum.to_f
|
94
94
|
- closed_deal_count = dat[:closed_deal_count].sum.to_i
|
95
|
-
= "%i days" % (total_elapsed / closed_deal_count)
|
95
|
+
= closed_deal_count.zero? ? 'n/a' : "%i days" % (total_elapsed / closed_deal_count)
|
@@ -20,7 +20,7 @@
|
|
20
20
|
%td.record-campaign-group
|
21
21
|
= record.campaign_group_name || e9_t(:no_group, :scope => 'e9_crm.campaigns')
|
22
22
|
%td.record-name
|
23
|
-
= record.name
|
23
|
+
= link_to record.name, campaign_visits_path(record), :title => 'View Campaign Activity'
|
24
24
|
%td.record-code
|
25
25
|
= display_campaign_code(record.code)
|
26
26
|
%td.record-affiliate-fee.num
|
@@ -1 +1 @@
|
|
1
|
-
$("
|
1
|
+
$("#records_table").html("<%= escape_javascript(render('reports_table', :collection => collection)) %>");
|
@@ -1,7 +1,9 @@
|
|
1
|
-
|
2
|
-
%
|
3
|
-
|
4
|
-
=
|
1
|
+
%fieldset
|
2
|
+
%legend= e9_t(:email_actions_legend)
|
3
|
+
- if (etag = contact_email_template_select_tag).present?
|
4
|
+
= form_for EmailDelivery.new(:contact_ids => @contact_ids), :url => new_admin_email_delivery_path, :html => { :method => :get, :id => 'contact_email_form', 'data-empty' => e9_t(:no_contacts_notification), 'data-count' => @contact_ids.length } do |f|
|
5
5
|
= etag
|
6
|
-
=
|
6
|
+
= f.hidden_field :contact_ids, :id => 'contact_email_uids'
|
7
7
|
= submit_tag e9_t(:send_email_template), :name => nil
|
8
|
+
- else
|
9
|
+
= I18n.t(:no_email_templates).html_safe
|
@@ -1,7 +1,6 @@
|
|
1
1
|
= title @index_title || e9_t(:index_title)
|
2
|
+
|
2
3
|
.toolbar
|
3
|
-
.toolbar-left
|
4
|
-
.toolbar-middle
|
5
4
|
.toolbar-right
|
6
5
|
= link_to_new_resource(resource_class, :class => 'new-resource')
|
7
6
|
|
@@ -19,4 +18,3 @@
|
|
19
18
|
%td{:colspan => 7}= e9_t(:no_records_text)
|
20
19
|
- else
|
21
20
|
= render collection
|
22
|
-
|
@@ -32,3 +32,6 @@
|
|
32
32
|
= link_to 'View Contact', 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.send(:should_paginate_index)
|
37
|
+
= will_paginate collection
|
@@ -1 +1 @@
|
|
1
|
-
$("
|
1
|
+
$("#records_table").html("<%= escape_javascript(render('leads_table', :collection => collection)) %>");
|
@@ -18,15 +18,24 @@
|
|
18
18
|
%legend= t(:deal_owner_legend)
|
19
19
|
.deal-contact
|
20
20
|
- if resource.owner
|
21
|
-
|
22
|
-
|
21
|
+
= link_to resource.owner do
|
22
|
+
.contact-photo
|
23
|
+
%img{:src => resource.owner.avatar_url, :alt => "Photo for #{resource.owner.name}"}
|
24
|
+
.contact-name= resource.owner.name
|
25
|
+
.contact-title= title_and_or_company(resource.owner)
|
23
26
|
- else
|
24
|
-
|
27
|
+
.contact-photo
|
28
|
+
%img{:src => User.new.avatar_url, :alt => "Default Contact Photo"}
|
29
|
+
.contact-name
|
30
|
+
= t(:no_deal_owner)
|
25
31
|
|
26
32
|
- if resource.contacts.any?
|
27
33
|
%fieldset.deal-contacts
|
28
34
|
%legend= t(:deal_contact_legend)
|
29
35
|
- resource.contacts.each do |contact|
|
30
36
|
.deal-contact
|
31
|
-
|
32
|
-
|
37
|
+
= link_to contact do
|
38
|
+
.contact-photo
|
39
|
+
%img{:src => contact.avatar_url, :alt => "Photo for #{contact.name}"}
|
40
|
+
.contact-name= contact.name
|
41
|
+
.contact-title= title_and_or_company(contact)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
.toolbar
|
2
|
+
.toolbar-left
|
3
|
+
= form_tag(resource_class, :method => :get, :class => 'scope-selects') do
|
4
|
+
%select{:name => 'campaign'}
|
5
|
+
= page_view_campaign_select_options
|
6
|
+
%select{:name => 'new_visits'}
|
7
|
+
= page_view_new_visit_select_options
|
8
|
+
%select{:name => 'month'}
|
9
|
+
= page_view_date_select_options(:type => :in_month)
|
10
|
+
|
11
|
+
%input.contact-autocomplete{:type => :text, :style => @contact.blank? && '' || 'display:none', :placeholder => 'Enter Contact...'}
|
12
|
+
.contact-select{:style => @contact.blank? && 'display:none' || ''}
|
13
|
+
%span.content= @contact.try(:name_with_email)
|
14
|
+
%input{:type => :hidden, :name => "contact", :value => @contact.try(:id)}
|
15
|
+
%a{:class => :remove, :title => "Remove", :alt => "Remove"} Remove
|
@@ -3,9 +3,9 @@
|
|
3
3
|
%tr
|
4
4
|
%th= orderable_column_link(:created_at)
|
5
5
|
%th= orderable_column_link('campaign.name', :campaign)
|
6
|
+
%th= orderable_column_link(:new_visit)
|
6
7
|
%th= orderable_column_link(:request_path)
|
7
|
-
%th= orderable_column_link(:
|
8
|
-
%th= orderable_column_link(:remote_ip)
|
8
|
+
%th= orderable_column_link('contact_name', :contact)
|
9
9
|
%tbody
|
10
10
|
- if collection.empty?
|
11
11
|
%tr
|
@@ -17,12 +17,12 @@
|
|
17
17
|
= I18n.l(record.created_at)
|
18
18
|
%td.record-campaign-name
|
19
19
|
= record.campaign_name || e9_t(:no_campaign)
|
20
|
+
%td.record-request-new-visit
|
21
|
+
= record.new_visit ? 'New Visit' : 'Repeat Visit'
|
20
22
|
%td.record-request-path
|
21
23
|
= record.request_path
|
22
|
-
%td.record-
|
23
|
-
= record.
|
24
|
-
%td.record-remote-ip
|
25
|
-
= record.remote_ip
|
24
|
+
%td.record-contact-name
|
25
|
+
= record.contact_name
|
26
26
|
|
27
27
|
- if controller.send(:should_paginate_index)
|
28
28
|
= will_paginate collection
|