e9_crm 0.1.6 → 0.1.7

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.
@@ -14,9 +14,15 @@ class E9Crm::DealsController < E9Crm::ResourcesController
14
14
  # Index/Reports Scopes
15
15
  #
16
16
 
17
- has_scope :leads, :only => :leads, :default => true
18
- has_scope :leads, :except => [:leads, :reports], :default => false
17
+ # NOTE default => 'true' only exists to ensure this scope is called
18
+ has_scope :only_leads, :only => :leads, :default => 'true' do |controller, scope|
19
+ scope.leads(true)
20
+ end
19
21
 
22
+ # NOTE default => 'false' only exists to ensure this scope is called
23
+ has_scope :no_leads, :except => [:leads, :reports], :default => 'false' do |controller, scope|
24
+ scope.leads(false)
25
+ end
20
26
 
21
27
  ##
22
28
  # Reports scopes
@@ -42,7 +48,6 @@ class E9Crm::DealsController < E9Crm::ResourcesController
42
48
  end
43
49
  end
44
50
 
45
-
46
51
  ##
47
52
  # Actions
48
53
  #
@@ -63,7 +68,9 @@ class E9Crm::DealsController < E9Crm::ResourcesController
63
68
  if params[:action] == 'reports'
64
69
  end_of_association_chain.all
65
70
  else
66
- end_of_association_chain.paginate(pagination_parameters)
71
+ end_of_association_chain
72
+ .joins("left outer join contacts on contacts.id = deals.contact_id")
73
+ .select("deals.*, contacts.first_name owner_name")
67
74
  end
68
75
  )
69
76
  end
@@ -1,16 +1,16 @@
1
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
- }
2
+ def deal_contact_select_options
3
+ @_deal_contact_select_options ||= begin
4
+ contacts = Contact.available_to_deal(resource)
5
+
6
+ options = contacts.map {|contact| [contact.name, contact.id] }
7
+ options.unshift ['Add Contact', nil]
8
+ options_for_select options
9
+ end
10
+ end
11
+
12
+ def deal_contact_select
13
+ select_tag 'contacts_ids', deal_contact_select_options
14
14
  end
15
15
 
16
16
  def deal_date_select_options(ending_month = false)
@@ -13,6 +13,8 @@ class Contact < ActiveRecord::Base
13
13
  # Associations
14
14
  #
15
15
  belongs_to :company
16
+ has_many :owned_deals, :class_name => 'Deal'
17
+ has_and_belongs_to_many :associated_deals, :class_name => 'Deal'
16
18
 
17
19
  has_many :users, :inverse_of => :contact, :dependent => :nullify do
18
20
 
@@ -158,6 +160,20 @@ class Contact < ActiveRecord::Base
158
160
  end
159
161
  }
160
162
 
