e9_crm 0.1.4 → 0.1.5

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 (53) hide show
  1. data/Gemfile.lock +38 -45
  2. data/app/controllers/e9_crm/advertising_campaigns_controller.rb +1 -1
  3. data/app/controllers/e9_crm/affiliate_campaigns_controller.rb +1 -1
  4. data/app/controllers/e9_crm/campaign_subclass_controller.rb +8 -0
  5. data/app/controllers/e9_crm/campaigns_controller.rb +16 -16
  6. data/app/controllers/e9_crm/contact_emails_controller.rb +3 -1
  7. data/app/controllers/e9_crm/contacts_controller.rb +29 -0
  8. data/app/controllers/e9_crm/dated_costs_controller.rb +60 -2
  9. data/app/controllers/e9_crm/email_campaigns_controller.rb +1 -1
  10. data/app/controllers/e9_crm/email_templates.controller.rb +1 -0
  11. data/app/controllers/e9_crm/resources_controller.rb +14 -1
  12. data/app/controllers/e9_crm/sales_campaigns_controller.rb +1 -1
  13. data/app/helpers/e9_crm/base_helper.rb +10 -3
  14. data/app/helpers/e9_crm/companies_helper.rb +7 -0
  15. data/app/helpers/e9_crm/contacts_helper.rb +11 -3
  16. data/app/helpers/e9_crm/email_templates_helper.rb +7 -0
  17. data/app/models/advertising_campaign.rb +2 -0
  18. data/app/models/contact.rb +24 -9
  19. data/app/models/contact_email.rb +5 -4
  20. data/app/models/dated_cost.rb +24 -0
  21. data/app/models/deal.rb +9 -9
  22. data/app/views/e9_crm/advertising_campaigns/costs.html.haml +0 -0
  23. data/app/views/e9_crm/campaigns/_table.html.haml +2 -0
  24. data/app/views/e9_crm/companies/_form_inner.html.haml +6 -0
  25. data/app/views/e9_crm/contacts/_contact.html.haml +1 -0
  26. data/app/views/e9_crm/contacts/_details.html.haml +12 -8
  27. data/app/views/e9_crm/contacts/_form_inner.html.haml +18 -32
  28. data/app/views/e9_crm/contacts/_who.html.haml +14 -0
  29. data/app/views/e9_crm/contacts/index.html.haml +4 -5
  30. data/app/views/e9_crm/dated_costs/_dated_cost.html.haml +8 -0
  31. data/app/views/e9_crm/dated_costs/_form.html.haml +3 -0
  32. data/app/views/e9_crm/dated_costs/_form_inner.html.haml +15 -0
  33. data/app/views/e9_crm/dated_costs/bulk_form.html.haml +20 -0
  34. data/app/views/e9_crm/dated_costs/create.js.erb +5 -0
  35. data/app/views/e9_crm/dated_costs/destroy.js.erb +3 -0
  36. data/app/views/e9_crm/dated_costs/edit.html.haml +3 -0
  37. data/app/views/e9_crm/dated_costs/edit.js.erb +1 -0
  38. data/app/views/e9_crm/dated_costs/index.html.haml +15 -0
  39. data/app/views/e9_crm/dated_costs/new.html.haml +2 -0
  40. data/app/views/e9_crm/dated_costs/show.html.haml +1 -0
  41. data/app/views/e9_crm/dated_costs/update.js.erb +5 -0
  42. data/app/views/e9_crm/email_templates/_footer.html.haml +0 -0
  43. data/app/views/e9_crm/email_templates/_form_inner.html.haml +3 -0
  44. data/app/views/e9_crm/email_templates/_header.html.haml +3 -0
  45. data/app/views/e9_crm/record_attributes/_form_partial.html.haml +4 -0
  46. data/app/views/e9_crm/resources/show.html.haml +1 -1
  47. data/config/locales/en.yml +17 -0
  48. data/config/routes.rb +14 -2
  49. data/e9_crm.gemspec +1 -1
  50. data/lib/e9_crm/model.rb +1 -1
  51. data/lib/e9_crm/version.rb +1 -1
  52. data/lib/generators/e9_crm/templates/migration.rb +2 -0
  53. metadata +25 -3
data/Gemfile.lock CHANGED
@@ -1,9 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- e9_crm (0.1.0)
5
- e9_rails (~> 0.0.4)
6
- e9_tags (~> 0.0.2)
4
+ e9_crm (0.1.4)
5
+ e9_rails (~> 0.0.13)
6
+ e9_tags (~> 0.0.11)
7
7
  has_scope
8
8
  inherited_resources (~> 1.1.2)
9
9
  money
@@ -14,39 +14,39 @@ GEM
14
14
  remote: http://rubygems.org/
15
15
  specs:
16
16
  abstract (1.0.0)
17
- actionmailer (3.0.5)
18
- actionpack (= 3.0.5)
17
+ actionmailer (3.0.6)
18
+ actionpack (= 3.0.6)
19
19
  mail (~> 2.2.15)
20
- actionpack (3.0.5)
21
- activemodel (= 3.0.5)
22
- activesupport (= 3.0.5)
20
+ actionpack (3.0.6)
21
+ activemodel (= 3.0.6)
22
+ activesupport (= 3.0.6)
23
23
  builder (~> 2.1.2)
24
24
  erubis (~> 2.6.6)
25
- i18n (~> 0.4)
25
+ i18n (~> 0.5.0)
26
26
  rack (~> 1.2.1)
27
- rack-mount (~> 0.6.13)
27
+ rack-mount (~> 0.6.14)
28
28
  rack-test (~> 0.5.7)
29
29
  tzinfo (~> 0.3.23)
30
- activemodel (3.0.5)
31
- activesupport (= 3.0.5)
30
+ activemodel (3.0.6)
31
+ activesupport (= 3.0.6)
32
32
  builder (~> 2.1.2)
33
- i18n (~> 0.4)
34
- activerecord (3.0.5)
35
- activemodel (= 3.0.5)
36
- activesupport (= 3.0.5)
33
+ i18n (~> 0.5.0)
34
+ activerecord (3.0.6)
35
+ activemodel (= 3.0.6)
36
+ activesupport (= 3.0.6)
37
37
  arel (~> 2.0.2)
38
38
  tzinfo (~> 0.3.23)
