e9_crm 0.1.18 → 0.1.19
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/deals_controller.rb +1 -1
- data/app/controllers/e9_crm/offers_controller.rb +6 -5
- data/app/helpers/e9_crm/base_helper.rb +0 -64
- data/app/helpers/e9_crm/deals_helper.rb +1 -1
- data/app/helpers/e9_crm/offers_helper.rb +9 -4
- data/app/models/campaign.rb +7 -7
- data/app/models/dated_cost.rb +1 -1
- data/app/models/deal.rb +74 -101
- data/app/models/offer.rb +12 -4
- data/app/models/sales_campaign.rb +5 -0
- data/app/views/e9_crm/contacts/_index_sidebar.html.haml +9 -1
- data/app/views/e9_crm/deals/_form_inner.html.haml +1 -4
- data/app/views/e9_crm/deals/_leads_table.html.haml +1 -4
- data/app/views/e9_crm/deals/_table.html.haml +0 -3
- data/app/views/e9_crm/leads/_form.html.haml +2 -2
- data/app/views/e9_crm/leads/create.js.erb +1 -6
- data/app/views/e9_crm/offers/_form_inner.html.haml +20 -9
- data/app/views/e9_crm/offers/_header.html.haml +1 -5
- data/app/views/e9_crm/offers/_public_offer.html.haml +0 -4
- data/app/views/e9_crm/resources/index.html.haml +3 -0
- data/config/locales/en.yml +5 -1
- data/config/routes.rb +1 -16
- data/e9_crm.gemspec +1 -0
- data/lib/e9_crm/system_emails_controller.rb +27 -0
- data/lib/e9_crm/version.rb +1 -1
- data/lib/e9_crm.rb +2 -0
- metadata +14 -19
- data/app/controllers/e9_crm/contact_offers_controller.rb +0 -3
- data/app/controllers/e9_crm/file_download_offers_controller.rb +0 -3
- data/app/controllers/e9_crm/new_content_subscription_offers_controller.rb +0 -3
- data/app/controllers/e9_crm/newsletter_subscription_offers_controller.rb +0 -3
- data/app/controllers/e9_crm/offer_subclass_controller.rb +0 -11
- data/app/controllers/e9_crm/video_offers_controller.rb +0 -3
- data/app/models/contact_offer.rb +0 -2
- data/app/models/file_download_offer.rb +0 -2
- data/app/models/new_content_subscription_offer.rb +0 -5
- data/app/models/newsletter_subscription_offer.rb +0 -5
- data/app/models/subscription_offer.rb +0 -3
- data/app/models/video_offer.rb +0 -2
- data/app/views/e9_crm/contact_offers/_form_inner.html.haml +0 -5
- data/app/views/e9_crm/new_content_subscription_offers/_form_inner.html.haml +0 -1
- data/app/views/e9_crm/newsletter_subscription_offers/_form_inner.html.haml +0 -1
- data/app/views/e9_crm/subscription_offers/_form_inner.html.haml +0 -5
- data/app/views/e9_crm/video_offers/_form_inner.html.haml +0 -5
@@ -7,7 +7,7 @@ class E9Crm::DealsController < E9Crm::ResourcesController
|
|
7
7
|
|
8
8
|
filter_access_to :leads, :reports, :require => :read, :context => :admin
|
9
9
|
|
10
|
-
skip_after_filter :flash_to_headers
|
10
|
+
skip_after_filter :flash_to_headers, :except => :destroy
|
11
11
|
|
12
12
|
prepend_before_filter :set_leads_index_title, :only => :leads
|
13
13
|
prepend_before_filter :set_reports_index_title, :only => :reports
|
@@ -7,6 +7,7 @@ class E9Crm::OffersController < E9Crm::ResourcesController
|
|
7
7
|
skip_before_filter :authenticate_user!, :filter_access_filter, :only => :show
|
8
8
|
|
9
9
|
before_filter :throw_forbidden_unless_offer_cookied, :only => :show
|
10
|
+
before_filter :ensure_mailing_list_ids, :only => [:create, :update]
|
10
11
|
|
11
12
|
has_scope :of_type, :as => :type, :only => :index do |_, scope, value|
|
12
13
|
scope.of_type("#{value}_offer".classify)
|
@@ -29,11 +30,7 @@ class E9Crm::OffersController < E9Crm::ResourcesController
|
|
29
30
|
end
|
30
31
|
|
31
32
|
def find_current_page
|
32
|
-
|
33
|
-
super
|
34
|
-
else
|
35
|
-
@current_page ||= Offer.page || super
|
36
|
-
end
|
33
|
+
@current_page ||= params[:action] == 'show' && Offer.page || super
|
37
34
|
end
|
38
35
|
|
39
36
|
def determine_layout
|
@@ -47,4 +44,8 @@ class E9Crm::OffersController < E9Crm::ResourcesController
|
|
47
44
|
def default_ordered_dir
|
48
45
|
:ASC
|
49
46
|
end
|
47
|
+
|
48
|
+
def ensure_mailing_list_ids
|
49
|
+
params[:offer][:mailing_list_ids] ||= []
|
50
|
+
end
|
50
51
|
end
|
@@ -1,11 +1,5 @@
|
|
1
1
|
module E9Crm::BaseHelper
|
2
2
|
|
3
|
-
#def kramdown(string)
|
4
|
-
#Kramdown::Document.new(string).to_html.html_safe
|
5
|
-
#end
|
6
|
-
|
7
|
-
#alias :k :kramdown
|
8
|
-
|
9
3
|
##
|
10
4
|
# Field maps
|
11
5
|
#
|
@@ -28,64 +22,6 @@ module E9Crm::BaseHelper
|
|
28
22
|
base_map
|
29
23
|
end
|
30
24
|
|
31
|
-
|
32
|
-
##
|
33
|
-
# Misc
|
34
|
-
#
|
35
|
-
|
36
|
-
#def link_to_add_record_attribute(association_name)
|
37
|
-
#link_to(
|
38
|
-
#t(:add_record_attribute, :scope => :e9_crm),
|
39
|
-
#'javascript:;',
|
40
|
-
#:class => 'add-nested-association',
|
41
|
-
#'data-association' => association_name
|
42
|
-
#)
|
43
|
-
#end
|
44
|
-
|
45
|
-
#def link_to_destroy_record_attribute
|
46
|
-
#link_to(
|
47
|
-
#t(:destroy_record_attribute, :scope => :e9_crm),
|
48
|
-
#'javascript:;',
|
49
|
-
#:class => 'destroy-nested-association'
|
50
|
-
#)
|
51
|
-
#end
|
52
|
-
|
53
|
-
#def render_record_attribute_form(association_name, form)
|
54
|
-
#render('e9_crm/record_attributes/form_partial', {
|
55
|
-
#:form => form,
|
56
|
-
#:association_name => association_name
|
57
|
-
#})
|
58
|
-
#end
|
59
|
-
|
60
|
-
#def render_record_attribute_association(association_name, form, options = {})
|
61
|
-
#options.symbolize_keys!
|
62
|
-
|
63
|
-
#association = resource.send(association_name)
|
64
|
-
|
65
|
-
#unless association.empty?
|
66
|
-
#form.fields_for(association_name) do |f|
|
67
|
-
#concat record_attribute_template(association_name, f, options)
|
68
|
-
#end
|
69
|
-
#end
|
70
|
-
#end
|
71
|
-
|
72
|
-
#def record_attribute_template(association_name, builder, options = {})
|
73
|
-
#options.symbolize_keys!
|
74
|
-
|
75
|
-
#render(
|
76
|
-
#:partial => options[:partial] || "e9_crm/record_attributes/#{association_name.to_s.singularize}",
|
77
|
-
#:locals => { :f => builder }
|
78
|
-
#)
|
79
|
-
#end
|
80
|
-
|
81
|
-
## tries to build an associated resource, looking to the assocatiaon's model for a method
|
82
|
-
## named "%{association_name}_build_parameters}" first for any default params
|
83
|
-
#def build_associated_resource(association_name)
|
84
|
-
#params_method = "#{association_name}_build_parameters"
|
85
|
-
#build_params = resource_class.send(params_method) if resource_class.respond_to?(params_method)
|
86
|
-
#resource.send(association_name).build(build_params || {})
|
87
|
-
#end
|
88
|
-
|
89
25
|
def sortable_controller?
|
90
26
|
@_sortable_controller ||= controller.class.ancestors.member?(E9Rails::Controllers::Sortable)
|
91
27
|
end
|
@@ -24,7 +24,7 @@ module E9Crm::DealsHelper
|
|
24
24
|
|
25
25
|
def deal_category_select_options
|
26
26
|
@_deal_category_select_options ||= begin
|
27
|
-
options = MenuOption.options_for('Deal Category')
|
27
|
+
options = MenuOption.options_for('Deal Category')
|
28
28
|
options.unshift ['All Categories', nil]
|
29
29
|
options_for_select(options)
|
30
30
|
end
|
@@ -1,13 +1,18 @@
|
|
1
1
|
module E9Crm::OffersHelper
|
2
2
|
def records_table_field_map_for_offer
|
3
3
|
{
|
4
|
-
:fields => {
|
5
|
-
:name => nil,
|
6
|
-
:type => lambda {|r| r.class.model_name.human }
|
7
|
-
}
|
4
|
+
:fields => { :name => nil }
|
8
5
|
}
|
9
6
|
end
|
10
7
|
|
8
|
+
def offer_mailing_lists
|
9
|
+
@_offer_mailing_lists ||= begin
|
10
|
+
retv = MailingList.newsletters.all
|
11
|
+
retv << MailingList.new_content_alerts
|
12
|
+
retv.compact
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
11
16
|
def offer_select_options(with_all_option = true)
|
12
17
|
options = %w(contact file_download new_content_subscription newsletter_subscription video).map {|t| [t.titleize, t] }
|
13
18
|
options.unshift(['All Types', nil]) if with_all_option
|
data/app/models/campaign.rb
CHANGED
@@ -8,13 +8,13 @@ class Campaign < ActiveRecord::Base
|
|
8
8
|
|
9
9
|
belongs_to :campaign_group
|
10
10
|
|
11
|
-
has_many
|
12
|
-
has_many
|
13
|
-
has_many
|
14
|
-
has_many
|
15
|
-
has_many
|
16
|
-
has_many
|
17
|
-
has_many
|
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
|
+
has_many :non_leads, :class_name => 'Deal', :conditions => ['deals.status != ?', Deal::Status::Lead]
|
17
|
+
has_many :page_views, :inverse_of => :campaign, :dependent => :nullify
|
18
18
|
|
19
19
|
# only advertising campaigns use this association
|
20
20
|
has_many :dated_costs, :as => :costable
|
data/app/models/dated_cost.rb
CHANGED
@@ -8,7 +8,7 @@ class DatedCost < ActiveRecord::Base
|
|
8
8
|
money_columns :cost
|
9
9
|
belongs_to :costable, :polymorphic => true
|
10
10
|
validates :date, :date => true
|
11
|
-
validates :cost, :numericality =>
|
11
|
+
validates :cost, :numericality => true
|
12
12
|
|
13
13
|
attr_accessor :temp_id
|
14
14
|
|
data/app/models/deal.rb
CHANGED
@@ -13,24 +13,28 @@ class Deal < ActiveRecord::Base
|
|
13
13
|
belongs_to :user
|
14
14
|
|
15
15
|
belongs_to :owner, :class_name => 'Contact', :foreign_key => :contact_id
|
16
|
+
belongs_to :dated_cost, :dependent => :delete
|
17
|
+
|
16
18
|
has_and_belongs_to_many :contacts
|
17
19
|
|
18
20
|
money_columns :value
|
19
21
|
|
20
22
|
validates :value, :numericality => true
|
21
23
|
validates :campaign, :presence => true
|
24
|
+
validate do |record|
|
25
|
+
if !Status::OPTIONS.include?(record.status)
|
26
|
+
record.errors.add(:status, :inclusion, :options => Status::OPTIONS)
|
27
|
+
elsif record.status_changed? && record.won? || record.lost? and record.status_was == Status::Lead
|
28
|
+
record.errors.add(:status, :illegal_conversion)
|
29
|
+
end
|
30
|
+
end
|
22
31
|
|
23
32
|
# non-lead validations (deals in the admin)
|
24
|
-
|
25
|
-
validates :name, :presence => { :unless => lambda {|r| r.lead? } }
|
33
|
+
validates :name, :presence => true, :unless => lambda {|r| r.lead? }
|
26
34
|
|
27
35
|
# lead only validations
|
28
|
-
|
29
|
-
validates :
|
30
|
-
validates :lead_email, :presence => { :if => lambda {|r| r.lead? } }
|
31
|
-
|
32
|
-
# NOTE should offer be validated?
|
33
|
-
#validates :offer, :presence => { :if => lambda {|r| r.lead? } }
|
36
|
+
validates :lead_name, :presence => true, :if => lambda {|r| r.lead? }
|
37
|
+
validates :lead_email, :presence => true, :email => { :allow_blank => true }, :if => lambda {|r| r.lead? }
|
34
38
|
|
35
39
|
# If a lead with a user, get the lead_name and lead_email from the user before validation
|
36
40
|
before_validation :get_name_and_email_from_user, :on => :create
|
@@ -39,14 +43,15 @@ class Deal < ActiveRecord::Base
|
|
39
43
|
# copy temp options over into info column
|
40
44
|
before_create :transform_options_column
|
41
45
|
|
46
|
+
# If a lead with no user, find the user by email or create it, then if mailing_lists
|
47
|
+
# were passed, assign the user those mailing lists
|
48
|
+
after_create :handle_lead_creation, :if => lambda {|r| r.lead? }
|
49
|
+
|
42
50
|
# denormalize campaign code and offer name columns
|
43
51
|
before_save :ensure_denormalized_columns
|
44
52
|
before_save :ensure_associated_campaign
|
45
|
-
|
46
|
-
|
47
|
-
# were passed, assign the user those mailing lists
|
48
|
-
after_create :handle_user_if_lead
|
49
|
-
after_create :send_offer_conversion_email_if_lead
|
53
|
+
before_save :handle_status_conversion, :if => lambda {|r| r.status_changed? }
|
54
|
+
before_save :handle_dated_cost, :if => lambda {|r| r.status_changed? || r.campaign_id_changed? }
|
50
55
|
|
51
56
|
# money column definitions for pseudo attributes (added on the reports scope)
|
52
57
|
%w(total_value average_value total_cost average_cost).each do |money_column|
|
@@ -73,38 +78,17 @@ class Deal < ActiveRecord::Base
|
|
73
78
|
campaigns.name campaign_name,
|
74
79
|
campaigns.new_visits new_visits,
|
75
80
|
campaigns.repeat_visits repeat_visits,
|
76
|
-
|
77
81
|
deals.closed_at closed_at,
|
78
82
|
deals.created_at created_at,
|
79
|
-
|
80
83
|
campaign_groups.name campaign_group,
|
81
84
|
SUM(IF(deals.status != 'lead',1,0)) deal_count,
|
82
85
|
COUNT(deals.id) lead_count,
|
83
86
|
SUM(IF(deals.status='won',1,0)) won_deal_count,
|
84
87
|
SUM(IF(deals.status='won',deals.value,0)) total_value,
|
85
88
|
AVG(IF(deals.status='won',deals.value,NULL)) average_value,
|
86
|
-
SUM(
|
87
|
-
|
88
|
-
|
89
|
-
WHEN "SalesCampaign"
|
90
|
-
THEN campaigns.sales_fee
|
91
|
-
WHEN "AffiliateCampaign"
|
92
|
-
THEN campaigns.sales_fee +
|
93
|
-
campaigns.affiliate_fee
|
94
|
-
ELSE
|
95
|
-
0
|
96
|
-
END) total_cost,
|
97
|
-
SUM(CASE campaigns.type
|
98
|
-
WHEN "AdvertisingCampaign"
|
99
|
-
THEN dated_costs.cost
|
100
|
-
WHEN "SalesCampaign"
|
101
|
-
THEN campaigns.sales_fee
|
102
|
-
WHEN "AffiliateCampaign"
|
103
|
-
THEN campaigns.sales_fee +
|
104
|
-
campaigns.affiliate_fee
|
105
|
-
ELSE
|
106
|
-
0
|
107
|
-
END) / SUM(IF(deals.status='won',1,0)) average_cost,
|
89
|
+
SUM(dated_costs.cost) total_cost,
|
90
|
+
SUM(dated_costs.cost) /
|
91
|
+
SUM(IF(deals.status='won',1,0)) average_cost,
|
108
92
|
FLOOR(AVG(
|
109
93
|
DATEDIFF(
|
110
94
|
deals.closed_at,
|
@@ -126,33 +110,6 @@ class Deal < ActiveRecord::Base
|
|
126
110
|
select(selects).joins(joins).group('campaigns.id')
|
127
111
|
}
|
128
112
|
|
129
|
-
validate do |record|
|
130
|
-
return unless record.status_changed?
|
131
|
-
|
132
|
-
case record.status
|
133
|
-
when Status::Lead
|
134
|
-
if [Status::Won, Status::Lost].member?(record.status_was)
|
135
|
-
record.errors.add(:status, :illegal_reversion)
|
136
|
-
elsif record.persisted?
|
137
|
-
# "revert" isn't happening on new records
|
138
|
-
record.send :_do_revert
|
139
|
-
end
|
140
|
-
when Status::Pending
|
141
|
-
if record.status_was == Status::Lead
|
142
|
-
record.send :_do_convert
|
143
|
-
end
|
144
|
-
when Status::Won, Status::Lost
|
145
|
-
if record.status_was == Status::Lead
|
146
|
-
record.errors.add(:status, :illegal_conversion)
|
147
|
-
elsif record.persisted?
|
148
|
-
# "close" isn't happening on new records
|
149
|
-
record.send :_do_close
|
150
|
-
end
|
151
|
-
else
|
152
|
-
record.errors.add(:status, :invalid, :options => Status::OPTIONS.join(', '))
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
113
|
scope :column_op, lambda {|op, column, value, reverse=false|
|
157
114
|
conditions = arel_table[column].send(op, value)
|
158
115
|
conditions = conditions.not if reverse
|
@@ -177,6 +134,10 @@ class Deal < ActiveRecord::Base
|
|
177
134
|
Drop.new(self)
|
178
135
|
end
|
179
136
|
|
137
|
+
def closed?
|
138
|
+
[Status::Won, Status::Lost].include? status
|
139
|
+
end
|
140
|
+
|
180
141
|
protected
|
181
142
|
|
182
143
|
def write_options(obj={})
|
@@ -195,29 +156,15 @@ class Deal < ActiveRecord::Base
|
|
195
156
|
end
|
196
157
|
end
|
197
158
|
|
198
|
-
def _do_convert
|
199
|
-
self.converted_at = Time.now.utc
|
200
|
-
notify_observers :before_convert
|
201
|
-
end
|
202
|
-
|
203
|
-
def _do_revert
|
204
|
-
self.converted_at = nil
|
205
|
-
notify_observers :before_revert
|
206
|
-
end
|
207
|
-
|
208
|
-
def _do_close
|
209
|
-
self.closed_at = Time.now.utc
|
210
|
-
notify_observers :before_close
|
211
|
-
end
|
212
|
-
|
213
159
|
# Typically, new Deals are 'pending', with the assumption that offers
|
214
160
|
# explicitly create Deals as 'lead' when they convert.
|
215
161
|
def _assign_initialization_defaults
|
216
162
|
self.status ||= Status::Pending
|
217
163
|
end
|
218
164
|
|
165
|
+
# this is for leads
|
219
166
|
def transform_options_column
|
220
|
-
self.info
|
167
|
+
self.info ||= options.to_hash.map {|k, v| "%s:\n%s\n\n" % [k.to_s.titleize, v] }.join
|
221
168
|
end
|
222
169
|
|
223
170
|
def ensure_denormalized_columns
|
@@ -236,31 +183,34 @@ class Deal < ActiveRecord::Base
|
|
236
183
|
end
|
237
184
|
end
|
238
185
|
|
239
|
-
def
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
186
|
+
def handle_lead_creation
|
187
|
+
# If user is not set explicitly yet a lead_email was passed, set the
|
188
|
+
# user, first by attempting to find it by lead_email, and on that
|
189
|
+
# failing, by creating a new prospect.
|
190
|
+
if user.blank?
|
191
|
+
self.user = User.find_by_email(lead_email) || create_prospect
|
192
|
+
update_attribute(:user_id, user.id)
|
193
|
+
end
|
245
194
|
|
246
|
-
|
247
|
-
|
248
|
-
|
195
|
+
# Assign the user's contact to the lead, creating it first if it does
|
196
|
+
# not yet exist
|
197
|
+
user.create_contact_if_missing!
|
198
|
+
self.contacts << user.contact
|
249
199
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
200
|
+
# finally if mailing_list_ids were passed in the creation of this lead
|
201
|
+
# pass them along to the user.
|
202
|
+
if @mailing_list_ids
|
203
|
+
user.mailing_list_ids |= @mailing_list_ids
|
254
204
|
end
|
255
|
-
end
|
256
205
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
206
|
+
begin
|
207
|
+
if offer && alert_email = offer.conversion_alert_email.presence
|
208
|
+
Rails.logger.debug("Sending Deal Conversion Alert to [#{alert_email}]")
|
209
|
+
Offer.conversion_email.send!(alert_email, :offer => offer, :lead => self)
|
210
|
+
end
|
211
|
+
rescue
|
212
|
+
Rails.logger.debug("Deal conversion alert failed: #{$!}")
|
261
213
|
end
|
262
|
-
rescue
|
263
|
-
Rails.logger.debug("Deal conversion alert failed: #{$!}")
|
264
214
|
end
|
265
215
|
|
266
216
|
def update_to_pending_status
|
@@ -277,11 +227,34 @@ class Deal < ActiveRecord::Base
|
|
277
227
|
)
|
278
228
|
end
|
279
229
|
|
230
|
+
def handle_status_conversion
|
231
|
+
case status
|
232
|
+
when Status::Lead
|
233
|
+
self.converted_at = nil
|
234
|
+
when Status::Pending
|
235
|
+
self.converted_at = Time.now.utc
|
236
|
+
self.closed_at = nil
|
237
|
+
when Status::Won, Status::Lost
|
238
|
+
self.converted_at ||= Time.now.utc
|
239
|
+
self.closed_at = Time.now.utc
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def handle_dated_cost
|
244
|
+
if campaign.respond_to?(:set_cost)
|
245
|
+
dated_cost.try(:delete)
|
246
|
+
|
247
|
+
if status == Status::Won
|
248
|
+
create_dated_cost(:cost => campaign.cost, :costable => campaign, :date => converted_at.to_date)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
280
253
|
class Drop < ::E9::Liquid::Drops::Base
|
281
254
|
source_methods :name, :category, :lead_email, :lead_name, :info, :offer,
|
282
255
|
:campaign, :contacts, :owner, :status
|
283
256
|
|
284
|
-
date_methods
|
257
|
+
date_methods :closed_at, :converted_at
|
285
258
|
end
|
286
259
|
|
287
260
|
module Status
|
data/app/models/offer.rb
CHANGED
@@ -16,13 +16,22 @@ class Offer < Renderable
|
|
16
16
|
self.delegate_options_methods = true
|
17
17
|
self.options_parameters = [
|
18
18
|
:submit_button_text,
|
19
|
-
:success_alert_text,
|
20
19
|
:success_page_text,
|
21
|
-
:download_link_text,
|
22
20
|
:conversion_alert_email,
|
23
|
-
:custom_form_html
|
21
|
+
:custom_form_html,
|
22
|
+
:mailing_list_ids
|
24
23
|
]
|
25
24
|
|
25
|
+
def has_mailing_list?(ml)
|
26
|
+
(mailing_list_ids || []).map(&:to_s).member?(ml.id.to_s)
|
27
|
+
end
|
28
|
+
|
29
|
+
def mailing_lists
|
30
|
+
@_mailing_lists ||= begin
|
31
|
+
mailing_list_ids ? MailingList.find_all_by_id(mailing_list_ids) : []
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
26
35
|
class << self
|
27
36
|
def conversion_email
|
28
37
|
SystemEmail.find_by_identifier(Identifiers::CONVERSION_EMAIL)
|
@@ -53,7 +62,6 @@ class Offer < Renderable
|
|
53
62
|
|
54
63
|
def _assign_initialization_defaults
|
55
64
|
self.submit_button_text ||= 'Submit!'
|
56
|
-
self.download_link_text ||= 'Click to download your file'
|
57
65
|
self.success_page_text ||= 'Thank you!'
|
58
66
|
end
|
59
67
|
|
@@ -23,6 +23,14 @@
|
|
23
23
|
%select{:name => 'company', :id => 'contact_company_select'}
|
24
24
|
= company_select_options
|
25
25
|
|
26
|
-
|
26
|
+
.field#contact_tag_list
|
27
|
+
%label{:for => 'contact_tag_autocomplete'} Tags
|
28
|
+
%input#contact_tag_autocomplete.list{:type => 'text', 'data-iname' => 'contact', 'data-field' => '[tagged]', :placeholder => 'Enter a tag...'}
|
29
|
+
%ul#contact_tag_select.select
|
30
|
+
- Array.wrap(params[:tagged]).each do |tag|
|
31
|
+
%li.ui-state-default
|
32
|
+
%span.content= tag
|
33
|
+
%a{:class => :remove, :title => "Remove", :alt => "Remove"} Remove
|
34
|
+
|
27
35
|
.actions
|
28
36
|
= submit_tag t(:clear_all_filters), :name => nil, :id => 'contact_search_clear'
|
@@ -1,9 +1,6 @@
|
|
1
1
|
.actions.top
|
2
2
|
- if resource.persisted?
|
3
|
-
|
4
|
-
= link_to 'Back to Leads', leads_path
|
5
|
-
- else
|
6
|
-
= link_to_destroy_resource(resource, :remote => false)
|
3
|
+
= link_to_destroy_resource(resource, :remote => false)
|
7
4
|
|
8
5
|
.field
|
9
6
|
= f.label :name, nil, :class => :req
|
@@ -29,9 +29,6 @@
|
|
29
29
|
= record.info
|
30
30
|
%td.actions
|
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)
|
34
34
|
= link_to 'Delete Lead', record, :method => :delete, :remote => true, :confirm => I18n.t("#{resource_class.i18n_scope}.links.confirm_destroy")
|
35
|
-
|
36
|
-
- if @controller.should_paginate_index
|
37
|
-
= will_paginate collection
|
@@ -12,9 +12,9 @@
|
|
12
12
|
|
13
13
|
= @offer.custom_form_html.html_safe
|
14
14
|
|
15
|
-
- if @offer.
|
15
|
+
- if @offer.mailing_lists.any?
|
16
16
|
%fieldset
|
17
|
-
- @offer.
|
17
|
+
- @offer.mailing_lists.each do |ml|
|
18
18
|
.field.checkbox
|
19
19
|
= label_tag "#{resource_instance_name}_mailing_list_ids_#{ml.id}", ml.description
|
20
20
|
= check_box_tag "#{resource_instance_name}[mailing_list_ids][]", ml.id, true, :id => "#{resource_instance_name}_mailing_list_ids_#{ml.id}"
|
@@ -2,10 +2,5 @@ var $offer = $('#offer_<%= @offer.id %>_body');
|
|
2
2
|
<% if resource.errors.any? %>
|
3
3
|
$('form .errors', $offer).html("<%= escape_javascript(resource_error_messages!) %>");
|
4
4
|
<% else %>
|
5
|
-
|
6
|
-
$('form .errors', $offer).html("");
|
7
|
-
$('form .notice', $offer).html("<%= escape_javascript(@offer.success_alert_text) %>");
|
8
|
-
<% else %>
|
9
|
-
window.location = "<%= public_offer_path(@offer) %>";
|
10
|
-
<% end %>
|
5
|
+
setTimeout(function(){ location.href="<%= public_offer_path(@offer) %>"; },0)
|
11
6
|
<% end %>
|
@@ -1,9 +1,28 @@
|
|
1
|
+
- content_for :bottom_javascripts do
|
2
|
+
-#= render 'shared/admin/tiny_mce') if use_tiny_mce?
|
3
|
+
= render 'shared/admin/tiny_mce'
|
4
|
+
|
1
5
|
.field
|
2
6
|
= f.label :name, nil, :class => :req
|
3
7
|
= f.text_field :name
|
4
8
|
|
9
|
+
.field
|
10
|
+
= f.label :submit_button_text
|
11
|
+
= f.text_field :submit_button_text
|
12
|
+
|
13
|
+
.field
|
14
|
+
= f.label :conversion_alert_email
|
15
|
+
= f.text_field :conversion_alert_email
|
16
|
+
|
17
|
+
%fieldset
|
18
|
+
%legend= f.label(:mailing_list_ids)
|
19
|
+
- offer_mailing_lists.each do |ml|
|
20
|
+
.field.checkbox
|
21
|
+
= check_box_tag "offer[mailing_list_ids][]", ml.id, resource.has_mailing_list?(ml), :id => "offer_mailing_list_ids_#{ml.id}"
|
22
|
+
= label_tag "offer_mailing_list_ids_#{ml.id}", ml.name
|
23
|
+
|
5
24
|
.field.tinymce
|
6
|
-
=
|
25
|
+
= f.label :template
|
7
26
|
= f.text_area :template
|
8
27
|
|
9
28
|
.field
|
@@ -18,11 +37,3 @@
|
|
18
37
|
= hidden_field_tag 'offer[node_ids][]', id, :id => "offer_node_ids_#{i}"
|
19
38
|
- else
|
20
39
|
= render 'shared/admin/region_type_select', :f => f
|
21
|
-
|
22
|
-
.field
|
23
|
-
= f.label :submit_button_text
|
24
|
-
= f.text_field :submit_button_text
|
25
|
-
|
26
|
-
.field
|
27
|
-
= f.label :conversion_alert_email
|
28
|
-
= f.text_field :conversion_alert_email
|
@@ -5,8 +5,4 @@
|
|
5
5
|
= offer_select_options
|
6
6
|
|
7
7
|
.toolbar-right
|
8
|
-
=
|
9
|
-
= label_tag 'new_offer_select', t('activerecord.links.new', :model => Offer.model_name.human)
|
10
|
-
%select{:name => 'type', :id => 'new_offer_select'}
|
11
|
-
= offer_select_options(false)
|
12
|
-
= submit_tag t(:go), :name => nil
|
8
|
+
= link_to_new_resource(Offer)
|
data/config/locales/en.yml
CHANGED
@@ -62,10 +62,13 @@ en:
|
|
62
62
|
blank: "None of the contacts selected are configured with primary emails. Please correct this and try again."
|
63
63
|
deal:
|
64
64
|
attributes:
|
65
|
+
campaign:
|
66
|
+
closed_no_change: You cannot change the campaign of a closed deal. To do so, you must commit the status as "pending" then try again.
|
65
67
|
status:
|
66
68
|
illegal_conversion: A Deal with "lead" status can only be converted to "pending"
|
67
69
|
illegal_reversion: A Deal that has been marked "won" or "lost" cannot be reverted to a "lead"
|
68
|
-
|
70
|
+
closed_no_destroy: You cannot delete a closed deal. To remove it, you must commit the status as "pending" then try again.
|
71
|
+
inclusion: "Status must be one of (%{options})"
|
69
72
|
|
70
73
|
models:
|
71
74
|
address_attribute: Address
|
@@ -148,6 +151,7 @@ en:
|
|
148
151
|
owner: Responsible
|
149
152
|
won_deal_count: Won count
|
150
153
|
offer:
|
154
|
+
mailing_list_ids: Subscriptions
|
151
155
|
template: Teaser Text
|
152
156
|
template_help: |
|
153
157
|
<h3>Variables:</h3>
|
data/config/routes.rb
CHANGED
@@ -61,22 +61,7 @@ Rails.application.routes.draw do
|
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
|
-
resources :offers, :
|
65
|
-
scope :path => :offers do
|
66
|
-
resources :contact_offers, :path => 'contact', :except => [:show, :index]
|
67
|
-
resources :file_download_offers, :path => 'file_download', :except => [:show, :index]
|
68
|
-
resources :new_content_subscription_offers, :path => 'new_content_subscription', :except => [:show, :index]
|
69
|
-
resources :newsletter_subscription_offers, :path => 'newsletter_subscription', :except => [:show, :index]
|
70
|
-
resources :video_offers, :path => 'video', :except => [:show, :index]
|
71
|
-
|
72
|
-
%w( contact file_download new_content_subscription newsletter_subscription video ).each do |path|
|
73
|
-
get "/#{path}", :as => "#{path}_offers_redirect", :to => redirect("/#{crm_path}/offers?type=#{path}")
|
74
|
-
get "/#{path}/:id", :as => "#{path}_offers_edit_redirect", :to => redirect("/#{crm_path}/#{path}/%{id}/edit"), :constraints => { :id => /\d+/ }
|
75
|
-
end
|
76
|
-
|
77
|
-
%w( contact file_download new_content_subscription newsletter_subscription video ).each do |path|
|
78
|
-
end
|
79
|
-
end
|
64
|
+
resources :offers, :except => :show
|
80
65
|
|
81
66
|
# leads are simply a scoped view of deals (only index)
|
82
67
|
get :leads, :as => :leads, :to => 'deals#leads'
|
data/e9_crm.gemspec
CHANGED
@@ -0,0 +1,27 @@
|
|
1
|
+
module E9Crm
|
2
|
+
module SystemEmailsController
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
alias :send_test_email_without_crm :send_test_email
|
7
|
+
|
8
|
+
def send_test_email(email, current_user)
|
9
|
+
if email.try(:identifier) == Offer::Identifiers::CONVERSION_EMAIL
|
10
|
+
offer = Offer.new(:name => 'TEST OFFER')
|
11
|
+
lead = Deal.new(:offer => offer,
|
12
|
+
:lead_email => 'LEAD_EMAIL@example.com',
|
13
|
+
:lead_name => 'LEAD_NAME',
|
14
|
+
:info => 'Some Info',
|
15
|
+
:created_at => DateTime.now)
|
16
|
+
|
17
|
+
Offer.conversion_email.send!(current_user, {
|
18
|
+
:offer => offer,
|
19
|
+
:lead => lead
|
20
|
+
})
|
21
|
+
else
|
22
|
+
send_test_email_without_crm(email)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/e9_crm/version.rb
CHANGED
data/lib/e9_crm.rb
CHANGED
@@ -8,6 +8,7 @@ module E9Crm
|
|
8
8
|
autoload :Model, 'e9_crm/model'
|
9
9
|
autoload :Email, 'e9_crm/email'
|
10
10
|
autoload :TrackingController, 'e9_crm/tracking_controller'
|
11
|
+
autoload :SystemEmailsController, 'e9_crm/system_emails_controller'
|
11
12
|
|
12
13
|
module Rack
|
13
14
|
autoload :ContactAutoCompleter, 'e9_crm/rack/contact_auto_completer'
|
@@ -53,6 +54,7 @@ module E9Crm
|
|
53
54
|
ApplicationController.send(:include, E9Crm::Controller)
|
54
55
|
|
55
56
|
::Email.send(:include, E9Crm::Email)
|
57
|
+
::Admin::SystemEmailsController.send(:include, E9Crm::SystemEmailsController)
|
56
58
|
|
57
59
|
E9Crm.tracking_controllers.each do |controller|
|
58
60
|
controller.send(:include, E9Crm::TrackingController)
|
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.
|
5
|
+
version: 0.1.19
|
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-
|
13
|
+
date: 2011-09-14 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rails
|
@@ -111,6 +111,17 @@ dependencies:
|
|
111
111
|
version: "0.13"
|
112
112
|
type: :runtime
|
113
113
|
version_requirements: *id009
|
114
|
+
- !ruby/object:Gem::Dependency
|
115
|
+
name: state_machine
|
116
|
+
prerelease: false
|
117
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
119
|
+
requirements:
|
120
|
+
- - ~>
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: "1.0"
|
123
|
+
type: :runtime
|
124
|
+
version_requirements: *id010
|
114
125
|
description: |
|
115
126
|
*NOTE his plugin requires the private e9_base CMS gem and WILL NOT WORK without it.*
|
116
127
|
|
@@ -164,23 +175,17 @@ files:
|
|
164
175
|
- app/controllers/e9_crm/companies_controller.rb
|
165
176
|
- app/controllers/e9_crm/contact_emails_controller.rb
|
166
177
|
- app/controllers/e9_crm/contact_merges_controller.rb
|
167
|
-
- app/controllers/e9_crm/contact_offers_controller.rb
|
168
178
|
- app/controllers/e9_crm/contacts_controller.rb
|
169
179
|
- app/controllers/e9_crm/dated_costs_controller.rb
|
170
180
|
- app/controllers/e9_crm/deals_controller.rb
|
171
181
|
- app/controllers/e9_crm/email_campaigns_controller.rb
|
172
182
|
- app/controllers/e9_crm/email_templates.controller.rb
|
173
|
-
- app/controllers/e9_crm/file_download_offers_controller.rb
|
174
183
|
- app/controllers/e9_crm/leads_controller.rb
|
175
|
-
- app/controllers/e9_crm/new_content_subscription_offers_controller.rb
|
176
|
-
- app/controllers/e9_crm/newsletter_subscription_offers_controller.rb
|
177
|
-
- app/controllers/e9_crm/offer_subclass_controller.rb
|
178
184
|
- app/controllers/e9_crm/offers_controller.rb
|
179
185
|
- app/controllers/e9_crm/page_views_controller.rb
|
180
186
|
- app/controllers/e9_crm/resources_controller.rb
|
181
187
|
- app/controllers/e9_crm/sales_campaigns_controller.rb
|
182
188
|
- app/controllers/e9_crm/users_controller.rb
|
183
|
-
- app/controllers/e9_crm/video_offers_controller.rb
|
184
189
|
- app/helpers/e9_crm/base_helper.rb
|
185
190
|
- app/helpers/e9_crm/campaign_groups_helper.rb
|
186
191
|
- app/helpers/e9_crm/campaigns_helper.rb
|
@@ -200,21 +205,15 @@ files:
|
|
200
205
|
- app/models/company.rb
|
201
206
|
- app/models/contact.rb
|
202
207
|
- app/models/contact_email.rb
|
203
|
-
- app/models/contact_offer.rb
|
204
208
|
- app/models/dated_cost.rb
|
205
209
|
- app/models/deal.rb
|
206
210
|
- app/models/email_campaign.rb
|
207
211
|
- app/models/email_template.rb
|
208
|
-
- app/models/file_download_offer.rb
|
209
|
-
- app/models/new_content_subscription_offer.rb
|
210
|
-
- app/models/newsletter_subscription_offer.rb
|
211
212
|
- app/models/no_campaign.rb
|
212
213
|
- app/models/offer.rb
|
213
214
|
- app/models/page_view.rb
|
214
215
|
- app/models/sales_campaign.rb
|
215
|
-
- app/models/subscription_offer.rb
|
216
216
|
- app/models/tracking_cookie.rb
|
217
|
-
- app/models/video_offer.rb
|
218
217
|
- app/observers/deal_observer.rb
|
219
218
|
- app/uploaders/file_uploader.rb
|
220
219
|
- app/views/e9_crm/advertising_campaigns/_form_inner.html.haml
|
@@ -234,7 +233,6 @@ files:
|
|
234
233
|
- app/views/e9_crm/contact_merges/_field.html.haml
|
235
234
|
- app/views/e9_crm/contact_merges/_form.html.haml
|
236
235
|
- app/views/e9_crm/contact_merges/new.html.haml
|
237
|
-
- app/views/e9_crm/contact_offers/_form_inner.html.haml
|
238
236
|
- app/views/e9_crm/contacts/_contact.html.haml
|
239
237
|
- app/views/e9_crm/contacts/_details.html.haml
|
240
238
|
- app/views/e9_crm/contacts/_form_inner.html.haml
|
@@ -280,8 +278,6 @@ files:
|
|
280
278
|
- app/views/e9_crm/leads/_form.html.haml
|
281
279
|
- app/views/e9_crm/leads/create.js.erb
|
282
280
|
- app/views/e9_crm/leads/new.html.haml
|
283
|
-
- app/views/e9_crm/new_content_subscription_offers/_form_inner.html.haml
|
284
|
-
- app/views/e9_crm/newsletter_subscription_offers/_form_inner.html.haml
|
285
281
|
- app/views/e9_crm/offers/_form_inner.html.haml
|
286
282
|
- app/views/e9_crm/offers/_header.html.haml
|
287
283
|
- app/views/e9_crm/offers/_offer.html.haml
|
@@ -301,8 +297,6 @@ files:
|
|
301
297
|
- app/views/e9_crm/resources/show.html.haml
|
302
298
|
- app/views/e9_crm/resources/update.js.erb
|
303
299
|
- app/views/e9_crm/sales_campaigns/_form_inner.html.haml
|
304
|
-
- app/views/e9_crm/subscription_offers/_form_inner.html.haml
|
305
|
-
- app/views/e9_crm/video_offers/_form_inner.html.haml
|
306
300
|
- app/views/record_attributes/_user.html.haml
|
307
301
|
- config/initializers/inflections.rb
|
308
302
|
- config/locales/e9.en.yml
|
@@ -317,6 +311,7 @@ files:
|
|
317
311
|
- lib/e9_crm/rack/company_auto_completer.rb
|
318
312
|
- lib/e9_crm/rack/contact_auto_completer.rb
|
319
313
|
- lib/e9_crm/rails_extensions.rb
|
314
|
+
- lib/e9_crm/system_emails_controller.rb
|
320
315
|
- lib/e9_crm/tracking_controller.rb
|
321
316
|
- lib/e9_crm/version.rb
|
322
317
|
- lib/generators/e9_crm/install_generator.rb
|
data/app/models/contact_offer.rb
DELETED
data/app/models/video_offer.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
= render 'e9_crm/subscription_offers/form_inner', :f => f
|
@@ -1 +0,0 @@
|
|
1
|
-
= render 'e9_crm/subscription_offers/form_inner', :f => f
|