e9_crm 0.1.21 → 0.1.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/app/controllers/e9_crm/campaigns_controller.rb +60 -17
  2. data/app/controllers/e9_crm/contacts_controller.rb +5 -0
  3. data/app/controllers/e9_crm/deals_controller.rb +14 -36
  4. data/app/controllers/e9_crm/offers_controller.rb +2 -2
  5. data/app/controllers/e9_crm/resources_controller.rb +4 -0
  6. data/app/helpers/e9_crm/campaigns_helper.rb +14 -3
  7. data/app/helpers/e9_crm/deals_helper.rb +17 -18
  8. data/app/models/campaign.rb +74 -6
  9. data/app/models/contact.rb +16 -1
  10. data/app/models/dated_cost.rb +1 -0
  11. data/app/models/deal.rb +8 -58
  12. data/app/models/no_campaign.rb +1 -1
  13. data/app/models/page_view.rb +6 -5
  14. data/app/views/e9_crm/affiliate_campaigns/_form_inner.html.haml +7 -1
  15. data/app/views/e9_crm/{deals → campaigns}/_reports_table.html.haml +7 -5
  16. data/app/views/e9_crm/campaigns/_table.html.haml +1 -1
  17. data/app/views/e9_crm/campaigns/reports.html.haml +17 -9
  18. data/app/views/e9_crm/{deals → campaigns}/reports.js.erb +0 -0
  19. data/app/views/e9_crm/contacts/_form_inner.html.haml +0 -3
  20. data/app/views/e9_crm/contacts/_table.html.haml +1 -1
  21. data/app/views/e9_crm/contacts/edit.html.haml +6 -0
  22. data/app/views/e9_crm/contacts/show.html.haml +3 -3
  23. data/app/views/e9_crm/deals/_form_inner.html.haml +1 -17
  24. data/app/views/e9_crm/deals/_header.html.haml +2 -0
  25. data/app/views/e9_crm/deals/_leads_header.html.haml +1 -1
  26. data/app/views/e9_crm/deals/_leads_table.html.haml +1 -1
  27. data/app/views/e9_crm/deals/_table.html.haml +1 -1
  28. data/app/views/e9_crm/deals/show.html.haml +23 -4
  29. data/app/views/e9_crm/leads/_form.html.haml +5 -5
  30. data/app/views/e9_crm/offers/_form_inner.html.haml +0 -1
  31. data/app/views/e9_crm/page_views/_table.html.haml +1 -1
  32. data/app/views/e9_crm/resources/_table.html.haml +1 -1
  33. data/app/views/e9_crm/resources/index.html.haml +1 -1
  34. data/app/views/e9_crm/sales_campaigns/_form_inner.html.haml +8 -2
  35. data/app/views/record_attributes/_user.html.haml +2 -2
  36. data/config/locales/e9.en.yml +2 -0
  37. data/config/locales/en.yml +5 -0
  38. data/config/routes.rb +1 -1
  39. data/lib/e9_crm/controller.rb +2 -2
  40. data/lib/e9_crm/rack/contact_auto_completer.rb +2 -2
  41. data/lib/e9_crm/tracking_controller.rb +2 -29
  42. data/lib/e9_crm/version.rb +1 -1
  43. metadata +5 -5
  44. data/app/views/e9_crm/deals/reports.html.haml +0 -19
@@ -2,43 +2,86 @@ class E9Crm::CampaignsController < E9Crm::ResourcesController
2
2
  defaults :resource_class => Campaign
3
3
  include E9Rails::Controllers::Orderable
4
4
 
5
+ helper :"e9_crm/deals"
6
+
5
7
  before_filter :redirect_new_to_subclass, :only => :new
6
8
 
7
- self.should_paginate_index = false
9
+ before_filter :redirect_for_default_from_time, :only => :reports
8
10
 
9
- has_scope :of_group, :as => :group, :only => :index
11
+ prepend_before_filter :set_reports_index_title, :only => :reports
12
+
13
+ filter_access_to :reports, :require => :read, :context => :admin
14
+
15
+ self.should_paginate_index = false
10
16
 
11
17
  has_scope :active, :only => :index, :default => 'true' do |_, scope, value|
12
18
  scope.active(E9.true_value?(value))
13
19
  end
14
20
 
15
- has_scope :of_type, :as => :type, :only => :index do |_, scope, value|
21
+ ##
22
+ # Reports
23
+ #
24
+
25
+ has_scope :reports, :only => :reports, :default => 'true' do |controller, scope, _|
26
+ if (args = controller.params.values_at(:from, :until)).any?
27
+ scope.reports(*args)
28
+ else
29
+ scope.reports
30
+ end
31
+ end
32
+
33
+ has_scope :of_group, :as => :group, :only => :reports
34
+
35
+ has_scope :type, :only => :reports do |_, scope, value|
16
36
  scope.of_type("#{value}_campaign".classify)
17
37
  end
18
38
 
39
+ def reports
40
+ index!
41
+ end
42
+
19
43
  protected
20
44
 
21
- def redirect_new_to_subclass
22
- types = %w(advertising affiliate email sales)
23
- type = types.member?(params[:type]) ? params[:type] : types.first
24
- redirect_to send("new_#{type}_campaign_path")
25
- end
45
+ def redirect_new_to_subclass
46
+ types = %w(advertising affiliate email sales)
47
+ type = types.member?(params[:type]) ? params[:type] : types.first
48
+ redirect_to send("new_#{type}_campaign_path")
49
+ end
26
50
 
27
- def collection_scope
28
- #end_of_association_chain.typed.includes(:campaign_group)
51
+ def collection_scope
52
+ if reports?
53
+ end_of_association_chain
29
54
 
30
- # NOTE this is a pretty ugly join just to be able to sort on campaign group name
55
+ else
31
56
  end_of_association_chain.typed
32
57
  .joins("left outer join campaign_groups on campaign_groups.id = campaigns.campaign_group_id")
33
58
  .select("campaigns.*, campaign_groups.name campaign_group_name")
34
59
  end
60
+ end
35
61
 
36
- def default_ordered_on
37
- 'type,campaign_group_name,name'
38
- end
62
+ def default_ordered_on
63
+ 'type,campaign_group_name,name'
64
+ end
39
65
 
40
- def default_ordered_dir
41
- 'ASC'
42
- end
66
+ def default_ordered_dir
67
+ 'ASC'
68
+ end
43
69
 
