Module: Models::ItemSpecificationHelper
- Extended by:
- ActiveSupport::Concern
- Includes:
- Memery
- Included in:
- Item
- Defined in:
- app/concerns/models/item_specification_helper.rb
Overview
ActiveSupport::Concern mixin: item specification helper.
Constant Summary collapse
- PER_ITEM_SPEC_TOKENS =
Tokens whose values are coincidentally identical across unrelated items but should
never be collapsed into a single ProductSpecification row. Two towel warmers at 175W are
not "the same spec" the way two product names "Pipe Adapter" are — editing one must not
silently mutate the others.The nightly consolidator is gone, and with it the only consumer of the merge opt-out —
which is why this helper no longer sets that flag. The column survives as
legacy_do_not_merge, read and written now only by the finished one-time electrical
migrations underlib/online_migrations/data_migrations/. The list stays because those
migrations key off it, and because it still records which tokens must be written
per-item rather than shared. %i[watts voltage amps ohms].freeze
Instance Method Summary collapse
-
#amps ⇒ Object
Amps.
-
#amps=(val) ⇒ void
Sets the amps.
-
#amps_static? ⇒ Boolean
Whether amps static.
-
#area(output_unit: :sqft) ⇒ Object
Area.
-
#aspect ⇒ Object
Aspect.
-
#btu_per_hour ⇒ Object
Btu per hour.
-
#calculate_amps(precision: 2) ⇒ Object
Calculate amps.
-
#calculate_coverage_for_membrane(output_unit: :sqft) ⇒ Object
Calculate coverage for membrane.
-
#calculate_geometric_sqft ⇒ Object
Calculate geometric sqft.
-
#calculate_heated_area_for_panels(output_unit: :sqft) ⇒ Object
Calculates the coverage area for an infrared heating panel based on the watts, output_unit can be :sqm for square meters.
-
#calculate_heated_area_sqft_for_panels ⇒ Object
Calculate heated area sqft for panels.
-
#calculate_heated_area_sqm_for_panels ⇒ Object
Calculate heated area sqm for panels.
-
#calculate_kilowatts(precision: 2) ⇒ Object
Calculate kilowatts.
-
#calculate_number_of_fixing_strips_at_3_in ⇒ Object
Calculate number of fixing strips at 3 in.
-
#calculate_number_of_fixing_strips_at_4_in ⇒ Object
Calculate number of fixing strips at 4 in.
-
#calculate_number_of_fixing_strips_at_5_in ⇒ Object
Calculate number of fixing strips at 5 in.
-
#calculate_number_of_fixing_strips_at_cable_spacing(spacing_in_inches = 4) ⇒ Object
Calculate number of fixing strips at cable spacing.
-
#calculate_ohms(precision: 2) ⇒ Object
Calculate ohms.
-
#calculate_ohms_per_ft ⇒ Object
Calculate ohms per ft.
-
#calculate_size_2d(output_unit: nil, precision: nil) ⇒ Object
Calculate size 2d.
-
#calculate_size_2d_ft ⇒ Object
Calculate size 2d ft.
-
#calculate_size_2d_in ⇒ Object
Calculate size 2d in.
-
#calculate_size_2d_metric_cm ⇒ Object
Calculate size 2d metric cm.
-
#calculate_size_2d_metric_mm ⇒ Object
Calculate size 2d metric mm.
-
#calculate_size_3d(output_unit: nil, precision: nil) ⇒ Object
Calculate size 3d.
-
#calculate_size_3d_ft ⇒ Object
Calculate size 3d ft.
-
#calculate_size_3d_in ⇒ Object
Calculate size 3d in.
-
#calculate_size_3d_metric_cm ⇒ Object
Calculate size 3d metric cm.
-
#calculate_size_3d_metric_mm ⇒ Object
Calculate size 3d metric mm.
-
#calculate_sqft(cable_spacing: nil, heated_area: true) ⇒ Object
Calculate sqft.
-
#calculate_thermal_power_per_hour ⇒ Integer?
This is like btu per hour but kW.
-
#calculate_volts(precision: 0) ⇒ Object
The voltage V in volts (V) is equal to the current I in amps (A) times the resistance R in ohms (Ω):.
-
#calculate_watts(precision: 0) ⇒ Object
The power P in watts (W) is equal to the voltage V in volts (V) times the current I in amps (A):.
-
#calculate_watts_per_sqft(precision: 2) ⇒ Object
Calculate watts per sqft.
-
#can_use_amps_for_calculation? ⇒ Boolean
Whether can use amps for calculation.
-
#can_use_ohms_for_calculation? ⇒ Boolean
Whether can use ohms for calculation.
-
#can_use_voltage_for_calculation? ⇒ Boolean
Whether can use voltage for calculation.
-
#can_use_watts_for_calculation? ⇒ Boolean
Whether can use watts for calculation.
-
#cold_lead_length ⇒ Object
Cold lead length.
-
#cold_lead_length=(val) ⇒ void
Sets the cold lead length.
-
#control_capacity ⇒ Object
Control capacity.
-
#coverage_at_3_5_in ⇒ Object
Coverage at 3 5 in.
-
#coverage_at_3_75_in ⇒ Object
Coverage at 3 75 in.
-
#coverage_at_3_in ⇒ Object
Coverage at 3 in.
-
#coverage_at_4_5_in ⇒ Object
Coverage at 4 5 in.
-
#coverage_at_4_in ⇒ Object
Coverage at 4 in.
-
#coverage_at_5_in ⇒ Object
Coverage at 5 in.
-
#coverage_formatted ⇒ Object
Coverage formatted.
-
#create_or_set_spec_value(grouping:, text_blurb:, token: nil, name: nil, method: 'text', units: nil, visibility: 'open_visibility', locale: nil, skip_spec_refresh: false, link_to_product_line: false) ⇒ Object
Create or set spec value.
-
#finish ⇒ Object
Finish.
-
#has_spec?(token) ⇒ Boolean
Whether has spec.
-
#is_dual_voltage? ⇒ Boolean
Whether is dual voltage.
-
#length(output_unit: :in) ⇒ Object
Length.
-
#length=(val, unit: :in) ⇒ void
Sets the length.
-
#length_formatted ⇒ Object
Length formatted.
-
#linear_ft ⇒ BigDecimal?
Returns the cable length in linear feet, or nil when the item is not a cable heating element.
-
#maximum_current ⇒ Object
Maximum current.
-
#num_poles ⇒ Object
Num poles.
-
#ohms ⇒ Object
Ohms.
-
#ohms=(val) ⇒ void
Sets the ohms.
-
#ohms_law_calculator ⇒ Object
Ohms law calculator.
-
#ohms_static? ⇒ Boolean
Whether ohms static.
-
#plan_grouping ⇒ Object
Plan grouping.
-
#plan_grouping=(val) ⇒ void
Sets the plan grouping.
-
#rendered_specifications ⇒ Hash
Normalized view of rendered_product_specifications.
-
#set_spec_value(token, value) ⇒ Object
Finds a direct product spec and sets the value.
-
#spec(token) ⇒ Object
Retrieves a spec from the rendered product specification Performs a little bit of value casting on the raw output before returning.
-
#spec_image(token) ⇒ Object
Spec image.
-
#spec_output(token, locale: Mobility.locale) ⇒ Object
returns the formatted output from the spec.
-
#spec_refresh_in_progress ⇒ Object
Spec refresh in progress.
-
#spec_unit(token) ⇒ Object
Spec unit.
-
#spec_value(token, output_unit: nil, precision: nil) ⇒ Object
returns the raw value from the spec.
-
#specs_for_identifier_label ⇒ Object
Specs for identifier label.
-
#sqft ⇒ Object
Sqft.
-
#sqft=(val) ⇒ void
Sets the sqft.
-
#token_specs_values_for_liquid(include_legacy: false) ⇒ Object
Renders a hash with a token spec value (possibly in multiple dimensions) and its value.
-
#voltage ⇒ Object
Voltage.
-
#voltage=(val) ⇒ void
Sets the voltage.
-
#voltage_formatted ⇒ Object
Voltage formatted.
-
#voltage_static? ⇒ Boolean
Whether voltage static.
-
#volts ⇒ Object
Volts.
-
#volts=(val) ⇒ void
Sets the volts.
-
#vop ⇒ Object
Vop.
-
#watts ⇒ Object
Watts.
-
#watts=(val) ⇒ void
Sets the watts.
-
#watts_formatted ⇒ Object
Watts formatted.
-
#watts_per_linear_feet(precision: 2) ⇒ Object
Watts per linear feet.
-
#watts_per_sqft ⇒ Object
Watts per sqft.
-
#watts_per_sqft_at_3_5_in_spacing ⇒ Object
Watts per sqft at 3 5 in spacing.
-
#watts_per_sqft_at_3_75_in_spacing ⇒ Object
Watts per sqft at 3 75 in spacing.
-
#watts_per_sqft_at_3_in_spacing ⇒ Object
Watts per sqft at 3 in spacing.
-
#watts_per_sqft_at_4_5_in_spacing ⇒ Object
Watts per sqft at 4 5 in spacing.
-
#watts_per_sqft_at_4_in_spacing ⇒ Object
Watts per sqft at 4 in spacing.
-
#watts_per_sqft_at_5_in_spacing ⇒ Object
Watts per sqft at 5 in spacing.
-
#watts_static? ⇒ Boolean
Whether watts static.
-
#width(output_unit: :in) ⇒ Object
Width.
-
#width=(val, unit: :in) ⇒ void
Sets the width.
-
#width_by_length_text ⇒ Object
Width by length text.
-
#width_by_length_text_2 ⇒ Object
Width by length text 2.
-
#width_by_length_text_3 ⇒ String?
For larger rolls.
-
#width_formatted ⇒ Object
Width formatted.
Instance Method Details
#amps ⇒ Object
Amps.
537 538 539 540 |
# File 'app/concerns/models/item_specification_helper.rb', line 537 def amps a = spec_value(:amps) a.is_a?(Numeric) ? a : nil end |
#amps=(val) ⇒ void
This method returns an undefined value.
Sets the amps.
545 546 547 |
# File 'app/concerns/models/item_specification_helper.rb', line 545 def amps=(val) create_or_set_spec_value(token: :amps, name: 'Amps', units: 'A', grouping: 'Electrical', text_blurb: val) end |
#amps_static? ⇒ Boolean
Whether amps static.
736 737 738 |
# File 'app/concerns/models/item_specification_helper.rb', line 736 def amps_static? rendered_specifications.dig(:amps, :static).to_b end |
#area(output_unit: :sqft) ⇒ Object
Area.
313 314 315 316 317 318 319 320 321 322 323 |
# File 'app/concerns/models/item_specification_helper.rb', line 313 def area(output_unit: :sqft) v = spec_value(:coverage, output_unit:) v ||= spec_value(:sqft, output_unit: :output_unit) if v.nil? && length.present? && width.present? cv = (length(output_unit: :in) * width(output_unit: :in)) cvunit = RubyUnits::Unit.new("#{cv} sqin") v = cvunit.convert_to(output_unit.to_s).scalar.to_f end v end |
#aspect ⇒ Object
Aspect.
916 917 918 919 920 921 922 923 924 925 926 |
# File 'app/concerns/models/item_specification_helper.rb', line 916 def aspect return unless (height = spec_value(:height)).present? && (width == spec_value(:width)).present? if height.to_i == width.to_i 'Vertical / Horizontal' elsif height.to_i > width.to_i 'Vertical' else 'Horizontal' end end |
#btu_per_hour ⇒ Object
Btu per hour.
785 786 787 788 789 790 791 792 793 |
# File 'app/concerns/models/item_specification_helper.rb', line 785 def btu_per_hour return unless (w = watts.presence) return unless w.to_f.positive? # If we have a thermal efficiency we will use it to calculate or assume 100 efficiency = spec_value(:thermal_output_efficiency)&.to_f || 100.0 # Apply the BTU conversion (w.to_f * (efficiency / 100.0) * RoomConfiguration::BTU_PER_HOUR_PER_WATT).round end |
#calculate_amps(precision: 2) ⇒ Object
Calculate amps.
577 578 579 |
# File 'app/concerns/models/item_specification_helper.rb', line 577 def calculate_amps(precision: 2) ohms_law_calculator.current&.round(precision) end |
#calculate_coverage_for_membrane(output_unit: :sqft) ⇒ Object
Calculate coverage for membrane.
296 297 298 299 300 301 302 303 304 305 306 307 308 |
# File 'app/concerns/models/item_specification_helper.rb', line 296 def calculate_coverage_for_membrane(output_unit: :sqft) coverage = 0.0 if is_membrane? coverage = spec_value(:coverage, output_unit:) elsif is_kit? kit_target_item_relations.includes(:target_item).find_each do |tir| next if tir.target_item.nil? || !tir.target_item.is_membrane? coverage += tir.target_item.spec_value(:coverage, output_unit:) * tir.quantity end end coverage&.positive? ? coverage.round(2) : nil end |
#calculate_geometric_sqft ⇒ Object
Calculate geometric sqft.
828 829 830 |
# File 'app/concerns/models/item_specification_helper.rb', line 828 def calculate_geometric_sqft calculate_sqft(heated_area: false) end |
#calculate_heated_area_for_panels(output_unit: :sqft) ⇒ Object
Calculates the coverage area for an infrared heating panel based on the watts, output_unit can be :sqm for square meters.
270 271 272 273 274 275 276 277 278 279 |
# File 'app/concerns/models/item_specification_helper.rb', line 270 def calculate_heated_area_for_panels(output_unit: :sqft) return if (w = watts).blank? return unless is_infrared_heating_panel? coverage_panel_in_sq_ft = (w.to_f / 7).ceil return coverage_panel_in_sq_ft if output_unit == :sqft coverage_unitized = "#{coverage_panel_in_sq_ft} sqft" RubyUnits::Unit.new(coverage_unitized).convert_to(output_unit.to_s).scalar.to_f.round end |
#calculate_heated_area_sqft_for_panels ⇒ Object
Calculate heated area sqft for panels.
283 284 285 |
# File 'app/concerns/models/item_specification_helper.rb', line 283 def calculate_heated_area_sqft_for_panels calculate_heated_area_for_panels(output_unit: :sqft) end |
#calculate_heated_area_sqm_for_panels ⇒ Object
Calculate heated area sqm for panels.
289 290 291 |
# File 'app/concerns/models/item_specification_helper.rb', line 289 def calculate_heated_area_sqm_for_panels calculate_heated_area_for_panels(output_unit: :sqm) end |
#calculate_kilowatts(precision: 2) ⇒ Object
Calculate kilowatts.
675 676 677 678 679 |
# File 'app/concerns/models/item_specification_helper.rb', line 675 def calculate_kilowatts(precision: 2) return unless (w = watts || calculate_watts) (w.to_f / 1000).round(precision) end |
#calculate_number_of_fixing_strips_at_3_in ⇒ Object
Calculate number of fixing strips at 3 in.
404 405 406 |
# File 'app/concerns/models/item_specification_helper.rb', line 404 def calculate_number_of_fixing_strips_at_3_in calculate_number_of_fixing_strips_at_cable_spacing(3) end |
#calculate_number_of_fixing_strips_at_4_in ⇒ Object
Calculate number of fixing strips at 4 in.
410 411 412 |
# File 'app/concerns/models/item_specification_helper.rb', line 410 def calculate_number_of_fixing_strips_at_4_in calculate_number_of_fixing_strips_at_cable_spacing(4) end |
#calculate_number_of_fixing_strips_at_5_in ⇒ Object
Calculate number of fixing strips at 5 in.
416 417 418 |
# File 'app/concerns/models/item_specification_helper.rb', line 416 def calculate_number_of_fixing_strips_at_5_in calculate_number_of_fixing_strips_at_cable_spacing(5) end |
#calculate_number_of_fixing_strips_at_cable_spacing(spacing_in_inches = 4) ⇒ Object
Calculate number of fixing strips at cable spacing.
389 390 391 392 393 394 395 396 397 398 399 400 |
# File 'app/concerns/models/item_specification_helper.rb', line 389 def calculate_number_of_fixing_strips_at_cable_spacing(spacing_in_inches = 4) return unless (cable_length = linear_ft) coefficients = { 3 => 0.1875, 4 => 0.225, 5 => 0.3125 } raise "Invalid spacing #{spacing_in_inches}, must be #{coefficients.keys.join(', ')}" unless spacing_in_inches.in?(coefficients.keys) coefficient = coefficients[spacing_in_inches] qty_fixing_strips = ((cable_length * coefficient) + 6) qty_fixing_strips = (qty_fixing_strips / 10).ceil * 10 # minimum 30 [30, qty_fixing_strips].max end |
#calculate_ohms(precision: 2) ⇒ Object
Calculate ohms.
694 695 696 |
# File 'app/concerns/models/item_specification_helper.rb', line 694 def calculate_ohms(precision: 2) ohms_law_calculator.resistance&.round(precision) end |
#calculate_ohms_per_ft ⇒ Object
Calculate ohms per ft.
683 684 685 686 687 688 689 |
# File 'app/concerns/models/item_specification_helper.rb', line 683 def calculate_ohms_per_ft l = spec_value(:heating_cable_length, output_unit: 'ft') || spec_value(:length, output_unit: 'ft') o = ohms return unless o.is_a?(Numeric) && l.is_a?(Numeric) && o.positive? && l.positive? (o.to_f / l).round(3) end |
#calculate_size_2d(output_unit: nil, precision: nil) ⇒ Object
Calculate size 2d.
599 600 601 602 603 604 605 606 607 |
# File 'app/concerns/models/item_specification_helper.rb', line 599 def calculate_size_2d(output_unit: nil, precision: nil) output_unit ||= spec_unit(:width) precision ||= { mm: 0, in: 1, m: 2, ft: 2 }[output_unit&.to_sym] s = [ spec_value(:width, output_unit:, precision:), spec_value(:length, output_unit:, precision:) || spec_value(:height, output_unit:, precision:) ].join(' x ') "#{s} #{output_unit}" end |
#calculate_size_2d_ft ⇒ Object
Calculate size 2d ft.
656 657 658 |
# File 'app/concerns/models/item_specification_helper.rb', line 656 def calculate_size_2d_ft calculate_size_2d(output_unit: 'ft', precision: 2) end |
#calculate_size_2d_in ⇒ Object
Calculate size 2d in.
650 651 652 |
# File 'app/concerns/models/item_specification_helper.rb', line 650 def calculate_size_2d_in calculate_size_2d(output_unit: 'in', precision: 0) end |
#calculate_size_2d_metric_cm ⇒ Object
Calculate size 2d metric cm.
668 669 670 |
# File 'app/concerns/models/item_specification_helper.rb', line 668 def calculate_size_2d_metric_cm calculate_size_2d(output_unit: 'cm', precision: 0) end |
#calculate_size_2d_metric_mm ⇒ Object
Calculate size 2d metric mm.
662 663 664 |
# File 'app/concerns/models/item_specification_helper.rb', line 662 def calculate_size_2d_metric_mm calculate_size_2d(output_unit: 'mm', precision: 0) end |
#calculate_size_3d(output_unit: nil, precision: nil) ⇒ Object
Calculate size 3d.
613 614 615 616 617 618 619 620 621 622 |
# File 'app/concerns/models/item_specification_helper.rb', line 613 def calculate_size_3d(output_unit: nil, precision: nil) output_unit ||= spec_unit(:width) precision ||= { mm: 0, in: 1, m: 2, ft: 2 }[output_unit&.to_sym] s = [ spec_value(:width, output_unit:, precision:), spec_value(:length, output_unit:, precision:) || spec_value(:height, output_unit:, precision:), spec_value(:depth, output_unit:, precision:) ].join(' x ') "#{s} #{output_unit}" end |
#calculate_size_3d_ft ⇒ Object
Calculate size 3d ft.
644 645 646 |
# File 'app/concerns/models/item_specification_helper.rb', line 644 def calculate_size_3d_ft calculate_size_3d(output_unit: 'ft', precision: 2) end |
#calculate_size_3d_in ⇒ Object
Calculate size 3d in.
638 639 640 |
# File 'app/concerns/models/item_specification_helper.rb', line 638 def calculate_size_3d_in calculate_size_3d(output_unit: 'in', precision: 0) end |
#calculate_size_3d_metric_cm ⇒ Object
Calculate size 3d metric cm.
632 633 634 |
# File 'app/concerns/models/item_specification_helper.rb', line 632 def calculate_size_3d_metric_cm calculate_size_3d(output_unit: 'cm', precision: 0) end |
#calculate_size_3d_metric_mm ⇒ Object
Calculate size 3d metric mm.
626 627 628 |
# File 'app/concerns/models/item_specification_helper.rb', line 626 def calculate_size_3d_metric_mm calculate_size_3d(output_unit: 'mm', precision: 0) end |
#calculate_sqft(cable_spacing: nil, heated_area: true) ⇒ Object
Calculate sqft.
836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 |
# File 'app/concerns/models/item_specification_helper.rb', line 836 def calculate_sqft(cable_spacing: nil, heated_area: true) calculated_area = nil effective_width = BigDecimal(width, 2) if width effective_length = BigDecimal(length, 2) if length if effective_length&.positive? case product_category.surface_calculation_method when 'standard' if effective_width&.positive? if (is_slab_heat_mat? || is_snow_melting_mat?) && heated_area # Apply padding rule of 3" (1.5" per side bleed out for heat) effective_width += 3.0 end calculated_area = (effective_length * effective_width / 144.0) if effective_width.positive? end when 'cable_spacing' cable_spacing = calculate_ideal_cable_spacing unless cable_spacing && (cable_spacing > 0.0) effective_width = (cable_spacing || effective_width).to_f calculated_area = (effective_length * effective_width / 144.0) if effective_width.positive? end end static_area = rendered_specifications.dig(:coverage, :raw) if rendered_specifications.dig(:coverage, :static).to_b effective_area = calculated_area || static_area effective_area = BigDecimal(effective_area, 2) if effective_area effective_area end |
#calculate_thermal_power_per_hour ⇒ Integer?
This is like btu per hour but kW
797 798 799 800 801 802 803 804 805 |
# File 'app/concerns/models/item_specification_helper.rb', line 797 def calculate_thermal_power_per_hour return unless (w = watts.presence) return unless w.to_f.positive? # If we have a thermal efficiency we will use it to calculate or assume 100 efficiency = spec_value(:thermal_output_efficiency)&.to_f || 100.0 # Convert to kw/h (w.to_f * (efficiency / 100.0) / 1000).round(2) end |
#calculate_volts(precision: 0) ⇒ Object
The voltage V in volts (V) is equal to the current I in amps (A) times the resistance R in ohms (Ω):
584 585 586 |
# File 'app/concerns/models/item_specification_helper.rb', line 584 def calculate_volts(precision: 0) ohms_law_calculator.voltage&.round(precision) end |
#calculate_watts(precision: 0) ⇒ Object
The power P in watts (W) is equal to the voltage V in volts (V) times the current I in amps (A):
591 592 593 |
# File 'app/concerns/models/item_specification_helper.rb', line 591 def calculate_watts(precision: 0) ohms_law_calculator.power&.round(precision) end |
#calculate_watts_per_sqft(precision: 2) ⇒ Object
Calculate watts per sqft.
816 817 818 819 820 821 822 823 824 |
# File 'app/concerns/models/item_specification_helper.rb', line 816 def calculate_watts_per_sqft(precision: 2) tw = watts || calculate_watts sqft = spec_value(:coverage) || calculate_sqft return unless tw&.positive? && sqft&.positive? wps = (BigDecimal(tw.to_s) / sqft).round(precision) wps = wps.to_i if wps.frac.zero? # Makes 15.0 => 15 wps end |
#can_use_amps_for_calculation? ⇒ Boolean
Whether can use amps for calculation.
742 743 744 |
# File 'app/concerns/models/item_specification_helper.rb', line 742 def can_use_amps_for_calculation? amps_static? && amps && amps > 0 end |
#can_use_ohms_for_calculation? ⇒ Boolean
Whether can use ohms for calculation.
718 719 720 |
# File 'app/concerns/models/item_specification_helper.rb', line 718 def can_use_ohms_for_calculation? ohms_static? && ohms && ohms > 0 end |
#can_use_voltage_for_calculation? ⇒ Boolean
Whether can use voltage for calculation.
730 731 732 |
# File 'app/concerns/models/item_specification_helper.rb', line 730 def can_use_voltage_for_calculation? voltage_static? && voltage && voltage > 0 end |
#can_use_watts_for_calculation? ⇒ Boolean
Whether can use watts for calculation.
706 707 708 |
# File 'app/concerns/models/item_specification_helper.rb', line 706 def can_use_watts_for_calculation? watts_static? && watts && watts > 0 end |
#cold_lead_length ⇒ Object
Cold lead length.
256 257 258 |
# File 'app/concerns/models/item_specification_helper.rb', line 256 def cold_lead_length spec_value(:cold_lead_length) end |
#cold_lead_length=(val) ⇒ void
This method returns an undefined value.
Sets the cold lead length.
263 264 265 |
# File 'app/concerns/models/item_specification_helper.rb', line 263 def cold_lead_length=(val) create_or_set_spec_value(token: :cold_lead_length, name: 'Cold Lead Length', units: 'in', grouping: 'Electrical', text_blurb: val) end |
#control_capacity ⇒ Object
Control capacity.
773 774 775 |
# File 'app/concerns/models/item_specification_helper.rb', line 773 def control_capacity (maximum_current || 0) * (num_poles || 1) end |
#coverage_at_3_5_in ⇒ Object
Coverage at 3 5 in.
348 349 350 351 352 |
# File 'app/concerns/models/item_specification_helper.rb', line 348 def coverage_at_3_5_in return unless (l = linear_ft) (l.to_f * 0.291667).round(1) end |
#coverage_at_3_75_in ⇒ Object
Coverage at 3 75 in.
356 357 358 359 360 |
# File 'app/concerns/models/item_specification_helper.rb', line 356 def coverage_at_3_75_in return unless (l = linear_ft) (l.to_f * 0.3125).round(1) end |
#coverage_at_3_in ⇒ Object
Coverage at 3 in.
340 341 342 343 344 |
# File 'app/concerns/models/item_specification_helper.rb', line 340 def coverage_at_3_in return unless (l = linear_ft) (l.to_f * 0.25).round(1) end |
#coverage_at_4_5_in ⇒ Object
Coverage at 4 5 in.
372 373 374 375 376 |
# File 'app/concerns/models/item_specification_helper.rb', line 372 def coverage_at_4_5_in return unless (l = linear_ft) (l.to_f * 0.375).round(1) end |
#coverage_at_4_in ⇒ Object
Coverage at 4 in.
364 365 366 367 368 |
# File 'app/concerns/models/item_specification_helper.rb', line 364 def coverage_at_4_in return unless (l = linear_ft) (l.to_f * 0.333333).round(1) end |
#coverage_at_5_in ⇒ Object
Coverage at 5 in.
380 381 382 383 384 |
# File 'app/concerns/models/item_specification_helper.rb', line 380 def coverage_at_5_in return unless (l = linear_ft) (l.to_f * 0.416667).round(1) end |
#coverage_formatted ⇒ Object
Coverage formatted.
900 901 902 |
# File 'app/concerns/models/item_specification_helper.rb', line 900 def coverage_formatted spec_output(:coverage) end |
#create_or_set_spec_value(grouping:, text_blurb:, token: nil, name: nil, method: 'text', units: nil, visibility: 'open_visibility', locale: nil, skip_spec_refresh: false, link_to_product_line: false) ⇒ Object
Create or set spec value.
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'app/concerns/models/item_specification_helper.rb', line 120 def create_or_set_spec_value(grouping:, text_blurb:, token: nil, name: nil, method: 'text', units: nil, visibility: 'open_visibility', locale: nil, skip_spec_refresh: false, link_to_product_line: false) return if text_blurb.blank? # No point raise ArgumentError, 'Must specify token or name or both but not none' if token.blank? && name.blank? # If we have a name but no token, we derive it token ||= ProductSpecification.generate_token_from_name_and_grouping(name, grouping) token = token.to_sym # If we have a token but no name, we derive the name name ||= ProductSpecification.generate_name_from_token_and_grouping(token, grouping) attrs = { name: name, token: token, method: method, visibility: visibility, grouping: grouping } # if locale is specified but is en-US, we automatically will fall back to en, it makes it easier this way locale = :en if locale == :'en-US' localized_field_units = nil localized_field_text_blurb = nil %w[units text_blurb].each do |fn| suffix = locale.present? ? "_#{LocaleUtility.parameterized_locale(locale)}" : '_en' fnl = "#{fn}#{suffix}" localized_field_units = fnl.to_sym if fn == 'units' localized_field_text_blurb = fnl.to_sym if fn == 'text_blurb' attrs[fnl.to_sym] = binding.local_variable_get(fn.to_sym) end attrs[:grouping] = grouping attrs[:skip_spec_refresh] = true if skip_spec_refresh ps = direct_product_specifications.find_by(token:) ps ||= ProductSpecification.find_by(token: token, product_line_id: primary_product_line_id, product_category_id: product_category_id) if link_to_product_line if ps ps.do_not_compact_translation_container = true # Check if this localized value is really necessary? we check if it is the same as the fallback (in english only) if locale.present? && locale != :en && locale.to_s.start_with?('en') && ps.text_blurb_en == attrs[localized_field_text_blurb] && ps.units_en == attrs[localized_field_units] # Delete those localized attributes we don't need them attrs.delete(localized_field_text_blurb) attrs.delete(localized_field_units) # Then the localized attribute are simply the same as the fallback and can be removed logger.info 'Localized version of attributes is same as fallback, ignoring' else logger.debug("Updating product specification") ps.update(attrs) end elsif text_blurb.present? # in the context of this method, an empty value doesn't make sense # Build a new ProductSpecification and associate it with this item logger.debug("Creating product specification") ps = ProductSpecification.new(attrs) ps.do_not_compact_translation_container = true if link_to_product_line ps.product_line_id = primary_product_line_id ps.product_category_id = product_category_id else ps.items << self unless ps.items.include?(self) end ps.save! end ps end |
#finish ⇒ Object
Finish.
809 810 811 |
# File 'app/concerns/models/item_specification_helper.rb', line 809 def finish rendered_specifications.dig(:finish, :output) end |
#has_spec?(token) ⇒ Boolean
Whether has spec.
13 14 15 |
# File 'app/concerns/models/item_specification_helper.rb', line 13 def has_spec?(token) rendered_specifications[token.to_sym].present? end |
#is_dual_voltage? ⇒ Boolean
Whether is dual voltage.
779 780 781 |
# File 'app/concerns/models/item_specification_helper.rb', line 779 def is_dual_voltage? spec_value(:dual_voltage) and spec_value(:dual_voltage).to_s.downcase.first != 'f' end |
#length(output_unit: :in) ⇒ Object
Length.
203 204 205 |
# File 'app/concerns/models/item_specification_helper.rb', line 203 def length(output_unit: :in) spec_value(:length, output_unit:) end |
#length=(val, unit: :in) ⇒ void
This method returns an undefined value.
Sets the length.
211 212 213 |
# File 'app/concerns/models/item_specification_helper.rb', line 211 def length=(val, unit: :in) create_or_set_spec_value(token: :length, name: 'Length', units: unit.to_s, grouping: 'Product Dimensions', text_blurb: val) end |
#length_formatted ⇒ Object
Length formatted.
882 883 884 |
# File 'app/concerns/models/item_specification_helper.rb', line 882 def length_formatted spec_output(:length) end |
#linear_ft ⇒ BigDecimal?
Returns the cable length in linear feet, or nil when the item is not a cable heating element
865 866 867 868 869 870 871 |
# File 'app/concerns/models/item_specification_helper.rb', line 865 def linear_ft return unless get_self_and_kit_items.any?(&:is_cable_heating_element?) return if length.blank? length(output_unit: :ft) end |
#maximum_current ⇒ Object
Maximum current.
761 762 763 |
# File 'app/concerns/models/item_specification_helper.rb', line 761 def maximum_current spec_value(:maximum_current) || spec_value(:maximum_current_per_relay) if is_control? || is_power? end |
#num_poles ⇒ Object
Num poles.
767 768 769 |
# File 'app/concerns/models/item_specification_helper.rb', line 767 def num_poles spec_value(:numbers_of_poles) if is_relay_panel? || is_legacy_relay? end |
#ohms ⇒ Object
Ohms.
494 495 496 497 |
# File 'app/concerns/models/item_specification_helper.rb', line 494 def ohms o = spec_value(:ohms) o.is_a?(Numeric) ? o.round(4) : nil end |
#ohms=(val) ⇒ void
This method returns an undefined value.
Sets the ohms.
502 503 504 |
# File 'app/concerns/models/item_specification_helper.rb', line 502 def ohms=(val) create_or_set_spec_value(token: :ohms, name: 'Ohms', units: 'ohm', grouping: 'Electrical', text_blurb: val) end |
#ohms_law_calculator ⇒ Object
Ohms law calculator.
563 564 565 566 567 568 569 570 571 572 |
# File 'app/concerns/models/item_specification_helper.rb', line 563 def ohms_law_calculator @ohms_law_calculator ||= begin attrs = {} attrs[:resistance] = ohms if can_use_ohms_for_calculation? attrs[:voltage] = voltage if can_use_voltage_for_calculation? attrs[:power] = watts if can_use_watts_for_calculation? attrs[:current] = amps if can_use_amps_for_calculation? OhmsLawCalculator.new(attrs).calc end end |
#ohms_static? ⇒ Boolean
Whether ohms static.
712 713 714 |
# File 'app/concerns/models/item_specification_helper.rb', line 712 def ohms_static? rendered_specifications.dig(:ohms, :static).to_b end |
#plan_grouping ⇒ Object
Plan grouping.
748 749 750 |
# File 'app/concerns/models/item_specification_helper.rb', line 748 def plan_grouping spec_value(:plan_grouping) end |
#plan_grouping=(val) ⇒ void
This method returns an undefined value.
Sets the plan grouping.
755 756 757 |
# File 'app/concerns/models/item_specification_helper.rb', line 755 def plan_grouping=(val) create_or_set_spec_value(token: :plan_grouping, name: 'Plan Grouping', grouping: 'Logistics', visibility: 'internal', text_blurb: val) end |
#rendered_specifications ⇒ Hash
Normalized view of rendered_product_specifications. Non-default locales
deserialize the Mobility container translation as a plain string-keyed
Hash (only the default locale comes back as a HashWithIndifferentAccess),
so bare symbol lookups/digs silently miss every spec — normalize once per
underlying hash instead of on every lookup.
34 35 36 37 38 39 40 41 42 43 |
# File 'app/concerns/models/item_specification_helper.rb', line 34 def rendered_specifications rps = rendered_product_specifications return {} if rps.nil? unless @rendered_specifications_source.equal?(rps) @rendered_specifications_source = rps @rendered_specifications = rps.with_indifferent_access end @rendered_specifications end |
#set_spec_value(token, value) ⇒ Object
Finds a direct product spec and sets the value.
86 87 88 89 90 91 92 93 |
# File 'app/concerns/models/item_specification_helper.rb', line 86 def set_spec_value(token, value) token = token.to_sym ds = direct_product_specifications.where(token:).first logger.error("No direct_product_specifications present for #{sku} with token #{token}, cannot set spec value") unless ds ds&.update_attribute!(:text_blurb, value) update_rendered_product_specifications value end |
#spec(token) ⇒ Object
Retrieves a spec from the rendered product specification
Performs a little bit of value casting on the raw output before returning
21 22 23 24 25 26 |
# File 'app/concerns/models/item_specification_helper.rb', line 21 def spec(token) return unless (ps = rendered_specifications[token.to_sym]) ps[:raw] = TypeCoercer.coerce(ps[:raw]) ps end |
#spec_image(token) ⇒ Object
Spec image.
194 195 196 197 198 |
# File 'app/concerns/models/item_specification_helper.rb', line 194 def spec_image(token) return unless (iid = spec(token)&.dig(:image_id)) Image.find(iid) end |
#spec_output(token, locale: Mobility.locale) ⇒ Object
returns the formatted output from the spec
185 186 187 188 189 |
# File 'app/concerns/models/item_specification_helper.rb', line 185 def spec_output(token, locale: Mobility.locale) Mobility.with_locale(locale) do spec(token)&.dig(:output)&.dup end end |
#spec_refresh_in_progress ⇒ Object
Spec refresh in progress.
47 48 49 |
# File 'app/concerns/models/item_specification_helper.rb', line 47 def spec_refresh_in_progress BackgroundJobStatus.search(worker_klass: 'ItemAttributeWorker', args: id).present? end |
#spec_unit(token) ⇒ Object
Spec unit.
75 76 77 78 79 80 |
# File 'app/concerns/models/item_specification_helper.rb', line 75 def spec_unit(token) u = spec(token)&.dig(:units)&.dup # Sqft fudging to handle leftover bad data until it transitions over in all product_specifications.units u = 'sqft' if /Sq\.? ?Ft\.?/i.match?(u) u end |
#spec_value(token, output_unit: nil, precision: nil) ⇒ Object
returns the raw value from the spec
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'app/concerns/models/item_specification_helper.rb', line 56 def spec_value(token, output_unit: nil, precision: nil) return unless (v = spec(token)&.dig(:raw)&.dup) current_unit_symbol = spec_unit(token) if current_unit_symbol.present? && output_unit.present? && current_unit_symbol.to_s != output_unit.to_s current_unit_val = RubyUnits::Unit.new("#{v} #{current_unit_symbol}") # We're using desired_unit for testing compatibility desired_unit = RubyUnits::Unit.new("1 #{output_unit}") # only convert if units are compatible v = current_unit_val.convert_to(output_unit.to_s).scalar.to_f if current_unit_val.compatible?(desired_unit) end v = v.round(precision) if precision.present? && v.respond_to?(:round) TypeCoercer.coerce(v) end |
#specs_for_identifier_label ⇒ Object
Specs for identifier label.
906 907 908 909 910 911 912 |
# File 'app/concerns/models/item_specification_helper.rb', line 906 def specs_for_identifier_label hsh = {} specifications_for_item_label.each do |rps| hsh[rps.name] = rps.output end hsh end |
#sqft ⇒ Object
Sqft.
327 328 329 |
# File 'app/concerns/models/item_specification_helper.rb', line 327 def sqft area(output_unit: :sqft) end |
#sqft=(val) ⇒ void
This method returns an undefined value.
Sets the sqft.
334 335 336 |
# File 'app/concerns/models/item_specification_helper.rb', line 334 def sqft=(val) create_or_set_spec_value(token: :coverage, name: 'Coverage', units: 'sqft', grouping: 'Product Dimensions', text_blurb: val) end |
#token_specs_values_for_liquid(include_legacy: false) ⇒ Object
Renders a hash with a token spec value (possibly in multiple dimensions)
and its value. This hash can be used for liquid merges
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 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 |
# File 'app/concerns/models/item_specification_helper.rb', line 934 def token_specs_values_for_liquid(include_legacy: false) = {} [:item_name] = name [:detailed_description_html] = detailed_description_html [:short_description] = short_description [:feature_1] = feature_1 [:feature_2] = feature_2 [:feature_3] = feature_3 [:feature_4] = feature_4 [:feature_5] = feature_5 rendered_product_specifications&.each do |k, _v| [k] = spec_output(k) ["#{k}_formatted"] = spec_output(k) if include_legacy # This is for legacy if spec_unit(k) ["#{k}_raw"] = spec_value(k) ["#{k}_units"] = spec_unit(k) end supported_dim_units = %i[ft in m cm mm] supported_weight_units = %i[lb oz kg g] supported_coverage_units = %i[sqft sqm] current_unit = spec_unit(k)&.to_sym target_units = if supported_dim_units.include?(current_unit) supported_dim_units elsif supported_weight_units.include?(current_unit) supported_weight_units elsif supported_coverage_units.include?(current_unit) supported_coverage_units else [] end # We iterate through each dimension unit we care to have a translation for and pull the value target_units.each do |unit| next unless (val = begin spec_value(k, output_unit: unit) rescue StandardError nil end) ["#{k}_#{unit}_raw"] = val ["#{k}_#{unit}_units"] = unit.to_s end end # Now combine computed methods ProductSpecification.methods_for_select.each do |method_string| method_symbolized = method_string.to_sym next if method_symbolized == :text begin [method_symbolized.to_s] ||= send(method_symbolized) rescue StandardError # Ignore this end end .with_indifferent_access.compact end |
#voltage ⇒ Object
Voltage.
508 509 510 511 |
# File 'app/concerns/models/item_specification_helper.rb', line 508 def voltage v = spec_value(:voltage) v.is_a?(Numeric) ? v : nil end |
#voltage=(val) ⇒ void
This method returns an undefined value.
Sets the voltage.
516 517 518 |
# File 'app/concerns/models/item_specification_helper.rb', line 516 def voltage=(val) create_or_set_spec_value(token: :voltage, name: 'Voltage', units: 'V', grouping: 'Electrical', text_blurb: val) end |
#voltage_formatted ⇒ Object
Voltage formatted.
888 889 890 |
# File 'app/concerns/models/item_specification_helper.rb', line 888 def voltage_formatted spec_output(:voltage) end |
#voltage_static? ⇒ Boolean
Whether voltage static.
724 725 726 |
# File 'app/concerns/models/item_specification_helper.rb', line 724 def voltage_static? rendered_specifications.dig(:voltage, :static).to_b end |
#volts ⇒ Object
Volts.
522 523 524 525 |
# File 'app/concerns/models/item_specification_helper.rb', line 522 def volts logger.warn 'Deprecated method volts, use voltage instead' voltage end |
#volts=(val) ⇒ void
This method returns an undefined value.
Sets the volts.
530 531 532 533 |
# File 'app/concerns/models/item_specification_helper.rb', line 530 def volts=(val) logger.warn 'Deprecated method volts, use voltage instead' create_or_set_spec_value(token: :voltage, name: 'Voltage', units: 'V', grouping: 'Electrical', text_blurb: val) end |
#vop ⇒ Object
Vop.
551 552 553 |
# File 'app/concerns/models/item_specification_helper.rb', line 551 def vop spec_value(:vop) end |
#watts ⇒ Object
Watts.
479 480 481 482 483 |
# File 'app/concerns/models/item_specification_helper.rb', line 479 def watts w = spec_value(:watts, output_unit: 'W') # Force watts in case this is expressed in kilowatts w.is_a?(Numeric) ? w : nil end |
#watts=(val) ⇒ void
This method returns an undefined value.
Sets the watts.
488 489 490 |
# File 'app/concerns/models/item_specification_helper.rb', line 488 def watts=(val) create_or_set_spec_value(token: :watts, name: 'Watts', units: 'W', grouping: 'Electrical', text_blurb: val) end |
#watts_formatted ⇒ Object
Watts formatted.
894 895 896 |
# File 'app/concerns/models/item_specification_helper.rb', line 894 def watts_formatted spec_output(:watts) end |
#watts_per_linear_feet(precision: 2) ⇒ Object
Watts per linear feet.
471 472 473 474 475 |
# File 'app/concerns/models/item_specification_helper.rb', line 471 def watts_per_linear_feet(precision: 2) return unless length && watts (BigDecimal(watts.to_s) / (length.to_f / 12)).truncate(precision) end |
#watts_per_sqft ⇒ Object
Watts per sqft.
557 558 559 |
# File 'app/concerns/models/item_specification_helper.rb', line 557 def watts_per_sqft spec_value(:watts_per_sqft) || calculate_watts_per_sqft end |
#watts_per_sqft_at_3_5_in_spacing ⇒ Object
Watts per sqft at 3 5 in spacing.
430 431 432 433 434 |
# File 'app/concerns/models/item_specification_helper.rb', line 430 def watts_per_sqft_at_3_5_in_spacing return unless watts && coverage_at_3_5_in (BigDecimal(watts.to_s) / coverage_at_3_5_in).truncate(1) end |
#watts_per_sqft_at_3_75_in_spacing ⇒ Object
Watts per sqft at 3 75 in spacing.
438 439 440 441 442 |
# File 'app/concerns/models/item_specification_helper.rb', line 438 def watts_per_sqft_at_3_75_in_spacing return unless watts && coverage_at_3_75_in (BigDecimal(watts.to_s) / coverage_at_3_75_in).truncate(1) end |
#watts_per_sqft_at_3_in_spacing ⇒ Object
Watts per sqft at 3 in spacing.
422 423 424 425 426 |
# File 'app/concerns/models/item_specification_helper.rb', line 422 def watts_per_sqft_at_3_in_spacing return unless watts && coverage_at_3_in (BigDecimal(watts.to_s) / coverage_at_3_in).truncate(1) end |
#watts_per_sqft_at_4_5_in_spacing ⇒ Object
Watts per sqft at 4 5 in spacing.
454 455 456 457 458 |
# File 'app/concerns/models/item_specification_helper.rb', line 454 def watts_per_sqft_at_4_5_in_spacing return unless watts && coverage_at_4_5_in (BigDecimal(watts.to_s) / coverage_at_4_5_in).truncate(1) end |
#watts_per_sqft_at_4_in_spacing ⇒ Object
Watts per sqft at 4 in spacing.
446 447 448 449 450 |
# File 'app/concerns/models/item_specification_helper.rb', line 446 def watts_per_sqft_at_4_in_spacing return unless watts && coverage_at_4_in (BigDecimal(watts.to_s) / coverage_at_4_in).truncate(1) end |
#watts_per_sqft_at_5_in_spacing ⇒ Object
Watts per sqft at 5 in spacing.
462 463 464 465 466 |
# File 'app/concerns/models/item_specification_helper.rb', line 462 def watts_per_sqft_at_5_in_spacing return unless watts && coverage_at_5_in (BigDecimal(watts.to_s) / coverage_at_5_in).truncate(1) end |
#watts_static? ⇒ Boolean
Whether watts static.
700 701 702 |
# File 'app/concerns/models/item_specification_helper.rb', line 700 def watts_static? rendered_specifications.dig(:watts, :static).to_b end |
#width(output_unit: :in) ⇒ Object
Width.
218 219 220 |
# File 'app/concerns/models/item_specification_helper.rb', line 218 def width(output_unit: :in) spec_value(:width, output_unit:) end |
#width=(val, unit: :in) ⇒ void
This method returns an undefined value.
Sets the width.
226 227 228 |
# File 'app/concerns/models/item_specification_helper.rb', line 226 def width=(val, unit: :in) create_or_set_spec_value(token: :width, name: 'Width', units: unit.to_s, grouping: 'Product Dimensions', text_blurb: val) end |
#width_by_length_text ⇒ Object
Width by length text.
232 233 234 235 236 |
# File 'app/concerns/models/item_specification_helper.rb', line 232 def width_by_length_text return unless length && width "#{format('%.2g', width.to_f / 12)}′ x #{format('%d', length.to_f / 12)}′" end |
#width_by_length_text_2 ⇒ Object
Width by length text 2.
240 241 242 243 244 |
# File 'app/concerns/models/item_specification_helper.rb', line 240 def width_by_length_text_2 return unless length && width "#{format('%.2g', width.to_f / 12)}′ x #{format('%02d', length.to_f / 12)}′" end |
#width_by_length_text_3 ⇒ String?
For larger rolls
248 249 250 251 252 |
# File 'app/concerns/models/item_specification_helper.rb', line 248 def width_by_length_text_3 return unless length && width "#{format('%.2g', width.to_f / 12)}′ x #{format('%03d', length.to_f / 12)}′" end |
#width_formatted ⇒ Object
Width formatted.
876 877 878 |
# File 'app/concerns/models/item_specification_helper.rb', line 876 def width_formatted spec_output(:width) end |