Class: Item
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- Item
- Includes:
- Memery, Models::Auditable, Models::CrossLinkable, Models::EdgeCachePurgeable, 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
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_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_... (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, FloorPlanRetriever, HeatingElementLine, HeatingElementPlan, ImageLibraryPlPcLadder, ImageLibraryRetriever, ImageRetriever, InventoryCommitter, KitAttributeGenerator, KitComposer, KitConsolidator, MarketingCycleCountScheduler, PopulateItemPopularity, PrepareNewKitComponent, ProductSpecificationsCloner, PublicationRetriever, ShippingBoxCalculator, SpecFixer, SpecificationsMasher, SpecificationsRetriever, SuggestedItemTool, SupportQrCode, SynchronizeRefurbSpecs, UpcBarcode, UpcMaker, VideoRetriever
Constant Summary collapse
- TRANSLATABLE_ATTRIBUTES =
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 =
Translation namespace.
'ItemAttributes'- SKU_REGEXP =
Sku regexp.
/\A\w[\w\-.]+\w\z/- AMAZON_ASIN_REGEXP =
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 =
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 =
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 =
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'
Constants included from Models::Publication
Models::Publication::CACHE_RELEVANT_ATTRIBUTES, Models::Publication::MARKETPLACE_DOWNLOAD_TOKEN_FLOOR, Models::Publication::MARKETPLACE_DOWNLOAD_TOKEN_LIFETIME, Models::Publication::PUBLIC_LOCALES, Models::Publication::REVISION_CHAIN_LIMIT
Constants included from Models::Embeddable
Models::Embeddable::MAX_CONTENT_LENGTH
Constants included from Models::ItemSpecificationHelper
Models::ItemSpecificationHelper::PER_ITEM_SPEC_TOKENS
Constants included from Models::Auditable
Models::Auditable::ALWAYS_IGNORED
Constants included from Models::Schedulable
Models::Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
-
#amazon_asin ⇒ void
readonly
Validates amazon asin.
-
#name_en ⇒ Object
readonly
Here we check specifically for the english name to be present.
-
#refresh_specs ⇒ Object
These are shortcuts for publications.
-
#skip_item_calc ⇒ Object
Returns the value of attribute skip_item_calc.
-
#sku ⇒ void
readonly
Validates sku.
-
#steel_content_value_ratio ⇒ Object
readonly
Section 232 declaration inputs (see Declaration232) — a ratio outside 0..1 or a negative weight would produce negative rows on a customs declaration.
-
#steel_content_weight_kg ⇒ void
readonly
Validates steel content weight kg.
-
#tax_class ⇒ Object
readonly
Here we check specifically for the english name to be present.
-
#update_search_text ⇒ Object
Returns the value of attribute update_search_text.
-
#update_upc ⇒ Object
Returns the value of attribute update_upc.
Attributes included from Models::Publication
#available_in_canada, #available_in_usa, #publication_previous_page_paths, #serve_in_locale
Attributes included from Models::Translatable
#do_not_compact_translation_container
Attributes included from Models::Kittable
#kit_components, #kit_components_for_specs, #kit_parents, #kit_source_item_relations, #kit_target_item_relations, #kit_target_item_relations_for_specs
Attributes included from Models::ItemLtreeSync
Belongs to collapse
-
#brand ⇒ Brand?
The associated brand.
-
#exclusive_item_group ⇒ ExclusiveItemGroup?
The associated exclusive item group.
-
#literature ⇒ Literature?
The associated literature.
-
#new_item ⇒ Item?
The associated new item.
-
#packaging_discrepancy_packing ⇒ Packing?
The associated packaging discrepancy packing.
-
#preferred_supplier ⇒ Supplier?
The associated preferred supplier.
-
#primary_image ⇒ Image?
The associated primary image.
-
#primary_product_line ⇒ ProductLine?
The associated primary product line.
-
#product_category ⇒ ProductCategory?
The associated product category.
-
#product_tax_code ⇒ ProductTaxCode?
The associated product tax code.
-
#replacement_for ⇒ Item?
The associated replacement for.
-
#secondary_product_category ⇒ ProductCategory?
The associated secondary product category.
-
#successor_item ⇒ Item?
The associated successor item.
-
#supplier_item ⇒ SupplierItem?
The associated supplier item.
-
#upload ⇒ Upload?
The associated upload.
Methods included from Models::Auditable
Has one collapse
-
#refurbished_version ⇒ Item?
The associated refurbished version.
Has many collapse
-
#catalog_item_site_maps ⇒ ActiveRecord::Associations::CollectionProxy
The associated catalog item site maps.
-
#catalog_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated catalog items.
-
#catalogs ⇒ ActiveRecord::Associations::CollectionProxy
The associated catalogs.
-
#compatible_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated compatible items.
-
#direct_packings ⇒ ActiveRecord::Associations::CollectionProxy
The associated direct packings.
-
#edi_communication_logs ⇒ ActiveRecord::Associations::CollectionProxy
The associated edi communication logs.
-
#edi_documents ⇒ ActiveRecord::Associations::CollectionProxy
The associated edi documents.
-
#google_feed_image_profiles ⇒ ActiveRecord::Associations::CollectionProxy
The associated google feed image profiles.
-
#image_profiles ⇒ ActiveRecord::Associations::CollectionProxy
The associated image profiles.
-
#images ⇒ ActiveRecord::Associations::CollectionProxy
The associated images.
-
#item_product_lines ⇒ ActiveRecord::Associations::CollectionProxy
The associated item product lines.
-
#item_relations ⇒ ActiveRecord::Associations::CollectionProxy
The associated item relations.
-
#line_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated line items.
-
#orderable_view_product_catalogs ⇒ ActiveRecord::Associations::CollectionProxy
The associated orderable view product catalogs.
-
#primary_variant_groups ⇒ ActiveRecord::Relation<VariantGroup>
Groups that point at this item as their curated lead child — cleared (not blocked) when the item goes away, so the items FK can't abort the destroy.
-
#product_lines ⇒ ActiveRecord::Associations::CollectionProxy
The associated product lines.
-
#publication_relations ⇒ ActiveRecord::Associations::CollectionProxy
The associated publication relations.
-
#purchase_order_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated purchase order items.
-
#related_source_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated related source items.
-
#related_target_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated related target items.
-
#related_target_items_for_specs ⇒ ActiveRecord::Associations::CollectionProxy
The associated related target items for specs.
-
#returned_rma_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated returned rma items.
-
#serial_numbers ⇒ ActiveRecord::Associations::CollectionProxy
The associated serial numbers.
-
#shipping_options ⇒ ActiveRecord::Associations::CollectionProxy
The associated shipping options.
-
#site_maps ⇒ ActiveRecord::Associations::CollectionProxy
The associated site maps.
-
#source_item_relations ⇒ ActiveRecord::Associations::CollectionProxy
The associated source item relations.
-
#specific_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated specific items.
-
#specific_publications ⇒ ActiveRecord::Associations::CollectionProxy
The associated specific publications.
-
#store_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated store items.
-
#superceded_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated superceded items.
-
#supplier_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated supplier items.
-
#target_item_relations ⇒ ActiveRecord::Associations::CollectionProxy
The associated target item relations.
-
#target_item_relations_for_specs ⇒ ActiveRecord::Associations::CollectionProxy
The associated target item relations for specs.
-
#translation_key_resources ⇒ ActiveRecord::Associations::CollectionProxy
The associated translation key resources.
-
#variant_group_members ⇒ ActiveRecord::Relation<VariantGroupMember>
Variant-family memberships: at most one DEFAULT family plus one override per channel (model-validated).
-
#variant_groups ⇒ ActiveRecord::Associations::CollectionProxy
The associated variant groups.
-
#view_product_catalogs ⇒ ActiveRecord::Associations::CollectionProxy
The associated view product catalogs.
Methods included from Models::ItemAmazonHelper
#amazon_marketplaces, #amazon_transparency_codes
Methods included from Models::CrossLinkable
#inbound_content_links, #outbound_content_links
Methods included from Models::Publication
#incoming_related_publication_links, #item_embeddings, #related_publication_links, #related_publications, #translated_publication_links, #translated_publications
Methods included from Models::Embeddable
Methods included from Models::Taggable
Has and belongs to many collapse
-
#articles ⇒ ActiveRecord::Associations::CollectionProxy
The associated articles.
-
#assortment_instructions ⇒ ActiveRecord::Associations::CollectionProxy
The associated assortment instructions.
-
#digital_assets ⇒ ActiveRecord::Associations::CollectionProxy
The associated digital assets.
-
#direct_product_specifications ⇒ ActiveRecord::Associations::CollectionProxy
The associated direct product specifications.
-
#packings ⇒ ActiveRecord::Associations::CollectionProxy
The associated packings.
-
#uploads ⇒ ActiveRecord::Associations::CollectionProxy
The associated uploads.
Delegated Instance Attributes collapse
-
#effective_nmfc_class ⇒ Object
Alias for Product_category#effective_nmfc_class.
-
#effective_nmfc_code ⇒ Object
Alias for Product_category#effective_nmfc_code.
-
#is_accessory? ⇒ Object
Alias for Product_category#is_accessory?.
-
#is_control? ⇒ Object
Alias for Product_category#is_control?.
-
#is_custom_mat? ⇒ Object
Alias for Product_category#is_custom_mat?.
-
#is_publication? ⇒ Object
Alias for Product_category#is_publication?.
-
#is_relay_panel? ⇒ Object
Alias for Product_category#is_relay_panel?.
-
#is_upgrade? ⇒ Object
Alias for Product_category#is_upgrade?.
-
#root_system_product_line ⇒ Object
Alias for Primary_product_line#root_system_product_line.
-
#suggested_item_applies_to ⇒ Object
Alias for Suggested_item_tool#suggested_item_applies_to.
-
#suggested_item_stock_threshold ⇒ Object
Alias for Suggested_item_tool#suggested_item_stock_threshold.
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 ⇒ Array<String>
Sorted distinct publication locales.
-
.async_update_all_items_product_specifications(public_only: true, active_only: true, limit: nil, not_updated_since: nil) ⇒ Object
Async update all items product specifications.
-
.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
Condition select options.
-
.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) ⇒ Array<Hash>
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 quantity from items and sqft.
-
.get_towel_warmer_tstat_options_for_web_and_apply_overrides(connection_method, tstat_options_override = [], available_in_catalog_id: nil) ⇒ Array<Hash>
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
Import translation keys.
-
.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
Item identifier label sizes select options.
-
.last_custom_mat_item ⇒ Object
Last custom mat item.
-
.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
Ransackable scopes.
-
.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 keys.
-
.rendered_product_specs_options_for_select(spec_key) ⇒ Object
Rendered product specs options for select.
-
.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) ⇒ Object
Whether sku is membrane.
-
.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
Tax classes for select.
-
.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
Uom select options.
-
.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 ⇒ ActiveRecord::Relation<Image>
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 my publications.
-
#all_site_maps ⇒ Object
All site maps.
-
#all_uploads ⇒ Object
All uploads.
-
#any_box_changed? ⇒ Object
Whether any box changed.
-
#async_update_rendered_product_specifications ⇒ Object
Async update rendered product specifications.
-
#authenticated_url(dimensions = nil) ⇒ Object
Authenticated url.
-
#auto_translate(reset_previous_values: false, locales: nil) ⇒ Object
Auto translate.
-
#auto_translate_attributes(reset_previous_values: false, locales: nil) ⇒ Object
Auto translate attributes.
-
#auto_translate_product_specifications(reset_previous_values: false, locales: nil) ⇒ Object
Auto translate product specifications.
-
#available_content_locales ⇒ Array<String>
Returns all locales from the catalog this item is part of.
-
#available_token_options_from_product_specifications ⇒ Object
Available token options from product specifications.
-
#base_weight_converted(unit: 'lbs', precision: nil) ⇒ Object
Base weight converted.
-
#box1_changed? ⇒ Object
Whether box1 changed.
-
#box1_defined? ⇒ Object
Whether box1 defined.
-
#box2_changed? ⇒ Object
Whether box2 changed.
-
#box2_defined? ⇒ Object
Whether box2 defined.
-
#box2_shipping_dimensions_to_package ⇒ Object
Box2 shipping dimensions to package.
-
#box2_shipping_height_converted(unit: 'in', precision: 0) ⇒ Object
Box2 shipping height converted.
-
#box2_shipping_length_converted(unit: 'in', precision: 0) ⇒ Object
Box2 shipping length converted.
-
#box2_shipping_weight_converted(unit: 'lbs', precision: nil) ⇒ Object
Box2 shipping weight converted.
-
#box2_shipping_width_converted(unit: 'in', precision: 0) ⇒ Object
Box2 shipping width converted.
-
#box3_changed? ⇒ Object
Whether box3 changed.
-
#box3_defined? ⇒ Object
Whether box3 defined.
-
#box3_shipping_dimensions_to_package ⇒ Object
Box3 shipping dimensions to package.
-
#box3_shipping_height_converted(unit: 'in', precision: 0) ⇒ Object
Box3 shipping height converted.
-
#box3_shipping_length_converted(unit: 'in', precision: 0) ⇒ Object
Box3 shipping length converted.
-
#box3_shipping_weight_converted(unit: 'lbs', precision: nil) ⇒ Object
Box3 shipping weight converted.
-
#box3_shipping_width_converted(unit: 'in', precision: 0) ⇒ Object
Box3 shipping width converted.
-
#boxes ⇒ Object
Boxes.
-
#boxes_shipping_dimensions_and_weights_converted(units: { length: 'in', weight: 'lbs' }, precision: 2) ⇒ Object
Boxes shipping dimensions and weights converted.
-
#boxes_shipping_dimensions_and_weights_display(units: { length: 'in', weight: 'lbs' }, precision: 2) ⇒ Object
Boxes shipping dimensions and weights display.
-
#boxes_to_packages ⇒ Object
Boxes to packages.
-
#calculate_ideal_cable_spacing ⇒ Object
Calculate ideal cable spacing.
-
#calculate_is_cable_system? ⇒ Object
Whether calculate is cable system.
-
#calculate_item_fields ⇒ Object
Calculate item fields.
-
#can_be_packaged? ⇒ Object
Whether can be packaged.
-
#canonical_path ⇒ String?
Hierarchical canonical path via product line ancestry + SKU.
-
#canonical_sku ⇒ Object
Canonical sku.
-
#canonical_url(locale: I18n.locale) ⇒ String?
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
Container type.
-
#content_locales_to_render ⇒ Object
Content locales to render.
-
#controllable? ⇒ Object
Whether controllable.
-
#country_of_origin_iso3 ⇒ Object
Country of origin iso3.
-
#country_of_origin_name ⇒ Object
Country of origin name.
-
#create_template_specifications ⇒ Object
Create template specifications.
-
#current_supplier_cost ⇒ Object
Current supplier cost.
-
#deep_dup ⇒ Object
Deep dup.
-
#default_short_description ⇒ Object
Default short description.
-
#detailed_description ⇒ String
Creates a text description from the html rendered description.
-
#discontinue_self_and_dependents ⇒ Object
Discontinue self and dependents.
-
#discontinue_store_and_catalog_items ⇒ Object
Discontinue store and catalog items.
-
#ean13 ⇒ Object
Ean13.
-
#edge_cache_urls ⇒ Array<String>
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 option name.
-
#effective_seo_description(char_limit: nil) ⇒ Object
Effective seo description.
-
#effective_seo_keywords ⇒ Object
Effective seo keywords.
-
#effective_seo_title(skip_sku: false) ⇒ Object
Effective seo title.
-
#express_weight_converted(weight_in_lbs, unit: 'lbs', precision: nil) ⇒ Object
Express weight converted.
-
#features ⇒ Array<String>
Features are a sub category of specs with feature priority set.
-
#fix_name ⇒ Object
Fix name.
-
#fixture_key ⇒ Object
Fixture key.
-
#freight_class ⇒ Object
Freight class.
-
#generate_refurbished_sku ⇒ Object
Generate refurbished sku.
-
#get_quantity_from_sqft(input_sqft, add_one_extra = false) ⇒ Object
Get quantity from sqft.
-
#gross_weight_converted(unit: 'lbs', precision: nil) ⇒ Object
Gross weight converted.
-
#gtin13 ⇒ Object
Gtin13.
-
#gtin_type ⇒ Object
Gtin type.
-
#gtin_type_friendly ⇒ Object
Gtin type friendly.
-
#harmonization_code_hs6(with_dot = true) ⇒ String?
Returns the first 6 digits of the harmonization code (HS6).
-
#has_ean13? ⇒ Object
Whether has ean13.
-
#has_features? ⇒ Object
Whether has features.
-
#has_heating_system? ⇒ Object
Whether has heating system.
-
#has_stock? ⇒ Object
Whether has stock.
-
#has_stock_in_store?(st_id) ⇒ Object
Whether has stock in store.
-
#image_url(dimensions, options = {}) ⇒ String?
Returns the primary image URL at the given dimensions.
-
#image_url2(options = {}) ⇒ String?
Use this new form that passes the options straight to the url generator.
-
#import_translation_keys ⇒ Array<TranslationKeyResource>
This method will import existing translations or link to existing ones.
-
#increment_request_counter ⇒ Object
Increment request counter.
-
#inherited_features ⇒ Array<String>
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? ⇒ Object
Whether is available to public.
-
#is_cable_accessory? ⇒ Object
Whether is cable accessory.
-
#is_cable_fit_guide? ⇒ Object
Whether is cable fit guide.
-
#is_cable_heating_element? ⇒ Object
Whether is cable heating element.
-
#is_cable_tape? ⇒ Object
Whether is cable tape.
-
#is_cerazorb? ⇒ Object
Whether is cerazorb.
-
#is_circuit_check? ⇒ Object
Whether is circuit check.
-
#is_cold_lead? ⇒ Object
Whether is cold lead.
-
#is_cork? ⇒ Object
Whether is cork.
-
#is_discontinued_or_publication ⇒ Boolean
Helper for validation: skips weight checks for discontinued items and publications.
-
#is_economy_snow_melt_control? ⇒ Object
Whether is economy snow melt control.
-
#is_floor_heating_product? ⇒ Object
Whether is floor heating product.
-
#is_goods? ⇒ Object
Whether is goods.
-
#is_heating_element? ⇒ Object
Whether is heating element.
-
#is_infrared_heating_panel? ⇒ Object
Whether is infrared heating panel.
-
#is_infrared_heating_panel_dual_connect? ⇒ Object
Whether is infrared heating panel dual connect.
-
#is_infrared_heating_panel_hardwired? ⇒ Object
Whether is infrared heating panel hardwired.
-
#is_infrared_heating_panel_hardwired_control? ⇒ Object
Whether is infrared heating panel hardwired control.
-
#is_infrared_heating_panel_plug_in? ⇒ Object
Whether is infrared heating panel plug in.
-
#is_infrared_heating_panel_plug_in_control? ⇒ Object
Whether is infrared heating panel plug in control.
-
#is_install_kit? ⇒ Object
Whether is install kit.
-
#is_junction_box? ⇒ Object
Whether is junction box.
-
#is_led_mirror? ⇒ Object
Whether is led mirror.
-
#is_legacy_relay? ⇒ Object
Whether is legacy relay.
-
#is_made_to_order_led_mirror? ⇒ Object
Whether is made to order led mirror.
-
#is_membrane? ⇒ Object
Whether is membrane.
-
#is_mirror? ⇒ Object
Whether is mirror.
-
#is_mirror_defogger? ⇒ Object
Whether is mirror defogger.
-
#is_oj_programmable_tstat? ⇒ Object
Whether is oj programmable tstat.
-
#is_oj_programmable_wifi_tstat? ⇒ Object
Whether is oj programmable wifi tstat.
-
#is_pipe_freeze_protection? ⇒ Object
Whether is pipe freeze protection.
-
#is_power? ⇒ Object
Whether is power.
-
#is_power_module? ⇒ Object
Whether is power module.
-
#is_radiator? ⇒ Object
Whether is radiator.
-
#is_refurbished? ⇒ Object
Whether is refurbished.
-
#is_reviewable? ⇒ Object
Whether is reviewable.
-
#is_roughin_kit? ⇒ Object
Whether is roughin kit.
-
#is_self_regulating_cable? ⇒ Object
Whether is self regulating cable.
-
#is_service? ⇒ Object
Whether is service.
-
#is_sh_cable? ⇒ Object
Whether is sh cable.
-
#is_shipping? ⇒ Object
Whether is shipping.
-
#is_slab_heat_mat? ⇒ Object
Whether is slab heat mat.
-
#is_sm_cable? ⇒ Object
Whether is sm cable.
-
#is_smartstat? ⇒ Object
Whether is smartstat.
-
#is_snow_melt_plaque? ⇒ Object
Whether is snow melt plaque.
-
#is_snow_melting_control? ⇒ Object
Whether is snow melting control.
-
#is_snow_melting_mat? ⇒ Object
Whether is snow melting mat.
-
#is_snow_melting_product? ⇒ Object
Whether is snow melting product.
-
#is_spare_parts? ⇒ Object
Whether is spare parts.
-
#is_thermalsheet? ⇒ Object
Whether is thermalsheet.
-
#is_thermostat? ⇒ Object
Whether is thermostat.
-
#is_towel_warmer? ⇒ Object
Whether is towel warmer.
-
#is_towel_warmer_dual_connect? ⇒ Object
Whether is towel warmer dual connect.
-
#is_towel_warmer_hardwired? ⇒ Object
Whether is towel warmer hardwired.
-
#is_towel_warmer_hardwired_control? ⇒ Object
Whether is towel warmer hardwired control.
-
#is_towel_warmer_plug_in? ⇒ Object
Whether is towel warmer plug in.
-
#is_towel_warmer_plug_in_control? ⇒ Object
Whether is towel warmer plug in control.
-
#is_tz_cable? ⇒ Object
Whether is tz cable.
-
#is_tz_ruler_cable? ⇒ Object
Whether is tz ruler cable.
-
#is_tz_thin_cable? ⇒ Object
Whether is tz thin cable.
-
#is_underlayment? ⇒ Object
Whether is underlayment.
-
#item_available_locales ⇒ Object
Item available locales.
-
#item_group_name ⇒ String?
The stable feed group identifier — the canonical family's slug (the backfill preserved the legacy composite string, so itemGroupIds did not change when grouping moved off path derivation).
-
#item_grouping_info(include_self: false, axis_filters: {}) ⇒ Data?
Sibling variants of this item — the canonical VariantGroup membership (explicit, curated), filtered to what the website may sell.
-
#item_state ⇒ Object
Item state.
-
#loaded_rendered_product_specifications ⇒ Object
Loaded rendered product specifications.
-
#make_upc_code ⇒ Object
Make upc code.
-
#missing_catalogs ⇒ Object
Missing catalogs.
-
#most_recent_revision(public_only = true) ⇒ Item?
The newest revision of this publication — walked through the real successor_item chain (see Publication#revision_chain); the legacy canonical-SKU prefix match only runs for chains the backfill hasn't linked yet.
-
#new_revision_sku ⇒ String
Next revision SKU ("TZ-MANUAL-A" → "TZ-MANUAL-B").
-
#non_refurbished_sku ⇒ Object
Non refurbished sku.
-
#order_count ⇒ Object
Order count.
-
#orderable_online? ⇒ Object
Whether orderable online.
-
#orderable_online_in_locale?(locale = I18n.locale) ⇒ Object
Whether orderable online in locale.
-
#past_model? ⇒ Object
Whether past model.
-
#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).
-
#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).
-
#plan_sensitive? ⇒ Boolean
Plan sensitive items are those tied up to the geometry of an installation plan.
-
#primary_image_url(options = {}) ⇒ String?
Returns the primary image URL for display (e.g., cart toast).
-
#primary_product_line_slug_ltree ⇒ Object
Primary product line slug ltree.
-
#product_category_ancestry_ids ⇒ Object
Product category ancestry ids.
-
#product_category_name ⇒ Object
Product category name.
-
#product_category_path ⇒ String
Returns ltree path for product category grouping (preferred - no DB lookup needed).
-
#product_category_priority ⇒ Object
Product category priority.
-
#product_category_slug ⇒ String
Returns product category URL for grouping (legacy - use product_category_path for new code).
-
#product_category_url ⇒ Object
Product category url.
-
#product_line_ancestry_ids ⇒ Object
Product line ancestry ids.
-
#product_line_for_heating_system ⇒ Object
Product line for heating system.
-
#product_line_for_public_sales_portal ⇒ Object
Product line for public sales portal.
-
#product_line_for_review ⇒ Object
Product line for review.
-
#product_line_ids_constellation ⇒ Array<Integer>
This pulls all product line id including inherited for this item, for the root system, and complimentary_product_line_ids.
-
#product_specifications(filters = {}) ⇒ Array<ProductSpecification>
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 empty specs.
-
#prune_unused_translations ⇒ Object
Prune unused translations.
- #public_description_html ⇒ String?
-
#public_description_text ⇒ Object
Public description text.
-
#public_file_name ⇒ Object
Public file name.
-
#public_name ⇒ Object
Public name.
-
#public_specifications ⇒ Array<OpenStruct>
Only specifications intended for the public are retrieved.
-
#publish_shipping_dimensions_changed_event(options = {}) ⇒ void
Publishes Events::ItemShippingDimensionsChanged when shipping-box dims actually changed on this save.
-
#purge_edge_cache(include_product_line: false) ⇒ Object
Purge edge cache.
-
#quantities_indicator_visible? ⇒ Object
Whether quantities indicator visible.
-
#relatives ⇒ ActiveRecord::Relation<Item>
Find all direct siblings and relatives items descendending the product category and product line tree.
-
#render_product_specifications(tokens: nil) ⇒ Object
Render product specifications.
-
#rendered_detailed_description_html ⇒ Object
Rendered detailed description html.
-
#rendered_product_specifications_grouped(locale: Mobility.locale, filter_grouping: nil, sort_order: []) ⇒ Object
Rendered product specifications grouped.
-
#requires_distributor_id_code? ⇒ Object
Whether requires distributor id code.
-
#retrieve_faqs ⇒ Object
Retrieve faqs.
-
#revised_publication_for_public ⇒ Object
Revised publication for public.
-
#revision_sku_conditions ⇒ Array(String, Hash)
Exact revision-chain predicate: the canonical SKU itself or CANONICAL-X (single letter).
-
#revisions ⇒ ActiveRecord::Relation<Item>
All revisions of this publication, newest SKU first.
-
#rma_reason_codes(include_advanced: true) ⇒ Object
Rma reason codes.
-
#run_shipping_audit(carrier: nil) ⇒ Array<Shipping::PackageAuditor>
Run shipping audit for all boxes, optionally for a specific carrier.
-
#safe_name ⇒ String?
Returns a name suitable for edit feed with any special character that will destroy a csv formatting.
-
#sales_product_line_path ⇒ String?
Returns ltree path for sales product line (preferred - reuses already-loaded ProductLine).
-
#sales_product_line_slug ⇒ Object
Sales product line slug.
-
#selection_name ⇒ Object
Selection name.
-
#set_grouping(force: false) ⇒ void
Records a grouping string identifier, this speeds up variant grouping lookup for google and reviews.io api calls.
-
#shift_images(locale: 'en', prefix: nil) ⇒ Hash
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) ⇒ Array<Float>?
unit_system SI = Standard International, e.g Metric ucs = United States Customary Unit.
-
#shipping_dimensions_display ⇒ Object
Shipping dimensions display.
-
#shipping_dimensions_to_package ⇒ Object
Shipping dimensions to package.
-
#shipping_height_converted(unit: 'in', precision: 0) ⇒ Object
Shipping height converted.
-
#shipping_length_converted(unit: 'in', precision: 0) ⇒ Object
Shipping length converted.
-
#shipping_volume ⇒ Object
Shipping volume.
-
#shipping_volume_in_cubic_feet ⇒ Object
Shipping volume in cubic feet.
-
#shipping_weight_converted(unit: 'lbs', precision: nil) ⇒ Object
Shipping weight converted.
-
#shipping_width_converted(unit: 'in', precision: 0) ⇒ Object
Shipping width converted.
-
#ships_in_single_box? ⇒ Object
Whether ships in single box.
-
#ships_via_crate? ⇒ Object
Whether ships via crate.
-
#ships_via_freight? ⇒ Object
Whether ships via freight.
-
#siblings ⇒ Object
Siblings.
-
#single_item_packings_from_md5 ⇒ ActiveRecord::Relation<Packing>
Finds packings of this item but only for a single quantity.
-
#sku_and_name ⇒ Object
Sku and name.
-
#specifications ⇒ Array<OpenStruct>
Retrieves rendered specifications as an object.
-
#specifications_for_item_label ⇒ Object
Specifications for item label.
-
#specifications_grouped ⇒ Object
Specifications grouped.
-
#star? ⇒ Boolean
Makes a star appear in the document library.
-
#supplier_skus ⇒ Object
Supplier skus.
-
#support_product_line_path ⇒ String?
Returns ltree path for support product line (preferred - reuses already-loaded ProductLine).
-
#support_product_line_slug ⇒ Object
Support product line slug.
-
#tags_display ⇒ Object
Tags display.
-
#third_party_skus(limit: 1) ⇒ Object
Third party skus.
-
#thumbnail_url(size: '30x30') ⇒ Object
Thumbnail url.
-
#to_liquid ⇒ Object
To liquid.
-
#to_packdims ⇒ Object
To packdims.
-
#to_s ⇒ Object
To s.
-
#total_shipping_weight ⇒ Object
Total shipping weight.
-
#total_shipping_weight_converted(unit: 'lbs', precision: nil) ⇒ Object
Total shipping weight converted.
-
#total_shipping_weight_of_kit_components ⇒ Object
Total shipping weight of kit components.
-
#update_boxes_from_packages(packages) ⇒ Object
Update boxes from packages.
-
#update_rendered_product_specifications(user_id: nil, tokens: nil, locales: nil) ⇒ Object
Update rendered product specifications.
-
#url_paths ⇒ Object
Url paths.
-
#variant_axis_tokens ⇒ Array<String>
The variant axes of this item's family (e.g. ["voltage", "size"]).
-
#variant_group ⇒ VariantGroup?
The item's DEFAULT variant family (channel-agnostic).
-
#variant_group_for(catalog = nil) ⇒ VariantGroup?
The variant family governing this item on a catalog: an explicit override membership wins, otherwise the default family resolves the catalog (inheriting the default's members when the override has none).
-
#variant_sort_keys ⇒ Array<String>
The family's variant-picker sort order.
-
#variants(include_self: false) ⇒ ActiveRecord::Relation<Item>
A more strict version of relatives, we don't look at descendants, only exact matches.
-
#versions_for_audit_trail(_params = {}) ⇒ Object
Versions for audit trail.
-
#warm_cache(include_product_line: true) ⇒ void
Finds the associated sitemap (url) end points of this item and its product line Perform a cache warmup.
-
#will_be_restricted_for_sales? ⇒ Object
Whether will be restricted for sales.
Methods included from Models::ItemAmazonHelper
#all_amazon_image_profiles, #amazon_description, #amazon_description=, #amazon_family_items, #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=, #amazon_title_differentiation, #amazon_title_differentiation=, #create_or_set_amazon_spec_value, #description_for_amazon, #is_amazon_item?, #reset_amazon_fields, #sync_amazon_asins, #title_for_amazon, with_asin
Methods included from Models::EdgeCachePurgeable
Methods included from Models::CrossLinkable
#case_evidence, #content_links_count, #linked_articles, #linked_content, #linked_faqs, #linked_posts, #linked_publications, #linked_showcases, #linked_videos
Methods included from Models::Publication
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, #durable_download_token, #embeddable_chunked?, embeddable_content_types, #embeddable_locales, #embedding_content_changed?, #fast_country_discontinue, #file_name_for_download, #find_durable_download_token, #friendly_locale_names, #generate_publication_name, #has_literature_changed?, hybrid_search_publications, #latest_revision, #legacy_sku_revision_chain, #linked_revision_chain, #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_download_url, #publication_edge_cache_urls, #publication_landing_page_paths, #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, #purge_publication_cache, #retrieve_publications_search_text, #revision_chain, #secondary_product_category_must_not_be_publication, #should_queue_embedding?, #translation_for_language, with_publication_attached
Methods included from Models::HybridSearchable
ranked_ids, rrf_ranked_relation
Methods included from Models::Embeddable
#content_for_embedding, embeddable_content_types, #embeddable_locales, #embedding_content_hash, #embedding_current?, #embedding_eligible?, 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, with_shape_lock
Methods included from Models::Taggable
#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
Methods included from Models::Translatable
#compact_translation_container, skip_compaction_for
Methods included from Models::ItemPackageContentHelper
#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
Methods included from Models::ItemSpecificationHelper
#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=, #rendered_specifications, #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
Methods included from Models::Kittable
#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
Methods included from Models::Auditable
#all_skipped_columns, #audit_reference_data, #should_not_save_version, #stamp_record
Methods included from Models::ItemLtreeSync
#build_ltree_paths_from_associations, bulk_sync_ltree_paths!, sync_items_for_product_categories!, sync_items_for_product_lines!, #sync_ltree_paths!
Methods included from Models::ItemScopable
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
Methods inherited from ApplicationRecord
ransackable_associations, ransackable_attributes, ransortable_attributes, #to_relation
Methods included from Models::Schedulable
Methods included from Models::AfterCommittable
Methods included from Models::EventPublishable
Instance Attribute Details
#amazon_asin ⇒ void (readonly)
This method returns an undefined value.
Validates amazon asin.
452 453 454 |
# File 'app/models/item.rb', line 452 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 (readonly)
Here we check specifically for the english name to be present
Validations:
444 |
# File 'app/models/item.rb', line 444 validates :name_en, :tax_class, presence: true |
#refresh_specs ⇒ Object
These are shortcuts for publications
220 221 222 |
# File 'app/models/item.rb', line 220 def refresh_specs @refresh_specs end |
#skip_item_calc ⇒ Object
Returns the value of attribute skip_item_calc.
780 781 782 |
# File 'app/models/item.rb', line 780 def skip_item_calc @skip_item_calc end |
#sku ⇒ void (readonly)
This method returns an undefined value.
Validates sku.
447 448 449 |
# File 'app/models/item.rb', line 447 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' } |
#steel_content_value_ratio ⇒ Object (readonly)
Section 232 declaration inputs (see Declaration232) — a ratio outside 0..1
or a negative weight would produce negative rows on a customs declaration.
Validations:
- Numericality ({ greater_than_or_equal_to: 0, less_than_or_equal_to: 1 })
460 |
# File 'app/models/item.rb', line 460 validates :steel_content_value_ratio, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 1 } |
#steel_content_weight_kg ⇒ void (readonly)
This method returns an undefined value.
Validates steel content weight kg.
463 |
# File 'app/models/item.rb', line 463 validates :steel_content_weight_kg, numericality: { greater_than_or_equal_to: 0 } |
#tax_class ⇒ Object (readonly)
Here we check specifically for the english name to be present
Validations:
444 |
# File 'app/models/item.rb', line 444 validates :name_en, :tax_class, presence: true |
#update_search_text ⇒ Object
Returns the value of attribute update_search_text.
780 781 782 |
# File 'app/models/item.rb', line 780 def update_search_text @update_search_text end |
#update_upc ⇒ Object
Returns the value of attribute update_upc.
780 781 782 |
# File 'app/models/item.rb', line 780 def update_upc @update_upc end |
Class Method Details
.accessories ⇒ ActiveRecord::Relation<Item>
A relation of Items that are accessories. Active Record Scope
555 |
# File 'app/models/item.rb', line 555 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
511 |
# File 'app/models/item.rb', line 511 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
659 660 661 662 663 |
# File 'app/models/item.rb', line 659 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 ⇒ Array<String>
all_tags method provided by Models::Taggable concern
Returns sorted distinct publication locales.
809 810 811 |
# File 'app/models/item.rb', line 809 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
Async update all items product specifications.
2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 |
# File 'app/models/item.rb', line 2909 def self.async_update_all_items_product_specifications(public_only: true, active_only: true, limit: nil, not_updated_since: nil) # Select items based on the conditions and if they are due for a refresh items = Item.non_publications items = items.available_to_public if public_only # implies active items = items.active unless public_only && !active_only # Filter items that haven't been refreshed in the last week 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
513 |
# File 'app/models/item.rb', line 513 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
515 |
# File 'app/models/item.rb', line 515 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
675 676 677 678 679 |
# File 'app/models/item.rb', line 675 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
586 587 588 589 |
# File 'app/models/item.rb', line 586 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
528 |
# File 'app/models/item.rb', line 528 scope :category_sorted, -> { joins(:product_category).order(ProductCategory[:priority], ProductCategory[:name], Item[:sku]) } |
.cold_leads ⇒ ActiveRecord::Relation<Item>
A relation of Items that are cold leads. Active Record Scope
562 |
# File 'app/models/item.rb', line 562 scope :cold_leads, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_SPARE_PARTS_COLD_LEADS)) } |
.condition_select_options ⇒ Object
Condition select options.
1192 1193 1194 |
# File 'app/models/item.rb', line 1192 def self. Item.conditions.keys.map { |c| [c.humanize.titleize, c] } end |
.controls ⇒ ActiveRecord::Relation<Item>
A relation of Items that are controls. Active Record Scope
533 |
# File 'app/models/item.rb', line 533 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
635 |
# File 'app/models/item.rb', line 635 scope :countertop_heaters, -> { by_product_category_path(LtreePaths::PC_HEATING_ELEMENTS_COUNTERTOP) } |
.custom_mats ⇒ ActiveRecord::Relation<Item>
A relation of Items that are custom mats. Active Record Scope
634 |
# File 'app/models/item.rb', line 634 scope :custom_mats, -> { by_product_category_path(LtreePaths::PC_HEATING_ELEMENTS_CUSTOM_MATS) } |
.discontinued ⇒ ActiveRecord::Relation<Item>
A relation of Items that are discontinued. Active Record Scope
512 |
# File 'app/models/item.rb', line 512 scope :discontinued, -> { where(is_discontinued: true) } |
.dropships ⇒ ActiveRecord::Relation<Item>
A relation of Items that are dropships. Active Record Scope
610 |
# File 'app/models/item.rb', line 610 scope :dropships, -> { where(dropship: true) } |
.easystats ⇒ ActiveRecord::Relation<Item>
A relation of Items that are easystats. Active Record Scope
547 |
# File 'app/models/item.rb', line 547 scope :easystats, -> { controls.where(Item[:primary_pl_path_slugs].ltree_descendant(LtreePaths::PL_FLOOR_HEATING_CONTROL_EASYSTAT)) } |
.electrical_plan_controls ⇒ ActiveRecord::Relation<Item>
A relation of Items that are electrical plan controls. Active Record Scope
625 626 627 628 629 |
# File 'app/models/item.rb', line 625 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
581 |
# File 'app/models/item.rb', line 581 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
541 |
# File 'app/models/item.rb', line 541 scope :floor_heating_controls, -> { controls.where(Item[:primary_pl_path_slugs].ltree_descendant(LtreePaths::PL_FLOOR_HEATING_CONTROL)) } |
.floor_heating_elements ⇒ ActiveRecord::Relation<Item>
A relation of Items that are floor heating elements. Active Record Scope
553 |
# File 'app/models/item.rb', line 553 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
606 |
# File 'app/models/item.rb', line 606 scope :for_support_portal, -> { where(product_category_id: ProductCategory.for_support_portal.select(:id)) } |
.forecastable ⇒ ActiveRecord::Relation<Item>
A relation of Items that are forecastable. Active Record Scope
583 |
# File 'app/models/item.rb', line 583 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) ⇒ Array<Hash>
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:
3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 |
# File 'app/models/item.rb', line 3279 def self.(connection_method, = [], available_in_catalog_id: nil) available_in_catalog_id = Catalog.locale_to_catalog_id(I18n.locale) if available_in_catalog_id.nil? num_overrides = .size # find how many overrides we have for sorting 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| .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| .index(h) || num_overrides } end |
.get_quantity_from_items_and_sqft(catalog_id, items, sqft, add_one_extra_of_last_item = false) ⇒ Object
Get quantity from items and sqft.
2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 |
# File 'app/models/item.rb', line 2087 def self.get_quantity_from_items_and_sqft(catalog_id, items, sqft, add_one_extra_of_last_item = 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| add_one_extra = if add_one_extra_of_last_item && (i == last_i) && pass.zero? # do this only on first pass 1 else 0 end qty = add_one_extra if item.sqft.to_f > 0.0 qty += if (i == last_i) || ((pass == 1) && (items[i + 1].sqft < sqft)) # do this on last item or on second pass if the next item isn't big enough (area / item.sqft).ceil.to_i # want more than enough to cover if last item else (area / item.sqft).floor.to_i # want what will fit the area with leftover for smaller items end end next unless qty.positive? res[item.sku] = qty area -= (item.sqft.to_f * qty) # we need a pricing weight to choose which is the best result 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) ⇒ Array<Hash>
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:
3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 |
# File 'app/models/item.rb', line 3256 def self.(connection_method, = [], available_in_catalog_id: nil) available_in_catalog_id = Catalog.locale_to_catalog_id(I18n.locale) if available_in_catalog_id.nil? num_overrides = .size # find how many overrides we have for sorting 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| # here we .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| .index(h) || num_overrides } end |
.goods ⇒ ActiveRecord::Relation<Item>
A relation of Items that are goods. Active Record Scope
559 |
# File 'app/models/item.rb', line 559 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
584 |
# File 'app/models/item.rb', line 584 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
604 |
# File 'app/models/item.rb', line 604 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
624 |
# File 'app/models/item.rb', line 624 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
531 |
# File 'app/models/item.rb', line 531 scope :heating_elements, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_HEATING_ELEMENTS)) } |
.identifiers_search ⇒ ActiveRecord::Relation<Item>
A relation of Items that are identifiers search. Active Record Scope
691 692 693 694 695 696 697 698 699 700 701 702 703 |
# File 'app/models/item.rb', line 691 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
Import translation keys.
2699 2700 2701 |
# File 'app/models/item.rb', line 2699 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
564 565 566 |
# File 'app/models/item.rb', line 564 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
653 |
# File 'app/models/item.rb', line 653 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
601 |
# File 'app/models/item.rb', line 601 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
600 |
# File 'app/models/item.rb', line 600 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
598 |
# File 'app/models/item.rb', line 598 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
597 |
# File 'app/models/item.rb', line 597 scope :infrared_heating_panels, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_INFRARED_HEATING_PANELS)) } |
.infrared_heating_panels_hardwired ⇒ ActiveRecord::Relation<Item>
A relation of Items that are infrared heating panels hardwired. Active Record Scope
599 |
# File 'app/models/item.rb', line 599 scope :infrared_heating_panels_hardwired, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_INFRARED_HEATING_PANELS_HARDWIRED)) } |
.install_kits ⇒ ActiveRecord::Relation<Item>
A relation of Items that are install kits. Active Record Scope
632 |
# File 'app/models/item.rb', line 632 scope :install_kits, -> { by_product_line_path(LtreePaths::PL_FLOOR_HEATING_TEMPZONE_INSTALLATION_KITS).merge(accessories) } |
.insulations ⇒ ActiveRecord::Relation<Item>
A relation of Items that are insulations. Active Record Scope
557 |
# File 'app/models/item.rb', line 557 scope :insulations, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_ACCESSORIES_INSULATIONS)) } |
.integration_kits ⇒ ActiveRecord::Relation<Item>
A relation of Items that are integration kits. Active Record Scope
550 |
# File 'app/models/item.rb', line 550 scope :integration_kits, -> { powers.where(Item[:primary_pl_path_slugs].ltree_descendant(LtreePaths::PL_FLOOR_HEATING_CONTROL_INTEGRATION)) } |
.item_identifier_label_sizes_select_options ⇒ Object
Item identifier label sizes select options.
1213 1214 1215 |
# File 'app/models/item.rb', line 1213 def self. [['2.3125" x 4" (S-8505)', 'regular'], ['4" x 6" (S-17044)', 'large']] end |
.last_custom_mat_item ⇒ Object
Last custom mat item.
1220 1221 1222 |
# File 'app/models/item.rb', line 1220 def self.last_custom_mat_item Item.by_product_line_path(LtreePaths::PL_FLOOR_HEATING_TEMPZONE_CUSTOM_MAT).merge(heating_elements).order('items.id DESC').first end |
.membranes ⇒ ActiveRecord::Relation<Item>
A relation of Items that are membranes. Active Record Scope
633 |
# File 'app/models/item.rb', line 633 scope :membranes, -> { where(sku: ItemConstants::MEMBRANE_SKUS) } |
.mirror_defoggers ⇒ ActiveRecord::Relation<Item>
A relation of Items that are mirror defoggers. Active Record Scope
543 |
# File 'app/models/item.rb', line 543 scope :mirror_defoggers, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_MIRROR_DEFOGGERS)) } |
.mirrors ⇒ ActiveRecord::Relation<Item>
A relation of Items that are mirrors. Active Record Scope
532 |
# File 'app/models/item.rb', line 532 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
519 520 521 522 523 524 525 526 527 |
# File 'app/models/item.rb', line 519 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
689 |
# File 'app/models/item.rb', line 689 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
688 |
# File 'app/models/item.rb', line 688 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
611 |
# File 'app/models/item.rb', line 611 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
575 |
# File 'app/models/item.rb', line 575 scope :non_kits, -> { where(is_kit: false) } |
.non_publications ⇒ ActiveRecord::Relation<Item>
A relation of Items that are non publications. Active Record Scope
574 |
# File 'app/models/item.rb', line 574 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
576 |
# File 'app/models/item.rb', line 576 scope :non_shipping, -> { where.not(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_SHIPPING_AND_HANDLING)) } |
.not_a_target_item ⇒ ActiveRecord::Relation<Item>
A relation of Items that are not a target item. Active Record Scope
612 |
# File 'app/models/item.rb', line 612 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
545 |
# File 'app/models/item.rb', line 545 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
544 |
# File 'app/models/item.rb', line 544 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
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 |
# File 'app/models/item.rb', line 636 scope :order_by_spec, ->(spec, datatype = 'varchar', direction = 'asc') { if %w[decimal integer numeric].include?(datatype.downcase) # For numeric types, extract numbers from text and handle NULL values 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 # For non-numeric types, use the original logic 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
540 |
# File 'app/models/item.rb', line 540 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
585 |
# File 'app/models/item.rb', line 585 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
592 593 594 |
# File 'app/models/item.rb', line 592 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
516 |
# File 'app/models/item.rb', line 516 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
549 |
# File 'app/models/item.rb', line 549 scope :power_modules, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_POWER_MODULES)) } |
.powers ⇒ ActiveRecord::Relation<Item>
A relation of Items that are powers. Active Record Scope
551 |
# File 'app/models/item.rb', line 551 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
681 682 683 684 685 686 |
# File 'app/models/item.rb', line 681 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
669 670 671 672 |
# File 'app/models/item.rb', line 669 scope :public_and_active_in_any_catalogs, -> { active .where("exists(#{CI_EXIST_CHECK_SQL} and ci.state NOT IN (?))", CatalogItem::HIDDEN_STATES) } |
.public_and_active_in_catalog_id ⇒ ActiveRecord::Relation<Item>
A relation of Items that are public and active in catalog id. Active Record Scope
664 665 666 667 668 |
# File 'app/models/item.rb', line 664 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
713 |
# File 'app/models/item.rb', line 713 scope :publications_search, ->(term) { canonical_search(term) } |
.ransackable_scopes(_auth_object = nil) ⇒ Object
Ransackable scopes.
862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 |
# File 'app/models/item.rb', line 862 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
548 |
# File 'app/models/item.rb', line 548 scope :relay_panels, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_POWER_RELAY_PANELS)) } |
.remote_services ⇒ ActiveRecord::Relation<Item>
A relation of Items that are remote services. Active Record Scope
561 |
# File 'app/models/item.rb', line 561 scope :remote_services, -> { services.where(Item[:sku].matches('%REMOTE%')) } |
.rendered_product_specs_keys ⇒ Object
Rendered product specs keys.
2963 2964 2965 |
# File 'app/models/item.rb', line 2963 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
Rendered product specs options for select.
2971 2972 2973 2974 2975 |
# File 'app/models/item.rb', line 2971 def self.(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
630 |
# File 'app/models/item.rb', line 630 scope :reservable, -> { where(require_reservation: true) } |
.reviewable ⇒ ActiveRecord::Relation<Item>
A relation of Items that are reviewable. Active Record Scope
613 |
# File 'app/models/item.rb', line 613 scope :reviewable, -> { joins(:product_category, :product_lines).merge(ProductLine.reviewable).merge(ProductCategory.reviewable) } |
.rough_in_kits ⇒ ActiveRecord::Relation<Item>
A relation of Items that are rough in kits. Active Record Scope
631 |
# File 'app/models/item.rb', line 631 scope :rough_in_kits, -> { by_product_line_path(LtreePaths::PL_FLOOR_HEATING_ROUGH_IN_KITS).merge(accessories) } |
.sensors ⇒ ActiveRecord::Relation<Item>
A relation of Items that are sensors. Active Record Scope
552 |
# File 'app/models/item.rb', line 552 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
560 |
# File 'app/models/item.rb', line 560 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
609 |
# File 'app/models/item.rb', line 609 scope :shipping, -> { where(tax_class: 'shp') } |
.sku_aliases_search ⇒ ActiveRecord::Relation<Item>
A relation of Items that are sku aliases search. Active Record Scope
590 |
# File 'app/models/item.rb', line 590 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
591 |
# File 'app/models/item.rb', line 591 scope :sku_and_aliases_search, ->(sku) { where('items.sku ILIKE :sku OR items.sku_aliases @> ARRAY[:sku]::varchar[]', sku:) } |
.sku_is_membrane?(sku) ⇒ Object
Whether sku is membrane.
1979 1980 1981 |
# File 'app/models/item.rb', line 1979 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
705 |
# File 'app/models/item.rb', line 705 scope :sku_search, ->(sku) { canonical_search(sku) } |
.smart_services ⇒ ActiveRecord::Relation<Item>
A relation of Items that are smart services. Active Record Scope
655 |
# File 'app/models/item.rb', line 655 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
595 |
# File 'app/models/item.rb', line 595 scope :smartpresets, -> { where(sku: SMARTPRESET_SERVICE_SKU) } |
.smartstats ⇒ ActiveRecord::Relation<Item>
A relation of Items that are smartstats. Active Record Scope
546 |
# File 'app/models/item.rb', line 546 scope :smartstats, -> { controls.where(Item[:primary_pl_path_slugs].ltree_descendant(LtreePaths::PL_FLOOR_HEATING_CONTROL_SMARTSTAT)) } |
.snow_melting_elements ⇒ ActiveRecord::Relation<Item>
A relation of Items that are snow melting elements. Active Record Scope
554 |
# File 'app/models/item.rb', line 554 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
563 |
# File 'app/models/item.rb', line 563 scope :spare_parts, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_SPARE_PARTS)) } |
.tax_classes_for_select ⇒ Object
Tax classes for select.
1206 1207 1208 |
# File 'app/models/item.rb', line 1206 def self.tax_classes_for_select TAX_CLASSES.invert end |
.tempzones ⇒ ActiveRecord::Relation<Item>
A relation of Items that are tempzones. Active Record Scope
596 |
# File 'app/models/item.rb', line 596 scope :tempzones, -> { where(Item[:primary_pl_path_slugs].ltree_descendant(LtreePaths::PL_FLOOR_HEATING_TEMPZONE)).merge(heating_elements) } |
.thermostats ⇒ ActiveRecord::Relation<Item>
A relation of Items that are thermostats. Active Record Scope
534 |
# File 'app/models/item.rb', line 534 scope :thermostats, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_CONTROLS_THERMOSTATS)) } |
.tools ⇒ ActiveRecord::Relation<Item>
A relation of Items that are tools. Active Record Scope
558 |
# File 'app/models/item.rb', line 558 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
542 |
# File 'app/models/item.rb', line 542 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
539 |
# File 'app/models/item.rb', line 539 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
538 |
# File 'app/models/item.rb', line 538 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
535 |
# File 'app/models/item.rb', line 535 scope :towel_warmers, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_TOWEL_WARMERS)) } |
.towel_warmers_hardwired ⇒ ActiveRecord::Relation<Item>
A relation of Items that are towel warmers hardwired. Active Record Scope
537 |
# File 'app/models/item.rb', line 537 scope :towel_warmers_hardwired, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_TOWEL_WARMERS_HARDWIRED)) } |
.towel_warmers_plug_in ⇒ ActiveRecord::Relation<Item>
A relation of Items that are towel warmers plug in. Active Record Scope
536 |
# File 'app/models/item.rb', line 536 scope :towel_warmers_plug_in, -> { where(Item[:pc_path_slugs].ltree_descendant(LtreePaths::PC_TOWEL_WARMERS_PLUG_IN)) } |
.underlayments ⇒ ActiveRecord::Relation<Item>
A relation of Items that are underlayments. Active Record Scope
608 |
# File 'app/models/item.rb', line 608 scope :underlayments, -> { where(Item[:pc_path_slugs].ltree_descendant([LtreePaths::PC_ACCESSORIES_INSULATIONS, LtreePaths::PC_ACCESSORIES_MEMBRANES])) } |
.uom_select_options ⇒ Object
Uom select options.
1199 1200 1201 |
# File 'app/models/item.rb', line 1199 def self. %w[each feet] end |
.upgrades ⇒ ActiveRecord::Relation<Item>
A relation of Items that are upgrades. Active Record Scope
556 |
# File 'app/models/item.rb', line 556 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
756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 |
# File 'app/models/item.rb', line 756 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
654 |
# File 'app/models/item.rb', line 654 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
614 615 616 617 618 619 620 621 622 623 |
# File 'app/models/item.rb', line 614 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
567 568 569 |
# File 'app/models/item.rb', line 567 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
570 571 572 |
# File 'app/models/item.rb', line 570 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 ⇒ ActiveRecord::Relation<Image>
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
3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 |
# File 'app/models/item.rb', line 3299 def all_images # Start simple find those that have direct links query = Image.left_outer_joins(:items) .left_outer_joins(:product_lines) .left_outer_joins(:product_categories) # Conditions as follow conditions = [] plids = product_line_ancestry_ids pcids = product_category_ancestry_ids # Condition 1 - Image tagged specifically for this item conditions << Item[:id].eq(id) # Condition 2 are images tagged by any ancestry product line but no specific product category conditions << ProductLine[:id].in(plids).and(ProductCategory[:id].eq(nil)) if plids.present? # Condition 3 are images tagged by any ancestry product category but no specific product line conditions << ProductLine[:id].eq(nil).and(ProductCategory[:id].in(pcids)) if pcids.present? # Condition 4 are images tagged by both product line and category ancestries conditions << ProductLine[:id].in(plids).and(ProductCategory[:id].in(pcids)) if plids.present? && pcids.present? # Create an or condition combined_conditions = conditions.reduce(:or) query.where(combined_conditions) end |
#all_my_publications(categories: nil, locale: nil, publication_category_paths: nil) ⇒ Object
All my publications.
2508 2509 2510 |
# File 'app/models/item.rb', line 2508 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
All site maps.
2793 2794 2795 |
# File 'app/models/item.rb', line 2793 def all_site_maps [] + site_maps.to_a + catalog_item_site_maps.to_a end |
#all_uploads ⇒ Object
All uploads.
3387 3388 3389 |
# File 'app/models/item.rb', line 3387 def all_uploads uploads.order(Upload[:created_at].desc) end |
#any_box_changed? ⇒ Object
Whether any box changed.
3380 3381 3382 |
# File 'app/models/item.rb', line 3380 def any_box_changed? box1_changed? || box2_changed? || box3_changed? end |
#articles ⇒ ActiveRecord::Associations::CollectionProxy
The associated articles.
426 |
# File 'app/models/item.rb', line 426 has_and_belongs_to_many :articles |
#assortment_instructions ⇒ ActiveRecord::Associations::CollectionProxy
The associated assortment instructions.
435 |
# File 'app/models/item.rb', line 435 has_and_belongs_to_many :assortment_instructions, inverse_of: :items |
#async_update_rendered_product_specifications ⇒ Object
Async update rendered product specifications.
2786 2787 2788 |
# File 'app/models/item.rb', line 2786 def async_update_rendered_product_specifications ItemAttributeWorker.perform_async(id) end |
#authenticated_url(dimensions = nil) ⇒ Object
Authenticated url.
1110 1111 1112 |
# File 'app/models/item.rb', line 1110 def authenticated_url(dimensions = nil) (dimensions.nil? ? literature..url : literature..thumb(dimensions, format: 'png', frame: '0').url) if literature end |
#auto_translate(reset_previous_values: false, locales: nil) ⇒ Object
Auto translate.
2609 2610 2611 2612 2613 2614 2615 2616 2617 |
# File 'app/models/item.rb', line 2609 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_attributes(reset_previous_values: reset_previous_values, locales: locales) 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
Auto translate attributes.
2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 |
# File 'app/models/item.rb', line 2624 def auto_translate_attributes(reset_previous_values: false, locales: nil) # Auto translate attributes from the translatable list locales ||= content_locales_to_render res = {} TRANSLATABLE_ATTRIBUTES.each do |attr_name| next unless (english_val = send(:"#{attr_name}_en").presence) # We loop through the locales res[attr_name] = {} locales.each do |locale| # If our locale already exists and we specify we do not want to reset value, we can skip next if !reset_previous_values && Mobility.with_locale(locale) { send(attr_name.to_sym) }.present? # Translate 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? # Store it in the locale 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
Auto translate product specifications.
2658 2659 2660 2661 2662 2663 2664 |
# File 'app/models/item.rb', line 2658 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 ⇒ Array<String>
Returns all locales from the catalog this item is part of
2842 2843 2844 2845 |
# File 'app/models/item.rb', line 2842 def available_content_locales # Join to catalog and find out in which locale we need to generate content, english is implied Catalog.eager_load(:catalog_items).merge(catalog_items.not_discontinued).pluck(:locales).flatten.compact.uniq.sort end |
#available_token_options_from_product_specifications ⇒ Object
Available token options from product specifications.
3020 3021 3022 |
# File 'app/models/item.rb', line 3020 def (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
Base weight converted.
2284 2285 2286 |
# File 'app/models/item.rb', line 2284 def base_weight_converted(unit: 'lbs', precision: nil) express_weight_converted base_weight, unit:, precision: end |
#box1_changed? ⇒ Object
Whether box1 changed.
3345 3346 3347 |
# File 'app/models/item.rb', line 3345 def box1_changed? %i[shipping_weight shipping_length shipping_width shipping_height].any? { |fn| send(:"#{fn}_previously_changed?") || send(:"will_save_change_to_#{fn}?") } end |
#box1_defined? ⇒ Object
Whether box1 defined.
3338 3339 3340 |
# File 'app/models/item.rb', line 3338 def box1_defined? %i[shipping_weight shipping_length shipping_width shipping_height].all? { |fn| send(fn)&.positive? } end |
#box2_changed? ⇒ Object
Whether box2 changed.
3359 3360 3361 |
# File 'app/models/item.rb', line 3359 def box2_changed? %i[box2_shipping_weight box2_shipping_length box2_shipping_width box2_shipping_height].any? { |fn| send(:"#{fn}_previously_changed?") || send(:"will_save_change_to_#{fn}?") } end |
#box2_defined? ⇒ Object
Whether box2 defined.
3352 3353 3354 |
# File 'app/models/item.rb', line 3352 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
Box2 shipping dimensions to package.
2346 2347 2348 2349 2350 2351 |
# File 'app/models/item.rb', line 2346 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
Box2 shipping height converted.
2226 2227 2228 2229 2230 |
# File 'app/models/item.rb', line 2226 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
Box2 shipping length converted.
2204 2205 2206 2207 2208 |
# File 'app/models/item.rb', line 2204 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
Box2 shipping weight converted.
2320 2321 2322 |
# File 'app/models/item.rb', line 2320 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
Box2 shipping width converted.
2215 2216 2217 2218 2219 |
# File 'app/models/item.rb', line 2215 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? ⇒ Object
Whether box3 changed.
3373 3374 3375 |
# File 'app/models/item.rb', line 3373 def box3_changed? %i[box3_shipping_weight box3_shipping_length box3_shipping_width box3_shipping_height].any? { |fn| send(:"#{fn}_previously_changed?") || send(:"will_save_change_to_#{fn}?") } end |
#box3_defined? ⇒ Object
Whether box3 defined.
3366 3367 3368 |
# File 'app/models/item.rb', line 3366 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
Box3 shipping dimensions to package.
2356 2357 2358 2359 2360 2361 |
# File 'app/models/item.rb', line 2356 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
Box3 shipping height converted.
2259 2260 2261 2262 2263 |
# File 'app/models/item.rb', line 2259 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
Box3 shipping length converted.
2237 2238 2239 2240 2241 |
# File 'app/models/item.rb', line 2237 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
Box3 shipping weight converted.
2329 2330 2331 |
# File 'app/models/item.rb', line 2329 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
Box3 shipping width converted.
2248 2249 2250 2251 2252 |
# File 'app/models/item.rb', line 2248 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
Boxes.
1319 1320 1321 1322 1323 1324 |
# File 'app/models/item.rb', line 1319 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
Boxes shipping dimensions and weights converted.
1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 |
# File 'app/models/item.rb', line 1423 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
Boxes shipping dimensions and weights display.
1439 1440 1441 1442 1443 1444 1445 1446 |
# File 'app/models/item.rb', line 1439 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| # %g drops trailing zeros so 37.0 → "37", 0.27 → "0.27", 0.5 → "0.5". # Previous precision: 0 default rounded sub-1″ dims to 0, producing # nonsense like "37 in x 25 in x 0 in" for items with fractional height. "#{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
Boxes to packages.
1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 |
# File 'app/models/item.rb', line 1329 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 |
#brand ⇒ Brand?
The associated brand.
296 |
# File 'app/models/item.rb', line 296 belongs_to :brand, optional: true |
#calculate_ideal_cable_spacing ⇒ Object
Calculate ideal cable spacing.
2006 2007 2008 2009 2010 2011 2012 2013 2014 |
# File 'app/models/item.rb', line 2006 def calculate_ideal_cable_spacing return @preloaded_ideal_cable_spacing if instance_variable_defined?(:@preloaded_ideal_cable_spacing) res = nil if primary_product_line && primary_product_line.get_first_heating_system_type.present? res = HeatingElementProductLineOption.(:ideal_cable_spacing, product_line_id: primary_product_line.get_first_heating_system_type.id).first end res end |
#calculate_is_cable_system? ⇒ Object
Whether calculate is cable system.
1994 1995 1996 1997 1998 1999 2000 2001 |
# File 'app/models/item.rb', line 1994 def calculate_is_cable_system? res = nil if primary_product_line && primary_product_line.get_first_heating_system_type.present? && HeatingElementProductLineOption.(: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
Calculate item fields.
1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 |
# File 'app/models/item.rb', line 1298 def calculate_item_fields # always set largest shipping dimension to shipping_length, then shipping_width, then shipping_height 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? ⇒ Object
Whether can be packaged.
1283 1284 1285 |
# File 'app/models/item.rb', line 1283 def can_be_packaged? Item.packageable.where(id:).present? end |
#canonical_path ⇒ String?
Hierarchical canonical path via product line ancestry + SKU.
e.g. "towel-warmer/barcelona/TW-BC-08BS-FS2"
924 925 926 927 928 929 930 931 |
# File 'app/models/item.rb', line 924 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
Canonical sku.
2429 2430 2431 2432 2433 2434 2435 2436 |
# File 'app/models/item.rb', line 2429 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) ⇒ String?
Canonical URL with locale prefix.
e.g. "/en-US/towel-warmer/barcelona/TW-BC-08BS-FS2"
937 938 939 940 941 942 |
# File 'app/models/item.rb', line 937 def canonical_url(locale: I18n.locale) path = canonical_path return nil unless path "/#{locale}/#{path}" end |
#catalog_item_site_maps ⇒ ActiveRecord::Associations::CollectionProxy
The associated catalog item site maps.
381 |
# File 'app/models/item.rb', line 381 has_many :catalog_item_site_maps, class_name: 'SiteMap', source: :site_maps, through: :catalog_items |
#catalog_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated catalog items.
311 |
# File 'app/models/item.rb', line 311 has_many :catalog_items, through: :store_items, inverse_of: :item |
#catalogs ⇒ ActiveRecord::Associations::CollectionProxy
The associated catalogs.
314 |
# File 'app/models/item.rb', line 314 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)
2389 2390 2391 2392 2393 2394 2395 |
# File 'app/models/item.rb', line 2389 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::Associations::CollectionProxy
The associated compatible items.
396 |
# File 'app/models/item.rb', line 396 has_many :compatible_items, -> { merge(ItemRelation.replacement_parts) }, through: :source_item_relations, source: :source_item |
#container_type ⇒ Object
Container type.
3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 |
# File 'app/models/item.rb', line 3240 def container_type # let's guess, if ships_via_crate? crate, if ships LTL, pallet, otherwise carton if ships_via_crate? Shipment.container_types.keys[2] # 'crate' elsif shipping_class == 'freight_service' Shipment.container_types.keys[1] # 'pallet' else Shipment.container_types.keys.first # 'carton' end end |
#content_locales_to_render ⇒ Object
Content locales to render.
2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 |
# File 'app/models/item.rb', line 2850 def content_locales_to_render if is_publication? Mobility.available_locales else locales = (Mobility.available_locales & ([I18n.default_locale] + available_content_locales)).uniq # Because en-US and en-CA are at this point the same, we don't bother rendering these, if this changes, this is # where you remove the following code. We'll put french in the same category why not. Don't solve this problem # until we actually have a product sold in france and canada locales.delete(:'en-US') locales.delete(:'en-CA') locales.delete(:'fr-CA') if locales.include?(:fr) locales end end |
#controllable? ⇒ Object
Whether controllable.
979 980 981 982 983 |
# File 'app/models/item.rb', line 979 def controllable? is_heating_element? || is_towel_warmer? || is_infrared_heating_panel? end |
#country_of_origin_iso3 ⇒ Object
Country of origin iso3.
905 906 907 908 909 |
# File 'app/models/item.rb', line 905 def country_of_origin_iso3 return unless coo ISO3166::Country[coo]&.alpha3 end |
#country_of_origin_name ⇒ Object
Country of origin name.
896 897 898 899 900 |
# File 'app/models/item.rb', line 896 def country_of_origin_name return unless coo ISO3166::Country[coo]&.iso_short_name end |
#create_template_specifications ⇒ Object
Create template specifications.
2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 |
# File 'app/models/item.rb', line 2980 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| # Check if there is already a spec for this, only template if blank 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
Current supplier cost.
970 971 972 973 974 |
# File 'app/models/item.rb', line 970 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
Deep dup.
227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'app/models/item.rb', line 227 def deep_dup klone = deep_clone( include: :item_product_lines, except: %i[upc upload_id last_sale_date first_sale_date popularity amazon_asin literature_id] ) do |_original, copy| copy.popularity = nil if copy.is_a?(Item) end # A publication owns its literature 1:1 — the dup gets its own stored copy # of the PDF, never an alias of the original's Literature row. klone.literature = literature. if literature.present? klone end |
#default_short_description ⇒ Object
Default short description.
2544 2545 2546 2547 2548 |
# File 'app/models/item.rb', line 2544 def default_short_description return unless (dd = detailed_description.to_s.squish.presence) && dd.present? dd.truncate(120, separator: ' ') end |
#detailed_description ⇒ String
Creates a text description from the html rendered description
2537 2538 2539 |
# File 'app/models/item.rb', line 2537 def detailed_description html_to_text(rendered_detailed_description_html) end |
#digital_assets ⇒ ActiveRecord::Associations::CollectionProxy
The associated digital assets.
429 |
# File 'app/models/item.rb', line 429 has_and_belongs_to_many :digital_assets |
#direct_packings ⇒ ActiveRecord::Associations::CollectionProxy
The associated direct packings.
405 |
# File 'app/models/item.rb', line 405 has_many :direct_packings, class_name: 'Packing', inverse_of: :item, dependent: :destroy |
#direct_product_specifications ⇒ ActiveRecord::Associations::CollectionProxy
The associated direct product specifications.
441 |
# File 'app/models/item.rb', line 441 has_and_belongs_to_many :direct_product_specifications, class_name: 'ProductSpecification', dependent: :destroy, inverse_of: :items |
#discontinue_self_and_dependents ⇒ Object
Discontinue self and dependents.
1270 1271 1272 1273 1274 1275 1276 1277 1278 |
# File 'app/models/item.rb', line 1270 def discontinue_self_and_dependents self.class.transaction do store_items.each do |si| si.catalog_items.each(&:discontinue) # This event updates the state and hides the catalog from feed si.update_attribute!(:is_discontinued, true) end update!(is_discontinued: true, cycle_count_grouping: 'not_set') end end |
#discontinue_store_and_catalog_items ⇒ Object
Discontinue store and catalog items.
1260 1261 1262 1263 1264 1265 |
# File 'app/models/item.rb', line 1260 def discontinue_store_and_catalog_items return if is_publication? discontinue_self_and_dependents if is_discontinued? true end |
#ean13 ⇒ Object
Ean13.
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 |
# File 'app/models/item.rb', line 1095 def ean13 return if upc.blank? case upc.size when 12 "0#{upc}" when 13 upc end end |
#edge_cache_urls ⇒ Array<String>
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.
2815 2816 2817 |
# File 'app/models/item.rb', line 2815 def edge_cache_urls all_site_maps.flat_map { |sm| [sm.url, *sm.section_cache_urls] }.uniq end |
#edi_communication_logs ⇒ ActiveRecord::Associations::CollectionProxy
The associated edi communication logs.
411 |
# File 'app/models/item.rb', line 411 has_many :edi_communication_logs, through: :edi_documents |
#edi_documents ⇒ ActiveRecord::Associations::CollectionProxy
The associated edi documents.
408 |
# File 'app/models/item.rb', line 408 has_many :edi_documents, dependent: :destroy |
#effective_nmfc_class ⇒ Object
Alias for Product_category#effective_nmfc_class
788 789 790 791 792 793 794 795 796 797 |
# File 'app/models/item.rb', line 788 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
788 789 790 791 792 793 794 795 796 797 |
# File 'app/models/item.rb', line 788 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
Effective option name.
3152 3153 3154 |
# File 'app/models/item.rb', line 3152 def effective_option_name option_name.presence || public_short_name.presence || name end |
#effective_seo_description(char_limit: nil) ⇒ Object
Effective seo description.
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 |
# File 'app/models/item.rb', line 1118 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 # We replace by spaces first in case line feed is used as a sentence separator. 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
Effective seo keywords.
2584 2585 2586 2587 2588 2589 2590 2591 |
# File 'app/models/item.rb', line 2584 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
Effective seo title.
1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 |
# File 'app/models/item.rb', line 1136 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) # if we have room add the sku s << " (#{sku})" end if s.size > SEO_TITLE_MAX_LENGTH # truncate s.truncate(SEO_TITLE_MAX_LENGTH, separator: /\s/, omission: '') end s end |
#exclusive_item_group ⇒ ExclusiveItemGroup?
The associated exclusive item group.
269 |
# File 'app/models/item.rb', line 269 belongs_to :exclusive_item_group, inverse_of: :items, optional: true |
#express_weight_converted(weight_in_lbs, unit: 'lbs', precision: nil) ⇒ Object
Express weight converted.
2271 2272 2273 2274 2275 2276 2277 |
# File 'app/models/item.rb', line 2271 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 |
#features ⇒ Array<String>
Features are a sub category of specs with feature priority set
2738 2739 2740 2741 2742 2743 2744 |
# File 'app/models/item.rb', line 2738 def features if has_features? [feature_1, feature_2, feature_3, feature_4, feature_5].filter_map(&:presence) else inherited_features # Look for inherited features end end |
#fix_name ⇒ Object
Fix name.
2553 2554 2555 2556 2557 2558 |
# File 'app/models/item.rb', line 2553 def fix_name # ' is interpreted as ′ self.name = name.tr("'", '′') # " is interpreted as ″ self.name = name.tr('"', '″') end |
#fixture_key ⇒ Object
Fixture key.
2019 2020 2021 |
# File 'app/models/item.rb', line 2019 def fixture_key sku.to_s end |
#freight_class ⇒ Object
Freight class.
1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 |
# File 'app/models/item.rb', line 1396 def freight_class freight_class = nil # important: item.base_weight is the better quality number and means Net Weight so the correct number to use when calculating item weight because tare weight (of the box, pallet, crate etc) is added after 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
Generate refurbished sku.
2470 2471 2472 |
# File 'app/models/item.rb', line 2470 def generate_refurbished_sku "#{sku}-BTK" end |
#get_quantity_from_sqft(input_sqft, add_one_extra = false) ⇒ Object
Get quantity from sqft.
2074 2075 2076 2077 2078 |
# File 'app/models/item.rb', line 2074 def get_quantity_from_sqft(input_sqft, add_one_extra = false) qty = add_one_extra ? 1 : 0 qty += (input_sqft / sqft).ceil.to_i if sqft.to_f > 0.0 qty end |
#google_feed_image_profiles ⇒ ActiveRecord::Associations::CollectionProxy
The associated google feed image profiles.
417 418 419 |
# File 'app/models/item.rb', line 417 has_many :google_feed_image_profiles, -> { website_image_profiles_excluding_card.image_order }, class_name: 'ImageProfile' |
#gross_weight_converted(unit: 'lbs', precision: nil) ⇒ Object
Gross weight converted.
2293 2294 2295 |
# File 'app/models/item.rb', line 2293 def gross_weight_converted(unit: 'lbs', precision: nil) express_weight_converted gross_weight, unit:, precision: end |
#gtin13 ⇒ Object
Gtin13.
2126 2127 2128 |
# File 'app/models/item.rb', line 2126 def gtin13 "0#{upc}" end |
#gtin_type ⇒ Object
Gtin type.
947 948 949 950 951 |
# File 'app/models/item.rb', line 947 def gtin_type return :missing if upc.blank? Item::UpcBarcode.identify_type(upc) end |
#gtin_type_friendly ⇒ Object
Gtin type friendly.
956 957 958 959 960 961 962 963 964 965 |
# File 'app/models/item.rb', line 956 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) ⇒ String?
Returns the first 6 digits of the harmonization code (HS6)
2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 |
# File 'app/models/item.rb', line 2140 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? ⇒ Object
Whether has ean13.
1088 1089 1090 |
# File 'app/models/item.rb', line 1088 def has_ean13? upc && upc.size == 13 end |
#has_features? ⇒ Object
Whether has features.
2732 2733 2734 |
# File 'app/models/item.rb', line 2732 def has_features? [feature_1, feature_2, feature_3, feature_4, feature_5].any?(&:present?) end |
#has_heating_system? ⇒ Object
Whether has heating system.
2047 2048 2049 |
# File 'app/models/item.rb', line 2047 def has_heating_system? primary_product_line.get_first_heating_system_type.present? end |
#has_stock? ⇒ Object
Whether has stock.
1236 1237 1238 |
# File 'app/models/item.rb', line 1236 def has_stock? self.class.with_stock.exists?(id:) end |
#has_stock_in_store?(st_id) ⇒ Object
Whether has stock in store.
1244 1245 1246 |
# File 'app/models/item.rb', line 1244 def has_stock_in_store?(st_id) self.class.with_stock_for(st_id).exists?(id:) end |
#image_profiles ⇒ ActiveRecord::Associations::CollectionProxy
The associated image profiles.
414 |
# File 'app/models/item.rb', line 414 has_many :image_profiles, -> { image_order } |
#image_url(dimensions, options = {}) ⇒ String?
Returns the primary image URL at the given dimensions.
1493 1494 1495 1496 |
# File 'app/models/item.rb', line 1493 def image_url(dimensions, = {}) opts = { size: dimensions }.merge() image_url2(opts) end |
#image_url2(options = {}) ⇒ String?
Use this new form that passes the options straight to the url generator
1477 1478 1479 1480 1481 1482 1483 |
# File 'app/models/item.rb', line 1477 def image_url2( = {}) if primary_image primary_image.image_url() elsif new_item&.primary_image new_item.primary_image.image_url() end end |
#images ⇒ ActiveRecord::Associations::CollectionProxy
The associated images.
422 |
# File 'app/models/item.rb', line 422 has_many :images, through: :image_profiles |
#import_translation_keys ⇒ Array<TranslationKeyResource>
This method will import existing translations or link to existing ones
2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 |
# File 'app/models/item.rb', line 2668 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) # The presence of resources implies it was imported 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) # Does this translation key exists? tk = TranslationKey.find_or_create_by_key!(text, TRANSLATION_NAMESPACE) # Do we need to import this translation tk.translations.where(locale: locale_string.first(2)).first_or_create!(text: translation) # And link our new resource tkrs << tk.translation_key_resources.where(resource: self, resource_attribute: attr).first_or_create! end end # Import the product specifications 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
Increment request counter.
995 996 997 998 999 |
# File 'app/models/item.rb', line 995 def increment_request_counter return unless persisted? Item.update_counters id, requested_counter: 1 end |
#inherited_features ⇒ Array<String>
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
2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 |
# File 'app/models/item.rb', line 2752 def inherited_features features_result = [] if (ppl = primary_product_line) && (pc_url = product_category_url) # Only take product lines which have features defined directly ppl.self_and_ancestors.select(&:has_features?).each do |pl| # If the product line is 'loose' we can use its features # The product category of the item must match if pl.product_categories.empty? || pl.product_categories.any? { |pc| pc_url.starts_with?(pc.url) } features_result = pl.features break end end end # If we get here there's nothing to inherit features_result.filter_map(&:presence) end |
#is_accessory? ⇒ Object
Alias for Product_category#is_accessory?
788 789 790 791 792 793 794 795 796 797 |
# File 'app/models/item.rb', line 788 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? ⇒ Object
Whether is available to public.
1029 1030 1031 1032 |
# File 'app/models/item.rb', line 1029 def is_available_to_public? logger.debug "Checking if #{id} / #{sku} is available to public" orderable_view_product_catalogs.present? end |
#is_cable_accessory? ⇒ Object
Whether is cable accessory.
1947 1948 1949 1950 |
# File 'app/models/item.rb', line 1947 def is_cable_accessory? product_category&.is_accessory? && pl_descendant_of_path?(LtreePaths::PL_FLOOR_HEATING_TEMPZONE_THIN_CABLE) end |
#is_cable_fit_guide? ⇒ Object
Whether is cable fit guide.
1929 1930 1931 1932 1933 |
# File 'app/models/item.rb', line 1929 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? ⇒ Object
Whether is cable heating element.
1816 1817 1818 |
# File 'app/models/item.rb', line 1816 def is_cable_heating_element? pc_descendant_of_path?(LtreePaths::PC_HEATING_ELEMENTS_HEATING_CABLES) end |
#is_cable_tape? ⇒ Object
Whether is cable tape.
1938 1939 1940 1941 1942 |
# File 'app/models/item.rb', line 1938 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? ⇒ Object
Whether is cerazorb.
1851 1852 1853 |
# File 'app/models/item.rb', line 1851 def is_cerazorb? primary_product_line&.is_cerazorb? && product_category&.is_insulation? end |
#is_circuit_check? ⇒ Object
Whether is circuit check.
1837 1838 1839 |
# File 'app/models/item.rb', line 1837 def is_circuit_check? sku == ItemConstants::CIRCUIT_CHECK_SKU end |
#is_cold_lead? ⇒ Object
Whether is cold lead.
1530 1531 1532 |
# File 'app/models/item.rb', line 1530 def is_cold_lead? pc_descendant_of_path?(LtreePaths::PC_SPARE_PARTS_COLD_LEADS) end |
#is_control? ⇒ Object
Alias for Product_category#is_control?
788 789 790 791 792 793 794 795 796 797 |
# File 'app/models/item.rb', line 788 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? ⇒ Object
Whether is cork.
1844 1845 1846 |
# File 'app/models/item.rb', line 1844 def is_cork? primary_product_line&.is_cork? && product_category&.is_insulation? end |
#is_custom_mat? ⇒ Object
Alias for Product_category#is_custom_mat?
788 789 790 791 792 793 794 795 796 797 |
# File 'app/models/item.rb', line 788 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 ⇒ Boolean
Helper for validation: skips weight checks for discontinued items and publications
889 890 891 |
# File 'app/models/item.rb', line 889 def is_discontinued_or_publication is_discontinued? || is_publication? end |
#is_economy_snow_melt_control? ⇒ Object
Whether is economy snow melt control.
1879 1880 1881 |
# File 'app/models/item.rb', line 1879 def is_economy_snow_melt_control? sku == ItemConstants::ECONOMY_SNOW_MELT_CONTROL_SKU end |
#is_floor_heating_product? ⇒ Object
Whether is floor heating product.
1523 1524 1525 |
# File 'app/models/item.rb', line 1523 def is_floor_heating_product? is_heating_element? && pl_descendant_of_path?(LtreePaths::PL_FLOOR_HEATING) end |
#is_goods? ⇒ Object
Whether is goods.
1737 1738 1739 |
# File 'app/models/item.rb', line 1737 def is_goods? tax_class == 'g' end |
#is_heating_element? ⇒ Object
Whether is heating element.
1809 1810 1811 |
# File 'app/models/item.rb', line 1809 def is_heating_element? pc_descendant_of_path?(LtreePaths::PC_HEATING_ELEMENTS) end |
#is_infrared_heating_panel? ⇒ Object
Whether is infrared heating panel.
1595 1596 1597 |
# File 'app/models/item.rb', line 1595 def is_infrared_heating_panel? pc_descendant_of_path?(LtreePaths::PC_INFRARED_HEATING_PANELS) end |
#is_infrared_heating_panel_dual_connect? ⇒ Object
Whether is infrared heating panel dual connect.
1616 1617 1618 |
# File 'app/models/item.rb', line 1616 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? ⇒ Object
Whether is infrared heating panel hardwired.
1609 1610 1611 |
# File 'app/models/item.rb', line 1609 def is_infrared_heating_panel_hardwired? pc_descendant_of_path?(LtreePaths::PC_INFRARED_HEATING_PANELS_HARDWIRED) end |
#is_infrared_heating_panel_hardwired_control? ⇒ Object
Whether is infrared heating panel hardwired control.
1630 1631 1632 |
# File 'app/models/item.rb', line 1630 def is_infrared_heating_panel_hardwired_control? sku.in?(ItemConstants::INFRARED_HEATING_PANELS_HARDWIRE_CONTROL_SKUS) end |
#is_infrared_heating_panel_plug_in? ⇒ Object
Whether is infrared heating panel plug in.
1602 1603 1604 |
# File 'app/models/item.rb', line 1602 def is_infrared_heating_panel_plug_in? pc_descendant_of_path?(LtreePaths::PC_INFRARED_HEATING_PANELS_PLUG_IN) end |
#is_infrared_heating_panel_plug_in_control? ⇒ Object
Whether is infrared heating panel plug in control.
1623 1624 1625 |
# File 'app/models/item.rb', line 1623 def is_infrared_heating_panel_plug_in_control? sku.in?(ItemConstants::INFRARED_HEATING_PANELS_PLUG_IN_CONTROL_SKUS) end |
#is_install_kit? ⇒ Object
Whether is install kit.
1551 1552 1553 |
# File 'app/models/item.rb', line 1551 def is_install_kit? sku&.start_with?(ItemConstants::INSTALL_KIT_SKU_PREFIX) end |
#is_junction_box? ⇒ Object
Whether is junction box.
1886 1887 1888 |
# File 'app/models/item.rb', line 1886 def is_junction_box? ItemConstants::JUNCTION_BOX_SKUS.include?(sku) end |
#is_led_mirror? ⇒ Object
Whether is led mirror.
1588 1589 1590 |
# File 'app/models/item.rb', line 1588 def is_led_mirror? is_mirror? && pl_descendant_of_path?(LtreePaths::PL_LED_MIRROR) end |
#is_legacy_relay? ⇒ Object
Whether is legacy relay.
1544 1545 1546 |
# File 'app/models/item.rb', line 1544 def is_legacy_relay? sku&.start_with?(ItemConstants::LEGACY_RELAY_SKU_PREFIX) end |
#is_made_to_order_led_mirror? ⇒ Object
Whether is made to order led mirror.
1969 1970 1971 1972 1973 |
# File 'app/models/item.rb', line 1969 def is_made_to_order_led_mirror? # here we only care if it shipped by Lumidesign, because some smaller component will just be added to the LED crate # rather than take up it's own pallet primary_product_line&.is_made_to_order_led_mirror? # && product_category&.is_mirror? end |
#is_membrane? ⇒ Object
Whether is membrane.
1955 1956 1957 |
# File 'app/models/item.rb', line 1955 def is_membrane? Item.sku_is_membrane?(sku) end |
#is_mirror? ⇒ Object
Whether is mirror.
1581 1582 1583 |
# File 'app/models/item.rb', line 1581 def is_mirror? pc_descendant_of_path?(LtreePaths::PC_MIRRORS) end |
#is_mirror_defogger? ⇒ Object
Whether is mirror defogger.
1637 1638 1639 |
# File 'app/models/item.rb', line 1637 def is_mirror_defogger? pc_descendant_of_path?(LtreePaths::PC_MIRROR_DEFOGGERS) end |
#is_oj_programmable_tstat? ⇒ Object
Whether is oj programmable tstat.
1772 1773 1774 |
# File 'app/models/item.rb', line 1772 def is_oj_programmable_tstat? is_thermostat? && LtreePaths::PL_OJ_PROGRAMMABLE_TSTAT_LINES.any? { |path| pl_descendant_of_path?(path) } end |
#is_oj_programmable_wifi_tstat? ⇒ Object
Whether is oj programmable wifi tstat.
1779 1780 1781 |
# File 'app/models/item.rb', line 1779 def is_oj_programmable_wifi_tstat? ItemConstants::OJ_PROGRAMMABLE_WIFI_TSTAT_SKU_PREFIXES.any? { |prefix| sku&.start_with?(prefix) } end |
#is_pipe_freeze_protection? ⇒ Object
Whether is pipe freeze protection.
1684 1685 1686 |
# File 'app/models/item.rb', line 1684 def is_pipe_freeze_protection? is_heating_element? && pl_descendant_of_path?(LtreePaths::PL_PIPE_FREEZE_PROTECTION) end |
#is_power? ⇒ Object
Whether is power.
1730 1731 1732 |
# File 'app/models/item.rb', line 1730 def is_power? pc_descendant_of_path?(LtreePaths::PC_POWER) end |
#is_power_module? ⇒ Object
Whether is power module.
1537 1538 1539 |
# File 'app/models/item.rb', line 1537 def is_power_module? ItemConstants::POWER_MODULE_SKU_PREFIXES.any? { |prefix| sku&.include?(prefix) } end |
#is_publication? ⇒ Object
Alias for Product_category#is_publication?
788 789 790 791 792 793 794 795 796 797 |
# File 'app/models/item.rb', line 788 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? ⇒ Object
Whether is radiator.
988 989 990 |
# File 'app/models/item.rb', line 988 def is_radiator? is_heating_element? || is_towel_warmer? || is_infrared_heating_panel? || is_mirror_defogger? end |
#is_refurbished? ⇒ Object
Whether is refurbished.
2477 2478 2479 |
# File 'app/models/item.rb', line 2477 def is_refurbished? condition_refurbished? end |
#is_relay_panel? ⇒ Object
Alias for Product_category#is_relay_panel?
788 789 790 791 792 793 794 795 796 797 |
# File 'app/models/item.rb', line 788 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? ⇒ Object
Whether is reviewable.
2026 2027 2028 |
# File 'app/models/item.rb', line 2026 def is_reviewable? Item.reviewable.where(id:).present? end |
#is_roughin_kit? ⇒ Object
Whether is roughin kit.
1962 1963 1964 |
# File 'app/models/item.rb', line 1962 def is_roughin_kit? sku&.include?(ItemConstants::ROUGHIN_KIT_SKU_PATTERN) end |
#is_self_regulating_cable? ⇒ Object
Whether is self regulating cable.
1572 1573 1574 1575 1576 |
# File 'app/models/item.rb', line 1572 def is_self_regulating_cable? pc_descendant_of_path?(LtreePaths::PC_HEATING_ELEMENTS_HEATING_CABLES) && (pl_descendant_of_path?(LtreePaths::PL_PIPE_FREEZE_PROTECTION_SELF_REG) || pl_descendant_of_path?(LtreePaths::PL_ROOF_GUTTER_DEICING_SELF_REG)) end |
#is_service? ⇒ Object
Whether is service.
1751 1752 1753 |
# File 'app/models/item.rb', line 1751 def is_service? tax_class == 'svc' end |
#is_sh_cable? ⇒ Object
Whether is sh cable.
1922 1923 1924 |
# File 'app/models/item.rb', line 1922 def is_sh_cable? is_heating_element? && pl_descendant_of_path?(LtreePaths::PL_FLOOR_HEATING_SLAB_HEAT_CABLE) end |
#is_shipping? ⇒ Object
Whether is shipping.
1758 1759 1760 |
# File 'app/models/item.rb', line 1758 def is_shipping? tax_class == 'shp' end |
#is_slab_heat_mat? ⇒ Object
Whether is slab heat mat.
1823 1824 1825 |
# File 'app/models/item.rb', line 1823 def is_slab_heat_mat? is_heating_element? && pl_descendant_of_path?(LtreePaths::PL_FLOOR_HEATING_SLAB_HEAT_MAT) end |
#is_sm_cable? ⇒ Object
Whether is sm cable.
1915 1916 1917 |
# File 'app/models/item.rb', line 1915 def is_sm_cable? is_heating_element? && pl_descendant_of_path?(LtreePaths::PL_SNOW_MELTING_CABLE) end |
#is_smartstat? ⇒ Object
Whether is smartstat.
1765 1766 1767 |
# File 'app/models/item.rb', line 1765 def is_smartstat? ItemConstants::IID_SMARTSTATS.include?(id) end |
#is_snow_melt_plaque? ⇒ Object
Whether is snow melt plaque.
1872 1873 1874 |
# File 'app/models/item.rb', line 1872 def is_snow_melt_plaque? sku == ItemConstants::SNOW_MELT_PLAQUE_SKU end |
#is_snow_melting_control? ⇒ Object
Whether is snow melting control.
1565 1566 1567 |
# File 'app/models/item.rb', line 1565 def is_snow_melting_control? pl_descendant_of_path?(LtreePaths::PL_SNOW_MELTING_CONTROL) end |
#is_snow_melting_mat? ⇒ Object
Whether is snow melting mat.
1830 1831 1832 |
# File 'app/models/item.rb', line 1830 def is_snow_melting_mat? is_heating_element? && pl_descendant_of_path?(LtreePaths::PL_SNOW_MELTING_MAT) end |
#is_snow_melting_product? ⇒ Object
Whether is snow melting product.
1558 1559 1560 |
# File 'app/models/item.rb', line 1558 def is_snow_melting_product? pl_descendant_of_path?(LtreePaths::PL_SNOW_MELTING) end |
#is_spare_parts? ⇒ Object
Whether is spare parts.
1744 1745 1746 |
# File 'app/models/item.rb', line 1744 def is_spare_parts? pc_descendant_of_path?(LtreePaths::PC_SPARE_PARTS) end |
#is_thermalsheet? ⇒ Object
Whether is thermalsheet.
1858 1859 1860 |
# File 'app/models/item.rb', line 1858 def is_thermalsheet? primary_product_line&.is_thermalsheet? && product_category&.is_insulation? end |
#is_thermostat? ⇒ Object
Whether is thermostat.
1723 1724 1725 |
# File 'app/models/item.rb', line 1723 def is_thermostat? pc_descendant_of_path?(LtreePaths::PC_CONTROLS_THERMOSTATS) end |
#is_towel_warmer? ⇒ Object
Whether is towel warmer.
1670 1671 1672 |
# File 'app/models/item.rb', line 1670 def is_towel_warmer? pc_descendant_of_path?(LtreePaths::PC_TOWEL_WARMERS) end |
#is_towel_warmer_dual_connect? ⇒ Object
Whether is towel warmer dual connect.
1691 1692 1693 1694 1695 1696 1697 |
# File 'app/models/item.rb', line 1691 def is_towel_warmer_dual_connect? pc_descendant_of_path?(LtreePaths::PC_TOWEL_WARMERS_DUAL_CONNECTION) || ( pc_descendant_of_path?(LtreePaths::PC_TOWEL_WARMERS) && spec_value(:connection_method) == 'Plug-in or Hardwired' ) end |
#is_towel_warmer_hardwired? ⇒ Object
Whether is towel warmer hardwired.
1677 1678 1679 |
# File 'app/models/item.rb', line 1677 def is_towel_warmer_hardwired? pc_descendant_of_path?(LtreePaths::PC_TOWEL_WARMERS_HARDWIRED) end |
#is_towel_warmer_hardwired_control? ⇒ Object
Whether is towel warmer hardwired control.
1716 1717 1718 |
# File 'app/models/item.rb', line 1716 def is_towel_warmer_hardwired_control? sku.in?(ItemConstants::TOWEL_WARMER_HARDWIRE_CONTROL_SKUS) end |
#is_towel_warmer_plug_in? ⇒ Object
Whether is towel warmer plug in.
1702 1703 1704 |
# File 'app/models/item.rb', line 1702 def is_towel_warmer_plug_in? pc_descendant_of_path?(LtreePaths::PC_TOWEL_WARMERS_PLUG_IN) end |
#is_towel_warmer_plug_in_control? ⇒ Object
Whether is towel warmer plug in control.
1709 1710 1711 |
# File 'app/models/item.rb', line 1709 def is_towel_warmer_plug_in_control? sku.in?(ItemConstants::TOWEL_WARMER_PLUG_IN_CONTROL_SKUS) end |
#is_tz_cable? ⇒ Object
Whether is tz cable.
1893 1894 1895 1896 |
# File 'app/models/item.rb', line 1893 def is_tz_cable? is_heating_element? && (pl_descendant_of_path?(LtreePaths::PL_FLOOR_HEATING_TEMPZONE_CABLE) || pl_descendant_of_path?(LtreePaths::PL_FLOOR_HEATING_TEMPZONE_RULER_CABLE)) end |
#is_tz_ruler_cable? ⇒ Object
Whether is tz ruler cable.
1908 1909 1910 |
# File 'app/models/item.rb', line 1908 def is_tz_ruler_cable? is_heating_element? && pl_descendant_of_path?(LtreePaths::PL_FLOOR_HEATING_TEMPZONE_RULER_CABLE) end |
#is_tz_thin_cable? ⇒ Object
Whether is tz thin cable.
1901 1902 1903 |
# File 'app/models/item.rb', line 1901 def is_tz_thin_cable? is_heating_element? && pl_descendant_of_path?(LtreePaths::PL_FLOOR_HEATING_TEMPZONE_THIN_CABLE) end |
#is_underlayment? ⇒ Object
Whether is underlayment.
1865 1866 1867 |
# File 'app/models/item.rb', line 1865 def is_underlayment? primary_product_line&.is_underlayment? && product_category&.is_insulation? end |
#is_upgrade? ⇒ Object
Alias for Product_category#is_upgrade?
788 789 790 791 792 793 794 795 796 797 |
# File 'app/models/item.rb', line 788 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
Item available locales.
1050 1051 1052 |
# File 'app/models/item.rb', line 1050 def item_available_locales LocaleUtility::SITE_LOCALES.select { |l| orderable_online_in_locale?(l) } end |
#item_group_name ⇒ String?
The stable feed group identifier — the canonical family's slug (the
backfill preserved the legacy composite string, so itemGroupIds did not
change when grouping moved off path derivation).
3106 3107 3108 |
# File 'app/models/item.rb', line 3106 def item_group_name variant_group&.slug end |
#item_grouping_info(include_self: false, axis_filters: {}) ⇒ Data?
Sibling variants of this item — the canonical VariantGroup membership
(explicit, curated), filtered to what the website may sell.
3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 |
# File 'app/models/item.rb', line 3117 def item_grouping_info(include_self: false, axis_filters: {}) return if product_category.skip_siblings return unless (group = variant_group) variants = group.effective_items.active.condition_new .joins(:product_category).where.not(ProductCategory[:custom_product].eq(true)) .order(:sku) axis_filters.each do |token, value| variants = variants.with_product_specification(token, value) 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: product_category_path, pl_url: sales_product_line_path, item_group_id: group.slug, item_group_name: group.slug, variants:) end |
#item_product_lines ⇒ ActiveRecord::Associations::CollectionProxy
The associated item product lines.
339 |
# File 'app/models/item.rb', line 339 has_many :item_product_lines, -> { order(:position) }, inverse_of: :item, dependent: :destroy |
#item_relations ⇒ ActiveRecord::Associations::CollectionProxy
The associated item relations.
369 |
# File 'app/models/item.rb', line 369 has_many :item_relations, class_name: 'PublicationItem', foreign_key: :publication_id, inverse_of: :publication, dependent: :destroy |
#item_state ⇒ Object
Item state.
1016 1017 1018 1019 1020 1021 1022 1023 1024 |
# File 'app/models/item.rb', line 1016 def item_state if is_discontinued 'Discontinued' elsif is_available_to_public? 'Published' else 'Private' end end |
#line_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated line items.
342 |
# File 'app/models/item.rb', line 342 has_many :line_items |
#literature ⇒ Literature?
The associated literature.
266 |
# File 'app/models/item.rb', line 266 belongs_to :literature, optional: true |
#loaded_rendered_product_specifications ⇒ Object
Loaded rendered product specifications.
2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 |
# File 'app/models/item.rb', line 2925 def loaded_rendered_product_specifications rp_specs = rendered_product_specifications || {} # Collect all product specification ids ps_ids = rp_specs.values.pluck('product_specification_id').uniq.compact # Preload the product specifications 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
Make upc code.
2133 2134 2135 |
# File 'app/models/item.rb', line 2133 def make_upc_code self.upc = Item::UpcMaker.new.process if upc.blank? end |
#missing_catalogs ⇒ Object
Missing catalogs.
3324 3325 3326 |
# File 'app/models/item.rb', line 3324 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) ⇒ Item?
The newest revision of this publication — walked through the real
successor_item chain (see Publication#revision_chain); the legacy
canonical-SKU prefix match only runs for chains the backfill hasn't
linked yet. +public_only+ filters to revisions visible to the public.
2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 |
# File 'app/models/item.rb', line 2403 def most_recent_revision(public_only = true) unless is_publication? items = Item.publications.where(*revision_sku_conditions) items = items.available_to_public if public_only return items.order(sku: :desc).first end chain = revision_chain if public_only visible_ids = Item.publications.available_to_public.where(id: chain.map(&:id)).pluck(:id).to_set chain = chain.select { |pub| visible_ids.include?(pub.id) } end chain.last end |
#new_item ⇒ Item?
The associated new item.
293 |
# File 'app/models/item.rb', line 293 belongs_to :new_item, class_name: 'Item', optional: true |
#new_revision_sku ⇒ String
Next revision SKU ("TZ-MANUAL-A" → "TZ-MANUAL-B"). The letter bumps off
the chain END (the newest known revision), not a bare SKU prefix scan —
the old scan could bump off an unrelated longer SKU sharing the prefix.
2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 |
# File 'app/models/item.rb', line 2442 def new_revision_sku latest_sku = (is_publication? ? latest_revision.sku : canonical_sku) sku_match = latest_sku.to_s.match(/(.*)-([[:alpha:]])$/) if sku_match && (sku_match.length == 3) base = sku_match[1] rev_code = sku_match[2] "#{base}-#{rev_code.succ}" elsif canonical_sku.present? "#{canonical_sku}-A" else raise "Publication #{id} #{sku} could not be parsed for revision (-a, -b, etc.)" end end |
#non_refurbished_sku ⇒ Object
Non refurbished sku.
2484 2485 2486 |
# File 'app/models/item.rb', line 2484 def non_refurbished_sku sku.delete_suffix('-BTK') end |
#order_count ⇒ Object
Order count.
2515 2516 2517 |
# File 'app/models/item.rb', line 2515 def order_count Order.contains_item_ids([id]).count end |
#orderable_online? ⇒ Object
Whether orderable online.
1251 1252 1253 1254 1255 |
# File 'app/models/item.rb', line 1251 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) ⇒ Object
Whether orderable online in locale.
1039 1040 1041 1042 1043 1044 1045 |
# File 'app/models/item.rb', line 1039 def orderable_online_in_locale?(locale = I18n.locale) # leverage preloaded reloation if available scoped_records = orderable_view_product_catalogs if orderable_view_product_catalogs.loaded? # If not loaded, then retrieve only what we need 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::Associations::CollectionProxy
The associated orderable view product catalogs.
333 334 335 336 |
# File 'app/models/item.rb', line 333 has_many :orderable_view_product_catalogs, -> { visible_to_public }, foreign_key: :item_id, class_name: 'ViewProductCatalog' |
#packaging_discrepancy_packing ⇒ Packing?
The associated packaging discrepancy packing.
300 |
# File 'app/models/item.rb', line 300 belongs_to :packaging_discrepancy_packing, class_name: 'Packing', optional: true |
#packings ⇒ ActiveRecord::Associations::CollectionProxy
The associated packings.
432 |
# File 'app/models/item.rb', line 432 has_and_belongs_to_many :packings, inverse_of: :items |
#past_model? ⇒ Object
Whether past model.
1463 1464 1465 |
# File 'app/models/item.rb', line 1463 def past_model? ( || []).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)
1659 1660 1661 1662 1663 1664 1665 |
# File 'app/models/item.rb', line 1659 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)
1646 1647 1648 1649 1650 1651 1652 |
# File 'app/models/item.rb', line 1646 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
1456 1457 1458 |
# File 'app/models/item.rb', line 1456 def plan_sensitive? is_heating_element? end |
#preferred_supplier ⇒ Supplier?
The associated preferred supplier.
284 |
# File 'app/models/item.rb', line 284 belongs_to :preferred_supplier, class_name: 'Supplier', optional: true |
#primary_image ⇒ Image?
The associated primary image.
272 |
# File 'app/models/item.rb', line 272 belongs_to :primary_image, class_name: 'Image', optional: true |
#primary_image_url(options = {}) ⇒ String?
Returns the primary image URL for display (e.g., cart toast).
Uses WYS_MAIN profile first, falls back to primary_image association.
1514 1515 1516 1517 1518 |
# File 'app/models/item.rb', line 1514 def primary_image_url( = {}) wys_main = image_profiles.find { |p| p.image_type == 'WYS_MAIN' } image = wys_main&.image || primary_image image&.image_url() end |
#primary_product_line ⇒ ProductLine?
The associated primary product line.
278 |
# File 'app/models/item.rb', line 278 belongs_to :primary_product_line, class_name: 'ProductLine', inverse_of: :primary_items, optional: true |
#primary_product_line_slug_ltree ⇒ Object
Primary product line slug ltree.
1793 1794 1795 |
# File 'app/models/item.rb', line 1793 def primary_product_line_slug_ltree primary_product_line&.slug_ltree&.to_s end |
#primary_variant_groups ⇒ ActiveRecord::Relation<VariantGroup>
Groups that point at this item as their curated lead child — cleared (not
blocked) when the item goes away, so the items FK can't abort the destroy.
326 327 |
# File 'app/models/item.rb', line 326 has_many :primary_variant_groups, class_name: 'VariantGroup', foreign_key: :primary_item_id, dependent: :nullify, inverse_of: :primary_item |
#product_category ⇒ ProductCategory?
The associated product category.
257 |
# File 'app/models/item.rb', line 257 belongs_to :product_category |
#product_category_ancestry_ids ⇒ Object
Product category ancestry ids.
2498 2499 2500 |
# File 'app/models/item.rb', line 2498 def product_category_ancestry_ids ProductCategory.self_and_ancestors_ids(product_category_id) end |
#product_category_name ⇒ Object
Product category name.
1152 1153 1154 |
# File 'app/models/item.rb', line 1152 def product_category_name ProductCategoryConstants.name_for(product_category_id) end |
#product_category_path ⇒ String
Returns ltree path for product category grouping (preferred - no DB lookup needed)
3058 3059 3060 3061 3062 3063 3064 3065 3066 |
# File 'app/models/item.rb', line 3058 def product_category_path pc_path = pc_path_slugs.to_s # Normalize to parent category for grouping purposes 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
Product category priority.
1159 1160 1161 |
# File 'app/models/item.rb', line 1159 def product_category_priority ProductCategoryConstants.priority_for(product_category_id) end |
#product_category_slug ⇒ String
Returns product category URL for grouping (legacy - use product_category_path for new code)
3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 |
# File 'app/models/item.rb', line 3045 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
Product category url.
1801 1802 1803 |
# File 'app/models/item.rb', line 1801 def product_category_url product_category&.url end |
#product_line_ancestry_ids ⇒ Object
Product line ancestry ids.
2491 2492 2493 |
# File 'app/models/item.rb', line 2491 def product_line_ancestry_ids ProductLine.self_and_ancestors_ids(product_line_ids) end |
#product_line_for_heating_system ⇒ Object
Product line for heating system.
2054 2055 2056 2057 2058 2059 2060 |
# File 'app/models/item.rb', line 2054 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
Product line for public sales portal.
2040 2041 2042 |
# File 'app/models/item.rb', line 2040 def product_line_for_public_sales_portal primary_product_line&.get_first_public_for_sales end |
#product_line_for_review ⇒ Object
Product line for review.
2033 2034 2035 |
# File 'app/models/item.rb', line 2033 def product_line_for_review primary_product_line&.get_first_reviewable end |
#product_line_ids_constellation ⇒ Array<Integer>
This pulls all product line id including inherited for this item, for the root system,
and complimentary_product_line_ids
1004 1005 1006 1007 1008 1009 1010 1011 |
# File 'app/models/item.rb', line 1004 def product_line_ids_constellation pl_ids = [] pl_ids += product_line_ids || [] # This will implicitly include the root system which is always an ancestor pl_ids += root_system_product_line&.complimentary_product_line_ids || [] # The complimentaries of the root system pl_ids += primary_product_line&.complimentary_product_line_ids || [] # The complimentaries of only this product line pl_ids = pl_ids.compact.uniq ProductLine.self_and_ancestors_ids(pl_ids).compact.uniq end |
#product_lines ⇒ ActiveRecord::Associations::CollectionProxy
The associated product lines.
345 |
# File 'app/models/item.rb', line 345 has_many :product_lines, through: :item_product_lines |
#product_specifications(filters = {}) ⇒ Array<ProductSpecification>
Retrieves all product specifications available to a given item, this does not
retrieve rendered specs but the specs definition used to build them
2597 2598 2599 2600 2601 |
# File 'app/models/item.rb', line 2597 def product_specifications(filters = {}) filters[:propagation] ||= %w[unrestricted item] res = Item::SpecificationsRetriever.new.process(self, filters) res.specifications end |
#product_tax_code ⇒ ProductTaxCode?
The associated product tax code.
287 |
# File 'app/models/item.rb', line 287 belongs_to :product_tax_code, inverse_of: :items, optional: true |
#prune_empty_specs ⇒ Object
Prune empty specs.
3010 3011 3012 3013 3014 3015 |
# File 'app/models/item.rb', line 3010 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
Prune unused translations.
3394 3395 3396 3397 3398 3399 |
# File 'app/models/item.rb', line 3394 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 ⇒ String?
2569 2570 2571 2572 |
# File 'app/models/item.rb', line 2569 def public_description_html (rendered_detailed_description_html.presence || primary_product_line&.description_html.presence)&.html_safe # rubocop:enable Rails/OutputSafety end |
#public_description_text ⇒ Object
Public description text.
2577 2578 2579 |
# File 'app/models/item.rb', line 2577 def public_description_text detailed_description.presence || primary_product_line&.description.presence end |
#public_file_name ⇒ Object
Public file name.
1173 1174 1175 |
# File 'app/models/item.rb', line 1173 def public_file_name "#{public_name}.#{Mime::Type.file_extension_of(literature.mime_type) || 'pdf'}" end |
#public_name ⇒ Object
Public name.
1166 1167 1168 |
# File 'app/models/item.rb', line 1166 def public_name public_short_name.presence || name end |
#public_specifications ⇒ Array<OpenStruct>
Only specifications intended for the public are retrieved
2718 2719 2720 |
# File 'app/models/item.rb', line 2718 def public_specifications specifications.select { |s| s.output.present? && s.grouping != 'Features' && s.grouping != 'Highlights' && s.visibility == 'open_visibility' } end |
#publication_relations ⇒ ActiveRecord::Associations::CollectionProxy
The associated publication relations.
366 |
# File 'app/models/item.rb', line 366 has_many :publication_relations, class_name: 'PublicationItem', inverse_of: :item, dependent: :destroy |
#publish_shipping_dimensions_changed_event(options = {}) ⇒ void
This method returns an undefined value.
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.
3172 3173 3174 3175 3176 3177 3178 3179 |
# File 'app/models/item.rb', line 3172 def publish_shipping_dimensions_changed_event( = {}) return unless any_box_changed? || [:force] Rails.configuration.event_store.publish( Events::ItemShippingDimensionsChanged.new(data: { item_id: id }), stream_name: "Item-#{id}" ) end |
#purchase_order_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated purchase order items.
399 |
# File 'app/models/item.rb', line 399 has_many :purchase_order_items |
#purge_edge_cache(include_product_line: false) ⇒ Object
Purge edge cache.
2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 |
# File 'app/models/item.rb', line 2823 def purge_edge_cache(include_product_line: false) # This doesn't exist unless staging or production 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? ⇒ Object
Whether quantities indicator visible.
2065 2066 2067 |
# File 'app/models/item.rb', line 2065 def quantities_indicator_visible? display_treatment.nil? || display_treatment != Item::DISPLAY_TREATMENT_HIDE_QUANTITIES end |
#refurbished_version ⇒ Item?
The associated refurbished version.
304 |
# File 'app/models/item.rb', line 304 has_one :refurbished_version, class_name: 'Item', foreign_key: :new_item_id |
#related_source_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated related source items.
387 |
# File 'app/models/item.rb', line 387 has_many :related_source_items, through: :source_item_relations, source: :source_item |
#related_target_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated related target items.
390 |
# File 'app/models/item.rb', line 390 has_many :related_target_items, through: :target_item_relations, source: :target_item |
#related_target_items_for_specs ⇒ ActiveRecord::Associations::CollectionProxy
The associated related target items for specs.
393 |
# File 'app/models/item.rb', line 393 has_many :related_target_items_for_specs, through: :target_item_relations_for_specs, source: :target_item |
#relatives ⇒ ActiveRecord::Relation<Item>
Find all direct siblings and relatives items descendending the product category and product line tree
3026 3027 3028 3029 3030 3031 3032 3033 3034 |
# File 'app/models/item.rb', line 3026 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
Render product specifications.
2774 2775 2776 2777 2778 2779 2780 2781 |
# File 'app/models/item.rb', line 2774 def render_product_specifications(tokens: nil) res = Item::SpecificationsMasher.new.process(item: self, tokens:).specifications if tokens.present? # We will merge the results (rendered_product_specifications || {}).merge(res) else res end end |
#rendered_detailed_description_html ⇒ Object
Rendered detailed description html.
2563 2564 2565 |
# File 'app/models/item.rb', line 2563 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
Rendered product specifications grouped.
2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 |
# File 'app/models/item.rb', line 2943 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 nil as last sort_order.index(k.to_sym) || Float::INFINITY, # Sort by sort_order if present v['name'] || nil # Sort nil as last ] end sorted.group_by { |_k, v| v['grouping'] || 'Other' } end end |
#replacement_for ⇒ Item?
The associated replacement for.
275 |
# File 'app/models/item.rb', line 275 belongs_to :replacement_for, class_name: 'Item', optional: true |
#requires_distributor_id_code? ⇒ Object
Whether requires distributor id code.
1786 1787 1788 |
# File 'app/models/item.rb', line 1786 def requires_distributor_id_code? sku&.start_with?('UWG4-4999', 'AWG4-4999') && !sku&.include?('-WY') end |
#retrieve_faqs ⇒ Object
Retrieve faqs.
854 855 856 |
# File 'app/models/item.rb', line 854 def retrieve_faqs Item::ArticleRetriever.new(article_types: %w[faq]).process(item: self).articles end |
#returned_rma_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated returned rma items.
348 |
# File 'app/models/item.rb', line 348 has_many :returned_rma_items, class_name: 'Rma', foreign_key: :returned_item_id |
#revised_publication_for_public ⇒ Object
Revised publication for public.
1290 1291 1292 1293 |
# File 'app/models/item.rb', line 1290 def revised_publication_for_public revision = most_recent_revision(:public) revision == self ? nil : revision end |
#revision_sku_conditions ⇒ Array(String, Hash)
Exact revision-chain predicate: the canonical SKU itself or CANONICAL-X
(single letter). Locale variants (…-SPANISH-A), lookalike same-prefix SKUs
(…1), and LIKE wildcards in the canonical (% / _) are all excluded.
Case-insensitive (~*) to match the previous ILIKE semantics.
2462 2463 2464 2465 |
# File 'app/models/item.rb', line 2462 def revision_sku_conditions ["sku = :canonical OR sku ~* :pattern", { canonical: canonical_sku, pattern: "^#{Regexp.escape(canonical_sku)}-[A-Za-z]$" }] end |
#revisions ⇒ ActiveRecord::Relation<Item>
All revisions of this publication, newest SKU first. A revision is the
canonical SKU plus a single-letter suffix (-A, -B) — locale variants like
-SPANISH-A / -FRENCH-A are NOT revisions (see #revision_sku_conditions).
2422 2423 2424 |
# File 'app/models/item.rb', line 2422 def revisions Item.publications.where(*revision_sku_conditions).order(sku: :desc) end |
#rma_reason_codes(include_advanced: true) ⇒ Object
Rma reason codes.
1181 1182 1183 1184 1185 1186 1187 |
# File 'app/models/item.rb', line 1181 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 # If we're not requesting advanced, then you only get the basic reason codes 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
799 800 801 |
# File 'app/models/item.rb', line 799 delegate :root_system_product_line, to: :primary_product_line, allow_nil: true |
#run_shipping_audit(carrier: nil) ⇒ Array<Shipping::PackageAuditor>
Run shipping audit for all boxes, optionally for a specific carrier
2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 |
# File 'app/models/item.rb', line 2366 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 ⇒ String?
Returns a name suitable for edit feed with any special character that will
destroy a csv formatting
1072 1073 1074 1075 1076 1077 1078 |
# File 'app/models/item.rb', line 1072 def safe_name return if name.blank? name.gsub("'", 'ft') .gsub('"', 'in') .gsub(%r{[^0-9A-Za-z.-/]}, ' ').squish end |
#sales_product_line_path ⇒ String?
Returns ltree path for sales product line (preferred - reuses already-loaded ProductLine)
3079 3080 3081 3082 3083 |
# File 'app/models/item.rb', line 3079 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
Sales product line slug.
3071 3072 3073 3074 3075 |
# File 'app/models/item.rb', line 3071 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 |
#secondary_product_category ⇒ ProductCategory?
The associated secondary product category.
281 |
# File 'app/models/item.rb', line 281 belongs_to :secondary_product_category, class_name: 'ProductCategory', optional: true |
#selection_name ⇒ Object
Selection name.
2531 2532 2533 |
# File 'app/models/item.rb', line 2531 def selection_name "#{sku} - #{name}#{' [Discontinued]' if is_discontinued?}" end |
#serial_numbers ⇒ ActiveRecord::Associations::CollectionProxy
The associated serial numbers.
384 |
# File 'app/models/item.rb', line 384 has_many :serial_numbers, through: :store_items |
#set_grouping(force: false) ⇒ void
This method returns an undefined value.
Records a grouping string identifier, this speeds up variant grouping lookup for
google and reviews.io api calls.
3185 3186 3187 3188 3189 3190 3191 |
# File 'app/models/item.rb', line 3185 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) ⇒ Hash
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
3429 3430 3431 |
# File 'app/models/item.rb', line 3429 def shift_images(locale: 'en', prefix: nil) Image::ImageShiftingService.shift_images_for_item(id, locale: locale, prefix: prefix) end |
#shipping_dimensions(unit: 'in', precision: 0) ⇒ Array<Float>?
unit_system SI = Standard International, e.g Metric
ucs = United States Customary Unit
2156 2157 2158 2159 2160 2161 2162 2163 2164 |
# File 'app/models/item.rb', line 2156 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
Shipping dimensions display.
1414 1415 1416 |
# File 'app/models/item.rb', line 1414 def shipping_dimensions_display "#{shipping_length}″ (L) x #{shipping_width}″ (W) x #{shipping_height}″ (H)" end |
#shipping_dimensions_to_package ⇒ Object
Shipping dimensions to package.
2336 2337 2338 2339 2340 2341 |
# File 'app/models/item.rb', line 2336 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
Shipping height converted.
2193 2194 2195 2196 2197 |
# File 'app/models/item.rb', line 2193 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
Shipping length converted.
2171 2172 2173 2174 2175 |
# File 'app/models/item.rb', line 2171 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::Associations::CollectionProxy
The associated shipping options.
351 |
# File 'app/models/item.rb', line 351 has_many :shipping_options |
#shipping_volume ⇒ Object
Shipping volume.
1378 1379 1380 1381 1382 |
# File 'app/models/item.rb', line 1378 def shipping_volume boxes.sum { |b| b[0] * b[1] * b[2] } rescue StandardError 0 end |
#shipping_volume_in_cubic_feet ⇒ Object
Shipping volume in cubic feet.
1387 1388 1389 1390 1391 |
# File 'app/models/item.rb', line 1387 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
Shipping weight converted.
2311 2312 2313 |
# File 'app/models/item.rb', line 2311 def shipping_weight_converted(unit: 'lbs', precision: nil) express_weight_converted shipping_weight, unit:, precision: end |
#shipping_width_converted(unit: 'in', precision: 0) ⇒ Object
Shipping width converted.
2182 2183 2184 2185 2186 |
# File 'app/models/item.rb', line 2182 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? ⇒ Object
Whether ships in single box.
3331 3332 3333 |
# File 'app/models/item.rb', line 3331 def ships_in_single_box? !(box2_defined? || box3_defined?) end |
#ships_via_crate? ⇒ Object
Whether ships via crate.
3233 3234 3235 |
# File 'app/models/item.rb', line 3233 def ships_via_crate? is_made_to_order_led_mirror? end |
#ships_via_freight? ⇒ Object
Whether ships via freight.
1986 1987 1988 1989 |
# File 'app/models/item.rb', line 1986 def ships_via_freight? # adding current pallet/freight shipping rules freight_service? end |
#siblings ⇒ Object
Siblings.
1227 1228 1229 1230 1231 |
# File 'app/models/item.rb', line 1227 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 ⇒ ActiveRecord::Relation<Packing>
Finds packings of this item but only for a single quantity
3222 3223 3224 3225 3226 3227 3228 |
# File 'app/models/item.rb', line 3222 def single_item_packings_from_md5 if (md5 = Shipping::Md5HashItem.process(self).md5) packings.where(md5:) else Packing.none end end |
#site_maps ⇒ ActiveRecord::Associations::CollectionProxy
The associated site maps.
378 |
# File 'app/models/item.rb', line 378 has_many :site_maps, as: :resource, dependent: :destroy |
#sku_and_name ⇒ Object
Sku and name.
1451 1452 1453 |
# File 'app/models/item.rb', line 1451 def sku_and_name "#{sku} - #{name}" end |
#source_item_relations ⇒ ActiveRecord::Associations::CollectionProxy
The associated source item relations.
354 |
# File 'app/models/item.rb', line 354 has_many :source_item_relations, class_name: 'ItemRelation', foreign_key: :target_item_id, dependent: :destroy |
#specific_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated specific items.
375 |
# File 'app/models/item.rb', line 375 has_many :specific_items, through: :item_relations, class_name: 'Item', source: :item |
#specific_publications ⇒ ActiveRecord::Associations::CollectionProxy
The associated specific publications.
372 |
# File 'app/models/item.rb', line 372 has_many :specific_publications, through: :publication_relations, class_name: 'Item', source: :publication |
#specifications ⇒ Array<OpenStruct>
Retrieves rendered specifications as an object
2705 2706 2707 |
# File 'app/models/item.rb', line 2705 def specifications rendered_product_specifications&.values&.map { |s| OpenStruct.new(s) } || [] end |
#specifications_for_item_label ⇒ Object
Specifications for item label.
2725 2726 2727 |
# File 'app/models/item.rb', line 2725 def specifications_for_item_label specifications.select { |rps| rps.print_on_item_label && rps.output.present? }.sort_by(&:name) end |
#specifications_grouped ⇒ Object
Specifications grouped.
2712 2713 2714 |
# File 'app/models/item.rb', line 2712 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
1081 1082 1083 |
# File 'app/models/item.rb', line 1081 def star? ( || []).intersect?(%w[Star star]) end |
#store_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated store items.
308 |
# File 'app/models/item.rb', line 308 has_many :store_items, inverse_of: :item, dependent: :destroy |
#successor_item ⇒ Item?
The associated successor item.
290 |
# File 'app/models/item.rb', line 290 belongs_to :successor_item, class_name: 'Item', optional: true |
#suggested_item_applies_to ⇒ Object
Alias for Suggested_item_tool#suggested_item_applies_to
803 804 805 |
# File 'app/models/item.rb', line 803 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
803 804 805 |
# File 'app/models/item.rb', line 803 delegate :suggested_item_stock_threshold, :suggested_item_applies_to, to: :suggested_item_tool |
#superceded_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated superceded items.
317 |
# File 'app/models/item.rb', line 317 has_many :superceded_items, class_name: 'Item', foreign_key: :successor_item_id |
#supplier_item ⇒ SupplierItem?
The associated supplier item.
260 |
# File 'app/models/item.rb', line 260 belongs_to :supplier_item, inverse_of: :items, optional: true |
#supplier_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated supplier items.
357 |
# File 'app/models/item.rb', line 357 has_many :supplier_items, inverse_of: :item, dependent: :destroy |
#supplier_skus ⇒ Object
Supplier skus.
1057 1058 1059 |
# File 'app/models/item.rb', line 1057 def supplier_skus ([secondary_model_number] + supplier_items.active.distinct.pluck(:supplier_sku)).filter_map(&:presence).uniq end |
#support_product_line_path ⇒ String?
Returns ltree path for support product line (preferred - reuses already-loaded ProductLine)
3096 3097 3098 3099 3100 |
# File 'app/models/item.rb', line 3096 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
Support product line slug.
3088 3089 3090 3091 3092 |
# File 'app/models/item.rb', line 3088 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 |
#tags_display ⇒ Object
Tags display.
816 817 818 |
# File 'app/models/item.rb', line 816 def .join(', ') end |
#target_item_relations ⇒ ActiveRecord::Associations::CollectionProxy
The associated target item relations.
360 |
# File 'app/models/item.rb', line 360 has_many :target_item_relations, class_name: 'ItemRelation', foreign_key: :source_item_id, dependent: :destroy |
#target_item_relations_for_specs ⇒ ActiveRecord::Associations::CollectionProxy
The associated target item relations for specs.
363 |
# File 'app/models/item.rb', line 363 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
Third party skus.
1065 1066 1067 |
# File 'app/models/item.rb', line 1065 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
Thumbnail url.
1502 1503 1504 |
# File 'app/models/item.rb', line 1502 def thumbnail_url(size: '30x30') image_url2(size:, thumbnail: true) end |
#to_liquid ⇒ Object
To liquid.
3420 3421 3422 |
# File 'app/models/item.rb', line 3420 def to_liquid Liquid::ItemDrop.new self end |
#to_packdims ⇒ Object
To packdims.
3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 |
# File 'app/models/item.rb', line 3196 def to_packdims # Organize our packdims, ceiling with decimal precision of 1, also min of 0.1, and sort to make sure that lengthxwidthxheight are in descending order for convention 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 # Weight gets an extra decimal precision swg = [shipping_weight.ceil(2), 0.01].max # we store an array of decimal 7,2. To prevent 0 which would cause a validation issue, the smallest packable weight will be 0.01 lbs (the weight of a standard envelope) 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 # Weight gets an extra decimal precision box2_swg = [box2_shipping_weight.ceil(2), 0.01].max # we store an array of decimal 7,2. To prevent 0 which would cause a validation issue, the smallest packable weight will be 0.01 lbs (the weight of a standard envelope) 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 # Weight gets an extra decimal precision box3_swg = [box3_shipping_weight.ceil(2), 0.01].max # we store an array of decimal 7,2. To prevent 0 which would cause a validation issue, the smallest packable weight will be 0.01 lbs (the weight of a standard envelope) packdims << [box3_sle, box3_swi, box3_she, box3_swg, Shipment::PACKDIM_CONTAINER_INTS[container_type]] end packdims end |
#to_s ⇒ Object
To s.
2522 2523 2524 2525 2526 |
# File 'app/models/item.rb', line 2522 def to_s s = "#{sku} - #{name}" s += ' (Discontinued)' if is_discontinued? s end |
#total_shipping_weight ⇒ Object
Total shipping weight.
3404 3405 3406 |
# File 'app/models/item.rb', line 3404 def total_shipping_weight boxes.sum { |b| b[3].to_f } end |
#total_shipping_weight_converted(unit: 'lbs', precision: nil) ⇒ Object
Total shipping weight converted.
2302 2303 2304 |
# File 'app/models/item.rb', line 2302 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
Total shipping weight of kit components.
3411 3412 3413 3414 3415 |
# File 'app/models/item.rb', line 3411 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::Associations::CollectionProxy
The associated translation key resources.
402 |
# File 'app/models/item.rb', line 402 has_many :translation_key_resources, as: :resource, dependent: :destroy |
#update_boxes_from_packages(packages) ⇒ Object
Update boxes from packages.
1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 |
# File 'app/models/item.rb', line 1344 def update_boxes_from_packages(packages) # use packages to populate and/or reset boxes 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) ⇒ Object
Update rendered product specifications.
2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 |
# File 'app/models/item.rb', line 2871 def update_rendered_product_specifications(user_id: nil, tokens: nil, locales: nil) return :skipped if new_record? || is_publication? locales ||= content_locales_to_render self.refresh_specs = false # prevent looping self.skip_item_calc = true # not needed # Render for each available locale, always include english locales.uniq.each do |locale| # If this item is not offered in the locale no need to generate this Mobility.with_locale(locale) do self.rendered_product_specifications = render_product_specifications(tokens:) end end self.rendered_product_specifications_at = Time.current # This makes sure we don't store bad translations that are not supposed to be there # this can yield unsavory results when rendering prune_unused_translations # If an updater_id is specified, we override the stamp res = :fail CurrentScope.with_user_id(user_id) do res = :success if save end if res == :success purge_edge_cache(include_product_line: false) # Async as well end res end |
#upload ⇒ Upload?
The associated upload.
263 |
# File 'app/models/item.rb', line 263 belongs_to :upload, optional: true |
#uploads ⇒ ActiveRecord::Associations::CollectionProxy
The associated uploads.
438 |
# File 'app/models/item.rb', line 438 has_and_belongs_to_many :uploads, dependent: :destroy |
#url_paths ⇒ Object
Url paths.
914 915 916 917 918 919 |
# File 'app/models/item.rb', line 914 def url_paths p = [] p += primary_product_line.url_paths p << sku p.compact end |
#variant_axis_tokens ⇒ Array<String>
The variant axes of this item's family (e.g. ["voltage", "size"]).
3139 3140 3141 |
# File 'app/models/item.rb', line 3139 def variant_axis_tokens variant_group&.axis_tokens || [] end |
#variant_group ⇒ VariantGroup?
The item's DEFAULT variant family (channel-agnostic). Reads the loaded
association when present so collection renders can preload
:variant_groups and stay N+1-free.
824 825 826 827 828 829 830 |
# File 'app/models/item.rb', line 824 def variant_group if variant_groups.loaded? variant_groups.detect { |group| group.parent_id.nil? && group.catalog_id.nil? } else variant_groups.merge(VariantGroup.defaults).first end end |
#variant_group_for(catalog = nil) ⇒ VariantGroup?
The variant family governing this item on a catalog: an explicit override
membership wins, otherwise the default family resolves the catalog
(inheriting the default's members when the override has none).
837 838 839 840 841 842 843 844 845 846 847 848 849 |
# File 'app/models/item.rb', line 837 def variant_group_for(catalog = nil) if catalog.present? catalog_id = catalog.respond_to?(:id) ? catalog.id : catalog.to_i explicit = if variant_groups.loaded? variant_groups.detect { |group| group.catalog_id == catalog_id && group.parent_id.present? } else variant_groups.where(catalog_id: catalog_id).where.not(parent_id: nil).first end return explicit if explicit end variant_group&.resolved_for(catalog) end |
#variant_group_members ⇒ ActiveRecord::Relation<VariantGroupMember>
Variant-family memberships: at most one DEFAULT family plus one override
per channel (model-validated). See VariantGroup for the inheritance rules.
320 |
# File 'app/models/item.rb', line 320 has_many :variant_group_members, dependent: :destroy |
#variant_groups ⇒ ActiveRecord::Associations::CollectionProxy
The associated variant groups.
323 |
# File 'app/models/item.rb', line 323 has_many :variant_groups, through: :variant_group_members |
#variant_sort_keys ⇒ Array<String>
The family's variant-picker sort order.
3145 3146 3147 |
# File 'app/models/item.rb', line 3145 def variant_sort_keys variant_group&.effective_sort_keys || [] end |
#variants(include_self: false) ⇒ ActiveRecord::Relation<Item>
A more strict version of relatives, we don't look at descendants, only exact matches
3039 3040 3041 |
# File 'app/models/item.rb', line 3039 def variants(include_self: false) item_grouping_info(include_self:)&.variants || Item.none end |
#versions_for_audit_trail(_params = {}) ⇒ Object
Versions for audit trail.
3437 3438 3439 3440 3441 3442 3443 3444 3445 |
# File 'app/models/item.rb', line 3437 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::Associations::CollectionProxy
The associated view product catalogs.
330 |
# File 'app/models/item.rb', line 330 has_many :view_product_catalogs |
#warm_cache(include_product_line: true) ⇒ void
This method returns an undefined value.
Finds the associated sitemap (url) end points of this item and its product line
Perform a cache warmup
2801 2802 2803 2804 2805 2806 2807 2808 |
# File 'app/models/item.rb', line 2801 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? ⇒ Object
Whether will be restricted for sales.
882 883 884 885 |
# File 'app/models/item.rb', line 882 def will_be_restricted_for_sales? restricted_for_sales || (product_category&.restricted_for_sales && primary_product_line&.restricted_for_sales) end |