Class: ProductFilter
Overview
== Schema Information
Table name: product_filters
Database name: primary
id :integer not null, primary key
apply_discount :boolean
cached_item_ids :integer is an Array
exclude_item_ids :integer default([]), not null, is an Array
exclude_product_category_ids :integer default([]), not null, is an Array
exclude_product_line_ids :integer default([]), not null, is an Array
item_ids :integer default([]), is an Array
max_lin_ft :integer
max_msrp_amount :decimal(8, 2)
max_qty :integer
max_sq_ft :integer
min_lin_ft :integer
min_msrp_amount :decimal(8, 2)
min_qty :integer default(1), not null
min_sq_ft :integer
product_category_ids :integer default([]), is an Array
product_line_ids :integer default([]), is an Array
resource_type :string
created_at :datetime
updated_at :datetime
assortment_instruction_id :integer
creator_id :integer
resource_id :integer
updater_id :integer
Indexes
idx_assortment_instruction_id (assortment_instruction_id)
idx_resource_id_resource_type (resource_id,resource_type)
Foreign Keys
fk_rails_... (assortment_instruction_id => assortment_instructions.id)
Defined Under Namespace
Classes: LineExtractor, LineQualifier
Constant Summary
Models::Auditable::ALWAYS_IGNORED
Instance Attribute Summary collapse
#creator, #updater
Class Method Summary
collapse
Instance Method Summary
collapse
#all_skipped_columns, #audit_reference_data, #should_not_save_version, #stamp_record
ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation
#publish_event
Instance Attribute Details
#criteria_met ⇒ Object
Returns the value of attribute criteria_met.
43
44
45
|
# File 'app/models/product_filter.rb', line 43
def criteria_met
@criteria_met
end
|
#max_lin_ft ⇒ Object
58
|
# File 'app/models/product_filter.rb', line 58
validates :max_lin_ft, numericality: { greater_than_or_equal_to: :min_lin_ft, if: -> { max_lin_ft.present? } }
|
#max_msrp_amount ⇒ Object
60
|
# File 'app/models/product_filter.rb', line 60
validates :max_msrp_amount, numericality: { greater_than_or_equal_to: :min_msrp_amount, if: -> { max_msrp_amount.present? } }
|
#max_qty ⇒ Object
54
|
# File 'app/models/product_filter.rb', line 54
validates :max_qty, numericality: { greater_than_or_equal_to: :min_qty, if: -> { max_qty.present? } }
|
#max_sq_ft ⇒ Object
56
|
# File 'app/models/product_filter.rb', line 56
validates :max_sq_ft, numericality: { greater_than_or_equal_to: :min_sq_ft, if: -> { max_sq_ft.present? } }
|
#min_lin_ft ⇒ Object
57
|
# File 'app/models/product_filter.rb', line 57
validates :min_lin_ft, numericality: { greater_than_or_equal_to: 1, if: -> { min_lin_ft.present? } }
|
#min_msrp_amount ⇒ Object
59
|
# File 'app/models/product_filter.rb', line 59
validates :min_msrp_amount, numericality: { greater_than_or_equal_to: 1, if: -> { min_msrp_amount.present? } }
|
#min_qty ⇒ Object
52
|
# File 'app/models/product_filter.rb', line 52
validates :min_qty, presence: true
|
#min_sq_ft ⇒ Object
55
|
# File 'app/models/product_filter.rb', line 55
validates :min_sq_ft, numericality: { greater_than_or_equal_to: 1, if: -> { min_sq_ft.present? } }
|
Class Method Details
.presence_checking ⇒ ActiveRecord::Relation<ProductFilter>
A relation of ProductFilters that are presence checking. Active Record Scope
63
|
# File 'app/models/product_filter.rb', line 63
scope :presence_checking, -> { where('product_filters.min_qty > 0 or product_filters.min_sq_ft > 0 or product_filters.min_lin_ft > 0 or product_filters.min_msrp_amount > 0') }
|
Instance Method Details
#any_items_match?(candidate_ids) ⇒ Boolean
Check if any of the given candidate item IDs match this filter's criteria.
More efficient than matching_item_ids when you only need a boolean result.
157
158
159
160
161
|
# File 'app/models/product_filter.rb', line 157
def any_items_match?(candidate_ids)
return false if candidate_ids.blank?
applicable_items_scope.where(id: candidate_ids).exists?
end
|
#applicable_item_ids_set ⇒ Set<Integer>
Returns a Set of applicable item IDs for fast O(1) lookup during batch operations.
NOTE: Prefer matching_item_ids(candidate_ids) when checking a small set of items
(e.g., order line items) as it's much more efficient.
168
169
170
|
# File 'app/models/product_filter.rb', line 168
def applicable_item_ids_set
@applicable_item_ids_set ||= applicable_items_scope.pluck(:id).to_set
end
|
#applicable_items_scope ⇒ ActiveRecord::Relation
Returns an ActiveRecord relation of applicable items using real-time ltree queries.
This is the preferred way to get applicable items as it doesn't require cache maintenance.
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
# File 'app/models/product_filter.rb', line 101
def applicable_items_scope
base_scope = Item.non_publications.active
has_pl_or_pc = product_line_ids.present? || product_category_ids.present?
scope = if has_pl_or_pc
if product_line_ids.present? && product_category_ids.present?
base_scope.by_product_line_id(product_line_ids).by_product_category_id(product_category_ids)
elsif product_line_ids.present?
base_scope.by_product_line_id(product_line_ids)
else
base_scope.by_product_category_id(product_category_ids)
end
elsif item_ids.present?
base_scope.where(id: item_ids)
else
Item.none
end
scope = scope.or(base_scope.where(id: item_ids)) if has_pl_or_pc && item_ids.present?
scope = scope.where.not(id: base_scope.by_product_line_id(exclude_product_line_ids).select(:id)) if exclude_product_line_ids.present?
scope = scope.where.not(id: base_scope.by_product_category_id(exclude_product_category_ids).select(:id)) if exclude_product_category_ids.present?
scope = scope.where.not(id: exclude_item_ids) if exclude_item_ids.present?
scope
end
|
46
|
# File 'app/models/product_filter.rb', line 46
belongs_to :assortment_instruction, inverse_of: :product_filters, optional: true
|
#deep_dup ⇒ Object
65
66
67
|
# File 'app/models/product_filter.rb', line 65
def deep_dup
deep_clone
end
|
#effective_item_skus ⇒ Object
77
78
79
|
# File 'app/models/product_filter.rb', line 77
def effective_item_skus
effective_items.pluck(:sku)
end
|
#effective_items ⇒ Object
73
74
75
|
# File 'app/models/product_filter.rb', line 73
def effective_items
applicable_items_scope.order(:sku)
end
|
#exclude_items ⇒ Object
189
190
191
|
# File 'app/models/product_filter.rb', line 189
def exclude_items
Item.where(id: exclude_item_ids)
end
|
#exclude_product_categories ⇒ Object
197
198
199
|
# File 'app/models/product_filter.rb', line 197
def exclude_product_categories
ProductCategory.where(id: exclude_product_category_ids)
end
|
#exclude_product_lines ⇒ Object
193
194
195
|
# File 'app/models/product_filter.rb', line 193
def exclude_product_lines
ProductLine.where(id: exclude_product_line_ids)
end
|
#has_product_conditions? ⇒ Boolean
81
82
83
|
# File 'app/models/product_filter.rb', line 81
def has_product_conditions?
[*item_ids, *product_line_ids, *product_category_ids, *exclude_item_ids, *exclude_product_line_ids, *exclude_product_category_ids].compact.present?
end
|
#items ⇒ Object
177
178
179
|
# File 'app/models/product_filter.rb', line 177
def items
Item.where(id: item_ids)
end
|
#matching_item_ids(candidate_ids) ⇒ Set<Integer>
Returns which of the given candidate item IDs match this filter's criteria.
This is much more efficient than fetching ALL applicable items when you only
need to check a small set of items (e.g., items from an order).
Results are memoized per candidate set so the same filter evaluated against
the same line items (common during discount calculation across many coupons)
hits the DB only once instead of once per coupon.
144
145
146
147
148
149
150
|
# File 'app/models/product_filter.rb', line 144
def matching_item_ids(candidate_ids)
return Set.new if candidate_ids.blank?
cache_key = candidate_ids.sort
@matching_item_ids_cache ||= {}
@matching_item_ids_cache[cache_key] ||= applicable_items_scope.where(id: candidate_ids).pluck(:id).to_set
end
|
#meet_conditions?(item, applicable_ids: nil) ⇒ Boolean
Check if an item matches the product filter criteria.
Uses real-time ltree queries - no cache maintenance needed.
92
93
94
95
|
# File 'app/models/product_filter.rb', line 92
def meet_conditions?(item, applicable_ids: nil)
ids = applicable_ids || applicable_item_ids_set
ids.include?(item.id)
end
|
#product_categories ⇒ Object
185
186
187
|
# File 'app/models/product_filter.rb', line 185
def product_categories
ProductCategory.where(id: product_category_ids)
end
|
#product_lines ⇒ Object
181
182
183
|
# File 'app/models/product_filter.rb', line 181
def product_lines
ProductLine.where(id: product_line_ids)
end
|
#reset_applicable_item_ids_set! ⇒ Object
Clear the memoized applicable_item_ids_set (call when filter criteria change)
173
174
175
|
# File 'app/models/product_filter.rb', line 173
def reset_applicable_item_ids_set!
@applicable_item_ids_set = nil
end
|
#resource ⇒ Resource
45
|
# File 'app/models/product_filter.rb', line 45
belongs_to :resource, polymorphic: true, optional: true
|
#to_s ⇒ Object
69
70
71
|
# File 'app/models/product_filter.rb', line 69
def to_s
"[ProductFilter:#{id}]"
end
|