e9_crm 0.1.1 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/app/controllers/e9_crm/advertising_campaigns_controller.rb +1 -0
- data/app/controllers/e9_crm/affiliate_campaigns_controller.rb +1 -0
- data/app/controllers/e9_crm/campaign_groups_controller.rb +8 -0
- data/app/controllers/e9_crm/campaigns_controller.rb +38 -1
- data/app/controllers/e9_crm/companies_controller.rb +1 -0
- data/app/controllers/e9_crm/contact_emails_controller.rb +3 -7
- data/app/controllers/e9_crm/contacts_controller.rb +6 -4
- data/app/controllers/e9_crm/dated_costs_controller.rb +1 -0
- data/app/controllers/e9_crm/deals_controller.rb +66 -2
- data/app/controllers/e9_crm/email_campaigns_controller.rb +1 -0
- data/app/controllers/e9_crm/email_templates.controller.rb +1 -0
- data/app/controllers/e9_crm/offers_controller.rb +1 -0
- data/app/controllers/e9_crm/page_views_controller.rb +1 -0
- data/app/controllers/e9_crm/resources_controller.rb +2 -1
- data/app/controllers/e9_crm/sales_campaigns_controller.rb +1 -0
- data/app/helpers/e9_crm/campaign_groups_helper.rb +8 -0
- data/app/helpers/e9_crm/campaigns_helper.rb +42 -11
- data/app/helpers/e9_crm/contacts_helper.rb +1 -1
- data/app/helpers/e9_crm/deals_helper.rb +25 -0
- data/app/models/advertising_campaign.rb +0 -1
- data/app/models/campaign.rb +40 -8
- data/app/models/campaign_group.rb +6 -0
- data/app/models/contact.rb +22 -0
- data/app/models/contact_email.rb +29 -18
- data/app/models/deal.rb +93 -14
- data/app/models/no_campaign.rb +5 -0
- data/app/models/page_view.rb +13 -44
- data/app/models/tracking_cookie.rb +0 -6
- data/app/observers/deal_observer.rb +3 -0
- data/app/views/e9_crm/advertising_campaigns/_form_inner.html.haml +1 -0
- data/app/views/e9_crm/affiliate_campaigns/_form_inner.html.haml +10 -0
- data/app/views/e9_crm/campaign_groups/_footer.html.haml +0 -0
- data/app/views/e9_crm/campaign_groups/_header.html.haml +3 -0
- data/app/views/e9_crm/campaigns/_footer.html.haml +0 -0
- data/app/views/e9_crm/campaigns/_form_inner.html.haml +20 -4
- data/app/views/e9_crm/campaigns/_header.html.haml +16 -0
- data/app/views/e9_crm/campaigns/_reports_table.html.haml +31 -0
- data/app/views/e9_crm/campaigns/_table.html.haml +31 -0
- data/app/views/e9_crm/campaigns/reports.html.haml +13 -0
- data/app/views/e9_crm/contact_emails/_form_inner.html.haml +1 -1
- data/app/views/e9_crm/contacts/_header.html.haml +5 -4
- data/app/views/e9_crm/deals/_reports_table.html.haml +86 -0
- data/app/views/e9_crm/deals/reports.html.haml +19 -0
- data/app/views/e9_crm/deals/reports.js.erb +1 -0
- data/app/views/e9_crm/email_campaigns/_form_inner.html.haml +1 -0
- data/app/views/e9_crm/page_views/_table.html.haml +7 -7
- data/app/views/e9_crm/resources/_table.html.haml +1 -1
- data/app/views/e9_crm/sales_campaigns/_form_inner.html.haml +11 -0
- data/config/locales/e9.en.yml +11 -1
- data/config/locales/en.yml +16 -5
- data/config/routes.rb +15 -12
- data/e9_crm.gemspec +1 -1
- data/lib/e9_crm/rails_extensions.rb +7 -0
- data/lib/e9_crm/tracking_controller.rb +69 -52
- data/lib/e9_crm/version.rb +1 -1
- data/lib/generators/e9_crm/install_generator.rb +1 -1
- data/lib/generators/e9_crm/templates/{create_e9_crm_tables.rb → migration.rb} +6 -7
- metadata +20 -6
- data/app/controllers/e9_crm/record_attributes_controller.rb +0 -3
- data/app/controllers/e9_crm/reports_controller.rb +0 -2
@@ -1,3 +1,11 @@
|
|
1
1
|
class E9Crm::CampaignGroupsController < E9Crm::ResourcesController
|
2
2
|
defaults :resource_class => CampaignGroup
|
3
|
+
include E9Rails::Controllers::Orderable
|
4
|
+
|
5
|
+
protected
|
6
|
+
|
7
|
+
# no pagination
|
8
|
+
def collection
|
9
|
+
get_collection_ivar || set_collection_ivar(end_of_association_chain.all)
|
10
|
+
end
|
3
11
|
end
|
@@ -1,4 +1,41 @@
|
|
1
1
|
class E9Crm::CampaignsController < E9Crm::ResourcesController
|
2
2
|
defaults :resource_class => Campaign
|
3
|
-
|
3
|
+
include E9Rails::Controllers::Orderable
|
4
|
+
|
5
|
+
filter_access_to :reports, :require => :read, :context => :admin
|
6
|
+
|
7
|
+
has_scope :of_group, :as => :group, :only => :index
|
8
|
+
|
9
|
+
has_scope :active, :only => :index do |_, scope, value|
|
10
|
+
scope.active(E9.true_value?(value))
|
11
|
+
end
|
12
|
+
|
13
|
+
has_scope :of_type, :as => :type, :only => :index do |_, scope, value|
|
14
|
+
scope.of_type("#{value}_campaign".classify)
|
15
|
+
end
|
16
|
+
|
17
|
+
def reports
|
18
|
+
index!
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def set_reports_index_title
|
24
|
+
@index_title = I18n.t(:reports_title, :scope => 'e9.e9_crm.campaigns')
|
25
|
+
end
|
26
|
+
|
27
|
+
def collection_scope
|
28
|
+
scope = end_of_association_chain
|
29
|
+
if params[:action] == 'reports'
|
30
|
+
scope = scope.select(
|
31
|
+
'campaigns.*, count(deals.id) won_deals_count, count(deals_campaigns.id) deals_count'
|
32
|
+
).joins([:deals, :won_deals])
|
33
|
+
end
|
34
|
+
scope
|
35
|
+
end
|
36
|
+
|
37
|
+
# no pagination
|
38
|
+
def collection
|
39
|
+
get_collection_ivar || set_collection_ivar(collection_scope.all)
|
40
|
+
end
|
4
41
|
end
|
@@ -17,21 +17,17 @@ class E9Crm::ContactEmailsController < E9Crm::ResourcesController
|
|
17
17
|
object = if params[resource_instance_name]
|
18
18
|
ContactEmail.new(params[resource_instance_name] || {})
|
19
19
|
else
|
20
|
-
ContactEmail.new_from_template(template, :from_email => current_user.email, :
|
20
|
+
ContactEmail.new_from_template(template, :from_email => current_user.email, :contact_ids => params[:uids])
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
# as the record won't be valid if the user_ids weren't passed in params
|
25
|
-
if object.user_ids.blank?
|
26
|
-
object.errors.add(:user_ids, :blank)
|
27
|
-
end
|
23
|
+
object.valid?
|
28
24
|
|
29
25
|
set_resource_ivar(object)
|
30
26
|
end
|
31
27
|
end
|
32
28
|
|
33
29
|
# throw record_not_found if there's no template. #new requires email_template_id
|
34
|
-
# be passed in params (and also
|
30
|
+
# be passed in params (and also contact_ids)
|
35
31
|
def template
|
36
32
|
@_template ||= EmailTemplate.find(params[:etid])
|
37
33
|
end
|
@@ -1,12 +1,13 @@
|
|
1
1
|
class E9Crm::ContactsController < E9Crm::ResourcesController
|
2
2
|
defaults :resource_class => Contact
|
3
3
|
|
4
|
+
include E9Rails::Controllers::Orderable
|
4
5
|
include E9Tags::Controller
|
5
6
|
|
6
7
|
respond_to :js, :html
|
7
8
|
|
8
9
|
before_filter :determine_title, :only => :index
|
9
|
-
before_filter :
|
10
|
+
before_filter :load_contact_ids, :only => :index
|
10
11
|
|
11
12
|
has_scope :search, :by_title, :by_company, :only => :index
|
12
13
|
has_scope :tagged, :only => :index, :type => :array
|
@@ -18,9 +19,10 @@ class E9Crm::ContactsController < E9Crm::ResourcesController
|
|
18
19
|
|
19
20
|
protected
|
20
21
|
|
21
|
-
def
|
22
|
-
@
|
23
|
-
|
22
|
+
def load_contact_ids
|
23
|
+
@contact_ids ||= begin
|
24
|
+
contact_id_sql = end_of_association_chain.scoped.select('contacts.id').to_sql
|
25
|
+
Contact.connection.send(:select_values, contact_id_sql, 'Contact ID Load')
|
24
26
|
end
|
25
27
|
end
|
26
28
|
|
@@ -1,19 +1,83 @@
|
|
1
1
|
class E9Crm::DealsController < E9Crm::ResourcesController
|
2
2
|
defaults :resource_class => Deal
|
3
|
+
include E9Rails::Controllers::Orderable
|
4
|
+
|
5
|
+
# for campaign select options
|
6
|
+
helper :"e9_crm/campaigns"
|
7
|
+
|
8
|
+
filter_access_to :leads, :reports, :require => :read, :context => :admin
|
3
9
|
|
4
|
-
filter_access_to :leads, :require => :read, :context => :admin
|
5
10
|
prepend_before_filter :set_leads_index_title, :only => :leads
|
11
|
+
prepend_before_filter :set_reports_index_title, :only => :reports
|
12
|
+
|
13
|
+
##
|
14
|
+
# Index/Reports Scopes
|
15
|
+
#
|
6
16
|
|
7
17
|
has_scope :leads, :only => :leads, :default => true
|
8
|
-
has_scope :leads, :except => :leads, :default => false
|
18
|
+
has_scope :leads, :except => [:leads, :reports], :default => false
|
19
|
+
|
20
|
+
|
21
|
+
##
|
22
|
+
# Reports scopes
|
23
|
+
#
|
24
|
+
|
25
|
+
has_scope :reports, :only => :reports, :type => :boolean, :default => true
|
26
|
+
|
27
|
+
has_scope :group, :only => :reports do |c, scope, value|
|
28
|
+
scope & Campaign.of_group(value)
|
29
|
+
end
|
30
|
+
|
31
|
+
has_scope :type, :only => :reports do |_, scope, value|
|
32
|
+
scope & Campaign.of_type("#{value}_campaign".classify)
|
33
|
+
end
|
34
|
+
|
35
|
+
has_scope :until_time, :as => :until, :unless => 'params[:from].present?'
|
36
|
+
|
37
|
+
has_scope :from_time, :as => :from do |controller, scope, value|
|
38
|
+
if controller.params[:until]
|
39
|
+
scope.for_time_range(value, controller.params[:until])
|
40
|
+
else
|
41
|
+
scope.from_time(value)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
##
|
47
|
+
# Actions
|
48
|
+
#
|
9
49
|
|
10
50
|
def leads
|
11
51
|
index!
|
12
52
|
end
|
13
53
|
|
54
|
+
def reports
|
55
|
+
index!
|
56
|
+
end
|
57
|
+
|
14
58
|
protected
|
15
59
|
|
60
|
+
def collection
|
61
|
+
get_collection_ivar || begin
|
62
|
+
set_collection_ivar(
|
63
|
+
if params[:action] == 'reports'
|
64
|
+
end_of_association_chain.all
|
65
|
+
else
|
66
|
+
end_of_association_chain.paginate(pagination_parameters)
|
67
|
+
end
|
68
|
+
)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
16
72
|
def set_leads_index_title
|
17
73
|
@index_title = I18n.t(:index_title, :scope => 'e9.e9_crm.leads')
|
18
74
|
end
|
75
|
+
|
76
|
+
def set_reports_index_title
|
77
|
+
@index_title = I18n.t(:index_title, :scope => 'e9.e9_crm.reports')
|
78
|
+
end
|
79
|
+
|
80
|
+
def ordered_if
|
81
|
+
%w(index reports).member? params[:action]
|
82
|
+
end
|
19
83
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
class E9Crm::PageViewsController < E9Crm::ResourcesController
|
2
2
|
defaults :resource_class => PageView
|
3
3
|
belongs_to :campaign, :contact, :polymorphic => true
|
4
|
+
include E9Rails::Controllers::Orderable
|
4
5
|
|
5
6
|
# NOTE association chain is prepended to ensure parent is loaded so other
|
6
7
|
# before filters can use collection_path, etc. Is there a better solution
|
@@ -1,10 +1,11 @@
|
|
1
1
|
class E9Crm::ResourcesController < E9Crm::BaseController
|
2
|
-
include E9Rails::Controllers::Orderable
|
3
2
|
include E9Rails::Helpers::ResourceErrorMessages
|
4
3
|
include E9Rails::Helpers::Pagination
|
5
4
|
|
6
5
|
inherit_resources
|
7
6
|
|
7
|
+
respond_to :js
|
8
|
+
|
8
9
|
add_resource_breadcrumbs
|
9
10
|
|
10
11
|
def self.defaults(hash = {})
|
@@ -1,14 +1,45 @@
|
|
1
1
|
module E9Crm::CampaignsHelper
|
2
|
-
def
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
2
|
+
def display_campaign_fee(val)
|
3
|
+
Money === val && val || 'n/a'
|
4
|
+
end
|
5
|
+
|
6
|
+
def display_campaign_code(val)
|
7
|
+
val || 'n/a'
|
8
|
+
end
|
9
|
+
|
10
|
+
def display_campaign_type(val)
|
11
|
+
val[/(.*)Campaign/, 1]
|
12
|
+
end
|
13
|
+
|
14
|
+
def campaign_type_select_options(with_all_option = true)
|
15
|
+
options = %w( advertising affiliate email sales ).map {|t| [t.titleize, t] }
|
16
|
+
options.unshift(['All Types', nil]) if with_all_option
|
17
|
+
options_for_select(options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def campaign_group_select_options
|
21
|
+
options = CampaignGroup.select('name, id').all.map {|c| [c.name, c.id] }
|
22
|
+
options.unshift(['All Groups', nil])
|
23
|
+
options_for_select(options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def campaign_date_select_options
|
27
|
+
''
|
28
|
+
end
|
29
|
+
|
30
|
+
def campaign_active_select_options
|
31
|
+
options = [
|
32
|
+
['All Statuses', nil],
|
33
|
+
['Active', true],
|
34
|
+
['Inactive', false]
|
35
|
+
]
|
36
|
+
options_for_select(options)
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# Accommodate for "NoCampaign" campaign in link
|
41
|
+
#
|
42
|
+
def link_to_edit_campaign(record)
|
43
|
+
link_to_edit_resource(record) unless record.is_a?(NoCampaign)
|
13
44
|
end
|
14
45
|
end
|
@@ -15,7 +15,7 @@ module E9Crm::ContactsHelper
|
|
15
15
|
def records_table_field_map_for_contact
|
16
16
|
{
|
17
17
|
:fields => {
|
18
|
-
:avatar => proc {|r| },
|
18
|
+
:avatar => proc {|r| "<img src=\"#{r.avatar_url}\" alt=\"Avatar for #{r.name}\" />".html_safe },
|
19
19
|
:details => proc {|r| render('details', :record => r) }
|
20
20
|
},
|
21
21
|
|
@@ -12,4 +12,29 @@ module E9Crm::DealsHelper
|
|
12
12
|
}
|
13
13
|
}
|
14
14
|
end
|
15
|
+
|
16
|
+
def deal_date_select_options(ending_month = false)
|
17
|
+
@_first_deal_date ||= Deal.order(:created_at).first.try(:created_at) || Date.today
|
18
|
+
|
19
|
+
date, cdate = @_first_deal_date, Date.today
|
20
|
+
|
21
|
+
options = []
|
22
|
+
|
23
|
+
if ending_month
|
24
|
+
prefix = 'Until'
|
25
|
+
label = prefix + ' Now'
|
26
|
+
else
|
27
|
+
prefix = 'From'
|
28
|
+
label = prefix + ' Inception'
|
29
|
+
end
|
30
|
+
|
31
|
+
begin
|
32
|
+
options << [date.strftime("#{prefix} %B %Y"), date.strftime('%Y/%m')]
|
33
|
+
date += 1.month
|
34
|
+
end while date.year <= cdate.year && date.month <= cdate.month
|
35
|
+
|
36
|
+
options.unshift([label, nil])
|
37
|
+
|
38
|
+
options_for_select(options)
|
39
|
+
end
|
15
40
|
end
|
data/app/models/campaign.rb
CHANGED
@@ -7,18 +7,50 @@ class Campaign < ActiveRecord::Base
|
|
7
7
|
include E9Rails::ActiveRecord::STI
|
8
8
|
|
9
9
|
belongs_to :campaign_group
|
10
|
-
|
11
|
-
has_many :
|
10
|
+
|
11
|
+
has_many :deals, :inverse_of => :campaign, :dependent => :nullify
|
12
|
+
has_many :won_deals, :class_name => 'Deal', :conditions => ['deals.status = ?', Deal::Status::Won]
|
13
|
+
has_many :lost_deals, :class_name => 'Deal', :conditions => ['deals.status = ?', Deal::Status::Lost]
|
14
|
+
has_many :pending_deals, :class_name => 'Deal', :conditions => ['deals.status = ?', Deal::Status::Pending]
|
15
|
+
has_many :leads, :class_name => 'Deal', :conditions => ['deals.status = ?', Deal::Status::Lead]
|
16
|
+
|
17
|
+
has_many :page_views, :inverse_of => :campaign, :dependent => :nullify
|
18
|
+
|
19
|
+
# only advertising campaigns use this association
|
20
|
+
has_many :dated_costs, :as => :costable
|
12
21
|
|
13
22
|
# NOTE tracking cookie code changes with new visits
|
14
|
-
has_many
|
23
|
+
has_many :tracking_cookies, :foreign_key => :code, :primary_key => :code, :class_name => 'TrackingCookie'
|
15
24
|
|
16
|
-
|
17
|
-
|
18
|
-
|
25
|
+
def self.default
|
26
|
+
NoCampaign.first || NoCampaign.create
|
27
|
+
end
|
19
28
|
|
20
|
-
|
21
|
-
|
29
|
+
validates :code, :presence => { :unless => lambda {|r| r.is_a?(NoCampaign) } },
|
30
|
+
:length => { :maximum => 32 },
|
31
|
+
:uniqueness => { :ignore_case => true, :allow_blank => true }
|
32
|
+
validates :affiliate_fee, :numericality => true
|
33
|
+
validates :sales_fee, :numericality => true
|
34
|
+
|
35
|
+
scope :active, lambda {|val=true| where(:active => val) }
|
36
|
+
scope :inactive, lambda { active(false) }
|
37
|
+
scope :of_group, lambda {|val| where(:campaign_group_id => val.to_param) }
|
38
|
+
|
39
|
+
def new_visit_session_count
|
40
|
+
page_views.new_visits.group(:session).count.keys.length
|
41
|
+
end
|
42
|
+
|
43
|
+
def new_visit_page_view_count
|
44
|
+
page_views.new_visits.group(:session).count.values.sum
|
45
|
+
end
|
46
|
+
|
47
|
+
def repeat_visit_session_count
|
48
|
+
page_views.repeat_visits.group(:session).count.keys.length
|
49
|
+
end
|
50
|
+
|
51
|
+
def repeat_visit_session_count
|
52
|
+
page_views.repeat_visits.group(:session).count.values.sum
|
53
|
+
end
|
22
54
|
|
23
55
|
##
|
24
56
|
# The sum cost of this campaign
|