Class: Item::Materials::Checks::RoofDeicing

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

Overview

For Self Regulating Cable only

Defined Under Namespace

Classes: Result

Constant Summary collapse

MAX_FT_PER_30_AMP_CIRCUIT_120V_R_G_DEICING_CABLE =
214.0

Instance Method Summary collapse

Instance Method Details

#container_or_rooms_have_floor_type_but_no_line_items_with_sku_fragment?(container, floor_type_test, sku_fragment) ⇒ Boolean

Returns:

  • (Boolean)


18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'app/services/item/materials/checks/roof_deicing.rb', line 18

def container_or_rooms_have_floor_type_but_no_line_items_with_sku_fragment?(container, floor_type_test, sku_fragment)
  res = false
  rooms = []
  if container.is_a?(RoomConfiguration)
    rooms << container
  else
    container.try(:room_configurations).each do |rc|
      rooms << rc
    end
  end
  rooms.each do |rc|
    if (rc.floor_type.try(floor_type_test) and container.line_items.where(room_configuration_id: rc.id).to_a.select{|li| li.item.sku.index(sku_fragment)}.empty?)
      res = true
      break
    end
  end
  return res
end

#get_rg_heating_elements(container) ⇒ Object



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

def get_rg_heating_elements(container)
  container.line_items.heating_elements.by_product_line_url(ProductLineUrls::ROOF_GUTTER_DEICING_SELF_REGULATING)
end

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



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