39
- activeresource (3.0.5)
40
- activemodel (= 3.0.5)
41
- activesupport (= 3.0.5)
42
- activesupport (3.0.5)
39
+ activeresource (3.0.6)
40
+ activemodel (= 3.0.6)
41
+ activesupport (= 3.0.6)
42
+ activesupport (3.0.6)
43
43
  acts-as-taggable-on (2.0.6)
44
44
  arel (2.0.9)
45
45
  builder (2.1.2)
46
- e9_rails (0.0.4)
46
+ e9_rails (0.0.13)
47
47
  inherited_resources
48
48
  rails (~> 3.0.0)
49
- e9_tags (0.0.2)
49
+ e9_tags (0.0.11)
50
50
  acts-as-taggable-on (~> 2.0.6)
51
51
  rails (~> 3.0.0)
52
52
  erubis (2.6.6)
@@ -56,7 +56,7 @@ GEM
56
56
  inherited_resources (1.1.2)
57
57
  has_scope (~> 0.5.0)
58
58
  responders (~> 0.6.0)
59
- mail (2.2.15)
59
+ mail (2.2.19)
60
60
  activesupport (>= 2.3.6)
61
61
  i18n (>= 0.4.0)
62
62
  mime-types (~> 1.16)
@@ -65,41 +65,34 @@ GEM
65
65
  money (3.6.1)
66
66
  i18n (~> 0.4)
67
67
  polyglot (0.3.1)
68
- rack (1.2.1)
69
- rack-mount (0.6.13)
68
+ rack (1.2.2)
69
+ rack-mount (0.6.14)
70
70
  rack (>= 1.0.0)
71
71
  rack-test (0.5.7)
72
72
  rack (>= 1.0)
73
- rails (3.0.5)
74
- actionmailer (= 3.0.5)
75
- actionpack (= 3.0.5)
76
- activerecord (= 3.0.5)
77
- activeresource (= 3.0.5)
78
- activesupport (= 3.0.5)
73
+ rails (3.0.6)
74
+ actionmailer (= 3.0.6)
75
+ actionpack (= 3.0.6)
76
+ activerecord (= 3.0.6)
77
+ activeresource (= 3.0.6)
78
+ activesupport (= 3.0.6)
79
79
  bundler (~> 1.0)
80
- railties (= 3.0.5)
81
- railties (3.0.5)
82
- actionpack (= 3.0.5)
83
- activesupport (= 3.0.5)
80
+ railties (= 3.0.6)
81
+ railties (3.0.6)
82
+ actionpack (= 3.0.6)
83
+ activesupport (= 3.0.6)
84
84
  rake (>= 0.8.7)
85
85
  thor (~> 0.14.4)
86
86
  rake (0.8.7)
87
- responders (0.6.2)
87
+ responders (0.6.4)
88
88
  thor (0.14.6)
89
89
  treetop (1.4.9)
90
90
  polyglot (>= 0.3.1)
91
- tzinfo (0.3.24)
92
- will_paginate (2.3.15)
91
+ tzinfo (0.3.27)
92
+ will_paginate (3.0.pre2)
93
93
 
94
94
  PLATFORMS
95
95
  ruby
96
96
 
97
97
  DEPENDENCIES
98
98
  e9_crm!
99
- e9_rails (~> 0.0.4)
100
- e9_tags (~> 0.0.2)
101
- has_scope
102
- inherited_resources (~> 1.1.2)
103
- money
104
- rails (~> 3.0.0)
105
- will_paginate
@@ -1,4 +1,4 @@
1
- class E9Crm::AdvertisingCampaignsController < E9Crm::ResourcesController
1
+ class E9Crm::AdvertisingCampaignsController < E9Crm::CampaignSubclassController
2
2
  defaults :resource_class => AdvertisingCampaign
3
3
  include E9Rails::Controllers::Orderable
4
4
  end
@@ -1,4 +1,4 @@
1
- class E9Crm::AffiliateCampaignsController < E9Crm::ResourcesController
1
+ class E9Crm::AffiliateCampaignsController < E9Crm::CampaignSubclassController
2
2
  defaults :resource_class => AffiliateCampaign
3
3
  include E9Rails::Controllers::Orderable
4
4
  end
@@ -0,0 +1,8 @@
1
+ class E9Crm::CampaignSubclassController < E9Crm::ResourcesController
2
+
3
+ protected
4
+
5
+ def add_index_breadcrumb
6
+ add_breadcrumb! Campaign.model_name.collection.titleize, campaigns_path
7
+ end
8
+ end
@@ -20,22 +20,22 @@ class E9Crm::CampaignsController < E9Crm::ResourcesController
20
20
 
21
21
  protected
22
22
 
23
- def set_reports_index_title
24
- @index_title = I18n.t(:reports_title, :scope => 'e9.e9_crm.campaigns')
25
- end
23
+ def set_reports_index_title
24
+ @index_title = I18n.t(:reports_title, :scope => 'e9.e9_crm.campaigns')
25
+ end
26
26
 
27
- def collection_scope
28
- scope = end_of_association_chain
29
- if params[:action] == 'reports'
30
- scope = scope.select(
31
- 'campaigns.*, count(deals.id) won_deals_count, count(deals_campaigns.id) deals_count'
32
- ).joins([:deals, :won_deals])
27
+ def collection_scope
28
+ scope = end_of_association_chain
29
+ if params[:action] == 'reports'
30
+ scope = scope.select(
31
+ 'campaigns.*, count(deals.id) won_deals_count, count(deals_campaigns.id) deals_count'
32
+ ).joins([:deals, :won_deals])
33
+ end
34
+ scope
35
+ end
36
+
37
+ # no pagination
38
+ def collection
39
+ get_collection_ivar || set_collection_ivar(collection_scope.all)
33
40
  end
34
- scope
35
- end
36
-
37
- # no pagination
38
- def collection
39
- get_collection_ivar || set_collection_ivar(collection_scope.all)
40
- end
41
41
  end
@@ -17,9 +17,11 @@ class E9Crm::ContactEmailsController < E9Crm::ResourcesController
17
17
  object = if params[resource_instance_name]
18
18
  ContactEmail.new(params[resource_instance_name] || {})
19
19
  else
