e9_crm 0.1.10 → 0.1.11

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 (43) hide show
  1. data/app/controllers/e9_crm/contacts_controller.rb +29 -10
  2. data/app/controllers/e9_crm/deals_controller.rb +0 -1
  3. data/app/controllers/e9_crm/email_templates.controller.rb +10 -0
  4. data/app/helpers/e9_crm/base_helper.rb +2 -0
  5. data/app/helpers/e9_crm/campaigns_helper.rb +7 -2
  6. data/app/helpers/e9_crm/contacts_helper.rb +7 -1
  7. data/app/models/company.rb +1 -0
  8. data/app/models/contact.rb +4 -1
  9. data/app/models/deal.rb +40 -30
  10. data/app/models/email_template.rb +4 -0
  11. data/app/models/sales_campaign.rb +1 -1
  12. data/app/views/e9_crm/campaigns/_table.html.haml +3 -0
  13. data/app/views/e9_crm/campaigns/reports.html.haml +0 -2
  14. data/app/views/e9_crm/contacts/_details.html.haml +4 -1
  15. data/app/views/e9_crm/contacts/_form_inner.html.haml +8 -2
  16. data/app/views/e9_crm/contacts/_index_sidebar.html.haml +13 -7
  17. data/app/views/e9_crm/contacts/_sidebar.html.haml +7 -7
  18. data/app/views/e9_crm/contacts/_table.html.haml +3 -0
  19. data/app/views/e9_crm/contacts/_who.html.haml +1 -1
  20. data/app/views/e9_crm/contacts/index.html.haml +0 -1
  21. data/app/views/e9_crm/contacts/show.html.haml +3 -1
  22. data/app/views/e9_crm/deals/_leads_table.html.haml +3 -0
  23. data/app/views/e9_crm/deals/_reports_table.html.haml +12 -12
  24. data/app/views/e9_crm/deals/_table.html.haml +3 -0
  25. data/app/views/e9_crm/email_templates/_form_inner.html.haml +1 -1
  26. data/app/views/e9_crm/page_views/_table.html.haml +3 -0
  27. data/app/views/e9_crm/resources/_table.html.haml +3 -0
  28. data/app/views/e9_crm/resources/index.html.haml +0 -2
  29. data/app/views/e9_crm/sales_campaigns/_form_inner.html.haml +1 -2
  30. data/config/locales/e9.en.yml +1 -1
  31. data/config/locales/en.yml +6 -3
  32. data/e9_crm.gemspec +2 -2
  33. data/lib/e9_crm/version.rb +1 -1
  34. data/lib/generators/e9_crm/templates/migration.rb +1 -0
  35. metadata +4 -12
  36. data/app/views/e9_crm/campaign_groups/_footer.html.haml +0 -0
  37. data/app/views/e9_crm/campaigns/_footer.html.haml +0 -0
  38. data/app/views/e9_crm/campaigns/_reports_table.html.haml +0 -31
  39. data/app/views/e9_crm/deals/_footer.html.haml +0 -0
  40. data/app/views/e9_crm/email_templates/_footer.html.haml +0 -0
  41. data/app/views/e9_crm/menu_options/_footer.html.haml +0 -0
  42. data/app/views/e9_crm/offers/_footer.html.haml +0 -0
  43. data/app/views/e9_crm/resources/_footer.html.haml +0 -1
@@ -11,17 +11,23 @@ class E9Crm::ContactsController < E9Crm::ResourcesController
11
11
  before_filter :determine_title, :only => :index
12
12
  before_filter :load_contact_ids, :only => :index
13
13
  before_filter :build_nested_associations, :only => [:new, :edit]
14
+ before_filter :set_tag_instructions_scope
14
15
 
15
16
  has_scope :search, :by_title, :by_company, :only => :index
16
17
  has_scope :tagged, :only => :index, :type => :array
18
+ has_scope :by_company, :as => :company, :only => :index
17
19
 
18
20
  # record attributes templates js
19
21
  skip_before_filter :authenticate_user!, :filter_access_filter, :only => :templates
20
22
  before_filter :build_resource, :only => :templates
21
- caches_action :templates
23
+ #caches_action :templates
22
24
 
25
+ # NOTE for some reason create! { redirect } is trying to redirect on failure
23
26
  def create
24
- create! { resource_path }
27
+ create! do |success, failure|
28
+ success.html { redirect_to resource_path }
29
+ failure.html { render :new }
30
+ end
25
31
  end
26
32
 
27
33
  def update
@@ -36,7 +42,7 @@ class E9Crm::ContactsController < E9Crm::ResourcesController
36
42
  #
37
43
  def load_contact_ids
38
44
  @contact_ids ||= begin
39
- contact_id_sql = end_of_association_chain.scoped.select('contacts.id').to_sql
45
+ contact_id_sql = end_of_association_chain.scoped.ok_to_email.select('contacts.id').to_sql
40
46
  Contact.connection.send(:select_values, contact_id_sql, 'Contact ID Load')
