Skip to content

Commit

Permalink
Merge pull request #78 from latera/HOMS-154
Browse files Browse the repository at this point in the history
HOMS-154 Add orders filter by custom fields
  • Loading branch information
Timofey Alekperov committed Feb 14, 2018
2 parents 22cbc0c + c67d2aa commit 6251acc
Show file tree
Hide file tree
Showing 19 changed files with 501 additions and 70 deletions.
30 changes: 30 additions & 0 deletions app/assets/javascripts/application.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,35 @@ class Homs
cache: true
language: I18n.locale)

enableOrderAttributePicker: (allowClear) =>
$('.order_attribute-picker').select2(
width: '100%'
allowClear: allowClear
theme: 'bootstrap'
formatSelection: -> (node) node.id
cache: true
language: I18n.locale)

currentOrderType = $('.order_type-picker option:selected').val()
if currentOrderType
@setAttributePickerOptions(currentOrderType)

setAttributePickerOptions: (orderType) =>
$.ajax '/orders/order_type_attributes/' + orderType,
method: 'GET'
success: (data) =>
if Object.keys(data.options).length > 0
$orderAttributePicker = $('.order_attribute-picker')
$orderAttributePicker.empty()

$.each(data.options, (key, value) =>
$orderAttributePicker
.append(
$('<option>', {value: key}).text(value.label)
))

$orderAttributePicker.prop('disabled', false).trigger('change')

updateOrderForm: (orderCode) =>
$.ajax('/orders/' + orderCode, dataType: 'html')
.done((response) -> $('#order-data').html($(response).find('#order-data').html()))
Expand All @@ -182,6 +211,7 @@ class Homs
$ ->
Application.enableDateTimePicker()
Application.enableOrderTypePicker(true)
Application.enableOrderAttributePicker(false)

class PatchedGrowl extends @Growl
@growl: (settings = {}) ->
Expand Down
26 changes: 26 additions & 0 deletions app/assets/stylesheets/framework_and_overrides.sass
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,29 @@ input
a
cursor: pointer

#custom-field-filter-container
margin-left: -30px

.custom-field-filter
margin-bottom: 20px

.label-overflow
cursor: pointer
width: 90%
white-space: nowrap
overflow: hidden
text-overflow: ellipsis

.label-checkbox
margin-bottom: 0.3em

.checkbox-margin
margin: 10px 5px 19px

.custom-field-filter-close
display: none
float: right
cursor: pointer

&:hover .custom-field-filter-close
display: inline-block
37 changes: 37 additions & 0 deletions app/classes/custom_fields/data_types/datetime_range.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
module CustomFields
module DataTypes
class DatetimeRange < CustomFields::Base
def validate_definition
true
end

def validate_value(attribute_name, value)
return true if value.empty?
return true if (value[:from].is_a?(Time) || value[:from].is_a?(Date)) &&
(value[:to].is_a?(Time) || value[:to].is_a?(Date))

coerce_value(value)
rescue ArgumentError
errors[attribute_name] << t('invalid_value',
attribute_name: attribute_name,
type: 'DateTimeFilter',
value: value)
end

def coerce_value(value)
unless value.is_a?(Hash)
raise NotImplementedError
end

{
from: datetime_obj.coerce_value(value[:from]),
to: datetime_obj.coerce_value(value[:to])
}
end

def datetime_obj
Datetime.new(options)
end
end
end
end
6 changes: 6 additions & 0 deletions app/controllers/orders_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ def set_order
@order = Order.new
end

def get_order_type_attributes
order_type = OrderType.find(params[:id])

render json: {options: order_type.fields}
end

protected

def resource_get
Expand Down
24 changes: 22 additions & 2 deletions app/filters/list_orders_filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,24 @@ def filter_by_user_id(rel, value)
end
end

def filter_by_custom_fields(relation, data)
if data[:custom_fields]
fields_definition = OrderType.find(data[:order_type_id]).fields

