Class: Item::Materials::Checks::SnowMelting

Inherits:
BaseService
  • Object
show all
Defined in:
app/services/item/materials/checks/snow_melting.rb

Overview

Service object: snow melting.

Defined Under Namespace

Classes: Result

Constant Summary collapse

SCV_DUAL_AMPS_THRESHOLD =

Threshold for scv dual amps.

16.0

Instance Method Summary collapse

Instance Method Details

#economy_paver_check(container, options) ⇒ Object (protected)

Test if we are looking at a room and if so if we have economy sm control group with paver, which is not recommended because economy uses slab sensor



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'app/services/item/materials/checks/snow_melting.rb', line 170

def economy_paver_check(container, options)
  unless container.instance_of?(::RoomConfiguration) && (container.floor_type.seo_key == "paver") && (economy_sm_control_lis = container.line_items.select { |li| ItemConstants::SNOWMELT_CONTROL_BUNDLES_BY_GROUP["SCE"].include?(li.sku) }).any?
    return []
  end

  material_alerts = []
  Rails.logger.debug do
    "#{container.class.name}:#{container.id}: get_snow_melting_material_alerts, container.floor_type.name: #{container.floor_type.name}, economy_sm_control_lis: #{economy_sm_control_lis.map do |li|
      [li.quantity, li.sku]
    end.inspect}"
  end
  items = economy_sm_control_lis.map(&:item)
  if items.any? && items.all? { |item| container.catalog.catalog_items.by_skus(item.sku).first.present? }
    ma_options = {}.merge(options)
    ma_options[:room] = container
    ma_options[:recommended_qty] = 0
    ma_options[:actual_qty] = 1
    ma_options[:items] = items
    ma_options[:unmaskable] = true
    ma_options[:name] = "Using the economy snow melting control with a paver surface is not recommended."
    material_alerts << Item::Materials::Alert.new(ma_options)
  end
  material_alerts
end

#get_sm_heating_elements(container) ⇒ Object (protected)



137
138
139
# File 'app/services/item/materials/checks/snow_melting.rb', line 137

def get_sm_heating_elements(container)
  container.line_items.heating_elements.select { |li| li.item&.is_snow_melting_product? }
end

#locality_check(container, options) ⇒ Object (protected)

Test if we are looking at a room and if so if we are installing in RI or NY because they require an OT sensor on the pavement ie we require SCP sm control group



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
# File 'app/services/item/materials/checks/snow_melting.rb', line 142

def locality_check(container, options)
  unless container.respond_to?(:installation_state_code) && container.installation_state_code.present? && %w[RI NY].include?(container.installation_state_code) && container.line_items.none? do |li|
    %w[SCP-120 SCE-120 SCPM-CO-120-3].include?(li.sku)
  end
    return []
  end

  material_alerts = []
  items = [Item.find_by(sku: "SCP-120")]
  items << Item.find_by(sku: "SCE-120") unless container.instance_of?(::RoomConfiguration) && (container.floor_type.seo_key == "paver")
  if items.any? && items.all? { |item| container.catalog.catalog_items.by_skus(item.sku).first.present? }
    ma_options = {}.merge(options)
    ma_options[:room] = container
    ma_options[:group_type] = "snow_melting_controls"
    ma_options[:group_name] = "Snow Melting Controls"
    ma_options[:recommended_qty] = 1
    ma_options[:actual_qty] = 0
    ma_options[:items] = items
    ma_options[:unmaskable] = true
    names_arr = items.map(&:public_name)
    ma_options[:name] =
      "Using the #{names_arr.join(' or ')} is strongly recommended because of state building and electrical codes in #{container.installation_state_code}, which require shutting off the system when the surface temperature exceeds a certain threshhold. The #{names_arr.join(' and ')} #{names_arr.length > 1 ? 'are' : 'is'} capable of sensing the surface temperature."
    material_alerts << Item::Materials::Alert.new(ma_options)
  end
  material_alerts
end

#process(container:, options: {}) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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
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
131
132
133
# File 'app/services/item/materials/checks/snow_melting.rb', line 18

