Class: ViewProductCatalog

Inherits:
ApplicationViewRecord show all
Includes:
Models::SaleDiscountable, Models::SearchableView
Defined in:
app/models/view_product_catalog.rb

Overview

== Schema Information

Table name: view_product_catalogs
Database name: primary

id :integer primary key
all_pl_paths_ids :ltree is an Array
all_pl_paths_slugs :ltree is an Array
alternate_warehouse_stock_reporting_max :integer
amazon_asin :string(10)
amazon_desired_product_type :string
amazon_fnsku :string
amazon_product_type_divergent :boolean
amazon_reported_product_type :string
amazon_title :text
amazon_variation_sku :string
amazon_variation_theme_name :string
amps :text
business_days_to_fulfill :integer
catalog_item_is_discontinued :boolean
catalog_item_state :string(30)
catalog_item_stock_reserved :integer
catalog_name :string(255)
clearance :boolean
country_of_origin :string(255)
coupon_code :string(255)
currency :string(255)
currency_symbol :string(255)
descendants_catalog_ids :integer is an Array
effective_price :decimal(8, 2)
effective_price_with_vat :decimal(, )
future_coupon_code :string(255)
future_coupon_effective_date :date
future_coupon_expiration_date :date
future_sale_price :decimal(8, 2)
future_sale_price_with_vat :decimal(, )
goods_vat_rate :decimal(6, 4)
google_feed :boolean
google_feed_title :string
gtin13 :text
hide_from_feed :boolean
inherited_item_product_category_ids :integer is an Array
inherited_item_product_line_ids :integer is an Array
item_condition :enum
item_grouping_identifier :string
item_is_discontinued :boolean
item_is_kit :boolean
item_is_web_accessible :boolean
item_name :text
item_parcel_oversize :boolean
item_primary_product_line_lineage_expanded :string(255)
item_primary_product_line_slug_ltree :ltree
item_shipping_class :enum
item_sku :string
map_percentage :decimal(5, 4)
map_price :decimal(, )
map_violation :boolean
max_discount :integer
msrp :decimal(8, 2)
old_price :decimal(10, 2)
option_name :text
parent_catalog_discount :decimal(5, 4)
parent_catalog_name :string(255)
parent_catalog_price :decimal(8, 2)
parent_price_updated_at :datetime
parent_sku :string
pc_path_ids :ltree
pc_path_slugs :ltree
price :decimal(8, 2)
price_difference :decimal(, )
price_difference_factor :decimal(, )
price_diverging :boolean
price_updated_at :datetime
price_updated_parent_differential_in_days :float
price_with_vat :decimal(, )
primary_pl_path_ids :ltree
primary_pl_path_slugs :ltree
product_category_lineage_expanded :text
product_category_name :string(255)
product_category_priority :integer
product_category_url :string(255)
product_line_ids :integer is an Array
product_specifications :jsonb
product_stock_status :text
retail_price :decimal(8, 2)
retailer_type :enum
sale_price :decimal(8, 2)
sale_price_effective_date :date
sale_price_expiration_date :date
sale_price_in_effect :boolean
sale_price_with_vat :decimal(, )
shipping_height_in :decimal(6, 2)
shipping_length_in :decimal(6, 2)
shipping_weight_lbs :decimal(8, 4)
shipping_width_in :decimal(6, 2)
short_description :string(120)
store_item_is_discontinued :boolean
store_item_qty_available :integer
store_item_qty_committed :integer
store_item_qty_on_hand :integer
store_item_unit_cogs :decimal(, )
successor_item_sku :string
third_party_part_number :string(255)
third_party_promo_part_number :string
third_party_sku :string
title :text
upc :string(255)
volts :text
watts :text
created_at :datetime
updated_at :datetime
amazon_variation_id :bigint
catalog_id :integer
catalog_item_id :integer
coupon_id :integer
future_coupon_id :integer
item_id :integer
item_primary_product_line_id :integer
item_product_category_id :integer
item_sales_portal_product_line_id :integer
new_item_id :integer
parent_catalog_item_id :integer
refurbished_item_id :integer
store_id :integer
store_item_id :integer
successor_item_id :integer

