Class: HeatingElementProductLineOption
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- HeatingElementProductLineOption
- Extended by:
- ActionView::Helpers::NumberHelper
- Includes:
- Models::Auditable
- Defined in:
- app/models/heating_element_product_line_option.rb
Overview
== Schema Information
Table name: heating_element_product_line_options
Database name: primary
id :integer not null, primary key
application_type :string(255)
environment :string(255)
ideal_cable_spacing :float
instant_quotable :boolean
is_public :boolean
membrane_recommended :boolean
membrane_type :string
priority :integer
require_cable_spacing :boolean
require_expansion_joint :boolean
underlayment_r_value :string(255)
underlayment_recommended :boolean
underlayment_type :string(255)
created_at :datetime not null
updated_at :datetime not null
creator_id :integer
floor_type_id :integer
product_line_id :integer
room_type_id :integer
store_id :integer
sub_floor_type_id :integer
updater_id :integer
Indexes
by_env_sid_rtid_ftid (environment,store_id,room_type_id,floor_type_id)
by_env_sid_sftid (environment,store_id,sub_floor_type_id)
by_ftid_plid_sftid (floor_type_id,product_line_id,sub_floor_type_id)
idx_floor_type_sub_floor_type_store (floor_type_id,sub_floor_type_id,store_id)
idx_is_public (is_public)
index_heating_element_product_line_options_on_creator_id (creator_id)
index_heating_element_product_line_options_on_instant_quotable (instant_quotable)
index_heating_element_product_line_options_on_store_id (store_id)
index_heating_element_product_line_options_on_updater_id (updater_id)
pl_id_mem_rec (product_line_id,membrane_recommended)
rt_id_sft_id_ft_id (room_type_id,sub_floor_type_id,floor_type_id)
sft_id_pl_id_mr (sub_floor_type_id,product_line_id,membrane_recommended)
Constant Summary collapse
- ENVIRONMENTS_HASH =
Environments hash.
{ 'Indoor' => { key: 'indoor', application_type: 'FH', base_product_line_url: 'floor-heating', default_room_type_seo_key: 'bathroom', default_floor_type_seo_key: 'tile-marble-or-stone' }, 'Outdoor' => { key: 'outdoor', application_type: 'SMRD', base_product_line_url: 'snow-melting', default_room_type_seo_key: 'driveway', default_floor_type_seo_key: 'asphalt' }, 'Countertop' => { key: 'countertop', application_type: 'CH', base_product_line_url: 'countertop-heater', default_room_type_seo_key: 'countertop', default_floor_type_seo_key: 'granite-countertop' }, 'Roof' => { key: 'roof', application_type: 'SMRD', base_product_line_url: 'roof-and-gutter-deicing', default_room_type_seo_key: 'roof', default_floor_type_seo_key: 'asphalt-shingle' }, 'Pipe' => { key: 'pipe', application_type: 'PIPE', base_product_line_url: 'pipe-freeze-protection', default_room_type_seo_key: 'pipe', default_floor_type_seo_key: 'pipe' }, 'Custom Mirror' => { key: 'custom-mirror', application_type: 'CUSTOM_MIRROR', base_product_line_url: 'led-mirror', default_room_type_seo_key: 'custom-mirror', default_floor_type_seo_key: 'custom-mirror' } }.freeze
- PUBLIC_ENVIRONMENTS =
Public environments.
%w[Indoor Outdoor].freeze
- PUBLIC_ENVIRONMENT_KEYS =
Keys used for public environment.
PUBLIC_ENVIRONMENTS.map { |e| ENVIRONMENTS_HASH[e][:key] }
- PUBLIC_ENVIRONMENTS_HASH =
Public environments hash.
ENVIRONMENTS_HASH.select { |k, _v| PUBLIC_ENVIRONMENTS.include?(k) }
- APPLICATION_TYPES =
["FH", "SM", "CH", "RD", "PIPE"]
ENVIRONMENTS_HASH.map { |_k, v| v[:application_type] }.uniq
- ENVIRONMENTS =
["Indoor", "Outdoor", "Countertop", "Roof", "Pipe"]
ENVIRONMENTS_HASH.map { |k, _v| k }
- DEFAULT_SUB_FLOOR_TYPE =
Default sub floor type.
'Unconfirmed/Other'.freeze
- PUBLIC_SUB_FLOOR_TYPE_KEYS =
Keys used for public sub floor type.
SubFloorType.active.by_name.map(&:seo_key)
- DEFAULT_FLOOR_TYPE_BY_ENVIRONMENT =
Default floor type by environment.
{ 'Indoor' => 'Tile, Marble or Stone', 'Outdoor' => 'Asphalt (new)', 'Countertop' => 'Granite countertop', 'Roof' => 'Asphalt shingle', 'Pipe' => 'Pipe', 'Custom Mirror' => 'Custom Mirror' }.freeze
- PUBLIC_FLOOR_TYPE_KEYS =
ENVIRONMENTS_HASH.map{|k,v| [k,FloorType.find_by(seo_key: v[:default_floor_type_seo_key])&.name]}.to_h
%w[asphalt existing-asphalt bamboo-floating bamboo-glued bamboo-nailed carpet-glued carpet concrete existing-concrete cork engineered-floating engineered-glued engineered-nailed unfinished-stamped-or-colored-concrete wood-glued wood-nailed heated-balcony heated-bench laminate-click-together-floating laminate-glued-together-floating laminate-nailed other paver resilients-vinyl-and-luxury-vinyl-tile-lvt tile-marble-or-stone].freeze
- UNDERLAYMENT_TYPES =
FloorType.active.by_environment(PUBLIC_ENVIRONMENTS).by_name.map{|f| f.seo_key}
['ThermalSheet'].freeze
- MEMBRANE_TYPES =
Recognised membrane types.
%w[Prodeso Ditra].freeze
- PRODUCT_LINE_BY_HEATING_SYSTEM_TYPE =
Product line by heating system type.
{ 'TempZone Flex Roll' => 'floor-heating-tempzone-flex-roll', 'TempZone Easy Mat' => 'floor-heating-tempzone-easy-mat', 'TempZone Cable' => 'floor-heating-tempzone-cable', 'TempZone Ruler Cable' => 'floor-heating-tempzone-ruler-cable', 'TempZone Thin Cable' => 'floor-heating-tempzone-thin-cable', 'Environ Flex Roll' => 'floor-heating-environ-flex-roll', 'Environ Easy Mat' => 'floor-heating-environ-easy-mat', 'Slab Heat Cable' => 'floor-heating-slab-heat-cable', 'Slab Heat Mat' => 'floor-heating-slab-heat-mat', 'Snow Melt Cable' => 'snow-melting-cable', 'Snow Melt Mat' => 'snow-melting-mat', 'Snow Melt PowerMat' => 'snowmelt-powermat', 'Snow Melt OmniMat' => 'snowmelt-omnimat', 'Snow Melt EcoMat' => 'snowmelt-ecomat' }.freeze
- LEGACY_PRODUCT_BY_HEATING_SYSTEM_TYPE =
Legacy product by heating system type.
{ 'TempZone Flex Roll' => 'TZ', 'TempZone Easy Mat' => 'TZEM', 'TempZone Cable' => 'TZC', 'TempZone Thin Cable' => 'TZTC', 'Environ Flex Roll' => 'EVFR', 'Environ Easy Mat' => 'EV2', 'Slab Heat Cable' => 'SHC', 'Slab Heat Mat' => 'SHM', 'Snow Melt Cable' => 'SMC', 'Snow Melt Mat' => 'SMM' }.freeze
- HEATING_SYSTEM_TYPE_BY_LEGACY_PRODUCT =
Heating system type by legacy product.
{ 'TZ' => 'TempZone Flex Roll', 'TZEM' => 'TempZone Easy Mat', 'TZC' => 'TempZone Cable', 'TZTC' => 'TempZone Thin Cable', 'EV2' => 'Environ Flex Roll', 'EVFR' => 'Environ Flex Roll', 'SMC' => 'Snow Melt Cable', 'SMM' => 'Snow Melt Mat', 'SHC' => 'Slab Heat Cable', 'SHM' => 'Slab Heat Mat' }.freeze
- CALLOUTS_BY_HEATING_SYSTEM =
Callouts by heating system.
{ 'TempZone Flex Roll' => ['Full coverage for any size space, such as kitchens, living rooms, or basements', 'Ideal for in-field flexibility', 'Single & twin conductor available', '15 watts per sq. ft., 1/8" thick'], 'TempZone Easy Mat' => ["Floor heating for specific larger areas 'blanket' coverage, such as a family room or bedroom", 'No-cut one piece, rectangular mat', '120 Volt / 240 Volt', '15 watts per sq. ft., 1/8" thick'], 'TempZone Cable' => ['At 3.75 inch spacing: 12 Watts per sq ft. (potentially a primary heat source)', 'At 5 inch spacing: 9 Watts per sq ft.', 'Ideal for in-field flexibility', 'Available in 120v or 240v systems', '3.7 Watts per linear ft'], 'TempZone Cable 3.75' => ['10-12 Watts per sq ft. (potentially a primary heat source)', 'Ideal for in-field flexibility', 'Available in 120v or 240v systems', '3.75 Watts per linear ft'], 'TempZone Cable 5' => ['8-9 Watts per sq ft.', 'Ideal for in-field flexibility', 'Available in 120v or 240v systems', '3.75 Watts per linear ft'], 'TempZone Ruler Cable' => ['At 3.75 inch spacing: 12 Watts per sq ft. (potentially a primary heat source)', 'At 5 inch spacing: 9 Watts per sq ft.', 'Ideal for in-field flexibility', 'Available in 120v or 240v systems', '3.7 Watts per linear ft'], 'TempZone Ruler Cable 3.75' => ['10-12 Watts per sq ft. (potentially a primary heat source)', 'Ideal for in-field flexibility', 'Available in 120v or 240v systems', '3.75 Watts per linear ft'], 'TempZone Ruler Cable 5' => ['8-9 Watts per sq ft.', 'Ideal for in-field flexibility', 'Available in 120v or 240v systems', '3.75 Watts per linear ft'], 'TempZone Thin Cable' => ['At 3 inch spacing: 12 Watts per sq ft. (potentially a primary heat source)', 'At 4 inch spacing: 9 Watts per sq ft.', 'Ideal for in-field flexibility', 'Available in 120v or 240v systems', '3 Watts per linear ft'], 'TempZone Thin Cable 3' => ['10-12 Watts per sq ft. (potentially a primary heat source)', 'Ideal for in-field flexibility', 'Available in 120v or 240v systems', '3 Watts per linear ft'], 'TempZone Thin Cable 4' => ['8-9 Watts per sq ft.', 'Ideal for in-field flexibility', 'Available in 120v or 240v systems', '3 Watts per linear ft'], 'Environ Flex Roll' => ['Ideal for in-field flexibility', 'Full coverage for any size space, commonly installed beneath carpet & laminate', '12 watts per sq. ft.'], 'Environ Easy Mat' => ["Floor heating for specific larger areas 'blanket' coverage, such as a family room", 'No-cut one piece', '12 watts per sq. ft.'], 'Snow Melt Cable' => ['Installs in asphalt, concrete, or under pavers in mortar', 'Perfect for driveways, patios, walkways and stairs', 'Available in 120V or 240V systems', 'Ultimate in flexible installation with free-form cable'], 'Snow Melt Mat' => ['Installs in asphalt, concrete, or under pavers in mortar', 'Perfect for driveways, patios, walkways and stairs', 'Available in 120V or 240V systems', 'Flexible installation with Flex Roll technology'], 'Slab Heat Cable' => ['Installs directly in concrete', 'Available in 120v or 240v systems', '6 Watts per lineal ft / 20 Watts per sq ft.', 'Ultimate in flexible installation with free-form cable'], 'Slab Heat Mat' => ['Installs directly in concrete', 'Available in 120v or 240v systems', '6 Watts per lineal ft / 20 Watts per sq ft.', 'Flexible installation with Flex Roll technology'] }.freeze
- CALLOUTS_BY_HEATING_SYSTEM_LIST =
Callouts by heating system list.
{ 'TempZone Flex Roll' => ['25 Year Warranty', '1/8" super-thin mat'], 'TempZone Easy Mat' => ['25 Year Warranty', '1/8" super-thin mat'], 'TempZone Shower Mat' => ['25 Year Warranty', '1/8" super-thin mat'], 'TempZone Custom Mat' => ['25 Year Warranty', '1/8" super-thin mat'], 'TempZone Cable' => ['25 Year Warranty', '3/16" robust cable'], 'TempZone Ruler Cable' => ['25 Year Warranty', '3/16" robust cable'], 'TempZone Thin Cable' => ['25 Year Warranty', '1/8" super-thin cable'], 'TempZone Thin Cable 3.0' => ['25 Year Warranty', '1/8" super-thin cable'], 'TempZone Cable 3.0' => ['25 Year Warranty', '3/16" robust cable'], # to support legacy 'TempZone Cable 3.5' => ['25 Year Warranty', '3/16" robust cable'], 'TempZone Cable 3.75' => ['25 Year Warranty', '3/16" robust cable'], 'TempZone Ruler Cable 3.0' => ['25 Year Warranty', '3/16" robust cable'], # to support legacy 'TempZone Ruler Cable 3.5' => ['25 Year Warranty', '3/16" robust cable'], 'TempZone Ruler Cable 3.75' => ['25 Year Warranty', '3/16" robust cable'], 'TempZone Thin Cable 3.5' => ['25 Year Warranty', '1/8" super-thin cable'], # to support legacy 'TempZone Thin Cable 3.75' => ['25 Year Warranty', '1/8" super-thin cable'], # to support legacy 'TempZone Thin Cable 4.0' => ['25 Year Warranty', '1/8" super-thin cable'], 'TempZone Cable 4.0' => ['25 Year Warranty', '3/16" robust cable'], # to support legacy 'TempZone Cable 4.75' => ['25 Year Warranty', '3/16" robust cable'], 'TempZone Cable 5.0' => ['25 Year Warranty', '3/16" robust cable'], 'TempZone Ruler Cable 4.0' => ['25 Year Warranty', '3/16" robust cable'], # to support legacy 'TempZone Ruler Cable 4.75' => ['25 Year Warranty', '3/16" robust cable'], 'TempZone Ruler Cable 5.0' => ['25 Year Warranty', '3/16" robust cable'], 'TempZone Thin Cable 4.75' => ['25 Year Warranty', '1/8" super-thin cable'], # to support legacy 'TempZone Thin Cable 5.0' => ['25 Year Warranty', '1/8" super-thin cable'], # to support legacy 'Environ Flex Roll' => ['10 Year Warranty under Laminate & Floating Hardwood, 5 Year under Carpet', '1/16" super-thin mat'], 'Environ Easy Mat' => ['10 Year Warranty under Laminate & Floating Hardwood, 5 Year under Carpet', '1/16" super-thin mat'], 'Snow Melt Cable' => ['10 Year Warranty', 'Energy efficient twin-conductor heating cable'], 'Snow Melt Mat' => ['10 Year Warranty', 'Energy efficient twin-conductor heating mat'], 'Slab Heat Cable' => ['10 Year Warranty', 'Energy efficient twin-conductor heating cable'], 'Slab Heat Mat' => ['10 Year Warranty', 'Energy efficient twin-conductor heating cable'] }.freeze
- WARRANTY_BY_HEATING_SYSTEM_LIST =
Warranty by heating system list.
{ 'TempZone Flex Roll' => '25 Years', 'TempZone Easy Mat' => '25 Years', 'TempZone Custom Mat' => '25 Years', 'TempZone Shower Mat' => '25 Years', 'TempZone Cable' => '25 Years', 'TempZone Ruler Cable' => '25 Years', 'TempZone Thin Cable' => '25 Years', 'TempZone Thin Cable 3.0' => '25 Years', 'TempZone Cable 3.0' => '25 Years', # to support legacy 'TempZone Cable 3.5' => '25 Years', 'TempZone Cable 3.75' => '25 Years', 'TempZone Thin Cable 3.5' => '25 Years', # to support legacy 'TempZone Thin Cable 3.75' => '25 Years', # to support legacy 'TempZone Thin Cable 4.0' => '25 Years', 'TempZone Cable 4.0' => '25 Years', # to support legacy 'TempZone Cable 4.75' => '25 Years', 'TempZone Cable 5.0' => '25 Years', 'TempZone Thin Cable 4.75' => '25 Years', # to support legacy 'TempZone Thin Cable 5.0' => '25 Years', # to support legacy 'Environ Flex Roll' => '10 Years under Laminate & Floating Hardwood, 5 Years under Carpet', 'Environ Easy Mat' => '10 Years under Laminate & Floating Hardwood, 5 Years under Carpet', 'Snow Melt Cable' => '10 Years', 'Snow Melt Mat' => '10 Years', 'Slab Heat Cable' => '10 Years', 'Slab Heat Mat' => '10 Years' }.freeze
- WATTS_PER_SQFT_BY_HEATING_SYSTEM_LIST =
Watts per sqft by heating system list.
{ 'TempZone Flex Roll' => '15', 'TempZone Easy Mat' => '15', 'TempZone Custom Mat' => '15', 'TempZone Shower Mat' => '15', 'TempZone Cable' => '10-12', 'TempZone Ruler Cable' => '10-12', 'TempZone Thin Cable' => '10-12', 'TempZone Thin Cable 3.0' => '10-12', 'TempZone Cable 3.0' => '12-15', # to support legacy 'TempZone Cable 3.5' => '11-14', 'TempZone Cable 3.75' => '10-12', 'TempZone Ruler Cable 3.0' => '12-15', # to support legacy 'TempZone Ruler Cable 3.5' => '11-14', 'TempZone Ruler Cable 3.75' => '10-12', 'TempZone Thin Cable 3.5' => '10-12', # to support legacy 'TempZone Thin Cable 3.75' => '9-11', # to support legacy 'TempZone Thin Cable 4.0' => '8-9', 'TempZone Cable 4.0' => '10-12', # to support legacy 'TempZone Cable 4.75' => '9-10', 'TempZone Cable 5.0' => '7-9', 'TempZone Ruler Cable 4.0' => '10-12', # to support legacy 'TempZone Ruler Cable 4.75' => '9-10', 'TempZone Ruler Cable 5.0' => '7-9', 'TempZone Thin Cable 4.75' => '7-9', # to support legacy 'TempZone Thin Cable 5.0' => '6-8', # to support legacy 'Environ Flex Roll' => '12', 'Environ Easy Mat' => '12', 'Snow Melt Cable' => '50', 'Snow Melt Mat' => '50', 'Slab Heat Cable' => '20', 'Slab Heat Mat' => '20' }.freeze
- PRICE_PER_SQFT_BY_HEATING_SYSTEM_LIST =
Price per sqft by heating system list.
{ 'TempZone Flex Roll' => '$10 - $12 per sq. ft.', 'TempZone Easy Mat' => '$10 - $12 per sq. ft.', 'TempZone Custom Mat' => '$15 - $30 per sq. ft.', 'TempZone Shower Mat' => '$15 - $20 per sq. ft.', 'TempZone Cable' => '$15 - $20 per sq. ft.', 'TempZone Ruler Cable' => '$15 - $20 per sq. ft.', 'TempZone Thin Cable' => '$8 - $10 per sq. ft.', 'TempZone Thin Cable 3.0' => '$8 - $10 per sq. ft.', 'TempZone Cable 3.0' => '$19 - $25 per sq. ft.', # to support legacy 'TempZone Cable 3.5' => '$16 - $22 per sq. ft.', 'TempZone Cable 3.75' => '$15 - $20 per sq. ft.', 'TempZone Ruler Cable 3.0' => '$19 - $25 per sq. ft.', # to support legacy 'TempZone Ruler Cable 3.5' => '$16 - $22 per sq. ft.', 'TempZone Ruler Cable 3.75' => '$15 - $20 per sq. ft.', 'TempZone Thin Cable 3.5' => '$7 - $10 per sq. ft.', # to support legacy 'TempZone Thin Cable 3.75' => '$6 - $8 per sq. ft.', # to support legacy 'TempZone Thin Cable 4.0' => '$6 - $8 per sq. ft.', 'TempZone Cable 4.0' => '$14 - $19 per sq. ft.', # to support legacy 'TempZone Cable 4.75' => '$13 - $18 per sq. ft.', 'TempZone Cable 5.0' => '$12 - $17 per sq. ft.', 'TempZone Ruler Cable 4.0' => '$14 - $19 per sq. ft.', # to support legacy 'TempZone Ruler Cable 4.75' => '$13 - $18 per sq. ft.', 'TempZone Ruler Cable 5.0' => '$12 - $17 per sq. ft.', 'TempZone Thin Cable 4.75' => '$5 - $7 per sq. ft.', # to support legacy 'TempZone Thin Cable 5.0' => '$5 - $7 per sq. ft.', # to support legacy 'Environ Flex Roll' => '$10 - $12 per sq. ft.', 'Environ Easy Mat' => '$10 - $12 per sq. ft.', 'Snow Melt Cable' => '$8 - $16 per sq. ft.', 'Snow Melt Mat' => '$10 - $20 per sq. ft.', 'Slab Heat Cable' => '$8 - $16 per sq. ft.', 'Slab Heat Mat' => '$10 - $20 per sq. ft.' }.freeze
- CABLE_SPACING_BY_HEATING_SYSTEM_LIST =
Cable spacing by heating system list.
{ 'TempZone Flex Roll' => '3.0', 'TempZone Easy Mat' => '3.0', 'TempZone Shower Mat' => '3.0', 'TempZone Custom Mat' => '3.0', 'TempZone Cable' => '3.0" to 5.0', 'TempZone Ruler Cable' => '3.0" to 5.0', 'TempZone Thin Cable' => '3.0" to 5.0', 'TempZone Thin Cable 3.0' => '3.0', 'TempZone Cable 3.0' => '3.0', # to support legacy 'TempZone Cable 3.5' => '3.5', 'TempZone Cable 3.75' => '3.75', 'TempZone Ruler Cable 3.0' => '3.0', # to support legacy 'TempZone Ruler Cable 3.5' => '3.5', 'TempZone Ruler Cable 3.75' => '3.75', 'TempZone Thin Cable 3.5' => '3.5', # to support legacy 'TempZone Thin Cable 3.75' => '3.75', # to support legacy 'TempZone Thin Cable 4.0' => '4.0', 'TempZone Cable 4.0' => '4.0', # to support legacy 'TempZone Cable 4.75' => '4.75', 'TempZone Cable 5.0' => '5.0', 'TempZone Ruler Cable 4.0' => '4.0', # to support legacy 'TempZone Ruler Cable 4.75' => '4.75', 'TempZone Ruler Cable 5.0' => '5.0', 'TempZone Thin Cable 4.75' => '4.75', # to support legacy 'TempZone Thin Cable 5.0' => '5.0', # to support legacy 'Environ Flex Roll' => '3.0', 'Environ Easy Mat' => '3.0', 'Snow Melt Cable' => '3.0', 'Snow Melt Mat' => '3.0', 'Slab Heat Cable' => '3.0', 'Slab Heat Mat' => '3.0' }.freeze
- INSTALLATION_BLURB_BY_HEATING_SYSTEM_LIST =
Installation blurb by heating system list.
{ 'TempZone Flex Roll' => 'Cut/Turn Installation', 'TempZone Easy Mat' => 'Spot Heat Placement', 'TempZone Shower Mat' => 'Spot Heat Placement', 'TempZone Custom Mat' => 'Spot Heat Placement', 'TempZone Cable' => 'Free-Form: Membrane or Fixing Strips', 'TempZone Ruler Cable' => 'Free-Form: Membrane or Fixing Strips', 'TempZone Thin Cable' => 'Free-Form Installation', 'TempZone Thin Cable 3.0' => 'Free-Form Installation', 'TempZone Cable 3.0' => 'Free-Form Installation', # to support legacy 'TempZone Cable 3.5' => 'Free-Form Installation', 'TempZone Cable 3.75' => 'Free-Form Installation', 'TempZone Ruler Cable 3.0' => 'Free-Form Installation', # to support legacy 'TempZone Ruler Cable 3.5' => 'Free-Form Installation', 'TempZone Ruler Cable 3.75' => 'Free-Form Installation', 'TempZone Thin Cable 3.5' => 'Free-Form Installation', # to support legacy 'TempZone Thin Cable 3.75' => 'Free-Form Installation', # to support legacy 'TempZone Thin Cable 4.0' => 'Free-Form Installation', 'TempZone Cable 4.0' => 'Free-Form Installation', # to support legacy 'TempZone Cable 4.75' => 'Free-Form Installation', 'TempZone Cable 5.0' => 'Free-Form Installation', 'TempZone Ruler Cable 4.0' => 'Free-Form Installation', # to support legacy 'TempZone Ruler Cable 4.75' => 'Free-Form Installation', 'TempZone Ruler Cable 5.0' => 'Free-Form Installation', 'TempZone Thin Cable 4.75' => 'Free-Form Installation', # to support legacy 'TempZone Thin Cable 5.0' => 'Free-Form Installation', # to support legacy 'Environ Flex Roll' => 'Cut/Turn Installation', 'Environ Easy Mat' => 'Spot Heat Placement', 'Snow Melt Cable' => 'Free-Form Installation', 'Snow Melt Mat' => 'Cut/Turn Installation', 'Slab Heat Cable' => 'Free-Form Installation', 'Slab Heat Mat' => 'Cut/Turn Installation' }.freeze
- INSTALLATION_LEVEL_BY_HEATING_SYSTEM_LIST =
Installation level by heating system list.
{ 'TempZone Flex Roll' => 'medium', 'TempZone Easy Mat' => 'easy', 'TempZone Shower Mat' => 'easy', 'TempZone Custom Mat' => 'easy', 'TempZone Cable' => 'easy', 'TempZone Ruler Cable' => 'easy', 'TempZone Thin Cable' => 'moderate', 'TempZone Cable 3.0' => 'moderate', # to support legacy 'TempZone Ruler Cable 3.0' => 'moderate', # to support legacy 'TempZone Thin Cable 3.0' => 'moderate', 'TempZone Cable 3.5' => 'easy', 'TempZone Cable 3.75' => 'easy', 'TempZone Ruler Cable 3.5' => 'easy', 'TempZone Ruler Cable 3.75' => 'easy', 'TempZone Thin Cable 3.5' => 'easy', # to support legacy 'TempZone Thin Cable 3.75' => 'easy', # to support legacy 'TempZone Cable 4.0' => 'moderate', # to support legacy 'TempZone Ruler Cable 4.0' => 'moderate', # to support legacy 'TempZone Thin Cable 4.0' => 'moderate', 'TempZone Cable 4.75' => 'easy', 'TempZone Cable 5.0' => 'easy', 'TempZone Ruler Cable 4.75' => 'easy', 'TempZone Ruler Cable 5.0' => 'easy', 'TempZone Thin Cable 4.75' => 'easy', # to support legacy 'TempZone Thin Cable 5.0' => 'easy', # to support legacy 'Environ Flex Roll' => 'medium', 'Environ Easy Mat' => 'easy', 'Snow Melt Cable' => 'moderate', 'Snow Melt Mat' => 'medium', 'Slab Heat Cable' => 'moderate', 'Slab Heat Mat' => 'medium' }.freeze
- FEATURES_BY_CONTROL_SKU_LIST =
Features by control sku list.
{ 'Indoor' => { 'Programmable' => { 'TH114-AF-GA' => false, 'TH115-AF-GA-08' => true, 'TH115-AF-12VDC' => true, 'UTN4-4999' => false, 'UTN5-4999' => false, 'UDG4-4999' => true, 'UDG4-4999-WY' => true, 'UDG4-4999-B' => true, 'UWG4-4999' => true, 'UWG5-4999-WY' => true, 'UWG4-4999-B' => true }, 'Built-In GFCI' => { 'TH114-AF-GA' => true, 'TH115-AF-GA-08' => true, 'TH115-AF-12VDC' => true, 'UTN4-4999' => true, 'UTN5-4999' => true, 'UDG4-4999' => true, 'UDG4-4999-WY' => true, 'UDG4-4999-B' => true, 'UWG4-4999' => true, 'UWG5-4999-WY' => true, 'UWG4-4999-B' => true }, 'Comes with floor sensor' => { 'TH114-AF-GA' => true, 'TH115-AF-GA-08' => true, 'TH115-AF-12VDC' => true, 'UTN4-4999' => true, 'UTN5-4999' => true, 'UDG4-4999' => true, 'UDG4-4999-WY' => true, 'UDG4-4999-B' => true, 'UWG4-4999' => true, 'UWG5-4999-WY' => true, 'UWG4-4999-B' => true }, 'Dual Voltage' => { 'TH114-AF-GA' => true, 'TH115-AF-GA-08' => true, 'TH115-AF-12VDC' => true, 'UTN4-4999' => true, 'UTN5-4999' => true, 'UDG4-4999' => true, 'UDG4-4999-WY' => true, 'UDG4-4999-B' => true, 'UWG4-4999' => true, 'UWG5-4999-WY' => true, 'UWG4-4999-B' => true }, 'Digital Temperature Readout' => { 'TH114-AF-GA' => true, 'TH115-AF-GA-08' => true, 'TH115-AF-12VDC' => true, 'UTN4-4999' => true, 'UTN5-4999' => true, 'UDG4-4999' => true, 'UDG4-4999-WY' => true, 'UWG5-4999-WY' => true, 'UDG4-4999-B' => true, 'UWG4-4999' => true, 'UWG4-4999-B' => true }, 'Touchscreen' => { 'TH114-AF-GA' => false, 'TH115-AF-GA-08' => false, 'TH115-AF-12VDC' => false, 'UTN4-4999' => false, 'UTN5-4999' => true, 'UDG4-4999' => true, 'UDG4-4999-WY' => true, 'UWG5-4999-WY' => true, 'UDG4-4999-B' => true, 'UWG4-4999' => true, 'UWG4-4999-B' => true }, 'Control via Phone/Web' => { 'TH114-AF-GA' => false, 'TH115-AF-GA-08' => false, 'TH115-AF-12VDC' => false, 'UTN4-4999' => false, 'UTN5-4999' => false, 'UDG4-4999' => false, 'UDG4-4999-WY' => false, 'UWG4-4999' => true, 'UWG5-4999-WY' => true, 'UWG4-4999-B' => true }, 'Maximum Load: 15 Amps' => { 'TH114-AF-GA' => true, 'TH115-AF-GA-08' => true, 'TH115-AF-12VDC' => true, 'UTN4-4999' => true, 'UTN5-4999' => true, 'UDG4-4999' => true, 'UDG4-4999-WY' => true, 'UDG4-4999-B' => true, 'UWG4-4999' => true, 'UWG5-4999-WY' => true, 'UWG4-4999-B' => true }, '3 Year Warranty' => { 'TH114-AF-GA' => true, 'TH115-AF-GA-08' => true, 'TH115-AF-12VDC' => true, 'UTN4-4999' => true, 'UTN5-4999' => true, 'UDG4-4999' => true, 'UDG4-4999-WY' => true, 'UDG4-4999-B' => true, 'UWG4-4999' => true, 'UWG5-4999-WY' => true, 'UWG4-4999-B' => true } }, 'Outdoor' => { 'Automatic' => { 'SCP-120' => true, 'SCA-DUAL' => true, 'SCE-120' => true, 'SCV-DUAL' => true, 'SCM-120' => false }, 'Outdoor Rated' => { 'SCP-120' => true, 'SCA-DUAL' => true, 'SCE-120' => false, 'SCV-DUAL' => true, 'SCM-120' => false }, 'Moisture Sensor' => { 'SCP-120' => true, 'SCA-DUAL' => true, 'SCE-120' => true, 'SCV-DUAL' => true, 'SCM-120' => false }, 'Air Temp Sensor' => { 'SCP-120' => true, 'SCA-DUAL' => true, 'SCE-120' => true, 'SCV-DUAL' => true, 'SCM-120' => false }, 'Slab Temp Sensor' => { 'SCP-120' => true, 'SCA-DUAL' => false, 'SCE-120' => true, 'SCV-DUAL' => false, 'SCM-120' => false }, 'Digital Temp Readout' => { 'SCP-120' => false, 'SCA-DUAL' => false, 'SCE-120' => true, 'SCV-DUAL' => false, 'SCM-120' => false }, 'Adjust After-Run Time' => { 'SCP-120' => true, 'SCA-DUAL' => true, 'SCE-120' => true, 'SCV-DUAL' => true, 'SCM-120' => false }, 'Reliable Manual Control' => { 'SCM-120' => true }, 'Timer Adjustable Up To 12 Hours' => { 'SCM-120' => true }, 'Remote Control via Smart Device' => { 'SCW-120' => true }, 'Works with IFTTT Service' => { 'SCW-120' => true }, 'On/Off Switch for Manual Operation' => { 'SCW-120' => true }, '2 Year Warranty' => { 'SCP-120' => true, 'SCA-DUAL' => true, 'SCE-120' => true, 'SCV-DUAL' => true, 'SCM-120' => true, 'SCW-120' => true } } }.freeze
- IQ_PRODUCT_HEADER_IMAGE_URL_BY_HEATING_SYSTEM_LIST =
Iq product header image url by heating system list.
{ 'TempZone Flex Roll' => 'https://ik.warmlyyours.com/img/tempzone-flex-roll-cable-c16e8f.png?tr=w-400,h-400,cm-pad_resize,bg-FFFFFF', 'TempZone Easy Mat' => 'https://ik.warmlyyours.com/img/iq-tempzone-easy-mat-thumbnail-b412fa.jpeg?tr=w-400,h-400,cm-pad_resize,bg-FFFFFF', 'TempZone Shower Mat' => 'https://ik.warmlyyours.com/img/iq-tempzone-shower-mat-f0bfbc.png?tr=w-400,h-400,cm-pad_resize,bg-FFFFFF', 'TempZone Cable' => 'https://ik.warmlyyours.com/img/tempzone-cable-with-grip-strips-qcungu?tr=w-400,h-400,cm-pad_resize,bg-FFFFFF', 'TempZone Ruler Cable' => 'https://ik.warmlyyours.com/img/iq-tempzone-ruler-cable-with-grip-strips-vmswnq.jpeg?tr=w-400,h-400,cm-pad_resize,bg-FFFFFF', 'TempZone Thin Cable' => 'https://ik.warmlyyours.com/img/tempzone-cable-with-grip-strips-qcungu?tr=w-400,h-400,cm-pad_resize,bg-FFFFFF', 'Environ Flex Roll' => 'https://ik.warmlyyours.com/img/iq-environ-flex-roll-thumbnail-c253e0.png?tr=w-400,h-400,cm-pad_resize,bg-FFFFFF', 'Environ Easy Mat' => 'https://ik.warmlyyours.com/img/iq-environ-easy-mat-thumbnail-b8b7eb.png?tr=w-400,h-400,cm-pad_resize,bg-FFFFFF', 'Snow Melt Cable' => 'https://ik.warmlyyours.com/img/iq-snow-melt-cable-thumbnail-2ff059.png?tr=w-400,h-400,cm-pad_resize,bg-FFFFFF', 'Snow Melt Mat' => 'https://ik.warmlyyours.com/img/iq-snow-melting-mat-thumbnail-a0e07c.png?tr=w-400,h-400,cm-pad_resize,bg-FFFFFF', 'Slab Heat Cable' => 'https://ik.warmlyyours.com/img/iq-slab-heating-cable-thumbnail-aa33fe.png?tr=w-400,h-400,cm-pad_resize,bg-FFFFFF', 'Slab Heat Mat' => 'https://ik.warmlyyours.com/img/iq-slab-heating-mat-b130ec.png?tr=w-400,h-400,cm-pad_resize,bg-FFFFFF' }.freeze
- IQ_PRODUCT_DESCRIPTION_BY_HEATING_SYSTEM_LIST =
Iq product description by heating system list.
{ 'TempZone Flex Roll' => 'Cut-and-Turn Format for Easy Installation', 'TempZone Easy Mat' => 'Targeted Heat Coverage for Small Areas', 'TempZone Shower Mat' => 'Targeted Heat Coverage for Shower Areas', 'TempZone Thin Cable 3.0' => 'Maximum Flexibility at a Minimal Cost', 'TempZone Cable 3.0' => 'Maximum Flexibility at a Minimal Cost', # to support legacy 'TempZone Cable 3.5' => 'Maximum Flexibility with Easy Installation', 'TempZone Cable 3.75' => 'Maximum Flexibility with Easy Installation', 'TempZone Ruler Cable 3.0' => 'Maximum Flexibility at a Minimal Cost', # to support legacy 'TempZone Ruler Cable 3.5' => 'Maximum Flexibility with Easy Installation', 'TempZone Ruler Cable 3.75' => 'Maximum Flexibility with Easy Installation', 'TempZone Thin Cable 3.5' => 'Maximum Flexibility with Easy Installation', # to support legacy 'TempZone Thin Cable 3.75' => 'Maximum Flexibility with Easy Installation', # to support legacy 'TempZone Thin Cable 4.0' => 'Maximum Flexibility at a Minimal Cost', 'TempZone Cable 4.0' => 'Maximum Flexibility at a Minimal Cost', # to support legacy 'TempZone Cable 4.75' => 'Maximum Flexibility with Easy Installation', 'TempZone Cable 5.0' => 'Maximum Flexibility with Easy Installation', 'TempZone Ruler Cable 4.0' => 'Maximum Flexibility at a Minimal Cost', # to support legacy 'TempZone Ruler Cable 4.75' => 'Maximum Flexibility with Easy Installation', 'TempZone Ruler Cable 5.0' => 'Maximum Flexibility with Easy Installation', 'TempZone Thin Cable 4.75' => 'Maximum Flexibility with Easy Installation', # to support legacy 'TempZone Thin Cable 5.0' => 'Maximum Flexibility with Easy Installation', # to support legacy 'Environ Flex Roll' => 'Cut/Turn Installation for Maximum Flexibility', 'Environ Easy Mat' => 'Easy & Quick Installation in Large Spaces', 'Snow Melt Cable' => 'Maximum Flexibility at a Minimal Cost', 'Snow Melt Mat' => 'Cut-and-Turn Format for Easy Installation', 'Slab Heat Cable' => 'Maximum Flexibility at a Minimal Cost', 'Slab Heat Mat' => 'Cut-and-Turn Format for Easy Installation' }.freeze
- IQ_IMAGE_NAMES_BY_HEATING_SYSTEM =
Iq image names by heating system.
{ 'TempZone Flex Roll' => 'tempzone.png', 'TempZone Easy Mat' => 'tempzone.png', 'TempZone Shower Mat' => 'tempzone.png', 'TempZone Cable' => 'tempzone.png', 'TempZone Ruler Cable' => 'tempzone.png', 'TempZone Thin Cable' => 'tempzone.png', 'Environ Flex Roll' => 'environ.png', 'Environ Easy Mat' => 'environ.png', 'Snow Melt Cable' => 'snow-melt-cable.png', 'Snow Melt Mat' => 'snow-melt-mat.png', 'Slab Heat Cable' => 'slab-cable.png', 'Slab Heat Mat' => 'slab-mat.png' }.freeze
- DEFAULT_EXPANSION_JOINT_SPACING =
Default expansion joint spacing.
20- CABLE_SPACING_EXTRA_COPY =
Cable spacing extra copy.
{ '3.0' => '(fixing strips)', '3.5' => '(DITRA-HEAT)', '3.75' => '(Prodeso)', '4.0' => '(fixing strips)', '4.75' => '(DITRA-HEAT)', '5.0' => '(fixing strips/Prodeso)' }.freeze
- COLDEST_MONTH_AVE_TEMP_THRESHOLD =
Threshold for coldest month ave temp.
40.0
Constants included from Models::Auditable
Models::Auditable::ALWAYS_IGNORED
Constants included from Models::Schedulable
Models::Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
- #priority ⇒ Object readonly
Belongs to collapse
- #floor_type ⇒ FloorType
- #product_line ⇒ ProductLine
- #room_type ⇒ RoomType
- #store ⇒ Store
- #sub_floor_type ⇒ SubFloorType
Methods included from Models::Auditable
Delegated Instance Attributes collapse
-
#heating_system_type_name ⇒ Object
Alias for Product_line#heating_system_type_name.
-
#product_line_is_heating_system_type ⇒ Object
Alias for Product_line#is_heating_system_type.
Class Method Summary collapse
- .application_type_select_options ⇒ Object
- .cable_spacing_for_select(cs_options = {}) ⇒ Object
- .compact_priorities ⇒ Object
-
.const_missing(name) ⇒ Object
Keep constant for backward compatibility, but delegate to method.
- .default_cable_spacings(installation_postal_code = nil, sub_floor_type = nil, _floor_type = nil) ⇒ Object
-
.default_room_type_by_environment ⇒ Object
Lazily load room type mappings to avoid N+1 queries at class load time.
- .environment_select_options ⇒ Object
- .get_default_floor_type_id_for_environment(env) ⇒ Object
- .get_default_product_line_by_heating_system_type(system) ⇒ Object
- .get_default_room_type_id_for_environment(env) ⇒ Object
- .get_default_room_type_key_for_environment(env) ⇒ Object
- .get_default_subfloor_type_id ⇒ Object
-
.get_field_array_from_options(assoc_sym, options = {}) ⇒ Array
Returns the distinct values of a field or association matching the filters.
- .get_product_line_for_room(rc) ⇒ Object
- .get_product_line_from_heating_system_type_code(code) ⇒ Object
- .get_product_line_from_heating_system_type_name(name) ⇒ Object
- .get_relay_panels_from_poles(poles) ⇒ Object
-
.get_suggested_underlayments(options) ⇒ Hash
Returns suggested underlayment items for the given room characteristics.
- .get_suggested_underlayments_for_room(rc) ⇒ Object
- .ideal_cable_spacing_select_options ⇒ Object
-
.instant_quotable_environments ⇒ Object
Cached list of environments that support instant quoting.
- .membrane_type_select_options ⇒ Object
- .next_priority ⇒ Object
-
.options_for_select(assoc_sym, assoc_sort_field = 'name', assoc_name_method = 'name', options = {}, include_blank = false, assoc_key = 'id') ⇒ Array
Returns values of an association for use in a select list.
-
.options_scope(options = {}) ⇒ ActiveRecord::Relation
Returns a scope filtered by the given attribute values.
-
.populate_options ⇒ Object
DEPRECATED USED ONLY FOR MIGRATION.
-
.prioritized ⇒ ActiveRecord::Relation<HeatingElementProductLineOption>
A relation of HeatingElementProductLineOptions that are prioritized.
- .product_line_is_iq_supported?(pl) ⇒ Boolean
- .product_line_options_for_select ⇒ Object
- .public_environment_select_options ⇒ Object
- .public_room_type_keys ⇒ Object
-
.readable_order ⇒ ActiveRecord::Relation<HeatingElementProductLineOption>
A relation of HeatingElementProductLineOptions that are readable order.
-
.reset_cached_constants! ⇒ Object
Keep constant for backward compatibility.
- .shc_cable_spacing_for_select(cs_options = {}) ⇒ Object
- .smc_cable_spacing_for_select(cs_options = {}) ⇒ Object
- .spacing_to_unit(spacing_in_inches, unit = 'in') ⇒ Object
- .tz_cable_spacing_for_select(cs_options = {}) ⇒ Object
-
.tz_cable_watts_per_sqft(cs, options) ⇒ BigDecimal?
cs = cable spacing, decimal in inch.
- .underlayment_type_select_options ⇒ Object
-
.valid_membrane_types ⇒ Object
Cached list of valid membrane types to avoid expensive DISTINCT queries on every request.
- .voltage_options_for_select(heating_system_product_line, include_24 = false, environment = nil, use_smc_voltages = nil) ⇒ Object
Instance Method Summary collapse
Methods included from Models::Auditable
#all_skipped_columns, #audit_reference_data, #should_not_save_version, #stamp_record
Methods inherited from ApplicationRecord
ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation
Methods included from Models::Schedulable
Methods included from Models::AfterCommittable
Methods included from Models::EventPublishable
Instance Attribute Details
#priority ⇒ Object (readonly)
59 |
# File 'app/models/heating_element_product_line_option.rb', line 59 validates :priority, :product_line, :floor_type, presence: true |
Class Method Details
.application_type_select_options ⇒ Object
803 804 805 |
# File 'app/models/heating_element_product_line_option.rb', line 803 def self. APPLICATION_TYPES.map { |o| o } end |
.cable_spacing_for_select(cs_options = {}) ⇒ Object
846 847 848 849 |
# File 'app/models/heating_element_product_line_option.rb', line 846 def self.cable_spacing_for_select( = {}) = { unit: 'in' }.merge() tz_cable_spacing_for_select() + shc_cable_spacing_for_select() + smc_cable_spacing_for_select() end |
.compact_priorities ⇒ Object
1239 1240 1241 1242 1243 |
# File 'app/models/heating_element_product_line_option.rb', line 1239 def self.compact_priorities HeatingElementProductLineOption.readable_order.each_with_index do |heplo, i| heplo.update_attribute!(:priority, i) end end |
.const_missing(name) ⇒ Object
Keep constant for backward compatibility, but delegate to method
98 99 100 101 102 103 104 |
# File 'app/models/heating_element_product_line_option.rb', line 98 def self.const_missing(name) if name == :DEFAULT_ROOM_TYPE_BY_ENVIRONMENT default_room_type_by_environment else super end end |
.default_cable_spacings(installation_postal_code = nil, sub_floor_type = nil, _floor_type = nil) ⇒ Object
864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 |
# File 'app/models/heating_element_product_line_option.rb', line 864 def self.default_cable_spacings(installation_postal_code = nil, sub_floor_type = nil, _floor_type = nil) cable_spacings = if sub_floor_type [3.75, 4.0] # these are the default starting TZ cable spacings calculated for the IQ, first is with membrane, second is without else [4.0, 3.0] # these are the default starting SM cable spacings calculated for the IQ, first is default, second is to compete with lower wattage systems out there end if installation_postal_code && sub_floor_type && (avg_temp = AverageMonthlyTemperature.get_from_postal_code(installation_postal_code)) coldest_month_ave_temp = avg_temp[:average_temperatures]&.min if coldest_month_ave_temp && (coldest_month_ave_temp >= COLDEST_MONTH_AVE_TEMP_THRESHOLD) && (sub_floor_type&.seo_key == 'wood') # 4 " spacing for wood subfloors in these zones cable_spacings = [3.75, 4.0] # these are the default starting TZ cable spacings calculated for the IQ, first is with membrane, second is without end end cable_spacings end |
.default_room_type_by_environment ⇒ Object
Lazily load room type mappings to avoid N+1 queries at class load time
89 90 91 92 93 94 95 |
# File 'app/models/heating_element_product_line_option.rb', line 89 def self.default_room_type_by_environment @default_room_type_by_environment ||= begin seo_keys = ENVIRONMENTS_HASH.values.pluck(:default_room_type_seo_key) room_types_by_key = RoomType.where(seo_key: seo_keys).index_by(&:seo_key) ENVIRONMENTS_HASH.transform_values { |v| room_types_by_key[v[:default_room_type_seo_key]]&.name } end end |
.environment_select_options ⇒ Object
807 808 809 |
# File 'app/models/heating_element_product_line_option.rb', line 807 def self. ENVIRONMENTS end |
.get_default_floor_type_id_for_environment(env) ⇒ Object
792 793 794 |
# File 'app/models/heating_element_product_line_option.rb', line 792 def self.get_default_floor_type_id_for_environment(env) FloorType.find_by(name: DEFAULT_FLOOR_TYPE_BY_ENVIRONMENT[env]).id end |
.get_default_product_line_by_heating_system_type(system) ⇒ Object
796 797 798 799 800 801 |
# File 'app/models/heating_element_product_line_option.rb', line 796 def self.get_default_product_line_by_heating_system_type(system) pl = nil url = PRODUCT_LINE_BY_HEATING_SYSTEM_TYPE[system] pl = ProductLine.find_by(slug_ltree: LtreePaths.slug_ltree_from_legacy_hyphen_url(url))&.id if url pl end |
.get_default_room_type_id_for_environment(env) ⇒ Object
780 781 782 |
# File 'app/models/heating_element_product_line_option.rb', line 780 def self.get_default_room_type_id_for_environment(env) RoomType.find_by(name: DEFAULT_ROOM_TYPE_BY_ENVIRONMENT[env]).id end |
.get_default_room_type_key_for_environment(env) ⇒ Object
784 785 786 |
# File 'app/models/heating_element_product_line_option.rb', line 784 def self.get_default_room_type_key_for_environment(env) RoomType.find_by(name: DEFAULT_ROOM_TYPE_BY_ENVIRONMENT[env]).seo_key end |
.get_default_subfloor_type_id ⇒ Object
788 789 790 |
# File 'app/models/heating_element_product_line_option.rb', line 788 def self.get_default_subfloor_type_id SubFloorType.find_by(name: DEFAULT_SUB_FLOOR_TYPE).id end |
.get_field_array_from_options(assoc_sym, options = {}) ⇒ Array
Returns the distinct values of a field or association matching the filters.
977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 |
# File 'app/models/heating_element_product_line_option.rb', line 977 def self.(assoc_sym, = {}) # Check if this is a direct field on the model or an association is_direct_field = column_names.exclude?("#{assoc_sym}_id") # Build the base query with filters and prioritized ordering # The .prioritized scope is important because callers often use .first to get the highest-priority value base_query = HeatingElementProductLineOption.joins(:product_line).prioritized .each do |k, v| base_query = base_query.where(k => v) unless k == assoc_sym || v.nil? end if is_direct_field # For direct fields (like :environment, :ideal_cable_spacing), pluck and get unique values # We can't use DISTINCT with ORDER BY on non-selected columns, so we pluck and uniq in Ruby base_query.pluck(assoc_sym).uniq else # For associations, get distinct foreign key values base_query.pluck("#{assoc_sym}_id").uniq end end |
.get_product_line_for_room(rc) ⇒ Object
1027 1028 1029 1030 1031 1032 1033 1034 |
# File 'app/models/heating_element_product_line_option.rb', line 1027 def self.get_product_line_for_room(rc) res = nil opt = HeatingElementProductLineOption.where(floor_type_id: rc.floor_type_id) opt = opt.where(sub_floor_type_id: rc.sub_floor_type_id) if rc.sub_floor_type_id opt = opt.prioritized.first res = opt.product_line if opt res end |
.get_product_line_from_heating_system_type_code(code) ⇒ Object
1019 1020 1021 1022 1023 1024 1025 |
# File 'app/models/heating_element_product_line_option.rb', line 1019 def self.get_product_line_from_heating_system_type_code(code) pl = nil name = HEATING_SYSTEM_TYPE_BY_LEGACY_PRODUCT[code] pl_id = get_default_product_line_by_heating_system_type(name) pl = ProductLine.find(pl_id) if pl_id.present? pl end |
.get_product_line_from_heating_system_type_name(name) ⇒ Object
1012 1013 1014 1015 1016 1017 |
# File 'app/models/heating_element_product_line_option.rb', line 1012 def self.get_product_line_from_heating_system_type_name(name) pl = nil pl_id = get_default_product_line_by_heating_system_type(name) pl = ProductLine.find(pl_id) if pl_id.present? pl end |
.get_relay_panels_from_poles(poles) ⇒ Object
1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 |
# File 'app/models/heating_element_product_line_option.rb', line 1187 def self.get_relay_panels_from_poles(poles) # get proper relay panels based on number of poles relay_panels_sku_qty = {} relay_panels_sku_qty['RLY-4PL-CC'] = 0 relay_panels_sku_qty['RLY-8PL-CC'] = 0 relay_panels_sku_qty['RLY-12PL-CC'] = 0 return relay_panels_sku_qty unless poles > 0 if poles <= 4 relay_panels_sku_qty['RLY-4PL-CC'] = 1 elsif poles <= 8 relay_panels_sku_qty['RLY-8PL-CC'] = 1 elsif poles <= 12 relay_panels_sku_qty['RLY-12PL-CC'] = 1 elsif poles <= 16 relay_panels_sku_qty['RLY-8PL-CC'] = 2 elsif poles > 16 relay_panels_sku_qty = {} qty_4 = 0 qty_8 = 0 qty_12 = if (poles % 12) > 8 (poles / 12).ceil else (poles / 12).floor end poles_left = poles - (12 * qty_12) if poles_left > 4 qty_8 = if (poles_left % 8) > 4 (poles_left / 8).ceil else (poles_left / 8).floor end poles_left -= (8 * qty_8) end qty_4 = (poles_left / 4).ceil if poles_left > 0 relay_panels_sku_qty['RLY-12PL-CC'] = qty_12 if qty_12 > 0 relay_panels_sku_qty['RLY-8PL-CC'] = qty_8 if qty_8 > 0 relay_panels_sku_qty['RLY-4PL-CC'] = qty_4 if qty_4 > 0 end relay_panels_sku_qty end |
.get_suggested_underlayments(options) ⇒ Hash
Returns suggested underlayment items for the given room characteristics.
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 |
# File 'app/models/heating_element_product_line_option.rb', line 1054 def self.get_suggested_underlayments() logger.debug("get_suggested_underlayments, options: #{.inspect}") # No insulation surface means no underlayment to suggest — not an error. # Raising here took down every caller's page render: #select_underlayment # runs inside _main_tab.html.erb, so one room with a non-positive # insulation_surface 500'd the whole tab (AppSignal #3640, #44). The # HeatedArea backfill only covers rows whose heated_area_sqft is positive; # a 0.0 heated area still derives 1.2 * 0.0. Every caller iterates the # returned hash, so an empty one degrades to "no suggestions". # to_f, not to_i: AccessoriesFinder passes a float insulation_surface, and # Membrane passes a fractional deficit. to_i truncates 0.5 to 0 and would # silently suppress suggestions for a real, if small, surface. return {} unless [:sqft].to_f.positive? u_lines = {} add_one_extra = [:add_one_extra] add_one_extra = false if add_one_extra.nil? [:product_line_id] ||= HeatingElementProductLineOption.get_product_line_from_heating_system_type_name([:heating_system_type_name]) if [:heating_system_type_name] opt = HeatingElementProductLineOption.all opt = opt.where(floor_type_id: [:floor_type_id]) if [:floor_type_id].present? opt = opt.where(product_line_id: [:product_line_id]) if [:product_line_id].present? opt = opt.where(sub_floor_type_id: [:sub_floor_type_id]) if [:sub_floor_type_id].present? opt = opt.where(ideal_cable_spacing: [:ideal_cable_spacing]) if [:ideal_cable_spacing].present? opt = opt.where(membrane_recommended: [:membrane_recommended]) unless [:membrane_recommended].nil? # keep .nil? for boolean - false is a valid value opt = opt.prioritized.first add_thermalsheet = opt&.underlayment_recommended && opt.underlayment_type == 'ThermalSheet' add_prodeso = opt&.membrane_recommended && opt.membrane_type.index('Prodeso') if add_thermalsheet && (thermalsheet_item = Item.find_by(sku: ItemConstants::THERMALSHEET_SHEET_SKU)) thermalsheet_units = thermalsheet_item.get_quantity_from_sqft([:sqft], add_one_extra) if thermalsheet_units > 0 u_lines[thermalsheet_item.sku] = { quantity: thermalsheet_units, name: thermalsheet_item.name, detailed_description: thermalsheet_item.detailed_description, item_id: thermalsheet_item.id } end end if add_prodeso # Calculate Prodeso membrane quantities - compare rolls-only vs sheets-only, pick cheaper # Rule: never mix rolls and sheets, use whichever option is more cost-effective catalog_id = [:catalog_id] || 1 area_sqft = [:sqft].to_f prodeso_items = Item.membranes.includes(:catalog_items).index_by(&:sku) # Calculate sheets-only cost (use 10.8 sqft sheets) sheet_item = prodeso_items[ItemConstants::MEMBRANE_SHEET_SKU] sheet_sqft = sheet_item&.sqft || 10.8 sheet_price = sheet_item&.catalog_items&.find { |ci| ci.catalog_id == catalog_id }&.amount || 59.0 sheets_needed = (area_sqft / sheet_sqft).ceil sheets_cost = sheets_needed * sheet_price # Calculate rolls-only cost (use 54 and/or 162 sqft rolls) roll_54 = prodeso_items[ItemConstants::MEMBRANE_SMALL_SKU] roll_162 = prodeso_items[ItemConstants::MEMBRANE_LARGE_SKU] roll_54_sqft = roll_54&.sqft || 54.0 roll_162_sqft = roll_162&.sqft || 162.0 roll_54_price = roll_54&.catalog_items&.find { |ci| ci.catalog_id == catalog_id }&.amount || 209.0 roll_162_price = roll_162&.catalog_items&.find { |ci| ci.catalog_id == catalog_id }&.amount || 509.0 # Find optimal roll combination using cost optimization # Try different combinations and pick the cheapest best_rolls_qty = nil best_rolls_cost = Float::INFINITY # Helper: ceiling that's forgiving of tiny remainders (< 1 sqft gap is acceptable) forgiving_ceil = lambda { |area, unit_sqft| ratio = area / unit_sqft (ratio - ratio.floor) < 0.02 ? ratio.floor.to_i : ratio.ceil.to_i } # Option 1: Use only 54 sqft rolls qty_54_only = [forgiving_ceil.call(area_sqft, roll_54_sqft), 1].max cost_54_only = qty_54_only * roll_54_price if cost_54_only < best_rolls_cost best_rolls_cost = cost_54_only best_rolls_qty = { ItemConstants::MEMBRANE_SMALL_SKU => qty_54_only } end # Option 2: Use 162 sqft rolls + 54 sqft rolls for remainder if area_sqft > roll_54_sqft qty_162 = (area_sqft / roll_162_sqft).floor remainder = area_sqft - (qty_162 * roll_162_sqft) qty_54 = remainder > 0 ? forgiving_ceil.call(remainder, roll_54_sqft) : 0 cost_mixed = (qty_162 * roll_162_price) + (qty_54 * roll_54_price) if cost_mixed < best_rolls_cost best_rolls_cost = cost_mixed best_rolls_qty = {} best_rolls_qty[ItemConstants::MEMBRANE_LARGE_SKU] = qty_162 if qty_162.positive? best_rolls_qty[ItemConstants::MEMBRANE_SMALL_SKU] = qty_54 if qty_54.positive? end # Option 3: Round up to one more 162 roll (might be cheaper than multiple 54s) qty_162_rounded = forgiving_ceil.call(area_sqft, roll_162_sqft) cost_162_only = qty_162_rounded * roll_162_price best_rolls_qty = { ItemConstants::MEMBRANE_LARGE_SKU => qty_162_rounded } if cost_162_only < best_rolls_cost end rolls_qty = best_rolls_qty rolls_cost = ((rolls_qty[ItemConstants::MEMBRANE_LARGE_SKU] || 0) * roll_162_price) + ((rolls_qty[ItemConstants::MEMBRANE_SMALL_SKU] || 0) * roll_54_price) # Rule: If area >= smallest roll size, always use rolls (more practical for installation) # Otherwise, compare cost and pick cheaper option use_rolls = area_sqft >= roll_54_sqft || rolls_cost < sheets_cost if use_rolls rolls_qty.each do |sku, qty| next unless qty.positive? item = prodeso_items[sku] u_lines[sku] = { quantity: qty, name: item.name, detailed_description: item.detailed_description, item_id: item.id } end elsif sheet_item u_lines[sheet_item.sku] = { quantity: sheets_needed, name: sheet_item.name, detailed_description: sheet_item.detailed_description, item_id: sheet_item.id } end end logger.debug("get_suggested_underlayments, u_lines: #{u_lines.inspect}") u_lines end |
.get_suggested_underlayments_for_room(rc) ⇒ Object
1036 1037 1038 1039 |
# File 'app/models/heating_element_product_line_option.rb', line 1036 def self.get_suggested_underlayments_for_room(rc) HeatingElementProductLineOption.get_suggested_underlayments({ sqft: rc.insulation_surface, sub_floor_type_id: rc.sub_floor_type_id, floor_type_id: rc.floor_type_id, product_line_id: rc.heating_system_product_line_id, catalog_id: rc.catalog.id }) end |
.ideal_cable_spacing_select_options ⇒ Object
815 816 817 |
# File 'app/models/heating_element_product_line_option.rb', line 815 def self. cable_spacing_for_select end |
.instant_quotable_environments ⇒ Object
Cached list of environments that support instant quoting
116 117 118 |
# File 'app/models/heating_element_product_line_option.rb', line 116 def self.instant_quotable_environments @instant_quotable_environments ||= (:environment, { instant_quotable: true }).uniq end |
.membrane_type_select_options ⇒ Object
823 824 825 |
# File 'app/models/heating_element_product_line_option.rb', line 823 def self. MEMBRANE_TYPES.zip end |
.next_priority ⇒ Object
1235 1236 1237 |
# File 'app/models/heating_element_product_line_option.rb', line 1235 def self.next_priority (HeatingElementProductLineOption.maximum(:priority) || 0) + 1 end |
.options_for_select(assoc_sym, assoc_sort_field = 'name', assoc_name_method = 'name', options = {}, include_blank = false, assoc_key = 'id') ⇒ Array
Returns values of an association for use in a select list.
930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 |
# File 'app/models/heating_element_product_line_option.rb', line 930 def self.(assoc_sym, assoc_sort_field = 'name', assoc_name_method = 'name', = {}, include_blank = false, assoc_key = 'id') Rails.logger.debug("HeatingElementProductLineOption.options_for_select", assoc_sym: assoc_sym, assoc_sort_field: assoc_sort_field) assoc_fk = "#{assoc_sym}_id" # Build the base query with filters base_query = HeatingElementProductLineOption.all .each do |k, v| base_query = base_query.where(k => v) unless k == assoc_sym || v.nil? end # Get distinct association IDs that match the filters matching_ids = base_query.where.not(assoc_fk => nil).distinct.pluck(assoc_fk) return [] if matching_ids.empty? # Query the association table directly for just the fields we need assoc_class = reflect_on_association(assoc_sym).klass order_clause = assoc_sort_field ? { assoc_sort_field => :asc } : {} # Check if assoc_name_method is a database column or a Ruby method # If it's a method (like heating_system_type_name), we need to load objects and call the method is_column = assoc_class.column_names.include?(assoc_name_method.to_s) is_key_column = assoc_class.column_names.include?(assoc_key.to_s) if is_column && is_key_column # Efficient path: both are columns, use pluck = assoc_class .where(id: matching_ids) .order(order_clause) .pluck(assoc_name_method, assoc_key) else # Fallback path: one or both are methods, load objects records = assoc_class.where(id: matching_ids).order(order_clause) = records.map { |r| [r.public_send(assoc_name_method), r.public_send(assoc_key)] } end .insert(0, ['----', nil]) if .any? && include_blank == true end |
.options_scope(options = {}) ⇒ ActiveRecord::Relation
Returns a scope filtered by the given attribute values.
1003 1004 1005 1006 1007 1008 1009 1010 |
# File 'app/models/heating_element_product_line_option.rb', line 1003 def self.( = {}) Rails.logger.debug("HeatingElementProductLineOption.options_scope") res = HeatingElementProductLineOption.includes(:product_line, :sub_floor_type, :floor_type) ( || {}).each do |k, v| res = res.where(k => v) if v.present? end res end |
.populate_options ⇒ Object
DEPRECATED USED ONLY FOR MIGRATION
1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 |
# File 'app/models/heating_element_product_line_option.rb', line 1256 def self. application_types = HeatingElementProductLineOption::APPLICATION_TYPES env_by_app_type = { 'FH' => ['Indoor'], 'SM' => ['Outdoor'], 'CH' => ['Countertop'] } heating_system_types = ['TempZone Flex Roll', 'TempZone Easy Mat', 'Environ Flex Roll', 'Environ Easy Mat', 'Slab Heat Cable', 'Slab Heat Mat', 'Snow Melt Cable', 'Snow Melt Mat'] heating_system_type_pl_ids = [12, 102, 99, 21, 25, 28, 37, 40] priority = 0 application_types.each do |application_type| # puts "application_type: #{application_type}" env_by_app_type[application_type].each do |environment| # puts "environment: #{environment}" sub_floor_type_ids ||= SubFloorType.active.by_name.pluck(:id) sub_floor_type_ids = [nil] if environment == 'Outdoor' # sub floor only applies to Indoor sub_floor_type_ids.each do |sub_floor_type_id| sub_floor_type = nil sub_floor_type = SubFloorType.find(sub_floor_type_id) if sub_floor_type_id # puts "sub_floor_type: #{sub_floor_type ? sub_floor_type.name : 'nil'}" floor_types = FloorType.active.by_environment(environment) floor_types.each do |floor_type| # puts "floor_type: #{floor_type.name}" # Need to exclude unfinished stamped concrete (id 5) except for newly poured concrete sub floor (id 3) if (floor_type.id == 5) && (sub_floor_type.id != 3) # puts "skipping floor_type floor_type: #{floor_type.name} and sub_floor_type: #{sub_floor_type ? sub_floor_type.name : 'nil'}" else require_expansion_joint = floor_type.require_expansion_joint? # use floor type to determine this for now # puts "require_expansion_joint: #{require_expansion_joint}" # get all public and not public (by passing for_iq=nil) heating_types for floor_type HeatingSystem.heating_system_types_for_floor_type(floor_type, room_type = nil, for_iq = nil).each do |heating_system_type| # get heating system type's corresponding product line # puts "heating_system_type: #{heating_system_type}" ind = heating_system_types.index(heating_system_type) product_line = ProductLine.find(heating_system_type_pl_ids[ind]) # puts "product_line: #{product_line.name}" # use legacy HeatingSystem to populate various options heating_system = HeatingSystem.new(heating_system_type) require_cable_spacing = heating_system.require_cable_spacing? # puts "require_cable_spacing: #{require_cable_spacing}" ideal_cable_spacing = nil ideal_cable_spacing = heating_system.ideal_cable_spacing(floor_type) if require_cable_spacing # puts "ideal_cable_spacing: #{ideal_cable_spacing}" is_public = false heating_system_types_public = HeatingSystem.heating_system_types_for_floor_type(floor_type, room_type = nil, for_iq = true) # figure out if public by passing in for_iq true and seeing current heating_system_type is in there is_public = true if heating_system_types_public.include?(heating_system_type) # puts "is_public: #{is_public}" # find insulation/underlayment options, here we reproduce some of the logic in floor_type's suggested_underlayment method underlayment_recommended = false add_thermalsheet = false product_type = begin heating_system.code rescue StandardError nil end product_type ||= floor_type.product # default to floor type's recommendation if %w[EV2 TZ EVFR TZEM].include? product_type && !((sub_floor_type && sub_floor_type.name.to_s.downcase.index('wood')) || floor_type.is_carpet?) add_thermalsheet = true end underlayment_recommended = true if add_thermalsheet # puts "underlayment_recommended: #{underlayment_recommended}" underlayment_type = nil underlayment_type = 'ThermalSheet' if add_thermalsheet # puts "underlayment_type: #{underlayment_type}" # for underlayment_r_value, just use this if then else, which is the only sense I can make out from the table produced by Scott here: https://docs.google.com/a/warmlyyours.com/spreadsheet/ccc?key=0AlWFu-aXWRVZdGxxaFBjamVSLVVKaFFiSGt0XzJOamc#gid=1 floor_type_name_lower_case = floor_type.name.downcase if heating_system_type.downcase.index('tempzone') && (floor_type_name_lower_case.index('bamboo') || floor_type_name_lower_case.index('') || floor_type_name_lower_case.index('carpet') || floor_type_name_lower_case.index('engineered') || floor_type_name_lower_case.index('laminate')) 'L' end 'H' if heating_system_type.downcase.index('environ') && floor_type_name_lower_case.index('carpet') # puts "underlayment_r_value: #{underlayment_r_value}" # great, now create the damn thing priority += 1 # puts "priority: #{priority}" attributes = { priority: priority, application_type: application_type, environment: environment, sub_floor_type_id: sub_floor_type_id, floor_type_id: floor_type.id, product_line_id: product_line.id, is_public: is_public, require_expansion_joint: require_expansion_joint, require_cable_spacing: require_cable_spacing, ideal_cable_spacing: ideal_cable_spacing, underlayment_recommended: underlayment_recommended, underlayment_type: underlayment_type } # puts "creating HeatingElementProductLineOption: attributes: #{attributes.inspect}" HeatingElementProductLineOption.create(attributes) end end end end end end end |
.prioritized ⇒ ActiveRecord::Relation<HeatingElementProductLineOption>
A relation of HeatingElementProductLineOptions that are prioritized. Active Record Scope
67 |
# File 'app/models/heating_element_product_line_option.rb', line 67 scope :prioritized, -> { joins(:product_line).order('heating_element_product_line_options.is_public DESC, heating_element_product_line_options.priority, product_lines.priority') } |
.product_line_is_iq_supported?(pl) ⇒ Boolean
1245 1246 1247 1248 1249 |
# File 'app/models/heating_element_product_line_option.rb', line 1245 def self.product_line_is_iq_supported?(pl) res = false res = PRODUCT_LINE_BY_HEATING_SYSTEM_TYPE[pl.heating_system_type_name].present? if pl && pl.heating_system_type_name.present? res end |
.product_line_options_for_select ⇒ Object
1229 1230 1231 |
# File 'app/models/heating_element_product_line_option.rb', line 1229 def self. HeatingElementProductLineOption.joins(:product_line).pluck(Arel.sql('distinct product_lines.lineage_expanded, product_lines.id')).sort end |
.public_environment_select_options ⇒ Object
811 812 813 |
# File 'app/models/heating_element_product_line_option.rb', line 811 def self. PUBLIC_ENVIRONMENTS_HASH.map { |k, _v| k } end |
.public_room_type_keys ⇒ Object
106 107 108 |
# File 'app/models/heating_element_product_line_option.rb', line 106 def self.public_room_type_keys @public_room_type_keys ||= RoomType.by_environment(PUBLIC_ENVIRONMENTS).pluck(:seo_key) end |
.readable_order ⇒ ActiveRecord::Relation<HeatingElementProductLineOption>
A relation of HeatingElementProductLineOptions that are readable order. Active Record Scope
64 65 66 |
# File 'app/models/heating_element_product_line_option.rb', line 64 scope :readable_order, -> { joins(:floor_type).order('heating_element_product_line_options.application_type ASC, heating_element_product_line_options.environment ASC, heating_element_product_line_options.sub_floor_type_id ASC, floor_types.name ASC, heating_element_product_line_options.priority ASC').readonly(false) } |
.reset_cached_constants! ⇒ Object
Keep constant for backward compatibility
121 122 123 124 125 126 |
# File 'app/models/heating_element_product_line_option.rb', line 121 def self.reset_cached_constants! @default_room_type_by_environment = nil @public_room_type_keys = nil @valid_membrane_types = nil @instant_quotable_environments = nil end |
.shc_cable_spacing_for_select(cs_options = {}) ⇒ Object
857 858 859 860 861 862 |
# File 'app/models/heating_element_product_line_option.rb', line 857 def self.shc_cable_spacing_for_select( = {}) = { unit: 'in' }.merge() [["SHC 12 watts/sqft - #{RubyUnits::Unit.new('6.0 in').to_s([:unit])}", 6.0], ["SHC 15 watts/sqft - #{RubyUnits::Unit.new('5.0 in').to_s([:unit])}", 5.0], ["SHC 17 watts/sqft - #{RubyUnits::Unit.new('4.0 in').to_s([:unit])}", 4.0], ["SHC 20 watts/sqft - #{RubyUnits::Unit.new('3.0 in').to_s([:unit])}", 3.0]] end |
.smc_cable_spacing_for_select(cs_options = {}) ⇒ Object
851 852 853 854 855 |
# File 'app/models/heating_element_product_line_option.rb', line 851 def self.smc_cable_spacing_for_select( = {}) = { unit: 'in' }.merge() [["SMC 25 watts/sqft - #{RubyUnits::Unit.new('6.0 in').to_s([:unit])}", 6.0], ["SMC up to 31.5 watts/sqft - #{RubyUnits::Unit.new('5.0 in').to_s([:unit])}", 5.0], ["SMC up to 33 watts/sqft - #{RubyUnits::Unit.new('4.5 in').to_s([:unit])}", 4.5], ["SMC up to 38.5 watts/sqft - #{RubyUnits::Unit.new('4.0 in').to_s([:unit])}", 4.0], ["SMC up to 43 watts/sqft - #{RubyUnits::Unit.new('3.5 in').to_s([:unit])}", 3.5], ["SMC up to 50 watts/sqft - #{RubyUnits::Unit.new('3.0 in').to_s([:unit])}", 3.0], ["SMC up to 60 watts/sqft - #{RubyUnits::Unit.new('2.5 in').to_s([:unit])}", 2.5]] end |
.spacing_to_unit(spacing_in_inches, unit = 'in') ⇒ Object
899 900 901 902 903 904 |
# File 'app/models/heating_element_product_line_option.rb', line 899 def self.spacing_to_unit(spacing_in_inches, unit = 'in') n = RubyUnits::Unit.new(spacing_in_inches, 'in') n = n.convert_to(unit) if unit != 'in' n = number_with_precision(n.scalar, strip_insignificant_zeros: true) "#{n} #{unit}" end |
.tz_cable_spacing_for_select(cs_options = {}) ⇒ Object
881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 |
# File 'app/models/heating_element_product_line_option.rb', line 881 def self.tz_cable_spacing_for_select( = {}) = { unit: 'in', tz_cable_pl_url: ProductLineUrls::FLOOR_HEATING_TEMPZONE_CABLE }.merge() opts = if [:sftid] && (sft = SubFloorType.find([:sftid]).name) && sft.index('Concrete') # disable 4 inch and greater spacing for concrete subfloors [] else [["TZ (Prodeso membrane) #{tz_cable_watts_per_sqft(5.0, )} watts/sqft - #{spacing_to_unit(5.0, [:unit])} spacing", 5.0], ["TZ (DITRA membrane) #{tz_cable_watts_per_sqft(4.75, )} watts/sqft - #{spacing_to_unit(4.75, [:unit])} spacing", 4.75], ["TZ #{tz_cable_watts_per_sqft(4.0, )} watts/sqft - #{spacing_to_unit(4.0, [:unit])} spacing", 4.0]] end opts += [["TZ (Prodeso membrane / Free form) #{tz_cable_watts_per_sqft(3.75, )} watts/sqft - #{spacing_to_unit(3.75, [:unit])} spacing", 3.75]] opts += [["TZ (DITRA membrane / Free form) #{tz_cable_watts_per_sqft(3.5, )} watts/sqft - #{spacing_to_unit(3.5, [:unit])} spacing", 3.5]] opts += [["TZ #{tz_cable_watts_per_sqft(3.0, )} watts/sqft - #{spacing_to_unit(3.0, [:unit])} spacing", 3.0]] opts += [["TZ (Alternating 2/3 stud Prodeso Membrane 2.5/3.75\" Spacing) #{tz_cable_watts_per_sqft(3.125, )} average watts/sqft - average #{spacing_to_unit(3.125, [:unit])} spacing", 3.125]] unless [:is_public] == true opts += [["TZ (Alternating 2/3 stud DITRA Membrane 2.3/3.5\" Spacing) #{tz_cable_watts_per_sqft(2.9, )} average watts/sqft - average #{spacing_to_unit(2.9, [:unit])} spacing", 2.9]] unless [:is_public] == true opts end |
.tz_cable_watts_per_sqft(cs, options) ⇒ BigDecimal?
cs = cable spacing, decimal in inch. So 3.5 for 3" 1/2
912 913 914 915 916 917 918 |
# File 'app/models/heating_element_product_line_option.rb', line 912 def self.tz_cable_watts_per_sqft(cs, ) slug = LtreePaths.slug_ltree_from_legacy_hyphen_url([:tz_cable_pl_url]) || [:tz_cable_pl_url].to_s tz_cable_pl = ProductLine.find_by(slug_ltree: slug) watts_per_sqft = RoomConfiguration::WATTS_PER_SQUARE_FOOT["#{tz_cable_pl.heating_system_type_name} #{cs}"] watts_per_sqft ||= (RoomConfiguration::WATTS_PER_SQUARE_FOOT[tz_cable_pl.heating_system_type_name.to_s] * 3.0 / cs).round(1) watts_per_sqft end |
.underlayment_type_select_options ⇒ Object
819 820 821 |
# File 'app/models/heating_element_product_line_option.rb', line 819 def self. UNDERLAYMENT_TYPES.zip end |
.valid_membrane_types ⇒ Object
Cached list of valid membrane types to avoid expensive DISTINCT queries on every request
111 112 113 |
# File 'app/models/heating_element_product_line_option.rb', line 111 def self.valid_membrane_types @valid_membrane_types ||= pluck(Arel.sql('distinct membrane_type')).compact end |
.voltage_options_for_select(heating_system_product_line, include_24 = false, environment = nil, use_smc_voltages = nil) ⇒ Object
827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 |
# File 'app/models/heating_element_product_line_option.rb', line 827 def self.(heating_system_product_line, include_24 = false, environment = nil, use_smc_voltages = nil) hs_name = heating_system_product_line&.heating_system_type_name if /TempZone Custom Mat/i.match?(hs_name) res = [120, 208, 240] elsif /TempZone/i.match?(hs_name) res = [120, 240] res += [24] if include_24 == true elsif /Countertop Heater/i.match?(hs_name) res = [] elsif (hs_name =~ /Snow/i && hs_name =~ /Cable/i) || hs_name =~ /Pipe Freeze Protection/i || hs_name =~ /Roof & Gutter/i res = [120, 208, 240, 277] else res = [120, 240] res += [24] if include_24 == true res += [208, 277] if (environment.to_s.downcase == 'outdoor') && use_smc_voltages end res end |
Instance Method Details
#floor_type ⇒ FloorType
Validations:
54 |
# File 'app/models/heating_element_product_line_option.rb', line 54 belongs_to :floor_type, inverse_of: :heating_element_product_line_options, optional: true |
#heating_system_type_name ⇒ Object
Alias for Product_line#heating_system_type_name
62 |
# File 'app/models/heating_element_product_line_option.rb', line 62 delegate :heating_system_type_name, to: :product_line |
#name_with_cable_spacing ⇒ Object
1340 1341 1342 1343 1344 1345 1346 1347 |
# File 'app/models/heating_element_product_line_option.rb', line 1340 def name_with_cable_spacing extra = '' if ideal_cable_spacing.present? extra = " at #{ideal_cable_spacing} inch spacing" extra += " #{CABLE_SPACING_EXTRA_COPY[ideal_cable_spacing.to_s]}" if product_line.slug_ltree.to_s.include?('tempzone.cable') end "#{product_line.heating_system_type_name}#{extra}" end |
#product_line ⇒ ProductLine
Validations:
55 |
# File 'app/models/heating_element_product_line_option.rb', line 55 belongs_to :product_line, inverse_of: :heating_element_product_line_options, optional: true |
#product_line_is_heating_system_type ⇒ Object
Alias for Product_line#is_heating_system_type
1233 |
# File 'app/models/heating_element_product_line_option.rb', line 1233 delegate :is_heating_system_type, to: :product_line, prefix: true |
#room_type ⇒ RoomType
57 |
# File 'app/models/heating_element_product_line_option.rb', line 57 belongs_to :room_type, inverse_of: :heating_element_product_line_options, optional: true |
#store ⇒ Store
56 |
# File 'app/models/heating_element_product_line_option.rb', line 56 belongs_to :store, inverse_of: :heating_element_product_line_options, optional: true |
#sub_floor_type ⇒ SubFloorType
53 |
# File 'app/models/heating_element_product_line_option.rb', line 53 belongs_to :sub_floor_type, inverse_of: :heating_element_product_line_options, optional: true |
#summary ⇒ Object
1251 1252 1253 |
# File 'app/models/heating_element_product_line_option.rb', line 1251 def summary "#{is_public ? 'Public' : 'Internal'}>#{application_type}>#{environment}>#{"#{sub_floor_type.name}>" if sub_floor_type}#{floor_type.name}>#{product_line.heating_system_type_name}" end |