70
+ def reports?
71
+ params[:action] == 'reports'
72
+ end
73
+
74
+ def set_reports_index_title
75
+ @index_title = I18n.t(:index_title, :scope => 'e9.e9_crm.reports')
76
+ end
77
+
78
+ def redirect_for_default_from_time
79
+ format = request.format.blank? || request.format == Mime::ALL ? Mime::HTML : request.format
80
+
81
+ if format.html? && params[:from].blank?
82
+ url = params.slice(:controller, :action)
83
+ url.merge!(:from => Date.today.strftime('%Y/%m'))
84
+ redirect_to url and return false
85
+ end
86
+ end
44
87
  end
@@ -22,6 +22,7 @@ class E9Crm::ContactsController < E9Crm::ResourcesController
22
22
 
23
23
  skip_before_filter :authenticate_user!, :filter_access_filter, :only => :templates
24
24
  before_filter :build_resource, :only => :templates
25
+ before_filter :set_edit_title, :only => :edit
25
26
 
26
27
  def templates
27
28
  render RecordAttribute::TEMPLATES
@@ -71,6 +72,10 @@ class E9Crm::ContactsController < E9Crm::ResourcesController
71
72
  end
72
73
  end
73
74
 
75
+ def set_edit_title
76
+ @edit_title ||= e9_t(:edit_title_with_name, :contact => resource.name)
77
+ end
78
+
74
79
  # we don't need @index_title in the breadcrumb here (too long)
75
80
  def add_index_breadcrumb
76
81
  add_breadcrumb! e9_t(:index_title), collection_path
@@ -5,34 +5,33 @@ class E9Crm::DealsController < E9Crm::ResourcesController
5
5
  # for campaign select options
6
6
  helper :"e9_crm/campaigns"
7
7
 
8
- filter_access_to :leads, :reports, :require => :read, :context => :admin
8
+ filter_access_to :leads, :require => :read, :context => :admin
9
9
 
10
10
  skip_after_filter :flash_to_headers, :except => :destroy
11
11
 
12
12
  prepend_before_filter :set_leads_index_title, :only => :leads
13
- prepend_before_filter :set_reports_index_title, :only => :reports
14
13
 
15
14
  before_filter :prepop_deal_owner_contact, :only => [:new, :edit]
16
15
 
17
- before_filter :redirect_for_default_from_time, :only => [:leads, :reports]
16
+ before_filter :redirect_for_default_from_time, :only => :leads
18
17
 
19
18
  ##
20
19
  # All Scopes
21
20
  #
22
21
 
23
22
  has_scope :until_time, :as => :until, :unless => 'params[:from].present?'
24
-
25
23
  has_scope :from_time, :as => :from do |controller, scope, value|
26
- #is_reports = controller.params[:action] == 'reports'
27
- is_reports = false
28
-
29
24
  if controller.params[:until]
30
- scope.for_time_range(value, controller.params[:until], :right_join => is_reports)
25
+ scope.for_time_range(value, controller.params[:until])
31
26
  else
32
- scope.from_time(value, :right_join => is_reports)
27
+ scope.from_time(value)
33
28
  end
34
29
  end
35
30
 
31
+ has_scope :closed_in_month, :as => :closed, :only => :index do |controller, scope, value|
32
+ scope.for_time_range(value, :column => :closed_at, :in => :month)
33
+ end
34
+
36
35
  ##
37
36
  # Leads Scopes
38
37
  #
@@ -57,20 +56,6 @@ class E9Crm::DealsController < E9Crm::ResourcesController
57
56
  has_scope :status, :only => :index
58
57
  has_scope :owner, :only => :index
59
58
 
60
- ##
61
- # Reports scopes
62
- #
63
-
64
- has_scope :reports, :only => :reports, :type => :boolean, :default => true
65
-
66
- has_scope :group, :only => :reports do |c, scope, value|
67
- scope & Campaign.of_group(value)
68
- end
69
-
70
- has_scope :type, :only => :reports do |_, scope, value|
71
- scope & Campaign.of_type("#{value}_campaign".classify)
72
- end
73
-
74
59
  ##
75
60
  # Actions
76
61
  #
@@ -79,10 +64,6 @@ class E9Crm::DealsController < E9Crm::ResourcesController
79
64
  index!
80
65
  end
81
66
 
82
- def reports
83
- index!
84
- end
85
-
86
67
  protected
87
68
 
88
69
  def add_edit_breadcrumb(opts = {})
@@ -94,18 +75,15 @@ class E9Crm::DealsController < E9Crm::ResourcesController
94
75
  def collection
95
76
  get_collection_ivar || begin
96
77
  set_collection_ivar(
97
- if params[:action] == 'reports'
98
- end_of_association_chain.all
78
+ if params[:action] == 'leads'
79
+ end_of_association_chain.includes(:contacts).paginate(pagination_parameters)
99
80
 
100
- elsif params[:action] == 'deals'
81
+ else
101
82
  # NOTE this is a pretty ugly join just to be able to sort on owner
102
83
  end_of_association_chain
103
84
  .joins("left outer join contacts on contacts.id = deals.contact_id")
104
85
  .select("deals.*, contacts.first_name owner_name")
105
86
  .all
106
-
107
- else
108
- end_of_association_chain.includes(:contacts).paginate(pagination_parameters)
109
87
  end
110
88
  )
111
89
  end
@@ -123,12 +101,12 @@ class E9Crm::DealsController < E9Crm::ResourcesController
123
101
  @index_title = I18n.t(:index_title, :scope => 'e9.e9_crm.leads')
124
102
  end
125
103
 
126
- def set_reports_index_title
127
- @index_title = I18n.t(:index_title, :scope => 'e9.e9_crm.reports')
104
+ def should_paginate_index
105
+ params[:action] == 'leads'
128
106
  end
129
107
 
130
108
  def ordered_if
131
- %w(index leads reports).member? params[:action]
109
+ %w(index leads).member? params[:action]
132
110
  end
133
111
 
134
112
  def default_ordered_on
@@ -38,11 +38,11 @@ class E9Crm::OffersController < E9Crm::ResourcesController
38
38
  end
39
39
 
40
40
  def default_ordered_on
41
- :name
41
+ 'name'
42
42
  end
43
43
 
44
44
  def default_ordered_dir
45
- :ASC
45
+ 'ASC'
46
46
  end
47
47
 
48
48
  def ensure_mailing_list_ids
@@ -32,6 +32,10 @@ class E9Crm::ResourcesController < E9Crm::BaseController
32
32
 
33
33
  protected
34
34
 
35
+ def should_paginate_index
36
+ self.class.should_paginate_index
37
+ end
38
+
35
39
  def filter_target
