Class: Item
- Inherits:
-
ApplicationRecord
show all
- Includes:
- Memery, Models::Auditable, Models::CrossLinkable, Models::Embeddable, Models::ItemAmazonHelper, Models::ItemLtreeSync, Models::ItemPackageContentHelper, Models::ItemScopable, Models::ItemSpecificationHelper, Models::Kittable, Models::LiquidMethods, Models::Publication, Models::Taggable, Models::Translatable, Models::Utilities::Html, PgSearch::Model
- Defined in:
- app/models/item.rb
Overview
The Item model represents products in the inventory system.
Items can be physical goods, services, kits, or publications.
Includes pricing, specifications, product categorization, and e-commerce functionality.
== Schema Information
Table name: items(Product catalog table containing SKU and product metadata.)
Database name: primary
id :integer not null, primary key
all_pl_paths_ids :ltree default([]), is an Array
all_pl_paths_slugs :ltree is an Array
alternative_volts :string default([]), is an Array
always_available_online :boolean
amazon_asin :string(10)
amazon_optimized_listing :boolean default(FALSE), not null
base_weight :decimal(8, 4)
box2_shipping_height :decimal(6, 2)
box2_shipping_length :decimal(6, 2)
box2_shipping_weight :decimal(8, 4)
box2_shipping_width :decimal(6, 2)
box3_shipping_height :decimal(6, 2)
box3_shipping_length :decimal(6, 2)
box3_shipping_weight :decimal(8, 4)
box3_shipping_width :decimal(6, 2)
condition :enum default("new")
content_url :string
coo :string(255)
cycle_count_grouping :enum default("warehouse")
detailed_description_html :text
disable_heuristic_accessories :boolean default(FALSE), not null
display_treatment :integer
do_not_replenish :boolean default(FALSE), not null
dropship :boolean
feature_1 :string
feature_2 :string
feature_3 :string
feature_4 :string
feature_5 :string
featured_position :integer default(100), not null
first_sale_date :date
gross_weight :decimal(8, 4)
grouping :string
harmonization_code :string(255)
ideal_cable_spacing :float
ignore_product_line_on_item_view :boolean default(FALSE), not null
is_cable_system :boolean
is_discontinued :boolean default(FALSE), not null
is_kit :boolean default(FALSE), not null
item_category :string(255)
last_sale_date :date
legacy_accessories_specs :jsonb
legacy_image_path :string(255)
legacy_qty_out_of_stock :integer default(2), not null
legacy_ship_line_type :string(255) default("S")
legacy_specifications :string(255)
moq :integer
name :string(255)
option_name :string
oversize :boolean default(FALSE), not null
pc_path_ids :ltree
pc_path_slugs :ltree
pdf_image_descriptions :text
pdf_images_analyzed_at :datetime
popularity :integer default(0)
popularity_offset :integer default(0), not null
primary_pl_path_ids :ltree
primary_pl_path_slugs :ltree
product_packaging_flag_audited :boolean default(FALSE), not null
product_weight_flag_audited :boolean default(FALSE), not null
public_short_name :string(255)
publication_base_name :string
publication_locales :string is an Array
qty_warn_on_stock :integer default(5), not null
redirection_path :string
rendered_product_specifications :jsonb
rendered_product_specifications_at :datetime
requested_counter :integer default(0), not null
require_reservation :boolean
restricted_for_sales :boolean default(FALSE), not null
review_product_packaging_flag :boolean default(FALSE), not null
review_product_weight_flag :boolean default(FALSE), not null
search_keywords :text
search_text :text
search_text_tsv :tsvector
secondary_model_number :string
seo_description :text
seo_keywords :string
seo_title :string
shipping_class :enum default("parcel_service"), not null
shipping_height :decimal(6, 2)
shipping_length :decimal(6, 2)
shipping_weight :decimal(8, 4)
shipping_width :decimal(6, 2)
short_description :string(120)
skip_serial_number_reservation_screen :boolean
sku(WarmlyYours SKU code. Use LIKE filters for product family searches.) :string not null
sku_aliases :string default([]), is an Array
slug :string
support_priority :integer default(1000)
tax_class :string(3) not null
terms_and_conditions :text
terms_of_service :text
translations :jsonb
unique_kit_dimensions :boolean default(FALSE), not null
unlimited_inventory :boolean default(FALSE), not null
unspsc_code :string(8)
uom :string default("each"), not null
upc :string(255)
upc_on_box :boolean default(FALSE), not null
visible_for_support :boolean default(TRUE), not null
created_at :datetime
updated_at :datetime
amazon_variation_id :integer
brand_id :integer
creator_id :integer
exclusive_item_group_id :integer
literature_id :integer
new_item_id :integer
packaging_discrepancy_packing_id :integer
preferred_supplier_id :integer
primary_image_id :integer
primary_product_line_id(Primary product line foreign key for grouping and categorization.) :integer
product_category_id :integer
product_tax_code_id :integer
replacement_for_id :integer
secondary_product_category_id :integer
successor_item_id :integer
supplier_item_id :integer
updater_id :integer
upload_id :integer
Indexes
idx_items_all_pl_paths_ids (all_pl_paths_ids) USING gin
idx_items_pc_path_ids (pc_path_ids) USING gist
idx_items_primary_pl_path_ids (primary_pl_path_ids) USING gist
idx_pc_id_discontinued_kit (product_category_id,is_discontinued,is_kit)
idx_pc_id_is_disc_created (product_category_id,is_discontinued,created_at)
idx_pc_id_literature_id (product_category_id,literature_id)
idx_ppl_id_product_cat_id (primary_product_line_id,product_category_id)
idx_product_cat_id_created_at (product_category_id,created_at)
idx_product_category_id_id (product_category_id,id)
idx_upload_id (upload_id)
index_items_name_like (name)
index_items_on_all_pl_paths_slugs (all_pl_paths_slugs) USING gist
index_items_on_amazon_asin (amazon_asin) UNIQUE
index_items_on_amazon_variation_id (amazon_variation_id)
index_items_on_brand_id (brand_id)
index_items_on_condition (condition)
index_items_on_exclusive_item_group_id (exclusive_item_group_id)
index_items_on_is_discontinued (is_discontinued)
index_items_on_is_kit (is_kit)
index_items_on_literature_id (literature_id)
index_items_on_new_item_id (new_item_id)
index_items_on_pc_path_slugs (pc_path_slugs) USING gist
index_items_on_primary_pl_path_slugs (primary_pl_path_slugs) USING gist
index_items_on_product_tax_code_id (product_tax_code_id)
index_items_on_publication_locales (publication_locales) USING gin
index_items_on_search_text_tsv (search_text_tsv) USING gin
index_items_on_secondary_model_number (secondary_model_number) WHERE (secondary_model_number IS NOT NULL)
index_items_on_secondary_product_category_id (secondary_product_category_id)
index_items_on_sku (sku) UNIQUE
index_items_on_sku_aliases (sku_aliases) USING gin
index_items_on_successor_item_id (successor_item_id)
index_items_on_upc_and_condition (upc,condition) UNIQUE
index_items_sku_like (sku) USING gin
items_product_category_id_condition_primary_product_line_id_idx (product_category_id,condition,primary_product_line_id)
items_rendered_product_specifications_idx (rendered_product_specifications) USING gin
items_supplier_item_id_idx (supplier_item_id)
Foreign Keys
fk_rails_... (amazon_variation_id => amazon_variations.id)
fk_rails_... (brand_id => brands.id)
fk_rails_... (new_item_id => items.id)
fk_rails_... (packaging_discrepancy_packing_id => packings.id) ON DELETE => nullify
fk_rails_... (primary_product_line_id => product_lines.id)
fk_rails_... (product_tax_code_id => product_tax_codes.id)
fk_rails_... (secondary_product_category_id => product_categories.id)
fk_rails_... (successor_item_id => items.id)
items_product_category_id_fk (product_category_id => product_categories.id)
items_supplier_item_id_fk (supplier_item_id => supplier_items.id) ON DELETE => cascade
Defined Under Namespace
Classes: AmazonFnskuBarcode, ArchiveItem, ArticleRetriever, Auditor, AvailabilityDateChecker, Cloner, ConvertElectricalSpecs, CopyRelatedItemsFromSiblings, CustomMatCreator, CycleCountPrioritizer, CycleCountScheduler, DataMatrixBarcode, FloorPlanRetriever, HeatingElementLine, HeatingElementPlan, ImageLibraryPlPcLadder, ImageLibraryRetriever, ImageRetriever, InventoryCommitter, KitAttributeGenerator, KitComposer, KitConsolidator, MapSpecToTemplate, MarketingCycleCountScheduler, PopulateItemPopularity, PrepareNewKitComponent, ProductSpecificationsCloner, PublicationRetriever, ShippingBoxCalculator, SpecFixer, SpecificationsMasher, SpecificationsRetriever, SuggestedItemTool, SupportQrCode, SynchronizeRefurbSpecs, UpcBarcode, UpcMaker, VideoRetriever
Constant Summary
collapse
- TRANSLATABLE_ATTRIBUTES =
%i[detailed_description_html feature_1 feature_2 feature_3 feature_4 feature_5 name option_name public_short_name
search_keywords seo_description seo_keywords seo_title short_description terms_and_conditions terms_of_service].freeze
- TRANSLATION_NAMESPACE =
'ItemAttributes'
- SKU_REGEXP =
/\A\w[\w\-.]+\w\z/
- AMAZON_ASIN_REGEXP =
/\b[A-Z0-9]{10}\b/
- DISPLAY_TREATMENT_HIDE_QUANTITIES =
Display treatment hide quantities.
0
- SINGLE_QUANTITY_SKUS =
Put sku in here that needs their own line always
[].freeze
- DOUBLE_POLE_VOLTAGES =
[208.0, 240.0].freeze
- FORECAST_EXCLUDED_SKU_PREFIXES =
SKU prefixes excluded from demand forecasting (custom/discontinued/special items)
%w[cth-dis- cths- cthx- ffx- tmcs tms-sp].freeze
- SMARTPRESET_SERVICE_SKU =
%w[SMARTPRESETFORM-USA-A SMARTPRESETFORM-CAN-A SMART-PRESET-FORM-B SMART-PRESET-OJ-FORM-A SMART-PRESET-OJ-FORM-B].freeze
- CI_EXIST_CHECK_SQL =
'select 1 from catalog_items ci inner join store_items si on ci.store_item_id = si.id where si.item_id = items.id and si.is_discontinued = false'
Models::Publication::CACHE_RELEVANT_ATTRIBUTES, Models::Publication::PUBLIC_LOCALES
Models::Embeddable::MAX_CONTENT_LENGTH
Models::ItemSpecificationHelper::PER_ITEM_SPEC_TOKENS
Models::Auditable::ALWAYS_IGNORED
Constants included
from Schedulable
Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
#available_in_canada, #available_in_usa, #serve_in_locale
#do_not_compact_translation_container
#skip_ltree_sync
#amazon_variation
#creator, #updater
#amazon_marketplaces, #amazon_transparency_codes
#inbound_content_links, #outbound_content_links
#item_embeddings
#content_embeddings
#tag_records, #taggings
#kit_components, #kit_components_for_specs, #kit_parents, #kit_source_item_relations, #kit_target_item_relations, #kit_target_item_relations_for_specs
Has and belongs to many
collapse
Delegated Instance Attributes
collapse
Class Method Summary
collapse
-
.accessories ⇒ ActiveRecord::Relation<Item>
A relation of Items that are accessories.
-
.active ⇒ ActiveRecord::Relation<Item>
A relation of Items that are active.
-
.active_in_catalog_ids ⇒ ActiveRecord::Relation<Item>
A relation of Items that are active in catalog ids.
-
.all_locales ⇒ Object
NOTE: all_tags method provided by Models::Taggable concern.
-
.async_update_all_items_product_specifications(public_only: true, active_only: true, limit: nil, not_updated_since: nil) ⇒ Object
-
.available_to_public ⇒ ActiveRecord::Relation<Item>
A relation of Items that are available to public.
-
.available_to_public_for_support ⇒ ActiveRecord::Relation<Item>
A relation of Items that are available to public for support.
-
.by_primary_product_line_ids_with_descendants ⇒ ActiveRecord::Relation<Item>
A relation of Items that are by primary product line ids with descendants.
-
.canonical_search ⇒ ActiveRecord::Relation<Item>
A relation of Items that are canonical search.
-
.category_sorted ⇒ ActiveRecord::Relation<Item>
A relation of Items that are category sorted.
-
.cold_leads ⇒ ActiveRecord::Relation<Item>
A relation of Items that are cold leads.
-
.condition_select_options ⇒ Object
-
.controls ⇒ ActiveRecord::Relation<Item>
A relation of Items that are controls.
-
.countertop_heaters ⇒ ActiveRecord::Relation<Item>
A relation of Items that are countertop heaters.
-
.custom_mats ⇒ ActiveRecord::Relation<Item>
A relation of Items that are custom mats.
-
.discontinued ⇒ ActiveRecord::Relation<Item>
A relation of Items that are discontinued.
-
.dropships ⇒ ActiveRecord::Relation<Item>
A relation of Items that are dropships.
-
.easystats ⇒ ActiveRecord::Relation<Item>
A relation of Items that are easystats.
-
.electrical_plan_controls ⇒ ActiveRecord::Relation<Item>
A relation of Items that are electrical plan controls.
-
.excludes_forecast_skus ⇒ ActiveRecord::Relation<Item>
A relation of Items that are excludes forecast skus.
-
.floor_heating_controls ⇒ ActiveRecord::Relation<Item>
A relation of Items that are floor heating controls.
-
.floor_heating_elements ⇒ ActiveRecord::Relation<Item>
A relation of Items that are floor heating elements.
-
.for_support_portal ⇒ ActiveRecord::Relation<Item>
A relation of Items that are for support portal.
-
.forecastable ⇒ ActiveRecord::Relation<Item>
A relation of Items that are forecastable.
-
.get_infrared_heating_panel_tstat_options_for_web_and_apply_overrides(connection_method, tstat_options_override = [], available_in_catalog_id: nil) ⇒ Object
Here we want a static web page (e.g. app/views/pages/infrared-heating-panels) to use the same source of SKUs as Item does but allow it to override some of the stuff, including the order:.
-
.get_quantity_from_items_and_sqft(catalog_id, items, sqft, add_one_extra_of_last_item = false) ⇒ Object
-
.get_towel_warmer_tstat_options_for_web_and_apply_overrides(connection_method, tstat_options_override = [], available_in_catalog_id: nil) ⇒ Object
Here we want a static web page (e.g. app/views/pages/towel-warmer/controls) to use the same source of SKUs as Item does but allow it to override some of the stuff, including the order:.
-
.goods ⇒ ActiveRecord::Relation<Item>
A relation of Items that are goods.
-
.goods_and_services_for_public ⇒ ActiveRecord::Relation<Item>
A relation of Items that are goods and services for public.
-
.goods_visible_for_support ⇒ ActiveRecord::Relation<Item>
A relation of Items that are goods visible for support.
-
.has_floor_sensor ⇒ ActiveRecord::Relation<Item>
A relation of Items that are has floor sensor.
-
.heating_elements ⇒ ActiveRecord::Relation<Item>
A relation of Items that are heating elements.
-
.identifiers_search ⇒ ActiveRecord::Relation<Item>
A relation of Items that are identifiers search.
-
.import_translation_keys ⇒ Object
-
.in_store ⇒ ActiveRecord::Relation<Item>
A relation of Items that are in store.
-
.indexable ⇒ ActiveRecord::Relation<Item>
A relation of Items that are indexable.
-
.infrared_heating_panel_controls_dual_connect ⇒ ActiveRecord::Relation<Item>
A relation of Items that are infrared heating panel controls dual connect.
-
.infrared_heating_panel_controls_hardwired ⇒ ActiveRecord::Relation<Item>
A relation of Items that are infrared heating panel controls hardwired.
-
.infrared_heating_panel_controls_plug_in ⇒ ActiveRecord::Relation<Item>
A relation of Items that are infrared heating panel controls plug in.
-
.infrared_heating_panels ⇒ ActiveRecord::Relation<Item>
A relation of Items that are infrared heating panels.
-
.infrared_heating_panels_hardwired ⇒ ActiveRecord::Relation<Item>
A relation of Items that are infrared heating panels hardwired.
-
.install_kits ⇒ ActiveRecord::Relation<Item>
A relation of Items that are install kits.
-
.insulations ⇒ ActiveRecord::Relation<Item>
A relation of Items that are insulations.
-
.integration_kits ⇒ ActiveRecord::Relation<Item>
A relation of Items that are integration kits.
-
.item_identifier_label_sizes_select_options ⇒ Object
-
.last_custom_mat_item ⇒ Object
-
.membranes ⇒ ActiveRecord::Relation<Item>
A relation of Items that are membranes.
-
.mirror_defoggers ⇒ ActiveRecord::Relation<Item>
A relation of Items that are mirror defoggers.
-
.mirrors ⇒ ActiveRecord::Relation<Item>
A relation of Items that are mirrors.
-
.missing_shipping_dimensions ⇒ ActiveRecord::Relation<Item>
A relation of Items that are missing shipping dimensions.
-
.needs_packaging_reviewed ⇒ ActiveRecord::Relation<Item>
A relation of Items that are needs packaging reviewed.
-
.needs_weight_reviewed ⇒ ActiveRecord::Relation<Item>
A relation of Items that are needs weight reviewed.
-
.non_dropships ⇒ ActiveRecord::Relation<Item>
A relation of Items that are non dropships.
-
.non_kits ⇒ ActiveRecord::Relation<Item>
A relation of Items that are non kits.
-
.non_publications ⇒ ActiveRecord::Relation<Item>
A relation of Items that are non publications.
-
.non_shipping ⇒ ActiveRecord::Relation<Item>
A relation of Items that are non shipping.
-
.not_a_target_item ⇒ ActiveRecord::Relation<Item>
A relation of Items that are not a target item.
-
.oj_programmable_tstats ⇒ ActiveRecord::Relation<Item>
A relation of Items that are oj programmable tstats.
-
.oj_tstats ⇒ ActiveRecord::Relation<Item>
A relation of Items that are oj tstats.
-
.order_by_spec ⇒ ActiveRecord::Relation<Item>
A relation of Items that are order by spec.
-
.order_towel_warmer_controls_hardwired ⇒ ActiveRecord::Relation<Item>
A relation of Items that are order towel warmer controls hardwired.
-
.orderable_online ⇒ ActiveRecord::Relation<Item>
A relation of Items that are orderable online.
-
.out_of_stock ⇒ ActiveRecord::Relation<Item>
A relation of Items that are out of stock.
-
.packageable ⇒ ActiveRecord::Relation<Item>
A relation of Items that are packageable.
-
.power_modules ⇒ ActiveRecord::Relation<Item>
A relation of Items that are power modules.
-
.powers ⇒ ActiveRecord::Relation<Item>
A relation of Items that are powers.
-
.primary_product_line_slug_ltree_cont ⇒ ActiveRecord::Relation<Item>
A relation of Items that are primary product line slug ltree cont.
-
.public_and_active_in_any_catalogs ⇒ ActiveRecord::Relation<Item>
A relation of Items that are public and active in any catalogs.
-
.public_and_active_in_catalog_id ⇒ ActiveRecord::Relation<Item>
A relation of Items that are public and active in catalog id.
-
.publications_search ⇒ ActiveRecord::Relation<Item>
A relation of Items that are publications search.
-
.ransackable_scopes(_auth_object = nil) ⇒ Object
-
.relay_panels ⇒ ActiveRecord::Relation<Item>
A relation of Items that are relay panels.
-
.remote_services ⇒ ActiveRecord::Relation<Item>
A relation of Items that are remote services.
-
.rendered_product_specs_keys ⇒ Object
-
.rendered_product_specs_options_for_select(spec_key) ⇒ Object
-
.reservable ⇒ ActiveRecord::Relation<Item>
A relation of Items that are reservable.
-
.reviewable ⇒ ActiveRecord::Relation<Item>
A relation of Items that are reviewable.
-
.rough_in_kits ⇒ ActiveRecord::Relation<Item>
A relation of Items that are rough in kits.
-
.sensors ⇒ ActiveRecord::Relation<Item>
A relation of Items that are sensors.
-
.services ⇒ ActiveRecord::Relation<Item>
A relation of Items that are services.
-
.shipping ⇒ ActiveRecord::Relation<Item>
A relation of Items that are shipping.
-
.sku_aliases_search ⇒ ActiveRecord::Relation<Item>
A relation of Items that are sku aliases search.
-
.sku_and_aliases_search ⇒ ActiveRecord::Relation<Item>
A relation of Items that are sku and aliases search.
-
.sku_is_membrane?(sku) ⇒ Boolean
-
.sku_search ⇒ ActiveRecord::Relation<Item>
A relation of Items that are sku search.
-
.smart_services ⇒ ActiveRecord::Relation<Item>
A relation of Items that are smart services.
-
.smartpresets ⇒ ActiveRecord::Relation<Item>
A relation of Items that are smartpresets.
-
.smartstats ⇒ ActiveRecord::Relation<Item>
A relation of Items that are smartstats.
-
.snow_melting_elements ⇒ ActiveRecord::Relation<Item>
A relation of Items that are snow melting elements.
-
.spare_parts ⇒ ActiveRecord::Relation<Item>
A relation of Items that are spare parts.
-
.tax_classes_for_select ⇒ Object
-
.tempzones ⇒ ActiveRecord::Relation<Item>
A relation of Items that are tempzones.
-
.thermostats ⇒ ActiveRecord::Relation<Item>
A relation of Items that are thermostats.
-
.tools ⇒ ActiveRecord::Relation<Item>
A relation of Items that are tools.
-
.towel_warmer_controls_dual_connect ⇒ ActiveRecord::Relation<Item>
A relation of Items that are towel warmer controls dual connect.
-
.towel_warmer_controls_hardwired ⇒ ActiveRecord::Relation<Item>
A relation of Items that are towel warmer controls hardwired.
-
.towel_warmer_controls_plug_in ⇒ ActiveRecord::Relation<Item>
A relation of Items that are towel warmer controls plug in.
-
.towel_warmers ⇒ ActiveRecord::Relation<Item>
A relation of Items that are towel warmers.
-
.towel_warmers_hardwired ⇒ ActiveRecord::Relation<Item>
A relation of Items that are towel warmers hardwired.
-
.towel_warmers_plug_in ⇒ ActiveRecord::Relation<Item>
A relation of Items that are towel warmers plug in.
-
.underlayments ⇒ ActiveRecord::Relation<Item>
A relation of Items that are underlayments.
-
.uom_select_options ⇒ Object
-
.upgrades ⇒ ActiveRecord::Relation<Item>
A relation of Items that are upgrades.
-
.with_all_catalog_items_discontinued ⇒ ActiveRecord::Relation<Item>
A relation of Items that are with all catalog items discontinued.
-
.with_features ⇒ ActiveRecord::Relation<Item>
A relation of Items that are with features.
-
.with_product_specification ⇒ ActiveRecord::Relation<Item>
A relation of Items that are with product specification.
-
.with_stock ⇒ ActiveRecord::Relation<Item>
A relation of Items that are with stock.
-
.with_stock_for ⇒ ActiveRecord::Relation<Item>
A relation of Items that are with stock for.
Instance Method Summary
collapse
-
#all_images ⇒ Object
Find all images linked to this item directly or by combination of product line or category ancestry This is a simpler method than image retriever.
-
#all_my_publications(categories: nil, locale: nil, publication_category_paths: nil) ⇒ Object
-
#all_site_maps ⇒ Object
-
#all_uploads ⇒ Object
-
#any_box_changed? ⇒ Boolean
-
#async_update_rendered_product_specifications ⇒ Object
-
#authenticated_url(dimensions = nil) ⇒ Object
-
#auto_translate(reset_previous_values: false, locales: nil) ⇒ Object
-
#auto_translate_attributes(reset_previous_values: false, locales: nil) ⇒ Object
-
#auto_translate_product_specifications(reset_previous_values: false, locales: nil) ⇒ Object
-
#available_content_locales ⇒ Object
Returns all locales from the catalog this item is part of.
-
#available_token_options_from_product_specifications ⇒ Object
-
#base_weight_converted(unit: 'lbs', precision: nil) ⇒ Object
-
#box1_changed? ⇒ Boolean
-
#box1_defined? ⇒ Boolean
-
#box2_changed? ⇒ Boolean
-
#box2_defined? ⇒ Boolean
-
#box2_shipping_dimensions_to_package ⇒ Object
-
#box2_shipping_height_converted(unit: 'in', precision: 0) ⇒ Object
-
#box2_shipping_length_converted(unit: 'in', precision: 0) ⇒ Object
-
#box2_shipping_weight_converted(unit: 'lbs', precision: nil) ⇒ Object
-
#box2_shipping_width_converted(unit: 'in', precision: 0) ⇒ Object
-
#box3_changed? ⇒ Boolean
-
#box3_defined? ⇒ Boolean
-
#box3_shipping_dimensions_to_package ⇒ Object
-
#box3_shipping_height_converted(unit: 'in', precision: 0) ⇒ Object
-
#box3_shipping_length_converted(unit: 'in', precision: 0) ⇒ Object
-
#box3_shipping_weight_converted(unit: 'lbs', precision: nil) ⇒ Object
-
#box3_shipping_width_converted(unit: 'in', precision: 0) ⇒ Object
-
#boxes ⇒ Object
-
#boxes_shipping_dimensions_and_weights_converted(units: { length: 'in', weight: 'lbs' }, precision: 2) ⇒ Object
-
#boxes_shipping_dimensions_and_weights_display(units: { length: 'in', weight: 'lbs' }, precision: 2) ⇒ Object
-
#boxes_to_packages ⇒ Object
-
#calculate_ideal_cable_spacing ⇒ Object
-
#calculate_is_cable_system? ⇒ Boolean
-
#calculate_item_fields ⇒ Object
-
#can_be_packaged? ⇒ Boolean
-
#canonical_path ⇒ Object
Hierarchical canonical path via product line ancestry + SKU.
-
#canonical_sku ⇒ Object
-
#canonical_url(locale: I18n.locale) ⇒ Object
Canonical URL with locale prefix.
-
#check_oversize?(carrier: nil) ⇒ Boolean
Check if item is oversize, optionally for a specific carrier When no carrier specified, checks all carriers (item is oversize if ANY carrier flags it).
-
#container_type ⇒ Object
-
#content_locales_to_render ⇒ Object
-
#controllable? ⇒ Boolean
-
#country_of_origin_iso3 ⇒ Object
-
#country_of_origin_name ⇒ Object
-
#create_template_specifications ⇒ Object
-
#current_supplier_cost ⇒ Object
-
#deep_dup ⇒ Object
-
#default_short_description ⇒ Object
-
#detailed_description ⇒ Object
Creates a text description from the html rendered description.
-
#discontinue_self_and_dependents ⇒ Object
-
#discontinue_store_and_catalog_items ⇒ Object
-
#ean13 ⇒ Object
-
#edge_cache_urls ⇒ Object
Absolute Cloudflare URLs for this item's pages AND their lazy section fragments (documents/reviews/…), which Cloudflare caches as separate edge entries from the page URL (see SiteMap#section_cache_urls).
-
#effective_option_name ⇒ Object
-
#effective_seo_description(char_limit: nil) ⇒ Object
-
#effective_seo_keywords ⇒ Object
-
#effective_seo_title(skip_sku: false) ⇒ Object
-
#express_weight_converted(weight_in_lbs, unit: 'lbs', precision: nil) ⇒ Object
-
#facet ⇒ Object
-
#facet_sort_keys ⇒ Object
-
#facet_tokens ⇒ Object
-
#features ⇒ Object
Features are a sub category of specs with feature priority set.
-
#fix_name ⇒ Object
-
#fixture_key ⇒ Object
-
#freight_class ⇒ Object
-
#generate_refurbished_sku ⇒ Object
-
#get_quantity_from_sqft(input_sqft, add_one_extra = false) ⇒ Object
-
#gross_weight_converted(unit: 'lbs', precision: nil) ⇒ Object
-
#gtin13 ⇒ Object
-
#gtin_type ⇒ Object
-
#gtin_type_friendly ⇒ Object
-
#harmonization_code_hs6(with_dot = true) ⇒ Object
Returns the first 6 digits of the harmonization code (HS6).
-
#has_ean13? ⇒ Boolean
-
#has_features? ⇒ Boolean
-
#has_heating_system? ⇒ Boolean
-
#has_stock? ⇒ Boolean
-
#has_stock_in_store?(st_id) ⇒ Boolean
-
#image_url(dimensions, options = {}) ⇒ Object
-
#image_url2(options = {}) ⇒ Object
Use this new form that passes the options straight to the url generator.
-
#import_translation_keys ⇒ Object
This method will import existing translations or link to existing ones.
-
#increment_request_counter ⇒ Object
-
#inherited_features ⇒ Object
Seek inherited features from the primary product line To inherit features, a product line's product category must be empty or matching e.g Tempzone Floor Heating has Heating Elements as a product category then items belonging to Tempzone Floor Heating must also be heating elements to inherit its features.
-
#is_available_to_public? ⇒ Boolean
-
#is_cable_accessory? ⇒ Boolean
-
#is_cable_fit_guide? ⇒ Boolean
-
#is_cable_heating_element? ⇒ Boolean
-
#is_cable_tape? ⇒ Boolean
-
#is_cerazorb? ⇒ Boolean
-
#is_circuit_check? ⇒ Boolean
-
#is_cold_lead? ⇒ Boolean
-
#is_cork? ⇒ Boolean
-
#is_discontinued_or_publication ⇒ Object
Helper for validation: skips weight checks for discontinued items and publications.
-
#is_economy_snow_melt_control? ⇒ Boolean
-
#is_floor_heating_product? ⇒ Boolean
-
#is_goods? ⇒ Boolean
-
#is_heating_element? ⇒ Boolean
-
#is_infrared_heating_panel? ⇒ Boolean
-
#is_infrared_heating_panel_dual_connect? ⇒ Boolean
-
#is_infrared_heating_panel_hardwired? ⇒ Boolean
-
#is_infrared_heating_panel_hardwired_control? ⇒ Boolean
-
#is_infrared_heating_panel_plug_in? ⇒ Boolean
-
#is_infrared_heating_panel_plug_in_control? ⇒ Boolean
-
#is_install_kit? ⇒ Boolean
-
#is_junction_box? ⇒ Boolean
-
#is_led_mirror? ⇒ Boolean
-
#is_legacy_relay? ⇒ Boolean
-
#is_made_to_order_led_mirror? ⇒ Boolean
-
#is_membrane? ⇒ Boolean
-
#is_mirror? ⇒ Boolean
-
#is_mirror_defogger? ⇒ Boolean
-
#is_oj_programmable_tstat? ⇒ Boolean
-
#is_oj_programmable_wifi_tstat? ⇒ Boolean
-
#is_pipe_freeze_protection? ⇒ Boolean
-
#is_power? ⇒ Boolean
-
#is_power_module? ⇒ Boolean
-
#is_radiator? ⇒ Boolean
-
#is_refurbished? ⇒ Boolean
-
#is_reviewable? ⇒ Boolean
-
#is_roughin_kit? ⇒ Boolean
-
#is_self_regulating_cable? ⇒ Boolean
-
#is_service? ⇒ Boolean
-
#is_sh_cable? ⇒ Boolean
-
#is_shipping? ⇒ Boolean
-
#is_slab_heat_mat? ⇒ Boolean
-
#is_sm_cable? ⇒ Boolean
-
#is_smartstat? ⇒ Boolean
-
#is_snow_melt_plaque? ⇒ Boolean
-
#is_snow_melting_control? ⇒ Boolean
-
#is_snow_melting_mat? ⇒ Boolean
-
#is_snow_melting_product? ⇒ Boolean
-
#is_spare_parts? ⇒ Boolean
-
#is_thermalsheet? ⇒ Boolean
-
#is_thermostat? ⇒ Boolean
-
#is_towel_warmer? ⇒ Boolean
-
#is_towel_warmer_dual_connect? ⇒ Boolean
-
#is_towel_warmer_hardwired? ⇒ Boolean
-
#is_towel_warmer_hardwired_control? ⇒ Boolean
-
#is_towel_warmer_plug_in? ⇒ Boolean
-
#is_towel_warmer_plug_in_control? ⇒ Boolean
-
#is_tz_cable? ⇒ Boolean
-
#is_tz_ruler_cable? ⇒ Boolean
-
#is_tz_thin_cable? ⇒ Boolean
-
#is_underlayment? ⇒ Boolean
-
#item_available_locales ⇒ Object
-
#item_group_name(context: :sales) ⇒ Object
-
#item_grouping_info(include_self: false, facet_filters: {}, context: nil) ⇒ Object
-
#item_state ⇒ Object
-
#loaded_rendered_product_specifications ⇒ Object
-
#make_upc_code ⇒ Object
-
#missing_catalogs ⇒ Object
-
#most_recent_revision(public_only = true) ⇒ Object
-
#new_revision_sku ⇒ Object
-
#non_refurbished_sku ⇒ Object
-
#order_count ⇒ Object
-
#orderable_online? ⇒ Boolean
-
#orderable_online_in_locale?(locale = I18n.locale) ⇒ Boolean
-
#past_model? ⇒ Boolean
-
#pc_descendant_of_path?(path_slug) ⇒ Boolean
Check if item's product category is or descends from the given path Uses pc_path_slugs stored directly on item (no DB query) Example: item.pc_descendant_of_path?(LtreePaths::PC_TOWEL_WARMERS).
-
#pl_descendant_of_path?(path_slug) ⇒ Boolean
Check if item's primary product line is or descends from the given path Uses ltree path stored directly on item (no DB query) Example: item.pl_descendant_of_path?(LtreePaths::PL_FLOOR_HEATING).
-
#plan_sensitive? ⇒ Boolean
Plan sensitive items are those tied up to the geometry of an installation plan.
-
#primary_image_url(options = {}) ⇒ Object
Returns the primary image URL for display (e.g., cart toast).
-
#primary_product_line_slug_ltree ⇒ Object
-
#product_category_ancestry_ids ⇒ Object
-
#product_category_name ⇒ Object
-
#product_category_path ⇒ Object
Returns ltree path for product category grouping (preferred - no DB lookup needed).
-
#product_category_priority ⇒ Object
-
#product_category_slug ⇒ Object
Returns product category URL for grouping (legacy - use product_category_path for new code).
-
#product_category_url ⇒ Object
-
#product_line_ancestry_ids ⇒ Object
-
#product_line_for_heating_system ⇒ Object
-
#product_line_for_public_sales_portal ⇒ Object
-
#product_line_for_review ⇒ Object
-
#product_line_ids_constellation ⇒ Object
This pulls all product line id including inherited for this item, for the root system, and complimentary_product_line_ids.
-
#product_specifications(filters = {}) ⇒ Object
Retrieves all product specifications available to a given item, this does not retrieve rendered specs but the specs definition used to build them.
-
#prune_empty_specs ⇒ Object
-
#prune_unused_translations ⇒ Object
-
#public_description_html ⇒ Object
-- Content is trusted, generated from Liquid templates.
-
#public_description_text ⇒ Object
-
#public_file_name ⇒ Object
-
#public_name ⇒ Object
-
#public_specifications ⇒ Object
Only specifications intended for the public are retrieved.
-
#publish_shipping_dimensions_changed_event(options = {}) ⇒ Object
Publishes Events::ItemShippingDimensionsChanged when shipping-box dims actually changed on this save.
-
#purge_edge_cache(include_product_line: false) ⇒ Object
-
#quantities_indicator_visible? ⇒ Boolean
-
#refresh_google_feed ⇒ Object
-
#relatives ⇒ Object
Find all direct siblings and relatives items descendending the product category and product line tree.
-
#render_product_specifications(tokens: nil) ⇒ Object
-
#rendered_detailed_description_html ⇒ Object
-
#rendered_product_specifications_grouped(locale: Mobility.locale, filter_grouping: nil, sort_order: []) ⇒ Object
-
#requires_distributor_id_code? ⇒ Boolean
-
#retrieve_faqs ⇒ Object
-
#revised_publication_for_public ⇒ Object
-
#rma_reason_codes(include_advanced: true) ⇒ Object
-
#run_shipping_audit(carrier: nil) ⇒ Array<Shipping::PackageAuditor>
Run shipping audit for all boxes, optionally for a specific carrier.
-
#safe_name ⇒ Object
Returns a name suitable for edit feed with any special character that will destroy a csv formatting.
-
#sales_product_line_path ⇒ Object
Returns ltree path for sales product line (preferred - reuses already-loaded ProductLine).
-
#sales_product_line_slug ⇒ Object
-
#selection_name ⇒ Object
-
#set_grouping(force: false) ⇒ Object
Records a grouping string identifier, this speeds up variant grouping lookup for google and reviews.io api calls.
-
#shift_images(locale: 'en', prefix: nil) ⇒ Object
Shifts images up to fill empty slots in the image type order for this item This method will move images to fill gaps in the sequence, maintaining the proper order.
-
#shipping_dimensions(unit: 'in', precision: 0) ⇒ Object
unit_system SI = Standard International, e.g Metric ucs = United States Customary Unit.
-
#shipping_dimensions_display ⇒ Object
-
#shipping_dimensions_to_package ⇒ Object
-
#shipping_height_converted(unit: 'in', precision: 0) ⇒ Object
-
#shipping_length_converted(unit: 'in', precision: 0) ⇒ Object
-
#shipping_volume ⇒ Object
-
#shipping_volume_in_cubic_feet ⇒ Object
-
#shipping_weight_converted(unit: 'lbs', precision: nil) ⇒ Object
-
#shipping_width_converted(unit: 'in', precision: 0) ⇒ Object
-
#ships_in_single_box? ⇒ Boolean
-
#ships_via_crate? ⇒ Boolean
-
#ships_via_freight? ⇒ Boolean
-
#siblings ⇒ Object
-
#single_item_packings_from_md5 ⇒ Object
Finds packings of this item but only for a single quantity.
-
#sku_and_name ⇒ Object
-
#specifications ⇒ Object
Retrieves rendered specifications as an object.
-
#specifications_for_item_label ⇒ Object
-
#specifications_grouped ⇒ Object
-
#star? ⇒ Boolean
Makes a star appear in the document library.
-
#supplier_skus ⇒ Object
-
#support_product_line_path ⇒ Object
Returns ltree path for support product line (preferred - reuses already-loaded ProductLine).
-
#support_product_line_slug ⇒ Object
-
#tags_display ⇒ Object
-
#third_party_skus(limit: 1) ⇒ Object
-
#thumbnail_url(size: '30x30') ⇒ Object
-
#to_liquid ⇒ Object
-
#to_packdims ⇒ Object
-
#to_s ⇒ Object
-
#total_shipping_weight ⇒ Object
-
#total_shipping_weight_converted(unit: 'lbs', precision: nil) ⇒ Object
-
#total_shipping_weight_of_kit_components ⇒ Object
-
#update_boxes_from_packages(packages) ⇒ Object
-
#update_rendered_product_specifications(user_id: nil, tokens: nil, locales: nil, skip_google_feed: true) ⇒ Object
-
#url_paths ⇒ Object
-
#variants(include_self: false) ⇒ Object
A more strict version of relatives, we don't look at descendants, only exact matches.
-
#versions_for_audit_trail(_params = {}) ⇒ Object
-
#warm_cache(include_product_line: true) ⇒ Object
Finds the associated sitemap (url) end points of this item and its product line Perform a cache warmup.
-
#will_be_restricted_for_sales? ⇒ Boolean
#all_amazon_image_profiles, #amazon_description, #amazon_description=, #amazon_feature_1, #amazon_feature_1=, #amazon_feature_2, #amazon_feature_2=, #amazon_feature_3, #amazon_feature_3=, #amazon_feature_4, #amazon_feature_4=, #amazon_feature_5, #amazon_feature_5=, #amazon_feature_6, #amazon_feature_6=, #amazon_feature_7, #amazon_feature_7=, #amazon_feature_8, #amazon_feature_8=, #amazon_feature_9, #amazon_feature_9=, #amazon_features, #amazon_generic_keyword, #amazon_generic_keyword=, #amazon_product_types, #amazon_target_keywords, #amazon_title, #amazon_title=, #create_or_set_amazon_spec_value, #description_for_amazon, #is_amazon_item?, #reset_amazon_fields, #sync_amazon_asins, #title_for_amazon, with_asin
#content_links_count, #linked_content, #linked_posts, #linked_publications, #linked_showcases, #linked_videos
ai_search_publications, ai_search_warning?, #alias_sku, #analyze_pdf_images!, #available_service_locales, #available_to_all_locales?, #check_redirection_path, clear_ai_search_warning!, #compose_name_with_languages, #content_for_embedding, #cover_image_url, cover_ratio_mismatch, #create_primary_image_from_pdf, #default_publication_logistics, embeddable_content_types, #embeddable_locales, #embedding_content_changed?, #fast_country_discontinue, #file_name_for_download, #friendly_locale_names, #generate_publication_name, #has_literature_changed?, hybrid_search_publications, #locale_for_embedding, #needs_vision_analysis?, #perform_country_discontinue, #product_category_must_be_publication, #publication_available_locales, #publication_base_name_clean_of_language, #publication_cache_relevant_change?, #publication_edge_cache_urls, #publication_pdf_changed?, #publication_sku_check, #publication_url, #publication_visible_to_public?, publications, publications_for_online_portal, publications_for_public, publications_for_public_in_store, publications_for_sales_portal, publications_for_support_portal, #publish_pdf_changed_event, #publish_publication_updated_event, #retrieve_publications_search_text, #secondary_product_category_must_not_be_publication, #set_search_text, #should_queue_embedding?, with_publication_attached
rrf_ranked_relation
#content_for_embedding, embeddable_content_types, #embeddable_locales, #embedding_content_hash, embedding_partition_class, #embedding_stale?, #embedding_type_name, #embedding_vector, #find_content_embedding, #find_similar, #generate_all_embeddings!, #generate_chunked_embeddings!, #generate_embedding!, #has_embedding?, #locale_for_embedding, #needs_chunking?, regenerate_all_embeddings, semantic_search
#add_tag, all_tags, #has_tag?, normalize_tag_names, not_tagged_with, #remove_tag, #tag_list, #tag_list=, #taggable_type_for_tagging, tagged_with, #tags, #tags=, tags_cloud, tags_exclude, tags_include, with_all_tags, with_any_tags, without_all_tags, without_any_tags
#compact_translation_container, skip_compaction_for
#build_package_content_entries, #condense_group_to_char_limit, #group_entries_for_max_unique_items, #package_content_html, #package_content_short_name, #package_contents_array, #package_contents_friendly
#amps, #amps=, #amps_static?, #area, #aspect, #btu_per_hour, #calculate_amps, #calculate_coverage_for_membrane, #calculate_geometric_sqft, #calculate_heated_area_for_panels, #calculate_heated_area_sqft_for_panels, #calculate_heated_area_sqm_for_panels, #calculate_kilowatts, #calculate_number_of_fixing_strips_at_3_in, #calculate_number_of_fixing_strips_at_4_in, #calculate_number_of_fixing_strips_at_5_in, #calculate_number_of_fixing_strips_at_cable_spacing, #calculate_ohms, #calculate_ohms_per_ft, #calculate_size_2d, #calculate_size_2d_ft, #calculate_size_2d_in, #calculate_size_2d_metric_cm, #calculate_size_2d_metric_mm, #calculate_size_3d, #calculate_size_3d_ft, #calculate_size_3d_in, #calculate_size_3d_metric_cm, #calculate_size_3d_metric_mm, #calculate_sqft, #calculate_thermal_power_per_hour, #calculate_volts, #calculate_watts, #calculate_watts_per_sqft, #can_use_amps_for_calculation?, #can_use_ohms_for_calculation?, #can_use_voltage_for_calculation?, #can_use_watts_for_calculation?, #cold_lead_length, #cold_lead_length=, #control_capacity, #coverage_at_3_5_in, #coverage_at_3_75_in, #coverage_at_3_in, #coverage_at_4_5_in, #coverage_at_4_in, #coverage_at_5_in, #coverage_formatted, #create_or_set_spec_value, #finish, #has_spec?, #is_dual_voltage?, #length, #length=, #length_formatted, #linear_ft, #maximum_current, #num_poles, #ohms, #ohms=, #ohms_law_calculator, #ohms_static?, #plan_grouping, #plan_grouping=, #set_spec_value, #spec, #spec_image, #spec_output, #spec_refresh_in_progress, #spec_unit, #spec_value, #specs_for_identifier_label, #sqft, #sqft=, #token_specs_values_for_liquid, #voltage, #voltage=, #voltage_formatted, #voltage_static?, #volts, #volts=, #vop, #watts, #watts=, #watts_formatted, #watts_per_linear_feet, #watts_per_sqft, #watts_per_sqft_at_3_5_in_spacing, #watts_per_sqft_at_3_75_in_spacing, #watts_per_sqft_at_3_in_spacing, #watts_per_sqft_at_4_5_in_spacing, #watts_per_sqft_at_4_in_spacing, #watts_per_sqft_at_5_in_spacing, #watts_static?, #width, #width=, #width_by_length_text, #width_by_length_text_2, #width_by_length_text_3, #width_formatted
#box_contents, #consolidate_linked_kits, #get_kit_item_ids, #get_kit_items, #get_multi_box_item_contents_item_id_hash_array, #get_self_and_kit_item_ids, #get_self_and_kit_items, #is_part_of_a_kit?, #is_part_of_an_active_kit?, #kit_contents, kits, #shipping_dimensions_changed?, #store_item_for
#all_skipped_columns, #audit_reference_data, #should_not_save_version, #stamp_record
#build_ltree_paths_from_associations, bulk_sync_ltree_paths!, sync_items_for_product_categories!, sync_items_for_product_lines!, #sync_ltree_paths!
by_product_category_id, by_product_category_id_direct, by_product_category_path, by_product_category_path_exact, by_product_category_url, by_product_category_url_exact, by_product_line_id, by_product_line_path, by_product_line_path_full, by_product_line_url, by_product_line_url_full, not_by_product_category_id, not_by_product_line_id
ransackable_associations, ransackable_attributes, ransortable_attributes, #to_relation
config
#after_commit
#publish_event
Instance Attribute Details
#amazon_asin ⇒ Object
319
320
321
|
# File 'app/models/item.rb', line 319
validates :amazon_asin, uniqueness: true,
format: { with: AMAZON_ASIN_REGEXP, message: 'must be 10 alphanumeric characters starting with a letter' },
allow_blank: true
|
#name_en ⇒ Object
Here we check specifically for the english name to be present
Validations:
315
|
# File 'app/models/item.rb', line 315
validates :name_en, :tax_class, presence: true
|
#refresh_specs ⇒ Object
These are shortcuts for publications
223
224
225
|
# File 'app/models/item.rb', line 223
def refresh_specs
@refresh_specs
end
|
#skip_item_calc ⇒ Object
Returns the value of attribute skip_item_calc.
641
642
643
|
# File 'app/models/item.rb', line 641
def skip_item_calc
@skip_item_calc
end
|
#sku ⇒ Object
316
317
318
|
# File 'app/models/item.rb', line 316
validates :sku, presence: true,
uniqueness: true,
format: { with: SKU_REGEXP, message: 'must only contain A-Z 0-9 - _ . and must end with a number or letter' }
|
#tax_class ⇒ Object
Here we check specifically for the english name to be present
Validations:
315
|
# File 'app/models/item.rb', line 315
validates :name_en, :tax_class, presence: true
|
#update_search_text ⇒ Object
Returns the value of attribute update_search_text.
641
642
643
|
# File 'app/models/item.rb', line 641
def update_search_text
@update_search_text
end
|
#update_upc ⇒ Object
Returns the value of attribute update_upc.
641
642
643
|
# File 'app/models/item.rb', line 641
def update_upc
@update_upc
end
|
Class Method Details
.accessories ⇒ ActiveRecord::Relation<Item>
A relation of Items that are accessories. Active Record Scope
416
|
# File 'app/models/item.rb', line 416
scope :accessories, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_ACCESSORIES)) }
|
.active ⇒ ActiveRecord::Relation<Item>
A relation of Items that are active. Active Record Scope
372
|
# File 'app/models/item.rb', line 372
scope :active, -> { where(is_discontinued: false) }
|
.active_in_catalog_ids ⇒ ActiveRecord::Relation<Item>
A relation of Items that are active in catalog ids. Active Record Scope
520
521
522
523
524
|
# File 'app/models/item.rb', line 520
scope :active_in_catalog_ids, ->(*catalog_ids) {
catalog_ids = [catalog_ids].flatten.filter_map(&:presence).uniq
active
.where("exists(#{CI_EXIST_CHECK_SQL} and ci.catalog_id IN (?))", catalog_ids.flatten)
}
|
.all_locales ⇒ Object
NOTE: all_tags method provided by Models::Taggable concern
670
671
672
|
# File 'app/models/item.rb', line 670
def self.all_locales
pluck(Arel.sql('distinct unnest(publication_locales) as locale')).compact.sort
end
|
.async_update_all_items_product_specifications(public_only: true, active_only: true, limit: nil, not_updated_since: nil) ⇒ Object
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
|
# File 'app/models/item.rb', line 2056
def self.async_update_all_items_product_specifications(public_only: true, active_only: true, limit: nil, not_updated_since: nil)
items = Item.non_publications
items = items.available_to_public if public_only items = items.active unless public_only && !active_only
items = items.where(Item[:rendered_product_specifications_at].eq(nil).or(Item[:rendered_product_specifications_at].lt(not_updated_since))) if not_updated_since
items = items.limit(limit) if limit
items.distinct.ids.each { |iid| ItemAttributeWorker.perform_async(iid) }
end
|
.available_to_public ⇒ ActiveRecord::Relation<Item>
A relation of Items that are available to public. Active Record Scope
374
|
# File 'app/models/item.rb', line 374
scope :available_to_public, -> { active.public_and_active_in_catalog_id(1, 2) }
|
.available_to_public_for_support ⇒ ActiveRecord::Relation<Item>
A relation of Items that are available to public for support. Active Record Scope
376
|
# File 'app/models/item.rb', line 376
scope :available_to_public_for_support, -> { condition_new.where(visible_for_support: true).where(primary_product_line_id: ProductLine.for_support_portal.select(:id)) }
|
.by_primary_product_line_ids_with_descendants ⇒ ActiveRecord::Relation<Item>
A relation of Items that are by primary product line ids with descendants. Active Record Scope
536
537
538
539
540
|
# File 'app/models/item.rb', line 536
scope :by_primary_product_line_ids_with_descendants, ->(*pl_ids) {
ids = [pl_ids].flatten.compact.map(&:to_i)
paths = ProductLine.where(id: ids).pluck(:ltree_path_ids).compact
paths.empty? ? none : where(Item[:primary_pl_path_ids].ltree_descendant(paths))
}
|
.canonical_search ⇒ ActiveRecord::Relation<Item>
A relation of Items that are canonical search. Active Record Scope
447
448
449
450
|
# File 'app/models/item.rb', line 447
scope :canonical_search, ->(sku) {
escaped = Regexp.escape(sku.to_s)
where('items.sku ~ ?', "^#{escaped}-[A-Za-z]{1,2}$").order(sku: :desc)
}
|
.category_sorted ⇒ ActiveRecord::Relation<Item>
A relation of Items that are category sorted. Active Record Scope
.cold_leads ⇒ ActiveRecord::Relation<Item>
A relation of Items that are cold leads. Active Record Scope
.condition_select_options ⇒ Object
919
920
921
|
# File 'app/models/item.rb', line 919
def self.condition_select_options
Item.conditions.keys.map { |c| [c.humanize.titleize, c] }
end
|
.controls ⇒ ActiveRecord::Relation<Item>
A relation of Items that are controls. Active Record Scope
394
|
# File 'app/models/item.rb', line 394
scope :controls, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_CONTROLS)) }
|
.countertop_heaters ⇒ ActiveRecord::Relation<Item>
A relation of Items that are countertop heaters. Active Record Scope
.custom_mats ⇒ ActiveRecord::Relation<Item>
A relation of Items that are custom mats. Active Record Scope
.discontinued ⇒ ActiveRecord::Relation<Item>
A relation of Items that are discontinued. Active Record Scope
373
|
# File 'app/models/item.rb', line 373
scope :discontinued, -> { where(is_discontinued: true) }
|
.dropships ⇒ ActiveRecord::Relation<Item>
A relation of Items that are dropships. Active Record Scope
471
|
# File 'app/models/item.rb', line 471
scope :dropships, -> { where(dropship: true) }
|
.easystats ⇒ ActiveRecord::Relation<Item>
A relation of Items that are easystats. Active Record Scope
.electrical_plan_controls ⇒ ActiveRecord::Relation<Item>
A relation of Items that are electrical plan controls. Active Record Scope
486
487
488
489
490
|
# File 'app/models/item.rb', line 486
scope :electrical_plan_controls, -> {
controls
.where(Item[:primary_pl_path_slugs].ltree_descendant(LtreePaths::PL_ALL_CONTROLS))
.where.not(sku: %w[RLY-12PL SCE-ELEC])
}
|
.excludes_forecast_skus ⇒ ActiveRecord::Relation<Item>
A relation of Items that are excludes forecast skus. Active Record Scope
442
|
# File 'app/models/item.rb', line 442
scope :excludes_forecast_skus, -> { where.not('items.sku SIMILAR TO ?', "(#{FORECAST_EXCLUDED_SKU_PREFIXES.join('|')})%") }
|
.floor_heating_controls ⇒ ActiveRecord::Relation<Item>
A relation of Items that are floor heating controls. Active Record Scope
.floor_heating_elements ⇒ ActiveRecord::Relation<Item>
A relation of Items that are floor heating elements. Active Record Scope
414
|
# File 'app/models/item.rb', line 414
scope :floor_heating_elements, -> { heating_elements.where(Item[:primary_pl_path_slugs].ltree_descendant(LtreePaths::PL_FLOOR_HEATING)) }
|
.for_support_portal ⇒ ActiveRecord::Relation<Item>
A relation of Items that are for support portal. Active Record Scope
.forecastable ⇒ ActiveRecord::Relation<Item>
A relation of Items that are forecastable. Active Record Scope
444
|
# File 'app/models/item.rb', line 444
scope :forecastable, -> { active.non_kits.non_publications.non_shipping.excludes_forecast_skus }
|
.get_infrared_heating_panel_tstat_options_for_web_and_apply_overrides(connection_method, tstat_options_override = [], available_in_catalog_id: nil) ⇒ Object
Here we want a static web page (e.g. app/views/pages/infrared-heating-panels) to use the same source of SKUs as Item does but allow it to override some of the stuff, including the order:
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
|
# File 'app/models/item.rb', line 2399
def self.get_infrared_heating_panel_tstat_options_for_web_and_apply_overrides(connection_method, tstat_options_override = [], available_in_catalog_id: nil)
available_in_catalog_id = Catalog.locale_to_catalog_id(I18n.locale) if available_in_catalog_id.nil?
num_overrides = tstat_options_override.size base_item_scope = Item.public_and_active_in_catalog_id(available_in_catalog_id)
controls = if connection_method == :hardwired
base_item_scope.infrared_heating_panel_controls_hardwired
else
base_item_scope.infrared_heating_panel_controls_plug_in
end
res = controls.map do |item|
tstat_options_override.find do |h|
h[:sku] == item.sku
end || { sku: item.sku, name: item.name, image: item.primary_image.image_url(width: 300, height: 300) }
end
res.sort_by { |h| tstat_options_override.index(h) || num_overrides }
end
|
.get_quantity_from_items_and_sqft(catalog_id, items, sqft, add_one_extra_of_last_item = false) ⇒ Object
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
|
# File 'app/models/item.rb', line 1480
def self.get_quantity_from_items_and_sqft(catalog_id, items, sqft, = false)
res_arr = []
cost_arr = []
2.times do |pass|
area = sqft
res = {}
cost = 0.0
last_i = items.length - 1
items.each_with_index do |item, i|
= if && (i == last_i) && pass.zero? 1
else
0
end
qty =
if item.sqft.to_f > 0.0
qty += if (i == last_i) || ((pass == 1) && (items[i + 1].sqft < sqft)) (area / item.sqft).ceil.to_i else
(area / item.sqft).floor.to_i end
end
next unless qty.positive?
res[item.sku] = qty
area -= (item.sqft.to_f * qty)
ci = item.catalog_items.find { |ci2| ci2.catalog_id == catalog_id } || item.catalog_items.first
cost += (qty * ci.amount.to_f)
end
res_arr << res
cost_arr << cost
end
res_arr[cost_arr.index(cost_arr.min)]
end
|
.get_towel_warmer_tstat_options_for_web_and_apply_overrides(connection_method, tstat_options_override = [], available_in_catalog_id: nil) ⇒ Object
Here we want a static web page (e.g. app/views/pages/towel-warmer/controls) to use the same source of SKUs as Item does but allow it to override some of the stuff, including the order:
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
|
# File 'app/models/item.rb', line 2380
def self.get_towel_warmer_tstat_options_for_web_and_apply_overrides(connection_method, tstat_options_override = [], available_in_catalog_id: nil)
available_in_catalog_id = Catalog.locale_to_catalog_id(I18n.locale) if available_in_catalog_id.nil?
num_overrides = tstat_options_override.size base_item_scope = Item.public_and_active_in_catalog_id(available_in_catalog_id)
controls = if connection_method == :hardwired
base_item_scope.towel_warmer_controls_hardwired
else
base_item_scope.towel_warmer_controls_plug_in
end
res = controls.map do |item|
tstat_options_override.find do |h|
h[:sku] == item.sku
end || { sku: item.sku, name: item.name, image: item.primary_image.image_url(width: 300, height: 300) }
end
res.sort_by { |h| tstat_options_override.index(h) || num_overrides }
end
|
.goods ⇒ ActiveRecord::Relation<Item>
A relation of Items that are goods. Active Record Scope
420
|
# File 'app/models/item.rb', line 420
scope :goods, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_GOODS)) }
|
.goods_and_services_for_public ⇒ ActiveRecord::Relation<Item>
A relation of Items that are goods and services for public. Active Record Scope
445
|
# File 'app/models/item.rb', line 445
scope :goods_and_services_for_public, -> { available_to_public.active.non_publications }
|
.goods_visible_for_support ⇒ ActiveRecord::Relation<Item>
A relation of Items that are goods visible for support. Active Record Scope
465
|
# File 'app/models/item.rb', line 465
scope :goods_visible_for_support, -> { non_publications.condition_new.goods.where(visible_for_support: true) }
|
.has_floor_sensor ⇒ ActiveRecord::Relation<Item>
A relation of Items that are has floor sensor. Active Record Scope
485
|
# File 'app/models/item.rb', line 485
scope :has_floor_sensor, -> { with_product_specification(:has_floor_sensor, 'y') }
|
.heating_elements ⇒ ActiveRecord::Relation<Item>
A relation of Items that are heating elements. Active Record Scope
.identifiers_search ⇒ ActiveRecord::Relation<Item>
A relation of Items that are identifiers search. Active Record Scope
552
553
554
555
556
557
558
559
560
561
562
563
564
|
# File 'app/models/item.rb', line 552
scope :identifiers_search, ->(identifier) {
where(%{
items.sku ILIKE :identifier_wild
OR items.upc = :identifier
OR items.upc = RIGHT(:identifier,12)
OR items.secondary_model_number ILIKE :identifier_wild
OR items.amazon_asin = :identifier
OR items.sku_aliases @> ARRAY[:identifier]::varchar[]
OR supplier_items.supplier_sku ILIKE :identifier_wild
},
identifier_wild: "#{identifier}%",
identifier:).left_outer_joins(:supplier_item).order(sanitize_sql_for_order([Arel.sql('items.is_discontinued = true,items.sku <-> ?'), identifier]))
}
|
.import_translation_keys ⇒ Object
1884
1885
1886
|
# File 'app/models/item.rb', line 1884
def self.import_translation_keys
Item.where.not(translations: {}).find_each(&:import_translation_keys)
end
|
.in_store ⇒ ActiveRecord::Relation<Item>
A relation of Items that are in store. Active Record Scope
425
426
427
|
# File 'app/models/item.rb', line 425
scope :in_store, ->(*store_ids) {
where('exists(select id from store_items where store_items.item_id = items.id and store_items.store_id IN (?) and store_items.is_discontinued = false)', [store_ids].flatten)
}
|
.indexable ⇒ ActiveRecord::Relation<Item>
A relation of Items that are indexable. Active Record Scope
514
|
# File 'app/models/item.rb', line 514
scope :indexable, -> { not_tagged_with('Noindex') }
|
.infrared_heating_panel_controls_dual_connect ⇒ ActiveRecord::Relation<Item>
A relation of Items that are infrared heating panel controls dual connect. Active Record Scope
462
|
# File 'app/models/item.rb', line 462
scope :infrared_heating_panel_controls_dual_connect, -> { where(sku: ItemConstants::INFRARED_HEATING_PANELS_PLUG_IN_CONTROL_SKUS + ItemConstants::INFRARED_HEATING_PANELS_HARDWIRE_CONTROL_SKUS) }
|
.infrared_heating_panel_controls_hardwired ⇒ ActiveRecord::Relation<Item>
A relation of Items that are infrared heating panel controls hardwired. Active Record Scope
461
|
# File 'app/models/item.rb', line 461
scope :infrared_heating_panel_controls_hardwired, -> { where(sku: ItemConstants::INFRARED_HEATING_PANELS_HARDWIRE_CONTROL_SKUS) }
|
.infrared_heating_panel_controls_plug_in ⇒ ActiveRecord::Relation<Item>
A relation of Items that are infrared heating panel controls plug in. Active Record Scope
459
|
# File 'app/models/item.rb', line 459
scope :infrared_heating_panel_controls_plug_in, -> { where(sku: ItemConstants::INFRARED_HEATING_PANELS_PLUG_IN_CONTROL_SKUS) }
|
.infrared_heating_panels ⇒ ActiveRecord::Relation<Item>
A relation of Items that are infrared heating panels. Active Record Scope
.infrared_heating_panels_hardwired ⇒ ActiveRecord::Relation<Item>
A relation of Items that are infrared heating panels hardwired. Active Record Scope
.install_kits ⇒ ActiveRecord::Relation<Item>
A relation of Items that are install kits. Active Record Scope
.insulations ⇒ ActiveRecord::Relation<Item>
A relation of Items that are insulations. Active Record Scope
.integration_kits ⇒ ActiveRecord::Relation<Item>
A relation of Items that are integration kits. Active Record Scope
.item_identifier_label_sizes_select_options ⇒ Object
931
932
933
|
# File 'app/models/item.rb', line 931
def self.item_identifier_label_sizes_select_options
[['2.3125" x 4" (S-8505)', 'regular'], ['4" x 6" (S-17044)', 'large']]
end
|
.last_custom_mat_item ⇒ Object
.membranes ⇒ ActiveRecord::Relation<Item>
A relation of Items that are membranes. Active Record Scope
494
|
# File 'app/models/item.rb', line 494
scope :membranes, -> { where(sku: ItemConstants::MEMBRANE_SKUS) }
|
.mirror_defoggers ⇒ ActiveRecord::Relation<Item>
A relation of Items that are mirror defoggers. Active Record Scope
.mirrors ⇒ ActiveRecord::Relation<Item>
A relation of Items that are mirrors. Active Record Scope
393
|
# File 'app/models/item.rb', line 393
scope :mirrors, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_MIRRORS)) }
|
.missing_shipping_dimensions ⇒ ActiveRecord::Relation<Item>
A relation of Items that are missing shipping dimensions. Active Record Scope
380
381
382
383
384
385
386
387
388
|
# File 'app/models/item.rb', line 380
scope :missing_shipping_dimensions, -> {
arel = Item.arel_table
goods.where(
arel[:shipping_length].lteq(0).or(arel[:shipping_length].eq(nil))
.or(arel[:shipping_width].lteq(0)).or(arel[:shipping_width].eq(nil))
.or(arel[:shipping_height].lteq(0)).or(arel[:shipping_height].eq(nil))
.or(arel[:shipping_weight].lteq(0)).or(arel[:shipping_weight].eq(nil))
)
}
|
.needs_packaging_reviewed ⇒ ActiveRecord::Relation<Item>
A relation of Items that are needs packaging reviewed. Active Record Scope
550
|
# File 'app/models/item.rb', line 550
scope :needs_packaging_reviewed, -> { where(review_product_packaging_flag: true) }
|
.needs_weight_reviewed ⇒ ActiveRecord::Relation<Item>
A relation of Items that are needs weight reviewed. Active Record Scope
549
|
# File 'app/models/item.rb', line 549
scope :needs_weight_reviewed, -> { where(review_product_weight_flag: true) }
|
.non_dropships ⇒ ActiveRecord::Relation<Item>
A relation of Items that are non dropships. Active Record Scope
472
|
# File 'app/models/item.rb', line 472
scope :non_dropships, -> { where('items.dropship = false or items.dropship is null') }
|
.non_kits ⇒ ActiveRecord::Relation<Item>
A relation of Items that are non kits. Active Record Scope
436
|
# File 'app/models/item.rb', line 436
scope :non_kits, -> { where(is_kit: false) }
|
.non_publications ⇒ ActiveRecord::Relation<Item>
A relation of Items that are non publications. Active Record Scope
435
|
# File 'app/models/item.rb', line 435
scope :non_publications, -> { where.not(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_PUBLICATIONS)) }
|
.non_shipping ⇒ ActiveRecord::Relation<Item>
A relation of Items that are non shipping. Active Record Scope
.not_a_target_item ⇒ ActiveRecord::Relation<Item>
A relation of Items that are not a target item. Active Record Scope
473
|
# File 'app/models/item.rb', line 473
scope :not_a_target_item, -> { where.missing(:source_item_relations) }
|
.oj_programmable_tstats ⇒ ActiveRecord::Relation<Item>
A relation of Items that are oj programmable tstats. Active Record Scope
406
|
# File 'app/models/item.rb', line 406
scope :oj_programmable_tstats, -> { oj_tstats.where(Item[:name].matches('%Programmable%')).where.not(Item[:name].matches('%Non Programmable%')) }
|
.oj_tstats ⇒ ActiveRecord::Relation<Item>
A relation of Items that are oj tstats. Active Record Scope
405
|
# File 'app/models/item.rb', line 405
scope :oj_tstats, -> { thermostats.where(Item[:sku].matches('%4999%')) }
|
.order_by_spec ⇒ ActiveRecord::Relation<Item>
A relation of Items that are order by spec. Active Record Scope
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
|
# File 'app/models/item.rb', line 497
scope :order_by_spec, ->(spec, datatype = 'varchar', direction = 'asc') {
if %w[decimal integer numeric].include?(datatype.downcase)
order_clause = "CASE
WHEN (items.rendered_product_specifications->'#{spec}'->>'raw') ~ '^[0-9]+\\.?[0-9]*$'
THEN (items.rendered_product_specifications->'#{spec}'->>'raw')::#{datatype}
WHEN (items.rendered_product_specifications->'#{spec}'->>'raw') ~ '^[0-9]+\\.?[0-9]*\\s+[a-zA-Z]+$'
THEN (regexp_replace(items.rendered_product_specifications->'#{spec}'->>'raw', '[^0-9\\.]', '', 'g'))::#{datatype}
ELSE NULL
END #{direction}"
order(Arel.sql(order_clause))
else
order(Arel.sql("(items.rendered_product_specifications->'#{spec}'->>'raw')::#{datatype} #{direction}"))
end
}
|
.order_towel_warmer_controls_hardwired ⇒ ActiveRecord::Relation<Item>
A relation of Items that are order towel warmer controls hardwired. Active Record Scope
401
|
# File 'app/models/item.rb', line 401
scope :order_towel_warmer_controls_hardwired, -> { in_order_of(:sku, ItemConstants::TOWEL_WARMER_HARDWIRE_CONTROL_SKUS) }
|
.orderable_online ⇒ ActiveRecord::Relation<Item>
A relation of Items that are orderable online. Active Record Scope
446
|
# File 'app/models/item.rb', line 446
scope :orderable_online, -> { non_publications.available_to_public.active.packageable }
|
.out_of_stock ⇒ ActiveRecord::Relation<Item>
A relation of Items that are out of stock. Active Record Scope
453
454
455
|
# File 'app/models/item.rb', line 453
scope :out_of_stock, -> {
joins(:store_items).where(StoreItem[:qty_available].lteq(Item[:legacy_qty_out_of_stock])).where(store_items: { location: 'AVAILABLE' })
}
|
.packageable ⇒ ActiveRecord::Relation<Item>
A relation of Items that are packageable. Active Record Scope
377
|
# File 'app/models/item.rb', line 377
scope :packageable, -> { where(Item[:shipping_weight].gt(0)).where(Item[:base_weight].gt(0)).where(Item[:shipping_length].gt(0)).where(Item[:shipping_width].gt(0)).where(Item[:shipping_height].gt(0)) }
|
.power_modules ⇒ ActiveRecord::Relation<Item>
A relation of Items that are power modules. Active Record Scope
.powers ⇒ ActiveRecord::Relation<Item>
A relation of Items that are powers. Active Record Scope
412
|
# File 'app/models/item.rb', line 412
scope :powers, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_POWER)) }
|
.primary_product_line_slug_ltree_cont ⇒ ActiveRecord::Relation<Item>
A relation of Items that are primary product line slug ltree cont. Active Record Scope
542
543
544
545
546
547
|
# File 'app/models/item.rb', line 542
scope :primary_product_line_slug_ltree_cont, ->(term) {
sanitized = term.to_s.strip.tr(' ', '_').gsub(/[^a-zA-Z0-9_.]/, '')
return none if sanitized.blank?
where(Item[:primary_pl_path_slugs].ltree_descendant(sanitized))
}
|
.public_and_active_in_any_catalogs ⇒ ActiveRecord::Relation<Item>
A relation of Items that are public and active in any catalogs. Active Record Scope
.public_and_active_in_catalog_id ⇒ ActiveRecord::Relation<Item>
A relation of Items that are public and active in catalog id. Active Record Scope
525
526
527
528
529
|
# File 'app/models/item.rb', line 525
scope :public_and_active_in_catalog_id, ->(*catalog_ids) {
catalog_ids = [catalog_ids].flatten.filter_map(&:presence).uniq
active
.where("exists(#{CI_EXIST_CHECK_SQL} and ci.state NOT IN (?) and ci.catalog_id IN (?))", CatalogItem::HIDDEN_STATES, catalog_ids.flatten)
}
|
.publications_search ⇒ ActiveRecord::Relation<Item>
A relation of Items that are publications search. Active Record Scope
574
|
# File 'app/models/item.rb', line 574
scope :publications_search, ->(term) { canonical_search(term) }
|
.ransackable_scopes(_auth_object = nil) ⇒ Object
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
|
# File 'app/models/item.rb', line 682
def self.ransackable_scopes(_auth_object = nil)
%i[keywords_search by_product_line_id pdf_search
by_product_category_id
by_primary_product_line_ids_with_descendants
active_in_catalog_ids
public_and_active_in_catalog_id
sku_and_aliases_search
tags_include
ai_search_publications
hybrid_search_publications
not_by_product_category_id
not_by_product_line_id
tags_exclude
primary_product_line_slug_ltree_cont
cover_ratio_mismatch]
end
|
.relay_panels ⇒ ActiveRecord::Relation<Item>
A relation of Items that are relay panels. Active Record Scope
.remote_services ⇒ ActiveRecord::Relation<Item>
A relation of Items that are remote services. Active Record Scope
422
|
# File 'app/models/item.rb', line 422
scope :remote_services, -> { services.where(Item[:sku].matches('%REMOTE%')) }
|
.rendered_product_specs_keys ⇒ Object
2098
2099
2100
|
# File 'app/models/item.rb', line 2098
def self.rendered_product_specs_keys
pluck('distinct jsonb_object_keys(rendered_product_specifications)').sort.map(&:to_sym)
end
|
.rendered_product_specs_options_for_select(spec_key) ⇒ Object
2102
2103
2104
2105
2106
|
# File 'app/models/item.rb', line 2102
def self.rendered_product_specs_options_for_select(spec_key)
Item.pluck("distinct rendered_product_specifications->'#{spec_key}'->>'output',rendered_product_specifications->'#{spec_key}'->>'raw'").reject do |v|
v[0].nil?
end.sort
end
|
.reservable ⇒ ActiveRecord::Relation<Item>
A relation of Items that are reservable. Active Record Scope
491
|
# File 'app/models/item.rb', line 491
scope :reservable, -> { where(require_reservation: true) }
|
.reviewable ⇒ ActiveRecord::Relation<Item>
A relation of Items that are reviewable. Active Record Scope
.rough_in_kits ⇒ ActiveRecord::Relation<Item>
A relation of Items that are rough in kits. Active Record Scope
.sensors ⇒ ActiveRecord::Relation<Item>
A relation of Items that are sensors. Active Record Scope
413
|
# File 'app/models/item.rb', line 413
scope :sensors, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_SENSORS)) }
|
.services ⇒ ActiveRecord::Relation<Item>
A relation of Items that are services. Active Record Scope
421
|
# File 'app/models/item.rb', line 421
scope :services, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_SERVICES)) }
|
.shipping ⇒ ActiveRecord::Relation<Item>
A relation of Items that are shipping. Active Record Scope
470
|
# File 'app/models/item.rb', line 470
scope :shipping, -> { where(tax_class: 'shp') }
|
.sku_aliases_search ⇒ ActiveRecord::Relation<Item>
A relation of Items that are sku aliases search. Active Record Scope
451
|
# File 'app/models/item.rb', line 451
scope :sku_aliases_search, ->(sku) { where('items.sku_aliases @> ARRAY[:sku]::varchar[]', sku:) }
|
.sku_and_aliases_search ⇒ ActiveRecord::Relation<Item>
A relation of Items that are sku and aliases search. Active Record Scope
452
|
# File 'app/models/item.rb', line 452
scope :sku_and_aliases_search, ->(sku) { where('items.sku ILIKE :sku OR items.sku_aliases @> ARRAY[:sku]::varchar[]', sku:) }
|
.sku_is_membrane?(sku) ⇒ Boolean
1416
1417
1418
|
# File 'app/models/item.rb', line 1416
def self.sku_is_membrane?(sku)
ItemConstants::MEMBRANE_SKUS.include?(sku)
end
|
.sku_search ⇒ ActiveRecord::Relation<Item>
A relation of Items that are sku search. Active Record Scope
566
|
# File 'app/models/item.rb', line 566
scope :sku_search, ->(sku) { canonical_search(sku) }
|
.smart_services ⇒ ActiveRecord::Relation<Item>
A relation of Items that are smart services. Active Record Scope
516
|
# File 'app/models/item.rb', line 516
scope :smart_services, -> { where(Item[:primary_pl_path_slugs].ltree_descendant(LtreePaths::PL_SERVICES)) }
|
.smartpresets ⇒ ActiveRecord::Relation<Item>
A relation of Items that are smartpresets. Active Record Scope
.smartstats ⇒ ActiveRecord::Relation<Item>
A relation of Items that are smartstats. Active Record Scope
.snow_melting_elements ⇒ ActiveRecord::Relation<Item>
A relation of Items that are snow melting elements. Active Record Scope
415
|
# File 'app/models/item.rb', line 415
scope :snow_melting_elements, -> { heating_elements.where(Item[:primary_pl_path_slugs].ltree_descendant(LtreePaths::PL_SNOW_MELTING)) }
|
.spare_parts ⇒ ActiveRecord::Relation<Item>
A relation of Items that are spare parts. Active Record Scope
424
|
# File 'app/models/item.rb', line 424
scope :spare_parts, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_SPARE_PARTS)) }
|
.tax_classes_for_select ⇒ Object
927
928
929
|
# File 'app/models/item.rb', line 927
def self.tax_classes_for_select
TAX_CLASSES.invert
end
|
.tempzones ⇒ ActiveRecord::Relation<Item>
A relation of Items that are tempzones. Active Record Scope
.thermostats ⇒ ActiveRecord::Relation<Item>
A relation of Items that are thermostats. Active Record Scope
A relation of Items that are tools. Active Record Scope
419
|
# File 'app/models/item.rb', line 419
scope :tools, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_TOOLS)) }
|
.towel_warmer_controls_dual_connect ⇒ ActiveRecord::Relation<Item>
A relation of Items that are towel warmer controls dual connect. Active Record Scope
403
|
# File 'app/models/item.rb', line 403
scope :towel_warmer_controls_dual_connect, -> { where(sku: ItemConstants::TOWEL_WARMER_PLUG_IN_CONTROL_SKUS + ItemConstants::TOWEL_WARMER_HARDWIRE_CONTROL_SKUS) }
|
.towel_warmer_controls_hardwired ⇒ ActiveRecord::Relation<Item>
A relation of Items that are towel warmer controls hardwired. Active Record Scope
400
|
# File 'app/models/item.rb', line 400
scope :towel_warmer_controls_hardwired, -> { where(sku: ItemConstants::TOWEL_WARMER_HARDWIRE_CONTROL_SKUS) }
|
.towel_warmer_controls_plug_in ⇒ ActiveRecord::Relation<Item>
A relation of Items that are towel warmer controls plug in. Active Record Scope
399
|
# File 'app/models/item.rb', line 399
scope :towel_warmer_controls_plug_in, -> { where(sku: ItemConstants::TOWEL_WARMER_PLUG_IN_CONTROL_SKUS) }
|
.towel_warmers ⇒ ActiveRecord::Relation<Item>
A relation of Items that are towel warmers. Active Record Scope
.towel_warmers_hardwired ⇒ ActiveRecord::Relation<Item>
A relation of Items that are towel warmers hardwired. Active Record Scope
.towel_warmers_plug_in ⇒ ActiveRecord::Relation<Item>
A relation of Items that are towel warmers plug in. Active Record Scope
.underlayments ⇒ ActiveRecord::Relation<Item>
A relation of Items that are underlayments. Active Record Scope
.uom_select_options ⇒ Object
923
924
925
|
# File 'app/models/item.rb', line 923
def self.uom_select_options
%w[each feet]
end
|
.upgrades ⇒ ActiveRecord::Relation<Item>
A relation of Items that are upgrades. Active Record Scope
417
|
# File 'app/models/item.rb', line 417
scope :upgrades, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_UPGRADES)) }
|
.with_all_catalog_items_discontinued ⇒ ActiveRecord::Relation<Item>
A relation of Items that are with all catalog items discontinued. Active Record Scope
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
|
# File 'app/models/item.rb', line 617
scope :with_all_catalog_items_discontinued, -> {
where(%{
(
SELECT COUNT(*)
FROM catalog_items ci1
INNER JOIN store_items si1 ON ci1.store_item_id = si1.id
WHERE si1.item_id = items.id
) > 0
AND
(
SELECT COUNT(*)
FROM catalog_items ci1
INNER JOIN store_items si1 ON ci1.store_item_id = si1.id
WHERE si1.item_id = items.id
) =
(
SELECT COUNT(*)
FROM catalog_items ci2
INNER JOIN store_items si2 ON ci2.store_item_id = si2.id
WHERE si2.item_id = items.id AND ci2.state = 'discontinued'
)
})
}
|
.with_features ⇒ ActiveRecord::Relation<Item>
A relation of Items that are with features. Active Record Scope
515
|
# File 'app/models/item.rb', line 515
scope :with_features, -> { where.not(feature_1: nil).where.not(feature_2: nil).where.not(feature_3: nil).where.not(feature_4: nil).where.not(feature_5: nil) }
|
.with_product_specification ⇒ ActiveRecord::Relation<Item>
A relation of Items that are with product specification. Active Record Scope
475
476
477
478
479
480
481
482
483
484
|
# File 'app/models/item.rb', line 475
scope :with_product_specification, ->(token, value, grouping = nil, include_absence_of = false) {
match_hsh = { raw: TypeCoercer.coerce(value) }
grouping = grouping.to_s.titleize if grouping.is_a?(Symbol)
match_hsh[:grouping] = grouping if grouping.present?
test_condition_criteria = +'items.rendered_product_specifications @> :condition_1'
test_condition_criteria << ' OR NOT (rendered_product_specifications ? :condition_2)' if include_absence_of
condition_1 = { token.to_s => match_hsh }.to_json
condition_2 = token.to_s
where(test_condition_criteria, condition_1:, condition_2:)
}
|
.with_stock ⇒ ActiveRecord::Relation<Item>
A relation of Items that are with stock. Active Record Scope
428
429
430
|
# File 'app/models/item.rb', line 428
scope :with_stock, -> {
where("exists(select id from store_items where store_items.item_id = items.id and qty_on_hand > 0 and store_items.location = 'AVAILABLE')")
}
|
.with_stock_for ⇒ ActiveRecord::Relation<Item>
A relation of Items that are with stock for. Active Record Scope
431
432
433
|
# File 'app/models/item.rb', line 431
scope :with_stock_for, ->(store_id) {
where("exists(select id from store_items where store_items.store_id = ? and store_items.item_id = items.id and qty_on_hand > 0 and store_items.location = 'AVAILABLE')", store_id)
}
|
Instance Method Details
#all_images ⇒ Object
Find all images linked to this item directly or by combination of product line or category ancestry
This is a simpler method than image retriever
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
|
# File 'app/models/item.rb', line 2418
def all_images
query = Image.left_outer_joins(:items)
.left_outer_joins(:product_lines)
.left_outer_joins(:product_categories)
conditions = []
plids = product_line_ancestry_ids
pcids = product_category_ancestry_ids
conditions << Item[:id].eq(id)
conditions << ProductLine[:id].in(plids).and(ProductCategory[:id].eq(nil)) if plids.present?
conditions << ProductLine[:id].eq(nil).and(ProductCategory[:id].in(pcids)) if pcids.present?
conditions << ProductLine[:id].in(plids).and(ProductCategory[:id].in(pcids)) if plids.present? && pcids.present?
combined_conditions = conditions.reduce { |acc, condition| acc.or(condition) }
query.where(combined_conditions)
end
|
#all_my_publications(categories: nil, locale: nil, publication_category_paths: nil) ⇒ Object
1740
1741
1742
|
# File 'app/models/item.rb', line 1740
def all_my_publications(categories: nil, locale: nil, publication_category_paths: nil)
Item::PublicationRetriever.new.process(self, categories:, locale:, publication_category_paths:).all_publications
end
|
#all_site_maps ⇒ Object
1955
1956
1957
|
# File 'app/models/item.rb', line 1955
def all_site_maps
[] + site_maps.to_a + catalog_item_site_maps.to_a
end
|
#all_uploads ⇒ Object
2476
2477
2478
|
# File 'app/models/item.rb', line 2476
def all_uploads
uploads.order(Upload[:created_at].desc)
end
|
#any_box_changed? ⇒ Boolean
2472
2473
2474
|
# File 'app/models/item.rb', line 2472
def any_box_changed?
box1_changed? || box2_changed? || box3_changed?
end
|
#articles ⇒ ActiveRecord::Relation<Article>
307
|
# File 'app/models/item.rb', line 307
has_and_belongs_to_many :articles
|
#assortment_instructions ⇒ ActiveRecord::Relation<AssortmentInstruction>
310
|
# File 'app/models/item.rb', line 310
has_and_belongs_to_many :assortment_instructions, inverse_of: :items
|
#async_update_rendered_product_specifications ⇒ Object
1951
1952
1953
|
# File 'app/models/item.rb', line 1951
def async_update_rendered_product_specifications
ItemAttributeWorker.perform_async(id)
end
|
#authenticated_url(dimensions = nil) ⇒ Object
864
865
866
|
# File 'app/models/item.rb', line 864
def authenticated_url(dimensions = nil)
(dimensions.nil? ? literature.attachment.url : literature.attachment.thumb(dimensions, format: 'png', frame: '0').url) if literature
end
|
#auto_translate(reset_previous_values: false, locales: nil) ⇒ Object
1808
1809
1810
1811
1812
1813
1814
1815
1816
|
# File 'app/models/item.rb', line 1808
def auto_translate(reset_previous_values: false, locales: nil)
locales ||= content_locales_to_render
Rails.logger.info "Product Specifications for Item #{id}:#{sku} will be rendered in #{locales.join(', ')}"
auto_translate_product_specifications(reset_previous_values:, locales:)
reload
update_rendered_product_specifications(locales:)
:success
end
|
#auto_translate_attributes(reset_previous_values: false, locales: nil) ⇒ Object
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
|
# File 'app/models/item.rb', line 1818
def auto_translate_attributes(reset_previous_values: false, locales: nil)
locales ||= content_locales_to_render
res = {}
TRANSLATABLE_ATTRIBUTES.each do |attr_name|
next unless (english_val = send(:"#{attr_name}_en").presence)
res[attr_name] = {}
locales.each do |locale|
next if !reset_previous_values && Mobility.with_locale(locale) { send(attr_name.to_sym) }.present?
localized_val = TranslationKey.translate(english_val, locale, namespace: TRANSLATION_NAMESPACE, auto_create: false, auto_translate: true, resource: self, resource_attribute: attr_name)
next if localized_val.blank?
Mobility.with_locale(locale) { send(:"#{attr_name}=", localized_val, locale:) }
res[attr_name][locale] = localized_val
end
end
if save && res
:success
else
:error
end
end
|
#auto_translate_product_specifications(reset_previous_values: false, locales: nil) ⇒ Object
1847
1848
1849
1850
1851
1852
1853
|
# File 'app/models/item.rb', line 1847
def auto_translate_product_specifications(reset_previous_values: false, locales: nil)
locales ||= content_locales_to_render
product_specifications.each do |ps|
ps.auto_translate(reset_previous_values:, locales:)
end
:success
end
|
#available_content_locales ⇒ Object
Returns all locales from the catalog this item is part of
1996
1997
1998
1999
|
# File 'app/models/item.rb', line 1996
def available_content_locales
Catalog.eager_load(:catalog_items).merge(catalog_items.not_discontinued).pluck(:locales).flatten.compact.uniq.sort
end
|
#available_token_options_from_product_specifications ⇒ Object
2142
2143
2144
|
# File 'app/models/item.rb', line 2142
def available_token_options_from_product_specifications
(rendered_product_specifications || {}).each_with_object({}.with_indifferent_access) { |(rpk, rpv), hsh| hsh[rpk] = rpv[:output] }
end
|
#base_weight_converted(unit: 'lbs', precision: nil) ⇒ Object
1610
1611
1612
|
# File 'app/models/item.rb', line 1610
def base_weight_converted(unit: 'lbs', precision: nil)
express_weight_converted base_weight, unit:, precision:
end
|
#box1_changed? ⇒ Boolean
2452
2453
2454
|
# File 'app/models/item.rb', line 2452
def box1_changed?
%i[shipping_weight shipping_length shipping_width shipping_weight].any? { |fn| send(:"#{fn}_previously_changed?") || send(:"will_save_change_to_#{fn}?") }
end
|
#box1_defined? ⇒ Boolean
2448
2449
2450
|
# File 'app/models/item.rb', line 2448
def box1_defined?
%i[shipping_weight shipping_length shipping_width shipping_weight].all? { |fn| send(fn)&.positive? }
end
|
#box2_changed? ⇒ Boolean
2460
2461
2462
|
# File 'app/models/item.rb', line 2460
def box2_changed?
%i[box2_shipping_weight box2_shipping_length box2_shipping_width box2_shipping_weight].any? { |fn| send(:"#{fn}_previously_changed?") || send(:"will_save_change_to_#{fn}?") }
end
|
#box2_defined? ⇒ Boolean
2456
2457
2458
|
# File 'app/models/item.rb', line 2456
def box2_defined?
%i[box2_shipping_weight box2_shipping_length box2_shipping_width box2_shipping_height].all? { |fn| send(fn)&.positive? }
end
|
#box2_shipping_dimensions_to_package ⇒ Object
1641
1642
1643
1644
1645
1646
|
# File 'app/models/item.rb', line 1641
def box2_shipping_dimensions_to_package
return unless box2_defined?
Shipping::Container.new(length: box2_shipping_length, width: box2_shipping_width, height: box2_shipping_height, weight: box2_shipping_weight,
container_type:)
end
|
#box2_shipping_height_converted(unit: 'in', precision: 0) ⇒ Object
1578
1579
1580
1581
1582
|
# File 'app/models/item.rb', line 1578
def box2_shipping_height_converted(unit: 'in', precision: 0)
return unless box2_shipping_height
RubyUnits::Unit.new("#{box2_shipping_height} in").convert_to(unit.to_s).scalar.to_f.round(precision)
end
|
#box2_shipping_length_converted(unit: 'in', precision: 0) ⇒ Object
1566
1567
1568
1569
1570
|
# File 'app/models/item.rb', line 1566
def box2_shipping_length_converted(unit: 'in', precision: 0)
return unless box2_shipping_length
RubyUnits::Unit.new("#{box2_shipping_length} in").convert_to(unit.to_s).scalar.to_f.round(precision)
end
|
#box2_shipping_weight_converted(unit: 'lbs', precision: nil) ⇒ Object
1626
1627
1628
|
# File 'app/models/item.rb', line 1626
def box2_shipping_weight_converted(unit: 'lbs', precision: nil)
express_weight_converted box2_shipping_weight, unit:, precision:
end
|
#box2_shipping_width_converted(unit: 'in', precision: 0) ⇒ Object
1572
1573
1574
1575
1576
|
# File 'app/models/item.rb', line 1572
def box2_shipping_width_converted(unit: 'in', precision: 0)
return unless box2_shipping_width
RubyUnits::Unit.new("#{box2_shipping_width} in").convert_to(unit.to_s).scalar.to_f.round(precision)
end
|
#box3_changed? ⇒ Boolean
2468
2469
2470
|
# File 'app/models/item.rb', line 2468
def box3_changed?
%i[box3_shipping_weight box3_shipping_length box3_shipping_width box3_shipping_weight].any? { |fn| send(:"#{fn}_previously_changed?") || send(:"will_save_change_to_#{fn}?") }
end
|
#box3_defined? ⇒ Boolean
2464
2465
2466
|
# File 'app/models/item.rb', line 2464
def box3_defined?
%i[box3_shipping_weight box3_shipping_length box3_shipping_width box3_shipping_height].all? { |fn| send(fn)&.positive? }
end
|
#box3_shipping_dimensions_to_package ⇒ Object
1648
1649
1650
1651
1652
1653
|
# File 'app/models/item.rb', line 1648
def box3_shipping_dimensions_to_package
return unless box3_defined?
Shipping::Container.new(length: box3_shipping_length, width: box3_shipping_width, height: box3_shipping_height, weight: box3_shipping_weight,
container_type:)
end
|
#box3_shipping_height_converted(unit: 'in', precision: 0) ⇒ Object
1596
1597
1598
1599
1600
|
# File 'app/models/item.rb', line 1596
def box3_shipping_height_converted(unit: 'in', precision: 0)
return unless box3_shipping_height
RubyUnits::Unit.new("#{box3_shipping_height} in").convert_to(unit.to_s).scalar.to_f.round(precision)
end
|
#box3_shipping_length_converted(unit: 'in', precision: 0) ⇒ Object
1584
1585
1586
1587
1588
|
# File 'app/models/item.rb', line 1584
def box3_shipping_length_converted(unit: 'in', precision: 0)
return unless box3_shipping_length
RubyUnits::Unit.new("#{box3_shipping_length} in").convert_to(unit.to_s).scalar.to_f.round(precision)
end
|
#box3_shipping_weight_converted(unit: 'lbs', precision: nil) ⇒ Object
1630
1631
1632
|
# File 'app/models/item.rb', line 1630
def box3_shipping_weight_converted(unit: 'lbs', precision: nil)
express_weight_converted box3_shipping_weight, unit:, precision:
end
|
#box3_shipping_width_converted(unit: 'in', precision: 0) ⇒ Object
1590
1591
1592
1593
1594
|
# File 'app/models/item.rb', line 1590
def box3_shipping_width_converted(unit: 'in', precision: 0)
return unless box3_shipping_width
RubyUnits::Unit.new("#{box3_shipping_width} in").convert_to(unit.to_s).scalar.to_f.round(precision)
end
|
#boxes ⇒ Object
1003
1004
1005
1006
1007
1008
|
# File 'app/models/item.rb', line 1003
def boxes
b = [[shipping_length, shipping_width, shipping_height, shipping_weight]]
b << [box2_shipping_length, box2_shipping_width, box2_shipping_height, box2_shipping_weight] if box2_defined?
b << [box3_shipping_length, box3_shipping_width, box3_shipping_height, box3_shipping_weight] if box3_defined?
b
end
|
#boxes_shipping_dimensions_and_weights_converted(units: { length: 'in', weight: 'lbs' }, precision: 2) ⇒ Object
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
|
# File 'app/models/item.rb', line 1083
def boxes_shipping_dimensions_and_weights_converted(units: { length: 'in', weight: 'lbs' }, precision: 2)
boxes.map do |b|
[
RubyUnits::Unit.new("#{b[0]} in").convert_to(units[:length].to_s).scalar.to_f.round(precision),
RubyUnits::Unit.new("#{b[1]} in").convert_to(units[:length].to_s).scalar.to_f.round(precision),
RubyUnits::Unit.new("#{b[2]} in").convert_to(units[:length].to_s).scalar.to_f.round(precision),
RubyUnits::Unit.new("#{b[3]} lb").convert_to(units[:weight].to_s).scalar.to_f.round(precision)
]
end
end
|
#boxes_shipping_dimensions_and_weights_display(units: { length: 'in', weight: 'lbs' }, precision: 2) ⇒ Object
1094
1095
1096
1097
1098
1099
1100
1101
|
# File 'app/models/item.rb', line 1094
def boxes_shipping_dimensions_and_weights_display(units: { length: 'in', weight: 'lbs' }, precision: 2)
boxes_shipping_dimensions_and_weights_converted(units:, precision:).map do |b|
"#{format('%g', b[0])} #{units[:length]} x #{format('%g', b[1])} #{units[:length]} x #{format('%g', b[2])} #{units[:length]} x #{format('%g', b[3])} #{units[:weight]}"
end
end
|
#boxes_to_packages ⇒ Object
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
|
# File 'app/models/item.rb', line 1010
def boxes_to_packages
packages = []
boxes.each do |box|
le, wi, he, we, = box + [0]
package = Shipping::Container.new(length: le, width: wi, height: he, weight: we, container_type: Shipment.container_type_from_packdim_int(0))
package.add_content(id, 1)
packages << package
end
packages
end
|
264
|
# File 'app/models/item.rb', line 264
belongs_to :brand, optional: true
|
#calculate_ideal_cable_spacing ⇒ Object
1434
1435
1436
1437
1438
1439
1440
|
# File 'app/models/item.rb', line 1434
def calculate_ideal_cable_spacing
res = nil
if primary_product_line && primary_product_line.get_first_heating_system_type.present?
res = HeatingElementProductLineOption.get_field_array_from_options(:ideal_cable_spacing, product_line_id: primary_product_line.get_first_heating_system_type.id).first
end
res
end
|
#calculate_is_cable_system? ⇒ Boolean
1425
1426
1427
1428
1429
1430
1431
1432
|
# File 'app/models/item.rb', line 1425
def calculate_is_cable_system?
res = nil
if primary_product_line && primary_product_line.get_first_heating_system_type.present? && HeatingElementProductLineOption.get_field_array_from_options(:require_cable_spacing,
product_line_id: primary_product_line.get_first_heating_system_type.id).first
res = true
end
res
end
|
#calculate_item_fields ⇒ Object
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
|
# File 'app/models/item.rb', line 985
def calculate_item_fields
sorted_dims = [shipping_length, shipping_width, shipping_height].sort_by(&:to_f)
self.shipping_length = sorted_dims[2]
self.shipping_width = sorted_dims[1]
self.shipping_height = sorted_dims[0]
box2_sorted_dims = [box2_shipping_length, box2_shipping_width, box2_shipping_height].sort_by(&:to_f)
self.box2_shipping_length = box2_sorted_dims[2]
self.box2_shipping_width = box2_sorted_dims[1]
self.box2_shipping_height = box2_sorted_dims[0]
box3_sorted_dims = [box3_shipping_length, box3_shipping_width, box3_shipping_height].sort_by(&:to_f)
self.box3_shipping_length = box3_sorted_dims[2]
self.box3_shipping_width = box3_sorted_dims[1]
self.box3_shipping_height = box3_sorted_dims[0]
self.ideal_cable_spacing = (calculate_ideal_cable_spacing if (self.is_cable_system = calculate_is_cable_system?))
true
end
|
#can_be_packaged? ⇒ Boolean
976
977
978
|
# File 'app/models/item.rb', line 976
def can_be_packaged?
Item.packageable.where(id:).present?
end
|
#canonical_path ⇒ Object
Hierarchical canonical path via product line ancestry + SKU.
e.g. "towel-warmer/barcelona/TW-BC-08BS-FS2"
730
731
732
733
734
735
736
737
|
# File 'app/models/item.rb', line 730
def canonical_path
return nil unless primary_product_line
pl_path = primary_product_line.canonical_path
return nil if pl_path.blank?
"#{pl_path}/#{sku}"
end
|
#canonical_sku ⇒ Object
1695
1696
1697
1698
1699
1700
1701
1702
|
# File 'app/models/item.rb', line 1695
def canonical_sku
sku_match = sku.match(/(.*)-([[:alpha:]])$/)
if sku_match && (sku_match.length == 3)
sku_match[1]
else
sku
end
end
|
#canonical_url(locale: I18n.locale) ⇒ Object
Canonical URL with locale prefix.
e.g. "/en-US/towel-warmer/barcelona/TW-BC-08BS-FS2"
741
742
743
744
745
746
|
# File 'app/models/item.rb', line 741
def canonical_url(locale: I18n.locale)
path = canonical_path
return nil unless path
"/#{locale}/#{path}"
end
|
#catalog_item_site_maps ⇒ ActiveRecord::Relation<SiteMap>
293
|
# File 'app/models/item.rb', line 293
has_many :catalog_item_site_maps, class_name: 'SiteMap', source: :site_maps, through: :catalog_items
|
#catalog_items ⇒ ActiveRecord::Relation<CatalogItem>
271
|
# File 'app/models/item.rb', line 271
has_many :catalog_items, through: :store_items, inverse_of: :item
|
#catalogs ⇒ ActiveRecord::Relation<Catalog>
272
|
# File 'app/models/item.rb', line 272
has_many :catalogs, through: :catalog_items
|
#check_oversize?(carrier: nil) ⇒ Boolean
Check if item is oversize, optionally for a specific carrier
When no carrier specified, checks all carriers (item is oversize if ANY carrier flags it)
1681
1682
1683
1684
1685
1686
1687
|
# File 'app/models/item.rb', line 1681
def check_oversize?(carrier: nil)
r = run_shipping_audit(carrier:)
r.any?(&:oversize_conditions?)
rescue StandardError
logger.error "Oversize check failed on item id #{id}, returning false"
false
end
|
#compatible_items ⇒ ActiveRecord::Relation<CompatibleItem>
298
|
# File 'app/models/item.rb', line 298
has_many :compatible_items, -> { merge(ItemRelation.replacement_parts) }, through: :source_item_relations, source: :source_item
|
#container_type ⇒ Object
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
|
# File 'app/models/item.rb', line 2368
def container_type
if ships_via_crate?
Shipment.container_types.keys[2] elsif shipping_class == 'freight_service'
Shipment.container_types.keys[1] else
Shipment.container_types.keys.first end
end
|
#content_locales_to_render ⇒ Object
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
|
# File 'app/models/item.rb', line 2001
def content_locales_to_render
if is_publication?
Mobility.available_locales
else
locales = (Mobility.available_locales & ([I18n.default_locale] + available_content_locales)).uniq
locales.delete(:'en-US')
locales.delete(:'en-CA')
locales.delete(:'fr-CA') if locales.include?(:fr)
locales
end
end
|
#controllable? ⇒ Boolean
771
772
773
774
775
|
# File 'app/models/item.rb', line 771
def controllable?
is_heating_element? ||
is_towel_warmer? ||
is_infrared_heating_panel?
end
|
#country_of_origin_iso3 ⇒ Object
715
716
717
718
719
|
# File 'app/models/item.rb', line 715
def country_of_origin_iso3
return unless coo
ISO3166::Country[coo]&.alpha3
end
|
#country_of_origin_name ⇒ Object
709
710
711
712
713
|
# File 'app/models/item.rb', line 709
def country_of_origin_name
return unless coo
ISO3166::Country[coo]&.iso_short_name
end
|
#create_template_specifications ⇒ Object
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
|
# File 'app/models/item.rb', line 2108
def create_template_specifications
return OpenStruct.new(created: [], errors: ['Missing Product Line or Product Category']) unless primary_product_line_id || product_category_id
res = Item::SpecificationsRetriever.new.process(self, template: true)
res_classic = Item::SpecificationsRetriever.new.process(self, template: false)
ps_created = []
ps_errors = []
res.specifications.each do |template_spec|
next if spec_value(template_spec.token).present? || res_classic.specifications.any? { |s| s.token == template_spec.token }
s = template_spec.dup
s.product_category_id = nil
s.product_line_id = nil
s.template = false
s.item_ids = [id].compact
s.template_product_specification_id = template_spec.id
if s.save
ps_created << s
else
ps_errors << "Template Spec id #{template_spec.id} : #{template_spec} could not be created for item #{id}|#{sku}. Errors: #{s.errors_to_s}"
end
end
OpenStruct.new(created: ps_created, errors: ps_errors)
end
|
#current_supplier_cost ⇒ Object
765
766
767
768
769
|
# File 'app/models/item.rb', line 765
def current_supplier_cost
return 'not found' if supplier_items.empty? || (current_price = supplier_items.order(created_at: :desc).first&.current_price).nil?
"#{current_price.unit_cost} #{current_price.currency}"
end
|
#deep_dup ⇒ Object
227
228
229
230
231
232
233
234
|
# File 'app/models/item.rb', line 227
def deep_dup
deep_clone(
include: :item_product_lines,
except: %i[upc upload_id last_sale_date first_sale_date popularity amazon_asin]
) do |_original, copy|
copy.popularity = nil if copy.is_a?(Item)
end
end
|
#default_short_description ⇒ Object
1763
1764
1765
1766
1767
|
# File 'app/models/item.rb', line 1763
def default_short_description
return unless (dd = detailed_description.to_s.squish.presence) && dd.present?
dd.truncate(120, separator: ' ')
end
|
#detailed_description ⇒ Object
Creates a text description from the html rendered description
1759
1760
1761
|
# File 'app/models/item.rb', line 1759
def detailed_description
html_to_text(rendered_detailed_description_html)
end
|
#digital_assets ⇒ ActiveRecord::Relation<DigitalAsset>
308
|
# File 'app/models/item.rb', line 308
has_and_belongs_to_many :digital_assets
|
#direct_packings ⇒ ActiveRecord::Relation<Packing>
301
|
# File 'app/models/item.rb', line 301
has_many :direct_packings, class_name: 'Packing', inverse_of: :item, dependent: :destroy
|
#direct_product_specifications ⇒ ActiveRecord::Relation<ProductSpecification>
312
|
# File 'app/models/item.rb', line 312
has_and_belongs_to_many :direct_product_specifications, class_name: 'ProductSpecification', dependent: :destroy, inverse_of: :items
|
#discontinue_self_and_dependents ⇒ Object
966
967
968
969
970
971
972
973
974
|
# File 'app/models/item.rb', line 966
def discontinue_self_and_dependents
self.class.transaction do
store_items.each do |si|
si.catalog_items.each(&:discontinue) si.update_attribute!(:is_discontinued, true)
end
update!(is_discontinued: true, cycle_count_grouping: 'not_set')
end
end
|
#discontinue_store_and_catalog_items ⇒ Object
959
960
961
962
963
964
|
# File 'app/models/item.rb', line 959
def discontinue_store_and_catalog_items
return if is_publication?
discontinue_self_and_dependents if is_discontinued?
true
end
|
#ean13 ⇒ Object
853
854
855
856
857
858
859
860
861
862
|
# File 'app/models/item.rb', line 853
def ean13
return if upc.blank?
case upc.size
when 12
"0#{upc}"
when 13
upc
end
end
|
#edge_cache_urls ⇒ Object
Absolute Cloudflare URLs for this item's pages AND their lazy section
fragments (documents/reviews/…), which Cloudflare caches as separate edge
entries from the page URL (see SiteMap#section_cache_urls). uniq: all_site_maps
merges two associations that can expand to overlapping section URLs.
1974
1975
1976
|
# File 'app/models/item.rb', line 1974
def edge_cache_urls
all_site_maps.flat_map { |sm| [sm.url, *sm.section_cache_urls] }.uniq
end
|
#edi_communication_logs ⇒ ActiveRecord::Relation<EdiCommunicationLog>
303
|
# File 'app/models/item.rb', line 303
has_many :edi_communication_logs, through: :edi_documents
|
#edi_documents ⇒ ActiveRecord::Relation<EdiDocument>
302
|
# File 'app/models/item.rb', line 302
has_many :edi_documents, dependent: :destroy
|
#effective_nmfc_class ⇒ Object
Alias for Product_category#effective_nmfc_class
649
650
651
652
653
654
655
656
657
658
|
# File 'app/models/item.rb', line 649
delegate :is_control?,
:is_upgrade?,
:is_accessory?,
:is_relay_panel?,
:is_custom_mat?,
:effective_nmfc_code,
:effective_nmfc_class,
:is_publication?,
to: :product_category,
allow_nil: true
|
#effective_nmfc_code ⇒ Object
Alias for Product_category#effective_nmfc_code
649
650
651
652
653
654
655
656
657
658
|
# File 'app/models/item.rb', line 649
delegate :is_control?,
:is_upgrade?,
:is_accessory?,
:is_relay_panel?,
:is_custom_mat?,
:effective_nmfc_code,
:effective_nmfc_class,
:is_publication?,
to: :product_category,
allow_nil: true
|
#effective_option_name ⇒ Object
2296
2297
2298
|
# File 'app/models/item.rb', line 2296
def effective_option_name
option_name.presence || public_short_name.presence || name
end
|
#effective_seo_description(char_limit: nil) ⇒ Object
868
869
870
871
872
873
874
875
876
877
878
879
880
|
# File 'app/models/item.rb', line 868
def effective_seo_description(char_limit: nil)
char_limit ||= SEO_META_DESCRIPTION_MAX_LENGTH
d = seo_description.presence || short_description.presence || public_description_text || name
return unless d
d.tr!("\n", ' ')
d.tr!("\r", ' ')
d.tr!("\t", ' ')
d.squeeze!(' ')
d = d.truncate(char_limit, separator: /\s/) if char_limit
d.squish
end
|
#effective_seo_keywords ⇒ Object
1790
1791
1792
1793
1794
1795
1796
1797
|
# File 'app/models/item.rb', line 1790
def effective_seo_keywords
return seo_keywords.presence if seo_keywords.present?
pl_keywords = primary_product_line&.effective_seo_keywords
return pl_keywords.join(',') if pl_keywords.is_a?(Array)
pl_keywords.presence
end
|
#effective_seo_title(skip_sku: false) ⇒ Object
882
883
884
885
886
887
888
889
890
891
892
893
|
# File 'app/models/item.rb', line 882
def effective_seo_title(skip_sku: false)
s = (seo_title.presence || public_short_name.presence || public_name.presence).to_s
if !skip_sku && (s.size + sku.size + 3) < SEO_TITLE_MAX_LENGTH && s.exclude?(sku)
s << " (#{sku})"
end
if s.size > SEO_TITLE_MAX_LENGTH
s.truncate(SEO_TITLE_MAX_LENGTH, separator: /\s/, omission: '')
end
s
end
|
255
|
# File 'app/models/item.rb', line 255
belongs_to :exclusive_item_group, inverse_of: :items, optional: true
|
#express_weight_converted(weight_in_lbs, unit: 'lbs', precision: nil) ⇒ Object
1602
1603
1604
1605
1606
1607
1608
|
# File 'app/models/item.rb', line 1602
def express_weight_converted(weight_in_lbs, unit: 'lbs', precision: nil)
return unless weight_in_lbs
precision ||= (unit == 'g' ? 0 : 2)
d = RubyUnits::Unit.new("#{weight_in_lbs} lbs")
d.convert_to(unit.to_s).scalar.to_f.round(precision)
end
|
#facet ⇒ Object
2277
2278
2279
2280
2281
2282
2283
2284
2285
|
# File 'app/models/item.rb', line 2277
def facet
return unless (pl = primary_product_line&.get_first_show_in_sales_portal_ancestor(exclude_main_line: false))
return unless (pc = product_category)
potential_facets = pl.facets.select { |f| f.product_category_ids.to_a.include?(pc.id) }
return if potential_facets.blank?
potential_facets.first
end
|
#facet_sort_keys ⇒ Object
2292
2293
2294
|
# File 'app/models/item.rb', line 2292
def facet_sort_keys
facet&.sort_keys
end
|
#facet_tokens ⇒ Object
2288
2289
2290
|
# File 'app/models/item.rb', line 2288
def facet_tokens
facet&.grouping_spec_tokens&.reject(&:blank?)
end
|
#features ⇒ Object
Features are a sub category of specs with feature priority set
1911
1912
1913
1914
1915
1916
1917
|
# File 'app/models/item.rb', line 1911
def features
if has_features?
[feature_1, feature_2, feature_3, feature_4, feature_5].filter_map(&:presence)
else
inherited_features end
end
|
#fix_name ⇒ Object
1769
1770
1771
1772
1773
1774
|
# File 'app/models/item.rb', line 1769
def fix_name
self.name = name.tr("'", '′')
self.name = name.tr('"', '″')
end
|
#fixture_key ⇒ Object
1442
1443
1444
|
# File 'app/models/item.rb', line 1442
def fixture_key
sku.to_s
end
|
#freight_class ⇒ Object
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
|
# File 'app/models/item.rb', line 1064
def freight_class
freight_class = nil
if base_weight.present? && shipping_volume_in_cubic_feet.present?
pcf = base_weight / shipping_volume_in_cubic_feet
Shipping::UpsFreight::FREIGHT_CLASS_BY_PCF.each do |fc, pcf_limits|
if pcf >= pcf_limits[:lower] && pcf < pcf_limits[:upper]
freight_class = fc.to_i
break
end
end
end
freight_class
end
|
#generate_refurbished_sku ⇒ Object
1720
1721
1722
|
# File 'app/models/item.rb', line 1720
def generate_refurbished_sku
"#{sku}-BTK"
end
|
#get_quantity_from_sqft(input_sqft, add_one_extra = false) ⇒ Object
1474
1475
1476
1477
1478
|
# File 'app/models/item.rb', line 1474
def get_quantity_from_sqft(input_sqft, = false)
qty = ? 1 : 0
qty += (input_sqft / sqft).ceil.to_i if sqft.to_f > 0.0
qty
end
|
#gross_weight_converted(unit: 'lbs', precision: nil) ⇒ Object
1614
1615
1616
|
# File 'app/models/item.rb', line 1614
def gross_weight_converted(unit: 'lbs', precision: nil)
express_weight_converted gross_weight, unit:, precision:
end
|
#gtin13 ⇒ Object
1516
1517
1518
|
# File 'app/models/item.rb', line 1516
def gtin13
"0#{upc}"
end
|
#gtin_type ⇒ Object
748
749
750
751
752
|
# File 'app/models/item.rb', line 748
def gtin_type
return :missing if upc.blank?
Item::UpcBarcode.identify_type(upc)
end
|
#gtin_type_friendly ⇒ Object
754
755
756
757
758
759
760
761
762
763
|
# File 'app/models/item.rb', line 754
def gtin_type_friendly
case gtin_type
when :gtin12
'GTIN-12/UPC'
when :gtin13
'GTIN-13/EAN'
else
'Unknown/Invalid'
end
end
|
#harmonization_code_hs6(with_dot = true) ⇒ Object
Returns the first 6 digits of the harmonization code (HS6)
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
|
# File 'app/models/item.rb', line 1525
def harmonization_code_hs6(with_dot = true)
return nil if harmonization_code.blank?
digits = harmonization_code.delete('.').first(6)
if with_dot
"#{digits[0..3]}.#{digits[4..5]}"
else
digits
end
end
|
#has_ean13? ⇒ Boolean
849
850
851
|
# File 'app/models/item.rb', line 849
def has_ean13?
upc && upc.size == 13
end
|
#has_features? ⇒ Boolean
1906
1907
1908
|
# File 'app/models/item.rb', line 1906
def has_features?
[feature_1, feature_2, feature_3, feature_4, feature_5].any?(&:present?)
end
|
#has_heating_system? ⇒ Boolean
1458
1459
1460
|
# File 'app/models/item.rb', line 1458
def has_heating_system?
primary_product_line.get_first_heating_system_type.present?
end
|
#has_stock? ⇒ Boolean
945
946
947
|
# File 'app/models/item.rb', line 945
def has_stock?
self.class.with_stock.exists?(id:)
end
|
#has_stock_in_store?(st_id) ⇒ Boolean
949
950
951
|
# File 'app/models/item.rb', line 949
def has_stock_in_store?(st_id)
self.class.with_stock_for(st_id).exists?(id:)
end
|
#image_profiles ⇒ ActiveRecord::Relation<ImageProfile>
304
|
# File 'app/models/item.rb', line 304
has_many :image_profiles, -> { image_order }
|
#image_url(dimensions, options = {}) ⇒ Object
1125
1126
1127
1128
|
# File 'app/models/item.rb', line 1125
def image_url(dimensions, options = {})
opts = { size: dimensions }.merge(options)
image_url2(opts)
end
|
#image_url2(options = {}) ⇒ Object
Use this new form that passes the options straight to the url generator
1117
1118
1119
1120
1121
1122
1123
|
# File 'app/models/item.rb', line 1117
def image_url2(options = {})
if primary_image
primary_image.image_url(options)
elsif new_item&.primary_image
new_item.primary_image.image_url(options)
end
end
|
#images ⇒ ActiveRecord::Relation<Image>
305
|
# File 'app/models/item.rb', line 305
has_many :images, through: :image_profiles
|
#import_translation_keys ⇒ Object
This method will import existing translations or link to existing ones
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
|
# File 'app/models/item.rb', line 1856
def import_translation_keys
tkrs = []
translations.each do |(locale_string, existing_translations)|
existing_translations.each do |attr, translation|
next unless attr.to_sym.in?(TRANSLATABLE_ATTRIBUTES)
next if translation_key_resources.joins(translation_key: :translations).where(resource_attribute: attr).joins(translation_key: :translations).where(TranslationText[:locale].eq(locale_string)).exists?
next if (text = TranslationKey.newline_normalize(send(:"#{attr}_en"))).blank?
next unless TranslationKey.translatable?(text)
tk = TranslationKey.where(key: text, namespace: TRANSLATION_NAMESPACE).first_or_create!
tk.translations.where(locale: locale_string.first(2)).first_or_create!(text: translation)
tkrs << tk.translation_key_resources.where(resource: self, resource_attribute: attr).first_or_create!
end
end
spec_ids = Item::SpecificationsMasher.new.process(item: self).specifications.values.pluck(:product_specification_id).uniq.compact
specifications_to_import = ProductSpecification.where(id: spec_ids)
tkrs += specifications_to_import.map(&:import_translation_keys).flatten.compact
tkrs
end
|
#increment_request_counter ⇒ Object
781
782
783
784
785
|
# File 'app/models/item.rb', line 781
def increment_request_counter
return unless persisted?
Item.update_counters id, requested_counter: 1
end
|
#inherited_features ⇒ Object
Seek inherited features from the primary product line
To inherit features, a product line's product category must be empty or matching
e.g Tempzone Floor Heating has Heating Elements as a product category
then items belonging to Tempzone Floor Heating must also be heating elements to
inherit its features
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
|
# File 'app/models/item.rb', line 1924
def inherited_features
features_result = []
if (ppl = primary_product_line) && (pc_url = product_category_url)
ppl.self_and_ancestors.select(&:has_features?).each do |pl|
if pl.product_categories.empty? || pl.product_categories.any? { |pc| pc_url.starts_with?(pc.url) }
features_result = pl.features
break
end
end
end
features_result.filter_map(&:presence)
end
|
#is_accessory? ⇒ Object
Alias for Product_category#is_accessory?
649
650
651
652
653
654
655
656
657
658
|
# File 'app/models/item.rb', line 649
delegate :is_control?,
:is_upgrade?,
:is_accessory?,
:is_relay_panel?,
:is_custom_mat?,
:effective_nmfc_code,
:effective_nmfc_class,
:is_publication?,
to: :product_category,
allow_nil: true
|
#is_available_to_public? ⇒ Boolean
808
809
810
811
|
# File 'app/models/item.rb', line 808
def is_available_to_public?
logger.debug "Checking if #{id} / #{sku} is available to public"
orderable_view_product_catalogs.present?
end
|
#is_cable_accessory? ⇒ Boolean
#is_cable_fit_guide? ⇒ Boolean
1385
1386
1387
1388
1389
|
# File 'app/models/item.rb', line 1385
def is_cable_fit_guide?
product_category&.is_accessory? &&
pl_descendant_of_path?(LtreePaths::PL_FLOOR_HEATING_TEMPZONE_THIN_CABLE) &&
name.to_s.downcase.include?('cable fixing plastic strip')
end
|
#is_cable_heating_element? ⇒ Boolean
#is_cable_tape? ⇒ Boolean
1391
1392
1393
1394
1395
|
# File 'app/models/item.rb', line 1391
def is_cable_tape?
product_category&.is_accessory? &&
pl_descendant_of_path?(LtreePaths::PL_FLOOR_HEATING_TEMPZONE_THIN_CABLE) &&
name.to_s.downcase.include?('tape')
end
|
#is_cerazorb? ⇒ Boolean
1340
1341
1342
|
# File 'app/models/item.rb', line 1340
def is_cerazorb?
primary_product_line&.is_cerazorb? && product_category&.is_insulation?
end
|
#is_circuit_check? ⇒ Boolean
1332
1333
1334
|
# File 'app/models/item.rb', line 1332
def is_circuit_check?
sku == ItemConstants::CIRCUIT_CHECK_SKU
end
|
#is_control? ⇒ Object
Alias for Product_category#is_control?
649
650
651
652
653
654
655
656
657
658
|
# File 'app/models/item.rb', line 649
delegate :is_control?,
:is_upgrade?,
:is_accessory?,
:is_relay_panel?,
:is_custom_mat?,
:effective_nmfc_code,
:effective_nmfc_class,
:is_publication?,
to: :product_category,
allow_nil: true
|
#is_cork? ⇒ Boolean
1336
1337
1338
|
# File 'app/models/item.rb', line 1336
def is_cork?
primary_product_line&.is_cork? && product_category&.is_insulation?
end
|
#is_custom_mat? ⇒ Object
Alias for Product_category#is_custom_mat?
649
650
651
652
653
654
655
656
657
658
|
# File 'app/models/item.rb', line 649
delegate :is_control?,
:is_upgrade?,
:is_accessory?,
:is_relay_panel?,
:is_custom_mat?,
:effective_nmfc_code,
:effective_nmfc_class,
:is_publication?,
to: :product_category,
allow_nil: true
|
#is_discontinued_or_publication ⇒ Object
Helper for validation: skips weight checks for discontinued items and publications
705
706
707
|
# File 'app/models/item.rb', line 705
def is_discontinued_or_publication
is_discontinued? || is_publication?
end
|
#is_economy_snow_melt_control? ⇒ Boolean
1356
1357
1358
|
# File 'app/models/item.rb', line 1356
def is_economy_snow_melt_control?
sku == ItemConstants::ECONOMY_SNOW_MELT_CONTROL_SKU
end
|
#is_floor_heating_product? ⇒ Boolean
1142
1143
1144
|
# File 'app/models/item.rb', line 1142
def is_floor_heating_product?
is_heating_element? && pl_descendant_of_path?(LtreePaths::PL_FLOOR_HEATING)
end
|
#is_goods? ⇒ Boolean
1274
1275
1276
|
# File 'app/models/item.rb', line 1274
def is_goods?
tax_class == 'g'
end
|
#is_heating_element? ⇒ Boolean
#is_infrared_heating_panel? ⇒ Boolean
#is_infrared_heating_panel_dual_connect? ⇒ Boolean
1196
1197
1198
|
# File 'app/models/item.rb', line 1196
def is_infrared_heating_panel_dual_connect?
is_infrared_heating_panel? && spec_value(:connection_method) == 'Plug-in or Hardwired'
end
|
#is_infrared_heating_panel_hardwired? ⇒ Boolean
#is_infrared_heating_panel_hardwired_control? ⇒ Boolean
1204
1205
1206
|
# File 'app/models/item.rb', line 1204
def is_infrared_heating_panel_hardwired_control?
sku.in?(ItemConstants::INFRARED_HEATING_PANELS_HARDWIRE_CONTROL_SKUS)
end
|
#is_infrared_heating_panel_plug_in? ⇒ Boolean
#is_infrared_heating_panel_plug_in_control? ⇒ Boolean
1200
1201
1202
|
# File 'app/models/item.rb', line 1200
def is_infrared_heating_panel_plug_in_control?
sku.in?(ItemConstants::INFRARED_HEATING_PANELS_PLUG_IN_CONTROL_SKUS)
end
|
#is_install_kit? ⇒ Boolean
1158
1159
1160
|
# File 'app/models/item.rb', line 1158
def is_install_kit?
sku&.start_with?(ItemConstants::INSTALL_KIT_SKU_PREFIX)
end
|
#is_junction_box? ⇒ Boolean
1360
1361
1362
|
# File 'app/models/item.rb', line 1360
def is_junction_box?
ItemConstants::JUNCTION_BOX_SKUS.include?(sku)
end
|
#is_led_mirror? ⇒ Boolean
1180
1181
1182
|
# File 'app/models/item.rb', line 1180
def is_led_mirror?
is_mirror? && pl_descendant_of_path?(LtreePaths::PL_LED_MIRROR)
end
|
#is_legacy_relay? ⇒ Boolean
1154
1155
1156
|
# File 'app/models/item.rb', line 1154
def is_legacy_relay?
sku&.start_with?(ItemConstants::LEGACY_RELAY_SKU_PREFIX)
end
|
#is_made_to_order_led_mirror? ⇒ Boolean
1410
1411
1412
1413
1414
|
# File 'app/models/item.rb', line 1410
def is_made_to_order_led_mirror?
primary_product_line&.is_made_to_order_led_mirror? end
|
#is_membrane? ⇒ Boolean
1402
1403
1404
|
# File 'app/models/item.rb', line 1402
def is_membrane?
Item.sku_is_membrane?(sku)
end
|
#is_mirror? ⇒ Boolean
1176
1177
1178
|
# File 'app/models/item.rb', line 1176
def is_mirror?
pc_descendant_of_path?(LtreePaths::PC_MIRRORS)
end
|
#is_mirror_defogger? ⇒ Boolean
#is_oj_programmable_tstat? ⇒ Boolean
#is_oj_programmable_wifi_tstat? ⇒ Boolean
1298
1299
1300
|
# File 'app/models/item.rb', line 1298
def is_oj_programmable_wifi_tstat?
ItemConstants::OJ_PROGRAMMABLE_WIFI_TSTAT_SKU_PREFIXES.any? { |prefix| sku&.start_with?(prefix) }
end
|
#is_pipe_freeze_protection? ⇒ Boolean
#is_power? ⇒ Boolean
1270
1271
1272
|
# File 'app/models/item.rb', line 1270
def is_power?
pc_descendant_of_path?(LtreePaths::PC_POWER)
end
|
#is_power_module? ⇒ Boolean
1150
1151
1152
|
# File 'app/models/item.rb', line 1150
def is_power_module?
ItemConstants::POWER_MODULE_SKU_PREFIXES.any? { |prefix| sku&.include?(prefix) }
end
|
#is_publication? ⇒ Object
Alias for Product_category#is_publication?
649
650
651
652
653
654
655
656
657
658
|
# File 'app/models/item.rb', line 649
delegate :is_control?,
:is_upgrade?,
:is_accessory?,
:is_relay_panel?,
:is_custom_mat?,
:effective_nmfc_code,
:effective_nmfc_class,
:is_publication?,
to: :product_category,
allow_nil: true
|
#is_radiator? ⇒ Boolean
777
778
779
|
# File 'app/models/item.rb', line 777
def is_radiator?
is_heating_element? || is_towel_warmer? || is_infrared_heating_panel? || is_mirror_defogger?
end
|
#is_refurbished? ⇒ Boolean
1724
1725
1726
|
# File 'app/models/item.rb', line 1724
def is_refurbished?
condition_refurbished?
end
|
#is_relay_panel? ⇒ Object
Alias for Product_category#is_relay_panel?
649
650
651
652
653
654
655
656
657
658
|
# File 'app/models/item.rb', line 649
delegate :is_control?,
:is_upgrade?,
:is_accessory?,
:is_relay_panel?,
:is_custom_mat?,
:effective_nmfc_code,
:effective_nmfc_class,
:is_publication?,
to: :product_category,
allow_nil: true
|
#is_reviewable? ⇒ Boolean
1446
1447
1448
|
# File 'app/models/item.rb', line 1446
def is_reviewable?
Item.reviewable.where(id:).present?
end
|
#is_roughin_kit? ⇒ Boolean
1406
1407
1408
|
# File 'app/models/item.rb', line 1406
def is_roughin_kit?
sku&.include?(ItemConstants::ROUGHIN_KIT_SKU_PATTERN)
end
|
#is_self_regulating_cable? ⇒ Boolean
#is_service? ⇒ Boolean
1282
1283
1284
|
# File 'app/models/item.rb', line 1282
def is_service?
tax_class == 'svc'
end
|
#is_shipping? ⇒ Boolean
1286
1287
1288
|
# File 'app/models/item.rb', line 1286
def is_shipping?
tax_class == 'shp'
end
|
#is_slab_heat_mat? ⇒ Boolean
#is_sm_cable? ⇒ Boolean
1377
1378
1379
|
# File 'app/models/item.rb', line 1377
def is_sm_cable?
is_heating_element? && pl_descendant_of_path?(LtreePaths::PL_SNOW_MELTING_CABLE)
end
|
#is_smartstat? ⇒ Boolean
1290
1291
1292
|
# File 'app/models/item.rb', line 1290
def is_smartstat?
ItemConstants::IID_SMARTSTATS.include?(id)
end
|
#is_snow_melt_plaque? ⇒ Boolean
1352
1353
1354
|
# File 'app/models/item.rb', line 1352
def is_snow_melt_plaque?
sku == ItemConstants::SNOW_MELT_PLAQUE_SKU
end
|
#is_snow_melting_control? ⇒ Boolean
#is_snow_melting_mat? ⇒ Boolean
1328
1329
1330
|
# File 'app/models/item.rb', line 1328
def is_snow_melting_mat?
is_heating_element? && pl_descendant_of_path?(LtreePaths::PL_SNOW_MELTING_MAT)
end
|
#is_snow_melting_product? ⇒ Boolean
1162
1163
1164
|
# File 'app/models/item.rb', line 1162
def is_snow_melting_product?
pl_descendant_of_path?(LtreePaths::PL_SNOW_MELTING)
end
|
#is_spare_parts? ⇒ Boolean
1278
1279
1280
|
# File 'app/models/item.rb', line 1278
def is_spare_parts?
pc_descendant_of_path?(LtreePaths::PC_SPARE_PARTS)
end
|
#is_thermalsheet? ⇒ Boolean
1344
1345
1346
|
# File 'app/models/item.rb', line 1344
def is_thermalsheet?
primary_product_line&.is_thermalsheet? && product_category&.is_insulation?
end
|
#is_thermostat? ⇒ Boolean
#is_towel_warmer? ⇒ Boolean
1234
1235
1236
|
# File 'app/models/item.rb', line 1234
def is_towel_warmer?
pc_descendant_of_path?(LtreePaths::PC_TOWEL_WARMERS)
end
|
#is_towel_warmer_dual_connect? ⇒ Boolean
#is_towel_warmer_hardwired? ⇒ Boolean
#is_towel_warmer_hardwired_control? ⇒ Boolean
1262
1263
1264
|
# File 'app/models/item.rb', line 1262
def is_towel_warmer_hardwired_control?
sku.in?(ItemConstants::TOWEL_WARMER_HARDWIRE_CONTROL_SKUS)
end
|
#is_towel_warmer_plug_in? ⇒ Boolean
#is_towel_warmer_plug_in_control? ⇒ Boolean
1258
1259
1260
|
# File 'app/models/item.rb', line 1258
def is_towel_warmer_plug_in_control?
sku.in?(ItemConstants::TOWEL_WARMER_PLUG_IN_CONTROL_SKUS)
end
|
#is_tz_ruler_cable? ⇒ Boolean
#is_tz_thin_cable? ⇒ Boolean
#is_underlayment? ⇒ Boolean
1348
1349
1350
|
# File 'app/models/item.rb', line 1348
def is_underlayment?
primary_product_line&.is_underlayment? && product_category&.is_insulation?
end
|
#is_upgrade? ⇒ Object
Alias for Product_category#is_upgrade?
649
650
651
652
653
654
655
656
657
658
|
# File 'app/models/item.rb', line 649
delegate :is_control?,
:is_upgrade?,
:is_accessory?,
:is_relay_panel?,
:is_custom_mat?,
:effective_nmfc_code,
:effective_nmfc_class,
:is_publication?,
to: :product_category,
allow_nil: true
|
#item_available_locales ⇒ Object
822
823
824
|
# File 'app/models/item.rb', line 822
def item_available_locales
LocaleUtility::SITE_LOCALES.select { |l| orderable_online_in_locale?(l) }
end
|
#item_group_name(context: :sales) ⇒ Object
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
|
# File 'app/models/item.rb', line 2211
def item_group_name(context: :sales)
pl_slug = case context
when :sales
sales_product_line_slug
when :support
support_product_line_slug
else
raise ArgumentError, "#{context} not supported, :sales or :support expected"
end
return if pl_slug.blank?
return if (pc_slug = product_category_slug).blank?
grouping_elements = [pl_slug.tr('.', '-').tr('_', '-').split('-'), pc_slug.split('-')].flatten
grouping_elements.delete('goods')
grouping_elements = grouping_elements.map(&:singularize)
grouping_elements = grouping_elements.each_with_index.map { |el, i| i < 2 ? el.first(2) : el }
grouping_elements = grouping_elements.compact.uniq
gn = grouping_elements.join('-').parameterize
if gn.size > 50
"#{gn.first(15)}-#{Digest::MD5.hexdigest(gn)}"
else
gn
end
end
|
#item_grouping_info(include_self: false, facet_filters: {}, context: nil) ⇒ Object
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
|
# File 'app/models/item.rb', line 2238
def item_grouping_info(include_self: false, facet_filters: {}, context: nil)
return if product_category.skip_siblings
context ||= :sales
use_pl_path = case context
when :sales
sales_product_line_path
when :support
support_product_line_path
else
raise ArgumentError, "#{context} not supported, :sales or :support expected"
end
use_pc_path = product_category_path
if use_pl_path.present?
variants = Item.active.condition_new.by_product_category_path(use_pc_path).by_product_line_path(use_pl_path).order(:sku)
variants = variants.joins(:product_category).where.not(ProductCategory[:custom_product].eq(true))
group_name = item_group_name(context:)
item_group_id = Digest::MD5.hexdigest(group_name)
facet_filters.each do |facet, value|
variants = variants.with_product_specification(facet, value)
end
else
variants = Item.none
end
variants = variants.where.not(id: id.to_i) unless include_self
result_class = Data.define(:pc_url, :pl_url, :item_group_id, :item_group_name, :variants) do
def initialize(pc_url: nil, pl_url: nil, item_group_id: nil, item_group_name: nil, variants: nil) = super
end
result_class.new(pc_url: use_pc_path, pl_url: use_pl_path, item_group_id:, item_group_name:, variants:)
end
|
#item_product_lines ⇒ ActiveRecord::Relation<ItemProductLine>
279
|
# File 'app/models/item.rb', line 279
has_many :item_product_lines, -> { order(:position) }, inverse_of: :item, dependent: :destroy
|
#item_relations ⇒ ActiveRecord::Relation<PublicationItem>
289
|
# File 'app/models/item.rb', line 289
has_many :item_relations, class_name: 'PublicationItem', foreign_key: :publication_id, inverse_of: :publication, dependent: :destroy
|
#item_state ⇒ Object
798
799
800
801
802
803
804
805
806
|
# File 'app/models/item.rb', line 798
def item_state
if is_discontinued
'Discontinued'
elsif is_available_to_public?
'Published'
else
'Private'
end
end
|
#line_items ⇒ ActiveRecord::Relation<LineItem>
280
|
# File 'app/models/item.rb', line 280
has_many :line_items
|
254
|
# File 'app/models/item.rb', line 254
belongs_to :literature, optional: true
|
#loaded_rendered_product_specifications ⇒ Object
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
|
# File 'app/models/item.rb', line 2069
def loaded_rendered_product_specifications
rp_specs = rendered_product_specifications || {}
ps_ids = rp_specs.values.pluck('product_specification_id').uniq.compact
product_specifications = ProductSpecification.includes(:items, :product_line, :product_category).where(id: ps_ids).index_by(&:id)
rp_specs.each_value do |v|
v['product_specification'] = product_specifications[v['product_specification_id']]
end
rp_specs
end
|
#make_upc_code ⇒ Object
1520
1521
1522
|
# File 'app/models/item.rb', line 1520
def make_upc_code
self.upc = Item::UpcMaker.new.process if upc.blank?
end
|
#missing_catalogs ⇒ Object
2440
2441
2442
|
# File 'app/models/item.rb', line 2440
def missing_catalogs
Catalog.where.not(id: catalog_items.pluck(:catalog_id)).where(store_id: store_items.pluck(:store_id)).where.not(is_discontinued: true).includes(:store).order(Catalog[:id].in([1, 2]).desc).order(Catalog[:name])
end
|
#most_recent_revision(public_only = true) ⇒ Object
1689
1690
1691
1692
1693
|
# File 'app/models/item.rb', line 1689
def most_recent_revision(public_only = true)
items = Item.publications.where(Item[:sku].matches("#{canonical_sku}%")).where('length(sku) <= ?', canonical_sku.size + 2)
items = items.available_to_public if public_only
items.order(sku: :desc).first
end
|
#new_item ⇒ Item
263
|
# File 'app/models/item.rb', line 263
belongs_to :new_item, class_name: 'Item', optional: true
|
#new_revision_sku ⇒ Object
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
|
# File 'app/models/item.rb', line 1704
def new_revision_sku
prev_revs = Item.where(Item[:sku].matches("#{canonical_sku}%")).order(sku: :desc)
sku_match = prev_revs.first.sku.match(/(.*)-([[:alpha:]])$/)
if sku_match && (sku_match.length == 3)
rev_code = sku_match[2]
new_rev = rev_code.succ
"#{canonical_sku}-#{new_rev}"
elsif canonical_sku.present?
"#{canonical_sku}-A"
else
raise "Last revision #{last_rev.id} #{last_rev.sku} could not be parsed for revision (-a, -b, etc.)"
end
end
|
#non_refurbished_sku ⇒ Object
1728
1729
1730
|
# File 'app/models/item.rb', line 1728
def non_refurbished_sku
sku.delete_suffix('-BTK')
end
|
#orderable_online? ⇒ Boolean
953
954
955
956
957
|
# File 'app/models/item.rb', line 953
def orderable_online?
Item.orderable_online.exists?(id:) &&
store_items.active.available.present? &&
catalog_items.active.present?
end
|
#orderable_online_in_locale?(locale = I18n.locale) ⇒ Boolean
814
815
816
817
818
819
820
|
# File 'app/models/item.rb', line 814
def orderable_online_in_locale?(locale = I18n.locale)
scoped_records = orderable_view_product_catalogs if orderable_view_product_catalogs.loaded?
scoped_records ||= orderable_view_product_catalogs.select(:catalog_id)
scoped_records.any? { |vpc| vpc.catalog_id == Catalog.locale_to_catalog_id(locale) }
end
|
#orderable_view_product_catalogs ⇒ ActiveRecord::Relation<ViewProductCatalog>
275
276
277
278
|
# File 'app/models/item.rb', line 275
has_many :orderable_view_product_catalogs,
-> { visible_to_public },
foreign_key: :item_id,
class_name: 'ViewProductCatalog'
|
#packaging_discrepancy_packing ⇒ Packing
266
|
# File 'app/models/item.rb', line 266
belongs_to :packaging_discrepancy_packing, class_name: 'Packing', optional: true
|
#packings ⇒ ActiveRecord::Relation<Packing>
309
|
# File 'app/models/item.rb', line 309
has_and_belongs_to_many :packings, inverse_of: :items
|
#past_model? ⇒ Boolean
1112
1113
1114
|
# File 'app/models/item.rb', line 1112
def past_model?
(tags || []).include?('past-model') || is_discontinued? || primary_product_line&.past_model?
end
|
#pc_descendant_of_path?(path_slug) ⇒ Boolean
Check if item's product category is or descends from the given path
Uses pc_path_slugs stored directly on item (no DB query)
Example: item.pc_descendant_of_path?(LtreePaths::PC_TOWEL_WARMERS)
1226
1227
1228
1229
1230
1231
1232
|
# File 'app/models/item.rb', line 1226
def pc_descendant_of_path?(path_slug)
return false if pc_path_slugs.blank? || path_slug.blank?
slugs = pc_path_slugs.to_s
path = path_slug.to_s
slugs == path || slugs.start_with?("#{path}.")
end
|
#pl_descendant_of_path?(path_slug) ⇒ Boolean
Check if item's primary product line is or descends from the given path
Uses ltree path stored directly on item (no DB query)
Example: item.pl_descendant_of_path?(LtreePaths::PL_FLOOR_HEATING)
1215
1216
1217
1218
1219
1220
1221
|
# File 'app/models/item.rb', line 1215
def pl_descendant_of_path?(path_slug)
return false if primary_pl_path_slugs.blank? || path_slug.blank?
slugs = primary_pl_path_slugs.to_s
path = path_slug.to_s
slugs == path || slugs.start_with?("#{path}.")
end
|
#plan_sensitive? ⇒ Boolean
Plan sensitive items are those tied up to the geometry of an installation plan
1108
1109
1110
|
# File 'app/models/item.rb', line 1108
def plan_sensitive?
is_heating_element?
end
|
#preferred_supplier ⇒ Supplier
260
|
# File 'app/models/item.rb', line 260
belongs_to :preferred_supplier, class_name: 'Supplier', optional: true
|
#primary_image ⇒ Image
256
|
# File 'app/models/item.rb', line 256
belongs_to :primary_image, class_name: 'Image', optional: true
|
#primary_image_url(options = {}) ⇒ Object
Returns the primary image URL for display (e.g., cart toast).
Uses WYS_MAIN profile first, falls back to primary_image association.
1136
1137
1138
1139
1140
|
# File 'app/models/item.rb', line 1136
def primary_image_url(options = {})
wys_main = image_profiles.find { |p| p.image_type == 'WYS_MAIN' }
image = wys_main&.image || primary_image
image&.image_url(options)
end
|
#primary_product_line ⇒ ProductLine
258
|
# File 'app/models/item.rb', line 258
belongs_to :primary_product_line, class_name: 'ProductLine', inverse_of: :primary_items, optional: true
|
#primary_product_line_slug_ltree ⇒ Object
1306
1307
1308
|
# File 'app/models/item.rb', line 1306
def primary_product_line_slug_ltree
primary_product_line&.slug_ltree&.to_s
end
|
251
|
# File 'app/models/item.rb', line 251
belongs_to :product_category
|
#product_category_ancestry_ids ⇒ Object
#product_category_name ⇒ Object
895
896
897
|
# File 'app/models/item.rb', line 895
def product_category_name
ProductCategoryConstants.name_for(product_category_id)
end
|
#product_category_path ⇒ Object
Returns ltree path for product category grouping (preferred - no DB lookup needed)
2175
2176
2177
2178
2179
2180
2181
2182
2183
|
# File 'app/models/item.rb', line 2175
def product_category_path
pc_path = pc_path_slugs.to_s
return LtreePaths::PC_INFRARED_HEATING_PANELS if pc_path.starts_with?('goods.infrared_heating_panels')
return LtreePaths::PC_TOWEL_WARMERS if pc_path.starts_with?('goods.towel_warmers') && !pc_path.starts_with?('goods.towel_warmers.dual_connection')
return 'goods.towel_warmers.dual_connection' if pc_path.starts_with?('goods.towel_warmers.dual_connection')
pc_path
end
|
#product_category_priority ⇒ Object
899
900
901
|
# File 'app/models/item.rb', line 899
def product_category_priority
ProductCategoryConstants.priority_for(product_category_id)
end
|
#product_category_slug ⇒ Object
Returns product category URL for grouping (legacy - use product_category_path for new code)
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
|
# File 'app/models/item.rb', line 2163
def product_category_slug
use_pc_url = product_category_url
use_pc_url = 'goods-infrared-heating-panels' if use_pc_url.starts_with?('goods-infrared-heating-panels')
if use_pc_url.starts_with?('goods-towel-warmers-dual-connection')
use_pc_url = 'goods-towel-warmers-dual-connection'
elsif use_pc_url.starts_with?('goods-towel-warmers')
use_pc_url = 'goods-towel-warmers'
end
use_pc_url
end
|
#product_category_url ⇒ Object
1311
1312
1313
|
# File 'app/models/item.rb', line 1311
def product_category_url
product_category&.url
end
|
#product_line_ancestry_ids ⇒ Object
#product_line_for_heating_system ⇒ Object
1462
1463
1464
1465
1466
1467
1468
|
# File 'app/models/item.rb', line 1462
def product_line_for_heating_system
(begin
primary_product_line.get_first_heating_system_type
rescue StandardError
nil
end)
end
|
#product_line_for_public_sales_portal ⇒ Object
1454
1455
1456
|
# File 'app/models/item.rb', line 1454
def product_line_for_public_sales_portal
primary_product_line&.get_first_public_for_sales
end
|
#product_line_for_review ⇒ Object
1450
1451
1452
|
# File 'app/models/item.rb', line 1450
def product_line_for_review
primary_product_line&.get_first_reviewable
end
|
#product_line_ids_constellation ⇒ Object
This pulls all product line id including inherited for this item, for the root system,
and complimentary_product_line_ids
789
790
791
792
793
794
795
796
|
# File 'app/models/item.rb', line 789
def product_line_ids_constellation
pl_ids = []
pl_ids += product_line_ids || [] pl_ids += root_system_product_line&.complimentary_product_line_ids || [] pl_ids += primary_product_line&.complimentary_product_line_ids || [] pl_ids = pl_ids.compact.uniq
ProductLine.self_and_ancestors_ids(pl_ids).compact.uniq
end
|
#product_lines ⇒ ActiveRecord::Relation<ProductLine>
281
|
# File 'app/models/item.rb', line 281
has_many :product_lines, through: :item_product_lines
|
#product_specifications(filters = {}) ⇒ Object
Retrieves all product specifications available to a given item, this does not
retrieve rendered specs but the specs definition used to build them
1801
1802
1803
1804
1805
|
# File 'app/models/item.rb', line 1801
def product_specifications(filters = {})
filters[:propagation] ||= %w[unrestricted item]
res = Item::SpecificationsRetriever.new.process(self, filters)
res.specifications
end
|
261
|
# File 'app/models/item.rb', line 261
belongs_to :product_tax_code, inverse_of: :items, optional: true
|
#prune_empty_specs ⇒ Object
2135
2136
2137
2138
2139
2140
|
# File 'app/models/item.rb', line 2135
def prune_empty_specs
ds = direct_product_specifications.empty_non_template_specs
ds_count = ds.size
ds.destroy_all
ds_count
end
|
#prune_unused_translations ⇒ Object
2480
2481
2482
2483
2484
2485
|
# File 'app/models/item.rb', line 2480
def prune_unused_translations
valid_locales = content_locales_to_render
translations.each do |(locale, _translation_attribute)|
translations.delete(locale) unless locale.to_sym.in?(valid_locales)
end
end
|
#public_description_html ⇒ Object
-- Content is trusted, generated from Liquid templates
1781
1782
1783
1784
|
# File 'app/models/item.rb', line 1781
def public_description_html
(rendered_detailed_description_html.presence || primary_product_line&.description_html.presence)&.html_safe
end
|
#public_description_text ⇒ Object
1786
1787
1788
|
# File 'app/models/item.rb', line 1786
def public_description_text
detailed_description.presence || primary_product_line&.description.presence
end
|
#public_file_name ⇒ Object
907
908
909
|
# File 'app/models/item.rb', line 907
def public_file_name
"#{public_name}.#{Mime::Type.file_extension_of(literature.mime_type) || 'pdf'}"
end
|
#public_name ⇒ Object
903
904
905
|
# File 'app/models/item.rb', line 903
def public_name
public_short_name.presence || name
end
|
#public_specifications ⇒ Object
Only specifications intended for the public are retrieved
1898
1899
1900
|
# File 'app/models/item.rb', line 1898
def public_specifications
specifications.select { |s| s.output.present? && s.grouping != 'Features' && s.grouping != 'Highlights' && s.visibility == 'open_visibility' }
end
|
#publication_relations ⇒ ActiveRecord::Relation<PublicationItem>
288
|
# File 'app/models/item.rb', line 288
has_many :publication_relations, class_name: 'PublicationItem', inverse_of: :item, dependent: :destroy
|
#publish_shipping_dimensions_changed_event(options = {}) ⇒ Object
Publishes Events::ItemShippingDimensionsChanged when shipping-box dims
actually changed on this save. The subscribed async handler
(Shipping::ItemPackingRefreshHandler) runs ItemMd5Extractor in a
background job so the foreground save isn't blocked on Packing.upsert
plus the HABTM item_ids write.
Gate is any_box_changed? only — the broader "no packing exists yet /
existing packing is invalid" conditions from the old inline path are
re-checked inside ItemMd5Extractor on the handler side, so we don't
need a DB hit here just to decide whether to publish.
Replaces the former synchronous set_packaged_items_md5_hash callback.
2312
2313
2314
2315
2316
2317
2318
2319
|
# File 'app/models/item.rb', line 2312
def publish_shipping_dimensions_changed_event(options = {})
return unless any_box_changed? || options[:force]
Rails.configuration.event_store.publish(
Events::ItemShippingDimensionsChanged.new(data: { item_id: id }),
stream_name: "Item-#{id}"
)
end
|
#purchase_order_items ⇒ ActiveRecord::Relation<PurchaseOrderItem>
299
|
# File 'app/models/item.rb', line 299
has_many :purchase_order_items
|
#purge_edge_cache(include_product_line: false) ⇒ Object
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
|
# File 'app/models/item.rb', line 1978
def purge_edge_cache(include_product_line: false)
return :disabled unless Cache::EdgeCacheUtility.edge_cache_enabled?
res = []
urls = edge_cache_urls
if urls.present?
Rails.logger.info "Purge Edge Cache called for item id #{id}"
jid = EdgeCacheWorker.perform_async('urls' => urls)
res += urls.map { |url| { url:, jid: } }
end
if include_product_line && (pl = primary_product_line)
res += pl.purge_edge_cache
end
res
end
|
#quantities_indicator_visible? ⇒ Boolean
#refresh_google_feed ⇒ Object
2048
2049
2050
2051
2052
2053
2054
|
# File 'app/models/item.rb', line 2048
def refresh_google_feed
return if (cids = catalog_items.for_google_feed.ids).blank?
GoogleFeedGeneratorWorker.perform_async('catalog_item_ids' => catalog_items.for_google_feed.ids)
cids
end
|
#refurbished_version ⇒ Item
268
|
# File 'app/models/item.rb', line 268
has_one :refurbished_version, class_name: 'Item', foreign_key: :new_item_id
|
295
|
# File 'app/models/item.rb', line 295
has_many :related_source_items, through: :source_item_relations, source: :source_item
|
296
|
# File 'app/models/item.rb', line 296
has_many :related_target_items, through: :target_item_relations, source: :target_item
|
297
|
# File 'app/models/item.rb', line 297
has_many :related_target_items_for_specs, through: :target_item_relations_for_specs, source: :target_item
|
#relatives ⇒ Object
Find all direct siblings and relatives items descendending the product category and product line tree
2147
2148
2149
2150
2151
2152
2153
2154
2155
|
# File 'app/models/item.rb', line 2147
def relatives
return Item.none unless persisted? && (product_category_id || primary_product_line_id)
siblings = Item.all
siblings = siblings.by_product_category_id(product_category_id) if product_category
siblings = siblings.where(Item[:primary_pl_path_ids].ltree_descendant(primary_pl_path_ids)) if primary_pl_path_ids.present?
siblings = siblings.where.not(id:) if id
siblings.limit(100).order(:sku)
end
|
#render_product_specifications(tokens: nil) ⇒ Object
1942
1943
1944
1945
1946
1947
1948
1949
|
# File 'app/models/item.rb', line 1942
def render_product_specifications(tokens: nil)
res = Item::SpecificationsMasher.new.process(item: self, tokens:).specifications
if tokens.present? (rendered_product_specifications || {}).merge(res)
else
res
end
end
|
#rendered_detailed_description_html ⇒ Object
1776
1777
1778
|
# File 'app/models/item.rb', line 1776
def rendered_detailed_description_html
@rendered_detailed_description_html ||= (detailed_description_html.present? ? detailed_description_html_template_instance.render(token_specs_values_for_liquid(include_legacy: true)) : nil)
end
|
#rendered_product_specifications_grouped(locale: Mobility.locale, filter_grouping: nil, sort_order: []) ⇒ Object
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
|
# File 'app/models/item.rb', line 2081
def rendered_product_specifications_grouped(locale: Mobility.locale, filter_grouping: nil, sort_order: [])
Mobility.with_locale(locale) do
filtered = loaded_rendered_product_specifications
.select { |_k, v| filter_grouping.nil? || v['grouping'] == filter_grouping }
sorted = filtered.sort_by do |k, v|
[
v['grouping'] || nil, sort_order.index(k.to_sym) || Float::INFINITY, v['name'] || nil ]
end
sorted.group_by { |_k, v| v['grouping'] || 'Other' }
end
end
|
#replacement_for ⇒ Item
257
|
# File 'app/models/item.rb', line 257
belongs_to :replacement_for, class_name: 'Item', optional: true
|
#requires_distributor_id_code? ⇒ Boolean
1302
1303
1304
|
# File 'app/models/item.rb', line 1302
def requires_distributor_id_code?
sku&.start_with?('UWG4-4999', 'AWG4-4999') && !sku&.include?('-WY')
end
|
#returned_rma_items ⇒ ActiveRecord::Relation<Rma>
282
|
# File 'app/models/item.rb', line 282
has_many :returned_rma_items, class_name: 'Rma', foreign_key: :returned_item_id
|
#revised_publication_for_public ⇒ Object
980
981
982
983
|
# File 'app/models/item.rb', line 980
def revised_publication_for_public
revision = most_recent_revision(:public)
revision == self ? nil : revision
end
|
#rma_reason_codes(include_advanced: true) ⇒ Object
911
912
913
914
915
916
917
|
# File 'app/models/item.rb', line 911
def rma_reason_codes(include_advanced: true)
rrcs = RmaReasonCode.active
rrcs = rrcs.for_product_category_ids(product_category_id).for_product_line_ids(primary_product_line_id) if product_category_id && primary_product_line_id
rrcs = rrcs.where(advanced_reason_code: false) unless include_advanced
rrcs
end
|
#root_system_product_line ⇒ Object
Alias for Primary_product_line#root_system_product_line
660
661
662
|
# File 'app/models/item.rb', line 660
delegate :root_system_product_line,
to: :primary_product_line,
allow_nil: true
|
Run shipping audit for all boxes, optionally for a specific carrier
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
|
# File 'app/models/item.rb', line 1658
def run_shipping_audit(carrier: nil)
carriers = carrier.present? ? [carrier] : nil
r = []
r1 = Shipping::PackageAuditor.new
r1.process(shipping_dimensions_to_package, carriers:)
r2 = r3 = nil
if box2_defined?
r2 = Shipping::PackageAuditor.new
r2.process(box2_shipping_dimensions_to_package, carriers:)
end
if box3_defined?
r3 = Shipping::PackageAuditor.new
r3.process(box3_shipping_dimensions_to_package, carriers:)
end
r << r1
r << r2 if r2
r << r3 if r3
r
end
|
#safe_name ⇒ Object
Returns a name suitable for edit feed with any special character that will
destroy a csv formatting
836
837
838
839
840
841
842
|
# File 'app/models/item.rb', line 836
def safe_name
return if name.blank?
name.gsub("'", 'ft')
.gsub('"', 'in')
.gsub(%r{[^0-9A-Za-z.-/]}, ' ').squish
end
|
#sales_product_line_path ⇒ Object
Returns ltree path for sales product line (preferred - reuses already-loaded ProductLine)
2192
2193
2194
2195
2196
|
# File 'app/models/item.rb', line 2192
def sales_product_line_path
pl_path = primary_product_line&.get_first_show_in_sales_portal_ancestor_path
pl_path ||= product_lines.map(&:get_first_show_in_sales_portal_ancestor_path).first
pl_path
end
|
#sales_product_line_slug ⇒ Object
2185
2186
2187
2188
2189
|
# File 'app/models/item.rb', line 2185
def sales_product_line_slug
slt = primary_product_line&.get_first_show_in_sales_portal_ancestor_slug_ltree
slt ||= product_lines.map(&:get_first_show_in_sales_portal_ancestor_slug_ltree).first
slt
end
|
259
|
# File 'app/models/item.rb', line 259
belongs_to :secondary_product_category, class_name: 'ProductCategory', optional: true
|
#selection_name ⇒ Object
1754
1755
1756
|
# File 'app/models/item.rb', line 1754
def selection_name
"#{sku} - #{name}#{' [Discontinued]' if is_discontinued?}"
end
|
#serial_numbers ⇒ ActiveRecord::Relation<SerialNumber>
294
|
# File 'app/models/item.rb', line 294
has_many :serial_numbers, through: :store_items
|
#set_grouping(force: false) ⇒ Object
Records a grouping string identifier, this speeds up variant grouping lookup for
google and reviews.io api calls.
2323
2324
2325
2326
2327
2328
2329
|
# File 'app/models/item.rb', line 2323
def set_grouping(force: false)
return unless is_goods? || is_service?
return if is_publication?
return unless force || product_category_id_changed? || primary_product_line_id_changed?
self.grouping = item_group_name
end
|
#shift_images(locale: 'en', prefix: nil) ⇒ Object
Shifts images up to fill empty slots in the image type order for this item
This method will move images to fill gaps in the sequence, maintaining the proper order
#shipping_dimensions(unit: 'in', precision: 0) ⇒ Object
unit_system SI = Standard International, e.g Metric
ucs = United States Customary Unit
1538
1539
1540
1541
1542
1543
1544
1545
1546
|
# File 'app/models/item.rb', line 1538
def shipping_dimensions(unit: 'in', precision: 0)
return unless shipping_length && shipping_width && shipping_height
[
shipping_length_converted(unit:, precision:),
shipping_width_converted(unit:, precision:),
shipping_height_converted(unit:, precision:)
]
end
|
#shipping_dimensions_display ⇒ Object
1079
1080
1081
|
# File 'app/models/item.rb', line 1079
def shipping_dimensions_display
"#{shipping_length}″ (L) x #{shipping_width}″ (W) x #{shipping_height}″ (H)"
end
|
#shipping_dimensions_to_package ⇒ Object
1634
1635
1636
1637
1638
1639
|
# File 'app/models/item.rb', line 1634
def shipping_dimensions_to_package
return unless box1_defined?
Shipping::Container.new(length: shipping_length, width: shipping_width, height: shipping_height, weight: shipping_weight,
container_type:)
end
|
#shipping_height_converted(unit: 'in', precision: 0) ⇒ Object
1560
1561
1562
1563
1564
|
# File 'app/models/item.rb', line 1560
def shipping_height_converted(unit: 'in', precision: 0)
return unless shipping_height
RubyUnits::Unit.new("#{shipping_height} in").convert_to(unit.to_s).scalar.to_f.round(precision)
end
|
#shipping_length_converted(unit: 'in', precision: 0) ⇒ Object
1548
1549
1550
1551
1552
|
# File 'app/models/item.rb', line 1548
def shipping_length_converted(unit: 'in', precision: 0)
return unless shipping_length
RubyUnits::Unit.new("#{shipping_length} in").convert_to(unit.to_s).scalar.to_f.round(precision)
end
|
#shipping_options ⇒ ActiveRecord::Relation<ShippingOption>
283
|
# File 'app/models/item.rb', line 283
has_many :shipping_options
|
#shipping_volume ⇒ Object
1052
1053
1054
1055
1056
|
# File 'app/models/item.rb', line 1052
def shipping_volume
boxes.sum { |b| b[0] * b[1] * b[2] }
rescue StandardError
0
end
|
#shipping_volume_in_cubic_feet ⇒ Object
1058
1059
1060
1061
1062
|
# File 'app/models/item.rb', line 1058
def shipping_volume_in_cubic_feet
res = nil
res = shipping_volume / 1728.0 if shipping_volume.present? && shipping_volume.positive?
res
end
|
#shipping_weight_converted(unit: 'lbs', precision: nil) ⇒ Object
1622
1623
1624
|
# File 'app/models/item.rb', line 1622
def shipping_weight_converted(unit: 'lbs', precision: nil)
express_weight_converted shipping_weight, unit:, precision:
end
|
#shipping_width_converted(unit: 'in', precision: 0) ⇒ Object
1554
1555
1556
1557
1558
|
# File 'app/models/item.rb', line 1554
def shipping_width_converted(unit: 'in', precision: 0)
return unless shipping_width
RubyUnits::Unit.new("#{shipping_width} in").convert_to(unit.to_s).scalar.to_f.round(precision)
end
|
#ships_in_single_box? ⇒ Boolean
2444
2445
2446
|
# File 'app/models/item.rb', line 2444
def ships_in_single_box?
!(box2_defined? || box3_defined?)
end
|
#ships_via_crate? ⇒ Boolean
2364
2365
2366
|
# File 'app/models/item.rb', line 2364
def ships_via_crate?
is_made_to_order_led_mirror?
end
|
#ships_via_freight? ⇒ Boolean
1420
1421
1422
1423
|
# File 'app/models/item.rb', line 1420
def ships_via_freight?
freight_service?
end
|
#siblings ⇒ Object
939
940
941
942
943
|
# File 'app/models/item.rb', line 939
def siblings
return Item.none unless primary_product_line_id
Item.by_product_line_id(primary_product_line_id).where.not(id:)
end
|
#single_item_packings_from_md5 ⇒ Object
Finds packings of this item but only for a single quantity
2356
2357
2358
2359
2360
2361
2362
|
# File 'app/models/item.rb', line 2356
def single_item_packings_from_md5
if (md5 = Shipping::Md5HashItem.process(self).md5)
packings.where(md5:)
else
Packing.none
end
end
|
#site_maps ⇒ ActiveRecord::Relation<SiteMap>
292
|
# File 'app/models/item.rb', line 292
has_many :site_maps, as: :resource, dependent: :destroy
|
#sku_and_name ⇒ Object
1103
1104
1105
|
# File 'app/models/item.rb', line 1103
def sku_and_name
"#{sku} - #{name}"
end
|
#source_item_relations ⇒ ActiveRecord::Relation<ItemRelation>
284
|
# File 'app/models/item.rb', line 284
has_many :source_item_relations, class_name: 'ItemRelation', foreign_key: :target_item_id, dependent: :destroy
|
#specific_items ⇒ ActiveRecord::Relation<Item>
291
|
# File 'app/models/item.rb', line 291
has_many :specific_items, through: :item_relations, class_name: 'Item', source: :item
|
#specific_publications ⇒ ActiveRecord::Relation<Item>
290
|
# File 'app/models/item.rb', line 290
has_many :specific_publications, through: :publication_relations, class_name: 'Item', source: :publication
|
#specifications ⇒ Object
Retrieves rendered specifications as an object
1889
1890
1891
|
# File 'app/models/item.rb', line 1889
def specifications
rendered_product_specifications&.values&.map { |s| OpenStruct.new(s) } || []
end
|
#specifications_for_item_label ⇒ Object
1902
1903
1904
|
# File 'app/models/item.rb', line 1902
def specifications_for_item_label
specifications.select { |rps| rps.print_on_item_label && rps.output.present? }.sort_by(&:name)
end
|
#specifications_grouped ⇒ Object
1893
1894
1895
|
# File 'app/models/item.rb', line 1893
def specifications_grouped
specifications.sort_by { |s| [s.grouping, s.name] }.group_by(&:grouping)
end
|
#star? ⇒ Boolean
Makes a star appear in the document library
845
846
847
|
# File 'app/models/item.rb', line 845
def star?
(tags || []).intersect?(%w[Star star])
end
|
#store_items ⇒ ActiveRecord::Relation<StoreItem>
270
|
# File 'app/models/item.rb', line 270
has_many :store_items, inverse_of: :item, dependent: :destroy
|
#successor_item ⇒ Item
262
|
# File 'app/models/item.rb', line 262
belongs_to :successor_item, class_name: 'Item', optional: true
|
#suggested_item_applies_to ⇒ Object
Alias for Suggested_item_tool#suggested_item_applies_to
664
665
666
|
# File 'app/models/item.rb', line 664
delegate :suggested_item_stock_threshold,
:suggested_item_applies_to,
to: :suggested_item_tool
|
#suggested_item_stock_threshold ⇒ Object
Alias for Suggested_item_tool#suggested_item_stock_threshold
664
665
666
|
# File 'app/models/item.rb', line 664
delegate :suggested_item_stock_threshold,
:suggested_item_applies_to,
to: :suggested_item_tool
|
#superceded_items ⇒ ActiveRecord::Relation<Item>
273
|
# File 'app/models/item.rb', line 273
has_many :superceded_items, class_name: 'Item', foreign_key: :successor_item_id
|
252
|
# File 'app/models/item.rb', line 252
belongs_to :supplier_item, inverse_of: :items, optional: true
|
#supplier_items ⇒ ActiveRecord::Relation<SupplierItem>
285
|
# File 'app/models/item.rb', line 285
has_many :supplier_items, inverse_of: :item, dependent: :destroy
|
#supplier_skus ⇒ Object
826
827
828
|
# File 'app/models/item.rb', line 826
def supplier_skus
([secondary_model_number] + supplier_items.active.distinct.pluck(:supplier_sku)).filter_map(&:presence).uniq
end
|
#support_product_line_path ⇒ Object
Returns ltree path for support product line (preferred - reuses already-loaded ProductLine)
2205
2206
2207
2208
2209
|
# File 'app/models/item.rb', line 2205
def support_product_line_path
pl_path = primary_product_line&.get_first_show_in_support_portal_ancestor_path
pl_path ||= product_lines.map(&:get_first_show_in_support_portal_ancestor_path).first
pl_path
end
|
#support_product_line_slug ⇒ Object
2198
2199
2200
2201
2202
|
# File 'app/models/item.rb', line 2198
def support_product_line_slug
slt = primary_product_line&.get_first_show_in_support_portal_ancestor_slug_ltree
slt ||= product_lines.map(&:get_first_show_in_support_portal_ancestor_slug_ltree).first
slt
end
|
674
675
676
|
# File 'app/models/item.rb', line 674
def tags_display
tags.join(', ')
end
|
#target_item_relations ⇒ ActiveRecord::Relation<ItemRelation>
286
|
# File 'app/models/item.rb', line 286
has_many :target_item_relations, class_name: 'ItemRelation', foreign_key: :source_item_id, dependent: :destroy
|
#target_item_relations_for_specs ⇒ ActiveRecord::Relation<ItemRelation>
287
|
# File 'app/models/item.rb', line 287
has_many :target_item_relations_for_specs, -> { where(include_in_spec: true) }, class_name: 'ItemRelation', foreign_key: :source_item_id
|
#third_party_skus(limit: 1) ⇒ Object
830
831
832
|
# File 'app/models/item.rb', line 830
def third_party_skus(limit: 1)
(catalog_items.where.not(third_party_sku: nil).where.not(CatalogItem[:third_party_sku].matches(sku)).pluck(:third_party_sku) - [sku]).filter_map(&:presence).uniq.sort.first(limit)
end
|
#thumbnail_url(size: '30x30') ⇒ Object
1130
1131
1132
|
# File 'app/models/item.rb', line 1130
def thumbnail_url(size: '30x30')
image_url2(size:, thumbnail: true)
end
|
#to_liquid ⇒ Object
2497
2498
2499
|
# File 'app/models/item.rb', line 2497
def to_liquid
Liquid::ItemDrop.new self
end
|
#to_packdims ⇒ Object
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
|
# File 'app/models/item.rb', line 2331
def to_packdims
sle, swi, she = [[shipping_length.ceil(1), 0.1].max, [shipping_width.ceil(1), 0.1].max, [shipping_height.ceil(1), 0.1].max].sort.reverse
swg = [shipping_weight.ceil(2), 0.01].max
packdims = [[sle, swi, she, swg, Shipment::PACKDIM_CONTAINER_INTS[container_type]]]
if box2_defined?
box2_sle, box2_swi, box2_she = [[box2_shipping_length.ceil(1), 0.1].max, [box2_shipping_width.ceil(1), 0.1].max, [box2_shipping_height.ceil(1), 0.1].max].sort.reverse
box2_swg = [box2_shipping_weight.ceil(2), 0.01].max
packdims << [box2_sle, box2_swi, box2_she, box2_swg, Shipment::PACKDIM_CONTAINER_INTS[container_type]]
end
if box3_defined?
box3_sle, box3_swi, box3_she = [[box3_shipping_length.ceil(1), 0.1].max, [box3_shipping_width.ceil(1), 0.1].max, [box3_shipping_height.ceil(1), 0.1].max].sort.reverse
box3_swg = [box3_shipping_weight.ceil(2), 0.01].max
packdims << [box3_sle, box3_swi, box3_she, box3_swg, Shipment::PACKDIM_CONTAINER_INTS[container_type]]
end
packdims
end
|
#to_s ⇒ Object
1748
1749
1750
1751
1752
|
# File 'app/models/item.rb', line 1748
def to_s
s = "#{sku} - #{name}"
s += ' (Discontinued)' if is_discontinued?
s
end
|
#total_shipping_weight ⇒ Object
2487
2488
2489
|
# File 'app/models/item.rb', line 2487
def total_shipping_weight
boxes.sum { |b| b[3].to_f }
end
|
#total_shipping_weight_converted(unit: 'lbs', precision: nil) ⇒ Object
1618
1619
1620
|
# File 'app/models/item.rb', line 1618
def total_shipping_weight_converted(unit: 'lbs', precision: nil)
express_weight_converted total_shipping_weight, unit:, precision:
end
|
#total_shipping_weight_of_kit_components ⇒ Object
2491
2492
2493
2494
2495
|
# File 'app/models/item.rb', line 2491
def total_shipping_weight_of_kit_components
return total_shipping_weight unless is_kit?
kit_target_item_relations.includes(:target_item).sum { |tir| tir.quantity * tir.target_item.total_shipping_weight }
end
|
#translation_key_resources ⇒ ActiveRecord::Relation<TranslationKeyResource>
300
|
# File 'app/models/item.rb', line 300
has_many :translation_key_resources, as: :resource, dependent: :destroy
|
#update_boxes_from_packages(packages) ⇒ Object
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
|
# File 'app/models/item.rb', line 1021
def update_boxes_from_packages(packages)
self.shipping_length = packages[0].try(:length)
self.shipping_width = packages[0].try(:width)
self.shipping_height = packages[0].try(:height)
self.shipping_weight = packages[0].try(:weight)
if packages.size > 1
self.box2_shipping_length = packages[1].try(:length)
self.box2_shipping_width = packages[1].try(:width)
self.box2_shipping_height = packages[1].try(:height)
self.box2_shipping_weight = packages[1].try(:weight)
else
self.box2_shipping_length = nil
self.box2_shipping_width = nil
self.box2_shipping_height = nil
self.box2_shipping_weight = nil
end
if packages.size > 2
self.box3_shipping_length = packages[2].try(:length)
self.box3_shipping_width = packages[2].try(:width)
self.box3_shipping_height = packages[2].try(:height)
self.box3_shipping_weight = packages[2].try(:weight)
else
self.box3_shipping_length = nil
self.box3_shipping_width = nil
self.box3_shipping_height = nil
self.box3_shipping_weight = nil
end
save
end
|
#update_rendered_product_specifications(user_id: nil, tokens: nil, locales: nil, skip_google_feed: true) ⇒ Object
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
|
# File 'app/models/item.rb', line 2016
def update_rendered_product_specifications(user_id: nil, tokens: nil, locales: nil, skip_google_feed: true)
return :skipped if new_record? || is_publication?
locales ||= content_locales_to_render
self.refresh_specs = false self.skip_item_calc = true locales.uniq.each do |locale|
Mobility.with_locale(locale) do
self.rendered_product_specifications = render_product_specifications(tokens:)
end
end
self.rendered_product_specifications_at = Time.current
prune_unused_translations
res = :fail
CurrentScope.with_user_id(user_id) do
res = :success if save
end
if res == :success
refresh_google_feed unless skip_google_feed purge_edge_cache(include_product_line: false) end
res
end
|
253
|
# File 'app/models/item.rb', line 253
belongs_to :upload, optional: true
|
#uploads ⇒ ActiveRecord::Relation<Upload>
311
|
# File 'app/models/item.rb', line 311
has_and_belongs_to_many :uploads, dependent: :destroy
|
#url_paths ⇒ Object
721
722
723
724
725
726
|
# File 'app/models/item.rb', line 721
def url_paths
p = []
p += primary_product_line.url_paths
p << sku
p.compact
end
|
#variants(include_self: false) ⇒ Object
A more strict version of relatives, we don't look at descendants, only exact matches
2158
2159
2160
|
# File 'app/models/item.rb', line 2158
def variants(include_self: false)
item_grouping_info(include_self:)&.variants || Item.none
end
|
#versions_for_audit_trail(_params = {}) ⇒ Object
2509
2510
2511
2512
2513
2514
2515
2516
2517
|
# File 'app/models/item.rb', line 2509
def versions_for_audit_trail(_params = {})
RecordVersion.where(<<~SQL.squish, id:, item_id_json: { item_id: id }.to_json)
(item_type = 'Item' AND item_id = :id)
OR (
item_type = 'ImageProfile'
AND reference_data @> :item_id_json
)
SQL
end
|
#view_product_catalogs ⇒ ActiveRecord::Relation<ViewProductCatalog>
274
|
# File 'app/models/item.rb', line 274
has_many :view_product_catalogs
|
#warm_cache(include_product_line: true) ⇒ Object
Finds the associated sitemap (url) end points of this item and its product line
Perform a cache warmup
1961
1962
1963
1964
1965
1966
1967
1968
|
# File 'app/models/item.rb', line 1961
def warm_cache(include_product_line: true)
return :disabled unless Cache::EdgeCacheUtility.edge_cache_enabled?
all_site_maps.each(&:warm_cache)
return unless include_product_line && (pl = primary_product_line)
pl.warm_cache
end
|
#will_be_restricted_for_sales? ⇒ Boolean
699
700
701
702
|
# File 'app/models/item.rb', line 699
def will_be_restricted_for_sales?
restricted_for_sales ||
(product_category&.restricted_for_sales && primary_product_line&.restricted_for_sales)
end
|