41
47
  end
42
48
  end
@@ -46,22 +52,35 @@ class E9Crm::ContactsController < E9Crm::ResourcesController
46
52
  #
47
53
  def determine_title
48
54
  params.delete(:search) if params[:search].blank?
49
-
50
- @index_title ||= if params[:tagged] && params[:search]
51
- e9_t(:index_title_with_search_and_tags, :tagged => params[:tagged].join(' or '), :search => params[:search])
52
- elsif params[:tagged]
53
- e9_t(:index_title_with_tags, :tagged => params[:tagged].join(' or '))
54
- elsif params[:search]
55
- e9_t(:index_title_with_search, :search => params[:search])
55
+
56
+ @index_title = 'Contacts'.tap do |t|
57
+ if params[:search]
58
+ t << " matching \"#{params[:search]}\""
59
+ end
60
+ if params[:tagged]
61
+ t << " tagged #{params[:tagged].map {|t| "\"#{t}\"" }.join(' or ')}"
62
+ end
63
+ if params[:company] =~ /\d+/ && company = Company.find_by_id(params[:company])
64
+ t << " in company \"#{company.name}\""
65
+ end
56
66
  end
57
67
  end
58
68
 
69
+ # we don't need @index_title in the breadcrumb here (too long)
70
+ def add_index_breadcrumb
71
+ add_breadcrumb! e9_t(:index_title), collection_path
72
+ end
73
+
59
74
  def collection_scope
60
75
  #TODO fix eager loading, which totally breaks because of the left outer joins in search
61
76
  #super.includes(:users => :subscriptions)
62
77
  scope = super
63
78
  end
64
79
 
80
+ def set_tag_instructions_scope
81
+ @tag_instructions_scope = 'activerecord.attributes.contact'
82
+ end
83
+
65
84
  def build_nested_associations
66
85
  object = params[:id] ? resource : build_resource
67
86
  object.build_all_record_attributes
@@ -64,7 +64,6 @@ class E9Crm::DealsController < E9Crm::ResourcesController
64
64
  scope & Campaign.of_type("#{value}_campaign".classify)
65
65
  end
66
66
 
67
-
68
67
  ##
69
68
  # Actions
70
69
  #
@@ -2,4 +2,14 @@ class E9Crm::EmailTemplatesController < E9Crm::ResourcesController
2
2
  defaults
3
3
  include E9Rails::Controllers::Orderable
4
4
  self.should_paginate_index = false
5
+
6
+ protected
7
+
8
+ def default_ordered_on
9
+ 'name'
10
+ end
11
+
12
+ def default_ordered_dir
13
+ 'ASC'
14
+ end
5
15
  end
@@ -101,6 +101,8 @@ module E9Crm::BaseHelper
101
101
  )
102
102
  end
103
103
 
104
+ # tries to build an associated resource, looking to the assocatiaon's model for a method
105
+ # named "%{association_name}_build_parameters}" first for any default params
104
106
  def build_associated_resource(association_name)
105
107
  params_method = "#{association_name}_build_parameters"
106
108
  build_params = resource_class.send(params_method) if resource_class.respond_to?(params_method)
@@ -3,12 +3,17 @@ module E9Crm::CampaignsHelper
3
3
  Money === val && val || 'n/a'
4
4
  end
5
5
 
6
+ def no_money
7
+ @_no_money ||= Money.new(0)
8
+ end
9
+
6
10
  def display_campaign_code(val)
7
11
  val && "?#{E9Crm.query_param}=#{val}" || 'n/a'
8
12
  end
9
13
 
10
- def display_campaign_type(val)
11
- val[/(.*)Campaign/, 1]
14
+ def display_campaign_type(val = '')
15
+ retv = val[/(.*)Campaign/, 1]
16
+ retv == 'No' ? 'No Campaign' : retv
12
17
  end
13
18
 
14
19
  def campaign_type_select_options(with_all_option = true)
@@ -9,6 +9,12 @@ module E9Crm::ContactsHelper
9
9
  end
10
10
  end
11
11
 
12
+ def company_select_options
13
+ options = Company.select('name', 'id').ordered.all.map {|c| [c.name, c.id] }
14
+ options.unshift(['Any Company', nil])
15
+ options_for_select(options, params[:company])
16
+ end
17
+
12
18
  def link_to_google(query, opts = {})
13
19
  return unless query.present?
14
20
 
@@ -75,7 +81,7 @@ module E9Crm::ContactsHelper
75
81
  def records_table_field_map_for_contact