Constant Summary

Constants included from Schedulable

Schedulable::SIMPLE_FORM_OPTIONS

Belongs to collapse

Delegated Instance Attributes collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Models::SaleDiscountable

#amount, #effective_price, #money_effective_price, #money_price, #money_sale_price, #sale_price_in_effect?, #sale_price_percentage_off

Methods included from Models::SearchableView

#crm_link, #crm_link_subtitle, #has_columns?, #readonly?

Methods inherited from ApplicationViewRecord

create, create!, #readonly?

Methods inherited from ApplicationRecord

ransackable_associations, ransackable_attributes, ransortable_attributes, #to_relation

Methods included from Schedulable

config

Methods included from Models::AfterCommittable

#after_commit

Methods included from Models::EventPublishable

#publish_event

Class Method Details

.belongs_to_product_category_idActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are belongs to product category id. Active Record Scope

Returns:

See Also:



170
171
172
173
174
175
# File 'app/models/view_product_catalog.rb', line 170

scope :belongs_to_product_category_id, ->(*pc_ids) {
  ids = [pc_ids].flatten.compact.uniq
  return none if ids.empty?

  where.ltree_contains(:pc_path_ids, ids, array: false)
}

.belongs_to_product_line_idActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are belongs to product line id. Active Record Scope

Returns:

See Also:



162
163
164
165
166
167
# File 'app/models/view_product_catalog.rb', line 162

scope :belongs_to_product_line_id, ->(*pl_ids) {
  ids = [pl_ids].flatten.compact.uniq
  return none if ids.empty?

  where.ltree_contains(:all_pl_paths_ids, ids)
}

.clearanceActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are clearance. Active Record Scope

Returns:

See Also:



180
# File 'app/models/view_product_catalog.rb', line 180

scope :clearance, -> { where(clearance: true) }

.excluding_refurbishedActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are excluding refurbished. Active Record Scope

Returns:

See Also:



179
# File 'app/models/view_product_catalog.rb', line 179

scope :excluding_refurbished, -> { where.not('item_sku LIKE ?', '%-BTK') }

.latest_probe_out_of_stock_onlineActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are latest probe out of stock online. Active Record Scope

Returns:

See Also:



277
278
279
280
281
# File 'app/models/view_product_catalog.rb', line 277

scope :latest_probe_out_of_stock_online, ->(*args) {
  return all if args.any? && !ActiveModel::Type::Boolean.new.cast(args.first)

  where(catalog_item_id: CatalogItemRetailerProbe.current_out_of_stock_online_item_ids)
}

.latest_probe_scrape_failureActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are latest probe scrape failure. Active Record Scope

Returns:

See Also:



259
260
261
262
263
# File 'app/models/view_product_catalog.rb', line 259

scope :latest_probe_scrape_failure, ->(*args) {
  return all if args.any? && !ActiveModel::Type::Boolean.new.cast(args.first)

  where(catalog_item_id: CatalogItemRetailerProbe.current_scrape_failure_item_ids)
}

.latest_probe_unreachable_onlineActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are latest probe unreachable online. Active Record Scope

Returns:

See Also:



272
273
274
275
276
# File 'app/models/view_product_catalog.rb', line 272

scope :latest_probe_unreachable_online, ->(*args) {
  return all if args.any? && !ActiveModel::Type::Boolean.new.cast(args.first)

  where(catalog_item_id: CatalogItemRetailerProbe.current_unreachable_online_item_ids)
}

.locale_to_catalogActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are locale to catalog. Active Record Scope

Returns:

See Also:



159
# File 'app/models/view_product_catalog.rb', line 159

scope :locale_to_catalog, ->(locale = I18n.locale) { where(catalog_id: Catalog.locale_to_catalog_id(locale)) }