string_field_names = fields_definition.select { |_k, v| %w(boolean number string).include? v[:type] }.keys
date_field_names = fields_definition.select { |_k, v| v[:type] == 'datetime' }.keys

filter_string_fields = data[:custom_fields].slice(*string_field_names).compact
filter_date_fields = data[:custom_fields].slice(*date_field_names).compact

filter_date_fields.reduce(relation.data_fields(filter_string_fields)) do |rel, (name, value)|
rel.data_datetime_range(name, value[:from], value[:to])
end
else
relation
end
end

def filter_by(rel, column, value)
rel.where(column => value)
end
Expand Down Expand Up @@ -77,13 +95,15 @@ def initialize(current_user, params = {})
end

def list_orders(relation = Order.all)
%w(state order_type_id user_id archived).reduce(Filters.filter_by_date(relation, filter_values)) do |rel, column|
rel = %w(state order_type_id user_id archived).reduce(Filters.filter_by_date(relation, filter_values)) do |rel, column|
Filters.filter_with_dispatch(rel, column, filter_values[column])
end

Filters.filter_by_custom_fields(rel, filter_values)
end

def filter_values
@filter_values ||= params.slice(*%w(state order_type_id archived user_id)).merge(dates)
@filter_values ||= params.slice(*%w(state order_type_id archived user_id custom_fields)).merge(dates)
end

def dates
Expand Down
16 changes: 16 additions & 0 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,22 @@ def order_types_for_select
end
end

def custom_fields_for_filter(order_type, attributes)
type_attributes = OrderType.find(order_type).fields.with_indifferent_access
prepared_fields = attributes.each_with_object({}) do |(attr, val), fields|
value = val
value[:localized] = localize_date_range(val) if type_attributes[attr][:type] == 'datetime'

fields[attr] = {value: value}
end

type_attributes.slice(*attributes.keys).deep_merge(prepared_fields)
end

def localize_date_range(date_range)
date_range.reduce({}) { |range, (k,v)| range[k] = DateTime.iso8601(v).strftime(datetime_format) if v.present?; range }
end

def boolean_indicator(boolean)
boolean ? tag(:span, class: %w(glyphicon glyphicon-ok)) : ''
end
Expand Down
11 changes: 11 additions & 0 deletions app/helpers/ui_elements_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@
module UiElementsHelper
include DatetimeFormat

def order_attribute_picker(name)
content_tag(:select,
name: name,
data: {
allowClear: false,
placeholder: I18n.t('helpers.custom_fields_filter.placeholder'),
},
disabled: true,
class: 'form-control order_attribute-picker') {}
end

def datetime_picker(name, options = {})
if options[:value].present?
value = options[:value].strftime(datetime_format)
Expand Down
5 changes: 5 additions & 0 deletions app/models/order.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ def id_from_code(code)
delegate :name, :code, :print_form_code, to: :order_type, prefix: true

default_scope { includes(:order_type).order('created_at DESC') }
scope :data_fields, ->(data) { where('data @> ?', data.to_json) }
scope :data_datetime_range, ->(field, from, to) {
where('(data->>:field)::timestamp between coalesce(:from, (data->>:field)::timestamp) and coalesce(:to, (data->>:field)::timestamp)',
{field: field, from: from, to: to})
}

enum state: %i(to_execute in_progress done)

Expand Down
10 changes: 10 additions & 0 deletions app/models/order_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ def field_definition_set
CustomFields::FieldDefSet.new(fields)
end

def filter_field_definition_set
filter_fields = fields.each_with_object({}) do |(key, value), h|
value[:type] = 'datetime_range' if value[:type] == 'datetime'

h[key] = value
end

CustomFields::FieldDefSet.new(filter_fields)
end

def make_invisile
update_attribute(:active, false)
end
Expand Down
Loading

0 comments on commit 6251acc

Please sign in to comment.