76
82
  {
77
83
  :fields => {
78
- :avatar => proc {|r| "<img src=\"#{r.avatar_url}\" alt=\"Avatar for #{r.name}\" />".html_safe },
84
+ :avatar => proc {|r| link_to("<img src=\"#{r.avatar_url}\" alt=\"Avatar for #{r.name}\" />".html_safe, contact_path(r)) },
79
85
  :details => proc {|r| render('details', :record => r) }
80
86
  },
81
87
 
@@ -7,4 +7,5 @@ class Company < ActiveRecord::Base
7
7
 
8
8
  validates :name, :presence => true, :uniqueness => { :allow_blank => true, :case_sensitive => false }
9
9
 
10
+ scope :ordered, lambda { order(arel_table[:name].asc) }
10
11
  end
@@ -154,6 +154,7 @@ class Contact < ActiveRecord::Base
154
154
  scope :contacts, lambda { where(:status => Status::Contact) }
155
155
  scope :ordered, lambda { order(arel_table[:first_name].asc) }
156
156
 
157
+ scope :ok_to_email, lambda { where(:ok_to_email => true) }
157
158
  scope :by_title, lambda {|val| where(:title => val) }
158
159
  scope :by_company, lambda {|val| where(:company_id => val) }
159
160
  scope :tagged, lambda {|tags|
@@ -164,6 +165,7 @@ class Contact < ActiveRecord::Base
164
165
  end
165
166
  }
166
167
 
168
+ # NOTE for future restriction?
167
169
  scope :deal_owners, lambda { scoped }
168
170
 
169
171
  def self.available_to_deal(deal)
@@ -317,7 +319,8 @@ class Contact < ActiveRecord::Base
317
319
 
318
320
  def ensure_no_associated_deals
319
321
  unless self.associated_deals.empty?
320
- object.errors.add(:associated_deals, :delete_restricted)
322
+ errors.add(:associated_deals, :delete_restricted)
323
+ false
321
324
  end
322
325
  end
323
326
 
data/app/models/deal.rb CHANGED
@@ -38,6 +38,7 @@ class Deal < ActiveRecord::Base
38
38
 
39
39
  # denormalize campaign code and offer name columns
40
40
  before_save :ensure_denormalized_columns
41
+ before_save :ensure_associated_campaign
41
42
 
42
43
  # If a lead with no user, find the user by email or create it, then if mailing_lists
43
44
  # were passed, assign the user those mailing lists
@@ -52,21 +53,30 @@ class Deal < ActiveRecord::Base
52
53
 
53
54
  attr_accessor :mailing_list_ids
54
55
 
56
+ #
57
+ # reports is technically a deal scope, but actually returns campaigns
58
+ # and a selection of relevant pseudo columns.
59
+ #
60
+ # NOTE reports probably should be a campaign scope? It doesn't really seem
61
+ # to matter. The resultset is neither Deals nor Campaigns, anyway, but
62
+ # a selection of calculated columns aggregated from data from both tables.
63
+ #
55
64
  scope :reports, lambda {
56
- select_sql = <<-SELECT.gsub(/\s+/, ' ')
57
- campaigns.id campaign_id,
58
- campaigns.type campaign_type,
59
- campaigns.name campaign_name,
60
- campaign_groups.name campaign_group,
61
- SUM(IF(deals.status != 'lead',1,0)) deal_count,
62
- COUNT(deals.id) lead_count,
63
- SUM(IF(deals.status='won',1,0)) won_deal_count,
64
- campaigns.new_visits new_visits,
65
- campaigns.repeat_visits repeat_visits,
66
-
67
- SUM(IF(deals.status='won',value,0)) total_value,
68
- AVG(IF(deals.status='won',value,NULL)) average_value,
69
-
65
+ selects = <<-SQL.gsub(/\s+/, ' ')
66
+ campaigns.type campaign_type,
67
+ campaigns.name campaign_name,
68
+ campaigns.new_visits new_visits,
69
+ campaigns.repeat_visits repeat_visits,
70
+
71
+ deals.closed_at closed_at,
72
+ deals.created_at created_at,
73
+
74
+ campaign_groups.name campaign_group,
75
+ SUM(IF(deals.status != 'lead',1,0)) deal_count,
76
+ COUNT(deals.id) lead_count,
77
+ SUM(IF(deals.status='won',1,0)) won_deal_count,
78
+ SUM(IF(deals.status='won',deals.value,0)) total_value,
79
+ AVG(IF(deals.status='won',deals.value,NULL)) average_value,
70
80
  SUM(CASE campaigns.type
71
81
  WHEN "AdvertisingCampaign"
72
82
  THEN dated_costs.cost
@@ -77,8 +87,7 @@ class Deal < ActiveRecord::Base
77
87
  campaigns.affiliate_fee
78
88
  ELSE
79
89
  0
80
- END) total_cost,
81
-
90
+ END) total_cost,
82
91
  SUM(CASE campaigns.type
83
92
  WHEN "AdvertisingCampaign"
84
93
  THEN dated_costs.cost
@@ -89,31 +98,28 @@ class Deal < ActiveRecord::Base
89
98
  campaigns.affiliate_fee
90
99
  ELSE
91
100
  0
92
- END) / SUM(IF(deals.status='won',1,0)) average_cost,
93
-
101
+ END) / SUM(IF(deals.status='won',1,0)) average_cost,
94
102
  FLOOR(AVG(
95
103
  DATEDIFF(
96
104
  deals.closed_at,
97
- deals.created_at))) average_elapsed
105
+ deals.created_at))) average_elapsed
106
+ SQL
98
107
 