36
40
  resource
37
41
  end
@@ -17,9 +17,20 @@ module E9Crm::CampaignsHelper
17
17
  val && "?#{E9Crm.query_param}=#{val}" || 'n/a'
18
18
  end
19
19
 
20
- def display_campaign_type(val = '')
21
- retv = val[/(.*)Campaign/, 1]
22
- retv == 'No' ? 'No Campaign' : retv
20
+ def display_campaign_type(val)
21
+ @_campaign_types ||= {}
22
+ @_campaign_types[val] ||= begin
23
+ retv = val[/(.*)Campaign/, 1]
24
+ retv == 'No' ? 'No Campaign' : retv
25
+ end
26
+ end
27
+
28
+ def display_campaign_group_by_id(val)
29
+ @_campaign_groups ||= CampaignGroup.all
30
+ @_campaign_group_by_id ||= {}
31
+ @_campaign_group_by_id[val] ||= begin
32
+ @_campaign_groups.find {|c| c.id == val }.try(:name) || 'No Group'
33
+ end
23
34
  end
24
35
 
25
36
  def campaign_type_select_options(with_all_option = true)
@@ -46,40 +46,34 @@ module E9Crm::DealsHelper
46
46
  end
47
47
  end
48
48
 
49
- def deal_date_select_options(ending_month = false)
49
+ def deal_date_select_options(options = {})
50
50
  @_first_deal_date ||= Deal.order(:created_at).first.try(:created_at) || Date.today
51
51
 
52
52
  date, cdate = @_first_deal_date, Date.today
53
53
 
54
- options = []
54
+ sel_options = []
55
55
 
56
- if ending_month
57
- prefix = 'Until'
56
+ if options[:type] == :until
57
+ prefix = 'Up to '
58
58
  label = prefix + ' Now'
59
+ elsif options[:type] == :in_month
60
+ prefix = 'Closed in '
61
+ label = 'Since Inception'
59
62
  else
60
- prefix = 'From'
63
+ prefix = 'Since '
61
64
  label = prefix + ' Inception'
62
65
  end
63
66
 
64
67
  begin
65
- options << [date.strftime("#{prefix} %B %Y"), date.strftime('%Y/%m')]
68
+ sel_options << [date.strftime("#{prefix}%B %Y"), date.strftime('%Y/%m')]
66
69
  date += 1.month
67
70
  end while date.year <= cdate.year && date.month <= cdate.month
68
71
 
69
- options.unshift([label, nil])
72
+ sel_options.reverse!
70
73
 
71
- options_for_select(options)
72
- end
74
+ sel_options.unshift([label, nil])
73
75
 
74
- def deal_cost(deal)
75
- campaign = deal.campaign
76
-
77
- if campaign.blank?
78
- 0
79
- else
80
- c = campaign.non_leads.count
81
- c > 0 ? campaign.cost.to_f / c : campaign.cost
82
- end.to_money
76
+ options_for_select(sel_options)
83
77
  end
84
78
 
85
79
  def deal_contacts
@@ -92,4 +86,9 @@ module E9Crm::DealsHelper
92
86
  def deal_contacts_array
93
87
  deal_contacts.map {|c| [c.name, c.id] }
94
88
  end
89
+
90
+ def title_and_or_company(contact)
91
+ [contact.title, contact.company_name].
92
+ map(&:presence).compact.join(' at ').html_safe
93
+ end
95
94
  end
@@ -22,10 +22,6 @@ class Campaign < ActiveRecord::Base
22
22
  # NOTE tracking cookie code changes with new visits
23
23
  has_many :tracking_cookies, :foreign_key => :code, :primary_key => :code, :class_name => 'TrackingCookie'
24
24
 
25
- def self.default
26
- NoCampaign.first || NoCampaign.create
27
- end
28
-
29
25
  validates :name, :presence => true,
30
26
  :uniqueness => { :allow_blank => true, :case_sensitive => false }
31
27
 
@@ -39,9 +35,81 @@ class Campaign < ActiveRecord::Base
39
35
 
40
36
  scope :active, lambda {|val=true| where(:active => val) }
41
37
  scope :inactive, lambda { active(false) }
42
- scope :of_group, lambda {|val| where(:campaign_group_id => val.to_param) }
38
+ scope :of_group, lambda {|val| joins(:campaign_group).where(:campaign_group_id => val.to_param) }
43
39
  scope :typed, lambda { where(arel_table[:type].not_eq('NoCampaign')) }
44
40
  scope :ordered, lambda { order(arel_table[:name].asc) }
41
+
42
+ scope :reports, lambda {|*args|
43
+ options = args.extract_options!
44
+
45
+ selects = <<-SQL.gsub(/\s+/, ' ')
46
+ campaigns.*,
47
+
48
+ SUM(IF(deals.status != 'lead',1,0)) deal_count,
49
+
50
+ COUNT(deals.id) lead_count,
51
+
52
+ SUM(IF(deals.status='won',1,0)) won_deal_count,
53
+ SUM(IF(deals.status='won',deals.value,0)) total_value,
54
+ AVG(IF(deals.status='won',deals.value,NULL)) average_value,
55
+
56
+ SUM(costs.total) total_cost,
57
+ SUM(costs.total) /
58
+ SUM(IF(deals.status='won',1,0)) average_cost,
59
+
60
+ rv.count repeat_visits,
61
+ nv.count new_visits,
62
+
63
+ FLOOR(AVG(
64
+ DATEDIFF(
65
+ deals.closed_at,
66
+ deals.created_at))) average_elapsed
67
+ SQL
68
+
69
+ select(selects)
70
+ .joins(
71
+ 'LEFT OUTER JOIN deals ' +
72
+ 'ON deals.campaign_id = campaigns.id ' +
73
+ "#{ 'AND ' + Deal.for_time_range_conditions(*args, options).to_sql if args.present?}")
74
+ .joins(
75
+ 'LEFT OUTER JOIN ( ' +
76
+ 'SELECT SUM(cost) total, costable_id dc_cid ' +
77
+ 'FROM dated_costs ' +
78
+ 'WHERE costable_type="Campaign" ' +
79
+ "#{ 'AND ' + DatedCost.for_time_range_conditions(*args, options).to_sql if args.present?}" +
80
+ ' GROUP BY dc_cid) costs ' +
81
+ 'ON costs.dc_cid = campaigns.id')
82
+ .joins(
83
+ 'LEFT OUTER JOIN ( ' +
84
+ 'SELECT COUNT(DISTINCT session) count, campaign_id nv_cid ' +
85
+ 'FROM page_views ' +
86
+ 'WHERE page_views.new_visit = 1 ' +
87
+ "#{ 'AND ' + PageView.for_time_range_conditions(*args, options).to_sql if args.present?}" +
88
+ ' GROUP BY nv_cid ) nv ' +
89
+ 'ON nv.nv_cid = campaigns.id')
90
+ .joins(
91
+ 'LEFT OUTER JOIN ( ' +
92
+ 'SELECT COUNT(DISTINCT session) count, campaign_id rv_cid ' +
93
+ 'FROM page_views ' +
94
+ 'WHERE page_views.new_visit = 0 ' +
95
+ "#{ 'AND ' + PageView.for_time_range_conditions(*args, options).to_sql if args.present?}" +
96
+ ' GROUP BY rv_cid ) rv ' +
97
+ 'ON rv.rv_cid = campaigns.id')
98
+ .group('campaigns.id')
99
+ }
100
+
101
+ def self.default
102
+ NoCampaign.first || NoCampaign.create
103
+ end
104
+
105
+ # money column definitions for pseudo attributes (added on the reports scope)
106
+ %w(total_value average_value total_cost average_cost).each do |money_column|
107
+ class_eval("def #{money_column}; (r = read_attribute(:#{money_column})) && Money.new(r) end")
108
+ end
109
+
110
+ %w(new_visits repeat_visits).each do |count_column|
111
+ class_eval("def #{count_column}; (r = read_attribute(:#{count_column})) || 0 end")
112
+ end
45
113
 