.main_resource_classObject



322
323
324
# File 'app/models/view_product_catalog.rb', line 322

def self.main_resource_class
  'CatalogItem'
end

.map_violationsActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are map violations. Active Record Scope

Returns:

See Also:



244
# File 'app/models/view_product_catalog.rb', line 244

scope :map_violations, -> { where(map_violation: true) }

.on_saleActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are on sale. Active Record Scope

Returns:

See Also:



178
# File 'app/models/view_product_catalog.rb', line 178

scope :on_sale, -> { where(sale_price_in_effect: true) }

.open_listing_issueActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are open listing issue. Active Record Scope

Returns:

See Also:



267
268
269
270
271
# File 'app/models/view_product_catalog.rb', line 267

scope :open_listing_issue, ->(*args) {
  return all if args.any? && !ActiveModel::Type::Boolean.new.cast(args.first)

  where(catalog_item_id: ListingIssue.open_item_ids)
}

.price_sortedActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are price sorted. Active Record Scope

Returns:

See Also:



157
# File 'app/models/view_product_catalog.rb', line 157

scope :price_sorted, -> { order(:sale_price, :price) }

.price_updated_since_daysActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are price updated since days. Active Record Scope

Returns:

See Also:



158
# File 'app/models/view_product_catalog.rb', line 158

scope :price_updated_since_days, ->(days) { where(ViewProductCatalog[:price_updated_at].gteq(days.to_i.days.ago)) }

.primary_catalogs_firstActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are primary catalogs first. Active Record Scope

Returns:

See Also:



292
293
294
295
# File 'app/models/view_product_catalog.rb', line 292

scope :primary_catalogs_first, -> {
  in_order_of(:catalog_id, CatalogConstants::ALL_MAIN_CATALOG_IDS, filter: false)
    .order(:item_sku)
}

.ransackable_scopes(_auth_object = nil) ⇒ Object

Expose ltree-powered scopes, spec filters, and search-form scopes to Ransack



303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'app/models/view_product_catalog.rb', line 303

def self.ransackable_scopes(_auth_object = nil)
  super + %i[
    belongs_to_product_line_id
    belongs_to_product_category_id
    price_updated_since_days
    spec_finish_eq
    spec_finish_in
    spec_towel_bars_eq
    spec_bar_shape_eq
    spec_connection_method_eq
    spec_mounting_method_eq
    spec_size_eq
    latest_probe_scrape_failure
    latest_probe_unreachable_online
    latest_probe_out_of_stock_online
    open_listing_issue
  ]
end

.refurbishedActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are refurbished. Active Record Scope

Returns:

See Also:



177
# File 'app/models/view_product_catalog.rb', line 177

scope :refurbished, -> { where(item_condition: 'refurbished').where.not(new_item_id: nil) }

.refurbished_or_clearanceActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are refurbished or clearance. Active Record Scope

Returns:

See Also:



242
# File 'app/models/view_product_catalog.rb', line 242

scope :refurbished_or_clearance, -> { refurbished.or(clearance) }

.spec_bar_shape_eqActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are spec bar shape eq. Active Record Scope

Returns:

See Also:



202
203
204
205
206
# File 'app/models/view_product_catalog.rb', line 202

scope :spec_bar_shape_eq, ->(value) {
  return all if value.blank?

  where("product_specifications -> 'bar_shape' ->> 'raw' ILIKE ?", "%#{value}%")
}

.spec_connection_method_eqActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are spec connection method eq. Active Record Scope

Returns:

See Also:



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'app/models/view_product_catalog.rb', line 207