20
- ContactEmail.new_from_template(template, :from_email => current_user.email, :contact_ids => params[:uids])
20
+ ContactEmail.new_from_template(template, :contact_ids => params[:uids])
21
21
  end
22
22
 
23
+ object.from_email ||= current_user.email
24
+
23
25
  object.valid?
24
26
 
25
27
  set_resource_ivar(object)
@@ -6,8 +6,11 @@ class E9Crm::ContactsController < E9Crm::ResourcesController
6
6
 
7
7
  respond_to :js, :html
8
8
 
9
+ carrierwave_column_methods :avatar, :context => :admin
10
+
9
11
  before_filter :determine_title, :only => :index
10
12
  before_filter :load_contact_ids, :only => :index
13
+ before_filter :build_nested_associations, :only => [:new, :edit]
11
14
 
12
15
  has_scope :search, :by_title, :by_company, :only => :index
13
16
  has_scope :tagged, :only => :index, :type => :array
@@ -17,8 +20,20 @@ class E9Crm::ContactsController < E9Crm::ResourcesController
17
20
  before_filter :build_resource, :only => :templates
18
21
  caches_action :templates
19
22
 
23
+ def create
24
+ create! { resource_path }
25
+ end
26
+
27
+ def update
28
+ update! { resource_path }
29
+ end
30
+
20
31
  protected
21
32
 
33
+ #
34
+ # Load all contact ids for the request (no pagination) using a direct sql query
35
+ # for the contact_id rather than loading all contacts.
36
+ #
22
37
  def load_contact_ids
23
38
  @contact_ids ||= begin
24
39
  contact_id_sql = end_of_association_chain.scoped.select('contacts.id').to_sql
@@ -26,6 +41,9 @@ class E9Crm::ContactsController < E9Crm::ResourcesController
26
41
  end
27
42
  end
28
43
 
44
+ #
45
+ # Change title depending on search params (tags & search)
46
+ #
29
47
  def determine_title
30
48
  params.delete(:search) if params[:search].blank?
31
49
 
@@ -38,6 +56,17 @@ class E9Crm::ContactsController < E9Crm::ResourcesController
38
56
  end
39
57
  end
40
58
 
59
+ def collection_scope
60
+ #TODO fix eager loading, which totally breaks because of the left outer joins in search
61
+ #super.includes(:users => :subscriptions)
62
+ scope = super
63
+ end
64
+
65
+ def build_nested_associations
66
+ object = params[:id] ? resource : build_resource
67
+ object.build_all_record_attributes
68
+ end
69
+
41
70
  def default_ordered_on
42
71
  'first_name'
43
72
  end
@@ -1,5 +1,63 @@
1
- class E9Crm::DatedCostsController < E9Crm::ResourcesController
2
- belongs_to :advertising_campaign
1
+ class E9Crm::DatedCostsController < E9Crm::CampaignSubclassController
2
+ belongs_to :advertising_campaign, :optional => true
3
3
  defaults :resource_class => DatedCost
4
4
  include E9Rails::Controllers::Orderable
5
+
6
+ filter_access_to :bulk_create, :require => :create, :context => :admin
7
+
8
+ before_filter :add_breadcrumbs
9
+ before_filter :generate_temp_id, :only => :new
10
+
11
+ def index
12
+ if params[:advertising_campaign_id]
13
+ index!
14
+ else
15
+ @advertising_campaigns = AdvertisingCampaign.all
16
+ render 'bulk_form'
17
+ end
18
+ end
19
+
20
+ def bulk_create
21
+ params[:id].zip(params[:cost]) do |id, cost|
22
+ DatedCost.create(
23
+ :costable_id => id,
24
+ :costable_type => AdvertisingCampaign.base_class.name,
25
+ :date => params[:date],
26
+ :cost => cost
27
+ )
28
+ end
29
+
30
+ flash[:notice] = "Advertising Costs Added"
31
+ redirect_to :marketing_report
32
+ end
33
+
34
+ protected
35
+
36
+ def collection
37
+ get_collection_ivar || set_collection_ivar(end_of_association_chain.all)
38
+ end
39
+
40
+ def default_ordered_on
41
+ 'date'
42
+ end
43
+
44
+ def default_ordered_dir
45
+ 'ASC'
46
+ end
47
+
48
+ def add_breadcrumbs
49
+ if parent?
50
+ add_breadcrumb! parent.name, edit_advertising_campaign_path(parent)
51
+ end
52
+
53
+ add_breadcrumb! e9_t(:index_title)
54
+ end
55
+
56
+ def determine_layout
57
+ request.xhr? ? false : super
58
+ end
59
+
60
+ def generate_temp_id
61
+ @temp_id ||= DateTime.now.to_i
62
+ end
5
63
  end
@@ -1,4 +1,4 @@
1
- class E9Crm::EmailCampaignsController < E9Crm::ResourcesController
1
+ class E9Crm::EmailCampaignsController < E9Crm::CampaignSubclassController
2
2
  defaults :resource_class => EmailCampaign
3
3
  include E9Rails::Controllers::Orderable
4
4
  end
@@ -1,4 +1,5 @@
1
1
  class E9Crm::EmailTemplatesController < E9Crm::ResourcesController
2
2
  defaults
3
3
  include E9Rails::Controllers::Orderable
4
+ self.should_paginate_index = false
4
5
  end
@@ -2,6 +2,9 @@ class E9Crm::ResourcesController < E9Crm::BaseController
2
2
  include E9Rails::Helpers::ResourceErrorMessages
3
3
  include E9Rails::Helpers::Pagination
4
4
 
5
+ class_inheritable_accessor :should_paginate_index
6
+ self.should_paginate_index = true
7
+
5
8
  inherit_resources
6
9
 
7
10
  respond_to :js
@@ -27,11 +30,21 @@ class E9Crm::ResourcesController < E9Crm::BaseController
27
30
  helper_method :parent
28
31
 
29
32
  def add_index_breadcrumb
33
+ yield if block_given?
30
34
  add_breadcrumb! @index_title || e9_t(:index_title), collection_path
31
35
  end
32
36
 
37
+ # expose collection scope to be overridden
38
+ def collection_scope
39
+ end_of_association_chain
40
+ end
41
+
33
42
  def collection