46
114
  def new_visit_session_count
47
115
  page_views.new_visits.group(:session).count.keys.length
@@ -55,7 +123,7 @@ class Campaign < ActiveRecord::Base
55
123
  page_views.repeat_visits.group(:session).count.keys.length
56
124
  end
57
125
 
58
- def repeat_visit_session_count
126
+ def repeat_visit_page_view_count
59
127
  page_views.repeat_visits.group(:session).count.values.sum
60
128
  end
61
129
 
@@ -1,6 +1,6 @@
1
1
  class Contact < ActiveRecord::Base
2
2
  include E9Tags::Model
3
- include E9Rails::ActiveRecord::AttributeSearchable
3
+ include E9::ActiveRecord::AttributeSearchable
4
4
  include E9Rails::ActiveRecord::Initialization
5
5
 
6
6
  # necessary so contact knows its merge path
@@ -215,6 +215,8 @@ class Contact < ActiveRecord::Base
215
215
  def merge_and_destroy!(other)
216
216
  merge_tags(other)
217
217
 
218
+ self.info = "#{self.info}\n\n#{other.info}"
219
+
218
220
  if success = save
219
221
  merge_destructive_and_destroy!(other)
220
222
  end
@@ -236,6 +238,8 @@ class Contact < ActiveRecord::Base
236
238
  self.address_attributes |= other.address_attributes
237
239
  self.phone_number_attributes |= other.phone_number_attributes
238
240
  self.instant_messaging_handle_attributes |= other.instant_messaging_handle_attributes
241
+
242
+ other.associated_deals.clear
239
243
  other.destroy
240
244
  end
241
245
 
@@ -327,6 +331,17 @@ class Contact < ActiveRecord::Base
327
331
  reject_record_attribute?(hash) || super
328
332
  end
329
333
 
334
+ def assign_to_or_mark_for_destruction(record, attributes, allow_destroy)
335
+ record.attributes = attributes.except(*UNASSIGNABLE_KEYS)
336
+ if has_destroy_flag?(attributes) && allow_destroy
337
+ if record.prospect?
338
+ record.mark_for_destruction
339
+ else
340
+ self.users.delete(record)
341
+ end
342
+ end
343
+ end
344
+
330
345
  #
331
346
  # #TODO figure out exactly how to handle rejection of Users
332
347
  #
@@ -4,6 +4,7 @@
4
4
  #
5
5
  class DatedCost < ActiveRecord::Base
6
6
  include E9Rails::ActiveRecord::Initialization
7
+ include E9::ActiveRecord::TimeScopes
7
8
 
8
9
  money_columns :cost
9
10
  belongs_to :costable, :polymorphic => true
data/app/models/deal.rb CHANGED
@@ -4,7 +4,6 @@
4
4
  class Deal < ActiveRecord::Base
5
5
  include E9Rails::ActiveRecord::Initialization
6
6
  include E9Rails::ActiveRecord::InheritableOptions
7
-
8
7
  include E9::ActiveRecord::TimeScopes
9
8
 
10
9
  self.options_column = false
@@ -24,7 +23,7 @@ class Deal < ActiveRecord::Base
24
23
  validates :campaign, :presence => true
25
24
  validate do |record|
26
25
  if !Status::OPTIONS.include?(record.status)
27
- record.errors.add(:status, :inclusion, :options => Status::OPTIONS)
26
+ record.errors.add(:status, :inclusion, :options => Status::HUMAN_OPTIONS.join(', '))
28
27
  elsif record.status_changed? && record.won? || record.lost? and record.status_was == Status::Lead
29
28
  record.errors.add(:status, :illegal_conversion)
30
29
  end
@@ -54,63 +53,12 @@ class Deal < ActiveRecord::Base
54
53
  before_save :handle_status_conversion, :if => lambda {|r| r.status_changed? }
55
54
  before_save :handle_dated_cost, :if => lambda {|r| r.status_changed? || r.campaign_id_changed? }
56
55
 
57
- # money column definitions for pseudo attributes (added on the reports scope)
58
- %w(total_value average_value total_cost average_cost).each do |money_column|
59
- class_eval("def #{money_column}; (r = read_attribute(:#{money_column})) && Money.new(r) end")
60
- end
61
-
62
56
  delegate :name, :to => :owner, :prefix => true, :allow_nil => true
63
57
 
64
58
  # mailing_list_ids may be set on Deals when they are being created as leads, this is
65
59
  # done via opt-in checkboxes on the form
66
60
  attr_accessor :mailing_list_ids
67
61
 
