redmine_crm 0.0.43 → 0.0.63
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.
- checksums.yaml +5 -5
- data/Gemfile +1 -1
- data/app/controllers/redmine_crm_controller.rb +26 -0
- data/app/views/redmine_crm/_money.html.erb +44 -0
- data/app/views/redmine_crm/settings.html.erb +10 -0
- data/bitbucket-pipelines.yml +1 -8
- data/config/currency_iso.json +1 -1
- data/config/locales/cs.yml +13 -0
- data/config/locales/de.yml +13 -0
- data/config/locales/en.yml +13 -0
- data/config/locales/es.yml +13 -0
- data/config/locales/ru.yml +13 -0
- data/config/routes.rb +5 -0
- data/doc/CHANGELOG +92 -1
- data/lib/redmine_crm/acts_as_draftable/draft.rb +1 -1
- data/lib/redmine_crm/acts_as_draftable/rcrm_acts_as_draftable.rb +4 -2
- data/lib/redmine_crm/acts_as_priceable/rcrm_acts_as_priceable.rb +33 -0
- data/lib/redmine_crm/acts_as_taggable/rcrm_acts_as_taggable.rb +10 -3
- data/lib/redmine_crm/acts_as_taggable/tag_list.rb +1 -1
- data/lib/redmine_crm/acts_as_viewed/rcrm_acts_as_viewed.rb +1 -1
- data/lib/redmine_crm/acts_as_votable/rcrm_acts_as_votable.rb +1 -1
- data/lib/redmine_crm/acts_as_votable/votable.rb +2 -2
- data/lib/redmine_crm/compatibility/routing_mapper_patch.rb +27 -0
- data/lib/redmine_crm/currency/formatting.rb +5 -5
- data/lib/redmine_crm/currency.rb +28 -17
- data/lib/redmine_crm/engine.rb +4 -0
- data/lib/redmine_crm/helpers/calendars_helper.rb +22 -0
- data/lib/redmine_crm/helpers/external_assets_helper.rb +1 -0
- data/lib/redmine_crm/helpers/form_tag_helper.rb +12 -0
- data/lib/redmine_crm/hooks/views_layouts_hook.rb +12 -0
- data/lib/redmine_crm/liquid/drops/attachment_drop.rb +47 -0
- data/lib/redmine_crm/liquid/drops/issue_relations_drop.rb +41 -0
- data/lib/redmine_crm/liquid/drops/issues_drop.rb +54 -28
- data/lib/redmine_crm/liquid/drops/time_entries_drop.rb +1 -1
- data/lib/redmine_crm/liquid/filters/arrays.rb +1 -1
- data/lib/redmine_crm/liquid/filters/base.rb +36 -4
- data/lib/redmine_crm/money_helper.rb +15 -14
- data/lib/redmine_crm/patches/liquid_patch.rb +33 -0
- data/lib/redmine_crm/settings/money.rb +46 -0
- data/lib/redmine_crm/settings.rb +53 -0
- data/lib/redmine_crm/version.rb +1 -1
- data/lib/redmine_crm.rb +15 -2
- data/redmine_crm.gemspec +4 -2
- data/test/acts_as_draftable/rcrm_acts_as_draftable_test.rb +0 -1
- data/test/acts_as_taggable/rcrm_acts_as_taggable_test.rb +97 -92
- data/test/fixtures/attachments.yml +14 -0
- data/test/liquid/drops/attachment_drop_test.rb +15 -0
- data/test/liquid/drops/issue_relations_drop_test.rb +24 -0
- data/test/liquid/drops/issues_drop_test.rb +4 -0
- data/test/liquid/filters/base_filter_test.rb +5 -1
- data/test/models/attachment.rb +3 -0
- data/test/models/issue.rb +7 -0
- data/test/models/issue_relation.rb +10 -0
- data/test/money_helper_test.rb +1 -1
- data/test/schema.rb +22 -1
- data/test/tags_helper_test.rb +4 -4
- data/vendor/assets/images/money.png +0 -0
- data/vendor/assets/javascripts/select2.js +2 -3
- data/vendor/assets/javascripts/select2_helpers.js +8 -2
- data/vendor/assets/javascripts/timepicker_addon.js +5 -0
- data/vendor/assets/stylesheets/calendars.css +15 -0
- data/vendor/assets/stylesheets/money.css +3 -0
- data/vendor/assets/stylesheets/select2.css +28 -18
- data/vendor/assets/stylesheets/timepicker_addon.css +5 -0
- metadata +57 -10
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RedmineCrm
|
4
|
+
module Hooks
|
5
|
+
class ViewsLayoutsHook < Redmine::Hook::ViewListener
|
6
|
+
def view_layouts_base_html_head(_context = {})
|
7
|
+
stylesheet_link_tag(:calendars, plugin: 'redmine_crm') +
|
8
|
+
stylesheet_link_tag(:money, plugin: 'redmine_crm')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module RedmineCrm
|
2
|
+
module Liquid
|
3
|
+
class AttachmentDrop < ::Liquid::Drop
|
4
|
+
delegate :id,
|
5
|
+
:filename,
|
6
|
+
:title,
|
7
|
+
:description,
|
8
|
+
:filesize,
|
9
|
+
:content_type,
|
10
|
+
:digest,
|
11
|
+
:downloads,
|
12
|
+
:created_on,
|
13
|
+
:token,
|
14
|
+
:visible?,
|
15
|
+
:image?,
|
16
|
+
:thumbnailable?,
|
17
|
+
:is_text?,
|
18
|
+
:readable?,
|
19
|
+
to: :@attachment
|
20
|
+
|
21
|
+
def initialize(attachment)
|
22
|
+
@attachment = attachment
|
23
|
+
end
|
24
|
+
|
25
|
+
def url(options = {})
|
26
|
+
Rails.application.routes.url_helpers.download_named_attachment_url(@attachment, { filename: filename,
|
27
|
+
host: Setting.host_name,
|
28
|
+
protocol: Setting.protocol }.merge(options))
|
29
|
+
end
|
30
|
+
|
31
|
+
def link
|
32
|
+
link_to((@attachment.description.blank? ? @attachment.filename : @attachment.description), url)
|
33
|
+
end
|
34
|
+
|
35
|
+
def author
|
36
|
+
@author ||= UserDrop.new @attachment.author
|
37
|
+
end
|
38
|
+
|
39
|
+
def read
|
40
|
+
@content ||= if @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte
|
41
|
+
File.new(@attachment.diskfile, "rb").read
|
42
|
+
end
|
43
|
+
@content
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module RedmineCrm
|
2
|
+
module Liquid
|
3
|
+
class IssueRelationsDrop < ::Liquid::Drop
|
4
|
+
def initialize(relations)
|
5
|
+
@relations = relations
|
6
|
+
end
|
7
|
+
|
8
|
+
def all
|
9
|
+
@all ||= @relations.map { |relation| IssueRelationDrop.new(relation) }
|
10
|
+
end
|
11
|
+
|
12
|
+
def visible
|
13
|
+
@visible ||= @all.select(&:visible?)
|
14
|
+
end
|
15
|
+
|
16
|
+
def each(&block)
|
17
|
+
all.each(&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def size
|
21
|
+
@relations.size
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class IssueRelationDrop < ::Liquid::Drop
|
26
|
+
delegate :relation_type, :delay, to: :@relation
|
27
|
+
|
28
|
+
def initialize(relation)
|
29
|
+
@relation = relation
|
30
|
+
end
|
31
|
+
|
32
|
+
def issue_from
|
33
|
+
@issue_from ||= IssueDrop.new(@relation.issue_from)
|
34
|
+
end
|
35
|
+
|
36
|
+
def issue_to
|
37
|
+
@issue_to ||= IssueDrop.new(@relation.issue_to)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -6,14 +6,15 @@ module RedmineCrm
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def before_method(id)
|
9
|
-
issue = @issues.where(:
|
9
|
+
issue = @issues.where(id: id).first || Issue.new
|
10
10
|
IssueDrop.new issue
|
11
11
|
end
|
12
12
|
|
13
13
|
def all
|
14
|
-
@all ||=
|
15
|
-
|
16
|
-
|
14
|
+
@all ||=
|
15
|
+
@issues.map do |issue|
|
16
|
+
IssueDrop.new issue
|
17
|
+
end
|
17
18
|
end
|
18
19
|
|
19
20
|
def visible
|
@@ -34,9 +35,8 @@ module RedmineCrm
|
|
34
35
|
|
35
36
|
delegate :id,
|
36
37
|
:subject,
|
37
|
-
:description,
|
38
38
|
:visible?,
|
39
|
-
:
|
39
|
+
:closed?,
|
40
40
|
:start_date,
|
41
41
|
:due_date,
|
42
42
|
:overdue?,
|
@@ -49,14 +49,14 @@ module RedmineCrm
|
|
49
49
|
:closed_on,
|
50
50
|
:updated_on,
|
51
51
|
:created_on,
|
52
|
-
:
|
52
|
+
to: :@issue
|
53
53
|
|
54
54
|
def initialize(issue)
|
55
55
|
@issue = issue
|
56
56
|
end
|
57
57
|
|
58
58
|
def link
|
59
|
-
link_to @issue.subject,
|
59
|
+
link_to @issue.subject, url
|
60
60
|
end
|
61
61
|
|
62
62
|
def url
|
@@ -96,23 +96,35 @@ module RedmineCrm
|
|
96
96
|
end
|
97
97
|
|
98
98
|
def parent
|
99
|
-
@parent ||= IssueDrop.new @issue.parent if @issue.parent
|
99
|
+
@parent ||= IssueDrop.new @issue.parent if @issue.parent
|
100
100
|
end
|
101
101
|
|
102
102
|
def project
|
103
|
-
@project ||= ProjectDrop.new @issue.project if @issue.project
|
103
|
+
@project ||= ProjectDrop.new @issue.project if @issue.project
|
104
|
+
end
|
105
|
+
|
106
|
+
def description
|
107
|
+
@description ||= replace_images_urls(@issue.description)
|
104
108
|
end
|
105
109
|
|
106
110
|
def subtasks
|
107
|
-
@subtasks ||= IssuesDrop.new @issue.children
|
111
|
+
@subtasks ||= IssuesDrop.new @issue.children
|
112
|
+
end
|
113
|
+
|
114
|
+
def relations_from
|
115
|
+
@relations_from ||= IssueRelationsDrop.new(@issue.relations_from.select { |r| r.other_issue(@issue) && r.other_issue(@issue).visible? })
|
116
|
+
end
|
117
|
+
|
118
|
+
def relations_to
|
119
|
+
@relations_to ||= IssueRelationsDrop.new(@issue.relations_to.select { |r| r.other_issue(@issue) && r.other_issue(@issue).visible? })
|
108
120
|
end
|
109
121
|
|
110
122
|
def notes
|
111
|
-
@notes ||= @issue.journals.where(
|
123
|
+
@notes ||= @issue.journals.where.not(notes: [nil, '']).order(:created_on).map(&:notes).map { |note| replace_images_urls(note) }
|
112
124
|
end
|
113
125
|
|
114
126
|
def journals
|
115
|
-
@journals ||= JournalsDrop.new
|
127
|
+
@journals ||= JournalsDrop.new(@issue.journals.where.not(notes: nil).find_each { |journal| journal.notes = replace_images_urls(journal.notes) })
|
116
128
|
end
|
117
129
|
|
118
130
|
def tags
|
@@ -126,19 +138,39 @@ module RedmineCrm
|
|
126
138
|
def color
|
127
139
|
@issue.respond_to?(:color) && @issue.color
|
128
140
|
end
|
129
|
-
|
141
|
+
|
130
142
|
def day_in_state
|
131
143
|
@issue.respond_to?(:day_in_state) && @issue.day_in_state
|
132
144
|
end
|
133
145
|
|
134
146
|
def checklists
|
135
|
-
@issue.respond_to?(:checklists) && @issue.checklists.map
|
147
|
+
@issue.respond_to?(:checklists) && @issue.checklists.map do |item|
|
148
|
+
{ 'id_done' => item.is_done, 'subject' => item.subject, 'is_section' => item.is_section }
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def helpdesk_ticket
|
153
|
+
return nil unless defined?(::HelpdeskTicketDrop)
|
154
|
+
|
155
|
+
@helpdesk_ticket ||= HelpdeskTicketDrop.new(@issue)
|
136
156
|
end
|
137
157
|
|
138
158
|
def custom_field_values
|
139
159
|
@issue.custom_field_values
|
140
|
-
end
|
160
|
+
end
|
161
|
+
|
162
|
+
private
|
141
163
|
|
164
|
+
def replace_images_urls(text)
|
165
|
+
text.gsub(/\!.*\!/) do |i_name|
|
166
|
+
i_name = i_name.delete('!')
|
167
|
+
i_name_css = i_name.scan(/^\{.*\}/).first.to_s
|
168
|
+
attachment = @issue.attachments.find_by(filename: i_name.gsub(i_name_css, ''))
|
169
|
+
image = AttachmentDrop.new attachment if attachment
|
170
|
+
attach_url = image.try(:url)
|
171
|
+
attach_url ? "!#{i_name_css}#{attach_url}!" : i_name
|
172
|
+
end
|
173
|
+
end
|
142
174
|
end
|
143
175
|
|
144
176
|
class JournalsDrop < ::Liquid::Drop
|
@@ -147,9 +179,10 @@ module RedmineCrm
|
|
147
179
|
end
|
148
180
|
|
149
181
|
def all
|
150
|
-
@all ||=
|
151
|
-
|
152
|
-
|
182
|
+
@all ||=
|
183
|
+
@journals.map do |journal|
|
184
|
+
JournalDrop.new journal
|
185
|
+
end
|
153
186
|
end
|
154
187
|
|
155
188
|
def visible
|
@@ -166,12 +199,7 @@ module RedmineCrm
|
|
166
199
|
end
|
167
200
|
|
168
201
|
class JournalDrop < ::Liquid::Drop
|
169
|
-
delegate :id,
|
170
|
-
:notes,
|
171
|
-
:created_on,
|
172
|
-
:private_notes,
|
173
|
-
:to => :@journal,
|
174
|
-
allow_nil: true
|
202
|
+
delegate :id, :notes, :created_on, :private_notes, to: :@journal, allow_nil: true
|
175
203
|
|
176
204
|
def initialize(journal)
|
177
205
|
@journal = journal
|
@@ -182,10 +210,8 @@ module RedmineCrm
|
|
182
210
|
end
|
183
211
|
|
184
212
|
def issue
|
185
|
-
@issue ||= IssueDrop.new @journal.issue if @journal.issue
|
213
|
+
@issue ||= IssueDrop.new @journal.issue if @journal.issue
|
186
214
|
end
|
187
|
-
|
188
215
|
end
|
189
|
-
|
190
216
|
end
|
191
217
|
end
|
@@ -100,7 +100,7 @@ module RedmineCrm
|
|
100
100
|
def tagged_with(input, tags, match='all')
|
101
101
|
return input unless input.respond_to?(:select)
|
102
102
|
input = input.values if input.is_a?(Hash)
|
103
|
-
tag_list =
|
103
|
+
tag_list = tags.is_a?(Array) ? tags.sort : tags.split(',').map(&:strip).sort
|
104
104
|
case match
|
105
105
|
when "all"
|
106
106
|
input.select do |object|
|
@@ -36,7 +36,7 @@ module RedmineCrm
|
|
36
36
|
|
37
37
|
def md5(input)
|
38
38
|
Digest::MD5.hexdigest(input) unless input.blank?
|
39
|
-
end
|
39
|
+
end
|
40
40
|
|
41
41
|
# example:
|
42
42
|
# {{ "http:://www.example.com?key=hello world" | encode }}
|
@@ -87,8 +87,8 @@ module RedmineCrm
|
|
87
87
|
to_number(input).floor.to_i
|
88
88
|
end
|
89
89
|
|
90
|
-
def currency(input, currency_code =
|
91
|
-
price_to_currency(input, currency_code, :converted => false)
|
90
|
+
def currency(input, currency_code = nil)
|
91
|
+
price_to_currency(input, currency_code || container_currency, :converted => false)
|
92
92
|
end
|
93
93
|
|
94
94
|
def call_method(input, method_name)
|
@@ -100,7 +100,7 @@ module RedmineCrm
|
|
100
100
|
def custom_field(input, field_name)
|
101
101
|
if input.respond_to?(:custom_field_values)
|
102
102
|
custom_value = input.custom_field_values.detect { |cfv| cfv.custom_field.name == field_name }
|
103
|
-
custom_value.custom_field.format.formatted_custom_value(nil, custom_value)
|
103
|
+
custom_value.custom_field.format.formatted_custom_value(nil, custom_value) if custom_value
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
@@ -121,6 +121,30 @@ module RedmineCrm
|
|
121
121
|
end
|
122
122
|
end
|
123
123
|
|
124
|
+
def multi_line(input)
|
125
|
+
input.to_s.gsub("\n", '<br/>').html_safe
|
126
|
+
end
|
127
|
+
|
128
|
+
def concat(input, *args)
|
129
|
+
result = input.to_s
|
130
|
+
args.flatten.each { |a| result << a.to_s }
|
131
|
+
result
|
132
|
+
end
|
133
|
+
|
134
|
+
# right justify and padd a string
|
135
|
+
def rjust(input, integer, padstr = '')
|
136
|
+
input.to_s.rjust(integer, padstr)
|
137
|
+
end
|
138
|
+
|
139
|
+
# left justify and padd a string
|
140
|
+
def ljust(input, integer, padstr = '')
|
141
|
+
input.to_s.ljust(integer, padstr)
|
142
|
+
end
|
143
|
+
|
144
|
+
def textile(input)
|
145
|
+
::RedCloth3.new(input).to_html
|
146
|
+
end
|
147
|
+
|
124
148
|
protected
|
125
149
|
|
126
150
|
# Convert an array of properties ('key:value') into a hash
|
@@ -210,6 +234,14 @@ module RedmineCrm
|
|
210
234
|
end
|
211
235
|
end
|
212
236
|
end
|
237
|
+
|
238
|
+
def container
|
239
|
+
@container ||= @context.registers[:container]
|
240
|
+
end
|
241
|
+
|
242
|
+
def container_currency
|
243
|
+
container.currency if container.respond_to?(:currency)
|
244
|
+
end
|
213
245
|
end
|
214
246
|
::Liquid::Template.register_filter(RedmineCrm::Liquid::Filters::Base)
|
215
247
|
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
require 'action_view'
|
2
|
+
require 'redmine_crm/settings/money'
|
2
3
|
|
3
4
|
module RedmineCrm
|
4
5
|
module MoneyHelper
|
5
|
-
|
6
6
|
def object_price(obj, price_field = :price, options = {})
|
7
7
|
options.merge!({:symbol => true})
|
8
8
|
price_to_currency(obj.try(price_field), obj.currency, options).to_s if obj.respond_to?(:currency)
|
9
9
|
end
|
10
10
|
|
11
|
-
def prices_collection_by_currency(prices_collection, options={})
|
11
|
+
def prices_collection_by_currency(prices_collection, options = {})
|
12
12
|
return [] if prices_collection.blank? || prices_collection == 0
|
13
13
|
prices = prices_collection
|
14
14
|
prices.reject!{|k, v| v.to_i == 0} if options[:hide_zeros]
|
@@ -18,17 +18,17 @@ module RedmineCrm
|
|
18
18
|
def deal_currency_icon(currency)
|
19
19
|
case currency.to_s.upcase
|
20
20
|
when 'EUR'
|
21
|
-
|
21
|
+
'icon-money-euro'
|
22
22
|
when 'GBP'
|
23
|
-
|
23
|
+
'icon-money-pound'
|
24
24
|
when 'JPY'
|
25
|
-
|
25
|
+
'icon-money-yen'
|
26
26
|
else
|
27
|
-
|
27
|
+
'icon-money-dollar'
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
def collection_for_currencies_select(default_currency =
|
31
|
+
def collection_for_currencies_select(default_currency = RedmineCrm::Settings::Money.default_currency, major_currencies = RedmineCrm::Settings::Money.major_currencies)
|
32
32
|
currencies = []
|
33
33
|
currencies << default_currency.to_s unless default_currency.blank?
|
34
34
|
currencies |= major_currencies
|
@@ -46,17 +46,18 @@ module RedmineCrm
|
|
46
46
|
end.sort{|x, y| x[0] <=> y[0]}
|
47
47
|
end
|
48
48
|
|
49
|
-
def price_to_currency(price, currency=
|
49
|
+
def price_to_currency(price, currency = RedmineCrm::Settings::Money.default_currency, options = {})
|
50
50
|
return '' if price.blank?
|
51
51
|
|
52
|
-
currency =
|
53
|
-
|
52
|
+
currency = 'USD' unless currency.is_a?(String)
|
53
|
+
default_options = {
|
54
|
+
decimal_mark: RedmineCrm::Settings::Money.decimal_separator,
|
55
|
+
thousands_separator: RedmineCrm::Settings::Money.thousands_delimiter
|
56
|
+
}.reject { |_k, v| v.nil? }
|
54
57
|
|
55
|
-
|
56
|
-
price.
|
58
|
+
currency = RedmineCrm::Currency.find(currency)
|
59
|
+
RedmineCrm::Currency.format(price.to_f, currency, default_options.merge(options))
|
57
60
|
end
|
58
|
-
|
59
|
-
|
60
61
|
end
|
61
62
|
end
|
62
63
|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module RedmineCrm
|
2
|
+
module Patches
|
3
|
+
module LiquidPatch
|
4
|
+
module StandardFilters
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.class_eval do
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def to_number(obj)
|
12
|
+
case obj
|
13
|
+
when Float
|
14
|
+
BigDecimal(obj.to_s)
|
15
|
+
when Numeric
|
16
|
+
obj
|
17
|
+
when String
|
18
|
+
(obj.strip =~ /^\d+\.\d+$/) ? BigDecimal(obj) : obj.to_i
|
19
|
+
else
|
20
|
+
0
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
unless Liquid::StandardFilters.included_modules.include?(RedmineCrm::Patches::LiquidPatch::StandardFilters)
|
32
|
+
Liquid::StandardFilters.send(:include, RedmineCrm::Patches::LiquidPatch::StandardFilters)
|
33
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'redmine_crm/settings'
|
2
|
+
|
3
|
+
module RedmineCrm
|
4
|
+
class Settings
|
5
|
+
class Money
|
6
|
+
TAX_TYPE_EXCLUSIVE = 1
|
7
|
+
TAX_TYPE_INCLUSIVE = 2
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def default_currency
|
11
|
+
RedmineCrm::Settings['default_currency'] || 'USD'
|
12
|
+
end
|
13
|
+
|
14
|
+
def major_currencies
|
15
|
+
currencies = RedmineCrm::Settings['major_currencies'].to_s.split(',').select { |c| !c.blank? }.map(&:strip)
|
16
|
+
currencies = %w[USD EUR GBP RUB CHF] if currencies.blank?
|
17
|
+
currencies.compact.uniq
|
18
|
+
end
|
19
|
+
|
20
|
+
def default_tax
|
21
|
+
RedmineCrm::Settings['default_tax'].to_f
|
22
|
+
end
|
23
|
+
|
24
|
+
def tax_type
|
25
|
+
((['1', '2'] & [RedmineCrm::Settings['tax_type'].to_s]).first || TAX_TYPE_EXCLUSIVE).to_i
|
26
|
+
end
|
27
|
+
|
28
|
+
def tax_exclusive?
|
29
|
+
tax_type == TAX_TYPE_EXCLUSIVE
|
30
|
+
end
|
31
|
+
|
32
|
+
def thousands_delimiter
|
33
|
+
([' ', ',', '.'] & [RedmineCrm::Settings['thousands_delimiter']]).first
|
34
|
+
end
|
35
|
+
|
36
|
+
def decimal_separator
|
37
|
+
([',', '.'] & [RedmineCrm::Settings['decimal_separator']]).first
|
38
|
+
end
|
39
|
+
|
40
|
+
def disable_taxes?
|
41
|
+
RedmineCrm::Settings['disable_taxes'].to_i > 0
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module RedmineCrm
|
2
|
+
class Settings
|
3
|
+
SECTIONS = {
|
4
|
+
'money' => { id: :money, label: :label_redmine_crm_money, partial: 'money' }
|
5
|
+
}.freeze
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def initialize_gem_settings
|
9
|
+
return if !Object.const_defined?('Setting') || Setting.respond_to?(:plugin_redmine_crm)
|
10
|
+
|
11
|
+
if Setting.respond_to?(:define_setting)
|
12
|
+
Setting.send(:define_setting, 'plugin_redmine_crm', 'default' => default_settings, 'serialized' => true)
|
13
|
+
elsif Setting.respond_to?(:available_settings)
|
14
|
+
Setting.available_settings['plugin_redmine_crm'] = { 'default' => default_settings, 'serialized' => true }
|
15
|
+
Setting.class.send(:define_method, 'plugin_redmine_crm', -> { Setting['plugin_redmine_crm'] })
|
16
|
+
Setting.class.send(:define_method, 'plugin_redmine_crm=', lambda do |val|
|
17
|
+
setting = find_or_default('plugin_redmine_crm')
|
18
|
+
setting.value = val || ''
|
19
|
+
@cached_settings['plugin_redmine_crm'] = nil
|
20
|
+
setting.save(validate: false)
|
21
|
+
setting.value
|
22
|
+
end)
|
23
|
+
end
|
24
|
+
@settings_initialized
|
25
|
+
end
|
26
|
+
|
27
|
+
# Use apply instead attrs assign because it can rewrite other attributes
|
28
|
+
def apply=(values)
|
29
|
+
initialize_gem_settings unless @settings_initialized
|
30
|
+
|
31
|
+
Setting.plugin_redmine_crm = Setting.plugin_redmine_crm.merge(values)
|
32
|
+
end
|
33
|
+
|
34
|
+
def values
|
35
|
+
initialize_gem_settings unless @settings_initialized
|
36
|
+
Object.const_defined?('Setting') ? Setting.plugin_redmine_crm : {}
|
37
|
+
end
|
38
|
+
|
39
|
+
def [](value)
|
40
|
+
initialize_gem_settings unless @settings_initialized
|
41
|
+
return Setting.plugin_redmine_crm[value] if Object.const_defined?('Setting')
|
42
|
+
|
43
|
+
nil
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def default_settings
|
49
|
+
{}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/redmine_crm/version.rb
CHANGED
data/lib/redmine_crm.rb
CHANGED
@@ -2,6 +2,10 @@ require 'active_record'
|
|
2
2
|
require 'action_view'
|
3
3
|
|
4
4
|
require 'redmine_crm/version'
|
5
|
+
require 'redmine_crm/engine'
|
6
|
+
|
7
|
+
require 'redmine_crm/settings'
|
8
|
+
require 'redmine_crm/settings/money'
|
5
9
|
|
6
10
|
require 'redmine_crm/acts_as_list/list'
|
7
11
|
require 'redmine_crm/acts_as_taggable/tag'
|
@@ -15,6 +19,7 @@ require 'redmine_crm/acts_as_votable/vote'
|
|
15
19
|
require 'redmine_crm/acts_as_votable/voter'
|
16
20
|
require 'redmine_crm/acts_as_draftable/rcrm_acts_as_draftable'
|
17
21
|
require 'redmine_crm/acts_as_draftable/draft'
|
22
|
+
require 'redmine_crm/acts_as_priceable/rcrm_acts_as_priceable'
|
18
23
|
|
19
24
|
require 'redmine_crm/currency'
|
20
25
|
require 'redmine_crm/helpers/tags_helper'
|
@@ -30,12 +35,17 @@ require 'redmine_crm/liquid/drops/news_drop'
|
|
30
35
|
require 'redmine_crm/liquid/drops/projects_drop'
|
31
36
|
require 'redmine_crm/liquid/drops/users_drop'
|
32
37
|
require 'redmine_crm/liquid/drops/time_entries_drop'
|
38
|
+
require 'redmine_crm/liquid/drops/attachment_drop'
|
39
|
+
require 'redmine_crm/liquid/drops/issue_relations_drop'
|
33
40
|
|
41
|
+
require 'redmine_crm/helpers/calendars_helper'
|
34
42
|
require 'redmine_crm/helpers/external_assets_helper'
|
35
43
|
require 'redmine_crm/helpers/form_tag_helper'
|
36
44
|
require 'redmine_crm/assets_manager'
|
37
45
|
|
38
46
|
require 'redmine_crm/compatibility/application_controller_patch'
|
47
|
+
require 'redmine_crm/compatibility/routing_mapper_patch'
|
48
|
+
require 'redmine_crm/patches/liquid_patch' unless BigDecimal.respond_to?(:new)
|
39
49
|
|
40
50
|
module RedmineCrm
|
41
51
|
GEM_NAME = 'redmine_crm'.freeze
|
@@ -50,6 +60,7 @@ end
|
|
50
60
|
RedmineCrm::AssetsManager.install_assets
|
51
61
|
|
52
62
|
if defined?(ActionView::Base)
|
63
|
+
ActionView::Base.send :include, RedmineCrm::CalendarsHelper
|
53
64
|
ActionView::Base.send :include, RedmineCrm::ExternalAssetsHelper
|
54
65
|
ActionView::Base.send :include, RedmineCrm::FormTagHelper
|
55
66
|
end
|
@@ -57,6 +68,7 @@ end
|
|
57
68
|
def requires_redmine_crm(arg)
|
58
69
|
def compare_versions(requirement, current)
|
59
70
|
raise ArgumentError.new('wrong version format') unless check_version_format(requirement)
|
71
|
+
|
60
72
|
requirement = requirement.split('.').collect(&:to_i)
|
61
73
|
requirement <=> current.slice(0, requirement.size)
|
62
74
|
end
|
@@ -65,7 +77,7 @@ def requires_redmine_crm(arg)
|
|
65
77
|
version =~ /^\d+.?\d*.?\d*$/m
|
66
78
|
end
|
67
79
|
|
68
|
-
arg = { :
|
80
|
+
arg = { version_or_higher: arg } unless arg.is_a?(Hash)
|
69
81
|
arg.assert_valid_keys(:version, :version_or_higher)
|
70
82
|
|
71
83
|
current = RedmineCrm::VERSION.split('.').map { |x| x.to_i }
|
@@ -73,6 +85,7 @@ def requires_redmine_crm(arg)
|
|
73
85
|
case k
|
74
86
|
when :version_or_higher
|
75
87
|
raise ArgumentError.new(':version_or_higher accepts a version string only') unless req.is_a?(String)
|
88
|
+
|
76
89
|
unless compare_versions(req, current) <= 0
|
77
90
|
Rails.logger.error "\033[31m[ERROR]\033[0m Redmine requires redmine_crm gem version #{req} or higher (you're using #{RedmineCrm::VERSION}).\n\033[31m[ERROR]\033[0m Please update with 'bundle update redmine_crm'." if Rails.logger
|
78
91
|
abort "\033[31mRedmine requires redmine_crm gem version #{req} or higher (you're using #{RedmineCrm::VERSION}).\nPlease update with 'bundle update redmine_crm'.\033[0m"
|
@@ -80,7 +93,7 @@ def requires_redmine_crm(arg)
|
|
80
93
|
when :version
|
81
94
|
req = [req] if req.is_a?(String)
|
82
95
|
if req.is_a?(Array)
|
83
|
-
unless req.detect {|ver| compare_versions(ver, current) == 0}
|
96
|
+
unless req.detect { |ver| compare_versions(ver, current) == 0 }
|
84
97
|
abort "\033[31mRedmine requires redmine_crm gem version #{req} (you're using #{RedmineCrm::VERSION}).\nPlease update with 'bundle update redmine_crm'.\033[0m"
|
85
98
|
end
|
86
99
|
elsif req.is_a?(Range)
|
data/redmine_crm.gemspec
CHANGED
@@ -10,16 +10,18 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.email = ["support@redminecrm.com"]
|
11
11
|
spec.summary = %q{Common libraries for RedmineUP plugins for Redmine}
|
12
12
|
spec.description = %q{Common libraries for RedmineUP plugins (www.redmineup.com) for Redmine. Requered Redmine from http://redmine.org}
|
13
|
-
spec.homepage = ""
|
14
|
-
spec.license = "
|
13
|
+
spec.homepage = "https://www.redmineup.com"
|
14
|
+
spec.license = "GPL-2.0"
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0")
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
|
+
spec.required_ruby_version = ">= 2.0.0"
|
20
21
|
|
21
22
|
spec.add_runtime_dependency 'rails'
|
22
23
|
spec.add_runtime_dependency 'liquid', '< 2.6.4'
|
24
|
+
spec.add_runtime_dependency 'rubyzip'
|
23
25
|
|
24
26
|
spec.add_development_dependency 'sqlite3'
|
25
27
|
spec.add_development_dependency 'mysql2'
|