ffcrm_cloudfuji 0.2.1 → 0.2.2
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.
- data/app/assets/javascripts/event_rules.js.coffee +55 -0
- data/app/assets/javascripts/ffcrm_cloudfuji.js +1 -1
- data/app/assets/stylesheets/event_rules.css.scss +53 -0
- data/app/assets/stylesheets/ffcrm_cloudfuji.css +1 -1
- data/app/controllers/admin/{lead_scoring_controller.rb → event_rules_controller.rb} +12 -12
- data/app/helpers/admin/event_rules_helper.rb +47 -0
- data/app/models/event_rule.rb +112 -0
- data/app/models/lead_event_rule_count.rb +4 -0
- data/app/observers/cloudfuji_lead_observer.rb +27 -0
- data/app/views/admin/{lead_scoring → event_rules}/_errors.html.haml +1 -1
- data/app/views/admin/event_rules/_form.html.haml +39 -0
- data/app/views/admin/{lead_scoring → event_rules}/index.html.haml +7 -7
- data/app/views/leads/_sidebar_show_lead_scoring.html.haml +3 -3
- data/config/locales/en-US.yml +5 -0
- data/config/routes.rb +1 -1
- data/db/migrate/20120524031157_extend_lead_scoring_as_event_rules.rb +54 -0
- data/db/migrate/20120525151511_add_ido_id_to_lead.rb +5 -0
- data/lib/fat_free_crm/cloudfuji/event_observers/customer_observer.rb +3 -1
- data/lib/fat_free_crm/cloudfuji/event_observers/email_observer.rb +4 -2
- data/lib/fat_free_crm/cloudfuji/event_observers/event_rules_observer.rb +23 -0
- data/lib/fat_free_crm/cloudfuji/event_observers/user_observer.rb +6 -5
- data/lib/fat_free_crm/cloudfuji.rb +1 -1
- data/lib/ffcrm_cloudfuji/engine.rb +9 -4
- data/lib/ffcrm_cloudfuji/version.rb +1 -1
- data/spec/event_observers/event_rules_observer_spec.rb +103 -0
- data/spec/factories/lead_scoring_factories.rb +9 -3
- data/spec/internal/db/schema.rb +19 -13
- data/spec/models/event_rule_spec.rb +47 -0
- data/spec/observers/cloudfuji_lead_observer_spec.rb +26 -0
- metadata +80 -92
- data/app/assets/javascripts/lead_scoring.js.coffee +0 -42
- data/app/assets/stylesheets/lead_scoring.css.scss +0 -47
- data/app/helpers/admin/lead_scoring_helper.rb +0 -10
- data/app/models/lead_scoring_rule.rb +0 -6
- data/app/models/lead_scoring_rule_count.rb +0 -4
- data/app/views/admin/lead_scoring/_form.html.haml +0 -14
- data/config/initializers/inflections.rb +0 -3
- data/lib/fat_free_crm/cloudfuji/event_observers/lead_scoring_observer.rb +0 -38
- data/spec/event_observers/lead_scoring_observer_spec.rb +0 -87
@@ -0,0 +1,55 @@
|
|
1
|
+
(($) ->
|
2
|
+
class @EventRules
|
3
|
+
constructor: (@templates = {}) ->
|
4
|
+
|
5
|
+
add_fields: (button, content) ->
|
6
|
+
new_id = new Date().getTime()
|
7
|
+
regexp = new RegExp('new_event_rule', 'g')
|
8
|
+
$('ul#event_rules').append(content.replace(regexp, new_id))
|
9
|
+
# Setup event autocomplete for new field
|
10
|
+
this.cloudfuji_event_autocomplete('input#event_rules_'+new_id+'_cloudfuji_event')
|
11
|
+
|
12
|
+
remove_fields: (button) ->
|
13
|
+
container = $(button).closest('li.event_rule')
|
14
|
+
index = container.data('index')
|
15
|
+
# If rule has no id, just remove
|
16
|
+
if $("#event_rules_"+index+"_id").length == 0
|
17
|
+
container.remove()
|
18
|
+
else
|
19
|
+
# If rule has an id, mark container as hidden and add _destroy field
|
20
|
+
container.hide()
|
21
|
+
container.append($('<input type="text" name="event_rules['+index+'][_destroy]" value="yes">'))
|
22
|
+
|
23
|
+
cloudfuji_event_autocomplete: (selector = 'input.cloudfuji_event') ->
|
24
|
+
$(selector).autocomplete({source: observed_cloudfuji_events, minLength: 0})
|
25
|
+
# Show all events on focus, if input is empty
|
26
|
+
$(selector).focus ->
|
27
|
+
$(this).autocomplete "search", "" if $(this).val() == ""
|
28
|
+
|
29
|
+
show_field_group: (select, group_name, key) ->
|
30
|
+
# Hide all fields, then show the selected field group
|
31
|
+
container = $(select).closest('li.event_rule')
|
32
|
+
container.find('.'+group_name+'_fields').hide()
|
33
|
+
container.find('.'+group_name+'_'+key).show()
|
34
|
+
|
35
|
+
$(document).ready ->
|
36
|
+
event_rules = new EventRules()
|
37
|
+
# Initialize autocomplete for events
|
38
|
+
event_rules.cloudfuji_event_autocomplete()
|
39
|
+
|
40
|
+
$("button.add_event_rule").live "click", ->
|
41
|
+
event_rules.add_fields this, $(this).data("content")
|
42
|
+
false
|
43
|
+
|
44
|
+
$(".remove_event_rule").live "click", ->
|
45
|
+
event_rules.remove_fields this
|
46
|
+
false
|
47
|
+
|
48
|
+
$('.event_category_select').live "change", ->
|
49
|
+
event_rules.show_field_group this, 'event_category', $(this).val()
|
50
|
+
|
51
|
+
$('.action_select').live "change", ->
|
52
|
+
event_rules.show_field_group this, 'action', $(this).val()
|
53
|
+
|
54
|
+
|
55
|
+
) jQuery
|
@@ -1 +1 @@
|
|
1
|
-
//= require
|
1
|
+
//= require event_rules
|
@@ -0,0 +1,53 @@
|
|
1
|
+
ul#event_rules {
|
2
|
+
div { display: inline; }
|
3
|
+
|
4
|
+
li.event_rule {
|
5
|
+
font-size: 13px;
|
6
|
+
|
7
|
+
&:last-child {
|
8
|
+
border-bottom: none;
|
9
|
+
}
|
10
|
+
|
11
|
+
input {
|
12
|
+
font-size: 13px;
|
13
|
+
margin: 0 4px;
|
14
|
+
vertical-align: middle;
|
15
|
+
margin-bottom: 3px;
|
16
|
+
}
|
17
|
+
.cloudfuji_event { width: 120px; }
|
18
|
+
.match_input { width: 140px; }
|
19
|
+
.numeric_input { width: 35px; }
|
20
|
+
.tag_input { width: 100px; }
|
21
|
+
input[type='checkbox'] {
|
22
|
+
width: 14px;
|
23
|
+
margin-left: 2px;
|
24
|
+
}
|
25
|
+
|
26
|
+
.field_with_errors {
|
27
|
+
display: inline;
|
28
|
+
input, select {
|
29
|
+
background-color: #ffdddd;
|
30
|
+
}
|
31
|
+
select {
|
32
|
+
border: 2px solid #ff9999;
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
a.remove_event_rule {
|
38
|
+
margin-right: 6px;
|
39
|
+
img {
|
40
|
+
vertical-align: middle;
|
41
|
+
margin-bottom: 4px;
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
.buttonbar.event_rules_buttons {
|
47
|
+
width: 1155px;
|
48
|
+
float: left;
|
49
|
+
font-size: 13px;
|
50
|
+
input[type='submit'], button { font-size: 14px; }
|
51
|
+
.save_or_cancel { float: right; }
|
52
|
+
button { float: left; }
|
53
|
+
}
|
@@ -1,41 +1,41 @@
|
|
1
|
-
class Admin::
|
1
|
+
class Admin::EventRulesController < Admin::ApplicationController
|
2
2
|
before_filter :require_user
|
3
|
-
before_filter "set_current_tab('admin/
|
3
|
+
before_filter "set_current_tab('admin/event_rules')", :only => [ :index, :update ]
|
4
4
|
|
5
|
-
# GET /admin/
|
5
|
+
# GET /admin/event_rules
|
6
6
|
#----------------------------------------------------------------------------
|
7
7
|
def index
|
8
|
-
@
|
9
|
-
@
|
8
|
+
@event_rules = EventRule.all
|
9
|
+
@event_rules << EventRule.new if @event_rules.empty?
|
10
10
|
|
11
11
|
respond_to do |format|
|
12
12
|
format.html # index.html.haml
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
# PUT /admin/
|
16
|
+
# PUT /admin/event_rules
|
17
17
|
#----------------------------------------------------------------------------
|
18
18
|
def update
|
19
19
|
# Create rules without ids,
|
20
20
|
# destroy rules with '_destroy' param,
|
21
21
|
# update rules with ids
|
22
|
-
@
|
23
|
-
params[:
|
22
|
+
@event_rules = []
|
23
|
+
params[:event_rules].each do |index, data|
|
24
24
|
if data["id"].blank?
|
25
|
-
@
|
25
|
+
@event_rules << EventRule.create(data)
|
26
26
|
else
|
27
|
-
if rule =
|
27
|
+
if rule = EventRule.find_by_id(data["id"])
|
28
28
|
if data["_destroy"]
|
29
29
|
rule.destroy
|
30
30
|
else
|
31
31
|
rule.update_attributes data
|
32
|
-
@
|
32
|
+
@event_rules << rule
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
if @
|
38
|
+
if @event_rules.all?(&:valid?)
|
39
39
|
flash[:notice] = "All rules were saved successfully."
|
40
40
|
else
|
41
41
|
flash[:error] = render_to_string(:partial => "errors").html_safe
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Admin::EventRulesHelper
|
2
|
+
|
3
|
+
def add_event_rule_button(f)
|
4
|
+
fields = f.fields_for "new_event_rule", EventRule.new do |builder|
|
5
|
+
render("form", :r => builder, :index => "new_event_rule")
|
6
|
+
end
|
7
|
+
button_tag 'Add New Rule', :class => "add_event_rule", "data-content" => "#{fields}"
|
8
|
+
end
|
9
|
+
|
10
|
+
def event_category_select(form)
|
11
|
+
form.select :event_category, [
|
12
|
+
["Cloudfuji event", :cloudfuji_event_received],
|
13
|
+
["Lead attribute", :lead_attribute_changed]
|
14
|
+
], {}, :class => "event_category_select"
|
15
|
+
end
|
16
|
+
|
17
|
+
def action_select(form)
|
18
|
+
form.select :action, [
|
19
|
+
["change Lead score", :change_lead_score],
|
20
|
+
["send notification", :send_notification],
|
21
|
+
["add tag", :add_tag],
|
22
|
+
["remove tag", :remove_tag]
|
23
|
+
], {}, :class => "action_select"
|
24
|
+
end
|
25
|
+
|
26
|
+
# Generates divs with form field groups for event rules
|
27
|
+
def fields_for_event_rule_group(object, subjects, field)
|
28
|
+
subjects = [subjects].flatten
|
29
|
+
content_tag(:div, :class => subjects.map {|s| "#{field}_#{s}" }.join(" ") << " #{field}_fields",
|
30
|
+
:style => (subjects.none? {|s| s == object.send(field) } ? "display: none;" : "")) do
|
31
|
+
yield
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def event_fields_for(object, events, &content)
|
36
|
+
fields_for_event_rule_group(object, events, 'event_category', &content)
|
37
|
+
end
|
38
|
+
|
39
|
+
def action_fields_for(object, actions, &content)
|
40
|
+
fields_for_event_rule_group(object, actions, 'action', &content)
|
41
|
+
end
|
42
|
+
|
43
|
+
def lead_attributes
|
44
|
+
Lead.attribute_names - %w(id deleted_at updated_at created_at)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
class EventRule < ActiveRecord::Base
|
2
|
+
|
3
|
+
# event category validations
|
4
|
+
validates_presence_of :event_category
|
5
|
+
validates_presence_of :cloudfuji_event, :if => lambda { self.event_category == 'cloudfuji_event_received' }
|
6
|
+
validates_presence_of :lead_attribute, :if => lambda { self.event_category == 'lead_attribute_changed' }
|
7
|
+
|
8
|
+
# action validations
|
9
|
+
validates_presence_of :action
|
10
|
+
validates_presence_of :tag, :if => lambda { %w(add_tag remove_tag).include?(self.action) }
|
11
|
+
validates_numericality_of :change_score_by, :only_integer => true, :if => lambda { self.action == 'change_lead_score' }
|
12
|
+
|
13
|
+
validates_numericality_of :limit_per_lead, :only_integer => true, :allow_blank => true
|
14
|
+
|
15
|
+
has_many :lead_event_rule_counts
|
16
|
+
|
17
|
+
def process(lead, match_data)
|
18
|
+
# How many times this rule has been applied to a given Lead
|
19
|
+
count = LeadEventRuleCount.find_by_lead_id_and_event_rule_id(lead, self) ||
|
20
|
+
LeadEventRuleCount.new(:lead => lead, :event_rule => self)
|
21
|
+
# Don't apply this rule more than limit_per_lead, if set
|
22
|
+
unless limit_per_lead.present? && count.count > limit_per_lead
|
23
|
+
# If :match is present, only apply the rule if data matches string
|
24
|
+
if match.blank? || event_matches?(match_data)
|
25
|
+
# Run the action method if defined
|
26
|
+
if respond_to?(action)
|
27
|
+
send(action, lead, match_data)
|
28
|
+
# Increment and save count of rule/lead applications
|
29
|
+
count.count += 1
|
30
|
+
count.save
|
31
|
+
else
|
32
|
+
raise "Do not know how to process '#{action}' action."
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Actions
|
39
|
+
# -----------------------------------------------------------------
|
40
|
+
def change_lead_score(lead, match_data)
|
41
|
+
lead.without_versioning do
|
42
|
+
lead.update_attribute :score, lead.score + change_score_by
|
43
|
+
end
|
44
|
+
# Add history event to lead, to record change of score
|
45
|
+
lead.versions.create! :event => "Rule for #{human_event_label}: Score changed by #{change_score_by} points. (New total: #{lead.score})"
|
46
|
+
end
|
47
|
+
|
48
|
+
def send_notification(lead, match_data)
|
49
|
+
if ::Cloudfuji::Platform.on_cloudfuji?
|
50
|
+
# Fire a Cloudfuji event
|
51
|
+
message = case event_category
|
52
|
+
when 'cloudfuji_event_received'
|
53
|
+
"Cloudfuji event was received - '#{cloudfuji_event}'"
|
54
|
+
when 'lead_attribute_changed'
|
55
|
+
"Lead \"#{lead.full_name}\" was updated - #{lead_attribute} was changed from '#{match_data[0]}' to '#{match_data[1]}'."
|
56
|
+
end
|
57
|
+
|
58
|
+
event = {
|
59
|
+
:category => :fat_free_crm,
|
60
|
+
:name => :notification,
|
61
|
+
:data => {
|
62
|
+
:message => message
|
63
|
+
}
|
64
|
+
}
|
65
|
+
::Cloudfuji::Event.publish(event)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def add_tag(lead, match_data)
|
70
|
+
lead.tag_list << tag
|
71
|
+
save_lead_without_versioning_or_observers(lead)
|
72
|
+
lead.versions.create! :event => "Rule for #{human_event_label}: Added tag '#{tag}'"
|
73
|
+
end
|
74
|
+
|
75
|
+
def remove_tag(lead, match_data)
|
76
|
+
lead.tag_list -= [tag]
|
77
|
+
save_lead_without_versioning_or_observers(lead)
|
78
|
+
lead.versions.create! :event => "Rule for #{human_event_label}: Removed tag '#{tag}'"
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def event_matches?(match_data)
|
85
|
+
test_string = case_insensitive_matching ? match.downcase : match
|
86
|
+
case event_category
|
87
|
+
when 'cloudfuji_event_received'
|
88
|
+
match_string = match_data.inspect
|
89
|
+
match_string.downcase! if case_insensitive_matching
|
90
|
+
match_string.include?(test_string)
|
91
|
+
when 'lead_attribute_changed'
|
92
|
+
match_string = match_data[1].dup
|
93
|
+
match_string.downcase! if case_insensitive_matching
|
94
|
+
match_string == test_string
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def human_event_label
|
99
|
+
case event_category
|
100
|
+
when 'cloudfuji_event_received'; "Cloudfuji event - '#{cloudfuji_event}'"
|
101
|
+
when 'lead_attribute_changed'; "Lead update - '#{lead_attribute}'"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def save_lead_without_versioning_or_observers(lead)
|
106
|
+
Lead.observers.disable :cloudfuji_lead_observer do
|
107
|
+
lead.without_versioning do
|
108
|
+
lead.save
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Fat Free CRM
|
2
|
+
# Copyright (C) 2008-2011 by Michael Dvorkin
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
#------------------------------------------------------------------------------
|
17
|
+
|
18
|
+
class CloudfujiLeadObserver < ActiveRecord::Observer
|
19
|
+
observe :lead
|
20
|
+
|
21
|
+
def after_update(lead)
|
22
|
+
# Find all event rules where the lead attribute is one of the changed fields
|
23
|
+
EventRule.find_all_by_event_category_and_lead_attribute('lead_attribute_changed', lead.changes.keys).each do |rule|
|
24
|
+
rule.process(lead, lead.changes[rule.lead_attribute]) # Send [old, new] values as matching data
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
%li.event_rule{"data-index" => index}
|
2
|
+
= link_to image_tag('delete.png', :size => '16x16', :alt => 'Remove Rule'), nil, :class => "remove_event_rule"
|
3
|
+
|
4
|
+
= r.hidden_field(:id) unless r.object.new_record?
|
5
|
+
|
6
|
+
If
|
7
|
+
= event_category_select(r)
|
8
|
+
|
9
|
+
= event_fields_for(r.object, 'cloudfuji_event_received') do
|
10
|
+
= r.text_field :cloudfuji_event, :class => "cloudfuji_event"
|
11
|
+
is received, and contains
|
12
|
+
|
13
|
+
= event_fields_for(r.object, 'lead_attribute_changed') do
|
14
|
+
= r.select :lead_attribute, lead_attributes, :class => "lead_attribute", :include_blank => true
|
15
|
+
changes, and equals
|
16
|
+
|
17
|
+
= content_tag(:small, "(optional)") << ":".html_safe
|
18
|
+
= r.text_field :match, :class => "match_input"
|
19
|
+
|
20
|
+
%small
|
21
|
+
(Case insensitive?
|
22
|
+
= r.check_box(:case_insensitive_matching) << h(")")
|
23
|
+
|
24
|
+
then
|
25
|
+
= action_select(r)
|
26
|
+
|
27
|
+
= action_fields_for(r.object, 'change_lead_score') do
|
28
|
+
by
|
29
|
+
= r.text_field :change_score_by, :class => "numeric_input"
|
30
|
+
points.
|
31
|
+
|
32
|
+
-# Add/Remove tag actions share the same field
|
33
|
+
= action_fields_for(r.object, %w(add_tag remove_tag)) do
|
34
|
+
= r.text_field :tag, :class => "tag_input"
|
35
|
+
|
36
|
+
= action_fields_for(r.object, %w(change_lead_score send_notification)) do
|
37
|
+
%small
|
38
|
+
(Limit per lead:
|
39
|
+
= r.text_field(:limit_per_lead, :class => "numeric_input") << h(")")
|
@@ -2,18 +2,18 @@
|
|
2
2
|
var observed_cloudfuji_events = #{Cloudfuji::Data.observed_events.map(&:to_s).inspect};
|
3
3
|
|
4
4
|
.title
|
5
|
-
|
5
|
+
Event Rules
|
6
6
|
|
7
7
|
.list
|
8
|
-
= form_for :
|
9
|
-
%ul#
|
10
|
-
- @
|
8
|
+
= form_for :event_rules do |f|
|
9
|
+
%ul#event_rules
|
10
|
+
- @event_rules.each_with_index do |rule, i|
|
11
11
|
= f.fields_for i.to_s, rule do |r|
|
12
12
|
= render "form", :r => r, :index => i
|
13
13
|
|
14
|
-
.buttonbar.
|
15
|
-
=
|
14
|
+
.buttonbar.event_rules_buttons
|
15
|
+
= add_event_rule_button(f)
|
16
16
|
.save_or_cancel
|
17
17
|
= submit_tag 'Save', :name => :save
|
18
18
|
#{t :or}
|
19
|
-
= link_to "Cancel",
|
19
|
+
= link_to "Cancel", admin_event_rules_path
|
@@ -1,8 +1,8 @@
|
|
1
|
-
.caption
|
1
|
+
.caption Event Rules
|
2
2
|
%li
|
3
3
|
%dt= lead.score
|
4
4
|
%tt Score:
|
5
|
-
- if lead.respond_to?(:
|
5
|
+
- if lead.respond_to?(:lead_event_rule_counts) && lead.lead_event_rule_counts.any?
|
6
6
|
%li
|
7
|
-
%dt= lead.
|
7
|
+
%dt= lead.lead_event_rule_counts.sum {|c| c.count }
|
8
8
|
%tt Total scoring events:
|
data/config/routes.rb
CHANGED
@@ -0,0 +1,54 @@
|
|
1
|
+
class ExtendLeadScoringAsEventRules < ActiveRecord::Migration
|
2
|
+
def up
|
3
|
+
# Save current values of boolean :once column
|
4
|
+
once_values = connection.select_all("SELECT id,once from lead_scoring_rules;")
|
5
|
+
|
6
|
+
rename_table :lead_scoring_rules, :event_rules
|
7
|
+
|
8
|
+
rename_table :lead_scoring_rule_counts, :lead_event_rule_counts
|
9
|
+
rename_column :lead_event_rule_counts, :lead_scoring_rule_id, :event_rule_id
|
10
|
+
|
11
|
+
add_column :event_rules, :event_category, :string, :default => 'cloudfuji_event_received'
|
12
|
+
|
13
|
+
# Columns for cloudfuji event matching
|
14
|
+
rename_column :event_rules, :event, :cloudfuji_event
|
15
|
+
|
16
|
+
# Columns for lead column changes
|
17
|
+
add_column :event_rules, :lead_attribute, :string
|
18
|
+
|
19
|
+
# Columns for actions
|
20
|
+
add_column :event_rules, :action, :string, :default => 'change_lead_score'
|
21
|
+
add_column :event_rules, :tag, :string
|
22
|
+
rename_column :event_rules, :points, :change_score_by
|
23
|
+
|
24
|
+
remove_column :event_rules, :once
|
25
|
+
add_column :event_rules, :limit_per_lead, :integer
|
26
|
+
add_column :event_rules, :case_insensitive_matching, :boolean
|
27
|
+
|
28
|
+
# Migrate :once values to :limit_times & :max_times
|
29
|
+
ids = once_values.select{|v| v['once'] == 't' }.map {|v| v['id'] }
|
30
|
+
if ids.any?
|
31
|
+
connection.execute("UPDATE event_rules SET limit_times = 1, max_times = 1 WHERE id IN (#{ids.join(',')});")
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
# Instead of meticulously mirroring the reverse of all these changes,
|
37
|
+
# just drop the tables and re-create the tables from the previous migration.
|
38
|
+
def down
|
39
|
+
# Remove tables
|
40
|
+
drop_table :event_rules
|
41
|
+
drop_table :lead_event_rule_counts
|
42
|
+
# Load previous migration
|
43
|
+
require File.expand_path('../20120515194445_add_lead_scoring_rules.rb', __FILE__)
|
44
|
+
migration = AddLeadScoringRules.new
|
45
|
+
# Only create tables (don't re-add columns to app tables)
|
46
|
+
migration.class_eval do
|
47
|
+
def add_column(table, column, type, options)
|
48
|
+
puts "-- not re-adding '#{column}' column to '#{table}' table."
|
49
|
+
end
|
50
|
+
end
|
51
|
+
# Run migration
|
52
|
+
migration.up
|
53
|
+
end
|
54
|
+
end
|
@@ -42,10 +42,12 @@ module FatFreeCRM
|
|
42
42
|
return result if result
|
43
43
|
end
|
44
44
|
|
45
|
-
lead
|
45
|
+
lead = Lead.find_by_ido_id(data['customer_ido_id'])
|
46
|
+
lead ||= Lead.find_by_email(data['email'])
|
46
47
|
lead ||= Lead.new
|
47
48
|
|
48
49
|
lead.email = data['email']
|
50
|
+
lead.ido_id = data['customer_ido_id']
|
49
51
|
lead.first_name = data['first_name'] || data['email'].split("@").first if lead.first_name.blank?
|
50
52
|
lead.last_name = data['last_name'] || data['email'].split("@").last if lead.last_name.blank?
|
51
53
|
lead.user ||= User.first
|
@@ -79,10 +79,12 @@ module FatFreeCRM
|
|
79
79
|
end
|
80
80
|
|
81
81
|
puts "No pre-existing records found, creating a lead"
|
82
|
-
lead = Lead.
|
82
|
+
lead = Lead.find_by_ido_id(data['customer_ido_id'])
|
83
|
+
lead ||= Lead.find_by_email(recipient)
|
83
84
|
lead ||= Lead.new
|
84
85
|
|
85
|
-
lead.email
|
86
|
+
lead.email = recipient
|
87
|
+
lead.ido_id = data['customer_ido_id']
|
86
88
|
lead.first_name = recipient.split("@").first if lead.first_name.blank?
|
87
89
|
lead.last_name = recipient.split("@").last if lead.last_name.blank?
|
88
90
|
lead.user ||= User.first
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module FatFreeCRM
|
2
|
+
module Cloudfuji
|
3
|
+
module EventObservers
|
4
|
+
class EventRulesObserver < ::Cloudfuji::EventObserver
|
5
|
+
# Fire for all events
|
6
|
+
def catch_all
|
7
|
+
data = params['data']
|
8
|
+
email = data['email'] || data['recipient']
|
9
|
+
# Look up Lead by ido_id, fall back to email address
|
10
|
+
lead = Lead.find_by_ido_id(data['customer_ido_id'])
|
11
|
+
if lead ||= Lead.find_by_email(email)
|
12
|
+
event_name = "#{params['category']}_#{params['event']}"
|
13
|
+
|
14
|
+
EventRule.find_all_by_event_category_and_cloudfuji_event('cloudfuji_event_received', event_name).each do |rule|
|
15
|
+
rule.process(lead, params['data'])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -3,20 +3,21 @@ module FatFreeCRM
|
|
3
3
|
module EventObservers
|
4
4
|
class UserObserver < ::Cloudfuji::EventObserver
|
5
5
|
def user_added
|
6
|
+
data = params['data']
|
7
|
+
ido_id = data['ido_id'].to_s
|
8
|
+
|
6
9
|
puts "Adding a new user with incoming data #{params.inspect}"
|
7
10
|
puts "Authlogic username column: #{::Authlogic::Cas.cas_username_column}="
|
8
|
-
puts "Setting username to: #{
|
9
|
-
|
10
|
-
data = params['data']
|
11
|
+
puts "Setting username to: #{ido_id}"
|
11
12
|
|
12
|
-
user = User.unscoped.find_or_create_by_ido_id(
|
13
|
+
user = User.unscoped.find_or_create_by_ido_id(ido_id)
|
13
14
|
|
14
15
|
user.email = data['email']
|
15
16
|
user.first_name = user.email.split('@').first
|
16
17
|
user.last_name = user.email.split('@').last
|
17
18
|
user.username = data['email']
|
18
19
|
user.deleted_at = nil
|
19
|
-
user.send("#{::Authlogic::Cas.cas_username_column}=".to_sym,
|
20
|
+
user.send("#{::Authlogic::Cas.cas_username_column}=".to_sym, ido_id)
|
20
21
|
|
21
22
|
puts user.inspect
|
22
23
|
|
@@ -1,15 +1,20 @@
|
|
1
1
|
module FatFreeCRM
|
2
2
|
module Cloudfuji
|
3
3
|
class Engine < Rails::Engine
|
4
|
+
config.before_initialize do
|
5
|
+
# Register observers to fire Cloudfuji events
|
6
|
+
(config.active_record.observers ||= []) << :cloudfuji_lead_observer
|
7
|
+
end
|
8
|
+
|
4
9
|
config.to_prepare do
|
5
10
|
require 'fat_free_crm/cloudfuji/view_hooks'
|
6
11
|
|
7
|
-
# Add
|
12
|
+
# Add Event Rules tab
|
8
13
|
begin
|
9
|
-
unless FatFreeCRM::Tabs.admin.any? {|t| t[:text] == "
|
14
|
+
unless FatFreeCRM::Tabs.admin.any? {|t| t[:text] == "Event Rules" }
|
10
15
|
FatFreeCRM::Tabs.admin << {
|
11
|
-
:text => "
|
12
|
-
:url => { :controller => "admin/
|
16
|
+
:text => "Event Rules",
|
17
|
+
:url => { :controller => "admin/event_rules" }
|
13
18
|
}
|
14
19
|
end
|
15
20
|
rescue TypeError
|