fat_free_crm 0.21.0 → 0.22.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.
Potentially problematic release.
This version of fat_free_crm might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/app/assets/config/fat_free_crm.js +3 -0
- data/app/assets/config/manifest.js +1 -3
- data/app/assets/javascripts/application.js.erb +1 -0
- data/app/assets/javascripts/crm.js.coffee +6 -3
- data/app/assets/javascripts/crm_select2.js.coffee +4 -1
- data/app/assets/javascripts/crm_tags.js.coffee +4 -4
- data/app/assets/javascripts/crm_validations.js.coffee +12 -0
- data/app/assets/stylesheets/bootstrap-custom.scss +3 -3
- data/app/assets/stylesheets/common.scss +9 -0
- data/app/assets/stylesheets/rails.scss +1 -1
- data/app/controllers/admin/field_groups_controller.rb +0 -2
- data/app/controllers/admin/fields_controller.rb +16 -13
- data/app/controllers/admin/tags_controller.rb +1 -1
- data/app/controllers/admin/users_controller.rb +1 -1
- data/app/controllers/application_controller.rb +11 -0
- data/app/controllers/comments_controller.rb +2 -0
- data/app/controllers/emails_controller.rb +2 -0
- data/app/controllers/entities/accounts_controller.rb +3 -1
- data/app/controllers/entities/campaigns_controller.rb +3 -1
- data/app/controllers/entities/contacts_controller.rb +3 -1
- data/app/controllers/entities/leads_controller.rb +4 -2
- data/app/controllers/entities/opportunities_controller.rb +3 -1
- data/app/controllers/entities_controller.rb +3 -1
- data/app/controllers/home_controller.rb +2 -0
- data/app/controllers/lists_controller.rb +7 -4
- data/app/controllers/tasks_controller.rb +3 -1
- data/app/controllers/users_controller.rb +2 -0
- data/app/helpers/application_helper.rb +4 -4
- data/app/helpers/opportunities_helper.rb +4 -2
- data/app/helpers/users_helper.rb +1 -1
- data/app/models/entities/campaign.rb +2 -2
- data/app/models/fields/custom_field.rb +2 -2
- data/app/models/fields/custom_field_pair.rb +6 -7
- data/app/models/fields/field.rb +1 -3
- data/app/models/list.rb +1 -1
- data/app/models/observers/entity_observer.rb +1 -1
- data/app/models/polymorphic/comment.rb +1 -1
- data/app/models/setting.rb +4 -5
- data/app/models/users/user.rb +1 -1
- data/app/views/accounts/_contact_info.html.haml +1 -1
- data/app/views/accounts/_top_section.html.haml +3 -3
- data/app/views/accounts/show.js.haml +1 -1
- data/app/views/accounts/update.js.haml +1 -0
- data/app/views/admin/custom_fields/_check_boxes_field.html.haml +4 -1
- data/app/views/admin/custom_fields/_date_pair_field.html.haml +1 -1
- data/app/views/campaigns/_top_section.html.haml +2 -2
- data/app/views/campaigns/show.js.haml +1 -1
- data/app/views/campaigns/update.js.haml +1 -0
- data/app/views/contacts/_top_section.html.haml +5 -5
- data/app/views/contacts/show.js.haml +2 -3
- data/app/views/contacts/update.js.haml +1 -0
- data/app/views/devise/sessions/new.html.haml +4 -5
- data/app/views/fields/_group.html.haml +5 -2
- data/app/views/fields/_group_table.html.haml +4 -5
- data/app/views/fields/_group_view.html.haml +4 -1
- data/app/views/fields/_sidebar_show.html.haml +5 -8
- data/app/views/fields/group.js.erb +3 -1
- data/app/views/layouts/application.html.haml +1 -1
- data/app/views/leads/_top_section.html.haml +4 -4
- data/app/views/leads/show.js.haml +1 -1
- data/app/views/leads/update.js.haml +1 -0
- data/app/views/opportunities/_top_section.html.haml +2 -2
- data/app/views/opportunities/show.js.haml +1 -1
- data/app/views/opportunities/update.js.haml +1 -0
- data/app/views/shared/_add_comment.html.haml +1 -1
- data/app/views/shared/_address.html.haml +1 -1
- data/app/views/tasks/_top_section.html.haml +4 -4
- data/bin/bundle +108 -2
- data/bin/rails +3 -3
- data/bin/rake +2 -2
- data/bin/setup +12 -15
- data/config/application.rb +9 -4
- data/config/boot.rb +3 -5
- data/config/cable.yml +10 -0
- data/config/database.yml +25 -0
- data/config/environment.rb +4 -3
- data/config/environments/development.rb +47 -14
- data/config/environments/production.rb +17 -15
- data/config/environments/test.rb +19 -9
- data/config/initializers/action_mailer.rb +1 -0
- data/config/initializers/content_security_policy.rb +21 -26
- data/config/initializers/custom_field_ransack_translations.rb +2 -1
- data/config/initializers/filter_parameter_logging.rb +6 -2
- data/config/initializers/inflections.rb +4 -4
- data/config/initializers/permissions_policy.rb +12 -0
- data/config/settings.default.yml +2 -1
- data/config/storage.yml +5 -5
- data/db/demo/field_groups.yml +2 -1
- data/db/migrate/20230526212613_convert_to_active_storage.rb +27 -11
- data/db/schema.rb +107 -105
- data/lib/fat_free_crm/callback.rb +2 -3
- data/lib/fat_free_crm/custom_fields.rb +1 -0
- data/lib/fat_free_crm/mail_processor/dropbox.rb +1 -1
- data/lib/fat_free_crm/version.rb +2 -2
- metadata +43 -19
- data/config/initializers/new_framework_defaults_6_0.rb +0 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ed29c049db6b4f6c31a7c1f5a3a083c1ab92a87d1475ae0808777a8d5c87c9d
|
4
|
+
data.tar.gz: ea1c36a463eafd3c50db26e072a447e74a8d07095a9bd19d0149096f681dc36b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31bf4871e24767881af295b9b686a62b5c7de6d56894d67f13af38d6721f8728b36d3a0535b05a9b7f14ebbc65d5648ee4dd9924ded07fcf3308fe04835ea428
|
7
|
+
data.tar.gz: 71240615f55f2e0ac3527223d240470d28c3ada768a5f7240c4aea3a1b976ced11e10a2d4335cd733971ba526719f06ff44b7a15ca41127bb63aea7dbc5dd4ab
|
@@ -9,8 +9,8 @@
|
|
9
9
|
@[0].toUpperCase() + @.substring(1)
|
10
10
|
|
11
11
|
window.crm =
|
12
|
-
EXPANDED: "&#
|
13
|
-
COLLAPSED: "&#
|
12
|
+
EXPANDED: "▽"
|
13
|
+
COLLAPSED: "▷"
|
14
14
|
searchRequest: null
|
15
15
|
autocompleter: null
|
16
16
|
base_url: ""
|
@@ -336,7 +336,10 @@
|
|
336
336
|
|
337
337
|
# Country dropdown needs special treatment ;-)
|
338
338
|
country = $("#" + from + "_attributes_country").select2("data")
|
339
|
-
|
339
|
+
if country.length == 1
|
340
|
+
country_dropdown = $("#" + to + "_attributes_country")
|
341
|
+
country_dropdown.val(country[0].id)
|
342
|
+
country_dropdown.trigger('change')
|
340
343
|
|
341
344
|
|
342
345
|
#----------------------------------------------------------------------------
|
@@ -15,6 +15,7 @@
|
|
15
15
|
$(this).select2
|
16
16
|
'width':'resolve'
|
17
17
|
placeholder: $(this).attr("placeholder")
|
18
|
+
allowClear: true
|
18
19
|
ajax:
|
19
20
|
url: $(this).data("url")
|
20
21
|
dataType: 'json'
|
@@ -22,16 +23,18 @@
|
|
22
23
|
$(this).select2
|
23
24
|
'width':'resolve'
|
24
25
|
placeholder: $(this).attr("placeholder")
|
26
|
+
allowClear: true
|
25
27
|
|
26
28
|
if $(this).prop("disabled") == true
|
27
29
|
$(this).next('.select2-container').disable()
|
28
|
-
$(this).next('.select2-container').hide()
|
30
|
+
$(this).next('.select2-container').hide()
|
29
31
|
|
30
32
|
$(".select2_tag").not(".select2-container, .select2-offscreen").each ->
|
31
33
|
$(this).select2
|
32
34
|
'width':'resolve'
|
33
35
|
placeholder: $(this).data("placeholder")
|
34
36
|
multiple: $(this).data("multiple")
|
37
|
+
allowClear: true
|
35
38
|
|
36
39
|
$(document).ready ->
|
37
40
|
crm.make_select2()
|
@@ -7,16 +7,16 @@
|
|
7
7
|
|
8
8
|
# The multiselect tag list has listeners to load/remove fieldsets related to tags
|
9
9
|
#----------------------------------------------------------------------------
|
10
|
-
$(document).on 'select2
|
10
|
+
$(document).on 'select2:select', "[name*='tag_list']", (event) ->
|
11
11
|
url = $(this).data('url')
|
12
12
|
asset_id = $(this).data('asset-id')
|
13
13
|
$.get(url, {
|
14
|
-
tag: event.
|
14
|
+
tag: event.params.data.text
|
15
15
|
asset_id: asset_id
|
16
16
|
collapsed: "no"
|
17
17
|
})
|
18
18
|
|
19
|
-
$(document).on 'select2
|
20
|
-
$("#field_groups div[data-tag='" + event.
|
19
|
+
$(document).on 'select2:unselect', "[name*='tag_list']", (event) ->
|
20
|
+
$("#field_groups div[data-tag='" + event.params.data.text + "']").remove()
|
21
21
|
|
22
22
|
) jQuery
|
@@ -0,0 +1,12 @@
|
|
1
|
+
#------------------------------------------------------------------------------
|
2
|
+
(($) ->
|
3
|
+
|
4
|
+
# Ensure that any html5 required fields are unhidden when invalid
|
5
|
+
#----------------------------------------------------------------------------
|
6
|
+
$(document).on 'click', 'form.simple_form input:submit', (event) ->
|
7
|
+
form = this.closest('form')
|
8
|
+
invalidInputs = form.querySelectorAll(':invalid')
|
9
|
+
$(invalidInputs).each ->
|
10
|
+
$(this).closest('.field_group').show()
|
11
|
+
|
12
|
+
) jQuery
|
@@ -165,12 +165,12 @@ button.navbar-toggler:focus {
|
|
165
165
|
dl {
|
166
166
|
li {
|
167
167
|
width: 23%;
|
168
|
-
font-size:
|
168
|
+
font-size: 1rem;
|
169
169
|
dt {
|
170
|
-
font-size:
|
170
|
+
font-size: 0.75rem;
|
171
171
|
}
|
172
172
|
tt {
|
173
|
-
font-size:
|
173
|
+
font-size: 0.75rem;
|
174
174
|
}
|
175
175
|
}
|
176
176
|
}
|
@@ -22,8 +22,6 @@ class Admin::FieldGroupsController < Admin::ApplicationController
|
|
22
22
|
def edit
|
23
23
|
@field_group = FieldGroup.find(params[:id])
|
24
24
|
|
25
|
-
@previous = FieldGroup.find_by_id(Regexp.last_match[1]) || Regexp.last_match[1].to_i if params[:previous].to_s =~ /(\d+)\z/
|
26
|
-
|
27
25
|
respond_with(@field_group)
|
28
26
|
end
|
29
27
|
|
@@ -33,7 +33,7 @@ class Admin::FieldsController < Admin::ApplicationController
|
|
33
33
|
# GET /fields/1/edit AJAX
|
34
34
|
#----------------------------------------------------------------------------
|
35
35
|
def edit
|
36
|
-
@field = Field.find(params[
|
36
|
+
@field = Field.find(params["id"])
|
37
37
|
respond_with(@field)
|
38
38
|
end
|
39
39
|
|
@@ -41,12 +41,12 @@ class Admin::FieldsController < Admin::ApplicationController
|
|
41
41
|
# POST /fields.xml AJAX
|
42
42
|
#----------------------------------------------------------------------------
|
43
43
|
def create
|
44
|
-
as = field_params[
|
44
|
+
as = field_params["as"]
|
45
|
+
klass= Field.lookup_class(as).safe_constantize
|
45
46
|
@field =
|
46
47
|
if as.match?(/pair/)
|
47
|
-
|
48
|
+
klass.create_pair("pair" => pair_params, "field" => field_params).first
|
48
49
|
elsif as.present?
|
49
|
-
klass = find_class(Field.lookup_class(as))
|
50
50
|
klass.create(field_params)
|
51
51
|
else
|
52
52
|
Field.new(field_params).tap(&:valid?)
|
@@ -59,10 +59,10 @@ class Admin::FieldsController < Admin::ApplicationController
|
|
59
59
|
# PUT /fields/1.xml AJAX
|
60
60
|
#----------------------------------------------------------------------------
|
61
61
|
def update
|
62
|
-
if field_params[
|
63
|
-
@field = CustomFieldPair.update_pair(
|
62
|
+
if field_params["as"].match?(/pair/)
|
63
|
+
@field = CustomFieldPair.update_pair("pair" => pair_params, "field" => field_params).first
|
64
64
|
else
|
65
|
-
@field = Field.find(params[
|
65
|
+
@field = Field.find(params["id"])
|
66
66
|
@field.update(field_params)
|
67
67
|
end
|
68
68
|
|
@@ -73,7 +73,7 @@ class Admin::FieldsController < Admin::ApplicationController
|
|
73
73
|
# DELETE /fields/1.xml HTML and AJAX
|
74
74
|
#----------------------------------------------------------------------------
|
75
75
|
def destroy
|
76
|
-
@field = Field.find(params[
|
76
|
+
@field = Field.find(params["id"])
|
77
77
|
@field.destroy
|
78
78
|
|
79
79
|
respond_with(@field)
|
@@ -82,7 +82,7 @@ class Admin::FieldsController < Admin::ApplicationController
|
|
82
82
|
# POST /fields/sort
|
83
83
|
#----------------------------------------------------------------------------
|
84
84
|
def sort
|
85
|
-
field_group_id = params[
|
85
|
+
field_group_id = params["field_group_id"].to_i
|
86
86
|
field_ids = params["fields_field_group_#{field_group_id}"] || []
|
87
87
|
|
88
88
|
field_ids.each_with_index do |id, index|
|
@@ -96,13 +96,12 @@ class Admin::FieldsController < Admin::ApplicationController
|
|
96
96
|
#----------------------------------------------------------------------------
|
97
97
|
def subform
|
98
98
|
field = field_params
|
99
|
-
as =
|
100
|
-
|
99
|
+
as = field_params["as"]
|
101
100
|
@field = if (id = field[:id]).present?
|
102
101
|
Field.find(id).tap { |f| f.as = as }
|
103
102
|
else
|
104
103
|
field_group_id = field[:field_group_id]
|
105
|
-
klass =
|
104
|
+
klass = Field.lookup_class(as).safe_constantize
|
106
105
|
klass.new(field_group_id: field_group_id, as: as)
|
107
106
|
end
|
108
107
|
|
@@ -114,7 +113,11 @@ class Admin::FieldsController < Admin::ApplicationController
|
|
114
113
|
protected
|
115
114
|
|
116
115
|
def field_params
|
117
|
-
params
|
116
|
+
params.require(:field).permit(:as, :collection_string, :disabled, :field_group_id, :hint, :label, :maxlength, :minlength, :name, :pair_id, :placeholder, :position, :required, :type, settings: {})
|
117
|
+
end
|
118
|
+
|
119
|
+
def pair_params
|
120
|
+
params.require(:pair).permit("0": [:hint, :required, :disabled, :id], "1": [:hint, :required, :disabled, :id])
|
118
121
|
end
|
119
122
|
|
120
123
|
def setup_current_tab
|
@@ -28,7 +28,7 @@ class Admin::TagsController < Admin::ApplicationController
|
|
28
28
|
# GET /admin/tags/1/edit AJAX
|
29
29
|
#----------------------------------------------------------------------------
|
30
30
|
def edit
|
31
|
-
@previous = Tag.find_by_id(
|
31
|
+
@previous = Tag.find_by_id(detect_previous_id) || detect_previous_id if detect_previous_id
|
32
32
|
end
|
33
33
|
|
34
34
|
# POST /admin/tags
|
@@ -35,7 +35,7 @@ class Admin::UsersController < Admin::ApplicationController
|
|
35
35
|
# GET /admin/users/1/edit AJAX
|
36
36
|
#----------------------------------------------------------------------------
|
37
37
|
def edit
|
38
|
-
@previous = User.find_by_id(
|
38
|
+
@previous = User.find_by_id(detect_previous_id) || detect_previous_id if detect_previous_id
|
39
39
|
|
40
40
|
respond_with(@user)
|
41
41
|
end
|
@@ -268,4 +268,15 @@ class ApplicationController < ActionController::Base
|
|
268
268
|
raise "Unknown resource"
|
269
269
|
end
|
270
270
|
end
|
271
|
+
|
272
|
+
# In a number of places, we pass ?previous=(id) or ?previous=crm.find_form...
|
273
|
+
# This method centralises all of the places we can pass in a previous param
|
274
|
+
# and extracts an int ID, or nil
|
275
|
+
def detect_previous_id
|
276
|
+
return unless params[:previous]
|
277
|
+
return if params[:previous].start_with?("crm")
|
278
|
+
|
279
|
+
params[:previous].to_i
|
280
|
+
end
|
281
|
+
ActiveSupport.run_load_hooks(:fat_free_crm_application_controller, self)
|
271
282
|
end
|
@@ -45,7 +45,7 @@ class AccountsController < EntitiesController
|
|
45
45
|
# GET /accounts/1/edit AJAX
|
46
46
|
#----------------------------------------------------------------------------
|
47
47
|
def edit
|
48
|
-
@previous = Account.my(current_user).find_by_id(
|
48
|
+
@previous = Account.my(current_user).find_by_id(detect_previous_id) || detect_previous_id if detect_previous_id
|
49
49
|
|
50
50
|
respond_with(@account)
|
51
51
|
end
|
@@ -160,4 +160,6 @@ class AccountsController < EntitiesController
|
|
160
160
|
@account_category_total[:all] = Account.my(current_user).count
|
161
161
|
@account_category_total[:other] = @account_category_total[:all] - categorized
|
162
162
|
end
|
163
|
+
|
164
|
+
ActiveSupport.run_load_hooks(:fat_free_crm_accounts_controller, self)
|
163
165
|
end
|
@@ -84,7 +84,7 @@ class CampaignsController < EntitiesController
|
|
84
84
|
# GET /campaigns/1/edit AJAX
|
85
85
|
#----------------------------------------------------------------------------
|
86
86
|
def edit
|
87
|
-
@previous = Campaign.my(current_user).find_by_id(
|
87
|
+
@previous = Campaign.my(current_user).find_by_id(detect_previous_id) || detect_previous_id if detect_previous_id
|
88
88
|
|
89
89
|
respond_with(@campaign)
|
90
90
|
end
|
@@ -204,4 +204,6 @@ class CampaignsController < EntitiesController
|
|
204
204
|
end
|
205
205
|
@campaign_status_total[:other] += @campaign_status_total[:all]
|
206
206
|
end
|
207
|
+
|
208
|
+
ActiveSupport.run_load_hooks(:fat_free_crm_campaigns_controller, self)
|
207
209
|
end
|
@@ -51,7 +51,7 @@ class ContactsController < EntitiesController
|
|
51
51
|
#----------------------------------------------------------------------------
|
52
52
|
def edit
|
53
53
|
@account = @contact.account || Account.new(user: current_user)
|
54
|
-
@previous = Contact.my(current_user).find_by_id(
|
54
|
+
@previous = Contact.my(current_user).find_by_id(detect_previous_id) || detect_previous_id if detect_previous_id
|
55
55
|
|
56
56
|
respond_with(@contact)
|
57
57
|
end
|
@@ -164,4 +164,6 @@ class ContactsController < EntitiesController
|
|
164
164
|
redirect_to contacts_path
|
165
165
|
end
|
166
166
|
end
|
167
|
+
|
168
|
+
ActiveSupport.run_load_hooks(:fat_free_crm_contacts_controller, self)
|
167
169
|
end
|
@@ -52,7 +52,7 @@ class LeadsController < EntitiesController
|
|
52
52
|
def edit
|
53
53
|
get_campaigns
|
54
54
|
|
55
|
-
@previous = Lead.my(current_user).find_by_id(
|
55
|
+
@previous = Lead.my(current_user).find_by_id(detect_previous_id) || detect_previous_id if detect_previous_id
|
56
56
|
|
57
57
|
respond_with(@lead)
|
58
58
|
end
|
@@ -108,7 +108,7 @@ class LeadsController < EntitiesController
|
|
108
108
|
@accounts = Account.my(current_user).order('name')
|
109
109
|
@opportunity = Opportunity.new(user: current_user, access: "Lead", stage: "prospecting", campaign: @lead.campaign, source: @lead.source)
|
110
110
|
|
111
|
-
@previous = Lead.my(current_user).find_by_id(
|
111
|
+
@previous = Lead.my(current_user).find_by_id(detect_previous_id) || detect_previous_id if detect_previous_id
|
112
112
|
|
113
113
|
respond_with(@lead)
|
114
114
|
end
|
@@ -268,4 +268,6 @@ class LeadsController < EntitiesController
|
|
268
268
|
get_data_for_sidebar(:campaign)
|
269
269
|
end
|
270
270
|
end
|
271
|
+
|
272
|
+
ActiveSupport.run_load_hooks(:fat_free_crm_leads_controller, self)
|
271
273
|
end
|
@@ -57,7 +57,7 @@ class OpportunitiesController < EntitiesController
|
|
57
57
|
@account = @opportunity.account || Account.new(user: current_user)
|
58
58
|
@accounts = Account.my(current_user).order('name')
|
59
59
|
|
60
|
-
@previous = Opportunity.my(current_user).find_by_id(
|
60
|
+
@previous = Opportunity.my(current_user).find_by_id(detect_previous_id) || detect_previous_id if detect_previous_id
|
61
61
|
|
62
62
|
respond_with(@opportunity)
|
63
63
|
end
|
@@ -227,4 +227,6 @@ class OpportunitiesController < EntitiesController
|
|
227
227
|
current_user.pref[:opportunities_sort_by] = Opportunity.sort_by_map[params[:sort_by]] if params[:sort_by]
|
228
228
|
session[:opportunities_filter] = params[:stage] if params[:stage]
|
229
229
|
end
|
230
|
+
|
231
|
+
ActiveSupport.run_load_hooks(:fat_free_crm_opportunities_controller, self)
|
230
232
|
end
|
@@ -83,7 +83,7 @@ class EntitiesController < ApplicationController
|
|
83
83
|
#----------------------------------------------------------------------------
|
84
84
|
def field_group
|
85
85
|
if @tag = Tag.find_by_name(params[:tag].strip)
|
86
|
-
if @
|
86
|
+
if @field_groups = FieldGroup.where(tag_id: @tag.id, klass_name: klass.to_s).order(:label, :created_at)
|
87
87
|
@asset = klass.find_by_id(params[:asset_id]) || klass.new
|
88
88
|
render('fields/group') && return
|
89
89
|
end
|
@@ -245,4 +245,6 @@ class EntitiesController < ApplicationController
|
|
245
245
|
Account.new(user: user)
|
246
246
|
end
|
247
247
|
end
|
248
|
+
|
249
|
+
ActiveSupport.run_load_hooks(:fat_free_crm_entities_controller, self)
|
248
250
|
end
|
@@ -165,4 +165,6 @@ class HomeController < ApplicationController
|
|
165
165
|
%w[zero one two].index(words.first).send(words.last) if %w[one two].include?(words.first) && %w[hour day days week weeks month].include?(words.last)
|
166
166
|
end
|
167
167
|
end
|
168
|
+
|
169
|
+
ActiveSupport.run_load_hooks(:fat_free_crm_home_controller, self)
|
168
170
|
end
|
@@ -9,13 +9,14 @@ class ListsController < ApplicationController
|
|
9
9
|
# POST /lists
|
10
10
|
#----------------------------------------------------------------------------
|
11
11
|
def create
|
12
|
-
|
12
|
+
list_attr = list_params.to_h
|
13
|
+
list_attr["user_id"] = current_user.id if params["is_global"] != "1"
|
13
14
|
|
14
15
|
# Find any existing list with the same name (case insensitive)
|
15
|
-
if @list = List.where("lower(name) = ?",
|
16
|
-
@list.update(
|
16
|
+
if @list = List.where("lower(name) = ?", list_attr[:name].downcase).where(user_id: list_attr[:user_id]).first
|
17
|
+
@list.update(list_attr)
|
17
18
|
else
|
18
|
-
@list = List.create(
|
19
|
+
@list = List.create(list_attr)
|
19
20
|
end
|
20
21
|
|
21
22
|
respond_with(@list)
|
@@ -39,4 +40,6 @@ class ListsController < ApplicationController
|
|
39
40
|
:user_id
|
40
41
|
)
|
41
42
|
end
|
43
|
+
|
44
|
+
ActiveSupport.run_load_hooks(:fat_free_crm_lists_controller, self)
|
42
45
|
end
|
@@ -58,7 +58,7 @@ class TasksController < ApplicationController
|
|
58
58
|
@category = Setting.unroll(:task_category)
|
59
59
|
@asset = @task.asset if @task.asset_id?
|
60
60
|
|
61
|
-
@previous = Task.tracked_by(current_user).find_by_id(
|
61
|
+
@previous = Task.tracked_by(current_user).find_by_id(detect_previous_id) || detect_previous_id if detect_previous_id
|
62
62
|
|
63
63
|
respond_with(@task)
|
64
64
|
end
|
@@ -224,4 +224,6 @@ class TasksController < ApplicationController
|
|
224
224
|
views = Task::ALLOWED_VIEWS
|
225
225
|
views.include?(view) ? view : views.first
|
226
226
|
end
|
227
|
+
|
228
|
+
ActiveSupport.run_load_hooks(:fat_free_crm_tasks_controller, self)
|
227
229
|
end
|
@@ -36,7 +36,7 @@ module ApplicationHelper
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def subtitle_link(id, text, hidden)
|
39
|
-
link_to("<small>#{hidden ? '&#
|
39
|
+
link_to("<small>#{hidden ? '▷' : '▽'}</small> #{sanitize text}".html_safe,
|
40
40
|
url_for(controller: :home, action: :toggle, id: id),
|
41
41
|
remote: true,
|
42
42
|
onclick: "crm.flip_subtitle(this)")
|
@@ -99,7 +99,7 @@ module ApplicationHelper
|
|
99
99
|
|
100
100
|
#----------------------------------------------------------------------------
|
101
101
|
def arrow_for(id)
|
102
|
-
content_tag(:span, "&#
|
102
|
+
content_tag(:span, "▷".html_safe, id: "#{id}_arrow", class: :arrow)
|
103
103
|
end
|
104
104
|
|
105
105
|
#----------------------------------------------------------------------------
|
@@ -115,13 +115,13 @@ module ApplicationHelper
|
|
115
115
|
|
116
116
|
#----------------------------------------------------------------------------
|
117
117
|
def link_to_delete(record, options = {})
|
118
|
-
confirm = options[:confirm] ||
|
118
|
+
confirm = options[:confirm] || t(:confirm_delete, record.class.to_s.downcase)
|
119
119
|
|
120
120
|
link_to(t(:delete) + "!",
|
121
121
|
options[:url] || url_for(record),
|
122
122
|
method: :delete,
|
123
123
|
remote: true,
|
124
|
-
confirm: confirm)
|
124
|
+
data: { confirm: confirm })
|
125
125
|
end
|
126
126
|
|
127
127
|
#----------------------------------------------------------------------------
|
@@ -41,8 +41,10 @@ module OpportunitiesHelper
|
|
41
41
|
selected_campaign = Campaign.find_by_id(options[:selected])
|
42
42
|
campaigns = ([selected_campaign] + Campaign.my(current_user).order(:name).limit(25)).compact.uniq
|
43
43
|
collection_select :opportunity, :campaign_id, campaigns, :id, :name,
|
44
|
-
{ selected: options[:selected], prompt: t(:select_a_campaign) },
|
45
|
-
style: 'width:330px;', class: 'select2'
|
44
|
+
{ selected: options[:selected], prompt: t(:select_a_campaign), include_blank: true },
|
45
|
+
style: 'width:330px;', class: 'select2',
|
46
|
+
placeholder: t(:select_a_campaign),
|
47
|
+
"data-url": auto_complete_campaigns_path(format: 'json')
|
46
48
|
end
|
47
49
|
|
48
50
|
# Generates the inline revenue message for the opportunity list table.
|
data/app/helpers/users_helper.rb
CHANGED
@@ -25,7 +25,7 @@ module UsersHelper
|
|
25
25
|
user_options = user_options_for_select(users, myself)
|
26
26
|
select(asset, :assigned_to, user_options,
|
27
27
|
{ include_blank: t(:unassigned) },
|
28
|
-
style: 'width: 160px;',
|
28
|
+
style: 'width: 160px;', "data-allow-clear" => false,
|
29
29
|
class: 'select2')
|
30
30
|
end
|
31
31
|
|
@@ -35,8 +35,8 @@ class Campaign < ActiveRecord::Base
|
|
35
35
|
belongs_to :user, optional: true # TODO: Is this really optional?
|
36
36
|
belongs_to :assignee, class_name: "User", foreign_key: :assigned_to, optional: true # TODO: Is this really optional?
|
37
37
|
has_many :tasks, as: :asset, dependent: :destroy # , :order => 'created_at DESC'
|
38
|
-
has_many :leads, -> { order "id DESC" }
|
39
|
-
has_many :opportunities, -> { order "id DESC" }
|
38
|
+
has_many :leads, -> { order "id DESC" }
|
39
|
+
has_many :opportunities, -> { order "id DESC" }
|
40
40
|
has_many :emails, as: :mediator
|
41
41
|
|
42
42
|
serialize :subscribed_users, Array
|
@@ -124,7 +124,7 @@ class CustomField < Field
|
|
124
124
|
#------------------------------------------------------------------------------
|
125
125
|
def add_column
|
126
126
|
self.name = generate_column_name if name.blank?
|
127
|
-
klass.connection.add_column(table_name, name, column_type, column_options)
|
127
|
+
klass.connection.add_column(table_name, name, column_type, **column_options)
|
128
128
|
klass.reset_column_information
|
129
129
|
klass.serialize_custom_fields!
|
130
130
|
end
|
@@ -142,7 +142,7 @@ class CustomField < Field
|
|
142
142
|
#------------------------------------------------------------------------------
|
143
143
|
def update_column
|
144
144
|
if errors.empty? && db_transition_safety(as_was) == :safe
|
145
|
-
klass.connection.change_column(table_name, name, column_type, column_options)
|
145
|
+
klass.connection.change_column(table_name, name, column_type, **column_options)
|
146
146
|
klass.reset_column_information
|
147
147
|
klass.serialize_custom_fields!
|
148
148
|
end
|
@@ -12,10 +12,9 @@ class CustomFieldPair < CustomField
|
|
12
12
|
#------------------------------------------------------------------------------
|
13
13
|
def self.create_pair(params)
|
14
14
|
fields = params['field']
|
15
|
-
|
16
|
-
pair = params.delete('pair')
|
15
|
+
pair = params['pair']
|
17
16
|
base_params = fields.delete_if { |k, _v| !%w[field_group_id label as].include?(k) }
|
18
|
-
klass =
|
17
|
+
klass = Field.lookup_class(fields['as']).safe_constantize
|
19
18
|
field1 = klass.create(base_params.merge(pair['0']))
|
20
19
|
field2 = klass.create(base_params.merge(pair['1']).merge('pair_id' => field1.id, 'required' => field1.required, 'disabled' => field1.disabled))
|
21
20
|
[field1, field2]
|
@@ -25,19 +24,19 @@ class CustomFieldPair < CustomField
|
|
25
24
|
#------------------------------------------------------------------------------
|
26
25
|
def self.update_pair(params)
|
27
26
|
fields = params['field']
|
28
|
-
pair = params
|
27
|
+
pair = params['pair']
|
29
28
|
base_params = fields.delete_if { |k, _v| !%w[field_group_id label as].include?(k) }
|
30
|
-
field1 = CustomFieldPair.find(
|
29
|
+
field1 = CustomFieldPair.find(pair['0']['id'])
|
31
30
|
field1.update(base_params.merge(pair['0']))
|
32
31
|
field2 = field1.paired_with
|
33
32
|
field2.update(base_params.merge(pair['1']).merge('required' => field1.required, 'disabled' => field1.disabled))
|
34
33
|
[field1, field2]
|
35
34
|
end
|
36
35
|
|
37
|
-
# Returns the field that this field is paired with
|
36
|
+
# Returns the field that this field is paired with (bi-directional)
|
38
37
|
#------------------------------------------------------------------------------
|
39
38
|
def paired_with
|
40
|
-
pair ||
|
39
|
+
pair || self.class.find_by_id(pair_id)
|
41
40
|
end
|
42
41
|
|
43
42
|
ActiveSupport.run_load_hooks(:fat_free_crm_custom_field_pair, self)
|
data/app/models/fields/field.rb
CHANGED
@@ -34,7 +34,7 @@ class Field < ActiveRecord::Base
|
|
34
34
|
serialize :collection, Array
|
35
35
|
serialize :settings, HashWithIndifferentAccess
|
36
36
|
|
37
|
-
belongs_to :field_group, optional: true
|
37
|
+
belongs_to :field_group, optional: true
|
38
38
|
|
39
39
|
scope :core_fields, -> { where(type: 'CoreField') }
|
40
40
|
scope :custom_fields, -> { where("type != 'CoreField'") }
|
@@ -92,8 +92,6 @@ class Field < ActiveRecord::Base
|
|
92
92
|
|
93
93
|
def render(value)
|
94
94
|
case as
|
95
|
-
when 'checkbox'
|
96
|
-
value.to_s == '0' ? "no" : "yes"
|
97
95
|
when 'date'
|
98
96
|
value&.strftime(I18n.t("date.formats.mmddyy"))
|
99
97
|
when 'datetime'
|