scope :spec_connection_method_eq, ->(value) {
  return all if value.blank?

  # Dual connection products ("Plug-in or Hardwired") work as both plug-in AND hardwired
  # So when filtering by Plug-in or Hardwired, include dual connection products too
  case value
  when 'Plug-in'
    where("product_specifications -> 'connection_method' ->> 'raw' ILIKE ? OR product_specifications -> 'connection_method' ->> 'raw' ILIKE ?",
          'Plug-in', 'Plug-in or Hardwired')
  when 'Hardwired'
    where("product_specifications -> 'connection_method' ->> 'raw' ILIKE ? OR product_specifications -> 'connection_method' ->> 'raw' ILIKE ?",
          'Hardwired', 'Plug-in or Hardwired')
  else
    # For "Plug-in or Hardwired" (dual connection) - exact match only
    where("product_specifications -> 'connection_method' ->> 'raw' ILIKE ?", value)
  end
}

.spec_finish_eqActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are spec finish eq. Active Record Scope

Returns:

See Also:



185
186
187
188
189
# File 'app/models/view_product_catalog.rb', line 185

scope :spec_finish_eq, ->(value) {
  return all if value.blank?

  where("product_specifications -> 'finish' ->> 'raw' ILIKE ?", value)
}

.spec_finish_inActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are spec finish in. Active Record Scope

Returns:

See Also:



190
191
192
193
194
195
# File 'app/models/view_product_catalog.rb', line 190

scope :spec_finish_in, ->(*args) {
  values = args.flatten
  return all if values.blank?

  where("product_specifications -> 'finish' ->> 'raw' ILIKE ANY (ARRAY[?])", values)
}

.spec_mounting_method_eqActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are spec mounting method eq. Active Record Scope

Returns:

See Also:



224
225
226
227
228
229
230
# File 'app/models/view_product_catalog.rb', line 224

scope :spec_mounting_method_eq, ->(value) {
  return all if value.blank?

  # Use partial matching with leading wildcard only for mounting
  # This allows "Wall Mounted" to match "Wall Mounted (20\" x 20 1/2\")" etc.
  where("product_specifications -> 'mounting_method' ->> 'raw' ILIKE ?", "#{value}%")
}

.spec_size_eqActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are spec size eq. Active Record Scope

Returns:

See Also:



234
235
236
237
238
239
240
241
# File 'app/models/view_product_catalog.rb', line 234

scope :spec_size_eq, ->(slug) {
  return all if slug.blank?

  label = TowelWarmerFilterSlugs::SIZE_LABELS[slug]
  return none unless label

  where("product_specifications -> 'size_classification' ->> 'raw' = ?", label)
}

.spec_towel_bars_eqActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are spec towel bars eq. Active Record Scope

Returns:

See Also:



196
197
198
199
200
201
# File 'app/models/view_product_catalog.rb', line 196

scope :spec_towel_bars_eq, ->(value) {
  return all if value.blank?

  # Towel bars can be a range like "4-6" or "12+" - match if raw contains the value
  where("product_specifications -> 'towel_bars' ->> 'raw' ILIKE ?", "%#{value}%")
}

.valid_for_google_local_inventoryActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are valid for google local inventory. Active Record Scope

Returns:

See Also:



284
285
286
287
288
289
290
# File 'app/models/view_product_catalog.rb', line 284

scope :valid_for_google_local_inventory, -> {
  where(item_condition: 'new')
    .where(ViewProductCatalog[:shipping_weight_lbs].gt(0))
    .where(ViewProductCatalog[:shipping_height_in].gt(0))
    .where(ViewProductCatalog[:shipping_length_in].gt(0))
    .where(ViewProductCatalog[:shipping_width_in].gt(0))
}

.vendor_catalogsActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are vendor catalogs. Active Record Scope

Returns:

See Also:



243
# File 'app/models/view_product_catalog.rb', line 243

scope :vendor_catalogs, -> { where(retailer_type: 'vendor') }

.visible_to_publicActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are visible to public. Active Record Scope

Returns:

See Also:



160
# File 'app/models/view_product_catalog.rb', line 160

scope :visible_to_public, -> { where(item_is_web_accessible: true) }

.with_stockActiveRecord::Relation<ViewProductCatalog>

A relation of ViewProductCatalogs that are with stock. Active Record Scope

Returns:

See Also:



176
# File 'app/models/view_product_catalog.rb', line 176

scope :with_stock, -> { where(store_item_qty_available: 1..) }

Instance Method Details

#active?Boolean

Returns:

  • (Boolean)


330
331
332
# File 'app/models/view_product_catalog.rb', line 330

def active?
  catalog_item_state == 'active'
end

#availabilityObject



405
406
407
# File 'app/models/view_product_catalog.rb', line 405

def availability
  product_stock_status
end

#bulky?Boolean

Returns:

  • (Boolean)


384
385
386
# File 'app/models/view_product_catalog.rb', line 384

def bulky?
  ships_freight? || item_parcel_oversize
end

#cache_keyObject



326
327
328
# File 'app/models/view_product_catalog.rb', line 326

def cache_key
  "#{self.class.model_name.cache_key}/#{id}-#{product_stock_status}-#{updated_at.utc.to_fs(:number)}"
end

#catalog_itemCatalogItem



134
# File 'app/models/view_product_catalog.rb', line 134

belongs_to :catalog_item, primary_key: :id, optional: true

#couponCoupon

Returns:

See Also:



141
# File 'app/models/view_product_catalog.rb', line 141

belongs_to :coupon

#effective_seo_descriptionObject

Alias for Catalog_item#effective_seo_description

Returns:

  • (Object)

    Catalog_item#effective_seo_description

See Also:



298
# File 'app/models/view_product_catalog.rb', line 298

delegate :seo_title, :effective_seo_description, :msrp, :msrp_with_vat, to: :catalog_item

#facetObject

Alias for Item#facet

Returns:

  • (Object)

    Item#facet

See Also:



297
# File 'app/models/view_product_catalog.rb', line 297

delegate :item_available_locales, :facet, :facet_tokens, :facet_sort_keys, to: :item

#facet_sort_keysObject

Alias for Item#facet_sort_keys

Returns:

  • (Object)

    Item#facet_sort_keys

See Also:



297
# File 'app/models/view_product_catalog.rb', line 297

delegate :item_available_locales, :facet, :facet_tokens, :facet_sort_keys, to: :item

#facet_tokensObject

Alias for Item#facet_tokens

Returns:

  • (Object)

    Item#facet_tokens

See Also:



297
# File 'app/models/view_product_catalog.rb', line 297

delegate :item_available_locales, :facet, :facet_tokens, :facet_sort_keys, to: :item

#itemItem

Returns:

See Also:



139
# File 'app/models/view_product_catalog.rb', line 139

belongs_to :item

#item_available_localesObject

Alias for Item#item_available_locales

Returns:

  • (Object)

    Item#item_available_locales

See Also:



297
# File 'app/models/view_product_catalog.rb', line 297

delegate :item_available_locales, :facet, :facet_tokens, :facet_sort_keys, to: :item

#localeObject

Helper method for now, TODO need to be something more robust in the future



335
336
337
# File 'app/models/view_product_catalog.rb', line 335

def locale
  Catalog.catalog_id_to_locale(catalog_id)
end

#msrpObject

Alias for Catalog_item#msrp

Returns:

  • (Object)

    Catalog_item#msrp

See Also:



298
# File 'app/models/view_product_catalog.rb', line 298

delegate :seo_title, :effective_seo_description, :msrp, :msrp_with_vat, to: :catalog_item

#msrp_with_vatObject

Alias for Catalog_item#msrp_with_vat

Returns:

  • (Object)

    Catalog_item#msrp_with_vat

See Also:



298
# File 'app/models/view_product_catalog.rb', line 298

delegate :seo_title, :effective_seo_description, :msrp, :msrp_with_vat, to: :catalog_item

#price_difference_factor_humanObject



388
389
390
391
392
# File 'app/models/view_product_catalog.rb', line 388

def price_difference_factor_human
  return unless price_difference_factor

  "#{(price_difference_factor * 100).round(2)} %"
end

#primary_product_lineProductLine