99
- SELECT
108
+ joins = <<-SQL.gsub(/\s+/, ' ')
109
+ RIGHT JOIN campaigns
110
+ ON deals.campaign_id = campaigns.id
100
111
 
101
- join_sql = <<-JOINS.gsub(/\s+/, ' ')
102
- LEFT OUTER JOIN dated_costs
103
- ON deals.campaign_id = dated_costs.costable_id
112
+ LEFT JOIN dated_costs
113
+ ON campaigns.id = dated_costs.costable_id
104
114
  AND dated_costs.costable_type = "Campaign"
105
115
 
106
- LEFT OUTER JOIN campaigns
107
- ON campaigns.id = deals.campaign_id
108
-
109
- LEFT OUTER JOIN campaign_groups
116
+ LEFT JOIN campaign_groups
110
117
  ON campaign_groups.id = campaigns.campaign_group_id
111
- JOINS
118
+ SQL
112
119
 
113
- select(select_sql).joins(join_sql).group(:campaign_id)
120
+ select(selects).joins(joins).group('campaigns.id')
114
121
  }
115
122
 
116
-
117
123
  validate do |record|
118
124
  return unless record.status_changed?
119
125
 
@@ -223,6 +229,10 @@ class Deal < ActiveRecord::Base
223
229
  self.offer_name ||= offer.name if offer.present?
224
230
  end
225
231
 
232
+ def ensure_associated_campaign
233
+ self.campaign ||= Campaign.default
234
+ end
235
+
226
236
  def get_name_and_email_from_user
227
237
  if lead? && user.present?
228
238
  self.lead_email = user.email
@@ -4,4 +4,8 @@
4
4
  class EmailTemplate < Email
5
5
  # TODO the email class hierarchy needs a major refactoring, it's backwards and convoluted
6
6
  before_save :generate_html_body_from_text_body
7
+
8
+ validates :text_body, :presence => true
9
+ validates :subject, :presence => true
10
+ validates :from_email, :presence => true, :email => { :allow_blank => true }
7
11
  end
@@ -6,7 +6,7 @@ class SalesCampaign < Campaign
6
6
  money_columns :sales_fee
7
7
 
8
8
  belongs_to :sales_person, :class_name => 'Contact'
9
- validates :sales_person, :presence => true
9
+ validates :sales_person, :presence => { :if => lambda {|x| x.type == 'SalesCampaign' } }
10
10
 
11
11
  ##
12
12
  # The sum cost of this campaign
@@ -31,3 +31,6 @@
31
31
  - if record.is_a?(AdvertisingCampaign)
32
32
  = link_to t(:edit_dated_costs), advertising_campaign_dated_costs_path(record), :class => 'dated-costs'
33
33
  = link_to_edit_campaign(record)
34
+
35
+ - if @controller.should_paginate_index
36
+ = will_paginate collection
@@ -9,5 +9,3 @@
9
9
  - else
10
10
  %div#records_table
11
11
  = render 'table', :resources => collection
12
-
13
- = render 'footer'
@@ -7,9 +7,12 @@
7
7
 
8
8
  - if record.users.any?
9
9
  .contact-emails
10
+ - unless record.ok_to_email?
11
+ .contact-email-warning
12
+ = resource_humanize(:not_ok_to_email)
10
13
  - record.users.each do |user|
11
14
  .contact-email
12
- = '* ' if contact_user_subscribed_to_newsletter?(user)
15
+ -#= '* ' if contact_user_subscribed_to_newsletter?(user)
13
16
  = link_to(user.email, "mailto:#{user.email}")
14
17
  = "(#{user.options.type})" if user.options.type
15
18
  = "(primary)" if user.primary?
@@ -1,9 +1,15 @@
1
- = render_record_attribute_form(:users, f)
1
+ %fieldset.nested-associations
2
+ %legend= f.label(:users)
3
+ = render_record_attribute_association(:users, f)
4
+ = link_to_add_record_attribute(:users)
5
+ .field.checkbox
6
+ = f.label :ok_to_email
7
+ = f.check_box :ok_to_email
2
8
 
3
9
  %fieldset.contact-standard-fields
4
10
  %legend= e9_t(:form_legend_standard)
5
11
  .field
6
- = f.label :first_name
12
+ = f.label :first_name, nil, :class => :req
7
13
  = f.text_field :first_name
8
14
  .field
9
15
  = f.label :last_name
