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 byMaintenance::ItemMaintenance#consolidate_specs.
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. %i[watts voltage amps ohms].freeze
Instance Method Summary collapse
- #amps ⇒ Object
- #amps=(val) ⇒ Object
- #amps_static? ⇒ Boolean
- #area(output_unit: :sqft) ⇒ Object
- #aspect ⇒ Object
- #btu_per_hour ⇒ Object
- #calculate_amps(precision: 2) ⇒ Object
- #calculate_coverage_for_membrane(output_unit: :sqft) ⇒ Object
- #calculate_geometric_sqft ⇒ Object
-
#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_sqm_for_panels ⇒ Object
- #calculate_kilowatts(precision: 2) ⇒ Object
- #calculate_number_of_fixing_strips_at_3_in ⇒ Object
- #calculate_number_of_fixing_strips_at_4_in ⇒ Object
- #calculate_number_of_fixing_strips_at_5_in ⇒ Object
- #calculate_number_of_fixing_strips_at_cable_spacing(spacing_in_inches = 4) ⇒ Object
- #calculate_ohms(precision: 2) ⇒ Object
- #calculate_ohms_per_ft ⇒ Object
- #calculate_size_2d(output_unit: nil, precision: nil) ⇒ Object
- #calculate_size_2d_ft ⇒ Object
- #calculate_size_2d_in ⇒ Object
- #calculate_size_2d_metric_cm ⇒ Object
- #calculate_size_2d_metric_mm ⇒ Object
- #calculate_size_3d(output_unit: nil, precision: nil) ⇒ Object
- #calculate_size_3d_ft ⇒ Object
- #calculate_size_3d_in ⇒ Object
- #calculate_size_3d_metric_cm ⇒ Object
- #calculate_size_3d_metric_mm ⇒ Object
- #calculate_sqft(cable_spacing: nil, heated_area: true) ⇒ Object
-
#calculate_thermal_power_per_hour ⇒ Object
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
- #can_use_amps_for_calculation? ⇒ Boolean
- #can_use_ohms_for_calculation? ⇒ Boolean
- #can_use_voltage_for_calculation? ⇒ Boolean
- #can_use_watts_for_calculation? ⇒ Boolean
- #cold_lead_length ⇒ Object
- #cold_lead_length=(val) ⇒ Object
- #control_capacity ⇒ Object
- #coverage_at_3_5_in ⇒ Object
- #coverage_at_3_75_in ⇒ Object
- #coverage_at_3_in ⇒ Object
- #coverage_at_4_5_in ⇒ Object
- #coverage_at_4_in ⇒ Object
- #coverage_at_5_in ⇒ Object
- #coverage_formatted ⇒ Object
- #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
- #finish ⇒ Object
- #has_spec?(token) ⇒ Boolean
- #is_dual_voltage? ⇒ Boolean
- #length(output_unit: :in) ⇒ Object
- #length=(val, unit: :in) ⇒ Object
- #length_formatted ⇒ Object
-
#linear_ft ⇒ Object
memoize :calculate_sqft.
- #maximum_current ⇒ Object
- #num_poles ⇒ Object
- #ohms ⇒ Object
- #ohms=(val) ⇒ Object
- #ohms_law_calculator ⇒ Object
- #ohms_static? ⇒ Boolean
- #plan_grouping ⇒ Object
- #plan_grouping=(val) ⇒ Object
-
#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_output(token, locale: Mobility.locale) ⇒ Object
returns the formatted output from the spec.
- #spec_refresh_in_progress ⇒ Object
- #spec_unit(token) ⇒ Object
-
#spec_value(token, output_unit: nil, precision: nil) ⇒ Object
returns the raw value from the spec.
- #specs_for_identifier_label ⇒ Object
- #sqft ⇒ Object
- #sqft=(val) ⇒ Object
-
#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=(val) ⇒ Object
- #voltage_formatted ⇒ Object
- #voltage_static? ⇒ Boolean
- #volts ⇒ Object
- #volts=(val) ⇒ Object
- #vop ⇒ Object
- #watts ⇒ Object
- #watts=(val) ⇒ Object
- #watts_formatted ⇒ Object
- #watts_per_linear_feet(precision: 2) ⇒ Object
- #watts_per_sqft ⇒ Object
- #watts_per_sqft_at_3_5_in_spacing ⇒ Object
- #watts_per_sqft_at_3_75_in_spacing ⇒ Object
- #watts_per_sqft_at_3_in_spacing ⇒ Object
- #watts_per_sqft_at_4_5_in_spacing ⇒ Object
- #watts_per_sqft_at_4_in_spacing ⇒ Object
- #watts_per_sqft_at_5_in_spacing ⇒ Object
- #watts_static? ⇒ Boolean
- #width(output_unit: :in) ⇒ Object
- #width=(val, unit: :in) ⇒ Object
- #width_by_length_text ⇒ Object
- #width_by_length_text_2 ⇒ Object
-
#width_by_length_text_3 ⇒ Object
For larger rolls.
- #width_formatted ⇒ Object
Instance Method Details
#amps ⇒ Object
383 384 385 386 |
# File 'app/concerns/models/item_specification_helper.rb', line 383 def amps a = spec_value(:amps) a.is_a?(Numeric) ? a : nil end |
#amps=(val) ⇒ Object
388 389 390 |
# File 'app/concerns/models/item_specification_helper.rb', line 388 def amps=(val) create_or_set_spec_value(token: :amps, name: 'Amps', units: 'A', grouping: 'Electrical', text_blurb: val) end |
#amps_static? ⇒ Boolean
520 521 522 |
# File 'app/concerns/models/item_specification_helper.rb', line 520 def amps_static? rendered_product_specifications.dig(:amps, :static).to_b end |
#area(output_unit: :sqft) ⇒ Object
222 223 224 225 226 227 228 229 230 231 232 |
# File 'app/concerns/models/item_specification_helper.rb', line 222 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
655 656 657 658 659 660 661 662 663 664 665 |
# File 'app/concerns/models/item_specification_helper.rb', line 655 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
552 553 554 555 556 557 558 559 560 |
# File 'app/concerns/models/item_specification_helper.rb', line 552 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
411 412 413 |
# File 'app/concerns/models/item_specification_helper.rb', line 411 def calculate_amps(precision: 2) ohms_law_calculator.current&.round(precision) end |
#calculate_coverage_for_membrane(output_unit: :sqft) ⇒ Object
208 209 210 211 212 213 214 215 216 217 218 219 220 |
# File 'app/concerns/models/item_specification_helper.rb', line 208 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
587 588 589 |
# File 'app/concerns/models/item_specification_helper.rb', line 587 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.
189 190 191 192 193 194 195 196 197 198 |
# File 'app/concerns/models/item_specification_helper.rb', line 189 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
200 201 202 |
# File 'app/concerns/models/item_specification_helper.rb', line 200 def calculate_heated_area_sqft_for_panels calculate_heated_area_for_panels(output_unit: :sqft) end |
#calculate_heated_area_sqm_for_panels ⇒ Object
204 205 206 |
# File 'app/concerns/models/item_specification_helper.rb', line 204 def calculate_heated_area_sqm_for_panels calculate_heated_area_for_panels(output_unit: :sqm) end |
#calculate_kilowatts(precision: 2) ⇒ Object
478 479 480 481 482 |
# File 'app/concerns/models/item_specification_helper.rb', line 478 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
291 292 293 |
# File 'app/concerns/models/item_specification_helper.rb', line 291 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
295 296 297 |
# File 'app/concerns/models/item_specification_helper.rb', line 295 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
299 300 301 |
# File 'app/concerns/models/item_specification_helper.rb', line 299 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
278 279 280 281 282 283 284 285 286 287 288 289 |
# File 'app/concerns/models/item_specification_helper.rb', line 278 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
492 493 494 |
# File 'app/concerns/models/item_specification_helper.rb', line 492 def calculate_ohms(precision: 2) ohms_law_calculator.resistance&.round(precision) end |
#calculate_ohms_per_ft ⇒ Object
484 485 486 487 488 489 490 |
# File 'app/concerns/models/item_specification_helper.rb', line 484 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
425 426 427 428 429 430 431 432 433 |
# File 'app/concerns/models/item_specification_helper.rb', line 425 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
466 467 468 |
# File 'app/concerns/models/item_specification_helper.rb', line 466 def calculate_size_2d_ft calculate_size_2d(output_unit: 'ft', precision: 2) end |
#calculate_size_2d_in ⇒ Object
462 463 464 |
# File 'app/concerns/models/item_specification_helper.rb', line 462 def calculate_size_2d_in calculate_size_2d(output_unit: 'in', precision: 0) end |
#calculate_size_2d_metric_cm ⇒ Object
474 475 476 |
# File 'app/concerns/models/item_specification_helper.rb', line 474 def calculate_size_2d_metric_cm calculate_size_2d(output_unit: 'cm', precision: 0) end |
#calculate_size_2d_metric_mm ⇒ Object
470 471 472 |
# File 'app/concerns/models/item_specification_helper.rb', line 470 def calculate_size_2d_metric_mm calculate_size_2d(output_unit: 'mm', precision: 0) end |
#calculate_size_3d(output_unit: nil, precision: nil) ⇒ Object
435 436 437 438 439 440 441 442 443 444 |
# File 'app/concerns/models/item_specification_helper.rb', line 435 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
458 459 460 |
# File 'app/concerns/models/item_specification_helper.rb', line 458 def calculate_size_3d_ft calculate_size_3d(output_unit: 'ft', precision: 2) end |
#calculate_size_3d_in ⇒ Object
454 455 456 |
# File 'app/concerns/models/item_specification_helper.rb', line 454 def calculate_size_3d_in calculate_size_3d(output_unit: 'in', precision: 0) end |
#calculate_size_3d_metric_cm ⇒ Object
450 451 452 |
# File 'app/concerns/models/item_specification_helper.rb', line 450 def calculate_size_3d_metric_cm calculate_size_3d(output_unit: 'cm', precision: 0) end |
#calculate_size_3d_metric_mm ⇒ Object
446 447 448 |
# File 'app/concerns/models/item_specification_helper.rb', line 446 def calculate_size_3d_metric_mm calculate_size_3d(output_unit: 'mm', precision: 0) end |
#calculate_sqft(cable_spacing: nil, heated_area: true) ⇒ Object
591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 |
# File 'app/concerns/models/item_specification_helper.rb', line 591 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_product_specifications.dig(:coverage, :raw) if rendered_product_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 ⇒ Object
This is like btu per hour but kW
563 564 565 566 567 568 569 570 571 |
# File 'app/concerns/models/item_specification_helper.rb', line 563 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 (Ω):
416 417 418 |
# File 'app/concerns/models/item_specification_helper.rb', line 416 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):
421 422 423 |
# File 'app/concerns/models/item_specification_helper.rb', line 421 def calculate_watts(precision: 0) ohms_law_calculator.power&.round(precision) end |
#calculate_watts_per_sqft(precision: 2) ⇒ Object
577 578 579 580 581 582 583 584 585 |
# File 'app/concerns/models/item_specification_helper.rb', line 577 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
524 525 526 |
# File 'app/concerns/models/item_specification_helper.rb', line 524 def can_use_amps_for_calculation? amps_static? && amps && amps > 0 end |
#can_use_ohms_for_calculation? ⇒ Boolean
508 509 510 |
# File 'app/concerns/models/item_specification_helper.rb', line 508 def can_use_ohms_for_calculation? ohms_static? && ohms && ohms > 0 end |
#can_use_voltage_for_calculation? ⇒ Boolean
516 517 518 |
# File 'app/concerns/models/item_specification_helper.rb', line 516 def can_use_voltage_for_calculation? voltage_static? && voltage && voltage > 0 end |
#can_use_watts_for_calculation? ⇒ Boolean
500 501 502 |
# File 'app/concerns/models/item_specification_helper.rb', line 500 def can_use_watts_for_calculation? watts_static? && watts && watts > 0 end |
#cold_lead_length ⇒ Object
180 181 182 |
# File 'app/concerns/models/item_specification_helper.rb', line 180 def cold_lead_length spec_value(:cold_lead_length) end |
#cold_lead_length=(val) ⇒ Object
184 185 186 |
# File 'app/concerns/models/item_specification_helper.rb', line 184 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
544 545 546 |
# File 'app/concerns/models/item_specification_helper.rb', line 544 def control_capacity (maximum_current || 0) * (num_poles || 1) end |
#coverage_at_3_5_in ⇒ Object
248 249 250 251 252 |
# File 'app/concerns/models/item_specification_helper.rb', line 248 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
254 255 256 257 258 |
# File 'app/concerns/models/item_specification_helper.rb', line 254 def coverage_at_3_75_in return unless (l = linear_ft) (l.to_f * 0.3125).round(1) end |
#coverage_at_3_in ⇒ Object
242 243 244 245 246 |
# File 'app/concerns/models/item_specification_helper.rb', line 242 def coverage_at_3_in return unless (l = linear_ft) (l.to_f * 0.25).round(1) end |
#coverage_at_4_5_in ⇒ Object
266 267 268 269 270 |
# File 'app/concerns/models/item_specification_helper.rb', line 266 def coverage_at_4_5_in return unless (l = linear_ft) (l.to_f * 0.375).round(1) end |
#coverage_at_4_in ⇒ Object
260 261 262 263 264 |
# File 'app/concerns/models/item_specification_helper.rb', line 260 def coverage_at_4_in return unless (l = linear_ft) (l.to_f * 0.333333).round(1) end |
#coverage_at_5_in ⇒ Object
272 273 274 275 276 |
# File 'app/concerns/models/item_specification_helper.rb', line 272 def coverage_at_5_in return unless (l = linear_ft) (l.to_f * 0.416667).round(1) end |
#coverage_formatted ⇒ Object
643 644 645 |
# File 'app/concerns/models/item_specification_helper.rb', line 643 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
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'app/concerns/models/item_specification_helper.rb', line 70 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 } attrs[:do_not_merge] = true if PER_ITEM_SPEC_TOKENS.include?(token) # 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
573 574 575 |
# File 'app/concerns/models/item_specification_helper.rb', line 573 def finish rendered_product_specifications.dig(:finish, :output) end |
#has_spec?(token) ⇒ Boolean
10 11 12 13 14 |
# File 'app/concerns/models/item_specification_helper.rb', line 10 def has_spec?(token) return false if rendered_product_specifications.nil? rendered_product_specifications[token.to_sym].present? end |
#is_dual_voltage? ⇒ Boolean
548 549 550 |
# File 'app/concerns/models/item_specification_helper.rb', line 548 def is_dual_voltage? spec_value(:dual_voltage) and spec_value(:dual_voltage).to_s.downcase.first != 'f' end |
#length(output_unit: :in) ⇒ Object
145 146 147 |
# File 'app/concerns/models/item_specification_helper.rb', line 145 def length(output_unit: :in) spec_value(:length, output_unit:) end |
#length=(val, unit: :in) ⇒ Object
149 150 151 |
# File 'app/concerns/models/item_specification_helper.rb', line 149 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
631 632 633 |
# File 'app/concerns/models/item_specification_helper.rb', line 631 def length_formatted spec_output(:length) end |
#linear_ft ⇒ Object
memoize :calculate_sqft
618 619 620 621 622 623 624 |
# File 'app/concerns/models/item_specification_helper.rb', line 618 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
536 537 538 |
# File 'app/concerns/models/item_specification_helper.rb', line 536 def maximum_current spec_value(:maximum_current) || spec_value(:maximum_current_per_relay) if is_control? || is_power? end |
#num_poles ⇒ Object
540 541 542 |
# File 'app/concerns/models/item_specification_helper.rb', line 540 def num_poles spec_value(:numbers_of_poles) if is_relay_panel? || is_legacy_relay? end |
#ohms ⇒ Object
355 356 357 358 |
# File 'app/concerns/models/item_specification_helper.rb', line 355 def ohms o = spec_value(:ohms) o.is_a?(Numeric) ? o.round(4) : nil end |
#ohms=(val) ⇒ Object
360 361 362 |
# File 'app/concerns/models/item_specification_helper.rb', line 360 def ohms=(val) create_or_set_spec_value(token: :ohms, name: 'Ohms', units: 'ohm', grouping: 'Electrical', text_blurb: val) end |
#ohms_law_calculator ⇒ Object
400 401 402 403 404 405 406 407 408 409 |
# File 'app/concerns/models/item_specification_helper.rb', line 400 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
504 505 506 |
# File 'app/concerns/models/item_specification_helper.rb', line 504 def ohms_static? rendered_product_specifications.dig(:ohms, :static).to_b end |
#plan_grouping ⇒ Object
528 529 530 |
# File 'app/concerns/models/item_specification_helper.rb', line 528 def plan_grouping spec_value(:plan_grouping) end |
#plan_grouping=(val) ⇒ Object
532 533 534 |
# File 'app/concerns/models/item_specification_helper.rb', line 532 def plan_grouping=(val) create_or_set_spec_value(token: :plan_grouping, name: 'Plan Grouping', grouping: 'Logistics', visibility: 'internal', text_blurb: val) end |
#set_spec_value(token, value) ⇒ Object
Finds a direct product spec and sets the value.
55 56 57 58 59 60 61 62 |
# File 'app/concerns/models/item_specification_helper.rb', line 55 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
18 19 20 21 22 23 24 |
# File 'app/concerns/models/item_specification_helper.rb', line 18 def spec(token) return if rendered_product_specifications.nil? return unless (ps = rendered_product_specifications[token.to_sym]) ps[:raw] = TypeCoercer.coerce(ps[:raw]) ps end |
#spec_image(token) ⇒ Object
139 140 141 142 143 |
# File 'app/concerns/models/item_specification_helper.rb', line 139 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
133 134 135 136 137 |
# File 'app/concerns/models/item_specification_helper.rb', line 133 def spec_output(token, locale: Mobility.locale) Mobility.with_locale(locale) do spec(token)&.dig(:output)&.dup end end |
#spec_refresh_in_progress ⇒ Object
26 27 28 |
# File 'app/concerns/models/item_specification_helper.rb', line 26 def spec_refresh_in_progress BackgroundJobStatus.search(worker_klass: 'ItemAttributeWorker', args: id).present? end |
#spec_unit(token) ⇒ Object
47 48 49 50 51 52 |
# File 'app/concerns/models/item_specification_helper.rb', line 47 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
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'app/concerns/models/item_specification_helper.rb', line 31 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
647 648 649 650 651 652 653 |
# File 'app/concerns/models/item_specification_helper.rb', line 647 def specs_for_identifier_label hsh = {} specifications_for_item_label.each do |rps| hsh[rps.name] = rps.output end hsh end |
#sqft ⇒ Object
234 235 236 |
# File 'app/concerns/models/item_specification_helper.rb', line 234 def sqft area(output_unit: :sqft) end |
#sqft=(val) ⇒ Object
238 239 240 |
# File 'app/concerns/models/item_specification_helper.rb', line 238 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
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 |
# File 'app/concerns/models/item_specification_helper.rb', line 671 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
364 365 366 367 |
# File 'app/concerns/models/item_specification_helper.rb', line 364 def voltage v = spec_value(:voltage) v.is_a?(Numeric) ? v : nil end |
#voltage=(val) ⇒ Object
369 370 371 |
# File 'app/concerns/models/item_specification_helper.rb', line 369 def voltage=(val) create_or_set_spec_value(token: :voltage, name: 'Voltage', units: 'V', grouping: 'Electrical', text_blurb: val) end |
#voltage_formatted ⇒ Object
635 636 637 |
# File 'app/concerns/models/item_specification_helper.rb', line 635 def voltage_formatted spec_output(:voltage) end |
#voltage_static? ⇒ Boolean
512 513 514 |
# File 'app/concerns/models/item_specification_helper.rb', line 512 def voltage_static? rendered_product_specifications.dig(:voltage, :static).to_b end |
#volts ⇒ Object
373 374 375 376 |
# File 'app/concerns/models/item_specification_helper.rb', line 373 def volts logger.warn 'Deprecated method volts, use voltage instead' voltage end |
#volts=(val) ⇒ Object
378 379 380 381 |
# File 'app/concerns/models/item_specification_helper.rb', line 378 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
392 393 394 |
# File 'app/concerns/models/item_specification_helper.rb', line 392 def vop spec_value(:vop) end |
#watts ⇒ Object
345 346 347 348 349 |
# File 'app/concerns/models/item_specification_helper.rb', line 345 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) ⇒ Object
351 352 353 |
# File 'app/concerns/models/item_specification_helper.rb', line 351 def watts=(val) create_or_set_spec_value(token: :watts, name: 'Watts', units: 'W', grouping: 'Electrical', text_blurb: val) end |
#watts_formatted ⇒ Object
639 640 641 |
# File 'app/concerns/models/item_specification_helper.rb', line 639 def watts_formatted spec_output(:watts) end |
#watts_per_linear_feet(precision: 2) ⇒ Object
339 340 341 342 343 |
# File 'app/concerns/models/item_specification_helper.rb', line 339 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
396 397 398 |
# File 'app/concerns/models/item_specification_helper.rb', line 396 def watts_per_sqft spec_value(:watts_per_sqft) || calculate_watts_per_sqft end |
#watts_per_sqft_at_3_5_in_spacing ⇒ Object
309 310 311 312 313 |
# File 'app/concerns/models/item_specification_helper.rb', line 309 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
315 316 317 318 319 |
# File 'app/concerns/models/item_specification_helper.rb', line 315 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
303 304 305 306 307 |
# File 'app/concerns/models/item_specification_helper.rb', line 303 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
327 328 329 330 331 |
# File 'app/concerns/models/item_specification_helper.rb', line 327 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
321 322 323 324 325 |
# File 'app/concerns/models/item_specification_helper.rb', line 321 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
333 334 335 336 337 |
# File 'app/concerns/models/item_specification_helper.rb', line 333 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
496 497 498 |
# File 'app/concerns/models/item_specification_helper.rb', line 496 def watts_static? rendered_product_specifications.dig(:watts, :static).to_b end |
#width(output_unit: :in) ⇒ Object
153 154 155 |
# File 'app/concerns/models/item_specification_helper.rb', line 153 def width(output_unit: :in) spec_value(:width, output_unit:) end |
#width=(val, unit: :in) ⇒ Object
157 158 159 |
# File 'app/concerns/models/item_specification_helper.rb', line 157 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
161 162 163 164 165 |
# File 'app/concerns/models/item_specification_helper.rb', line 161 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
167 168 169 170 171 |
# File 'app/concerns/models/item_specification_helper.rb', line 167 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 ⇒ Object
For larger rolls
174 175 176 177 178 |
# File 'app/concerns/models/item_specification_helper.rb', line 174 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
627 628 629 |
# File 'app/concerns/models/item_specification_helper.rb', line 627 def width_formatted spec_output(:width) end |