163
+ def self.available_to_deal(deal)
164
+ return all unless deal.persisted?
165
+
166
+ sql = <<-SQL
167
+ SELECT distinct contacts.* FROM `contacts`
168
+ LEFT OUTER JOIN `contacts_deals`
169
+ ON `contacts_deals`.`contact_id` = `contacts`.`id`
170
+ WHERE (`contacts_deals`.`deal_id` IS NULL
171
+ OR `contacts_deals`.`deal_id` != #{deal.id})
172
+ SQL
173
+
174
+ find_by_sql(sql)
175
+ end
176
+
161
177
  #
162
178
  # Carrierwave
163
179
  #
data/app/models/deal.rb CHANGED
@@ -9,13 +9,20 @@ class Deal < ActiveRecord::Base
9
9
  belongs_to :tracking_cookie, :inverse_of => :deals
10
10
  belongs_to :offer, :inverse_of => :deals
11
11
 
12
+ belongs_to :owner, :class_name => 'Contact', :foreign_key => :contact_id
13
+ has_and_belongs_to_many :contacts
14
+
12
15
  money_columns :value
16
+
17
+ validates :name, :presence => true
13
18
  validates :value, :numericality => true
14
19
 
15
20
  %w(total_value average_value total_cost average_cost).each do |money_column|
16
21
  class_eval("def #{money_column}; (r = read_attribute(:#{money_column})) && Money.new(r) end")
17
22
  end
18
23
 
24
+ delegate :name, :to => :owner, :prefix => true, :allow_nil => true
25
+
19
26
  scope :reports, lambda {
20
27
  select_sql = <<-SELECT.gsub(/\s+/, ' ')
21
28
  campaigns.id campaign_id,
@@ -120,7 +127,6 @@ class Deal < ActiveRecord::Base
120
127
  scope :won, lambda {|reverse=true| column_eq(:status, Status::Won, !reverse) }
121
128
  scope :lost, lambda {|reverse=true| column_eq(:status, Status::Lost, !reverse) }
122
129
 
123
-
124
130
  protected
125
131
 
126
132
  def method_missing(method_name, *args)
@@ -30,4 +30,8 @@ class MenuOption < ActiveRecord::Base
30
30
  def self.fetch_values(key)
31
31
  connection.send(:select_values, options_for(key).order(:position).project('value').to_sql, 'Menu Option Select')
32
32
  end
33
+
34
+ def to_s
35
+ value
36
+ end
33
37
  end
@@ -1,4 +1,3 @@
1
- - contact_ids = collection.map(&:id)
2
1
  .toolbar
3
2
  .toolbar-left
4
3
  = form_tag(resource_class, :method => :get, :id => 'contact_search_form') do
@@ -12,7 +11,7 @@
12
11
  = tag
13
12
  = hidden_field_tag 'uids', @contact_ids.join(','), :id => 'contact_email_uids'
14
13
  = submit_tag e9_t(:send_email_template), :name => nil
15
- - if (tag = contact_email_template_select_tag).present?
14
+ - if (tag = contact_newsletter_select_tag).present?
16
15
  = 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
16
  = tag
18
17
  = hidden_field_tag 'uids', @contact_ids.join(','), :id => 'contact_newsletter_uids'
@@ -0,0 +1,16 @@
1
+ - field_map = local_assigns[:field_map] || records_table_field_map
2
+
3
+ %table.records
4
+ %tbody
5
+ - if collection.empty?
6
+ %tr
7
+ %td{:colspan => field_map[:fields].length + 1}= e9_t(:no_records_text)
8
+ - else
9
+ - collection.each do |record|
10
+ %tr{:id => "ids_#{record.id}", :class => cycle('odd', 'even')}
11
+ - field_map[:fields].each do |key, value|
12
+ %td{:class => "record-#{key.to_s.dasherize}"}
13
+ = value.respond_to?(:call) ? value.call(record) : record.send(key)
14
+ %td.links
15
+ - field_map[:links][record].each do |link|
16
+ = link
@@ -1,12 +1,38 @@
1
1
  = title (@index_title || e9_t(:index_title))
2
2
 
3
- #index-header
4
- = render 'header'
3
+ #index-body
4
+ #records_table
5
+ = render 'table', :resources => collection
6
+ = render 'footer'
5
7
 
6
- #contact-tag-list
7
- = render 'tag_table'
8
+ #index-sidebar
9
+ .actions
10
+ = link_to_new_resource(Contact)
11
+ = link_to_new_resource(Company)
8
12
 
9
- #records_table
10
- = render 'table', :resources => collection
13
+ -# Email actions (template, newsletter)
14
+ - etag, ntag = contact_email_template_select_tag, contact_newsletter_select_tag
15
+ - if [etag, ntag].any?(&:present?)
16
+ %fieldset
17
+ %legend= e9_t(:email_actions_legend)
18
+ - if etag
19
+ = form_tag new_contact_email_path, :method => :get, :id => 'contact_email_form', 'data-empty' => e9_t(:no_contacts_notification), 'data-count' => @contact_ids.length do
20
+ = etag
21
+ = hidden_field_tag 'uids', @contact_ids.join(','), :id => 'contact_email_uids'
22
+ = submit_tag e9_t(:send_email_template), :name => nil
23
+ - if ntag
24
+ = 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
25
+ = ntag
26
+ = hidden_field_tag 'uids', @contact_ids.join(','), :id => 'contact_newsletter_uids'
27
+ = submit_tag e9_t(:send_email_newsletter), :name => nil
11
28
 
12
- = render 'footer'
29
+ -# Search filter options
30
+ %fieldset
31
+ %legend= e9_t(:search_options_legend)
32
+ = form_tag(resource_class, :method => :get, :id => 'contact_search_form') do
33
+ = label_tag 'contact_search_field', t(:search)
34
+ = text_field_tag 'search', params[:search], :id => 'contact_search_field'
35
+ = submit_tag t(:go), :name => nil
36
+ = render 'tag_table'
37
+ .actions
38
+ = submit_tag t(:clear), :name => nil, :id => 'contact_search_clear'
@@ -19,6 +19,6 @@
19
19
  = google_search_link(company.name)
20
20
  = google_news_link(company.name)
21
21
  - if company.info.present?
22
- = contact_simple_format(text)
22
+ = contact_simple_format(company.info)
23
23
  .contact-sidebar
24
24
  = render 'sidebar'
File without changes
@@ -1,5 +1,27 @@
1
- - resource.attributes.each_pair do |field, value|
2
- - next if ['id', 'created_at', 'updated_at'].include?(field)
3
- .field
4
- = f.label field
5
- = f.text_field field
1
+ .actions
2
+ = link_to_destroy_resource(resource, :remote => false) if resource.persisted?
3
+ .field
4
+ = f.label :name, nil, :class => :req
5
+ = f.text_field :name
6
+ .field
7
+ = f.label :info
8
+ = f.text_area :info
9
+ .field
10
+ = f.label :value, nil, :class => :req
11
+ = f.text_field :value
12
+ .field.select
13
+ = f.label :contacts
14
+ %select.list{'data-iname' => resource_instance_name, 'data-field' => '[contact_ids]'}
15
+ = deal_contact_select_options
16
+ %ul.select
17
+ - f.object.contacts.each do |contact|
18
+ %li
19
+ %span= contact.name
20
+ %input{:type => :hidden, :name => "contact[contact_ids][]", :value => contact.id}
21
+ %a{:class => :remove, :title => "Remove", :alt => "Remove"} Remove
22
+ .field.select
23
+ = f.label :owner
24
+ = f.collection_select :contact_id, Contact.all, :id, :name
25
+ .field.select
26
+ = f.label :category
27
+ = f.select :category, MenuOption.options_for('Deal Category'), :include_blank => 'No Category'
@@ -0,0 +1,41 @@
1
+ %table.records
2
+ %thead
3
+ %tr
4
+ %th= orderable_column_link(:name)
5
+ %th= orderable_column_link(:status)
6
+ %th= orderable_column_link(:category)
7
+ %th= orderable_column_link('owner_name', :owner)
8
+ %th= orderable_column_link(:value)
9
+ %th= t(:actions)
10
+ %tbody
11
+ -# prepare a hash to store the accumulated row data for calculations
12
+ - dat = Hash.new {|k,v| k[v] = [] }
13
+
14
+ - if collection.empty?
15
+ %tr
16
+ %td{:colspan => 6}= e9_t(:no_records_text, :scope => 'e9_crm.deals')
17
+ - else
18
+ - collection.each do |record|
19
+ %tr{:id => "ids_#{record.id}", :class => cycle('odd', 'even')}
20
+ %td.record-name
21
+ = record.name
22
+ %td.record-status
23
+ = record.status
24
+ %td.record-category
25
+ = record.category
26
+ %td.record-owner
27
+ = record.owner_name
28
+ %td.record-value
29
+ - dat[:value] << record.value
30
+ = record.value
31
+ %td.actions
32
+ = link_to_edit_resource(record)
33
+ = link_to_destroy_resource(record)
34
+
35
+ %tfooter
36
+ %tr{:class => 'record-totals'}
37
+ %td.record-totals-label{:colspan => 4}
38
+ #{t(:total)}:
39
+ %td.record-totals
40
+ = dat[:value].sum
41
+ %td
@@ -18,6 +18,8 @@ en:
18
18
  send_email_newsletter: Send Newsletter
19
19
  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?"
20
20
  no_contacts_notification: "You cannot send an email with no recipients!"
21
+ email_actions_legend: Email Actions
22
+ search_options_legend: Search Filters
21
23
  contact_merges:
22
24
  new_title: Merge Contacts
23
25
  no_value: (No Value)
@@ -1,14 +1,16 @@
1
1
  en:
2
+ actions: Actions
2
3
  clear: Clear
4
+ edit_dated_costs: Edit Costs
3
5
  go: Go
4
- search: Search
5
- view: View
6
- none: None
7
- totals: Totals
8
6
  inline_help_link: '[?]'
9
- edit_dated_costs: Edit Costs
10
- news: News
11
7
  map: Map
8
+ news: News
9
+ none: None
10
+ search: Search
11
+ total: Total
12
+ totals: Totals
13
+ view: View
12
14
 
13
15
  e9_crm:
14
16
  add_record_attribute: Add
@@ -1,3 +1,3 @@
1
1
  module E9Crm
2
- VERSION = '0.1.6'
2
+ VERSION = '0.1.7'
3
3
  end
@@ -1,27 +1,15 @@
1
1
  jQuery(function($) {
2
- var selector_prefix = 'body.controller-e9-crm-contacts',
3
- $selector = $(selector_prefix);
4
2
 
5
- $.fn.exclusiveCheck = function() {
6
- var selector = $(this);
7
- return this.each(function(i) {
8
- $(this).click(function(e) {
9
- var clicked = this;
10
- if (this.checked) {
11
- selector.each(function() {
12
- if (this != clicked) this.checked = false;
13
- });
14
- }
15
- });
16
- });
17
- }
3
+ $('.dated-costs > .actions a').bind('ajax:success', function(e, data, status, xhr) {
4
+ $(data).insertBefore($(this).closest('.actions'));
5
+ });
18
6
 
19
7
  /*
20
8
  * A function might exist for this already, but basically this stores the query variables
21
9
  * in a hash when the page loads for later re-use/modification.
22
10
  */
23
- $.query = (function() {
24
- var qs = document.location.search;
11
+ function query_to_hash(qs) {
12
+ if (!qs) qs = document.location.search;
25
13
 
26
14
  if (!qs.length) return {};
27
15
 
@@ -44,7 +32,118 @@ jQuery(function($) {
44
32
  }
45
33
 
46
34
  return params;
47
- })();
35
+ }
36
+
37
+ $.query = query_to_hash();
38
+
39
+ $.fn.bindSelectChange = function(callback) {
40
+ this.bind($.browser.msie ? 'propertychange' : 'change', callback);
41
+ }
42
+
43
+ $("#campaign_code_field input").keyup(function() {
44
+ $.event.trigger('campaign_code_change', [$(this).val()]);
45
+ });
46
+
47
+ $("#campaign_code_hint").bind("campaign_code_change", function(e, code) {
48
+ $(this).html(function(i, v) {
49
+ return v.replace(/=(.*)$/, '='+code);
50
+ });
51
+ });
52
+
53
+ $('.ordered-column a').live('click', function(e) {
54
+ e.preventDefault();
55
+
56
+ var $this = $(this),
57
+ href = $this.attr('href'),
58
+ qs = href.match(/\?.*$/)[0];
59
+
60
+ var qh = qs && query_to_hash(qs) || {};
61
+
62
+ $.extend($.query, {
63
+ order : qh.order,
64
+ sort : qh.sort
65
+ });
66
+
67
+ submit_with_query();
68
+ });
69
+
70
+ $("#campaign_search_form").each(function(i, el) {
71
+ var
72
+ $form = $(el),
73
+ $st = $(el).find('select[name=type]'),
74
+ $sg = $(el).find('select[name=group]'),
75
+ $sa = $(el).find('select[name=active]'),
76
+ $sf = $(el).find('select[name=from]'),
77
+ $su = $(el).find('select[name=until]')
78
+ ;
79
+
80
+ $st.val($.query.type);
81
+ $sg.val($.query.group);
82
+ $sa.val($.query.active);
83
+ $sf.val($.query.from);
84
+ $su.val($.query.until);
85
+
86
+ $('select', $form).bindSelectChange(function() {
87
+ var opts = {}, v;
88
+ if (v = $st.val()) {
89
+ opts['type'] = v;
90
+ } else {
91
+ delete $.query['type'];
92
+ }
93
+ if (v = $sg.val()) {
94
+ opts['group'] = v;
95
+ } else {
96
+ delete $.query['group'];
97
+ }
98
+ if (v = $sa.val()) {
99
+ opts['active'] = v;
100
+ } else {
101
+ delete $.query['active'];
102
+ }
103
+ if (v = $sf.val()) {
104
+ opts['from'] = v;
105
+ } else {
106
+ delete $.query['from'];
107
+ }
108
+ if (v = $su.val()) {
109
+ opts['until'] = v;
110
+ } else {
111
+ delete $.query['until'];
112
+ }
113
+ $.extend($.query, opts);
114
+ submit_with_query();
115
+ });
116
+ });
117
+
118
+ $("#new_campaign_form").each(function(i, el) {
119
+ var $form = $(el);
120
+
121
+ $('select', $form).bindSelectChange(function() {
122
+ var $this = $(this);
123
+
124
+ $form.attr("action", function(i, val) {
125
+ return val.replace(/\/\w*\/new$/, '/'+$this.val()+'/new');
126
+ });
127
+ });
128
+ });
129
+
130
+ var selector_prefix = 'body.controller-e9-crm-contacts',
131
+ $selector = $(selector_prefix);
132
+
133
+ $.fn.exclusiveCheck = function() {
134
+ var selector = $(this);
135
+ return this.each(function(i) {
136
+ $(this).click(function(e) {
137
+ var clicked = this;
138
+ if (this.checked) {
139
+ selector.each(function() {
140
+ if (this != clicked) this.checked = false;
141
+ });
142
+ }
143
+ });
144
+ });
145
+ }
146
+
48
147
 
49
148
  /*
50
149
  * The status of "primary" for a User login is stored on the individual records, but must be exlcusive in
@@ -57,33 +156,33 @@ jQuery(function($) {
57
156
  $('.nested-association input[type=radio][name$="[primary]"]', $(selector_prefix)).exclusiveCheck();
58
157
  })();
59
158
 
60
- /**
159
+ /*
61
160
  * Adds a new nested assocation. Depends on the nested association
62
161
  * js templates being loaded.
63
162
  */
64
163
  $('a.add-nested-association').click(function(e) {
65
164
  e.preventDefault();
66
165
 
67
- var $this = $(this),
68
- $parent = $this.closest('.nested-associations'),
69
- template,
70
- index;
166
+ var $this = $(this), template;
71
167
 
168
+ // get the template for this attribute type
72
169
  try {
73
170
  template = E9CRM.js_templates[this.getAttribute('data-association')];
74
171
  } catch(e) { return }
75
172
 
173
+ // sub in the current index and increment it
76
174
  template = template.replace(
77
175
  new RegExp(E9CRM.js_templates.start_child_index, 'g'),
78
176
  ++E9CRM.js_templates.current_child_index
79
177
  );
80
178
 
81
- $(template).appendTo($parent);
179
+ // and insert the new template before this link
180
+ $(template).insertBefore($this);
82
181
 
83
182
  exclusifyEmailRadios();
84
183
  });
85
184
 
86
- /**
185
+ /*
87
186
  * Effectively destroys an added nested association, removing the container
88
187
  * the association is not persisted, or hiding it and setting the _destroy
89
188
  * parameter for the association if it is.
@@ -91,17 +190,22 @@ jQuery(function($) {
91
190
  $('a.destroy-nested-association').live('click', function(e) {
92
191
  e.preventDefault();
93
192
 
193
+ // grab the parent nested-association and attempt to get its hidden
194
+ // 'destroy' input if it exists.
94
195
  var $parent = $(this).closest('.nested-association').hide(),
95
196
  $destro = $parent.find('input[id$=__destroy]');
96
197
 
97
- if ($destro.length) {
98
- $destro.val('1');
99
- } else {
100
- $parent.remove();
101
- }
198
+ // If a in input ending in __destroy was found it means that this is a
199
+ // persisted record. Set that input's value to '1' so it will be destroyed
200
+ // on record commit.
201
+ if ($destro.length) { $destro.val('1'); }
202
+
203
+ // otherwise this record was created locally and has not been saved, so
204
+ // simply remove it.
205
+ else { $parent.remove(); }
102
206
  });
103
207
 
104
- var filter_contacts = function(data) {
208
+ var submit_with_query = function(data) {
105
209
  $.ajax({
106
210
  dataType: 'script',
107
211
  url: window.location.pathname,
@@ -156,7 +260,7 @@ jQuery(function($) {
156
260
  'tagged[]': $.makeArray($(this).find('input[name="tagged[]"]').map(function(i, el) { return $(el).attr('checked') ? $(el).val() : null }))
157
261
  });
158
262
 
159
- filter_contacts();
263
+ submit_with_query();
160
264
  });
161
265
 
162
266
  $('form#contact_search_form', $(selector_prefix)).live('submit', function(e) {
@@ -166,7 +270,7 @@ jQuery(function($) {
166
270
  'search': $(this).find('input[name=search]').val()
167
271
  });
168
272
 
169
- filter_contacts();
273
+ submit_with_query();
170
274
  });
171
275
 
172
276
  $('input#contact_search_clear', $(selector_prefix)).live('click', function(e) {
@@ -178,10 +282,10 @@ jQuery(function($) {
178
282
 
179
283
  $.query = {};
180
284
 
181
- filter_contacts();
285
+ submit_with_query();
182
286
  });
183
287
 
184
- //$('#menu_option_key_select_form select').change(function(e) {
288
+ //$('#menu_option_key_select_form select').bindSelectChange(function(e) {
185
289
  //$(this).submit();
186
290
  //});
187
291
  });
@@ -68,9 +68,16 @@ class CreateE9CrmStructure < ActiveRecord::Migration
68
68
  t.timestamps
69
69
  end
70
70
 
71
+ create_table :contacts_deals, :force => true, :id => false do |t|
72
+ t.references :contact, :deal
73
+ end
74
+
71
75
  create_table :deals, :force => true do |t|
72
76
  t.string :type
73
- t.references :offer, :campaign, :tracking_cookie
77
+ t.string :name
78
+ t.string :category
79
+ t.text :info
80
+ t.references :offer, :campaign, :tracking_cookie, :contact
74
81
  t.timestamp :created_at, :updated_at, :converted_at, :closed_at
75
82
  t.string :status, :limit => 32
76
83
  t.integer :value, :default => 0
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.6
5
+ version: 0.1.7
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-19 00:00:00 -04:00
13
+ date: 2011-05-20 00:00:00 -04:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -215,6 +215,7 @@ files:
215
215
  - app/views/e9_crm/contacts/_form_inner.html.haml
216
216
  - app/views/e9_crm/contacts/_header.html.haml
217
217
  - app/views/e9_crm/contacts/_sidebar.html.haml
218
+ - app/views/e9_crm/contacts/_table.html.haml
218
219
  - app/views/e9_crm/contacts/_tag_table.html.haml
219
220
  - app/views/e9_crm/contacts/_who.html.haml
220
221
  - app/views/e9_crm/contacts/index.html.haml
@@ -233,9 +234,11 @@ files:
233
234
  - app/views/e9_crm/dated_costs/new.html.haml
234
235
  - app/views/e9_crm/dated_costs/show.html.haml
235
236
  - app/views/e9_crm/dated_costs/update.js.erb
237
+ - app/views/e9_crm/deals/_footer.html.haml
236
238
  - app/views/e9_crm/deals/_form_inner.html.haml
237
239
  - app/views/e9_crm/deals/_header.html.haml
238
240
  - app/views/e9_crm/deals/_reports_table.html.haml
241
+ - app/views/e9_crm/deals/_table.html.haml
239
242
  - app/views/e9_crm/deals/leads.html.haml
240
243
  - app/views/e9_crm/deals/reports.html.haml
241
244
  - app/views/e9_crm/deals/reports.js.erb