e9_crm 0.1.1

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 (120) hide show
  1. data/.gitignore +3 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +105 -0
  4. data/README.md +31 -0
  5. data/Rakefile +2 -0
  6. data/app/controllers/e9_crm/advertising_campaigns_controller.rb +3 -0
  7. data/app/controllers/e9_crm/affiliate_campaigns_controller.rb +3 -0
  8. data/app/controllers/e9_crm/base_controller.rb +5 -0
  9. data/app/controllers/e9_crm/campaign_groups_controller.rb +3 -0
  10. data/app/controllers/e9_crm/campaigns_controller.rb +4 -0
  11. data/app/controllers/e9_crm/companies_controller.rb +3 -0
  12. data/app/controllers/e9_crm/contact_emails_controller.rb +38 -0
  13. data/app/controllers/e9_crm/contact_merges_controller.rb +26 -0
  14. data/app/controllers/e9_crm/contacts_controller.rb +46 -0
  15. data/app/controllers/e9_crm/dated_costs_controller.rb +4 -0
  16. data/app/controllers/e9_crm/deals_controller.rb +19 -0
  17. data/app/controllers/e9_crm/email_campaigns_controller.rb +3 -0
  18. data/app/controllers/e9_crm/email_templates.controller.rb +3 -0
  19. data/app/controllers/e9_crm/menu_options_controller.rb +26 -0
  20. data/app/controllers/e9_crm/offers_controller.rb +3 -0
  21. data/app/controllers/e9_crm/page_views_controller.rb +20 -0
  22. data/app/controllers/e9_crm/record_attributes_controller.rb +3 -0
  23. data/app/controllers/e9_crm/reports_controller.rb +2 -0
  24. data/app/controllers/e9_crm/resources_controller.rb +43 -0
  25. data/app/controllers/e9_crm/sales_campaigns_controller.rb +3 -0
  26. data/app/helpers/e9_crm/base_helper.rb +77 -0
  27. data/app/helpers/e9_crm/campaigns_helper.rb +14 -0
  28. data/app/helpers/e9_crm/contact_merges_helper.rb +17 -0
  29. data/app/helpers/e9_crm/contacts_helper.rb +27 -0
  30. data/app/helpers/e9_crm/deals_helper.rb +15 -0
  31. data/app/helpers/e9_crm/menu_options_helper.rb +11 -0
  32. data/app/helpers/e9_crm/page_views_helper.rb +2 -0
  33. data/app/models/address_attribute.rb +4 -0
  34. data/app/models/advertising_campaign.rb +15 -0
  35. data/app/models/affiliate.rb +4 -0
  36. data/app/models/affiliate_campaign.rb +15 -0
  37. data/app/models/campaign.rb +34 -0
  38. data/app/models/campaign_group.rb +5 -0
  39. data/app/models/company.rb +4 -0
  40. data/app/models/contact.rb +258 -0
  41. data/app/models/contact_email.rb +49 -0
  42. data/app/models/dated_cost.rb +9 -0
  43. data/app/models/deal.rb +83 -0
  44. data/app/models/email_campaign.rb +13 -0
  45. data/app/models/email_template.rb +7 -0
  46. data/app/models/instant_messaging_handle_attribute.rb +4 -0
  47. data/app/models/menu_option.rb +33 -0
  48. data/app/models/offer.rb +50 -0
  49. data/app/models/page_view.rb +80 -0
  50. data/app/models/phone_number_attribute.rb +4 -0
  51. data/app/models/record_attribute.rb +41 -0
  52. data/app/models/sales_campaign.rb +15 -0
  53. data/app/models/sales_person.rb +4 -0
  54. data/app/models/tracking_cookie.rb +61 -0
  55. data/app/models/website_attribute.rb +4 -0
  56. data/app/observers/deal_observer.rb +11 -0
  57. data/app/uploaders/file_uploader.rb +34 -0
  58. data/app/views/e9_crm/campaigns/_form_inner.html.haml +5 -0
  59. data/app/views/e9_crm/contact_emails/_form.html.haml +7 -0
  60. data/app/views/e9_crm/contact_emails/_form_inner.html.haml +11 -0
  61. data/app/views/e9_crm/contact_emails/destroy.js.erb +3 -0
  62. data/app/views/e9_crm/contact_emails/send_email.js.erb +1 -0
  63. data/app/views/e9_crm/contact_merges/_field.html.haml +10 -0
  64. data/app/views/e9_crm/contact_merges/_form.html.haml +10 -0
  65. data/app/views/e9_crm/contact_merges/new.html.haml +2 -0
  66. data/app/views/e9_crm/contacts/_details.html.haml +22 -0
  67. data/app/views/e9_crm/contacts/_form_inner.html.haml +51 -0
  68. data/app/views/e9_crm/contacts/_header.html.haml +19 -0
  69. data/app/views/e9_crm/contacts/_tag_table.html.haml +15 -0
  70. data/app/views/e9_crm/contacts/index.html.haml +13 -0
  71. data/app/views/e9_crm/contacts/index.js.erb +5 -0
  72. data/app/views/e9_crm/contacts/merge.html.haml +1 -0
  73. data/app/views/e9_crm/contacts/templates.js.erb +1 -0
  74. data/app/views/e9_crm/deals/_form_inner.html.haml +5 -0
  75. data/app/views/e9_crm/deals/_header.html.haml +0 -0
  76. data/app/views/e9_crm/deals/leads.html.haml +13 -0
  77. data/app/views/e9_crm/email_templates/_form_inner.html.haml +9 -0
  78. data/app/views/e9_crm/menu_options/_form_inner.html.haml +6 -0
  79. data/app/views/e9_crm/menu_options/_header.html.haml +8 -0
  80. data/app/views/e9_crm/offers/_form.html.haml +7 -0
  81. data/app/views/e9_crm/offers/_form_inner.html.haml +42 -0
  82. data/app/views/e9_crm/offers/_form_inner.html.haml.bak +43 -0
  83. data/app/views/e9_crm/page_views/_table.html.haml +25 -0
  84. data/app/views/e9_crm/record_attributes/_address_attribute.html.haml +5 -0
  85. data/app/views/e9_crm/record_attributes/_instant_messaging_handle_attribute.html.haml +5 -0
  86. data/app/views/e9_crm/record_attributes/_phone_number_attribute.html.haml +5 -0
  87. data/app/views/e9_crm/record_attributes/_record_attribute.html.haml +10 -0
  88. data/app/views/e9_crm/record_attributes/_templates.js.erb +12 -0
  89. data/app/views/e9_crm/record_attributes/_user.html.haml +23 -0
  90. data/app/views/e9_crm/record_attributes/_website_attribute.html.haml +5 -0
  91. data/app/views/e9_crm/resources/_footer.html.haml +1 -0
  92. data/app/views/e9_crm/resources/_form.html.haml +7 -0
  93. data/app/views/e9_crm/resources/_form_inner.html.haml +5 -0
  94. data/app/views/e9_crm/resources/_header.html.haml +0 -0
  95. data/app/views/e9_crm/resources/_table.html.haml +21 -0
  96. data/app/views/e9_crm/resources/create.js.erb +6 -0
  97. data/app/views/e9_crm/resources/destroy.js.erb +3 -0
  98. data/app/views/e9_crm/resources/edit.html.haml +2 -0
  99. data/app/views/e9_crm/resources/index.html.haml +13 -0
  100. data/app/views/e9_crm/resources/index.js.erb +1 -0
  101. data/app/views/e9_crm/resources/new.html.haml +2 -0
  102. data/app/views/e9_crm/resources/show.html.haml +2 -0
  103. data/app/views/e9_crm/resources/update.js.erb +5 -0
  104. data/config/initializers/inflections.rb +3 -0
  105. data/config/locales/e9.en.yml +28 -0
  106. data/config/locales/en.yml +63 -0
  107. data/config/routes.rb +61 -0
  108. data/e9_crm.gemspec +29 -0
  109. data/lib/e9_crm/model.rb +63 -0
  110. data/lib/e9_crm/rails_extensions.rb +98 -0
  111. data/lib/e9_crm/tracking_controller.rb +78 -0
  112. data/lib/e9_crm/version.rb +3 -0
  113. data/lib/e9_crm.rb +59 -0
  114. data/lib/generators/e9_crm/install_generator.rb +32 -0
  115. data/lib/generators/e9_crm/templates/create_e9_crm_tables.rb +107 -0
  116. data/lib/generators/e9_crm/templates/initializer.rb +4 -0
  117. data/lib/generators/e9_crm/templates/javascript.js +187 -0
  118. data/test/functional/e9_crm/campaign_types_controller_test.rb +49 -0
  119. data/test/functional/home_controller_test.rb +8 -0
  120. metadata +283 -0
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .bundle
2
+ *.swp
3
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,105 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ e9_crm (0.1.0)
5
+ e9_rails (~> 0.0.4)
6
+ e9_tags (~> 0.0.2)
7
+ has_scope
8
+ inherited_resources (~> 1.1.2)
9
+ money
10
+ rails (~> 3.0.0)
11
+ will_paginate
12
+
13
+ GEM
14
+ remote: http://rubygems.org/
15
+ specs:
16
+ abstract (1.0.0)
17
+ actionmailer (3.0.5)
18
+ actionpack (= 3.0.5)
19
+ mail (~> 2.2.15)
20
+ actionpack (3.0.5)
21
+ activemodel (= 3.0.5)
22
+ activesupport (= 3.0.5)
23
+ builder (~> 2.1.2)
24
+ erubis (~> 2.6.6)
25
+ i18n (~> 0.4)
26
+ rack (~> 1.2.1)
27
+ rack-mount (~> 0.6.13)
28
+ rack-test (~> 0.5.7)
29
+ tzinfo (~> 0.3.23)
30
+ activemodel (3.0.5)
31
+ activesupport (= 3.0.5)
32
+ builder (~> 2.1.2)
33
+ i18n (~> 0.4)
34
+ activerecord (3.0.5)
35
+ activemodel (= 3.0.5)
36
+ activesupport (= 3.0.5)
37
+ arel (~> 2.0.2)
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)
43
+ acts-as-taggable-on (2.0.6)
44
+ arel (2.0.9)
45
+ builder (2.1.2)
46
+ e9_rails (0.0.4)
47
+ inherited_resources
48
+ rails (~> 3.0.0)
49
+ e9_tags (0.0.2)
50
+ acts-as-taggable-on (~> 2.0.6)
51
+ rails (~> 3.0.0)
52
+ erubis (2.6.6)
53
+ abstract (>= 1.0.0)
54
+ has_scope (0.5.0)
55
+ i18n (0.5.0)
56
+ inherited_resources (1.1.2)
57
+ has_scope (~> 0.5.0)
58
+ responders (~> 0.6.0)
59
+ mail (2.2.15)
60
+ activesupport (>= 2.3.6)
61
+ i18n (>= 0.4.0)
62
+ mime-types (~> 1.16)
63
+ treetop (~> 1.4.8)
64
+ mime-types (1.16)
65
+ money (3.6.1)
66
+ i18n (~> 0.4)
67
+ polyglot (0.3.1)
68
+ rack (1.2.1)
69
+ rack-mount (0.6.13)
70
+ rack (>= 1.0.0)
71
+ rack-test (0.5.7)
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)
79
+ bundler (~> 1.0)
80
+ railties (= 3.0.5)
81
+ railties (3.0.5)
82
+ actionpack (= 3.0.5)
83
+ activesupport (= 3.0.5)
84
+ rake (>= 0.8.7)
85
+ thor (~> 0.14.4)
86
+ rake (0.8.7)
87
+ responders (0.6.2)
88
+ thor (0.14.6)
89
+ treetop (1.4.9)
90
+ polyglot (>= 0.3.1)
91
+ tzinfo (0.3.24)
92
+ will_paginate (2.3.15)
93
+
94
+ PLATFORMS
95
+ ruby
96
+
97
+ DEPENDENCIES
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
data/README.md ADDED
@@ -0,0 +1,31 @@
1
+ CRM Plugin for the e9 CMS
2
+ =========================
3
+
4
+ It should be noted that while this plugin is intended for use in the
5
+ e9 CMS, it does neither includes nor requires it.
6
+
7
+ To use, add as a gem and install by running:
8
+
9
+ rails g e9_crm:install
10
+
11
+ Then modify the installed initializer as per your app, including
12
+ the controller module in your desired controllers, with the final
13
+ result looking something like this:
14
+
15
+ require 'e9_crm'
16
+
17
+ User.send :include, E9Crm::Backend::ActiveRecord
18
+
19
+ Rails.configuration.after_initialize do
20
+ [
21
+ MyFirstTrackedController,
22
+ MySecondTrackedController
23
+ ].each {|c| c.send(:include, E9Crm::TrackingController) }
24
+ end
25
+
26
+ NOTE: A few assumptions are made:
27
+ ---------------------------------
28
+
29
+ 1. Your app has a "User" model
30
+ 2. Your app has a controller method #current_user to return the
31
+ currently logged in user.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler"
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,3 @@
1
+ class E9Crm::AdvertisingCampaignsController < E9Crm::ResourcesController
2
+ defaults :resource_class => AdvertisingCampaign
3
+ end
@@ -0,0 +1,3 @@
1
+ class E9Crm::AffiliateCampaignsController < E9Crm::ResourcesController
2
+ defaults :resource_class => AffiliateCampaign
3
+ end
@@ -0,0 +1,5 @@
1
+ class E9Crm::BaseController < AdminController
2
+ include E9Rails::Helpers::ResourceLinks
3
+ include E9Rails::Helpers::Title
4
+ include E9Rails::Helpers::Translation
5
+ end
@@ -0,0 +1,3 @@
1
+ class E9Crm::CampaignGroupsController < E9Crm::ResourcesController
2
+ defaults :resource_class => CampaignGroup
3
+ end
@@ -0,0 +1,4 @@
1
+ class E9Crm::CampaignsController < E9Crm::ResourcesController
2
+ defaults :resource_class => Campaign
3
+ has_scope :of_type, :as => :t, :only => :index
4
+ end
@@ -0,0 +1,3 @@
1
+ class E9Crm::CompaniesController < E9Crm::ResourcesController
2
+ defaults :resource_class => Company
3
+ end
@@ -0,0 +1,38 @@
1
+ class E9Crm::ContactEmailsController < E9Crm::ResourcesController
2
+ defaults
3
+
4
+ respond_to :js, :html
5
+
6
+ def create
7
+ create! do |success, failure|
8
+ success.html { redirect_to :admin_sent_email }
9
+ success.js { head :ok }
10
+ end
11
+ end
12
+
13
+ protected
14
+
15
+ def build_resource
16
+ get_resource_ivar || begin
17
+ object = if params[resource_instance_name]
18
+ ContactEmail.new(params[resource_instance_name] || {})
19
+ else
20
+ ContactEmail.new_from_template(template, :from_email => current_user.email, :user_ids => params[:uids])
21
+ end
22
+
23
+ # we set the user_ids.blank? error right away signifiying a problem,
24
+ # as the record won't be valid if the user_ids weren't passed in params
25
+ if object.user_ids.blank?
26
+ object.errors.add(:user_ids, :blank)
27
+ end
28
+
29
+ set_resource_ivar(object)
30
+ end
31
+ end
32
+
33
+ # throw record_not_found if there's no template. #new requires email_template_id
34
+ # be passed in params (and also user_ids)
35
+ def template
36
+ @_template ||= EmailTemplate.find(params[:etid])
37
+ end
38
+ end
@@ -0,0 +1,26 @@
1
+ class E9Crm::ContactMergesController < E9Crm::BaseController
2
+ before_filter :build_resources
3
+
4
+ def create
5
+ if @contact_a.update_attributes(params[:contact])
6
+ @contact_a.merge_and_destroy!(@contact_b)
7
+ redirect_to @contact_a
8
+ else
9
+ render :new
10
+ end
11
+ end
12
+
13
+ protected
14
+
15
+ def build_resources
16
+ @contact ||= Contact.new
17
+ @contact_a ||= Contact.find(params[:contact_a_id])
18
+
19
+ # NOTE lets see if this works
20
+ @contact_b ||= if params[:contact]
21
+ Contact.new(params[:contact])
22
+ else
23
+ Contact.find(params[:contact_b_id])
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,46 @@
1
+ class E9Crm::ContactsController < E9Crm::ResourcesController
2
+ defaults :resource_class => Contact
3
+
4
+ include E9Tags::Controller
5
+
6
+ respond_to :js, :html
7
+
8
+ before_filter :determine_title, :only => :index
9
+ before_filter :load_user_ids, :only => :index
10
+
11
+ has_scope :search, :by_title, :by_company, :only => :index
12
+ has_scope :tagged, :only => :index, :type => :array
13
+
14
+ # record attributes templates js
15
+ skip_before_filter :authenticate_user!, :filter_access_filter, :only => :templates
16
+ before_filter :build_resource, :only => :templates
17
+ caches_action :templates
18
+
19
+ protected
20
+
21
+ def load_user_ids
22
+ @user_ids ||= begin
23
+ (User.primary.joins(:contact) & end_of_association_chain.scoped).all.map(&:id)
24
+ end
25
+ end
26
+
27
+ def determine_title
28
+ params.delete(:search) if params[:search].blank?
29
+
30
+ @index_title ||= if params[:tagged] && params[:search]
31
+ e9_t(:index_title_with_search_and_tags, :tagged => params[:tagged].join(' or '), :search => params[:search])
32
+ elsif params[:tagged]
33
+ e9_t(:index_title_with_tags, :tagged => params[:tagged].join(' or '))
34
+ elsif params[:search]
35
+ e9_t(:index_title_with_search, :search => params[:search])
36
+ end
37
+ end
38
+
39
+ def default_ordered_on
40
+ 'first_name'
41
+ end
42
+
43
+ def default_ordered_at
44
+ 'ASC'
45
+ end
46
+ end
@@ -0,0 +1,4 @@
1
+ class E9Crm::DatedCostsController < E9Crm::ResourcesController
2
+ belongs_to :advertising_campaign
3
+ defaults :resource_class => DatedCost
4
+ end
@@ -0,0 +1,19 @@
1
+ class E9Crm::DealsController < E9Crm::ResourcesController
2
+ defaults :resource_class => Deal
3
+
4
+ filter_access_to :leads, :require => :read, :context => :admin
5
+ prepend_before_filter :set_leads_index_title, :only => :leads
6
+
7
+ has_scope :leads, :only => :leads, :default => true
8
+ has_scope :leads, :except => :leads, :default => false
9
+
10
+ def leads
11
+ index!
12
+ end
13
+
14
+ protected
15
+
16
+ def set_leads_index_title
17
+ @index_title = I18n.t(:index_title, :scope => 'e9.e9_crm.leads')
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ class E9Crm::EmailCampaignsController < E9Crm::ResourcesController
2
+ defaults :resource_class => EmailCampaign
3
+ end
@@ -0,0 +1,3 @@
1
+ class E9Crm::EmailTemplatesController < E9Crm::ResourcesController
2
+ defaults
3
+ end
@@ -0,0 +1,26 @@
1
+ class E9Crm::MenuOptionsController < E9Crm::ResourcesController
2
+ defaults :resource_class => MenuOption
3
+ include E9Rails::Controllers::Sortable
4
+
5
+ has_scope :options_for, :as => :key, :only => :index
6
+
7
+ # NOTE The reason this is set in a filter instead of just a default scope value
8
+ # is that it is used in the index view to add the key param to the new
9
+ # resource link
10
+ #
11
+ before_filter :ensure_default_fetch_key, :only => :index
12
+
13
+ def create
14
+ create! { collection_path(:key => resource.key) }
15
+ end
16
+
17
+ def update
18
+ update! { collection_path(:key => resource.key) }
19
+ end
20
+
21
+ protected
22
+
23
+ def ensure_default_fetch_key
24
+ params[:key] ||= MenuOption::KEYS.sort.first
25
+ end
26
+ end
@@ -0,0 +1,3 @@
1
+ class E9Crm::OffersController < E9Crm::ResourcesController
2
+ defaults :resource_class => Offer
3
+ end
@@ -0,0 +1,20 @@
1
+ class E9Crm::PageViewsController < E9Crm::ResourcesController
2
+ defaults :resource_class => PageView
3
+ belongs_to :campaign, :contact, :polymorphic => true
4
+
5
+ # NOTE association chain is prepended to ensure parent is loaded so other
6
+ # before filters can use collection_path, etc. Is there a better solution
7
+ # for this?
8
+ #
9
+ prepend_before_filter :association_chain
10
+
11
+ has_scope :until_time, :as => :until, :unless => 'params[:from].present?'
12
+
13
+ has_scope :from_time, :as => :from do |controller, scope, value|
14
+ if controller.params[:until]
15
+ scope.for_time_range(value, controller.params[:until])
16
+ else
17
+ scope.from_time(value)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ class E9Crm::RecordAttributesController < ApplicationController
2
+ helper 'e9_crm/base'
3
+ end
@@ -0,0 +1,2 @@
1
+ class E9Crm::ReportsController < E9Crm::BaseController
2
+ end
@@ -0,0 +1,43 @@
1
+ class E9Crm::ResourcesController < E9Crm::BaseController
2
+ include E9Rails::Controllers::Orderable
3
+ include E9Rails::Helpers::ResourceErrorMessages
4
+ include E9Rails::Helpers::Pagination
5
+
6
+ inherit_resources
7
+
8
+ add_resource_breadcrumbs
9
+
10
+ def self.defaults(hash = {})
11
+ super(hash.reverse_merge(:route_prefix => nil))
12
+ end
13
+
14
+ def create
15
+ create! { collection_path }
16
+ end
17
+
18
+ def update
19
+ update! { collection_path }
20
+ end
21
+
22
+ protected
23
+
24
+ # NOTE parent is defined so it's always available, it will be overridden on controllers which have belongs_to routes
25
+ def parent; end
26
+ helper_method :parent
27
+
28
+ def add_index_breadcrumb
29
+ add_breadcrumb! @index_title || e9_t(:index_title), collection_path
30
+ end
31
+
32
+ def collection
33
+ get_collection_ivar || set_collection_ivar(end_of_association_chain.paginate(pagination_parameters))
34
+ end
35
+
36
+ def default_ordered_on
37
+ 'created_at'
38
+ end
39
+
40
+ def default_ordered_dir
41
+ 'DESC'
42
+ end
43
+ end
@@ -0,0 +1,3 @@
1
+ class E9Crm::SalesCampaignsController < E9Crm::ResourcesController
2
+ defaults :resource_class => SalesCampaign
3
+ end
@@ -0,0 +1,77 @@
1
+ module E9Crm::BaseHelper
2
+
3
+ ##
4
+ # Field maps
5
+ #
6
+
7
+ def records_table_field_map(options = {})
8
+ options.symbolize_keys!
9
+ options.reverse_merge!(:class_name => resource_class.base_class.name.underscore)
10
+
11
+ base_map = {
12
+ :fields => { :id => nil },
13
+ :links => lambda {|r| [link_to_edit_resource(r), link_to_destroy_resource(r)] }
14
+ }
15
+
16
+ method_name = "records_table_field_map_for_#{options[:class_name]}"
17
+
18
+ if respond_to?(method_name)
19
+ base_map.merge! send(method_name)
20
+ end
21
+
22
+ base_map
23
+ end
24
+
25
+
26
+ ##
27
+ # Misc
28
+ #
29
+
30
+ def link_to_add_record_attribute(association_name)
31
+ link_to(
32
+ t(:add_record_attribute, :scope => :e9_crm),
33
+ 'javascript:;',
34
+ :class => 'add-nested-association',
35
+ 'data-association' => association_name
36
+ )
37
+ end
38
+
39
+ def link_to_destroy_record_attribute
40
+ link_to(
41
+ t(:destroy_record_attribute, :scope => :e9_crm),
42
+ 'javascript:;',
43
+ :class => 'destroy-nested-association'
44
+ )
45
+ end
46
+
47
+ def render_record_attribute_association(association_name, form, options = {})
48
+ options.symbolize_keys!
49
+
50
+ association = resource.send(association_name)
51
+
52
+ unless association.empty?
53
+ form.fields_for(association_name) do |f|
54
+ concat record_attribute_template(association_name, f, options)
55
+ end
56
+ end
57
+ end
58
+
59
+ def record_attribute_template(association_name, builder, options = {})
60
+ options.symbolize_keys!
61
+
62
+ render({
63
+ :partial => options[:partial] || "e9_crm/record_attributes/#{association_name.to_s.singularize}",
64
+ :locals => { :f => builder }
65
+ })
66
+ end
67
+
68
+ def build_associated_resource(association_name)
69
+ params_method = "#{association_name}_build_parameters"
70
+ build_params = resource_class.send(params_method) if resource_class.respond_to?(params_method)
71
+ resource.send(association_name).build(build_params || {})
72
+ end
73
+
74
+ def sortable_controller?
75
+ @_sortable_controller ||= controller.class.ancestors.member?(E9Rails::Controllers::Sortable)
76
+ end
77
+ end
@@ -0,0 +1,14 @@
1
+ module E9Crm::CampaignsHelper
2
+ def records_table_map_for_campaign
3
+ {
4
+ :fields => {
5
+ :type => nil,
6
+ :name => nil,
7
+ :code => nil,
8
+ :affiliate_fee => proc {|r| v = r.affiliate_fee; Money === v ? v : 'n/a' },
9
+ :sales_fee => nil,
10
+ :status => proc {|r| resource_class.human_attribute_name(Campaign::Status::VALUES[r.status]) }
11
+ }
12
+ }
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ module E9Crm::ContactMergesHelper
2
+ def contact_a(field_name)
3
+ @_contact_a_vals ||= {}
4
+ @_contact_a_vals[field_name] ||= merge_contact_val(@contact_a, field_name)
5
+ end
6
+
7
+ def contact_b(field_name)
8
+ @_contact_b_vals ||= {}
9
+ @_contact_b_vals[field_name] ||= merge_contact_val(@contact_b, field_name)
10
+ end
11
+
12
+ def merge_contact_val(obj, field_name)
13
+ # return '' here rather than nil so inputs will have a value, otherwise checked
14
+ # with no value ends up being interpreted as "on"
15
+ obj.send(field_name) || ''
16
+ end
17
+ end
@@ -0,0 +1,27 @@
1
+ module E9Crm::ContactsHelper
2
+
3
+ def link_to_contact_search(attribute, query, text = nil)
4
+ link_to(text || query, contacts_path(attribute => query), :class => "contact-search contact-#{attribute.to_s.dasherize}-search")
5
+ end
6
+
7
+ def contact_email_template_select_options
8
+ options_for_select( EmailTemplate.order('name').map {|e| [e.name, e.id] })
9
+ end
10
+
11
+ def contact_newsletter_select_options
12
+ options_for_select( UserEmail.pending.order('name').map {|e| [e.name, e.id] })
13
+ end
14
+
15
+ def records_table_field_map_for_contact
16
+ {
17
+ :fields => {
18
+ :avatar => proc {|r| },
19
+ :details => proc {|r| render('details', :record => r) }
20
+ },
21
+
22
+ :links => proc {|r|
23
+ [link_to_show_resource(r), link_to_edit_resource(r), link_to_destroy_resource(r)]
24
+ }
25
+ }
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ module E9Crm::DealsHelper
2
+ def records_table_field_map_for_deal
3
+ {
4
+ :fields => {
5
+ :created_at => nil,
6
+ :offer => nil,
7
+ :campaign => nil
8
+ },
9
+
10
+ :links => proc {|r|
11
+ []
12
+ }
13
+ }
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module E9Crm::MenuOptionsHelper
2
+ def records_table_field_map_for_menu_option
3
+ {
4
+ :fields => {
5
+ :position => proc { '<div class="handle">+++</div>'.html_safe },
6
+ :value => nil,
7
+ :key => nil
8
+ }
9
+ }
10
+ end
11
+ end
@@ -0,0 +1,2 @@
1
+ module E9Crm::PageViewsHelper
2
+ end
@@ -0,0 +1,4 @@
1
+ # Attribute for address info
2
+ #
3
+ class AddressAttribute < RecordAttribute
4
+ end
@@ -0,0 +1,15 @@
1
+ # An ad driven campaign.
2
+ #
3
+ # Unique from other campaigns in that their cost is derived from associated
4
+ # DatedCost records.
5
+ #
6
+ class AdvertisingCampaign < Campaign
7
+ has_many :dated_costs, :as => :costable
8
+
9
+ ##
10
+ # The sum cost of this campaign
11
+ #
12
+ def cost
13
+ Money.new(dated_costs.sum(:cost))
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ # A contact subtype for affiliates, who drive affiliate campaigns
2
+ #
3
+ class Affiliate < Contact
4
+ end
@@ -0,0 +1,15 @@
1
+ # An affiliate campaign
2
+ #
3
+ # Carries an affiliate fee (and sales fee)
4
+ #
5
+ class AffiliateCampaign < SalesCampaign
6
+ money_columns :affiliate_fee
7
+ belongs_to :affiliate
8
+
9
+ ##
10
+ # The sum cost of this campaign
11
+ #
12
+ def cost
13
+ super + affiliate_fee
14
+ end
15
+ end