@@ -3,8 +3,9 @@
3
3
  = link_to_collection(Company)
4
4
 
5
5
  -# Email actions (template, newsletter)
6
- - etag, ntag = contact_email_template_select_tag, contact_newsletter_select_tag
7
- - if [etag, ntag].any?(&:present?)
6
+ -#- etag, ntag = contact_email_template_select_tag, contact_newsletter_select_tag
7
+ -#- if [etag, ntag].any?(&:present?)
8
+ - if (etag = contact_newsletter_select_tag).present?
8
9
  %fieldset
9
10
  %legend= e9_t(:email_actions_legend)
10
11
  - if etag
@@ -12,11 +13,11 @@
12
13
  = etag
13
14
  = hidden_field_tag 'uids', @contact_ids.join(','), :id => 'contact_email_uids'
14
15
  = submit_tag e9_t(:send_email_template), :name => nil
15
- - if ntag
16
- = form_tag send_email_admin_user_email_path('__ID__'), :method => :put, :id => 'contact_newsletter_form', 'data-confirm' => e9_t(:contact_newsletter_confirmation, :count => collection.length), 'data-empty' => e9_t(:no_contacts_notification), 'data-count' => @contact_ids.length do
17
- = ntag
18
- = hidden_field_tag 'uids', @contact_ids.join(','), :id => 'contact_newsletter_uids'
19
- = submit_tag e9_t(:send_email_newsletter), :name => nil
16
+ -#- if ntag
17
+ -#= form_tag send_email_admin_user_email_path('__ID__'), :method => :put, :id => 'contact_newsletter_form', 'data-confirm' => e9_t(:contact_newsletter_confirmation, :count => collection.length), 'data-empty' => e9_t(:no_contacts_notification), 'data-count' => @contact_ids.length do
18
+ -#= ntag
19
+ -#= hidden_field_tag 'uids', @contact_ids.join(','), :id => 'contact_newsletter_uids'
20
+ -#= submit_tag e9_t(:send_email_newsletter), :name => nil
20
21
 
21
22
  -# Search filter options
22
23
  %fieldset
@@ -25,6 +26,11 @@
25
26
  = label_tag 'contact_search_field', t(:search)
26
27
  = text_field_tag 'search', params[:search], :id => 'contact_search_field'
27
28
  = submit_tag t(:go), :name => nil
29
+
30
+ = form_tag(resource_class, :method => :get, :class => 'scope-selects') do
31
+ %select{:name => 'company'}
32
+ = company_select_options
33
+
28
34
  = render 'tag_table'
29
35
  .actions
30
36
  = submit_tag t(:clear), :name => nil, :id => 'contact_search_clear'
@@ -1,9 +1,3 @@
1
- - if resource.phone_number_attributes.any?
2
- .contact-phone-numbers
3
- %label= Contact.human_attribute_name(:phone_number_attributes)
4
- - resource.phone_number_attributes.each do |phone_number_attribute|
5
- .contact-phone-number= phone_number_attribute
6
-
7
1
  - if resource.users.any?
8
2
  .contact-emails
9
3
  %label= Contact.human_attribute_name(:users)
@@ -14,6 +8,12 @@
14
8
  = "(#{user.options.type})" if user.options.type
15
9
  = "(primary)" if user.primary?
16
10
 
11
+ - if resource.phone_number_attributes.any?
12
+ .contact-phone-numbers
13
+ %label= Contact.human_attribute_name(:phone_number_attributes)
14
+ - resource.phone_number_attributes.each do |phone_number_attribute|
15
+ .contact-phone-number= phone_number_attribute
16
+
17
17
  - if resource.instant_messaging_handle_attributes.any?
18
18
  .contact-im-handles
19
19
  %label= Contact.human_attribute_name(:instant_messaging_handle_attributes)
@@ -25,7 +25,7 @@
25
25
  %label= Contact.human_attribute_name(:website_attributes)
26
26
  - resource.website_attributes.each do |website_attribute|
27
27
  .contact-website
28
- = auto_link(website_attribute.to_s, :rel => "external nofollow")
28
+ = link_to(website_attribute.to_s, website_attribute.to_s, :rel => "external nofollow")
29
29
 
30
30
  - if resource.address_attributes.any?
31
31
  .contact-addresses
@@ -14,3 +14,6 @@
14
14
  %td.links
15
15
  - field_map[:links][record].each do |link|
16
16
  = link
17
+
18
+ - if @controller.should_paginate_index
19
+ = will_paginate collection
@@ -12,4 +12,4 @@
12
12
 
13
13
  - if record.company_id?
14
14
  %span.contact-who-company
15
- = link_to_contact_search(:search, record.company_name)
15
+ = link_to_contact_search(:company, record.company_id, record.company_name)
@@ -3,7 +3,6 @@
3
3
  #index-body
4
4
  #records_table
5
5
  = render 'table', :resources => collection
