Class: HeatingSystemCalculator::BaseCalculator

Inherits:
Object
  • Object
show all
Includes:
Service
Defined in:
app/services/heating_system_calculator/base_calculator.rb

Overview

Service object: base calculator.

Instance Method Summary collapse

Methods included from Service

#attributes_used, #build_result, call, #logger

Constructor Details

#initialize(attributes) ⇒ BaseCalculator

Returns a new instance of BaseCalculator.



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'app/services/heating_system_calculator/base_calculator.rb', line 40

def initialize(attributes)
  # super() with no args initializes @attributes (ActiveModel::Attributes) without
  # calling assign_attributes on the incoming hash. BaseCalculator receives a superset
  # of its own attribute names (CalculateQuote passes attributes_used which includes
  # catalog_id, currency, cable_spacings, etc.), so bulk-assigning via super would
  # raise ActiveModel::UnknownAttributeError. We assign only what this class declares.
  super()
  self.require_expansion_joint = attributes[:require_expansion_joint]
  self.expansion_joint_spacing = attributes[:expansion_joint_spacing]
  self.skip_expansion_joint    = attributes[:skip_expansion_joint]
  self.heated_area = HeatedArea.new(attributes)
  return self if heated_area.error

  self.heating_system = HeatingSystem.new(attributes.merge(heated_area:))
  return self if heating_system.error

  self.heating_system_items = HeatingSystemItems.new(attributes.merge(heated_area:).merge(heating_system:))
  self if heating_system_items.error
end

Instance Method Details

#calculate_elementsObject



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'app/services/heating_system_calculator/base_calculator.rb', line 96

def calculate_elements
  case element_calculation_method
  when :classic_recursive
    element_res = ElementFinderByArea.new({ element_set: heating_system_items.element_set }).calculate_elements_for_heated_area_sqft(
      heated_area.heated_area_sqft, heated_area.insulation_surface
    )
  when :zone_fit
    exp_joint_sp = require_expansion_joint ? expansion_joint_spacing : nil
    skip_exp_joint = require_expansion_joint ? skip_expansion_joint : nil
    element_type = :mat
    cable_sp = nil
    if heating_system.heating_system_product_line.is_cable_system?
      element_type = :cable
      cable_sp = heating_system.cable_spacing
    end
    element_res = ElementFinderByZones.new({ element_set: heating_system_items.element_set, expansion_joint_spacing: exp_joint_sp, skip_expansion_joint: skip_exp_joint, element_type:, cable_spacing: cable_sp }).fit_elements_into_heated_area_zones(
      heated_area.zones, heated_area.heated_area_sqft
    )
  end
  element_res
end

#calculate_systemObject



60
61
62
63
64
65
66
67
68
69
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
# File 'app/services/heating_system_calculator/base_calculator.rb', line 60

def calculate_system
  return report_error(heated_area.error.merge({ params: attributes })) if heated_area.error
  return report_error(heating_system.error.merge({ params: attributes })) if heating_system.error
  return report_error(heating_system_items.error.merge({ params: attributes })) if heating_system_items.error

  case element_calculation_method
  when :unsupported
    return report_error({ error_status: :unsupported, error_message: 'Heating System Calculator system type not supported at this time.',
                          params: attributes })
  when :no_solutions_possible
    return report_error({ error_status: :no_solutions_found, error_message: 'Heating System Calculator could find no solutions.',
                          params: attributes })
  else
    elements_result = calculate_elements
  end
  return elements_result.error.merge({ params: attributes, found_solution: false }).with_indifferent_access if elements_result.error

  if elements_result.coverage_percentage < 70.0
    # valid solution must covers 70% or more
    return report_error({ error_status: :no_solutions_found,
                          error_message: 'Heating System Calculator could find no solutions to cover 70 % or more of the desired heated area.', params: attributes })
  end

  controls_result = find_controls(elements_result.elements)
  return report_error(controls_result.error.merge({ params: attributes, found_solution: false })) if controls_result.error

  accessories_result = find_accessories(elements_result.elements, controls_result.controls)
  return report_error(accessories_result.error.merge({ params: attributes, found_solution: false })) if accessories_result.error

  smart_services_result = find_smart_services(elements_result.elements, controls_result.controls, accessories_result.accessories)
  return report_error(smart_services_result.error.merge({ params: attributes, found_solution: false })) if smart_services_result.error

  { elements: elements_result.elements, coverage_percentage: elements_result.coverage_percentage, target_area: elements_result.target_area,
    controls: controls_result.controls, accessories: accessories_result.accessories, smart_services: smart_services_result.smart_services, found_solution: true }.with_indifferent_access
