@@ -153,6 +153,10 class CustomField < ActiveRecord::Base | |||
|
153 | 153 | format.query_filter_options(self, query) |
|
154 | 154 | end |
|
155 | 155 | |
|
156 | def totalable? | |
|
157 | format.totalable_supported | |
|
158 | end | |
|
159 | ||
|
156 | 160 | # Returns a ORDER BY clause that can used to sort customized |
|
157 | 161 | # objects by their value of the custom field. |
|
158 | 162 | # Returns nil if the custom field can not be used for sorting. |
@@ -80,7 +80,7 class QueryCustomFieldColumn < QueryColumn | |||
|
80 | 80 | self.name = "cf_#{custom_field.id}".to_sym |
|
81 | 81 | self.sortable = custom_field.order_statement || false |
|
82 | 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 | 84 | @inline = true |
|
85 | 85 | @cf = custom_field |
|
86 | 86 | end |
@@ -692,7 +692,7 class Query < ActiveRecord::Base | |||
|
692 | 692 | end |
|
693 | 693 | if column.is_a?(QueryCustomFieldColumn) |
|
694 | 694 | custom_field = column.custom_field |
|
695 |
send "total_for_ |
|
|
695 | send "total_for_custom_field", custom_field, scope | |
|
696 | 696 | else |
|
697 | 697 | send "total_for_#{column.name}", scope |
|
698 | 698 | end |
@@ -710,21 +710,9 class Query < ActiveRecord::Base | |||
|
710 | 710 | group(group_by_statement) |
|
711 | 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 | 713 | def total_for_custom_field(custom_field, scope, &block) |
|
722 | total = scope.joins(:custom_values). | |
|
723 | where(:custom_values => {:custom_field_id => custom_field.id}). | |
|
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? | |
|
714 | total = custom_field.format.total_for_scope(custom_field, scope) | |
|
715 | total = map_total(total) {|t| custom_field.format.cast_total_value(custom_field, t)} | |
|
728 | 716 | total |
|
729 | 717 | end |
|
730 | 718 |
@@ -61,6 +61,10 module Redmine | |||
|
61 | 61 | class_attribute :searchable_supported |
|
62 | 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 | 68 | # Restricts the classes that the custom field can be added to |
|
65 | 69 | # Set to nil for no restrictions |
|
66 | 70 | class_attribute :customized_class_names |
@@ -370,6 +374,7 module Redmine | |||
|
370 | 374 | |
|
371 | 375 | class Numeric < Unbounded |
|
372 | 376 | self.form_partial = 'custom_fields/formats/numeric' |
|
377 | self.totalable_supported = true | |
|
373 | 378 | |
|
374 | 379 | def order_statement(custom_field) |
|
375 | 380 | # Make the database cast values into numeric |
@@ -377,6 +382,18 module Redmine | |||
|
377 | 382 | # CustomValue validations should ensure that it doesn't occur |
|
378 | 383 | "CAST(CASE #{join_alias custom_field}.value WHEN '' THEN '0' ELSE #{join_alias custom_field}.value END AS decimal(30,3))" |
|
379 | 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 | 397 | end |
|
381 | 398 | |
|
382 | 399 | class IntFormat < Numeric |
@@ -412,6 +429,10 module Redmine | |||
|
412 | 429 | value.to_f |
|
413 | 430 | end |
|
414 | 431 | |
|
432 | def cast_total_value(custom_field, value) | |
|
433 | value.to_f.round(2) | |
|
434 | end | |
|
435 | ||
|
415 | 436 | def validate_single_value(custom_field, value, customized=nil) |
|
416 | 437 | errs = super |
|
417 | 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