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.
Files changed (44) hide show
  1. data/app/controllers/e9_crm/deals_controller.rb +1 -1
  2. data/app/controllers/e9_crm/offers_controller.rb +6 -5
  3. data/app/helpers/e9_crm/base_helper.rb +0 -64
  4. data/app/helpers/e9_crm/deals_helper.rb +1 -1
  5. data/app/helpers/e9_crm/offers_helper.rb +9 -4
  6. data/app/models/campaign.rb +7 -7
  7. data/app/models/dated_cost.rb +1 -1
  8. data/app/models/deal.rb +74 -101
  9. data/app/models/offer.rb +12 -4
  10. data/app/models/sales_campaign.rb +5 -0
  11. data/app/views/e9_crm/contacts/_index_sidebar.html.haml +9 -1
  12. data/app/views/e9_crm/deals/_form_inner.html.haml +1 -4
  13. data/app/views/e9_crm/deals/_leads_table.html.haml +1 -4
  14. data/app/views/e9_crm/deals/_table.html.haml +0 -3
  15. data/app/views/e9_crm/leads/_form.html.haml +2 -2
  16. data/app/views/e9_crm/leads/create.js.erb +1 -6
  17. data/app/views/e9_crm/offers/_form_inner.html.haml +20 -9
  18. data/app/views/e9_crm/offers/_header.html.haml +1 -5
  19. data/app/views/e9_crm/offers/_public_offer.html.haml +0 -4
  20. data/app/views/e9_crm/resources/index.html.haml +3 -0
  21. data/config/locales/en.yml +5 -1
  22. data/config/routes.rb +1 -16
  23. data/e9_crm.gemspec +1 -0
  24. data/lib/e9_crm/system_emails_controller.rb +27 -0
  25. data/lib/e9_crm/version.rb +1 -1
  26. data/lib/e9_crm.rb +2 -0
  27. metadata +14 -19
  28. data/app/controllers/e9_crm/contact_offers_controller.rb +0 -3
  29. data/app/controllers/e9_crm/file_download_offers_controller.rb +0 -3
  30. data/app/controllers/e9_crm/new_content_subscription_offers_controller.rb +0 -3
  31. data/app/controllers/e9_crm/newsletter_subscription_offers_controller.rb +0 -3
  32. data/app/controllers/e9_crm/offer_subclass_controller.rb +0 -11
  33. data/app/controllers/e9_crm/video_offers_controller.rb +0 -3
  34. data/app/models/contact_offer.rb +0 -2
  35. data/app/models/file_download_offer.rb +0 -2
  36. data/app/models/new_content_subscription_offer.rb +0 -5
  37. data/app/models/newsletter_subscription_offer.rb +0 -5
  38. data/app/models/subscription_offer.rb +0 -3
  39. data/app/models/video_offer.rb +0 -2
  40. data/app/views/e9_crm/contact_offers/_form_inner.html.haml +0 -5
  41. data/app/views/e9_crm/new_content_subscription_offers/_form_inner.html.haml +0 -1
  42. data/app/views/e9_crm/newsletter_subscription_offers/_form_inner.html.haml +0 -1
  43. data/app/views/e9_crm/subscription_offers/_form_inner.html.haml +0 -5
  44. 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
- if params[:action] != 'show'
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').sort
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
@@ -8,13 +8,13 @@ class Campaign < ActiveRecord::Base
8
8
 
9
9
  belongs_to :campaign_group
10
10
 
11
- has_many :deals, :inverse_of => :campaign, :dependent => :nullify
12
- has_many :won_deals, :class_name => 'Deal', :conditions => ['deals.status = ?', Deal::Status::Won]
13
- has_many :lost_deals, :class_name => 'Deal', :conditions => ['deals.status = ?', Deal::Status::Lost]
14
- has_many :pending_deals, :class_name => 'Deal', :conditions => ['deals.status = ?', Deal::Status::Pending]
15
- has_many :leads, :class_name => 'Deal', :conditions => ['deals.status = ?', Deal::Status::Lead]
16
- has_many :non_leads, :class_name => 'Deal', :conditions => ['deals.status != ?', Deal::Status::Lead]
17
- has_many :page_views, :inverse_of => :campaign, :dependent => :nullify
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
@@ -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 => { :greater_than => 0 }
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
- # require a deal name
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
- # require lead_name and lead_email; gotten from current_user if it exists
29
- validates :lead_name, :presence => { :if => lambda {|r| r.lead? } }
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
- # 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_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(CASE campaigns.type
87
- WHEN "AdvertisingCampaign"
88
- THEN dated_costs.cost
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 = options.to_hash.map {|k, v| "%s:\n%s\n\n" % [k.to_s.titleize, v] }.join
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 handle_user_if_lead
240
- if lead?
241
- if user.blank? && lead_email
242
- user = User.find_by_email(lead_email) || create_prospect
243
- update_attribute(:user_id, u.id)
244
- end
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
- if user.present?
247
- user.create_contact_if_missing!
248
- self.contacts << user.contact
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
- if @mailing_list_ids
251
- user.mailing_list_ids |= @mailing_list_ids
252
- end
253
- end
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
- def send_offer_conversion_email_if_lead
258
- if lead? && offer && email = offer.conversion_alert_email.presence
259
- Rails.logger.debug("Sending Deal Conversion Alert to [#{email}]")
260
- Offer.conversion_email.send!(email, :offer => offer, :lead => self)
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 :closed_at, :converted_at
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
 
@@ -14,4 +14,9 @@ class SalesCampaign < Campaign
14
14
  def cost
15
15
  sales_fee