135
# File 'app/models/view_product_catalog.rb', line 135

belongs_to :primary_product_line, class_name: 'ProductLine', foreign_key: :item_primary_product_line_id, optional: true

#product_available?Boolean

Returns:

  • (Boolean)


401
402
403
# File 'app/models/view_product_catalog.rb', line 401

def product_available?
  product_stock_status == 'InStock'
end

#product_categoryProductCategory



136
# File 'app/models/view_product_catalog.rb', line 136

belongs_to :product_category, class_name: 'ProductCategory', foreign_key: :item_product_category_id, optional: true

#product_type(separator: nil, limit: nil) ⇒ Object



394
395
396
397
398
399
# File 'app/models/view_product_catalog.rb', line 394

def product_type(separator: nil, limit: nil)
  Feed::ProductTypeGenerator.process(product_line: primary_product_line,
                                     product_category:,
                                     separator:,
                                     limit:)
end

#refurbished_itemItem

Returns:

See Also:



140
# File 'app/models/view_product_catalog.rb', line 140

belongs_to :refurbished_item, class_name: 'Item'

#sales_portal_product_lineProductLine



137
# File 'app/models/view_product_catalog.rb', line 137

belongs_to :sales_portal_product_line, class_name: 'ProductLine', foreign_key: :item_sales_portal_product_line_id, optional: true

#seo_titleObject

Alias for Catalog_item#seo_title

Returns:

  • (Object)

    Catalog_item#seo_title

See Also:



298
# File 'app/models/view_product_catalog.rb', line 298

delegate :seo_title, :effective_seo_description, :msrp, :msrp_with_vat, to: :catalog_item

#ships_freight?Boolean

Returns:

  • (Boolean)


380
381
382
# File 'app/models/view_product_catalog.rb', line 380

def ships_freight?
  Item.shipping_classes.invert[item_shipping_class] == 'freight_service'
end

#spec(token) ⇒ Object



339
340
341
342
343
344
# File 'app/models/view_product_catalog.rb', line 339

def spec(token)
  return unless (ps = product_specifications[token.to_sym])

  ps[:raw] = TypeCoercer.coerce(ps[:raw])
  ps
end

#spec_image(token) ⇒ Object



374
375
376
377
378
# File 'app/models/view_product_catalog.rb', line 374

def spec_image(token)
  return unless (iid = spec(token)&.dig(:image_id))

  Image.find(iid)
end

#spec_output(token) ⇒ Object



346
347
348
# File 'app/models/view_product_catalog.rb', line 346

def spec_output(token)
  spec(token)&.dig(:output)&.dup
end

#spec_value(token, output_unit: nil) ⇒ Numeric, ...

Returns the raw value from the spec, optionally converted to a target unit.
Used by facet sorting to normalize values stored in different units.

Parameters:

  • token (Symbol, String)

    the spec token (e.g., :width, :length)

  • output_unit (String, nil) (defaults to: nil)

    target unit for conversion (e.g., 'in', 'ft', 'lbs')

Returns:

  • (Numeric, String, nil)

    the spec value, converted if output_unit specified



355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# File 'app/models/view_product_catalog.rb', line 355

def spec_value(token, output_unit: nil)
  return unless (ps = spec(token))
  return unless (v = ps.dig(:raw))

  v = TypeCoercer.coerce(v)

  if output_unit.present? && (current_unit = ps.dig(:units)).present? && current_unit.to_s != output_unit.to_s
    begin
      current = RubyUnits::Unit.new("#{v} #{current_unit}")
      target = RubyUnits::Unit.new("1 #{output_unit}")
      v = current.convert_to(output_unit.to_s).scalar.to_f if current.compatible?(target)
    rescue ArgumentError, RubyUnits::Unit::ArgumentError
      # Unit conversion failed (incompatible or unknown units), return original value
    end
  end

  v
end

#store_itemStoreItem

Returns:

See Also:



138
# File 'app/models/view_product_catalog.rb', line 138

belongs_to :store_item