##// END OF EJS Templates
Merged r14944 (#21413)....
Jean-Philippe Lang -
r14563:f2fd7905557d
parent child
Show More
@@ -153,6 +153,10 class CustomField < ActiveRecord::Base
153 format.query_filter_options(self, query)
153 format.query_filter_options(self, query)
154 end
154 end
155
155
156 def totalable?
157 format.totalable_supported
158 end
159
156 # Returns a ORDER BY clause that can used to sort customized
160 # Returns a ORDER BY clause that can used to sort customized
157 # objects by their value of the custom field.
161 # objects by their value of the custom field.
158 # Returns nil if the custom field can not be used for sorting.
162 # Returns nil if the custom field can not be used for sorting.
@@ -80,7 +80,7 class QueryCustomFieldColumn < QueryColumn
80 self.name = "cf_#{custom_field.id}".to_sym
80 self.name = "cf_#{custom_field.id}".to_sym
81 self.sortable = custom_field.order_statement || false
81 self.sortable = custom_field.order_statement || false
82 self.groupable = custom_field.group_statement || false
82 self.groupable = custom_field.group_statement || false
83 self.totalable = ['int', 'float'].include?(custom_field.field_format)
83 self.totalable = custom_field.totalable?
84 @inline = true
84 @inline = true
85 @cf = custom_field
85 @cf = custom_field
86 end
86 end
@@ -692,7 +692,7 class Query < ActiveRecord::Base
692 end
692 end
693 if column.is_a?(QueryCustomFieldColumn)
693 if column.is_a?(QueryCustomFieldColumn)
694 custom_field = column.custom_field
694 custom_field = column.custom_field
695 send "total_for_#{custom_field.field_format}_custom_field", custom_field, scope
695 send "total_for_custom_field", custom_field, scope
696 else
696 else
697 send "total_for_#{column.name}", scope
697 send "total_for_#{column.name}", scope
698 end
698 end
@@ -710,21 +710,9 class Query < ActiveRecord::Base
710 group(group_by_statement)
710 group(group_by_statement)
711 end
711 end
712
712
713 def total_for_float_custom_field(custom_field, scope)
714 total_for_custom_field(custom_field, scope) {|t| t.to_f.round(2)}
715 end
716
717 def total_for_int_custom_field(custom_field, scope)
718 total_for_custom_field(custom_field, scope) {|t| t.to_i}
719 end
720
721 def total_for_custom_field(custom_field, scope, &block)
713 def total_for_custom_field(custom_field, scope, &block)
722 total = scope.joins(:custom_values).
714 total = custom_field.format.total_for_scope(custom_field, scope)
723 where(:custom_values => {:custom_field_id => custom_field.id}).
715 total = map_total(total) {|t| custom_field.format.cast_total_value(custom_field, t)}
724 where.not(:custom_values => {:value => ''}).
725 sum("CAST(#{CustomValue.table_name}.value AS decimal(30,3))")
726
727 total = map_total(total, &block) if block_given?
728 total
716 total
729 end
717 end
730
718
@@ -61,6 +61,10 module Redmine
61 class_attribute :searchable_supported
61 class_attribute :searchable_supported
62 self.searchable_supported = false
62 self.searchable_supported = false
63
63
64 # Set this to true if field values can be summed up
65 class_attribute :totalable_supported
66 self.totalable_supported = false
67
64 # Restricts the classes that the custom field can be added to
68 # Restricts the classes that the custom field can be added to
65 # Set to nil for no restrictions
69 # Set to nil for no restrictions
66 class_attribute :customized_class_names
70 class_attribute :customized_class_names
@@ -370,6 +374,7 module Redmine
370
374
371 class Numeric < Unbounded
375 class Numeric < Unbounded
372 self.form_partial = 'custom_fields/formats/numeric'
376 self.form_partial = 'custom_fields/formats/numeric'
377 self.totalable_supported = true
373
378
374 def order_statement(custom_field)
379 def order_statement(custom_field)
375 # Make the database cast values into numeric
380 # Make the database cast values into numeric
@@ -377,6 +382,18 module Redmine
377 # CustomValue validations should ensure that it doesn't occur
382 # CustomValue validations should ensure that it doesn't occur
378 "CAST(CASE #{join_alias custom_field}.value WHEN '' THEN '0' ELSE #{join_alias custom_field}.value END AS decimal(30,3))"
383 "CAST(CASE #{join_alias custom_field}.value WHEN '' THEN '0' ELSE #{join_alias custom_field}.value END AS decimal(30,3))"
379 end
384 end
385
386 # Returns totals for the given scope
387 def total_for_scope(custom_field, scope)
388 scope.joins(:custom_values).
389 where(:custom_values => {:custom_field_id => custom_field.id}).
390 where.not(:custom_values => {:value => ''}).
391 sum("CAST(#{CustomValue.table_name}.value AS decimal(30,3))")
392 end
393
394 def cast_total_value(custom_field, value)
395 cast_single_value(custom_field, value)
396 end
380 end
397 end
381
398
382 class IntFormat < Numeric
399 class IntFormat < Numeric
@@ -412,6 +429,10 module Redmine
412 value.to_f
429 value.to_f
413 end
430 end
414
431
432 def cast_total_value(custom_field, value)
433 value.to_f.round(2)
434 end
435
415 def validate_single_value(custom_field, value, customized=nil)
436 def validate_single_value(custom_field, value, customized=nil)
416 errs = super
437 errs = super
417 errs << ::I18n.t('activerecord.errors.messages.invalid') unless (Kernel.Float(value) rescue nil)
438 errs << ::I18n.t('activerecord.errors.messages.invalid') unless (Kernel.Float(value) rescue nil)
General Comments 0
You need to be logged in to leave comments. Login now