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.
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