16
16
  end
17
+
18
+ def set_cost(options = {})
19
+ dated_costs.clear
20
+ dated_costs.create(options.merge(:cost => cost))
21
+ end
17
22
  end
@@ -23,6 +23,14 @@
23
23
  %select{:name => 'company', :id => 'contact_company_select'}
24
24
  = company_select_options
25
25
 
26
- = render 'tag_table'
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
- - if resource.lead?
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
- = link_to_show_resource(record.contacts.first)
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
@@ -40,6 +40,3 @@
40
40
  %td.record-totals.num
41
41
  = dat[:value].sum.to_money.format
42
42
  %td
43
-
44
- - if @controller.should_paginate_index
45
- = will_paginate collection
@@ -12,9 +12,9 @@
12
12
 
13
13
  = @offer.custom_form_html.html_safe
14
14
 
15
- - if @offer.kind_of?(SubscriptionOffer)
15
+ - if @offer.mailing_lists.any?
16
16
  %fieldset
17
- - @offer.class.mailing_lists.each do |ml|
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
- <% if @offer.kind_of?(SubscriptionOffer) %>
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
- = help_label(f, :template, :markdown => true)
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
- = form_tag new_contact_offer_path, :method => :get, :id => 'new_offer_form' do
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)
@@ -1,6 +1,2 @@
1
1
  #offer-body
2
2
  = k resource.success_page_text
3
-
4
- - if resource.file?
5
- #offer-download-link
6
- = link_to(resource.download_link_text, resource.file_url)
@@ -9,3 +9,6 @@
9
9
  - else
10
10
  %div#records_table
11
11
  = render 'table', :resources => collection
12
+
13
+ - if controller.should_paginate_index
14
+ = will_paginate collection
@@ -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
- invalid: "Status must be one of (%{options})"
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, :only => [:index, :destroy]
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
@@ -28,4 +28,5 @@ Gem::Specification.new do |s|
28
28
  s.add_dependency("e9_attributes")
29
29
  s.add_dependency("will_paginate")
30
30
  s.add_dependency("kramdown", "~> 0.13")
31
+ s.add_dependency("state_machine", "~> 1.0")
31
32
  end
@@ -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
@@ -1,3 +1,3 @@
1
1
  module E9Crm
2
- VERSION = '0.1.18'
2
+ VERSION = '0.1.19'
3
3
  end
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.18
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-12 00:00:00 Z
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
@@ -1,3 +0,0 @@
1
- class E9Crm::ContactOffersController < E9Crm::OfferSubclassController
2
- defaults :resource_class => ContactOffer
3
- end
@@ -1,3 +0,0 @@
1
- class E9Crm::FileDownloadOffersController < E9Crm::OfferSubclassController
2
- defaults :resource_class => FileDownloadOffer
3
- end
@@ -1,3 +0,0 @@
1
- class E9Crm::NewContentSubscriptionOffersController < E9Crm::OfferSubclassController
2
- defaults :resource_class => NewContentSubscriptionOffer
3
- end
@@ -1,3 +0,0 @@
1
- class E9Crm::NewsletterSubscriptionOffersController < E9Crm::OfferSubclassController
2
- defaults :resource_class => NewsletterSubscriptionOffer
3
- end
@@ -1,11 +0,0 @@
1
- class E9Crm::OfferSubclassController < E9Crm::ResourcesController
2
- protected
3
-
4
- def add_index_breadcrumb
5
- add_breadcrumb! Offer.model_name.collection.titleize, offers_path
6
- end
7
-
8
- def determine_layout
9
- request.xhr? ? false : super
10
- end
11
- end
@@ -1,3 +0,0 @@
1
- class E9Crm::VideoOffersController < E9Crm::OfferSubclassController
2
- defaults :resource_class => VideoOffer
3
- end
@@ -1,2 +0,0 @@
1
- class ContactOffer < Offer
2
- end
@@ -1,2 +0,0 @@
1
- class FileDownloadOffer < Offer
2
- end
@@ -1,5 +0,0 @@
1
- class NewContentSubscriptionOffer < SubscriptionOffer
2
- def self.mailing_lists
3
- [::MailingList.new_content_alerts]
4
- end
5
- end
@@ -1,5 +0,0 @@
1
- class NewsletterSubscriptionOffer < SubscriptionOffer
2
- def self.mailing_lists
3
- [::MailingList.newsletter]
4
- end
5
- end
@@ -1,3 +0,0 @@
1
- class SubscriptionOffer < Offer
2
- def self.mailing_lists; [] end
3
- end
@@ -1,2 +0,0 @@
1
- class VideoOffer < Offer
2
- end
@@ -1,5 +0,0 @@
1
- = render 'e9_crm/offers/form_inner', :f => f
2
-
3
- .field{:class => request.xhr? ? 'tinymcexhr' : 'tinymce'}
4
- = help_label(f, :success_page_text, :key => :markdown_help, :header => "Markdown Help", :class => :req)
5
- = f.text_area :success_page_text
@@ -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
@@ -1,5 +0,0 @@
1
- = render 'e9_crm/offers/form_inner', :f => f
2
-
3
- .field
4
- = f.label :success_alert_text
5
- = f.text_field :success_alert_text
@@ -1,5 +0,0 @@
1
- = render 'e9_crm/offers/form_inner', :f => f
2
-
3
- .field{:class => request.xhr? ? 'tinymcexhr' : 'tinymce'}
4
- = help_label(f, :success_page_text, :key => :markdown_help, :header => "Markdown Help", :class => :req)
5
- = f.text_area :success_page_text