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.
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