def process(container:, options: {})
  sm_heating_elements = get_sm_heating_elements(container)
  return Result.new(status: :skipped) unless qualify?(container) && sm_heating_elements.present?

  material_alerts = []
  # first test if we have any snow melt products
  # get actual sm controls in the line items
  all_bundled_sm_skus = ItemConstants::SNOWMELT_CONTROL_SKUS
  all_controls_sm_skus = ItemConstants::SNOWMELT_CONTROL_TSTAT_SKUS
  controls = container.line_items.select { |li| all_controls_sm_skus.include?(li.sku) }
  # get actual relay panels
  relay_panels = container.line_items.relay_panels
  # get current of the sm heating system
  current = sm_heating_elements.to_a.sum { |li| li.item.amps * li.quantity.to_f }
  # next test if we have more sm controls than we have sm heating elements
  num_controls = controls.sum(&:quantity)
  num_heating_elements = sm_heating_elements.sum(&:quantity)
  if num_controls > num_heating_elements
    ma_options = {}.merge(options)
    ma_options[:room] = container
    ma_options[:recommended_qty] = num_heating_elements
    ma_options[:actual_qty] = num_controls
    ma_options[:items] = controls.filter_map(&:item)
    ma_options[:unmaskable] = true
    ma_options[:name] = "At least one heating element per control is recommended."
    material_alerts << Item::Materials::Alert.new(ma_options)
  end
  if (num_controls == 0) && (num_heating_elements > 0)
    ma_options = {}.merge(options)
    ma_options[:room] = container
    ma_options[:recommended_qty] = 1
    ma_options[:actual_qty] = num_controls
    ma_options[:items] = Item.where(sku: all_controls_sm_skus).to_a
    ma_options[:unmaskable] = true
    ma_options[:name] = "At least one Snow Melting control is recommended."
    material_alerts << Item::Materials::Alert.new(ma_options)
  end

  material_alerts += locality_check(container, options)

  material_alerts += economy_paver_check(container, options)

  # next test for each sm control we have
  ItemConstants::SNOWMELT_CONTROL_BUNDLES_BY_GROUP.select { |_k, v| controls.any? { |li| v.include?(li.sku) } }.each do |group_sku, bundled_sm_skus|
    # if we have sm control group items in both the bundled group and outside the bundled group, it is not recommended
    sm_control = Item.find_by(sku: ItemConstants::SNOWMELT_CONTROL_BUNDLES_BY_GROUP[group_sku].first)
    if (non_group_bundle_lis = container.line_items.select { |li| (all_bundled_sm_skus - bundled_sm_skus).include?(li.sku) }).any?
      # we do, so set up the alert
      ma_options = {}.merge(options)
      ma_options[:room] = container
      ma_options[:recommended_qty] = 0
      ma_options[:actual_qty] = 1
      ma_options[:unmaskable] = true
      items = non_group_bundle_lis.filter_map(&:item)
      ma_options[:name] = "Using the following items is not recommended with the #{ItemConstants::SNOWMELT_CONTROL_BUNDLE_SKU_NAME_HASH[group_sku]} snow melting control:"
      ma_options[:items] = items
      material_alerts << Item::Materials::Alert.new(ma_options)
    end
    # if we have sm controls but not the other group items, it is not recommended
    bundled_skus_not_in_lis = bundled_sm_skus.select { |sku| container.line_items.find { |li| li.sku == sku }.nil? }
    next unless bundled_skus_not_in_lis.any?

    # we are missing some skus, so set up the alert
    items = bundled_skus_not_in_lis.map { |sku| Item.find_by(sku: sku) }
    next unless items.any? && items.all? { |item| container.catalog.catalog_items.by_skus(item.sku).first.present? }

    ma_options = {}.merge(options)
    ma_options[:room] = container
    ma_options[:recommended_qty] = controls.select { |li| li.sku == sm_control.sku }.sum(&:quantity)
    ma_options[:actual_qty] = 0
    ma_options[:unmaskable] = true
    ma_options[:name] = "The following items are recommended with the #{ItemConstants::SNOWMELT_CONTROL_BUNDLE_SKU_NAME_HASH[group_sku]} snow melting control:"
    ma_options[:items] = items
    material_alerts << Item::Materials::Alert.new(ma_options)
  end
  # check relay panels and RCO if we have controls
  if controls.any?
    # set minimum recommended relay panels, unless SCV control only and current under 16 amps
    poles = if (controls.length == 1) && (controls.first.sku == "SCV-DUAL") && (current < SCV_DUAL_AMPS_THRESHOLD)
              0
            else
              # get number of poles in the sm heating system
              sm_heating_elements.to_a.sum { |li| (Item::DOUBLE_POLE_VOLTAGES.include?(li.item.voltage) || li.item.amps > 15.0 ? 2 : 1).round * li.quantity }
            end
    # get relay_panels required from poles
    # first test if we have enough
    actual_poles = relay_panels.to_a.sum { |li| li.num_poles.to_i * li.quantity }
    if actual_poles != poles
      relay_panels_sku_qty = HeatingElementProductLineOption.get_relay_panels_from_poles(poles)
      relay_panels_sku_qty.each do |sku, qty|
        actual_qty = relay_panels.select { |li| li.sku == sku }.sum(&:quantity)
        next unless (qty != actual_qty) && container.catalog.catalog_items.by_skus(sku).first.present? && (item = Item.find_by(sku: sku)).present?

        ma_options = {}.merge(options)
        ma_options[:room] = container
        ma_options[:recommended_qty] = qty
        ma_options[:actual_qty] = actual_qty
        ma_options[:items] = [item]
        ma_options[:unmaskable] = true
        material_alerts << Item::Materials::Alert.new(ma_options)
      end
    end
    rcos = container.line_items.select { |li| li.sku == "RCO" }
    if rcos.any? && controls.find { |li| %w[SCP-120 SCA-DUAL].include?(li.sku) }.nil? && (item = Item.find_by(sku: "RCO")).present?
      ma_options = {}.merge(options)
      ma_options[:room] = container
      ma_options[:recommended_qty] = 0
      ma_options[:actual_qty] = rcos.sum(&:quantity)
      ma_options[:items] = [item]
      ma_options[:unmaskable] = true
      ma_options[:name] = "The RCO is only compatible with Premium and Advanced snow melting controls."
      material_alerts << Item::Materials::Alert.new(ma_options)
    end
  end
  Result.new(status: :ok, alerts: material_alerts)
end

#qualify?(container) ⇒ Boolean

Returns:

  • (Boolean)


13
14
15
16
# File 'app/services/item/materials/checks/snow_melting.rb', line 13

def qualify?(container)
  # we only apply this test when a container is a room or is a quote or order with no rooms, ie a single system
  container.is_a?(RoomConfiguration) || (container.respond_to?(:room_configurations) && container.room_configurations.empty?)
end