e9_crm 0.1.26 → 0.1.27

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/app/controllers/e9_crm/base_controller.rb +1 -1
  2. data/app/controllers/e9_crm/campaigns_controller.rb +1 -1
  3. data/app/controllers/e9_crm/leads_controller.rb +0 -1
  4. data/app/controllers/e9_crm/page_views_controller.rb +57 -8
  5. data/app/controllers/e9_crm/resources_controller.rb +1 -0
  6. data/app/controllers/e9_crm/visits_controller.rb +60 -0
  7. data/app/helpers/e9_crm/contacts_helper.rb +2 -9
  8. data/app/helpers/e9_crm/page_views_helper.rb +45 -0
  9. data/app/models/campaign.rb +23 -23
  10. data/app/models/contact.rb +17 -4
  11. data/app/models/page_view.rb +3 -20
  12. data/app/models/tracking_cookie.rb +16 -0
  13. data/app/views/e9_crm/affiliate_campaigns/_form_inner.html.haml +2 -1
  14. data/app/views/e9_crm/campaigns/_reports_table.html.haml +3 -3
  15. data/app/views/e9_crm/campaigns/_table.html.haml +1 -1
  16. data/app/views/e9_crm/campaigns/reports.js.erb +1 -1
  17. data/app/views/e9_crm/contacts/_sidebar_email_form.html.haml +7 -5
  18. data/app/views/e9_crm/contacts/index.html.haml +1 -1
  19. data/app/views/e9_crm/contacts/show.html.haml +1 -0
  20. data/app/views/e9_crm/dated_costs/index.html.haml +1 -3
  21. data/app/views/e9_crm/deals/_leads_table.html.haml +3 -0
  22. data/app/views/e9_crm/deals/_table.html.haml +3 -0
  23. data/app/views/e9_crm/deals/leads.js.erb +1 -1
  24. data/app/views/e9_crm/deals/show.html.haml +14 -5
  25. data/app/views/e9_crm/page_views/_header.html.haml +15 -0
  26. data/app/views/e9_crm/page_views/_table.html.haml +6 -6
  27. data/app/views/e9_crm/resources/index.html.haml +0 -3
  28. data/app/views/e9_crm/resources/index.js.erb +1 -1
  29. data/app/views/e9_crm/sales_campaigns/_form_inner.html.haml +2 -1
  30. data/app/views/e9_crm/visits/_header.html.haml +3 -0
  31. data/app/views/e9_crm/visits/_table.html.haml +27 -0
  32. data/config/locales/e9.en.yml +19 -12
  33. data/config/routes.rb +8 -16
  34. data/e9_crm.gemspec +0 -8
  35. data/lib/e9_crm/controller.rb +27 -12
  36. data/lib/e9_crm/model.rb +6 -5
  37. data/lib/e9_crm/rack/email_campaign_auto_completer.rb +29 -0
  38. data/lib/e9_crm/rails_extensions.rb +0 -33
  39. data/lib/e9_crm/tracking_controller.rb +3 -5
  40. data/lib/e9_crm/version.rb +1 -1
  41. data/lib/e9_crm.rb +7 -5
  42. metadata +48 -165
  43. data/app/controllers/e9_crm/email_templates.controller.rb +0 -46
  44. data/app/models/email_template.rb +0 -27
  45. data/app/views/e9_crm/email_templates/_form_inner.html.haml +0 -12
  46. data/app/views/e9_crm/email_templates/_header.html.haml +0 -7
  47. data/app/views/e9_crm/email_templates/select.html.haml +0 -5
  48. data/lib/e9_crm/email.rb +0 -18
@@ -1,3 +1,3 @@
1
1
  class E9Crm::BaseController < AdminController
2
- include E9Rails::Helpers::ResourceLinks
2
+ self.route_scope = nil
3
3
  end
@@ -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
- belongs_to :campaign, :contact, :polymorphic => true
4
- include E9Rails::Controllers::Orderable
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
- has_scope :until_time, :as => :until, :unless => 'params[:from].present?'
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
- has_scope :from_time, :as => :from do |controller, scope, value|
15
- if controller.params[:until]
16
- scope.for_time_range(value, controller.params[:until])
17
- else
18
- scope.from_time(value)
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 = EmailTemplate.order('name').map {|e| [e.name, e.id] }
73
- #select_tag 'etid', options_for_select( options.presence || [['n/a', nil]] )
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
@@ -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 repeat_visits,
62
- nv.count new_visits,
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
- .joins(
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
- .joins(
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
- .joins(
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
- .joins(
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
- .group('campaigns.id')
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
- %w(new_visits repeat_visits).each do |count_column|
115
- class_eval("def #{count_column}; (r = read_attribute(:#{count_column})) || 0 end")
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
- page_views.new_visits.group(:session).count.values.sum
123
+ new_visits.group(:session).count.values.sum
124
124
  end
125
125
 
126
- def repeat_visit_session_count
127
- page_views.repeat_visits.group(:session).count.keys.length
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
- page_views.repeat_visits.group(:session).count.values.sum
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
@@ -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
 
@@ -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
- #attr_accessor :should_cache
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
- %input.contact-autocomplete{:type => 'text'}
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
- $("table.records").replaceWith("<%= escape_javascript(render('reports_table', :collection => collection)) %>");
1
+ $("#records_table").html("<%= escape_javascript(render('reports_table', :collection => collection)) %>");
@@ -1,7 +1,9 @@
1
- - if (etag = contact_email_template_select_tag).present?
2
- %fieldset
3
- %legend= e9_t(:email_actions_legend)
4
- = form_tag new_contact_email_path, :method => :get, :id => 'contact_email_form', 'data-empty' => e9_t(:no_contacts_notification), 'data-count' => @contact_ids.length do
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
- = hidden_field_tag 'uids', @contact_ids.join(','), :id => 'contact_email_uids'
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
@@ -12,7 +12,7 @@
12
12
  .toolbar-right
13
13
  #sidebar-actions
14
14
  %fieldset
15
- %legend= "Manage"#e9_t(:search_options_legend)
15
+ %legend= "Manage"
16
16
  .manage-contacts
17
17
  = link_to_new_resource(Contact)
18
18
  .manage-company
@@ -8,6 +8,7 @@
8
8
 
9
9
  .contact-links.actions
10
10
  = link_to_edit_resource(resource)
11
+ = link_to "View Activity", page_views_url(:contact => resource.id)
11
12
  = google_search_link(resource.name)
12
13
  = google_news_link(resource.name)
13
14
 
@@ -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
@@ -40,3 +40,6 @@
40
40
  %td.record-totals.num
41
41
  = dat[:value].sum.to_money.format
42
42
  %td
43
+
44
+ - if controller.send(:should_paginate_index)
45
+ = will_paginate collection
@@ -1 +1 @@
1
- $("table.records").replaceWith("<%= escape_javascript(render('leads_table', :collection => collection)) %>");
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
- .contact-link= link_to(resource.owner.name, resource.owner)
22
- .contact-title= title_and_or_company(resource.owner)
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
- = t(:no_deal_owner)
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
- .contact-link= link_to(contact.name, contact)
32
- .contact-title= title_and_or_company(contact)
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(:referer)
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-referer
23
- = record.referer
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