e9_crm 0.1.10 → 0.1.11

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