6
- = render 'footer'
7
6
 
8
7
  #index-sidebar
9
8
  = render 'index_sidebar'
@@ -1,6 +1,8 @@
1
1
  .contact-body
2
2
  = title resource.name
3
- = render 'who', :record => resource
3
+ .contact-photo
4
+ %img{:src => resource.avatar_url, :alt => "Avatar for #{resource.name}"}
5
+ = render 'who', :record => resource, :hide_name => true
4
6
  .contact-links.actions
5
7
  = link_to_edit_resource(resource)
6
8
  = google_search_link(resource.name)
@@ -32,3 +32,6 @@
32
32
  = link_to_show_resource(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
@@ -25,11 +25,11 @@
25
25
  - collection.each do |record|
26
26
  %tr{:id => "ids_#{record.id}", :class => cycle('odd', 'even')}
27
27
  %td.record-campaign-type
28
- = record.campaign_type[/(.*)Campaign/, 1]
28
+ = display_campaign_type(record.campaign_type)
29
29
  %td.record-campaign-name
30
- = record.campaign_name
30
+ = record.campaign_name || 'n/a'
31
31
  %td.record-campaign-group
32
- = record.campaign_group
32
+ = record.campaign_group || 'n/a'
33
33
  %td.record-new-visits
34
34
  - dat[:new_visits] << record.new_visits
35
35
  = record.new_visits
@@ -47,16 +47,16 @@
47
47
  = record.won_deal_count.to_i
48
48
  %td.record-total-value
49
49
  - dat[:total_value] << record.total_value
50
- = record.total_value
50
+ = record.total_value || no_money
51
51
  %td.record-averate-value
52
52
  - dat[:average_value] << record.average_value
53
- = record.average_value
53
+ = record.average_value || no_money
54
54
  %td.record-total-cost
55
55
  - dat[:total_cost] << record.total_cost
56
- = record.total_cost
56
+ = record.total_cost || no_money
57
57
  %td.record-average-cost
58
58
  - dat[:average_cost] << record.average_cost
59
- = record.average_cost
59
+ = record.average_cost || no_money
60
60
  %td.record-average-elapsed
61
61
  - dat[:average_elapsed] << record.average_elapsed
62
62
  = record.average_elapsed && "%s days" % record.average_elapsed || 'n/a'
@@ -75,12 +75,12 @@
75
75
  %td.record-won-deal-count
76
76
  = dat[:won_deal_count].sum.to_i
77
77
  %td.record-total-value
78
- = dat[:total_value].average
79
- %td.record-averate-value
80
- = dat[:average_value].average
78
+ = dat[:total_value].compact.sum.to_money
79
+ %td.record-average-value
80
+ = dat[:average_value].compact.average.to_money
81
81
  %td.record-total-cost
82
- = dat[:total_cost].compact.sum
82
+ = dat[:total_cost].compact.sum.to_money
83
83
  %td.record-average-cost
84
- = dat[:average_cost].compact.average
84
+ = dat[:average_cost].compact.average.to_money
85
85
  %td.record-average-elapsed
86
86
  = "%s days" % dat[:average_elapsed].compact.average
@@ -39,3 +39,6 @@
39
39
  %td.record-totals
40
40
  = dat[:value].sum
41
41
  %td
42
+
43
+ - if @controller.should_paginate_index
44
+ = will_paginate collection
@@ -2,7 +2,7 @@
2
2
  = f.label :name, nil, :class => :req
3
3
  = f.text_field :name
4
4
  .field
5
- = f.label :from_email
5
+ = f.label :from_email, nil, :class => :req
6
6
  = f.text_field :from_email
7
7
  .field
8
8
  = f.label :subject, nil, :class => :req
@@ -23,3 +23,6 @@
23
23
  = record.referer
24
24
  %td.record-remote-ip
25
25
  = record.remote_ip
26
+
27
+ - if @controller.should_paginate_index
28
+ = will_paginate collection
@@ -22,3 +22,6 @@
22
22
  %td.links
23
23
  - field_map[:links][record].each do |link|
24
24
  = link
25
+
26
+ - if @controller.should_paginate_index
27
+ = will_paginate collection
@@ -9,5 +9,3 @@
9
9
  - else
10
10
  %div#records_table
11
11
  = render 'table', :resources => collection
12
-
13
- = render 'footer'
@@ -3,9 +3,8 @@
3
3
  %fieldset
4
4
  %legend= e9_t(:salesperson_information_legend, :scope => 'e9_crm.campaigns')
5
5
  .field
6
- = f.label :sales_person_id
6
+ = f.label :sales_person_id, nil, :class => (f.object.type == 'SalesCampaign' ? :req : nil)
7
7
  = f.collection_select :sales_person_id, Contact.sales_persons.ordered.all, :id, :name, :prompt => true
8
8
  .field
9
9
  = help_label f, :sales_fee
10
10
  = f.text_field :sales_fee
11
-
@@ -16,7 +16,7 @@ en:
16
16
  send_email_template: Send Email
17
17
  send_email_newsletter: Send Newsletter
18
18
  contact_newsletter_confirmation: "The system will send the newsletter to all of the selected contacts (%{count}) if they are subscribed to receieve email. Are you sure you want to proceed?"
19
- no_contacts_notification: "You cannot send an email with no recipients!"
19
+ no_contacts_notification: "Either you have selected no contacts, or all of those selected are opted out of bulk email. Please correct this and try again."
20
20
  email_actions_legend: Email Actions
21
21
  search_options_legend: Search Filters
22
22
  contact_merges:
@@ -42,6 +42,7 @@ en:
42
42
  code:
43
43
  invalid: "%{attribute} must be comprised of letters and numbers only."
44
44
  contact:
45
+ delete_restricted: "This contact is related to leads and/or deals and can not be deleted."
45
46
  attributes:
46
47
  users:
47
48
  taken: "Two or more of the login accounts entered share a duplicate email."
@@ -49,7 +50,7 @@ en:
49
50
  contact_email:
50
51
  attributes:
51
52
  contact_ids:
52
- blank: "You cannot send an email with no recipients!"
53
+ blank: "Either you have selected no contacts, or all of those selected are opted out of bulk email. Please correct this and try again."
53
54
  user_ids:
54
55
  blank: "None of the contacts selected are configured with primary emails. Please correct this and try again."
55
56
  deal:
@@ -78,7 +79,7 @@ en:
78
79
  menu_options: Menu Option
79
80
  new_content_subscription_offer: New Content Subscription Offer
80
81
  newsletter_subscription_offer: Newsletter Subscription Offer
81
- no_campaign: '(No Campaign)'
82
+ no_campaign: No Campaign
82
83
  offer: Offer
83
84
  page_view: Page View
84
85
  phone_number_attrubute: Phone
@@ -101,9 +102,11 @@ en:
101
102
  users: Email Addresses
102
103
  address_attributes: Addresses
103
104
  instant_messaging_handle_attributes: IM Handles
104
- phone_number_attrubutes: Phone Numbers
105
+ phone_number_attributes: Phone Numbers
105
106
  website_attributes: Websites
106
107
  info: Background Information
108
+ not_ok_to_email: "This contact will not receive bulk email."
109
+ tag_instructions: "Tags are words or phrases that describe or categorize this contact.\n\nWhen searching a particular tag, the system will show all contacts with that tag."
107
110
  company:
108
111
  info: Background Information
109
112
  deal:
data/e9_crm.gemspec CHANGED
@@ -23,8 +23,8 @@ Gem::Specification.new do |s|
23
23
  s.add_dependency("inherited_resources", "~> 1.1.2")
24
24
  s.add_dependency("has_scope")
25
25
  s.add_dependency("money")
26
- s.add_dependency("e9_rails", "~> 0.0.15")
27
- s.add_dependency("e9_tags", "~> 0.0.11")
26
+ s.add_dependency("e9_rails", "~> 0.0.16")
27
+ s.add_dependency("e9_tags", "~> 0.0.12")
28
28
  s.add_dependency("will_paginate")
29
29
  s.add_dependency("kramdown", "~> 0.13")
30
30
  end
@@ -1,3 +1,3 @@
1
1
  module E9Crm
2
- VERSION = '0.1.10'
2
+ VERSION = '0.1.11'
3
3
  end
@@ -26,6 +26,7 @@ class CreateE9CrmStructure < ActiveRecord::Migration
26
26
  t.string :title
27
27
  t.string :avatar
28
28
  t.string :status
29
+ t.boolean :ok_to_email, :default => true
29
30
  t.text :info
30
31
  t.references :company
31
32
  t.timestamps
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.10
5
+ version: 0.1.11
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-05-26 00:00:00 -04:00
13
+ date: 2011-05-27 00:00:00 -04:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -65,7 +65,7 @@ dependencies:
65
65
  requirements:
66
66
  - - ~>
67
67
  - !ruby/object:Gem::Version
68
- version: 0.0.15
68
+ version: 0.0.16
69
69
  type: :runtime
70
70
  version_requirements: *id005
71
71
  - !ruby/object:Gem::Dependency
@@ -76,7 +76,7 @@ dependencies:
76
76
  requirements:
77
77
  - - ~>
78
78
  - !ruby/object:Gem::Version
79
- version: 0.0.11
79
+ version: 0.0.12
80
80
  type: :runtime
81
81
  version_requirements: *id006
82
82
  - !ruby/object:Gem::Dependency
@@ -216,13 +216,10 @@ files:
216
216
  - app/views/e9_crm/advertising_campaigns/_form_inner.html.haml
217
217
  - app/views/e9_crm/advertising_campaigns/costs.html.haml
218
218
  - app/views/e9_crm/affiliate_campaigns/_form_inner.html.haml
219
- - app/views/e9_crm/campaign_groups/_footer.html.haml
220
219
  - app/views/e9_crm/campaign_groups/_form_inner.html.haml
221
220
  - app/views/e9_crm/campaign_groups/_header.html.haml
222
- - app/views/e9_crm/campaigns/_footer.html.haml
223
221
  - app/views/e9_crm/campaigns/_form_inner.html.haml
224
222
  - app/views/e9_crm/campaigns/_header.html.haml
225
- - app/views/e9_crm/campaigns/_reports_table.html.haml
226
223
  - app/views/e9_crm/campaigns/_table.html.haml
227
224
  - app/views/e9_crm/campaigns/reports.html.haml
228
225
  - app/views/e9_crm/companies/_form_inner.html.haml
@@ -259,7 +256,6 @@ files:
259
256
  - app/views/e9_crm/dated_costs/new.html.haml
260
257
  - app/views/e9_crm/dated_costs/show.html.haml
261
258
  - app/views/e9_crm/dated_costs/update.js.erb
262
- - app/views/e9_crm/deals/_footer.html.haml
263
259
  - app/views/e9_crm/deals/_form_inner.html.haml
264
260
  - app/views/e9_crm/deals/_header.html.haml
265
261
  - app/views/e9_crm/deals/_leads_header.html.haml
@@ -272,7 +268,6 @@ files:
272
268
  - app/views/e9_crm/deals/reports.html.haml
273
269
  - app/views/e9_crm/deals/reports.js.erb
274
270
  - app/views/e9_crm/email_campaigns/_form_inner.html.haml
275
- - app/views/e9_crm/email_templates/_footer.html.haml
276
271
  - app/views/e9_crm/email_templates/_form_inner.html.haml
277
272
  - app/views/e9_crm/email_templates/_header.html.haml
278
273
  - app/views/e9_crm/file_download_offers/_form.html.haml
@@ -280,12 +275,10 @@ files:
280
275
  - app/views/e9_crm/leads/_form.html.haml
281
276
  - app/views/e9_crm/leads/create.js.erb
282
277
  - app/views/e9_crm/leads/new.html.haml
283
- - app/views/e9_crm/menu_options/_footer.html.haml
284
278
  - app/views/e9_crm/menu_options/_form_inner.html.haml
285
279
  - app/views/e9_crm/menu_options/_header.html.haml
286
280
  - app/views/e9_crm/new_content_subscription_offers/_form_inner.html.haml
287
281
  - app/views/e9_crm/newsletter_subscription_offers/_form_inner.html.haml
288
- - app/views/e9_crm/offers/_footer.html.haml
289
282
  - app/views/e9_crm/offers/_form_inner.html.haml
290
283
  - app/views/e9_crm/offers/_header.html.haml
291
284
  - app/views/e9_crm/offers/_offer.html.haml
@@ -300,7 +293,6 @@ files:
300
293
  - app/views/e9_crm/record_attributes/_templates.js.erb
301
294
  - app/views/e9_crm/record_attributes/_user.html.haml
302
295
  - app/views/e9_crm/record_attributes/_website_attribute.html.haml
303
- - app/views/e9_crm/resources/_footer.html.haml
304
296
  - app/views/e9_crm/resources/_form.html.haml
305
297
  - app/views/e9_crm/resources/_form_inner.html.haml
306
298
  - app/views/e9_crm/resources/_header.html.haml
File without changes
File without changes
@@ -1,31 +0,0 @@
1
- %table.records
2
- %thead
3
- %tr
4
- %th= orderable_column_link(:type)
5
- %th= orderable_column_link(:name)
6
- %th= orderable_column_link('campaign_group.name', :campaign_group)
7
- %th= orderable_column_link(:new_visits)
8
- %th= orderable_column_link(:repeat_visits)
9
- %th= orderable_column_link(:deals_count)
10
- %th= orderable_column_link(:won_deals_count)
11
- %tbody
12
- - if collection.empty?
13
- %tr
14
- %td{:colspan => 5}= e9_t(:no_records_text)
15
- - else
16
- - collection.each do |record|
17
- %tr{:id => "ids_#{record.id}", :class => cycle('odd', 'even')}
18
- %td.record-type
19
- = record.type[/(.*)Campaign/, 1]
20
- %td.record-name
21
- = record.name
22
- %td.record-campaign-group
23
- = record.campaign_group || e9_t(:no_group, :scope => 'e9_crm.campaigns')
24
- %td.record-new-visits
25
- = record.new_visits
26
- %td.record-repeat-visits
27
- = record.repeat_visits
28
- %td.record-deals-count
29
- = record.deals_count
30
- %td.record-won-deals-count
31
- = record.won_deals_count
File without changes
File without changes
File without changes
File without changes
@@ -1 +0,0 @@
1
- = will_paginate collection