e9_crm 0.1.21 → 0.1.22

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 (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'