format.query_filter_options(self, query)
end
+ def totalable?
+ format.totalable_supported
+ end
+
# Returns a ORDER BY clause that can used to sort customized
# objects by their value of the custom field.
# Returns nil if the custom field can not be used for sorting.
self.name = "cf_#{custom_field.id}".to_sym
self.sortable = custom_field.order_statement || false
self.groupable = custom_field.group_statement || false
- self.totalable = ['int', 'float'].include?(custom_field.field_format)
+ self.totalable = custom_field.totalable?
@inline = true
@cf = custom_field
end
end
if column.is_a?(QueryCustomFieldColumn)
custom_field = column.custom_field
- send "total_for_#{custom_field.field_format}_custom_field", custom_field, scope
+ send "total_for_custom_field", custom_field, scope
else
send "total_for_#{column.name}", scope
end
group(group_by_statement)
end
- def total_for_float_custom_field(custom_field, scope)
- total_for_custom_field(custom_field, scope) {|t| t.to_f.round(2)}
- end
-
- def total_for_int_custom_field(custom_field, scope)
- total_for_custom_field(custom_field, scope) {|t| t.to_i}
- end
-
def total_for_custom_field(custom_field, scope, &block)
- total = scope.joins(:custom_values).
- where(:custom_values => {:custom_field_id => custom_field.id}).
- where.not(:custom_values => {:value => ''}).
- sum("CAST(#{CustomValue.table_name}.value AS decimal(30,3))")
-
- total = map_total(total, &block) if block_given?
+ total = custom_field.format.total_for_scope(custom_field, scope)
+ total = map_total(total) {|t| custom_field.format.cast_total_value(custom_field, t)}
total
end
class_attribute :searchable_supported
self.searchable_supported = false
+ # Set this to true if field values can be summed up
+ class_attribute :totalable_supported
+ self.totalable_supported = false
+
# Restricts the classes that the custom field can be added to
# Set to nil for no restrictions
class_attribute :customized_class_names
class Numeric < Unbounded
self.form_partial = 'custom_fields/formats/numeric'
+ self.totalable_supported = true
def order_statement(custom_field)
# Make the database cast values into numeric
# CustomValue validations should ensure that it doesn't occur
"CAST(CASE #{join_alias custom_field}.value WHEN '' THEN '0' ELSE #{join_alias custom_field}.value END AS decimal(30,3))"
end
+
+ # Returns totals for the given scope
+ def total_for_scope(custom_field, scope)
+ scope.joins(:custom_values).
+ where(:custom_values => {:custom_field_id => custom_field.id}).
+ where.not(:custom_values => {:value => ''}).
+ sum("CAST(#{CustomValue.table_name}.value AS decimal(30,3))")
+ end
+
+ def cast_total_value(custom_field, value)
+ cast_single_value(custom_field, value)
+ end
end
class IntFormat < Numeric
value.to_f
end
+ def cast_total_value(custom_field, value)
+ value.to_f.round(2)
+ end
+
def validate_single_value(custom_field, value, customized=nil)
errs = super
errs << ::I18n.t('activerecord.errors.messages.invalid') unless (Kernel.Float(value) rescue nil)