34
- get_collection_ivar || set_collection_ivar(end_of_association_chain.paginate(pagination_parameters))
43
+ get_collection_ivar || begin
44
+ set_collection_ivar(
45
+ collection_scope.send *(should_paginate_index ? [:paginate, pagination_parameters] : [:all])
46
+ )
47
+ end
35
48
  end
36
49
 
37
50
  def default_ordered_on
@@ -1,4 +1,4 @@
1
- class E9Crm::SalesCampaignsController < E9Crm::ResourcesController
1
+ class E9Crm::SalesCampaignsController < E9Crm::CampaignSubclassController
2
2
  defaults :resource_class => SalesCampaign
3
3
  include E9Rails::Controllers::Orderable
4
4
  end
@@ -6,7 +6,7 @@ module E9Crm::BaseHelper
6
6
 
7
7
  def records_table_field_map(options = {})
8
8
  options.symbolize_keys!
9
- options.reverse_merge!(:class_name => resource_class.base_class.name.underscore)
9
+ options.reverse_merge!(:class_name => resource_class.name.underscore)
10
10
 
11
11
  base_map = {
12
12
  :fields => { :id => nil },
@@ -44,6 +44,13 @@ module E9Crm::BaseHelper
44
44
  )
45
45
  end
46
46
 
47
+ def render_record_attribute_form(association_name, form)
48
+ render('e9_crm/record_attributes/form_partial', {
49
+ :form => form,
50
+ :association_name => association_name
51
+ })
52
+ end
53
+
47
54
  def render_record_attribute_association(association_name, form, options = {})
48
55
  options.symbolize_keys!
49
56
 
@@ -59,10 +66,10 @@ module E9Crm::BaseHelper
59
66
  def record_attribute_template(association_name, builder, options = {})
60
67
  options.symbolize_keys!
61
68
 
62
- render({
69
+ render(
63
70
  :partial => options[:partial] || "e9_crm/record_attributes/#{association_name.to_s.singularize}",
64
71
  :locals => { :f => builder }
65
- })
72
+ )
66
73
  end
67
74
 
68
75
  def build_associated_resource(association_name)
@@ -0,0 +1,7 @@
1
+ module E9Crm::CompaniesHelper
2
+ def records_table_field_map_for_company
3
+ {
4
+ :fields => { :name => nil }
5
+ }
6
+ end
7
+ end
@@ -12,6 +12,12 @@ module E9Crm::ContactsHelper
12
12
  options_for_select( UserEmail.pending.order('name').map {|e| [e.name, e.id] })
13
13
  end
14
14
 
15
+ def contact_user_subscribed_to_newsletter?(user)
16
+ @_newsletter ||= MailingList.newsletter
17
+
18
+ user.subscription_ids.include? @_newsletter.id
19
+ end
20
+
15
21
  def records_table_field_map_for_contact
16
22
  {
17
23
  :fields => {
@@ -19,9 +25,11 @@ module E9Crm::ContactsHelper
19
25
  :details => proc {|r| render('details', :record => r) }
20
26
  },
21
27
 
22
- :links => proc {|r|
23
- [link_to_show_resource(r), link_to_edit_resource(r), link_to_destroy_resource(r)]
24
- }
28
+ :links => proc {|r| [
29
+ link_to_show_resource(r),
30
+ link_to_edit_resource(r),
31
+ link_to_destroy_resource(r)
32
+ ]}
25
33
  }
26
34
  end
27
35
  end
@@ -0,0 +1,7 @@
1
+ module E9Crm::EmailTemplatesHelper
2
+ def records_table_field_map_for_email_template
3
+ {
4
+ :fields => { :name => nil }
5
+ }
6
+ end
7
+ end
@@ -5,6 +5,8 @@
5
5
  #
6
6
  class AdvertisingCampaign < Campaign
7
7
 
8
+ accepts_nested_attributes_for :dated_costs
9
+
8
10
  ##
9
11
  # The sum cost of this campaign
10
12
  #
@@ -94,6 +94,14 @@ class Contact < ActiveRecord::Base
94
94
  accepts_nested_attributes_for association_name.to_sym, :allow_destroy => true, :reject_if => :reject_record_attribute?
95
95
  end
96
96
 
97
+ def build_all_record_attributes
98
+ RECORD_ATTRIBUTES.each do |attr|
99
+ params_method = "#{attr}_build_parameters"
100
+ build_params = self.class.send(params_method) if self.class.respond_to?(params_method)
101
+ send(attr).send(:build, build_params || {})
102
+ end
103
+ end
104
+
97
105
  ##
98
106
  # Validations
99
107
  #
@@ -119,15 +127,18 @@ class Contact < ActiveRecord::Base
119
127
  LEFT OUTER JOIN record_attributes
120
128
  ON record_attributes.record_id = contacts.id
121
129
  AND record_attributes.record_type = 'Contact'
122
- LEFT OUTER JOIN users
123
- ON users.contact_id = contacts.id
130
+ LEFT OUTER JOIN users AS contacts_users
131
+ ON contacts_users.contact_id = contacts.id
124
132
  }
125
133
 
126
- joins(join_sql).group('contacts.id').where(
127
- any_attrs_like_scope_conditions(:first_name, :last_name, :title, query)
128
- .or(RecordAttribute.attr_like_scope_condition(:value, query))
129
- .or(User.attr_like_scope_condition(:email, query))
130
- )
134
+ where_sql = any_attrs_like_scope_conditions(:first_name, :last_name, :title, query)
135
+ .or(RecordAttribute.attr_like_scope_condition(:value, query))
136
+ .to_sql
137
+
138
+ ucond = sanitize_sql_array(['contacts_users.email like ?', "%#{query}%"])
139
+ where_sql << " OR (#{ucond})"
140
+
141
+ select("distinct contacts.*").joins(join_sql).where(where_sql)
131
142
  }
132
143
 
133
144
  scope :sales_persons, lambda { where(:status => Status::SalesPerson) }
@@ -152,7 +163,7 @@ class Contact < ActiveRecord::Base
152
163
 
153
164
  # The parameters for building the JS template for associated users
154
165
  def self.users_build_parameters # :nodoc:
155
- { :status => User::Status::PROSPECT }
166
+ { :status => User::Status::Prospect }
156
167
  end
157
168
 
158
169
  ##
