e9_crm 0.1.1
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/.gitignore +3 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +105 -0
- data/README.md +31 -0
- data/Rakefile +2 -0
- data/app/controllers/e9_crm/advertising_campaigns_controller.rb +3 -0
- data/app/controllers/e9_crm/affiliate_campaigns_controller.rb +3 -0
- data/app/controllers/e9_crm/base_controller.rb +5 -0
- data/app/controllers/e9_crm/campaign_groups_controller.rb +3 -0
- data/app/controllers/e9_crm/campaigns_controller.rb +4 -0
- data/app/controllers/e9_crm/companies_controller.rb +3 -0
- data/app/controllers/e9_crm/contact_emails_controller.rb +38 -0
- data/app/controllers/e9_crm/contact_merges_controller.rb +26 -0
- data/app/controllers/e9_crm/contacts_controller.rb +46 -0
- data/app/controllers/e9_crm/dated_costs_controller.rb +4 -0
- data/app/controllers/e9_crm/deals_controller.rb +19 -0
- data/app/controllers/e9_crm/email_campaigns_controller.rb +3 -0
- data/app/controllers/e9_crm/email_templates.controller.rb +3 -0
- data/app/controllers/e9_crm/menu_options_controller.rb +26 -0
- data/app/controllers/e9_crm/offers_controller.rb +3 -0
- data/app/controllers/e9_crm/page_views_controller.rb +20 -0
- data/app/controllers/e9_crm/record_attributes_controller.rb +3 -0
- data/app/controllers/e9_crm/reports_controller.rb +2 -0
- data/app/controllers/e9_crm/resources_controller.rb +43 -0
- data/app/controllers/e9_crm/sales_campaigns_controller.rb +3 -0
- data/app/helpers/e9_crm/base_helper.rb +77 -0
- data/app/helpers/e9_crm/campaigns_helper.rb +14 -0
- data/app/helpers/e9_crm/contact_merges_helper.rb +17 -0
- data/app/helpers/e9_crm/contacts_helper.rb +27 -0
- data/app/helpers/e9_crm/deals_helper.rb +15 -0
- data/app/helpers/e9_crm/menu_options_helper.rb +11 -0
- data/app/helpers/e9_crm/page_views_helper.rb +2 -0
- data/app/models/address_attribute.rb +4 -0
- data/app/models/advertising_campaign.rb +15 -0
- data/app/models/affiliate.rb +4 -0
- data/app/models/affiliate_campaign.rb +15 -0
- data/app/models/campaign.rb +34 -0
- data/app/models/campaign_group.rb +5 -0
- data/app/models/company.rb +4 -0
- data/app/models/contact.rb +258 -0
- data/app/models/contact_email.rb +49 -0
- data/app/models/dated_cost.rb +9 -0
- data/app/models/deal.rb +83 -0
- data/app/models/email_campaign.rb +13 -0
- data/app/models/email_template.rb +7 -0
- data/app/models/instant_messaging_handle_attribute.rb +4 -0
- data/app/models/menu_option.rb +33 -0
- data/app/models/offer.rb +50 -0
- data/app/models/page_view.rb +80 -0
- data/app/models/phone_number_attribute.rb +4 -0
- data/app/models/record_attribute.rb +41 -0
- data/app/models/sales_campaign.rb +15 -0
- data/app/models/sales_person.rb +4 -0
- data/app/models/tracking_cookie.rb +61 -0
- data/app/models/website_attribute.rb +4 -0
- data/app/observers/deal_observer.rb +11 -0
- data/app/uploaders/file_uploader.rb +34 -0
- data/app/views/e9_crm/campaigns/_form_inner.html.haml +5 -0
- data/app/views/e9_crm/contact_emails/_form.html.haml +7 -0
- data/app/views/e9_crm/contact_emails/_form_inner.html.haml +11 -0
- data/app/views/e9_crm/contact_emails/destroy.js.erb +3 -0
- data/app/views/e9_crm/contact_emails/send_email.js.erb +1 -0
- data/app/views/e9_crm/contact_merges/_field.html.haml +10 -0
- data/app/views/e9_crm/contact_merges/_form.html.haml +10 -0
- data/app/views/e9_crm/contact_merges/new.html.haml +2 -0
- data/app/views/e9_crm/contacts/_details.html.haml +22 -0
- data/app/views/e9_crm/contacts/_form_inner.html.haml +51 -0
- data/app/views/e9_crm/contacts/_header.html.haml +19 -0
- data/app/views/e9_crm/contacts/_tag_table.html.haml +15 -0
- data/app/views/e9_crm/contacts/index.html.haml +13 -0
- data/app/views/e9_crm/contacts/index.js.erb +5 -0
- data/app/views/e9_crm/contacts/merge.html.haml +1 -0
- data/app/views/e9_crm/contacts/templates.js.erb +1 -0
- data/app/views/e9_crm/deals/_form_inner.html.haml +5 -0
- data/app/views/e9_crm/deals/_header.html.haml +0 -0
- data/app/views/e9_crm/deals/leads.html.haml +13 -0
- data/app/views/e9_crm/email_templates/_form_inner.html.haml +9 -0
- data/app/views/e9_crm/menu_options/_form_inner.html.haml +6 -0
- data/app/views/e9_crm/menu_options/_header.html.haml +8 -0
- data/app/views/e9_crm/offers/_form.html.haml +7 -0
- data/app/views/e9_crm/offers/_form_inner.html.haml +42 -0
- data/app/views/e9_crm/offers/_form_inner.html.haml.bak +43 -0
- data/app/views/e9_crm/page_views/_table.html.haml +25 -0
- data/app/views/e9_crm/record_attributes/_address_attribute.html.haml +5 -0
- data/app/views/e9_crm/record_attributes/_instant_messaging_handle_attribute.html.haml +5 -0
- data/app/views/e9_crm/record_attributes/_phone_number_attribute.html.haml +5 -0
- data/app/views/e9_crm/record_attributes/_record_attribute.html.haml +10 -0
- data/app/views/e9_crm/record_attributes/_templates.js.erb +12 -0
- data/app/views/e9_crm/record_attributes/_user.html.haml +23 -0
- data/app/views/e9_crm/record_attributes/_website_attribute.html.haml +5 -0
- data/app/views/e9_crm/resources/_footer.html.haml +1 -0
- data/app/views/e9_crm/resources/_form.html.haml +7 -0
- data/app/views/e9_crm/resources/_form_inner.html.haml +5 -0
- data/app/views/e9_crm/resources/_header.html.haml +0 -0
- data/app/views/e9_crm/resources/_table.html.haml +21 -0
- data/app/views/e9_crm/resources/create.js.erb +6 -0
- data/app/views/e9_crm/resources/destroy.js.erb +3 -0
- data/app/views/e9_crm/resources/edit.html.haml +2 -0
- data/app/views/e9_crm/resources/index.html.haml +13 -0
- data/app/views/e9_crm/resources/index.js.erb +1 -0
- data/app/views/e9_crm/resources/new.html.haml +2 -0
- data/app/views/e9_crm/resources/show.html.haml +2 -0
- data/app/views/e9_crm/resources/update.js.erb +5 -0
- data/config/initializers/inflections.rb +3 -0
- data/config/locales/e9.en.yml +28 -0
- data/config/locales/en.yml +63 -0
- data/config/routes.rb +61 -0
- data/e9_crm.gemspec +29 -0
- data/lib/e9_crm/model.rb +63 -0
- data/lib/e9_crm/rails_extensions.rb +98 -0
- data/lib/e9_crm/tracking_controller.rb +78 -0
- data/lib/e9_crm/version.rb +3 -0
- data/lib/e9_crm.rb +59 -0
- data/lib/generators/e9_crm/install_generator.rb +32 -0
- data/lib/generators/e9_crm/templates/create_e9_crm_tables.rb +107 -0
- data/lib/generators/e9_crm/templates/initializer.rb +4 -0
- data/lib/generators/e9_crm/templates/javascript.js +187 -0
- data/test/functional/e9_crm/campaign_types_controller_test.rb +49 -0
- data/test/functional/home_controller_test.rb +8 -0
- metadata +283 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
e9_crm (0.1.0)
|
|
5
|
+
e9_rails (~> 0.0.4)
|
|
6
|
+
e9_tags (~> 0.0.2)
|
|
7
|
+
has_scope
|
|
8
|
+
inherited_resources (~> 1.1.2)
|
|
9
|
+
money
|
|
10
|
+
rails (~> 3.0.0)
|
|
11
|
+
will_paginate
|
|
12
|
+
|
|
13
|
+
GEM
|
|
14
|
+
remote: http://rubygems.org/
|
|
15
|
+
specs:
|
|
16
|
+
abstract (1.0.0)
|
|
17
|
+
actionmailer (3.0.5)
|
|
18
|
+
actionpack (= 3.0.5)
|
|
19
|
+
mail (~> 2.2.15)
|
|
20
|
+
actionpack (3.0.5)
|
|
21
|
+
activemodel (= 3.0.5)
|
|
22
|
+
activesupport (= 3.0.5)
|
|
23
|
+
builder (~> 2.1.2)
|
|
24
|
+
erubis (~> 2.6.6)
|
|
25
|
+
i18n (~> 0.4)
|
|
26
|
+
rack (~> 1.2.1)
|
|
27
|
+
rack-mount (~> 0.6.13)
|
|
28
|
+
rack-test (~> 0.5.7)
|
|
29
|
+
tzinfo (~> 0.3.23)
|
|
30
|
+
activemodel (3.0.5)
|
|
31
|
+
activesupport (= 3.0.5)
|
|
32
|
+
builder (~> 2.1.2)
|
|
33
|
+
i18n (~> 0.4)
|
|
34
|
+
activerecord (3.0.5)
|
|
35
|
+
activemodel (= 3.0.5)
|
|
36
|
+
activesupport (= 3.0.5)
|
|
37
|
+
arel (~> 2.0.2)
|
|
38
|
+
tzinfo (~> 0.3.23)
|
|
39
|
+
activeresource (3.0.5)
|
|
40
|
+
activemodel (= 3.0.5)
|
|
41
|
+
activesupport (= 3.0.5)
|
|
42
|
+
activesupport (3.0.5)
|
|
43
|
+
acts-as-taggable-on (2.0.6)
|
|
44
|
+
arel (2.0.9)
|
|
45
|
+
builder (2.1.2)
|
|
46
|
+
e9_rails (0.0.4)
|
|
47
|
+
inherited_resources
|
|
48
|
+
rails (~> 3.0.0)
|
|
49
|
+
e9_tags (0.0.2)
|
|
50
|
+
acts-as-taggable-on (~> 2.0.6)
|
|
51
|
+
rails (~> 3.0.0)
|
|
52
|
+
erubis (2.6.6)
|
|
53
|
+
abstract (>= 1.0.0)
|
|
54
|
+
has_scope (0.5.0)
|
|
55
|
+
i18n (0.5.0)
|
|
56
|
+
inherited_resources (1.1.2)
|
|
57
|
+
has_scope (~> 0.5.0)
|
|
58
|
+
responders (~> 0.6.0)
|
|
59
|
+
mail (2.2.15)
|
|
60
|
+
activesupport (>= 2.3.6)
|
|
61
|
+
i18n (>= 0.4.0)
|
|
62
|
+
mime-types (~> 1.16)
|
|
63
|
+
treetop (~> 1.4.8)
|
|
64
|
+
mime-types (1.16)
|
|
65
|
+
money (3.6.1)
|
|
66
|
+
i18n (~> 0.4)
|
|
67
|
+
polyglot (0.3.1)
|
|
68
|
+
rack (1.2.1)
|
|
69
|
+
rack-mount (0.6.13)
|
|
70
|
+
rack (>= 1.0.0)
|
|
71
|
+
rack-test (0.5.7)
|
|
72
|
+
rack (>= 1.0)
|
|
73
|
+
rails (3.0.5)
|
|
74
|
+
actionmailer (= 3.0.5)
|
|
75
|
+
actionpack (= 3.0.5)
|
|
76
|
+
activerecord (= 3.0.5)
|
|
77
|
+
activeresource (= 3.0.5)
|
|
78
|
+
activesupport (= 3.0.5)
|
|
79
|
+
bundler (~> 1.0)
|
|
80
|
+
railties (= 3.0.5)
|
|
81
|
+
railties (3.0.5)
|
|
82
|
+
actionpack (= 3.0.5)
|
|
83
|
+
activesupport (= 3.0.5)
|
|
84
|
+
rake (>= 0.8.7)
|
|
85
|
+
thor (~> 0.14.4)
|
|
86
|
+
rake (0.8.7)
|
|
87
|
+
responders (0.6.2)
|
|
88
|
+
thor (0.14.6)
|
|
89
|
+
treetop (1.4.9)
|
|
90
|
+
polyglot (>= 0.3.1)
|
|
91
|
+
tzinfo (0.3.24)
|
|
92
|
+
will_paginate (2.3.15)
|
|
93
|
+
|
|
94
|
+
PLATFORMS
|
|
95
|
+
ruby
|
|
96
|
+
|
|
97
|
+
DEPENDENCIES
|
|
98
|
+
e9_crm!
|
|
99
|
+
e9_rails (~> 0.0.4)
|
|
100
|
+
e9_tags (~> 0.0.2)
|
|
101
|
+
has_scope
|
|
102
|
+
inherited_resources (~> 1.1.2)
|
|
103
|
+
money
|
|
104
|
+
rails (~> 3.0.0)
|
|
105
|
+
will_paginate
|
data/README.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
CRM Plugin for the e9 CMS
|
|
2
|
+
=========================
|
|
3
|
+
|
|
4
|
+
It should be noted that while this plugin is intended for use in the
|
|
5
|
+
e9 CMS, it does neither includes nor requires it.
|
|
6
|
+
|
|
7
|
+
To use, add as a gem and install by running:
|
|
8
|
+
|
|
9
|
+
rails g e9_crm:install
|
|
10
|
+
|
|
11
|
+
Then modify the installed initializer as per your app, including
|
|
12
|
+
the controller module in your desired controllers, with the final
|
|
13
|
+
result looking something like this:
|
|
14
|
+
|
|
15
|
+
require 'e9_crm'
|
|
16
|
+
|
|
17
|
+
User.send :include, E9Crm::Backend::ActiveRecord
|
|
18
|
+
|
|
19
|
+
Rails.configuration.after_initialize do
|
|
20
|
+
[
|
|
21
|
+
MyFirstTrackedController,
|
|
22
|
+
MySecondTrackedController
|
|
23
|
+
].each {|c| c.send(:include, E9Crm::TrackingController) }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
NOTE: A few assumptions are made:
|
|
27
|
+
---------------------------------
|
|
28
|
+
|
|
29
|
+
1. Your app has a "User" model
|
|
30
|
+
2. Your app has a controller method #current_user to return the
|
|
31
|
+
currently logged in user.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
class E9Crm::ContactEmailsController < E9Crm::ResourcesController
|
|
2
|
+
defaults
|
|
3
|
+
|
|
4
|
+
respond_to :js, :html
|
|
5
|
+
|
|
6
|
+
def create
|
|
7
|
+
create! do |success, failure|
|
|
8
|
+
success.html { redirect_to :admin_sent_email }
|
|
9
|
+
success.js { head :ok }
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
protected
|
|
14
|
+
|
|
15
|
+
def build_resource
|
|
16
|
+
get_resource_ivar || begin
|
|
17
|
+
object = if params[resource_instance_name]
|
|
18
|
+
ContactEmail.new(params[resource_instance_name] || {})
|
|
19
|
+
else
|
|
20
|
+
ContactEmail.new_from_template(template, :from_email => current_user.email, :user_ids => params[:uids])
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# we set the user_ids.blank? error right away signifiying a problem,
|
|
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
|
|
28
|
+
|
|
29
|
+
set_resource_ivar(object)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# throw record_not_found if there's no template. #new requires email_template_id
|
|
34
|
+
# be passed in params (and also user_ids)
|
|
35
|
+
def template
|
|
36
|
+
@_template ||= EmailTemplate.find(params[:etid])
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
class E9Crm::ContactMergesController < E9Crm::BaseController
|
|
2
|
+
before_filter :build_resources
|
|
3
|
+
|
|
4
|
+
def create
|
|
5
|
+
if @contact_a.update_attributes(params[:contact])
|
|
6
|
+
@contact_a.merge_and_destroy!(@contact_b)
|
|
7
|
+
redirect_to @contact_a
|
|
8
|
+
else
|
|
9
|
+
render :new
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
protected
|
|
14
|
+
|
|
15
|
+
def build_resources
|
|
16
|
+
@contact ||= Contact.new
|
|
17
|
+
@contact_a ||= Contact.find(params[:contact_a_id])
|
|
18
|
+
|
|
19
|
+
# NOTE lets see if this works
|
|
20
|
+
@contact_b ||= if params[:contact]
|
|
21
|
+
Contact.new(params[:contact])
|
|
22
|
+
else
|
|
23
|
+
Contact.find(params[:contact_b_id])
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
class E9Crm::ContactsController < E9Crm::ResourcesController
|
|
2
|
+
defaults :resource_class => Contact
|
|
3
|
+
|
|
4
|
+
include E9Tags::Controller
|
|
5
|
+
|
|
6
|
+
respond_to :js, :html
|
|
7
|
+
|
|
8
|
+
before_filter :determine_title, :only => :index
|
|
9
|
+
before_filter :load_user_ids, :only => :index
|
|
10
|
+
|
|
11
|
+
has_scope :search, :by_title, :by_company, :only => :index
|
|
12
|
+
has_scope :tagged, :only => :index, :type => :array
|
|
13
|
+
|
|
14
|
+
# record attributes templates js
|
|
15
|
+
skip_before_filter :authenticate_user!, :filter_access_filter, :only => :templates
|
|
16
|
+
before_filter :build_resource, :only => :templates
|
|
17
|
+
caches_action :templates
|
|
18
|
+
|
|
19
|
+
protected
|
|
20
|
+
|
|
21
|
+
def load_user_ids
|
|
22
|
+
@user_ids ||= begin
|
|
23
|
+
(User.primary.joins(:contact) & end_of_association_chain.scoped).all.map(&:id)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def determine_title
|
|
28
|
+
params.delete(:search) if params[:search].blank?
|
|
29
|
+
|
|
30
|
+
@index_title ||= if params[:tagged] && params[:search]
|
|
31
|
+
e9_t(:index_title_with_search_and_tags, :tagged => params[:tagged].join(' or '), :search => params[:search])
|
|
32
|
+
elsif params[:tagged]
|
|
33
|
+
e9_t(:index_title_with_tags, :tagged => params[:tagged].join(' or '))
|
|
34
|
+
elsif params[:search]
|
|
35
|
+
e9_t(:index_title_with_search, :search => params[:search])
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def default_ordered_on
|
|
40
|
+
'first_name'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def default_ordered_at
|
|
44
|
+
'ASC'
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
class E9Crm::DealsController < E9Crm::ResourcesController
|
|
2
|
+
defaults :resource_class => Deal
|
|
3
|
+
|
|
4
|
+
filter_access_to :leads, :require => :read, :context => :admin
|
|
5
|
+
prepend_before_filter :set_leads_index_title, :only => :leads
|
|
6
|
+
|
|
7
|
+
has_scope :leads, :only => :leads, :default => true
|
|
8
|
+
has_scope :leads, :except => :leads, :default => false
|
|
9
|
+
|
|
10
|
+
def leads
|
|
11
|
+
index!
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
protected
|
|
15
|
+
|
|
16
|
+
def set_leads_index_title
|
|
17
|
+
@index_title = I18n.t(:index_title, :scope => 'e9.e9_crm.leads')
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
class E9Crm::MenuOptionsController < E9Crm::ResourcesController
|
|
2
|
+
defaults :resource_class => MenuOption
|
|
3
|
+
include E9Rails::Controllers::Sortable
|
|
4
|
+
|
|
5
|
+
has_scope :options_for, :as => :key, :only => :index
|
|
6
|
+
|
|
7
|
+
# NOTE The reason this is set in a filter instead of just a default scope value
|
|
8
|
+
# is that it is used in the index view to add the key param to the new
|
|
9
|
+
# resource link
|
|
10
|
+
#
|
|
11
|
+
before_filter :ensure_default_fetch_key, :only => :index
|
|
12
|
+
|
|
13
|
+
def create
|
|
14
|
+
create! { collection_path(:key => resource.key) }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def update
|
|
18
|
+
update! { collection_path(:key => resource.key) }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
protected
|
|
22
|
+
|
|
23
|
+
def ensure_default_fetch_key
|
|
24
|
+
params[:key] ||= MenuOption::KEYS.sort.first
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
class E9Crm::PageViewsController < E9Crm::ResourcesController
|
|
2
|
+
defaults :resource_class => PageView
|
|
3
|
+
belongs_to :campaign, :contact, :polymorphic => true
|
|
4
|
+
|
|
5
|
+
# NOTE association chain is prepended to ensure parent is loaded so other
|
|
6
|
+
# before filters can use collection_path, etc. Is there a better solution
|
|
7
|
+
# for this?
|
|
8
|
+
#
|
|
9
|
+
prepend_before_filter :association_chain
|
|
10
|
+
|
|
11
|
+
has_scope :until_time, :as => :until, :unless => 'params[:from].present?'
|
|
12
|
+
|
|
13
|
+
has_scope :from_time, :as => :from do |controller, scope, value|
|
|
14
|
+
if controller.params[:until]
|
|
15
|
+
scope.for_time_range(value, controller.params[:until])
|
|
16
|
+
else
|
|
17
|
+
scope.from_time(value)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
class E9Crm::ResourcesController < E9Crm::BaseController
|
|
2
|
+
include E9Rails::Controllers::Orderable
|
|
3
|
+
include E9Rails::Helpers::ResourceErrorMessages
|
|
4
|
+
include E9Rails::Helpers::Pagination
|
|
5
|
+
|
|
6
|
+
inherit_resources
|
|
7
|
+
|
|
8
|
+
add_resource_breadcrumbs
|
|
9
|
+
|
|
10
|
+
def self.defaults(hash = {})
|
|
11
|
+
super(hash.reverse_merge(:route_prefix => nil))
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def create
|
|
15
|
+
create! { collection_path }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def update
|
|
19
|
+
update! { collection_path }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
protected
|
|
23
|
+
|
|
24
|
+
# NOTE parent is defined so it's always available, it will be overridden on controllers which have belongs_to routes
|
|
25
|
+
def parent; end
|
|
26
|
+
helper_method :parent
|
|
27
|
+
|
|
28
|
+
def add_index_breadcrumb
|
|
29
|
+
add_breadcrumb! @index_title || e9_t(:index_title), collection_path
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def collection
|
|
33
|
+
get_collection_ivar || set_collection_ivar(end_of_association_chain.paginate(pagination_parameters))
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def default_ordered_on
|
|
37
|
+
'created_at'
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def default_ordered_dir
|
|
41
|
+
'DESC'
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
module E9Crm::BaseHelper
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# Field maps
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
def records_table_field_map(options = {})
|
|
8
|
+
options.symbolize_keys!
|
|
9
|
+
options.reverse_merge!(:class_name => resource_class.base_class.name.underscore)
|
|
10
|
+
|
|
11
|
+
base_map = {
|
|
12
|
+
:fields => { :id => nil },
|
|
13
|
+
:links => lambda {|r| [link_to_edit_resource(r), link_to_destroy_resource(r)] }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
method_name = "records_table_field_map_for_#{options[:class_name]}"
|
|
17
|
+
|
|
18
|
+
if respond_to?(method_name)
|
|
19
|
+
base_map.merge! send(method_name)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
base_map
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
# Misc
|
|
28
|
+
#
|
|
29
|
+
|
|
30
|
+
def link_to_add_record_attribute(association_name)
|
|
31
|
+
link_to(
|
|
32
|
+
t(:add_record_attribute, :scope => :e9_crm),
|
|
33
|
+
'javascript:;',
|
|
34
|
+
:class => 'add-nested-association',
|
|
35
|
+
'data-association' => association_name
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def link_to_destroy_record_attribute
|
|
40
|
+
link_to(
|
|
41
|
+
t(:destroy_record_attribute, :scope => :e9_crm),
|
|
42
|
+
'javascript:;',
|
|
43
|
+
:class => 'destroy-nested-association'
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def render_record_attribute_association(association_name, form, options = {})
|
|
48
|
+
options.symbolize_keys!
|
|
49
|
+
|
|
50
|
+
association = resource.send(association_name)
|
|
51
|
+
|
|
52
|
+
unless association.empty?
|
|
53
|
+
form.fields_for(association_name) do |f|
|
|
54
|
+
concat record_attribute_template(association_name, f, options)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def record_attribute_template(association_name, builder, options = {})
|
|
60
|
+
options.symbolize_keys!
|
|
61
|
+
|
|
62
|
+
render({
|
|
63
|
+
:partial => options[:partial] || "e9_crm/record_attributes/#{association_name.to_s.singularize}",
|
|
64
|
+
:locals => { :f => builder }
|
|
65
|
+
})
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def build_associated_resource(association_name)
|
|
69
|
+
params_method = "#{association_name}_build_parameters"
|
|
70
|
+
build_params = resource_class.send(params_method) if resource_class.respond_to?(params_method)
|
|
71
|
+
resource.send(association_name).build(build_params || {})
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def sortable_controller?
|
|
75
|
+
@_sortable_controller ||= controller.class.ancestors.member?(E9Rails::Controllers::Sortable)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module E9Crm::CampaignsHelper
|
|
2
|
+
def records_table_map_for_campaign
|
|
3
|
+
{
|
|
4
|
+
:fields => {
|
|
5
|
+
:type => nil,
|
|
6
|
+
:name => nil,
|
|
7
|
+
:code => nil,
|
|
8
|
+
:affiliate_fee => proc {|r| v = r.affiliate_fee; Money === v ? v : 'n/a' },
|
|
9
|
+
:sales_fee => nil,
|
|
10
|
+
:status => proc {|r| resource_class.human_attribute_name(Campaign::Status::VALUES[r.status]) }
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module E9Crm::ContactMergesHelper
|
|
2
|
+
def contact_a(field_name)
|
|
3
|
+
@_contact_a_vals ||= {}
|
|
4
|
+
@_contact_a_vals[field_name] ||= merge_contact_val(@contact_a, field_name)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def contact_b(field_name)
|
|
8
|
+
@_contact_b_vals ||= {}
|
|
9
|
+
@_contact_b_vals[field_name] ||= merge_contact_val(@contact_b, field_name)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def merge_contact_val(obj, field_name)
|
|
13
|
+
# return '' here rather than nil so inputs will have a value, otherwise checked
|
|
14
|
+
# with no value ends up being interpreted as "on"
|
|
15
|
+
obj.send(field_name) || ''
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module E9Crm::ContactsHelper
|
|
2
|
+
|
|
3
|
+
def link_to_contact_search(attribute, query, text = nil)
|
|
4
|
+
link_to(text || query, contacts_path(attribute => query), :class => "contact-search contact-#{attribute.to_s.dasherize}-search")
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def contact_email_template_select_options
|
|
8
|
+
options_for_select( EmailTemplate.order('name').map {|e| [e.name, e.id] })
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def contact_newsletter_select_options
|
|
12
|
+
options_for_select( UserEmail.pending.order('name').map {|e| [e.name, e.id] })
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def records_table_field_map_for_contact
|
|
16
|
+
{
|
|
17
|
+
:fields => {
|
|
18
|
+
:avatar => proc {|r| },
|
|
19
|
+
:details => proc {|r| render('details', :record => r) }
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
:links => proc {|r|
|
|
23
|
+
[link_to_show_resource(r), link_to_edit_resource(r), link_to_destroy_resource(r)]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# An ad driven campaign.
|
|
2
|
+
#
|
|
3
|
+
# Unique from other campaigns in that their cost is derived from associated
|
|
4
|
+
# DatedCost records.
|
|
5
|
+
#
|
|
6
|
+
class AdvertisingCampaign < Campaign
|
|
7
|
+
has_many :dated_costs, :as => :costable
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
# The sum cost of this campaign
|
|
11
|
+
#
|
|
12
|
+
def cost
|
|
13
|
+
Money.new(dated_costs.sum(:cost))
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# An affiliate campaign
|
|
2
|
+
#
|
|
3
|
+
# Carries an affiliate fee (and sales fee)
|
|
4
|
+
#
|
|
5
|
+
class AffiliateCampaign < SalesCampaign
|
|
6
|
+
money_columns :affiliate_fee
|
|
7
|
+
belongs_to :affiliate
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
# The sum cost of this campaign
|
|
11
|
+
#
|
|
12
|
+
def cost
|
|
13
|
+
super + affiliate_fee
|
|
14
|
+
end
|
|
15
|
+
end
|