end

#element_calculation_methodObject



143
144
145
146
147
148
149
150
151
152
# File 'app/services/heating_system_calculator/base_calculator.rb', line 143

def element_calculation_method
  res = :unsupported
  tire_tracks_states = %w[tire_tracks_legacy tire_tracks]
  if ['TempZone Flex Roll', 'Environ Flex Roll', 'Slab Heat Mat', 'Slab Heat Cable', 'TempZone Cable', 'TempZone Ruler Cable', 'TempZone Thin Cable'].include?(heating_system.heating_system_type_name) || (heating_system.heating_system_product_line&.snow_melt? && !(tire_tracks_states.include?(heated_area.coverage_state) || require_expansion_joint)) # only use this classic_recursive algorithm with snow melt mat or cable if we are *not* covering tire tracks
    res = :classic_recursive # this classic_recursive algorithm assumes the heating elements can be cut/flipped/turned to fill the equivalent square footage, and so ignores zone information
  elsif ['Environ Easy Mat', 'TempZone Easy Mat'].include?(heating_system.heating_system_type_name) || (heating_system.heating_system_product_line&.snow_melt? && (tire_tracks_states.include?(heated_area.coverage_state) || require_expansion_joint)) # only use this zone_fit algorithm with snow melt mat if we are covering tire tracks
    res = :zone_fit
  end
  res
end

#find_accessories(elements, controls) ⇒ Object



131
132
133
134
135
# File 'app/services/heating_system_calculator/base_calculator.rb', line 131

def find_accessories(elements, controls)
  AccessoriesFinder.new({ heated_area:, heating_system:, accessory_set: heating_system_items.accessory_set, underlayment_set: heating_system_items.underlayment_set, rough_in_kit_for_tstat: heating_system_items.rough_in_kit_for_tstat, rough_in_kit_for_power_module: heating_system_items.rough_in_kit_for_power_module }).find_accessories(
    elements, controls
  )
end

#find_controls(elements) ⇒ Object



118
119
120
121
122
123
124
125
126
127
128
129
# File 'app/services/heating_system_calculator/base_calculator.rb', line 118

def find_controls(elements)
  case heating_system.heating_system_product_line.snow_melt?
  when true
    SnowMeltingControlsFinder.new({ control_set: heating_system_items.control_set, sensor_set: heating_system_items.sensor_set, power_set: heating_system_items.power_set }).find_controls_for_elements(
      elements, heating_system.voltage.id
    )
  else
    FloorHeatingControlsFinder.new({ control_set: heating_system_items.control_set, power_set: heating_system_items.power_set }).find_controls_for_elements(
      elements, heating_system.voltage.id
    )
  end
end

#find_smart_services(elements, controls, accessories) ⇒ Object



137
138
139
140
141
# File 'app/services/heating_system_calculator/base_calculator.rb', line 137

def find_smart_services(elements, controls, accessories)
  SmartServicesFinder.new({ heated_area:, heating_system:, accessory_set: heating_system_items.accessory_set, smart_service_set: heating_system_items.smart_service_set, underlayment_set: heating_system_items.underlayment_set, rough_in_kit_for_tstat: heating_system_items.rough_in_kit_for_tstat, rough_in_kit_for_power_module: heating_system_items.rough_in_kit_for_power_module }).find_smart_services(
    elements, controls, accessories
  )
end

#report_error(error_hash) ⇒ Object



154
155
156
157
# File 'app/services/heating_system_calculator/base_calculator.rb', line 154

def report_error(error_hash)
  self.error = error_hash.merge({ found_solution: false }).with_indifferent_access
  error
end