Class: Gemgento::Product
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- Gemgento::Product
- Defined in:
- app/models/gemgento/product.rb
Overview
Instance Attribute Summary collapse
-
#attribute_values ⇒ Object
Returns the value of attribute attribute_values.
-
#configurable_attribute_ordering ⇒ Object
Returns the value of attribute configurable_attribute_ordering.
-
#sync_needed ⇒ Object
Returns the value of attribute sync_needed.
Class Method Summary collapse
-
.filter(filters, store = nil) ⇒ ActiveRecord::Result
Filter products based on attribute values.
-
.order_by_attribute(attribute, direction = 'ASC', is_numeric = false, store = nil) ⇒ ActiveRecord::Result
Order ActiveRecord result by attribute values.
Instance Method Summary collapse
- #after_touch ⇒ Object
-
#attribute_value(code, store = nil) ⇒ String, ...
Get an attribute value.
-
#categories(store = nil) ⇒ Object
Categories related to the product.
-
#configurable? ⇒ Boolean
Check if the product is configurable.
-
#configurable_attribute_order(store = nil, active_only = true) ⇒ Object
Return the ordering of configurable attribute values.
-
#current_category(category_id = nil, store = nil) ⇒ Gemgento::Category
Determine the current category of a product based on the active navigation categories related to the product.
-
#get_configurable_attribute_ordering(store, active_only) ⇒ Hash(Hash(Array(Integer)))
Calculate the ordering of configurable attribute values.
-
#in_stock?(quantity = 1, store = nil) ⇒ Boolean
Determine if product has a specific inventory level.
-
#is_catalog_visible? ⇒ Boolean
Determine if the product is catalog visible.
-
#manage_cache_expires_at ⇒ DateTime?
If the product has a cache_expires_at date set, make sure it hasn’t expired.
-
#mark_deleted ⇒ Void
Mark a product deleted.
-
#mark_deleted! ⇒ Void
Mark a product deleted and save.
-
#method_missing(method, *args) ⇒ Object
Attempts to return attribute_value before error.
-
#on_sale?(user_group = nil, store = nil, quantity = 1.0) ⇒ Boolean
Determine if product is on sale.
-
#original_price(store = nil) ⇒ Float
Get the original, non sale, price for a product.
-
#price(user_group = nil, store = nil, quantity = 1.0) ⇒ Object
Get the product price.
- #remove_from_active_quotes ⇒ Object
-
#set_attribute_value(code, value, store = nil) ⇒ Boolean
Set an attribute value.
-
#set_cache_expires_at ⇒ Void
Calculate the datetime that the product cache should expire.
-
#set_configurable_products_by_magento_ids(magento_ids) ⇒ void
Set the associated configurable products, using an array of Magento product IDs.
-
#set_simple_products_by_magento_ids(magento_ids) ⇒ void
Set the associated simple products, using an array of Magento product IDs.
-
#simple? ⇒ Boolean
Check if the product is simple.
- #sync_needed? ⇒ Boolean
- #to_param ⇒ Object
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *args) ⇒ Object
Attempts to return attribute_value before error.
153 154 155 156 157 158 159 |
# File 'app/models/gemgento/product.rb', line 153 def method_missing(method, *args) begin return self.attribute_value(method) rescue super end end |
Instance Attribute Details
#attribute_values ⇒ Object
Returns the value of attribute attribute_values.
69 70 71 |
# File 'app/models/gemgento/product.rb', line 69 def attribute_values @attribute_values end |
#configurable_attribute_ordering ⇒ Object
Returns the value of attribute configurable_attribute_ordering.
69 70 71 |
# File 'app/models/gemgento/product.rb', line 69 def configurable_attribute_ordering @configurable_attribute_ordering end |
#sync_needed ⇒ Object
Returns the value of attribute sync_needed.
69 70 71 |
# File 'app/models/gemgento/product.rb', line 69 def sync_needed @sync_needed end |
Class Method Details
.filter(filters, store = nil) ⇒ ActiveRecord::Result
Filter products based on attribute values.
filter example:
{attribute: Gemgento::ProductAttribute.find_by(code: 'size'), value: 'large'})
or
{attribute: Gemgento::ProductAttribute.find_by(code: 'size'), value: %w[large small]})
or
{attribute: [Gemgento::ProductAttribute.find_by(code: 'size'), Gemgento::ProductAttribute.find_by(code: 'dimension')], value: 'large'})
or
{attribute: [Gemgento::ProductAttribute.find_by(code: 'size'), Gemgento::ProductAttribute.find_by(code: 'dimension')], value: %w[large small]})
or
[{attribute: Gemgento::ProductAttribute.find_by(code: 'size'), value: 'large'}), {attribute: Gemgento::ProductAttribute.find_by(code: 'color'), value: 'red'})]
Filters can also take an optional operand, the default operand is '=' or 'IN' for an array
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
# File 'app/models/gemgento/product.rb', line 225 def self.filter(filters, store = nil) store = Store.current if store.nil? filters = [filters] unless filters.is_a? Array products = self filters.each_with_index do |filter, index| filter[:attribute] = [filter[:attribute]] unless filter[:attribute].is_a? Array operand = filter[:value].is_a?(Array) ? 'IN' : ( filter.has_key?(:operand) ? filter[:operand] : '=' ) value_placeholder = filter[:value].is_a?(Array) ? '(?)' : '?' unless filter[:attribute][0].frontend_input == 'select' products = products.joins(ActiveRecord::Base.escape_sql( "INNER JOIN gemgento_product_attribute_values AS value#{index} ON value#{index}.product_id = gemgento_products.id AND value#{index}.value #{operand} #{value_placeholder} AND value#{index}.store_id = ? INNER JOIN gemgento_product_attributes AS attribute#{index} ON attribute#{index}.id = value#{index}.product_attribute_id AND attribute#{index}.id IN (?)", filter[:value], store.id, filter[:attribute].map { |a| a.id } )).distinct.readonly(false) else products = products.joins(ActiveRecord::Base.escape_sql( "INNER JOIN gemgento_product_attribute_values AS value#{index} ON value#{index}.product_id = gemgento_products.id INNER JOIN gemgento_product_attributes AS attribute#{index} ON attribute#{index}.id = value#{index}.product_attribute_id AND attribute#{index}.id IN (?) INNER JOIN gemgento_product_attribute_options AS option#{index} ON option#{index}.product_attribute_id = attribute#{index}.id AND value#{index}.value = option#{index}.value AND option#{index}.label #{operand} #{value_placeholder}", filter[:attribute].map { |a| a.id }, filter[:value] )).distinct.readonly(false) # does not compare against values end end return products end |
.order_by_attribute(attribute, direction = 'ASC', is_numeric = false, store = nil) ⇒ ActiveRecord::Result
Order ActiveRecord result by attribute values.
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
# File 'app/models/gemgento/product.rb', line 268 def self.order_by_attribute(attribute, direction = 'ASC', is_numeric = false, store = nil) store = Store.current if store.nil? raise 'Direction must be equivalent to ASC or DESC' if direction != 'ASC' and direction != 'DESC' products = self unless attribute.frontend_input == 'select' products = products.joins( ActiveRecord::Base.escape_sql( 'INNER JOIN gemgento_product_attribute_values ON gemgento_product_attribute_values.product_id = gemgento_products.id AND gemgento_product_attribute_values.product_attribute_id = ? AND gemgento_product_attribute_values.store_id = ? ' + 'INNER JOIN gemgento_product_attributes ON gemgento_product_attributes.id = gemgento_product_attribute_values.product_attribute_id ', attribute.id, store.id )) if is_numeric products = products.reorder("CAST(gemgento_product_attribute_values.value AS SIGNED) #{direction}") else products = products.reorder("gemgento_product_attribute_values.value #{direction}") end else products = products.joins( ActiveRecord::Base.escape_sql( 'INNER JOIN gemgento_product_attribute_values ON gemgento_product_attribute_values.product_id = gemgento_products.id AND gemgento_product_attribute_values.product_attribute_id = ? ' + 'INNER JOIN gemgento_product_attributes ON gemgento_product_attributes.id = gemgento_product_attribute_values.product_attribute_id ' + 'INNER JOIN gemgento_product_attribute_options ON gemgento_product_attribute_options.product_attribute_id = gemgento_product_attributes.id AND gemgento_product_attribute_options.value = gemgento_product_attribute_values.value ' + 'AND gemgento_product_attribute_options.store_id = ?', attribute.id, store.id )) if is_numeric products = products.reorder("CAST(gemgento_product_attribute_options.order AS SIGNED) #{direction}") else products = products.reorder("gemgento_product_attribute_options.order #{direction}") end end products = products.readonly(false) return products end |
Instance Method Details
#after_touch ⇒ Object
523 524 525 |
# File 'app/models/gemgento/product.rb', line 523 def after_touch # do nothing end |
#attribute_value(code, store = nil) ⇒ String, ...
Get an attribute value.
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'app/models/gemgento/product.rb', line 116 def attribute_value(code, store = nil) store = Gemgento::Store.current if store.nil? product_attribute_value = self.attribute_values.select { |value| !value.product_attribute.nil? && value.product_attribute.code == code.to_s && value.store_id == store.id }.first ## if the attribute is not currently associated with the product, check if it exists if product_attribute_value.nil? product_attribute = Gemgento::ProductAttribute.find_by(code: code) if product_attribute.nil? # throw an error if the code is not recognized raise "Unknown product attribute code - #{code}" end else product_attribute = product_attribute_value.product_attribute end value = product_attribute_value.nil? ? product_attribute.default_value : product_attribute_value.value return nil if value.nil? if product_attribute.frontend_input == 'boolean' || product_attribute.code == 'is_recurring' if value == 'Yes' || value == '1' || value == '1.0' value = true else value = false end elsif product_attribute.frontend_input == 'select' option = product_attribute..find_by(value: value, store: store) value = option.nil? ? nil : option.label end return value end |
#categories(store = nil) ⇒ Object
Categories related to the product.
509 510 511 512 |
# File 'app/models/gemgento/product.rb', line 509 def categories(store = nil) return super if store.nil? Gemgento::Category.where(id: self.product_categories.where(store: store).pluck(:category_id)) end |
#configurable? ⇒ Boolean
Check if the product is configurable.
494 495 496 |
# File 'app/models/gemgento/product.rb', line 494 def configurable? magento_type == 'configurable' end |
#configurable_attribute_order(store = nil, active_only = true) ⇒ Object
Return the ordering of configurable attribute values.
344 345 346 |
# File 'app/models/gemgento/product.rb', line 344 def configurable_attribute_order(store = nil, active_only = true) self.configurable_attribute_ordering ||= self.get_configurable_attribute_ordering(store, active_only) end |
#current_category(category_id = nil, store = nil) ⇒ Gemgento::Category
Determine the current category of a product based on the active navigation categories related to the product. A preferred category id can be specified, if this category is not found in the products navigation categories, then the lowest level navigation category is returned.
483 484 485 486 487 488 489 |
# File 'app/models/gemgento/product.rb', line 483 def current_category(category_id = nil, store = nil) @current_category ||= begin self.categories(store || Gemgento::Store.current).active..find(category_id) rescue ActiveRecord::RecordNotFound self.categories(store || Gemgento::Store.current).active..bottom_level.first! end end |
#get_configurable_attribute_ordering(store, active_only) ⇒ Hash(Hash(Array(Integer)))
Calculate the ordering of configurable attribute values
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 |
# File 'app/models/gemgento/product.rb', line 353 def get_configurable_attribute_ordering(store, active_only) store = Store.current if store.nil? order = {} if self.magento_type != 'configurable' && !self.configurable_products.empty? configurable_product = self.configurable_products.first else configurable_product = self end if active_only simple_products = configurable_product.simple_products.active.eager else simple_products = self.simple_products.eager end configurable_attributes = self.product_attribute_set.product_attributes. where(is_configurable: true, frontend_input: 'select', scope: 'global') configurable_attributes.each do |attribute| order[attribute.code] = [] simple_products = simple_products.sort_by do |simple_product| if o = simple_product..find_by(product_attribute: attribute, store: store) o.order else 0 end end mapping = {} simple_products.each do |simple_product| value = simple_product.attribute_value(attribute.code, store) mapping[value] = [] if mapping[value].nil? mapping[value] << simple_product.id unless mapping[value].include? simple_product.id end order[attribute.code] = [] mapping.each do |k, value| order[attribute.code] << { value: k, simple_product_ids: value } end end return order end |
#in_stock?(quantity = 1, store = nil) ⇒ Boolean
Determine if product has a specific inventory level.
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'app/models/gemgento/product.rb', line 166 def in_stock?(quantity = 1, store = nil) store = Store.current if store.nil? if self.magento_type == 'configurable' inventories = Inventory.where(product_id: self.simple_products.active.select(:id), store: store) if inventories.empty? # no inventories means inventory is not tracked return true else inventories.each do |inventory| return true if inventory.in_stock?(quantity) end return false end else if inventory = self.inventories.find_by(store: store) return inventory.in_stock?(quantity) else return true end end end |
#is_catalog_visible? ⇒ Boolean
Determine if the product is catalog visible.
402 403 404 |
# File 'app/models/gemgento/product.rb', line 402 def is_catalog_visible? return [2, 4].include?(self.visibility) end |
#manage_cache_expires_at ⇒ DateTime?
If the product has a cache_expires_at date set, make sure it hasn’t expired. If it has, set it again.
445 446 447 |
# File 'app/models/gemgento/product.rb', line 445 def manage_cache_expires_at self.set_cache_expires_at if self.cache_expires_at && self.cache_expires_at < Time.now end |
#mark_deleted ⇒ Void
Mark a product deleted.
194 195 196 197 |
# File 'app/models/gemgento/product.rb', line 194 def mark_deleted self.deleted_at = Time.now self.shopify_adapter.destroy if self.shopify_adapter end |
#mark_deleted! ⇒ Void
Mark a product deleted and save.
202 203 204 205 |
# File 'app/models/gemgento/product.rb', line 202 def mark_deleted! mark_deleted self.save end |
#on_sale?(user_group = nil, store = nil, quantity = 1.0) ⇒ Boolean
Determine if product is on sale.
327 328 329 |
# File 'app/models/gemgento/product.rb', line 327 def on_sale?(user_group = nil, store = nil, quantity = 1.0) return self.attribute_value('price', store).to_f != self.price(user_group, store, quantity) end |
#original_price(store = nil) ⇒ Float
Get the original, non sale, price for a product.
335 336 337 |
# File 'app/models/gemgento/product.rb', line 335 def original_price(store = nil) return self.attribute_value('price', store).to_f end |
#price(user_group = nil, store = nil, quantity = 1.0) ⇒ Object
Get the product price.
317 318 319 |
# File 'app/models/gemgento/product.rb', line 317 def price(user_group = nil, store = nil, quantity = 1.0) Gemgento::Price.new(self, user_group, store, quantity).calculate end |
#remove_from_active_quotes ⇒ Object
514 515 516 517 518 519 520 521 |
# File 'app/models/gemgento/product.rb', line 514 def remove_from_active_quotes self.line_items .joins('INNER JOIN gemgento_quotes ON gemgento_line_items.itemizable_id = gemgento_quotes.id') .joins('LEFT JOIN gemgento_orders ON gemgento_quotes.id = gemgento_orders.quote_id') .where(gemgento_line_items: { itemizable_type: 'Gemgento::Quote' }) .where(gemgento_orders: { id: nil }).where('gemgento_quotes.created_at >= ?', 30.days.ago) .destroy_all end |
#set_attribute_value(code, value, store = nil) ⇒ Boolean
Set an attribute value.
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'app/models/gemgento/product.rb', line 81 def set_attribute_value(code, value, store = nil) store = Store.current if store.nil? product_attribute = ProductAttribute.find_by(code: code) if product_attribute.nil? return false else # enforce a single attribute value per attribute per store per product product_attribute_values = ProductAttributeValue.where(product_id: self.id, product_attribute_id: product_attribute.id, store: store) if product_attribute_values.size > 1 ProductAttributeValue.where(product_id: self.id, product_attribute_id: product_attribute.id, store: store).where('id != ?', product_attribute_values.first.id).destroy_all end # set the attribute value product_attribute_value = ProductAttributeValue.where(product_id: self.id, product_attribute_id: product_attribute.id, store: store).first_or_initialize product_attribute_value.product = self product_attribute_value.product_attribute = product_attribute product_attribute_value.value = value product_attribute_value.store = store product_attribute_value.save! self.product_attribute_values << product_attribute_value unless self.product_attribute_values.include?(product_attribute_value) self.attribute_values = nil # reload cached attributes values return true end end |
#set_cache_expires_at ⇒ Void
Calculate the datetime that the product cache should expire.
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 |
# File 'app/models/gemgento/product.rb', line 452 def set_cache_expires_at self.cache_expires_at = nil Store.all.each do |store| UserGroup.all.each do |user_group| if Price.new(self, user_group, store).has_special? date = self.attribute_value('special_to_date', store) else date = PriceRule.first_to_expire(self, user_group, store) end next if date.nil? self.cache_expires_at = date if self.cache_expires_at.nil? || date < self.cache_expires_at end end self.sync_needed = false self.save end |
#set_configurable_products_by_magento_ids(magento_ids) ⇒ void
This method returns an undefined value.
Set the associated configurable products, using an array of Magento product IDs.
428 429 430 431 432 433 434 435 436 437 438 439 440 |
# File 'app/models/gemgento/product.rb', line 428 def set_configurable_products_by_magento_ids(magento_ids) configurable_product_ids = [] magento_ids.each do |magento_id| configurable_product = Product.active.find_by(magento_id: magento_id) next if configurable_product.nil? self.configurable_products << configurable_product unless self.configurable_products.include? configurable_product configurable_product_ids << configurable_product.id end self.configurable_products.delete(self.configurable_products.where('configurable_product_id NOT IN (?)', configurable_product_ids)) end |
#set_simple_products_by_magento_ids(magento_ids) ⇒ void
This method returns an undefined value.
Set the associated simple products, using an array of Magento product IDs.
410 411 412 413 414 415 416 417 418 419 420 421 422 |
# File 'app/models/gemgento/product.rb', line 410 def set_simple_products_by_magento_ids(magento_ids) simple_product_ids = [] magento_ids.each do |magento_id| simple_product = Product.active.find_by(magento_id: magento_id) next if simple_product.nil? self.simple_products << simple_product unless self.simple_products.include? simple_product simple_product_ids << simple_product.id end self.simple_products.delete(self.simple_products.where('simple_product_id NOT IN (?)', simple_product_ids)) end |
#simple? ⇒ Boolean
Check if the product is simple.
501 502 503 |
# File 'app/models/gemgento/product.rb', line 501 def simple? magento_type == 'simple' end |
#sync_needed? ⇒ Boolean
71 72 73 |
# File 'app/models/gemgento/product.rb', line 71 def sync_needed? self.sync_needed.to_bool end |
#to_param ⇒ Object
472 473 474 |
# File 'app/models/gemgento/product.rb', line 472 def to_param "#{self.id}-#{self.url_key}" end |