68
- #
69
- # reports is technically a deal scope, but actually returns campaigns
70
- # and a selection of relevant pseudo columns.
71
- #
72
- # NOTE reports probably should be a campaign scope? It doesn't really seem
73
- # to matter. The resultset is neither Deals nor Campaigns, anyway, but
74
- # a selection of calculated columns aggregated from data from both tables.
75
- #
76
- scope :reports, lambda {
77
- selects = <<-SQL.gsub(/\s+/, ' ')
78
- campaigns.type campaign_type,
79
- campaigns.name campaign_name,
80
- campaigns.new_visits new_visits,
81
- campaigns.repeat_visits repeat_visits,
82
- deals.closed_at closed_at,
83
- deals.created_at created_at,
84
- campaign_groups.name campaign_group,
85
- SUM(IF(deals.status != 'lead',1,0)) deal_count,
86
- COUNT(deals.id) lead_count,
87
- SUM(IF(deals.status='won',1,0)) won_deal_count,
88
- SUM(IF(deals.status='won',deals.value,0)) total_value,
89
- AVG(IF(deals.status='won',deals.value,NULL)) average_value,
90
- SUM(dated_costs.cost) total_cost,
91
- SUM(dated_costs.cost) /
92
- SUM(IF(deals.status='won',1,0)) average_cost,
93
- FLOOR(AVG(
94
- DATEDIFF(
95
- deals.closed_at,
96
- deals.created_at))) average_elapsed
97
- SQL
98
-
99
- joins = <<-SQL.gsub(/\s+/, ' ')
100
- RIGHT JOIN campaigns
101
- ON deals.campaign_id = campaigns.id
102
-
103
- LEFT JOIN dated_costs
104
- ON campaigns.id = dated_costs.costable_id
105
- AND dated_costs.costable_type = "Campaign"
106
-
107
- LEFT JOIN campaign_groups
108
- ON campaign_groups.id = campaigns.campaign_group_id
109
- SQL
110
-
111
- select(selects).joins(joins).group('campaigns.id')
112
- }
113
-
114
62
  scope :column_op, lambda {|op, column, value, reverse=false|
115
63
  conditions = arel_table[column].send(op, value)
116
64
  conditions = conditions.not if reverse
@@ -262,10 +210,12 @@ class Deal < ActiveRecord::Base
262
210
  end
263
211
 
264
212
  module Status
265
- OPTIONS = %w(lead pending won lost)
266
- Lead = OPTIONS[0]
267
- Pending = OPTIONS[1]
268
- Won = OPTIONS[2]
269
- Lost = OPTIONS[3]
213
+ OPTIONS = %w(lead pending won lost)
214
+ Lead = OPTIONS[0]
215
+ Pending = OPTIONS[1]
216
+ Won = OPTIONS[2]
217
+ Lost = OPTIONS[3]
218
+
219
+ HUMAN_OPTIONS = [Pending, Won, Lost].map(&:titleize)
270
220
  end
271
221
  end
@@ -8,6 +8,6 @@ class NoCampaign < Campaign
8
8
  end
9
9
 
10
10
  def code
11
- 'No Code'
11
+ 'NoCode'
12
12
  end
13
13
  end
@@ -14,15 +14,16 @@
14
14
  #
15
15
  class PageView < ActiveRecord::Base
16
16
  include E9Rails::ActiveRecord::Scopes::Times
17
+ include E9::ActiveRecord::TimeScopes
17
18
 
18
19
  belongs_to :tracking_cookie
19
20
 
20
21
  belongs_to :campaign, :inverse_of => :page_views
21
22
  has_one :user, :through => :tracking_cookie
22
23
 
23
- attr_accessor :should_cache
24
+ #attr_accessor :should_cache
24
25
 
25
- after_create :increment_campaign_visit_cache, :if => '!!should_cache'
26
+ #after_create :increment_campaign_visit_cache, :if => '!!should_cache'
26
27
 
27
28
  scope :by_user, lambda {|*users|
28
29
  users.flatten!
@@ -43,7 +44,7 @@ class PageView < ActiveRecord::Base
43
44
 
44
45
  protected
45
46
 
46
- def increment_campaign_visit_cache
47
- Campaign.increment_counter(new_visit ? :new_visits : :repeat_visits, campaign_id)
48
- end
47
+ #def increment_campaign_visit_cache
48
+ #Campaign.increment_counter(new_visit ? :new_visits : :repeat_visits, campaign_id)
49
+ #end
49
50
  end
@@ -4,7 +4,13 @@
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
- = f.collection_select :affiliate_id, Contact.affiliates.ordered.all, :id, :name, {:prompt => true}, :id => 'campaign_affiliate_id'
7
+ %input.contact-autocomplete{:type => 'text'}
8
+ - contact = f.object.affiliate
9
+ .contact-select{:style => contact.blank? && 'display:none' || ''}
10
+ %span.content= contact.try(:name)
11
+ %input{:type => :hidden, :name => "#{resource_instance_name}[affiliate_id]", :value => contact.try(:id)}
12
+ %a{:class => :remove, :title => "Remove", :alt => "Remove"} Remove
13
+
8
14
  .field
9
15
  = help_label f, :affiliate_fee
10
16
  = f.text_field :affiliate_fee, :value => f.object.affiliate_fee.to_s
@@ -3,7 +3,7 @@
3
3
  %tr
4
4
  %th= orderable_column_link(:campaign_type)
5
5
  %th= orderable_column_link(:campaign_group)
6
- %th= orderable_column_link(:campaign_name)
6
+ %th= orderable_column_link(:name)
7
7
  %th= orderable_column_link(:new_visits)
8
8
  %th= orderable_column_link(:repeat_visits)
9
9
  %th= orderable_column_link(:lead_count)
@@ -14,6 +14,7 @@
14
14
  %th= orderable_column_link(:total_cost)
15
15
  %th= orderable_column_link(:average_cost)
16
16
  %th= orderable_column_link(:average_elapsed)
17
+
17
18
  %tbody
18
19
  -# prepare a hash to store the accumulated row data for calculations
19
20
  - dat = Hash.new {|k,v| k[v] = [] }
@@ -25,11 +26,11 @@
25
26
  - collection.each do |record|
26
27
  %tr{:id => "ids_#{record.id}", :class => cycle('odd', 'even')}
27
28
  %td.record-campaign-type
28
- = display_campaign_type(record.campaign_type)
29
+ = display_campaign_type(record.type)
29
30
  %td.record-campaign-group
30
- = record.campaign_group || 'n/a'
31
- %td.record-campaign-name
32
- = record.campaign_name || 'n/a'
31
+ = display_campaign_group_by_id(record.campaign_group)
32
+ %td.record-name
33
+ = record.name || 'n/a'
33
34
  %td.record-new-visits.num
34
35
  - dat[:new_visits] << record.new_visits
35
36
  = record.new_visits
@@ -60,6 +61,7 @@
60
61
  %td.record-average-elapsed.num
61
62
  - dat[:average_elapsed] << record.average_elapsed
62
63
  = record.average_elapsed && "%s days" % record.average_elapsed || 'n/a'
64
+
63
65
  %tfooter
64
66
  %tr{:class => 'record-totals'}
65
67
  %td.record-totals-label{:colspan => 3}
@@ -32,5 +32,5 @@
32
32
  = link_to t(:edit_dated_costs), advertising_campaign_dated_costs_path(record), :class => 'dated-costs'
33
33
  = link_to_edit_campaign(record)
34
34
 
35
- - if @controller.should_paginate_index
35
+ - if controller.send(:should_paginate_index)
36
36
  = will_paginate collection
@@ -1,11 +1,19 @@
1
- = title (@index_title || e9_t(:reports_title))
1
+ = title (@index_title || e9_t(:index_title, :scope => 'e9_crm.reports'))
2
2
 
3
- = render 'header'
3
+ .toolbar
4
+ .toolbar-left
5
+ = form_tag(resource_class, :method => :get, :class => 'scope-selects') do
6
+ %select{:name => 'type'}
7
+ = campaign_type_select_options
8
+ %select{:name => 'group'}
9
+ = campaign_group_select_options
10
+ %select{:name => 'from'}
11
+ = deal_date_select_options
12
+ %select{:name => 'until'}
13
+ = deal_date_select_options(:type => :until)
4
14
 
5
- - if sortable_controller?
6
- = form_tag polymorphic_path([:update_order, resource_class]) do
7
- %div#records_table
8
- = render 'table', :resources => collection
9
- - else
10
- %div#records_table
11
- = render 'table', :resources => collection
15
+ .toolbar-right
16
+ = link_to_collection(Campaign)
17
+
18
+ %div#records_table
19
+ = render 'reports_table'
@@ -20,9 +20,6 @@
20
20
  .field
21
21
  = f.label :title
22
22
  = f.text_field :title
23
- .field
24
- = f.label :status
25
- = f.select :status, Contact::Status::VALUES.map {|v| [v.titleize, v] }
26
23
 
27
24
  = upload_mount_field(resource.avatar, :reset_path => true)
28
25
 
@@ -15,5 +15,5 @@
15
15
  - field_map[:links][record].each do |link|
16
16
  = link
17
17
 
18
- - if @controller.should_paginate_index
18
+ - if controller.send(:should_paginate_index)
19
19
  = will_paginate collection
@@ -0,0 +1,6 @@
1
+ = title @edit_title || e9_t(:edit_title)
2
+
3
+ .actions
4
+ = link_to 'View Contact', resource
5
+
6
+ = render 'form'
@@ -55,7 +55,7 @@
55
55
  %td.contact-deal-status
56
56
  = deal.status
57
57
  %td.contact-deal-value
58
- = deal.value
58
+ = deal.value.format
59
59
 
60
60
  .contact.leads
61
61
  %h2
@@ -74,10 +74,10 @@
74
74
  - else
75
75
  - leads.each do |lead|
76
76
  %tr
77
- %td.contact-lead-name
78
- = link_to lead.offer_name, edit_deal_path(lead)
79
77
  %td.contact-lead-created-at
80
78
  = l(lead.created_at)
79
+ %td.contact-lead-name
80
+ = link_to lead.offer_name, edit_deal_path(lead)
81
81
 
82
82
  .contact-sidebar
83
83
  = render 'sidebar'
@@ -19,7 +19,7 @@
19
19
  = f.collection_select :campaign_id, Campaign.ordered.all, :id, :to_s, {:prompt => true}, :id => 'deal_campaign_select'
20
20
  .field.select
21
21
  = f.label :status
22
- = f.select :status, Deal::Status::OPTIONS[1..-1]
22
+ = f.select :status, Deal::Status::HUMAN_OPTIONS.map {|d| [d, d.downcase] }
23
23
  .field.select
24
24
  = f.label :contacts
25
25
  %input#contact_autocomplete.list{:type => 'text', 'data-values' => resource.contact_ids.join(','), 'data-iname' => resource_instance_name, 'data-field' => '[contact_ids]'}
@@ -40,19 +40,3 @@
40
40
  .field.date-picker
41
41
  = f.label :closed_at
42
42
  = f.text_field :closed_at, :class => 'date-picker', :value => l(resource.closed_at.try(:to_date))
43
-
44
- .field
45
- Created At:
46
- = l(resource.created_at)
47
- .field
48
- Closed At:
49
- = resource.closed_at ? l(resource.closed_at) : 'n/a'
50
- .field
51
- Campaign Cost:
52
- = resource.campaign.try(:cost) || 0
53
- .field
54
- Campaign Deal Count:
55
- = resource.campaign ? resource.campaign.non_leads.count : 0
56
- .field
57
- Cost:
58
- = deal_cost(resource)
@@ -7,6 +7,8 @@
7
7
  = deal_category_select_options
8
8
  %select{:name => 'owner'}
9
9
  = deal_owner_select_options
10
+ %select{:name => 'closed'}
11
+ = deal_date_select_options(:type => :in_month)
10
12
 
11
13
  .toolbar-right
12
14
  = link_to I18n.t('activerecord.links.index', :models => 'Leads'), leads_path
@@ -6,7 +6,7 @@
6
6
  %select{:name => 'from'}
7
7
  = deal_date_select_options
8
8
  %select{:name => 'until'}
9
- = deal_date_select_options(true)
9
+ = deal_date_select_options(:type => :until)
10
10
 
11
11
  .toolbar-right
12
12
  = link_to_collection(Deal)
@@ -27,7 +27,7 @@
27
27
  = record.lead_email
28
28
  %td.record-info
29
29
  = k record.info
30
- %td.actions
30
+ %td.links
31
31
  - if record.contacts.present?
32
32
  = link_to 'View Contact', record.contacts.first
33
33
  = link_to 'Create Deal', edit_deal_path(record)
@@ -20,7 +20,7 @@
20
20
  %td.record-name
21
21
  = record.name
22
22
  %td.record-status
23
- = record.status
23
+ = record.status.titleize
24
24
  %td.record-category
25
25
  = record.category
26
26
  %td.record-owner
@@ -1,4 +1,7 @@
1
- = title e9_t(:show_title)
1
+ = title resource.name
2
+
3
+ .actions
4
+ = link_to_edit_resource(resource)
2
5
 
3
6
  .deal-header
4
7
  .deal-category
@@ -8,6 +11,22 @@
8
11
  .deal-status
9
12
  = resource.status
10
13
 
11
- .deal-body
12
- .deal-info
13
- = k(resource.info)
14
+ .deal-info
15
+ = k(resource.info)
16
+
17
+ %fieldset.deal-owner
18
+ %legend= t(:deal_owner_legend)
19
+ .deal-contact
20
+ - if resource.owner
21
+ .contact-link= link_to(resource.owner.name, resource.owner)
22
+ .contact-title= title_and_or_company(resource.owner)
23
+ - else
24
+ = t(:no_deal_owner)
25
+
26
+ - if resource.contacts.any?
27
+ %fieldset.deal-contacts
28
+ %legend= t(:deal_contact_legend)
29
+ - resource.contacts.each do |contact|
30
+ .deal-contact
31
+ .contact-link= link_to(contact.name, contact)
32
+ .contact-title= title_and_or_company(contact)
@@ -1,14 +1,14 @@
1
- = form_for resource, :url => public_offer_deals_path(@offer), :remote => request.xhr? do |f|
1
+ = form_for resource, :url => public_offer_deals_path(@offer) do |f|
2
2
  .errors= resource_error_messages!
3
3
  .notice
4
4
 
5
5
  - if f.object.user.blank?
6
6
  .field
7
- = f.label :lead_email
8
- = f.text_field :lead_email
7
+ = f.label :lead_email, nil, :class => :req
8
+ = f.text_field :lead_email, :class => 'email required'
9
9
  .field
10
- = f.label :lead_name
11
- = f.text_field :lead_name
10
+ = f.label :lead_name, nil, :class => :req
11
+ = f.text_field :lead_name, :class => 'required'
12
12
 
13
13
  = @offer.custom_form_html.html_safe
14
14
 
@@ -1,5 +1,4 @@
1
1
  - content_for :bottom_javascripts do
2
- -#= render 'shared/admin/tiny_mce') if use_tiny_mce?
3
2
  = render 'shared/admin/tiny_mce'
4
3
 
5
4
  .field
@@ -24,5 +24,5 @@
24
24
  %td.record-remote-ip
25
25
  = record.remote_ip
26
26
 
27
- - if @controller.should_paginate_index
27
+ - if controller.send(:should_paginate_index)
28
28
  = will_paginate collection
@@ -23,5 +23,5 @@
23
23
  - field_map[:links][record].each do |link|
24
24
  = link
25
25
 
26
- - if @controller.should_paginate_index
26
+ - if controller.send(:should_paginate_index)
27
27
  = will_paginate collection
@@ -10,5 +10,5 @@
10
10
  %div#records_table
11
11
  = render 'table', :resources => collection
12
12
 
13
- - if controller.should_paginate_index
13
+ - if controller.send(:should_paginate_index)
14
14
  = will_paginate collection
@@ -3,8 +3,14 @@
3
3
  %fieldset
4
4
  %legend= e9_t(:salesperson_information_legend, :scope => 'e9_crm.campaigns')
5
5
  .field
6
- = f.label :sales_person_id, nil, :class => (f.object.type == 'SalesCampaign' ? :req : nil)
7
- = f.collection_select :sales_person_id, Contact.sales_persons.ordered.all, :id, :name, :prompt => true
6
+ = f.label :sales_person, :class => :req, :for => 'campaign_sales_person_id'
7
+ %input.contact-autocomplete{:type => 'text'}
8
+ - contact = f.object.sales_person
9
+ .contact-select{:style => contact.blank? && 'display:none' || ''}
10
+ %span.content= contact.try(:name)
11
+ %input{:type => :hidden, :name => "#{resource_instance_name}[sales_person_id]", :value => contact.try(:id)}
12
+ %a{:class => :remove, :title => "Remove", :alt => "Remove"} Remove
13
+
8
14
  .field
9
15
  = help_label f, :sales_fee
10
16
  = f.text_field :sales_fee, :value => f.object.sales_fee.to_s
@@ -20,5 +20,5 @@
20
20
  = ff.label :primary_true, ff.object.class.human_attribute_name(:primary)
21
21
  = ff.radio_button :primary, true
22
22
 
23
- - if f.object.prospect?
24
- = link_to_destroy_record_attribute
23
+ -#- if f.object.prospect?
24
+ = link_to_destroy_record_attribute
@@ -19,6 +19,7 @@ en:
19
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
+ edit_title_with_name: "Edit %{contact}"
22
23
  contact_merges:
23
24
  new_title: Merge Contacts
24
25
  no_value: (No Value)
@@ -31,6 +32,7 @@ en:
31
32
  select_submit: Send Email Now
32
33
  leads:
33
34
  index_title: Leads
35
+ no_records_text: No leads exist.
34
36
  reports:
35
37
  index_title: Marketing Report
36
38
  no_records_text: No data exists for those query parameters.
@@ -5,6 +5,9 @@ en:
5
5
  merge_conflict: "<p>This email is already attached to another contact and cannot be used.</p><p>Do you want to edit that contact instead?</p>"
6
6
  duplicate_email_warning: "<p>You cannot enter the same email twice.</p>"
7
7
  no_offer_value: No Offer
8
+ deal_owner_legend: Responsible
9
+ no_deal_owner: No one is responsible
10
+ deal_contact_legend: Associated Contacts
8
11
 
9
12
  actions: Actions
10
13
  clear: Clear
@@ -45,6 +48,8 @@ en:
45
48
  confirm_destroy: Are you sure? This cannot be undone.
46
49
  campaign_group:
47
50
  confirm_destroy: Are you sure? This cannot be undone. Any campaigns which are associated with this group will become groupless.
51
+ with_model:
52
+ show: "View %{name}"
48
53
 
49
54
  errors:
50
55
  messages:
data/config/routes.rb CHANGED
@@ -66,7 +66,7 @@ Rails.application.routes.draw do
66
66
 
67
67
  # leads are simply a scoped view of deals (only index)
68
68
  get :leads, :as => :leads, :to => 'deals#leads'
69
- get :marketing_report, :to => 'deals#reports'
69
+ get :marketing_report, :to => 'campaigns#reports'
70
70
 
71
71
  get '/merge_contacts/:contact_a_id/and/:contact_b_id', :as => :new_contact_merge, :to => 'contact_merges#new'
72
72
  post '/merge_contacts', :as => :contact_merges, :to => 'contact_merges#create'
@@ -66,8 +66,8 @@ module E9Crm
66
66
  else
67
67
  attrs = {}
68
68
 
69
- if current_user && !@_tracking_cookie.user_id?
70
- E9Crm.log("Cookie user (#{@_tracking_cookie.user_id}) not current_user (#{current_user.id}), changing...")
69
+ if current_user && @_tracking_cookie.user_id.nil?
70
+ E9Crm.log("Cookie has no user, setting as current_user (#{current_user.id})")
71
71
  attrs[:user] = current_user
72
72
  end
73
73
 
@@ -11,9 +11,9 @@ module E9Crm::Rack
11
11
  if env["PATH_INFO"] =~ /^\/autocomplete\/contacts/
12
12
  params = Rack::Request.new(env).params
13
13
 
14
- if query = params['query']
14
+ if query = params['query'] || params['term']
15
15
  relation =
16
- Contact.any_attrs_like('first_name', 'last_name', query).
16
+ Contact.any_attrs_like('first_name', 'last_name', query, :matcher => '%s%%').
17
17
  limit(params['limit'] || DEFAULT_LIMIT).
18
18
  joins("LEFT JOIN users on users.contact_id = contacts.id").
19
19
  where(%{users.options REGEXP "primary: [\\"']?true" OR users.options IS NULL}).
@@ -3,8 +3,7 @@ module E9Crm
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- prepend_before_filter :check_for_new_session
7
- after_filter :track_page_view
6
+ before_filter :track_page_view
8
7
 
9
8
  prepend_before_filter do
10
9
  E9Crm.log("E9Crm tracking controller request")
@@ -13,24 +12,6 @@ module E9Crm
13
12
 
14
13
  protected
15
14
 
16
- #
17
- # Checks to see if our session is new (a first request). During such a call
18
- # the session id has not been set yet.
19
- #
20
- # This is useful when determining whether or not the page view (created afterwards)
21
- # should increment the counter cache for its associated Campaign, as this should
22
- # only happen once per session.
23
- #
24
- def check_for_new_session
25
- if request.session_options[:id].blank? && request.get?
26
- E9Crm.log("No session found, page view will increment campaign counter cache")
27
- @_should_cache = true
28
- end
29
-
30
- E9Crm.log("session id: #{request.session_options[:id]}")
31
- E9Crm.log("session get?: #{request.get?}")
32
- end
33
-
34
15
  #
35
16
  # Track a page view and associate it with the loaded cookie.
36
17
  #
@@ -43,13 +24,6 @@ module E9Crm
43
24
  # [:campaign] The campaign associated with the tracking cookie or the default
44
25
  # campaign (typically the NoCampaign record)
45
26
  #
46
- # [:should_cache] Whether or not this page view should increment the page view
47
- # count for it's associated page. This should only happen once
48
- # per session and for this reason, is only true on sessionless
49
- # (new) requests. This is determined by looking for a session id
50
- # during the before filter, as in the after filter the session id
51
- # has been assigned.
52
- #
53
27
  def track_page_view
54
28
  if request.get?
55
29
  @_page_view ||= tracking_cookie.page_views.create({
@@ -59,8 +33,7 @@ module E9Crm
59
33
  :remote_ip => request.remote_ip,
60
34
  :session => request.session_options[:id],
61
35
  :campaign => tracking_campaign,
62
- :new_visit => session[:new_visit].present?,
63
- :should_cache => !!@_should_cache
36
+ :new_visit => session[:new_visit].present?
64
37
  })
65
38
  end
66
39
  end
@@ -1,3 +1,3 @@
1
1
  module E9Crm
2
- VERSION = '0.1.21'
2
+ VERSION = '0.1.22'
3
3
  end
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.21
5
+ version: 0.1.22
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-09-16 00:00:00 Z
13
+ date: 2011-09-21 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rails
@@ -223,8 +223,10 @@ files:
223
223
  - app/views/e9_crm/campaign_groups/_header.html.haml
224
224
  - app/views/e9_crm/campaigns/_form_inner.html.haml
225
225
  - app/views/e9_crm/campaigns/_header.html.haml
226
+ - app/views/e9_crm/campaigns/_reports_table.html.haml
226
227
  - app/views/e9_crm/campaigns/_table.html.haml
227
228
  - app/views/e9_crm/campaigns/reports.html.haml
229
+ - app/views/e9_crm/campaigns/reports.js.erb
228
230
  - app/views/e9_crm/companies/_form_inner.html.haml
229
231
  - app/views/e9_crm/companies/_header.html.haml
230
232
  - app/views/e9_crm/contact_emails/_form.html.haml
@@ -245,6 +247,7 @@ files:
245
247
  - app/views/e9_crm/contacts/_table.html.haml
246
248
  - app/views/e9_crm/contacts/_tag_table.html.haml
247
249
  - app/views/e9_crm/contacts/_who.html.haml
250
+ - app/views/e9_crm/contacts/edit.html.haml
248
251
  - app/views/e9_crm/contacts/index.html.haml
249
252
  - app/views/e9_crm/contacts/index.js.erb
250
253
  - app/views/e9_crm/contacts/show.html.haml
@@ -265,13 +268,10 @@ files:
265
268
  - app/views/e9_crm/deals/_header.html.haml
266
269
  - app/views/e9_crm/deals/_leads_header.html.haml
267
270
  - app/views/e9_crm/deals/_leads_table.html.haml
268
- - app/views/e9_crm/deals/_reports_table.html.haml
269
271
  - app/views/e9_crm/deals/_table.html.haml
270
272
  - app/views/e9_crm/deals/leads.html.haml
271
273
  - app/views/e9_crm/deals/leads.js.erb
272
274
  - app/views/e9_crm/deals/offer_form.html.haml
273
- - app/views/e9_crm/deals/reports.html.haml
274
- - app/views/e9_crm/deals/reports.js.erb
275
275
  - app/views/e9_crm/deals/show.html.haml
276
276
  - app/views/e9_crm/email_campaigns/_form_inner.html.haml
277
277
  - app/views/e9_crm/email_templates/_form_inner.html.haml
@@ -1,19 +0,0 @@
1
- = title (@index_title || e9_t(:index_title, :scope => 'e9_crm.reports'))
2
-
3
- .toolbar
4
- .toolbar-left
5
- = form_tag(resource_class, :method => :get, :class => 'scope-selects') do
6
- %select{:name => 'type'}
7
- = campaign_type_select_options
8
- %select{:name => 'group'}
9
- = campaign_group_select_options
10
- %select{:name => 'from'}
11
- = deal_date_select_options
12
- %select{:name => 'until'}
13
- = deal_date_select_options(true)
14
-
15
- .toolbar-right
16
- = link_to_collection(Campaign)
17
-
18
- %div#records_table
19
- = render 'reports_table'