@@ -267,8 +278,12 @@ class Contact < ActiveRecord::Base
267
278
  reject_record_attribute?(hash) || super
268
279
  end
269
280
 
281
+ #
282
+ # #TODO figure out exactly how to handle rejection of Users
283
+ #
270
284
  def reject_record_attribute?(attributes)
271
- attributes.keys.member?('value') && attributes['value'].blank?
285
+ attributes.keys.member?('value') && attributes['value'].blank? ||
286
+ attributes.keys.member?('email') && attributes['email'].blank?
272
287
  end
273
288
 
274
289
  module Status
@@ -13,10 +13,11 @@ class ContactEmail < Email
13
13
  class << self
14
14
  def new_from_template(template, attrs = {})
15
15
  new({
16
- :name => "#{template.name} - #{DateTime.now.to_i}",
17
- :subject => template.subject,
18
- :html_body => template.html_body,
19
- :text_body => template.text_body
16
+ :name => "#{template.name} - #{DateTime.now.to_i}",
17
+ :subject => template.subject,
18
+ :from_email => template.from_email,
19
+ :html_body => template.html_body,
20
+ :text_body => template.text_body
20
21
  }.merge(attrs))
21
22
  end
22
23
  end
@@ -3,7 +3,31 @@
3
3
  # date so sums for date ranges can be generated.
4
4
  #
5
5
  class DatedCost < ActiveRecord::Base
6
+ include E9Rails::ActiveRecord::Initialization
7
+
6
8
  money_columns :cost
7
9
  belongs_to :costable, :polymorphic => true
8
10
  validates :date, :date => true
11
+ validates :cost, :numericality => { :greater_than => 0 }
12
+
13
+ attr_accessor :temp_id
14
+
15
+ def as_json(options={})
16
+ {}.tap do |hash|
17
+ hash[:id] = self.id
18
+ hash[:cost] = self.cost
19
+ hash[:date] = self.date
20
+ hash[:costable_type] = self.costable_type.try(:underscore)
21
+ hash[:costable_id] = self.costable_id
22
+ hash[:errors] = self.errors
23
+
24
+ hash.merge!(options)
25
+ end
26
+ end
27
+
28
+ protected
29
+
30
+ def _assign_initialization_defaults
31
+ self.date ||= Date.today
32
+ end
9
33
  end
data/app/models/deal.rb CHANGED
@@ -31,29 +31,29 @@ class Deal < ActiveRecord::Base
31
31
  SUM(IF(deals.status='won',value,0)) total_value,
32
32
  AVG(IF(deals.status='won',value,NULL)) average_value,
33
33
 