def process(container:, options:{})
  return Result.new(status: :skipped) unless qualify?(container)

  material_alerts = []
  rg_heating_elements = get_rg_heating_elements(container)
  # get actual sm controls in the line items
  all_bundled_rg_skus = DEICING_CONTROL_BUNDLES_BY_GROUP.map{|k,v| v}.flatten
  all_controls_rg_skus = DEICING_CONTROL_BUNDLES_BY_GROUP.map{|k,v| v.first}
  controls = container.line_items.select{|li| all_controls_rg_skus.include?(li.sku)}
  # get actual relay panels
  relay_panels = container.line_items.relay_panels
  # next test if we have more sm controls than we have sm heating elements
  if (num_controls = controls.sum{|li| li.quantity}) > (num_heating_elements = rg_heating_elements.sum{|li| li.quantity})
    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.map{|li| li.item}.compact
    ma_options[:name] = "At least one heating element per control is recommended."
    material_alerts << Item::Materials::Alert.new(ma_options)
  end
  # next test for each rg control we have
  DEICING_CONTROL_BUNDLES_BY_GROUP.select{|k,v| controls.any?{|li| v.include?(li.sku)}}.each do |group_sku, bundled_rg_skus|
    # if we have sm control group items in both the bundled group and outside the bundled group, it is not recommended
    rg_control = Item.find_by(sku: DEICING_CONTROL_BUNDLES_BY_GROUP[group_sku].first)
    if (non_group_bundle_lis = container.line_items.select{|li| (all_bundled_rg_skus - bundled_rg_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
      items = non_group_bundle_lis.map{|li| li.item}.compact
      ma_options[:name] = "Using the following items is not recommended with the #{DEICING_CONTROL_BUNDLE_SKU_NAME_HASH[group_sku]} roof and gutter deicing control:"
      ma_options[:items] = items
      ma_options[:unmaskable] = true
      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_rg_skus.select{|sku| container.line_items.detect{|li| li.sku == sku}.nil?}
    if bundled_skus_not_in_lis.any?
      items = bundled_skus_not_in_lis.map{|sku| Item.find_by(sku: sku)}
      # we are missing some skus, so set up the alert
      if items.any? and 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 == rg_control.sku}.sum{|li| li.quantity}
        ma_options[:actual_qty] = 0
        ma_options[:name] = "The following items are recommended with the #{DEICING_CONTROL_BUNDLE_SKU_NAME_HASH[group_sku]} roof and gutter deicing control:"
        ma_options[:items] = items
        ma_options[:unmaskable] = true
        material_alerts << Item::Materials::Alert.new(ma_options)
      end
    end
  end
  # check relay panels and RCO if we have controls
  if controls.any?
    # get minimum number of poles in the rg heating system
    # roof/gutter deicing heating elements are sold in line items of quantities of 1 foot, so for e.g. 1000 of ET-SR-120, but we do not know at this point how this cable will be cut and into how many sub-zones, thus we don't know the number of heating elements. We can, however, guess the minimum number of heating elements by the maximum number of feet for a given 30 amp circuit (ie per voltage).
    # we start by counting the number of feet of rg cable of each voltage
    volts_arr = container.line_items.heating_elements.collect{|li| li.item.voltage}.uniq
    qtys_arr = volts_arr.map{|v| container.line_items.heating_elements.with_product_specification(:voltage, v).to_a.select{|li| li.item.product_lines.any?{|pl| pl.roof_deicing?}}.sum{|li| li.quantity}}
    # now count the poles, for 240V we double the max number of feet per circuit (this will halve the number of circuits), but then it will double the number of poles so voltage cancels out in the pole calculation, as long as you separate out the voltages beforehand since they can't be part of the same circuit. Find the minimum number of poles by rounding up ie ceiling.
    poles = 0
    qtys_arr.each_with_index do |q, i|
      poles += (q/MAX_FT_PER_30_AMP_CIRCUIT_120V_R_G_DEICING_CABLE).ceil
    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{|li| li.quantity}
        if qty != actual_qty and container.catalog.catalog_items.by_skus(sku).first.present? and (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
    end
    rcos = container.line_items.select{|li| li.sku == "RCO"}
    if rcos.any? and controls.detect{|li| ["SCA-DUAL"].include?(li.sku)}.nil? and (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{|li| li.quantity}
      ma_options[:items] = [item]
      ma_options[:unmaskable] = true
      ma_options[:name] = "The RCO is only compatible with the Advanced roof and gutter deicing control."
      material_alerts << Item::Materials::Alert.new(ma_options)
    end
  end
  if container_or_rooms_have_floor_type_but_no_line_items_with_sku_fragment?(container, :is_slate_shingle?, "ET-CL-CU-SLS") and (items = Item.available_to_public.where("items.sku ilike '%ET-CL-CU-SLS%'")).any?
    ma_options = {}.merge(options)
    ma_options[:room] = container
    ma_options[:recommended_qty] = 1
    ma_options[:actual_qty] = 0
    ma_options[:items] = items
    ma_options[:unmaskable] = true
    ma_options[:name] = "We recommend one of these special order copper 3-prong roof clips with Slate shingle roof and roof and gutter deicing."
    material_alerts << Item::Materials::Alert.new(ma_options)
  end
  if container_or_rooms_have_floor_type_but_no_line_items_with_sku_fragment?(container, :is_copper?, "ET-CL-CU-P25") and (items = Item.available_to_public.where("items.sku ilike '%ET-CL-CU-P25%'")).any?
    ma_options = {}.merge(options)
    ma_options[:room] = container
    ma_options[:recommended_qty] = 1
    ma_options[:actual_qty] = 0
    ma_options[:items] = items
    ma_options[:unmaskable] = true
    ma_options[:name] = "We recommend one of these special order copper 3-prong roof clips with Copper roof and roof and gutter deicing."
    material_alerts << Item::Materials::Alert.new(ma_options)
  end
  if (container.line_items.select{|li| li.item.sku.index("SR-PWR-KIT")}.empty? and container.line_items.select{|li| li.item.sku.index("SR-PLUG-KIT")}.empty?)
    ma_options = {}.merge(options)
    ma_options[:room] = container
    ma_options[:recommended_qty] = 1
    ma_options[:actual_qty] = 0
    ma_options[:items] = [Item.find_by(sku: "SR-PWR-KIT"), Item.find_by(sku: "SR-PLUG-KIT")]
    ma_options[:unmaskable] = true
    ma_options[:name] = "We recommend one of these Power Connection Kits with roof and gutter deicing cable."
    material_alerts << Item::Materials::Alert.new(ma_options)
  end



  Result.new(status: :ok, alerts: material_alerts)
end

#qualify?(container) ⇒ Boolean

Returns:

  • (Boolean)


10
11
12
# File 'app/services/item/materials/checks/roof_deicing.rb', line 10

def qualify?(container)
  get_rg_heating_elements(container).any?
end