e9_crm 0.1.18 → 0.1.19
Sign up to get free protection for your applications and to get access to all the features.
- 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
|