34
- (CASE campaigns.type
35
- WHEN "SalesCampaign"
36
- THEN SUM(campaigns.sales_fee)
34
+ SUM(CASE campaigns.type
37
35
  WHEN "AdvertisingCampaign"
38
36
  THEN dated_costs.cost
37
+ WHEN "SalesCampaign"
38
+ THEN campaigns.sales_fee
39
39
  WHEN "AffiliateCampaign"
40
- THEN SUM(campaigns.sales_fee +
41
- campaigns.affiliate_fee)
40
+ THEN campaigns.sales_fee +
41
+ campaigns.affiliate_fee
42
42
  ELSE
43
43
  0
44
44
  END) total_cost,
45
45
 
46
- (CASE campaigns.type
47
- WHEN "SalesCampaign"
48
- THEN campaigns.sales_fee
46
+ SUM(CASE campaigns.type
49
47
  WHEN "AdvertisingCampaign"
50
48
  THEN dated_costs.cost
49
+ WHEN "SalesCampaign"
50
+ THEN campaigns.sales_fee
51
51
  WHEN "AffiliateCampaign"
52
52
  THEN campaigns.sales_fee +
53
53
  campaigns.affiliate_fee
54
54
  ELSE
55
55
  0
56
- END / COUNT(deals.id)) average_cost,
56
+ END) / SUM(IF(deals.status='won',1,0)) average_cost,
57
57
 
58
58
  FLOOR(AVG(
59
59
  DATEDIFF(
@@ -28,4 +28,6 @@
28
28
  %td.record-sales-fee
29
29
  = display_campaign_fee(record.sales_fee)
30
30
  %td.links
31
+ - if record.is_a?(AdvertisingCampaign)
32
+ = link_to t(:edit_dated_costs), advertising_campaign_dated_costs_path(record), :class => 'dated-costs'
31
33
  = link_to_edit_campaign(record)
@@ -0,0 +1,6 @@
1
+ .field
2
+ = f.label :name, nil, :class => :req
3
+ = f.text_field :name
4
+ .field.tinymce
5
+ = f.label :info
6
+ = f.text_area :info
@@ -0,0 +1 @@
1
+ = resource.name
@@ -1,10 +1,13 @@
1
- .contact-who
2
- %span.contact-name= record.name
3
- - if record.company_id? || record.title?
4
- = " - "
5
- = link_to_contact_search(:by_title, record.title) if record.title?
6
- = " at " if record.company_id? && record.title?
7
- = link_to_contact_search(:by_company, record.company_id, record.company_name) if record.company_id?
1
+ = render 'who', :record => record
2
+
3
+ - if record.users.any?
4
+ .contact-phone-numbers
5
+ - record.users.each do |user|
6
+ .contact-email
7
+ = '* ' if contact_user_subscribed_to_newsletter?(user)
8
+ = link_to(user.email, "mailto:#{user.email}")
9
+ = "(#{user.options.type})" if user.options.type
10
+ = "(primary)" if user.primary?
8
11
 
9
12
  - if record.phone_number_attributes.any?
10
13
  .contact-phone-numbers
@@ -19,4 +22,5 @@
19
22
  - if record.website_attributes.any?
20
23
  .contact-websites
21
24
  - record.website_attributes.each do |website_attribute|
22
- .contact-website= website_attribute
25
+ .contact-website
26
+ = auto_link(website_attribute.to_s, :rel => "external nofollow")
@@ -12,40 +12,26 @@
12
12
  .field
13
13
  = f.label :title
14
14
  = f.text_field :title
15
+ .field
16
+ = f.label :status
17
+ = f.select :status, Contact::Status::VALUES.map {|v| [v.titleize, v] }
18
+
19
+ = upload_mount_field(resource.avatar, :reset_path => true)
15
20
 
16
21
  = render 'e9_tags/form', :f => f, :context => [:users, true]
17
22
 
18
23
  %fieldset.contact-contact-fields
19
24
  %legend= e9_t(:form_legend_contact)
20
-
21
- %fieldset.nested-associations
22
- %legend
23
- %span= f.label(:users)
24
- = link_to_add_record_attribute(:users)
25
- = render_record_attribute_association(:users, f)
26
-
27
- %fieldset.nested-associations
28
- %legend
29
- %span= f.label(:phone_number_attributes)
30
- = link_to_add_record_attribute(:phone_number_attributes)
31
- = render_record_attribute_association(:phone_number_attributes, f)
32
-
33
- %fieldset.nested-associations
34
- %legend
35
- %span= f.label(:instant_messaging_handle_attributes)
36
- = link_to_add_record_attribute(:instant_messaging_handle_attributes)
37
- = render_record_attribute_association(:instant_messaging_handle_attributes, f)
38
-
39
- %fieldset.nested-associations
40
- %legend
41
- %span= f.label(:website_attributes)
42
- = link_to_add_record_attribute(:website_attributes)
43
- = render_record_attribute_association(:website_attributes, f)
44
-
45
- %fieldset.nested-associations
46
- %legend
47
- %span= f.label(:address_attributes)
48
- = link_to_add_record_attribute(:address_attributes)
49
- = render_record_attribute_association(:address_attributes, f)
50
-
51
- = javascript_include_tag templates_contacts_path
25
+ = render_record_attribute_form(:users , f)
26
+ = render_record_attribute_form(:phone_number_attributes , f)
27
+ = render_record_attribute_form(:instant_messaging_handle_attributes , f)
28
+ = render_record_attribute_form(:website_attributes , f)
29
+ = render_record_attribute_form(:address_attributes , f)
30
+
31
+ %fieldset.contact-background-info
32
+ %legend= f.label(:info)
33
+ .field.tinymce
34
+ = f.text_area :info
35
+
36
+ - content_for :bottom_javascripts do
37
+ = javascript_include_tag templates_contacts_path
@@ -0,0 +1,14 @@
1
+ .contact-who
2
+ %span.contact-who-name= record.name
3
+
4
+ = " - " if record.company_id? || record.title?
5
+
6
+ - if record.title?
7
+ %span.contact-who-title
8
+ = link_to_contact_search(:by_title, record.title)
9
+
10
+ = " at " if record.company_id? && record.title?
11
+
12
+ - if record.company_id?
13
+ %span.contact-who-company
14
+ = link_to_contact_search(:by_company, record.company_id, record.company_name)
@@ -1,13 +1,12 @@
1
1
  = title (@index_title || e9_t(:index_title))
2
2
 
3
-
4
- #index_header
3
+ #index-header
5
4
  = render 'header'
6
5
 
7
- #records_table
8
- = render 'table', :resources => collection
9
-
10
6
  #contact-tag-list
11
7
  = render 'tag_table'
12
8
 
9
+ #records_table
10
+ = render 'table', :resources => collection
11
+
13
12
  = render 'footer'
@@ -0,0 +1,8 @@
1
+ .dated-cost{:id => "dated_cost_#{dated_cost.id}"}
2
+ .field
3
+ = l(dated_cost.date)
4
+ .field.cost{':data-cost' => dated_cost.cost.to_f}
5
+ = dated_cost.cost
6
+ .actions
7
+ = link_to_edit_resource(dated_cost, :remote => true)
8
+ = link_to_destroy_resource(dated_cost, :remote => true)
@@ -0,0 +1,3 @@
1
+ = form_for resource, :url => polymorphic_path([parent, resource]), :remote => request.xhr? do |f|
2
+ .errors= resource_error_messages!
3
+ = render 'form_inner', :f => f
@@ -0,0 +1,15 @@
1
+ - id = f.object.persisted? ? f.object.id : @temp_id
2
+ .field.date-picker
3
+ - if temp_id = f.object.temp_id || @temp_id
4
+ = f.hidden_field :temp_id, :value => temp_id
5
+ - fid = "dated_cost_date_#{id}"
6
+ - unless request.xhr?
7
+ = f.label :date, nil, :class => :req, :for => id
8
+ = f.text_field :date, :class => 'date-picker', :value => l(f.object.date), :id => id
9
+ .field
10
+ - fid = "dated_cost_cost_#{id}"
11
+ - unless request.xhr?
12
+ = f.label :cost, nil, :class => :req, :for => id
13
+ = f.text_field :cost, :id => id
14
+ .actions
15
+ = f.submit
@@ -0,0 +1,20 @@
1
+ = form_tag bulk_create_dated_costs_path do
2
+ .field.date-picker
3
+ = label_tag 'dated_cost_date', resource_class.human_attribute_name(:date)
4
+ %input{:id => 'dated_cost_date', :type => 'text', :class => 'date-picker', :name => 'date', :value => l(params[:date] || Date.today)}
5
+
6
+ %table
7
+ %thead
8
+ %th= AdvertisingCampaign.model_name.human
9
+ %th= resource_class.human_attribute_name(:cost)
10
+ %tbody
11
+ - @advertising_campaigns.each do |ac|
12
+ %tr
13
+ %td
14
+ = ac.name
15
+ %td
16
+ %input{:type => 'hidden', :name => 'id[]', :value => ac.id}
17
+ %input{:type => 'text', :name => 'cost[]'}
18
+
19
+ .actions
20
+ = submit_tag
@@ -0,0 +1,5 @@
1
+ <% if resource.errors.any? %>
2
+ $("#dated_cost_<%= resource.temp_id %>").html("<%= escape_javascript(render('form')) %>");
3
+ <% else %>
4
+ $("#dated_cost_<%= resource.temp_id %>").replaceWith("<%= escape_javascript(render(resource)) %>");
5
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <% if !resource.errors.any? %>
2
+ $("#dated_cost_<%= resource.id %>").fadeOut();
3
+ <% end %>
@@ -0,0 +1,3 @@
1
+ - id = resource.persisted? ? "dated_cost_#{resource.id}" : nil
2
+ .dated-cost{:id => id }
3
+ = render 'form'
@@ -0,0 +1 @@
1
+ $("#dated_cost_<%= resource.id %>").html("<%= escape_javascript(render('form')) %>");
@@ -0,0 +1,15 @@
1
+ = title @index_title || e9_t(:index_title)
2
+
3
+ %fieldset
4
+ .dated-costs
5
+ .dated-cost-labels
6
+ .field
7
+ = resource_class.human_attribute_name(:date)
8
+ .field
9
+ = resource_class.human_attribute_name(:cost)
10
+
11
+ = render collection
12
+
13
+ .actions
14
+ = link_to_new_resource(resource_class, :remote => true)
15
+
@@ -0,0 +1,2 @@
1
+ .dated-cost{:id => "dated_cost_#{@temp_id}"}
2
+ = render 'form'
@@ -0,0 +1 @@
1
+ = render resource
@@ -0,0 +1,5 @@
1
+ <% if resource.errors.any? %>
2
+ $("#dated_cost_<%= resource.id %>").html("<%= escape_javascript(render('form')) %>");
3
+ <% else %>
4
+ $("#dated_cost_<%= resource.id %>").replaceWith("<%= escape_javascript(render(resource)) %>");
5
+ <% end %>
@@ -1,6 +1,9 @@
1
1
  .field
2
2
  = f.label :name, nil, :class => :req
3
3
  = f.text_field :name
4
+ .field
5
+ = f.label :from_email
6
+ = f.text_field :from_email
4
7
  .field
5
8
  = f.label :subject, nil, :class => :req
6
9
  = f.text_field :subject
@@ -0,0 +1,3 @@
1
+ .toolbar
2
+ .toolbar-right
3
+ = link_to_new_resource(EmailTemplate)
@@ -0,0 +1,4 @@
1
+ %fieldset.nested-associations
2
+ %legend= form.label(association_name)
3
+ = render_record_attribute_association(association_name, form)
4
+ = link_to_add_record_attribute(association_name)
@@ -1,2 +1,2 @@
1
1
  = title e9_t(:show_title)
2
- = render 'form'
2
+ = render resource
@@ -6,12 +6,18 @@ en:
6
6
  none: None
7
7
  totals: Totals
8
8
  inline_help_link: '[?]'
9
+ edit_dated_costs: Edit Costs
9
10
 
10
11
  e9_crm:
11
12
  add_record_attribute: Add
12
13
  destroy_record_attribute: Remove
13
14
 
14
15
  activerecord:
16
+ titles:
17
+ show: 'Show %{model}'
18
+ campaign:
19
+ show: '%{model}'
20
+
15
21
  links:
16
22
  edit: "Edit"
17
23
  destroy: "Delete"
@@ -54,6 +60,7 @@ en:
54
60
  campaign_type: Campaign Type
55
61
  company: Company
56
62
  contact: Contact
63
+ dated_cost: Advertising Cost
57
64
  deal: Deal
58
65
  page_view: Page View
59
66
  tracking_cookie: Tracking Cookie
@@ -62,6 +69,16 @@ en:
62
69
  campaign:
63
70
  name: Name
64
71
  code_hint: Append to URL
72
+ contact:
73
+ avatar: Photo
74
+ users: Email Addresses
75
+ address_attributes: Addresses
76
+ instant_messaging_handle_attributes: Instant Messaging Handles
77
+ phone_number_attrubutes: Phone Numbers
78
+ website_attributes: Websites
79
+ info: Background Information
80
+ company:
81
+ info: Background Information
65
82
  no_campaign:
66
83
  name: No Campaign
67
84
  offer:
data/config/routes.rb CHANGED
@@ -3,9 +3,15 @@ Rails.application.routes.draw do
3
3
 
4
4
  scope :path => crm_path, :module => :e9_crm do
5
5
  resources :companies, :except => :show
6
- resources :contacts, :except => :show do
6
+ resources :contacts do
7
+ # page_views currently not routed, but near working
7
8
  #resources :page_views, :path => 'activity', :only => :index
9
+
8
10
  collection { get :templates }
11
+ member do
12
+ post :upload_avatar
13
+ delete :reset_avatar
14
+ end
9
15
  end
10
16
  resources :deals, :except => :show
11
17
  resources :offers, :except => :show
@@ -18,7 +24,14 @@ Rails.application.routes.draw do
18
24
  collection { post :update_order }
19
25
  end
20
26
 
27
+ resources :dated_costs, :path => 'advertising_costs', :only => [:index] do
28
+ collection do
29
+ post :bulk_create
30
+ end
31
+ end
32
+
21
33
  resources :campaigns, :only => [:index, :destroy] do
34
+ # page_views currently not routed, but near working
22
35
  #resources :page_views, :path => 'activity', :only => :index
23
36
  end
24
37
  scope :path => :campaigns do
@@ -51,7 +64,6 @@ Rails.application.routes.draw do
51
64
  campaigns/email
52
65
  campaigns/sales
53
66
  campaigns/groups
54
- contacts
55
67
  deals
56
68
  email_templates
57
69
  menu_options
data/e9_crm.gemspec CHANGED
@@ -23,7 +23,7 @@ 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.13")
26
+ s.add_dependency("e9_rails", "~> 0.0.14")
27
27
  s.add_dependency("e9_tags", "~> 0.0.11")
28
28
  s.add_dependency("will_paginate")
29
29
  end
data/lib/e9_crm/model.rb CHANGED
@@ -21,7 +21,7 @@ module E9Crm
21
21
 
22
22
  self.options_parameters = [:type, :primary]
23
23
 
24
- scope :primary, lambda { where(arel_table[:options].matches("%primary: true%")) }
24
+ scope :primary, lambda { where(%Q{#{table_name}.options REGEXP "primary: [\\"']?true"}) }
25
25
 
26
26
  before_create :create_contact_if_missing
27
27
  after_destroy :cleanup_contact
@@ -1,3 +1,3 @@
1
1
  module E9Crm
2
- VERSION = '0.1.4'
2
+ VERSION = '0.1.5'
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.text :info
29
30
  t.references :company
30
31
  t.timestamps
31
32
  end
@@ -63,6 +64,7 @@ class CreateE9CrmStructure < ActiveRecord::Migration
63
64
 
64
65
  create_table :companies, :force => true do |t|
65
66
  t.string :name
67
+ t.text :info
66
68
  t.timestamps
67
69
  end
68
70
 
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.4
5
+ version: 0.1.5
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-16 00:00:00 -04:00
13
+ date: 2011-05-18 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.13
68
+ version: 0.0.14
69
69
  type: :runtime
70
70
  version_requirements: *id005
71
71
  - !ruby/object:Gem::Dependency
@@ -140,6 +140,7 @@ files:
140
140
  - app/controllers/e9_crm/affiliate_campaigns_controller.rb
141
141
  - app/controllers/e9_crm/base_controller.rb
142
142
  - app/controllers/e9_crm/campaign_groups_controller.rb
143
+ - app/controllers/e9_crm/campaign_subclass_controller.rb
143
144
  - app/controllers/e9_crm/campaigns_controller.rb
144
145
  - app/controllers/e9_crm/companies_controller.rb
145
146
  - app/controllers/e9_crm/contact_emails_controller.rb
@@ -157,9 +158,11 @@ files:
157
158
  - app/helpers/e9_crm/base_helper.rb
158
159
  - app/helpers/e9_crm/campaign_groups_helper.rb
159
160
  - app/helpers/e9_crm/campaigns_helper.rb
161
+ - app/helpers/e9_crm/companies_helper.rb
160
162
  - app/helpers/e9_crm/contact_merges_helper.rb
161
163
  - app/helpers/e9_crm/contacts_helper.rb
162
164
  - app/helpers/e9_crm/deals_helper.rb
165
+ - app/helpers/e9_crm/email_templates_helper.rb
163
166
  - app/helpers/e9_crm/menu_options_helper.rb
164
167
  - app/helpers/e9_crm/page_views_helper.rb
165
168
  - app/models/address_attribute.rb
@@ -189,6 +192,7 @@ files:
189
192
  - app/observers/deal_observer.rb
190
193
  - app/uploaders/file_uploader.rb
191
194
  - app/views/e9_crm/advertising_campaigns/_form_inner.html.haml
195
+ - app/views/e9_crm/advertising_campaigns/costs.html.haml
192
196
  - app/views/e9_crm/affiliate_campaigns/_form_inner.html.haml
193
197
  - app/views/e9_crm/campaign_groups/_footer.html.haml
194
198
  - app/views/e9_crm/campaign_groups/_header.html.haml
@@ -198,6 +202,7 @@ files:
198
202
  - app/views/e9_crm/campaigns/_reports_table.html.haml
199
203
  - app/views/e9_crm/campaigns/_table.html.haml
200
204
  - app/views/e9_crm/campaigns/reports.html.haml
205
+ - app/views/e9_crm/companies/_form_inner.html.haml
201
206
  - app/views/e9_crm/contact_emails/_form.html.haml
202
207
  - app/views/e9_crm/contact_emails/_form_inner.html.haml
203
208
  - app/views/e9_crm/contact_emails/destroy.js.erb
@@ -205,14 +210,28 @@ files:
205
210
  - app/views/e9_crm/contact_merges/_field.html.haml
206
211
  - app/views/e9_crm/contact_merges/_form.html.haml
207
212
  - app/views/e9_crm/contact_merges/new.html.haml
213
+ - app/views/e9_crm/contacts/_contact.html.haml
208
214
  - app/views/e9_crm/contacts/_details.html.haml
209
215
  - app/views/e9_crm/contacts/_form_inner.html.haml
210
216
  - app/views/e9_crm/contacts/_header.html.haml
211
217
  - app/views/e9_crm/contacts/_tag_table.html.haml
218
+ - app/views/e9_crm/contacts/_who.html.haml
212
219
  - app/views/e9_crm/contacts/index.html.haml
213
220
  - app/views/e9_crm/contacts/index.js.erb
214
221
  - app/views/e9_crm/contacts/merge.html.haml
215
222
  - app/views/e9_crm/contacts/templates.js.erb
223
+ - app/views/e9_crm/dated_costs/_dated_cost.html.haml
224
+ - app/views/e9_crm/dated_costs/_form.html.haml
225
+ - app/views/e9_crm/dated_costs/_form_inner.html.haml
226
+ - app/views/e9_crm/dated_costs/bulk_form.html.haml
227
+ - app/views/e9_crm/dated_costs/create.js.erb
228
+ - app/views/e9_crm/dated_costs/destroy.js.erb
229
+ - app/views/e9_crm/dated_costs/edit.html.haml
230
+ - app/views/e9_crm/dated_costs/edit.js.erb
231
+ - app/views/e9_crm/dated_costs/index.html.haml
232
+ - app/views/e9_crm/dated_costs/new.html.haml
233
+ - app/views/e9_crm/dated_costs/show.html.haml
234
+ - app/views/e9_crm/dated_costs/update.js.erb
216
235
  - app/views/e9_crm/deals/_form_inner.html.haml
217
236
  - app/views/e9_crm/deals/_header.html.haml
218
237
  - app/views/e9_crm/deals/_reports_table.html.haml
@@ -220,7 +239,9 @@ files:
220
239
  - app/views/e9_crm/deals/reports.html.haml
221
240
  - app/views/e9_crm/deals/reports.js.erb
222
241
  - app/views/e9_crm/email_campaigns/_form_inner.html.haml
242
+ - app/views/e9_crm/email_templates/_footer.html.haml
223
243
  - app/views/e9_crm/email_templates/_form_inner.html.haml
244
+ - app/views/e9_crm/email_templates/_header.html.haml
224
245
  - app/views/e9_crm/menu_options/_form_inner.html.haml
225
246
  - app/views/e9_crm/menu_options/_header.html.haml
226
247
  - app/views/e9_crm/offers/_form.html.haml
@@ -228,6 +249,7 @@ files:
228
249
  - app/views/e9_crm/offers/_form_inner.html.haml.bak
229
250
  - app/views/e9_crm/page_views/_table.html.haml
230
251
  - app/views/e9_crm/record_attributes/_address_attribute.html.haml
252
+ - app/views/e9_crm/record_attributes/_form_partial.html.haml
231
253
  - app/views/e9_crm/record_attributes/_instant_messaging_handle_attribute.html.haml
232
254
  - app/views/e9_crm/record_attributes/_phone_number_attribute.html.haml
233
255
  - app/views/e9_crm/record_attributes/_record_attribute.html.haml