Class: RoomConfiguration
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- RoomConfiguration
- Extended by:
- FriendlyId
- Includes:
- ActionView::Helpers::NumberHelper, Models::Auditable, Models::HeatLossable, Models::Lineage, Models::LiquidMethods, Models::Notable, Models::Pickable
- Defined in:
- app/models/room_configuration.rb
Overview
== Schema Information
Table name: room_configurations
Database name: primary
id :integer not null, primary key
additional_notes :text
alternate_heplo_ids :integer default([]), is an Array
ancestors_count :integer
asset :string(255)
average_ceiling_height :decimal(5, 2)
cable_spacing :decimal(4, 2)
cad_engine_status :integer
cad_engine_xml :text
ceiling_sq_ft :decimal(8, 2)
children_count :integer
coverage_state :enum
currency :string(255)
depth_above_cable :string(255)
depth_below_cable :string(255)
descendants_count :integer
desired_temperature :float default(68.0), not null
ev2_coverage :string(255)
ev2help :boolean default(FALSE)
expansion_joint_spacing :integer
first_view_date :datetime
floorplan_xml :text
from_edit :boolean
full_coverage_estimate :float
has_new_floorplan :boolean default(TRUE)
heating_requirement :enum default("unknown"), not null
hidden :boolean default(FALSE)
image_re_rendered_with_good_im :boolean
installation_date :date
installation_plan_cable_spacing :decimal(4, 2)
installation_plan_not_required :boolean default(FALSE)
installation_plan_scale :string(255)
insulation_surface :integer
is_rendered :boolean default(FALSE)
last_bom :json
last_heat_loss :json
legacy_iq_from_crm :boolean
name :string(255) not null
name_with_config :string(1000)
notes :text
number_fireplaces :integer default(0), not null
other_floor_type_label :string(255)
paver_thickness :string(255)
plan_created_at :datetime
position :integer default(100)
preferred_shipping_method :string(255)
priority :string(255) default("standard")
quotation_expiration_date :datetime
reception_date :datetime
reception_type :string(255) default("Unspecified"), not null
reference_number :string
requires_render :boolean default(FALSE)
requires_upgrade :boolean
room_length :string(255)
room_width :string(255)
sealing_factor :string(255) default("average"), not null
selected_membrane_cable_spacing :float
selected_strips_cable_spacing :float
service_panel_note :string
set_in :string(255)
show_non_public_heplos :boolean
situation :enum default("unknown"), not null
skip_expansion_joint_validation :boolean
slug :string
square_footage :integer
state :string(255)
underlayment_material :string(255)
vignette :boolean default(FALSE), not null
wyi_alert_sent :boolean
created_at :datetime
updated_at :datetime
contact_point_id :integer
controlled_by_id :integer
creator_id :integer
deleter_id :integer
designer_employee_id :integer
electrician_id :integer
floor_type_id :integer
floorplanner_employee_id :integer
heating_system_product_line_id :integer
heating_system_type_id :integer
installation_address_id :integer
installation_plan_qc_employee_id :integer
installation_plan_voltage_id :integer
installer_id :integer
labeler_employee_id :integer
legacy_proto_iq_room_id :integer
legacy_selected_instant_quote_id :integer
measure_job_id :integer
opportunity_id :integer not null
parent_id :integer
quoted_heating_system_pl_id :integer
retail_outlet_id :integer
room_event_id :integer
room_plan_id :integer
room_type_id :integer
showcase_id :integer
sub_floor_type_id :integer
system_owner_id :integer
updater_id :integer
visit_id :bigint
voltage_id :integer
Indexes
index_room_configurations_on_cad_engine_status (cad_engine_status)
index_room_configurations_on_contact_point_id (contact_point_id) USING hash
index_room_configurations_on_creator_id (creator_id)
index_room_configurations_on_designer_employee_id (designer_employee_id) USING hash
index_room_configurations_on_floorplanner_employee_id (floorplanner_employee_id) USING hash
index_room_configurations_on_heating_system_product_line_id (heating_system_product_line_id)
index_room_configurations_on_heating_system_type_id (heating_system_type_id)
index_room_configurations_on_image_re_rendered_with_good_im (image_re_rendered_with_good_im)
index_room_configurations_on_installation_address_id (installation_address_id) USING hash
index_room_configurations_on_labeler_employee_id (labeler_employee_id) USING hash
index_room_configurations_on_legacy_iq_from_crm (legacy_iq_from_crm)
index_room_configurations_on_legacy_proto_iq_room_id (legacy_proto_iq_room_id)
index_room_configurations_on_measure_job_id (measure_job_id)
index_room_configurations_on_opportunity_id (opportunity_id)
index_room_configurations_on_parent_id (parent_id)
index_room_configurations_on_quoted_heating_system_pl_id (quoted_heating_system_pl_id)
index_room_configurations_on_reception_type (reception_type)
index_room_configurations_on_reference_number (reference_number) USING gin
index_room_configurations_on_room_plan_id (room_plan_id) USING hash
index_room_configurations_on_room_type_id (room_type_id)
index_room_configurations_on_showcase_id (showcase_id)
index_room_configurations_on_slug (slug) USING hash
index_room_configurations_on_state (state) USING hash
index_room_configurations_on_sub_floor_type_id (sub_floor_type_id)
index_room_configurations_on_vignette (vignette)
index_room_configurations_on_visit_id (visit_id) WHERE (visit_id IS NOT NULL) USING hash
index_room_configurations_reference_number_like (reference_number)
room_configurations_controlled_by_id_idx (controlled_by_id)
room_configurations_unique_reference_number (reference_number) UNIQUE
Foreign Keys
fk_rails_... (contact_point_id => contact_points.id)
fk_rails_... (controlled_by_id => room_configurations.id)
fk_rails_... (designer_employee_id => parties.id)
fk_rails_... (floor_type_id => floor_types.id)
fk_rails_... (floorplanner_employee_id => parties.id)
fk_rails_... (heating_system_product_line_id => product_lines.id)
fk_rails_... (installation_address_id => addresses.id)
fk_rails_... (labeler_employee_id => parties.id)
fk_rails_... (opportunity_id => opportunities.id) ON DELETE => cascade
fk_rails_... (quoted_heating_system_pl_id => product_lines.id)
fk_rails_... (room_plan_id => room_plans.id) ON DELETE => nullify
fk_rails_... (room_type_id => room_types.id)
fk_rails_... (showcase_id => showcase_legacies.id)
fk_rails_... (sub_floor_type_id => sub_floor_types.id)
fk_rails_... (visit_id => visits.id) ON DELETE => nullify
Defined Under Namespace
Classes: AbortUpdateRhc, CalculateQuote, Copier, OperatingCostsCalculator
Constant Summary collapse
- MC_FLOORTYPE_ID_BY_WY_FLOORTYPE_ID =
WY floor types
1: Bamboo (Nailed), 2: Carpet, 3: Tile and Stone, 4: Engineered (Floating), 5: Pouring a new indoor Concrete Slab, 6: Laminate (Click Together Floating), 7: Marble, 8: Resilients, 9: Stone, 10: Vinyl, 11: Wood (Nailed), 12: Wood (Glued), 13: Bamboo (Floating), 14: Bamboo (Glued), 15: Engineered (Glued), 16: Engineered (Nailed), 17: Laminate (Glued Together Floating), 18: Laminate (Nailed), 19: Other, 20: Asphalt, 21: Paver, 22: Pouring a new outdoor Concrete Slab, 23: Carpet (Glued), 24: Cork, 25: Pouring a new outdoor Concrete Slab with a Surface Covering { '1' => '7', '2' => '1', '3' => '4', '4' => '5', '5' => '6', '6' => '5', '7' => '4', '8' => '3', '9' => '4', '10' => '2', '11' => '7', '12' => '3', '13' => '3', '14' => '3', '15' => '5', '16' => '5', '17' => '5', '19' => '3', '20' => '6', '21' => '6', '22' => '6', '23' => '1', '24' => '3', '25' => '6' }.freeze
- MC_ROOMTYPE_ID_BY_WY_ROOMTYPE_ID =
WY room types
1: Basement, 2: Bathroom, 3: Master Bathroom, 4: Bedroom, 5: Master Bedroom, 6: Breakfast Nook, 7: Dining Room, 8: Entry/Hallway, 9: Family Room, 10: Kitchen, 11: Laundry, 12: Living Room, 13: Recreation/Media Room, 14: Mudroom, 15: Office, 16: Powder Room, 17: Sunroom, 18: Other, 19: Shower/Sauna, 20: Driveway, 21: Sidewalk, 22: Stairs, 23: Patio, 24: Garage, 25: Ensuite, 26: Landing, 27: Entry, 28: Exit, 29: Walkway, 30: Courtyard, 31: Ramp, 32: Porch, 33: Carport, 34: Bridge, 35: Valet, 36: Addition, 37: Enclosed Porch, 38: Three Season Room, 39: Four Season Room, 40: Home Theater Room, 41: Shop Floor { '1' => '28', '2' => '17', '3' => '31', '4' => '6', '5' => '30', '6' => '20', '7' => '1', '8' => '2', '9' => '14', '10' => '18', '11' => '26', '12' => '0', '13' => '16', '14' => '34', '15' => '38', '16' => '35', '17' => '14', '18' => '43', '19' => '17', '22' => '5', '23' => '27', '24' => '34', '25' => '36', '26' => '2', '27' => '2', '28' => '2', '32' => '27', '36' => '27', '37' => '27', '38' => '27', '39' => '16', '40' => '16', '41' => '29' }.freeze
- MC_ROOMNAME_BY_MC_ROOMTYPE_ID =
{ '0' => 'Living Room', '1' => 'Dining Room', '2' => 'Foyer', '3' => 'Lower Hall', '4' => 'Upper Hall', '5' => 'Upper Stairs', '6' => 'Bedroom 1', '7' => 'Closet 1', '8' => 'Bedroom 2', '9' => 'Closet 2', '10' => 'Bedroom 3', '11' => 'Closet 3', '12' => 'Bedroom 4', '13' => 'Closet 4', '14' => 'Family/Great Room', '15' => 'Lower Stairs', '16' => 'Den', '17' => 'Bathroom 1', '18' => 'Kitchen', '19' => 'Dinette', '20' => 'Nook', '21' => 'Kitchen Hallway', '22' => 'Kitchen Foyer', '23' => 'Kitchen Entrance', '24' => 'Kitchen Stairs', '25' => 'Kitchen Landing', '26' => 'Laundry', '27' => 'Porch', '28' => 'Basement', '29' => 'Commercial Office', '30' => 'Master Bedroom', '31' => 'Master Bathroom', '32' => 'Master Closet', '33' => 'Pantry', '34' => 'Utility', '35' => 'Bathroom 2', '36' => 'Bathroom 3', '37' => 'Basement Stairs', '38' => 'Home Office', '39' => 'Basement Bedroom 1', '40' => 'Basement Bedroom 2', '41' => 'Basement Bathroom', '42' => 'Basement Family Room', '43' => 'Basement Misc.' }.freeze
- TYPICAL_SQFT_BY_WY_ROOMTYPE_ID =
{ '1' => 500, '2' => 50, '3' => 100, '4' => 200, '5' => 400, '6' => 100, '7' => 200, '8' => 50, '9' => 300, '10' => 300, '11' => 50, '12' => 300, '13' => 300, '14' => 100, '15' => 150, '16' => 40, '17' => 200, '18' => 100, '19' => 30, '20' => 250, '21' => 200, '22' => 75, '23' => 150, '24' => 200, '25' => 50, '26' => 75, '27' => 75, '28' => 75, '29' => 100, '30' => 200, '31' => 25, '32' => 200, '33' => 75, '34' => 75, '35' => 75, '36' => 75, '37' => 150, '38' => 150, '39' => 150, '40' => 200, '41' => 300 }.freeze
- PRIORITIES =
['same day order', 'same day', 'next day', '2 days', 'standard'].freeze
- CAD_ENGINE_STATUS =
{ 'Pending Design Conversion' => 1, 'In CAD Conversion' => 2, 'CAD Conversion Complete' => 3, 'Error' => 4 }.freeze
- CUSTOMER_CANCELABLE_STATES =
%i[draft complete].freeze
- CANCELABLE_STATES =
CUSTOMER_CANCELABLE_STATES + %i[in_design awaiting_quality_control]
- CLOSED_STATES =
%i[complete cancelled].freeze
- REFERENCE_NUMBER_PATTERN =
/^(IQR\d+)(-V)?(\d+)?$|^(IP\d+)(-R)?(\d+)?$/i- TEMPERATURE_OPTIONS =
[['Low', 60.0], ['Average', 68.0], ['Warm', 72.0], ['Hot', 80.0]].freeze
- WATTS_PER_SQUARE_FOOT =
{ 'TempZone Flex Roll' => 15.0, 'TempZone Easy Mat' => 15.0, 'TempZone Thin Cable' => 12.0, 'TempZone Thin Cable 3' => 12.0, 'TempZone Thin Cable 4' => 9.0, 'TempZone Cable' => 14.8, 'TempZone Cable 3.5' => 12.7, 'TempZone Cable 3.75' => 11.84, 'TempZone Cable 4' => 11.125, 'TempZone Cable 4.75' => 9.3, 'TempZone Cable 5' => 8.9, 'TempZone Cable 3.125' => 14.4, 'TempZone Ruler Cable' => 14.8, 'TempZone Ruler Cable 3.5' => 12.7, 'TempZone Ruler Cable 3.75' => 11.84, 'TempZone Ruler Cable 4' => 11.125, 'TempZone Ruler Cable 4.75' => 9.3, 'TempZone Ruler Cable 5' => 8.9, 'TempZone Ruler Cable 3.125' => 14.4, 'Environ Flex Roll' => 12.0, 'Environ Easy Mat' => 12.0, 'Slab Heat Mat' => 20.0, 'Slab Heat Cable' => 20.0, 'Snow Melt Cable' => 50.0, 'Snow Melt PoweMat' => 50.0, 'Snow Melt OmniMat' => 38.5, 'Snow Melt EcoMat' => 31.5, 'Snow Melt Mat' => 50.0 }.freeze
- DEFAULT_ECONOMY_AMB_TEMP =
63.0- PUBLIC_TZ_CABLE_SPACINGS =
[3.0, 4.0, 5.0].freeze
- PUBLIC_PRODESO_CABLE_SPACINGS =
[3.75, 5.0].freeze
- PUBLIC_DITRA_CABLE_SPACINGS =
[3.5, 4.75].freeze
- PUBLIC_CABLE_SPACINGS =
PUBLIC_TZ_CABLE_SPACINGS + PUBLIC_PRODESO_CABLE_SPACINGS + PUBLIC_DITRA_CABLE_SPACINGS
- PUBLIC_SH_CABLE_SPACINGS =
[3.0, 4.0, 5.0, 6.0].freeze
- PUBLIC_SM_CABLE_SPACINGS =
[3.0].freeze
- ROOM_ICON_BY_STATE =
{ 'draft' => 'pen-square', 'in_design' => 'cogs', 'awaiting_quality_control' => 'cogs', 'complete' => 'check-square', 'cancelled' => 'close' }.freeze
- FALLBACK_ROOM_ICON =
'object-group'- EMPTY_ALTERNATE_HEATING_SYSTEMS_BLURB =
{ 'engineering' => 'Leave empty for unrestricted heating systems.' }.freeze
- ENGINEERING_QUOTING_STATES =
%i[draft in_design awaiting_quality_control complete].freeze
Constants included from Models::Auditable
Models::Auditable::ALWAYS_IGNORED
Constants included from HeatLossableConstants
HeatLossableConstants::BTU_PER_HOUR_PER_WATT, HeatLossableConstants::HIGH_U_VALUE_THRESHOLD, HeatLossableConstants::HLC_PRIMARY_OK_THRESHOLD, HeatLossableConstants::INFILTRATION_AREA_FACTORS, HeatLossableConstants::INFILTRATION_FIREPLACE_FACTORS, HeatLossableConstants::INFILTRATION_SEALING_FACTORS, HeatLossableConstants::PIE_CHART_FLAG_COLORS, HeatLossableConstants::PIE_CHART_OK_COLORS
Constants included from Models::Schedulable
Models::Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
-
#currency ⇒ void
readonly
Validates currency.
-
#enter_heat_loss_info ⇒ Object
Returns the value of attribute enter_heat_loss_info.
-
#insulation_surface ⇒ Object
readonly
Minimum 9 sq.ft (roughly a 3x3 closet) for heat loss calculations.
-
#name ⇒ void
readonly
Validates name.
-
#new_note ⇒ Object
Returns the value of attribute new_note.
-
#reception_type ⇒ void
readonly
Validates reception type.
-
#reuse_upload_id ⇒ Object
Returns the value of attribute reuse_upload_id.
-
#updating_installation_plans ⇒ Object
Returns the value of attribute updating_installation_plans.
-
#validate_budget ⇒ Object
Returns the value of attribute validate_budget.
Belongs to collapse
-
#controlled_by ⇒ RoomConfiguration?
The associated controlled by.
-
#designer_employee ⇒ Employee?
The associated designer employee.
-
#electrician ⇒ Customer?
The associated electrician.
-
#floor_type ⇒ FloorType?
The associated floor type.
-
#floorplanner_employee ⇒ Employee?
The associated floorplanner employee.
-
#heating_system_product_line ⇒ ProductLine
where product line is marked as a heating_element_system, optional: true.
-
#installation_address ⇒ Address
Legacy Installation Record data, migrated onto Warranty v2 (doc/tasks/202608051319_INSTALLATION_RECORDS_TO_WARRANTIES.md).
-
#installation_plan_qc_employee ⇒ Employee?
The associated installation plan qc employee.
-
#installation_plan_voltage ⇒ Voltage?
The associated installation plan voltage.
-
#installer ⇒ Customer?
The associated installer.
-
#labeler_employee ⇒ Employee?
The associated labeler employee.
-
#opportunity ⇒ Opportunity?
The associated opportunity.
-
#quoted_heating_system_pl ⇒ ProductLine
where product line is marked as a heating_element_system, optional: true.
-
#retail_outlet ⇒ Customer?
The associated retail outlet.
-
#room_plan ⇒ RoomPlan?
The associated room plan.
-
#room_type ⇒ RoomType?
The associated room type.
-
#sub_floor_type ⇒ SubFloorType?
The associated sub floor type.
-
#system_owner ⇒ Customer?
The associated system owner.
-
#visit ⇒ Visit?
The associated visit.
-
#voltage ⇒ Voltage?
The associated voltage.
Methods included from Models::Auditable
Has many collapse
-
#activities ⇒ ActiveRecord::Associations::CollectionProxy
The associated activities.
-
#cad_files ⇒ ActiveRecord::Associations::CollectionProxy
The associated cad files.
-
#controlled_rooms ⇒ ActiveRecord::Associations::CollectionProxy
The associated controlled rooms.
-
#element_pole_assignments ⇒ ActiveRecord::Associations::CollectionProxy
The associated element pole assignments.
-
#exterior_walls ⇒ ActiveRecord::Associations::CollectionProxy
The associated exterior walls.
-
#floor_plan_display_room_configurations ⇒ ActiveRecord::Associations::CollectionProxy
The associated floor plan display room configurations.
-
#floor_plan_displays ⇒ ActiveRecord::Associations::CollectionProxy
The associated floor plan displays.
-
#installed_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated installed items.
-
#material_alerts ⇒ ActiveRecord::Associations::CollectionProxy
The associated material alerts.
-
#room_layout_images ⇒ ActiveRecord::Associations::CollectionProxy
The associated room layout images.
-
#uploads ⇒ ActiveRecord::Associations::CollectionProxy
The associated uploads.
-
#zones ⇒ ActiveRecord::Associations::CollectionProxy
The associated zones.
Methods included from Models::Pickable
Has one collapse
-
#ceiling ⇒ Ceiling?
The associated ceiling.
-
#under_floor ⇒ UnderFloor?
The associated under floor.
Has and belongs to many collapse
-
#installed_product_lines ⇒ ActiveRecord::Associations::CollectionProxy
The associated installed product lines.
-
#orders ⇒ ActiveRecord::Associations::CollectionProxy
The associated orders.
-
#quotes ⇒ ActiveRecord::Associations::CollectionProxy
The associated quotes.
-
#support_cases ⇒ ActiveRecord::Associations::CollectionProxy
The associated support cases.
Delegated Instance Attributes collapse
-
#catalog ⇒ Object
Alias for Customer#catalog.
-
#company ⇒ Object
Alias for Customer#company.
-
#customer ⇒ Object
Alias for Opportunity#customer.
-
#easy_mat? ⇒ Object
Alias for Heating_system_product_line#easy_mat?.
-
#environ_flex_roll? ⇒ Object
Alias for Heating_system_product_line#environ_flex_roll?.
-
#environment ⇒ Object
Alias for Room_type#environment.
-
#flex_roll? ⇒ Object
Alias for Heating_system_product_line#flex_roll?.
-
#heating_elements ⇒ Object
Alias for Line_items#heating_elements.
-
#installation_country_iso ⇒ Object
Alias for Opportunity#installation_country_iso.
-
#installation_country_iso3 ⇒ Object
Alias for Opportunity#installation_country_iso3.
-
#installation_postal_code ⇒ Object
Alias for Opportunity#installation_postal_code.
-
#installation_state_code ⇒ Object
Alias for Opportunity#installation_state_code.
-
#others ⇒ Object
Alias for Line_items#others.
-
#template_options_for_select ⇒ Object
Alias for Class#template_options_for_select.
Class Method Summary collapse
-
.active ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are active.
-
.all_reception_types_for_select ⇒ Object
All reception types for select.
-
.by_created_at ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are by created at.
-
.by_reference_number ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are by reference number.
-
.category_options_for_select ⇒ Object
Category options for select.
-
.complete ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are complete.
-
.complete_and_awaiting_transmission ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are complete and awaiting transmission.
-
.contains_item_ids ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are contains item ids.
-
.default_attributes(store_id = 1) ⇒ Object
Default attributes.
-
.determine_style(opportunity, current_opportunity) ⇒ Object
Determine style.
-
.dt_rooms ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are dt rooms.
-
.formatted_resources_query(room_configurations) ⇒ Object
Formatted resources query.
-
.group_name_to_key(group_name) ⇒ Object
Legacy IQ option group methods removed.
-
.has_no_quotes ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are has no quotes.
-
.has_uploads_of_category ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are has uploads of category.
-
.heating_element_count_sql ⇒ Object
Builds a correlated subquery for heating element quantity count Uses ltree with hardcoded path constant for zero DB lookups.
-
.image_needs_re_rendering_with_good_im ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are image needs re rendering with good im.
-
.in_cad_processing ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are in cad processing.
-
.in_quoting ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are in quoting.
-
.is_ditra_cable_spacing?(cs) ⇒ Object
Whether is ditra cable spacing.
-
.is_membrane_cable_spacing?(cs) ⇒ Object
Whether is membrane cable spacing.
-
.is_prodeso_cable_spacing?(cs) ⇒ Object
Whether is prodeso cable spacing.
-
.last_revision_reference_number(root_reference_number) ⇒ Object
Last revision reference number.
-
.last_revisions ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are last revisions.
-
.lookup ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are lookup.
-
.non_drafts ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are non drafts.
-
.non_revisions ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are non revisions.
-
.order_by_heating_elements_count ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are order by heating elements count.
-
.reception_type_for_select ⇒ Object
Reception type for select.
-
.reception_type_valid_values ⇒ Object
Reception type valid values.
-
.rev_tag(rc) ⇒ Object
Rev tag.
-
.revision_reference_number(rc) ⇒ Object
Revision reference number.
-
.root_reference_number(rc) ⇒ Object
Root reference number.
-
.rp_rooms ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are rp rooms.
-
.states_for_select ⇒ Object
States for select.
-
.template_options_for_select ⇒ Object
Template options for select.
-
.update_or_create_from_rhc_args(rhc_args, options, customer, system_name, room_layout_image_params = nil) ⇒ Hash
Creates (or reuses, by share key) a room configuration from Instant Quote rhc args, calculating the quote and adding the selected line items.
-
.upload_categories_for_select ⇒ Object
Upload categories for select.
-
.vignettes_for_product_line_id ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are vignettes for product line id.
-
.vignettes_for_product_line_url ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are vignettes for product line url.
-
.with_heating_elements_count ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are with heating elements count.
-
.with_item_id ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are with item id.
-
.with_line_items ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are with line items.
-
.with_single_heating_element ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are with single heating element.
-
.with_vignette ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are with vignette.
-
.without_revisions ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are without revisions.
Instance Method Summary collapse
-
#add_bom_line_item(bom_item) ⇒ Object
Adds a line item from a BOM hash (from HeatingSystemCalculator).
-
#add_line_item(options) ⇒ LineItem
Adds (or increments) a line item for the given catalog item.
-
#add_selected_line_items_from_rhc_elements(rhc_results) ⇒ Object
Add selected line items from rhc elements.
-
#add_selected_line_items_from_rhc_group(rhc_results, group, inds) ⇒ Object
Add selected line items from rhc group.
-
#add_selected_line_items_from_rhc_kits(rhc_results, group, inds) ⇒ Object
Add selected line items from rhc kits.
-
#allow_heat_loss_calculation? ⇒ Object
Whether allow heat loss calculation.
-
#alternate_heplo_names ⇒ Object
Alternate heplo names.
-
#apply_line_items_from_rhc_results(rhc_results, options) ⇒ void
Adds line items for the selected element set, control, kit, and accessories from CalculateQuote results.
-
#area ⇒ Object
Area.
-
#belongs_only_to_legacy_quotes? ⇒ Object
Whether belongs only to legacy quotes.
-
#billing_entity ⇒ Object
Billing entity.
-
#build_activity ⇒ Object
Build activity.
-
#cable_spacing_mismatch? ⇒ Object
Whether cable spacing mismatch.
-
#calculate_heat_loss ⇒ Object
Calculate heat loss.
-
#calculate_operating_cost_rate_using_hep ⇒ Object
Calculate operating cost rate using hep.
-
#calculate_total_amps ⇒ Object
Calculate total amps.
-
#calculate_total_kilowatts ⇒ Object
Calculate total kilowatts.
-
#calculate_total_watts ⇒ Object
Calculate total watts.
-
#can_add_to_cart? ⇒ Object
Whether can add to cart.
-
#can_calculate_heat_loss? ⇒ Object
Whether can calculate heat loss.
-
#can_have_installation_plan? ⇒ Object
Whether can have installation plan.
-
#can_have_room_layout? ⇒ Object
Whether can have room layout.
-
#cancelable? ⇒ Object
Whether cancelable.
-
#check_room_layout_or_note_attached ⇒ Object
Check room layout or note attached.
-
#config_name ⇒ Object
Config name.
-
#config_pretty ⇒ Object
Config pretty.
-
#control_voltage ⇒ Object
Control voltage.
-
#controlled_rooms_by_quote(quote) ⇒ Object
Controlled rooms by quote.
-
#coverage_percentage ⇒ Object
Coverage percentage.
-
#create_and_link_vignette_installation_plan_image ⇒ Object
Create and link vignette installation plan image.
-
#create_heatloss_followup_activity(user, upload_link) ⇒ Object
Create heatloss followup activity.
-
#create_revision(copy_line_items = false, copy_room_layout = false, copy_installation_plan = false) ⇒ Object
Create revision.
-
#crm_link ⇒ Object
Crm link.
-
#currency_symbol ⇒ Object
Currency symbol.
-
#deep_dup ⇒ Object
Deep dup.
-
#deletable?(current_user) ⇒ Object
Whether deletable.
-
#design_tool_params_hsh ⇒ Object
Design tool params hsh.
-
#dimension_label ⇒ Object
Dimension label.
-
#dimensions_label ⇒ Object
Dimensions label.
-
#editing_locked? ⇒ Object
Whether editing locked.
-
#effective_voltage(voltage_only = false) ⇒ Object
Effective voltage.
-
#electrical_file_name(with_extension = true) ⇒ Object
Electrical file name.
-
#electrical_plan_pdf ⇒ Object
Electrical plan pdf.
-
#email_for_plan_request_confirmation ⇒ Object
Email for plan request confirmation.
-
#engineer_signature_tag ⇒ Object
Creates an engineer signature tag for installation plan.
-
#entering_heat_loss_info? ⇒ Object
Whether entering heat loss info.
-
#ev2_volume_discount(msrp = false) ⇒ Object
Ev2 volume discount.
-
#event_flow_name ⇒ Object
Legacy iqd_total method removed - IQ system deprecated.
-
#exclude_manually_initiated_event?(_event) ⇒ Object
Whether exclude manually initiated event.
-
#file_name(with_extension = true) ⇒ Object
File name.
-
#find_recommended_accessories(options = {}) ⇒ Array
Finds accessories recommended for this room's heating elements and controls.
-
#floor_plan ⇒ Object
Floor plan.
-
#floor_type_name ⇒ Object
Floor type name.
-
#floorplan_quote_parent_line_items ⇒ Object
Floorplan quote parent line items.
-
#generate_all_plans ⇒ Object
Generate all plans.
-
#generate_bill_of_materials ⇒ Object
Generate bill of materials.
-
#generate_electrical_plan_pdf(suggested_skus = [], preview = false, version: 'v2') ⇒ Object
Generate electrical plan pdf.
-
#generate_individual_install_plan_pdf(plan, version: 'v2') ⇒ Object
Generate individual install plan pdf.
-
#generate_installation_plan_pdf(version: 'v2') ⇒ Object
Generate installation plan pdf.
-
#generate_multizone_plan_pdf(version: 'v2') ⇒ Object
Generate multizone plan pdf.
-
#get_bom_elements_from_line_items ⇒ Object
Get bom elements from line items.
-
#get_file(plan, resource, category, files_transferred) ⇒ Object
Get file.
-
#get_heat_loss(inside_temperature, outside_temperature) ⇒ Object
Get heat loss.
-
#get_heat_supplied ⇒ Object
Get heat supplied.
-
#get_heating_system_type ⇒ Object
Get heating system type.
-
#get_name_with_config ⇒ Object
Get name with config.
-
#get_operating_costs ⇒ Object
Get operating costs.
-
#get_or_generate_electrical_plan_pdf(version: 'v2', force: false) ⇒ Object
Get or generate electrical plan pdf.
-
#get_or_generate_installation_plan_pdf(version: 'v2', force: false) ⇒ Object
+version+ — 'v2' (default, current/modern generator) or 'v1' (LEGACY generator).
-
#get_or_generate_multizone_plan_pdf(version: 'v2', force: false) ⇒ Object
Get or generate multizone plan pdf.
-
#get_recommended_materials(options = {}) ⇒ Array
Recommended accessories for this room's heating elements, or an empty array when not applicable.
-
#get_selected_floor_warming_line_items ⇒ Object
Get selected floor warming line items.
-
#get_selected_line_items ⇒ Object
Get selected line items.
-
#get_weighted_average_heat_loss(hl_comfort, hl_economy) ⇒ Object
Get weighted average heat loss.
-
#grouped_cable_spacing_options_for_select ⇒ Object
Grouped cable spacing options for select.
-
#guess_under_floor_type_id ⇒ Object
Guess under floor type id.
-
#has_heat_loss_report_pdf? ⇒ Object
Whether has heat loss report pdf.
-
#has_installation_plan_cad? ⇒ Object
Whether has installation plan cad.
-
#has_installation_plan_image? ⇒ Object
Whether has installation plan image.
-
#has_installation_plans? ⇒ Object
Whether has installation plans.
-
#has_items_that_require_cable_spacing? ⇒ Object
Whether has items that require cable spacing.
-
#has_notes? ⇒ Object
Whether has notes.
-
#has_plans? ⇒ Object
Whether has plans.
-
#has_prodeso? ⇒ Object
Whether has prodeso.
-
#has_room_layout_file? ⇒ Object
Whether has room layout file.
-
#has_strips? ⇒ Object
Whether has strips.
-
#has_zone_information? ⇒ Object
Whether has zone information.
-
#heat_loss_children ⇒ Object
Heat loss children.
-
#heat_loss_name ⇒ Object
Heat loss name.
-
#heat_loss_report_pdf ⇒ Object
Heat loss report pdf.
-
#heating_system_type_name ⇒ Object
Heating system type name.
-
#heating_system_type_name_includes?(product) ⇒ Object
Whether heating system type name includes.
-
#heating_system_type_name_with_tz_cable_spacing ⇒ Object
Heating system type name with tz cable spacing.
-
#heplo_summary(pretty = nil) ⇒ Object
Heplo summary.
-
#ideal_cable_spacing ⇒ Object
Ideal cable spacing.
-
#in_design_or_later? ⇒ Object
Whether in design or later.
-
#installation_heated_area_sqft ⇒ Object
this could be different than the installation sq.ft when we deal with snow melt/slab heat mats.
-
#installation_plan_and_bom_attached? ⇒ Object
Whether installation plan and bom attached.
-
#installation_plan_blocking_reasons ⇒ Object
Returns human-readable reasons why design_complete / complete cannot fire.
-
#installation_plan_cad ⇒ Object
Installation plan cad.
-
#installation_plan_cad=(attributes = {}) ⇒ Object
Installation plan cad.
-
#installation_plan_image ⇒ Object
Installation plan image.
-
#installation_plan_image=(attributes = {}) ⇒ Object
Installation plan image.
-
#installation_plan_pdf ⇒ Object
Installation plan pdf.
-
#installation_plan_reference_number ⇒ Object
Installation plan reference number.
-
#installation_plans_attached? ⇒ Object
Whether installation plans attached.
-
#installation_sqft ⇒ Object
Installation sqft.
-
#invalidate_design_guidelines ⇒ Object
Invalidate design guidelines.
-
#is_cable_with_options?(options = {}) ⇒ Boolean
Whether this configuration is a cable system matching the given installation type and cable spacing.
-
#is_countertop? ⇒ Object
Whether is countertop.
-
#is_in_a_completed_quote? ⇒ Object
Whether is in a completed quote.
-
#is_snow_or_ice_melting? ⇒ Object
Whether is snow or ice melting.
-
#main_rep ⇒ Object
Main rep.
-
#max_ambient_temperature ⇒ Object
Max ambient temperature.
-
#meta_description ⇒ Object
Meta description.
-
#meta_title ⇒ Object
Meta title.
-
#name_with_customer_opp_and_room ⇒ Object
Name with customer opp and room.
-
#name_with_dimensions ⇒ Object
Name with dimensions.
-
#name_with_room ⇒ Object
Name with room.
-
#name_with_room_and_opp ⇒ Object
Name with room and opp.
-
#notify_rep_of_room_completion ⇒ Object
Notify rep of room completion.
-
#ok_to_customer_cancel? ⇒ Object
Whether ok to customer cancel.
-
#ok_to_delete? ⇒ Object
Whether ok to delete.
-
#operating_cost_in_cents_per_day ⇒ Object
Operating cost in cents per day.
-
#order ⇒ Object
Order.
-
#orderable? ⇒ Object
Whether orderable.
-
#other_revisions_and_configurations ⇒ Object
Other revisions and configurations.
-
#party_for_plan_request_confirmation ⇒ Object
Party for plan request confirmation.
-
#plan_thumbnail ⇒ Object
Plan thumbnail.
-
#pole_assignments_possible? ⇒ Object
Whether pole assignments possible.
-
#populate_line_items_from_bom_results(bom_results) ⇒ Object
Populates line items from HeatingSystemCalculator BOM results.
-
#pretty_coverage_state_description ⇒ Object
Pretty coverage state description.
-
#primary_party ⇒ Object
Primary party.
-
#priority_urgency_factor ⇒ Object
Priority urgency factor.
-
#promotion_discount(msrp = false) ⇒ Object
Promotion discount.
-
#promotion_that_applies(msrp = false) ⇒ Object
Promotion that applies.
-
#public_path ⇒ Object
Public path.
-
#ready_for_engineering? ⇒ Object
Whether ready for engineering.
-
#rectangular_area ⇒ Object
Rectangular area.
-
#refresh_plans(delay: nil) ⇒ Object
Refresh plans.
-
#release_orders_awaiting_completed_installation_plans ⇒ Object
Release orders awaiting completed installation plans.
-
#remove_line_item(line_item, quantity = 1) ⇒ Object
Remove line item.
-
#require_cable_spacing? ⇒ Object
Whether require cable spacing.
-
#require_expansion_joint? ⇒ Object
Whether require expansion joint.
-
#reset_last_heat_loss ⇒ Object
Reset last heat loss.
-
#reusable_layouts ⇒ Object
Reusable layouts.
-
#revision ⇒ Object
Revision.
-
#room_configurations_for_control ⇒ Object
Room configurations for control.
-
#room_configurations_for_control_select ⇒ Object
Room configurations for control select.
-
#room_layout_attached? ⇒ Boolean
This validation is called on new object, hence you must parse the array instead of using activerecord.
-
#room_layout_image ⇒ Object
Room layout image.
-
#room_layout_image=(attributes = {}) ⇒ Object
Room layout image.
-
#room_layout_or_note_attached? ⇒ Object
Whether room layout or note attached.
-
#room_length_raw ⇒ Object
Room length raw.
-
#room_length_raw=(measurement) ⇒ Object
Room length raw.
-
#room_plan_attached? ⇒ Object
Whether room plan attached.
-
#room_plan_editing_locked? ⇒ Object
Whether room plan editing locked.
-
#room_prefix ⇒ Object
Room prefix.
-
#room_width_raw ⇒ Object
Room width raw.
-
#room_width_raw=(measurement) ⇒ Object
Room width raw.
-
#select_default_line_items ⇒ Object
Select default line items.
-
#send_online_plan_request_confirmation ⇒ Object
Send online plan request confirmation.
-
#send_same_day_design_alert ⇒ Object
Send same day design alert.
-
#send_to_engineering_and_create_crm_quote ⇒ Object
Send to engineering and create crm quote.
-
#set_currency ⇒ Object
Set currency.
-
#set_quoted_heating_system_product_line ⇒ Object
Set quoted heating system product line.
-
#set_reference_number ⇒ Object
Set reference number.
-
#should_generate_new_friendly_id? ⇒ Object
Whether should generate new friendly id.
-
#show_cable_spacing_message? ⇒ Object
Whether show cable spacing message.
-
#show_voltage_message? ⇒ Object
Whether show voltage message.
-
#slug_candidates ⇒ Object
Slug candidates.
-
#state_description(describe_state = nil) ⇒ Object
State description.
-
#status ⇒ Object
Status.
-
#sub_floor_type_name ⇒ Object
Sub floor type name.
-
#synchronization_targets ⇒ Object
Retrieves valid synchronization targets when a room's line item are changed, which records get the updated items.
-
#temperature_options_for_select ⇒ Object
Temperature options for select.
-
#to_param ⇒ Object
This prevents friendly id from automatically using slug when passing object, slug should be manually set.
-
#to_s ⇒ Object
To s.
-
#total ⇒ Object
implement total for a room configuration which is just the subtotal.
-
#total_length ⇒ Object
Total length.
-
#tracer_solutions ⇒ Object
Tracer solutions.
-
#transmittable? ⇒ Object
Whether transmittable.
-
#transmittable_and_settled? ⇒ Object
Whether transmittable and settled.
-
#tz_installation_sqft ⇒ Object
Tz installation sqft.
-
#unlink_vignette_installation_plan_image ⇒ Object
Unlink vignette installation plan image.
-
#update_quote_status ⇒ Object
Update quote status.
-
#valid_cable_spacing ⇒ Object
Valid cable spacing.
-
#valid_expansion_joint_spacing ⇒ Object
Valid expansion joint spacing.
-
#valid_insulation_surface ⇒ Object
Valid insulation surface.
-
#versions_for_audit_trail(_params = {}) ⇒ Object
Versions for audit trail.
-
#vignette_valid_only_for_completed_rooms_with_plans ⇒ Object
Vignette valid only for completed rooms with plans.
-
#voltage_mismatch? ⇒ Object
Whether voltage mismatch.
-
#warranty_card ⇒ Object
Warranty card.
-
#warranty_card=(attributes = {}) ⇒ Object
Warranty card.
-
#web_room? ⇒ Object
Whether web room.
Methods included from Models::Auditable
#all_skipped_columns, #audit_reference_data, #should_not_save_version, #stamp_record
Methods included from Models::HeatLossable
#children_heat_loss_recursive, #get_children_heat_loss, #get_self_and_children_heat_loss, #get_u_value, #heat_loss_children_recursive, #insulation_type, #reset_room_last_heat_loss, #self_and_children_heat_loss_recursive
Methods included from Models::Lineage
#ancestors, #ancestors_ids, #children_and_roots, #descendants, #descendants_ids, #ensure_non_recursive_lineage, #family_members, #generate_full_name, #generate_full_name_array, #lineage, #lineage_array, #lineage_simple, #root, #root_id, #self_ancestors_and_descendants, #self_ancestors_and_descendants_ids, #self_and_ancestors, #self_and_ancestors_ids, #self_and_children, #self_and_descendants, #self_and_descendants_ids, #self_and_siblings, #self_and_siblings_ids, #siblings, #siblings_ids
Methods included from Models::Pickable
#all_my_publications, #append_suggested_items, #append_suggested_materials, #control_capacity, #determine_catalog_for_picking, #determine_skus_to_filter, #discounted_shipping_total, #electrical_heating_elements, #fix_catalog, #get_material_alerts, #has_custom_products?, #invalidate_material_alerts!, #line_items_grouped_by_room_configuration, #lines_match_pick_catalog_on_flip, #meets_custom_products_threshold?, #pricing_program_discount_factor, #purge_empty_line_items, #soft_recalc, #subtotal, #subtotal_after_trade_discount_without_shipping, #subtotal_discounted_without_shipping, #subtotal_msrp_without_shipping, #switching_pick_catalog?, #synchronize_lines, #total_amps_by_product_line, #total_coverage_by_product_line, #total_linear_feet_by_product_line, #total_spec_by_product_line, #total_watts_by_product_line, #underlayments
Methods included from Models::Notable
Methods inherited from ApplicationRecord
ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation
Methods included from Models::Schedulable
Methods included from Models::AfterCommittable
Methods included from Models::EventPublishable
Instance Attribute Details
#currency ⇒ void (readonly)
This method returns an undefined value.
Validates currency.
471 |
# File 'app/models/room_configuration.rb', line 471 validates :currency, presence: true |
#enter_heat_loss_info ⇒ Object
Returns the value of attribute enter_heat_loss_info.
172 173 174 |
# File 'app/models/room_configuration.rb', line 172 def enter_heat_loss_info @enter_heat_loss_info end |
#insulation_surface ⇒ Object (readonly)
Minimum 9 sq.ft (roughly a 3x3 closet) for heat loss calculations
Validations (if => #entering_heat_loss_info? ):
- Numericality ({ less_than_or_equal_to: 9999.9, greater_than_or_equal_to: 9.0, message: 'must be at least 9 sq.ft (roughly a small closet)' })
467 468 |
# File 'app/models/room_configuration.rb', line 467 validates :insulation_surface, numericality: { less_than_or_equal_to: 9999.9, greater_than_or_equal_to: 9.0, message: 'must be at least 9 sq.ft (roughly a small closet)' }, if: :entering_heat_loss_info? |
#name ⇒ void (readonly)
This method returns an undefined value.
Validates name.
474 |
# File 'app/models/room_configuration.rb', line 474 validates :name, presence: true |
#new_note ⇒ Object
Returns the value of attribute new_note.
172 173 174 |
# File 'app/models/room_configuration.rb', line 172 def new_note @new_note end |
#reception_type ⇒ void (readonly)
This method returns an undefined value.
Validates reception type.
464 |
# File 'app/models/room_configuration.rb', line 464 validates :reception_type, presence: true |
#reuse_upload_id ⇒ Object
Returns the value of attribute reuse_upload_id.
172 173 174 |
# File 'app/models/room_configuration.rb', line 172 def reuse_upload_id @reuse_upload_id end |
#updating_installation_plans ⇒ Object
Returns the value of attribute updating_installation_plans.
172 173 174 |
# File 'app/models/room_configuration.rb', line 172 def updating_installation_plans @updating_installation_plans end |
#validate_budget ⇒ Object
Returns the value of attribute validate_budget.
172 173 174 |
# File 'app/models/room_configuration.rb', line 172 def validate_budget @validate_budget end |
Class Method Details
.active ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are active. Active Record Scope
504 |
# File 'app/models/room_configuration.rb', line 504 scope :active, -> { where("room_configurations.state != 'cancelled'") } |
.all_reception_types_for_select ⇒ Object
All reception types for select.
722 723 724 725 |
# File 'app/models/room_configuration.rb', line 722 def self.all_reception_types_for_select # Include legacy types for historical data display RoomConfigurationConstants::ALL_RECEPTION_TYPES.to_h end |
.by_created_at ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are by created at. Active Record Scope
491 |
# File 'app/models/room_configuration.rb', line 491 scope :by_created_at, -> { order('room_configurations.created_at DESC') } |
.by_reference_number ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are by reference number. Active Record Scope
496 |
# File 'app/models/room_configuration.rb', line 496 scope :by_reference_number, -> { order('room_configurations.reference_number desc') } |
.category_options_for_select ⇒ Object
Category options for select.
624 625 626 |
# File 'app/models/room_configuration.rb', line 624 def self. [['Installation Plan - Image', 'installation_plan_image'], ['Installation Plan - CAD', 'installation_plan_cad'], ['Installation Plan Heated Area - Image', 'installation_heated_area']] end |
.complete ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are complete. Active Record Scope
492 |
# File 'app/models/room_configuration.rb', line 492 scope :complete, -> { where(state: 'complete').by_created_at } |
.complete_and_awaiting_transmission ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are complete and awaiting transmission. Active Record Scope
493 |
# File 'app/models/room_configuration.rb', line 493 scope :complete_and_awaiting_transmission, -> { joins(:quotes).where("room_configurations.state = 'complete' AND quotes.state NOT IN ('complete','cancelled')").by_created_at } |
.contains_item_ids ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are contains item ids. Active Record Scope
501 |
# File 'app/models/room_configuration.rb', line 501 scope :contains_item_ids, ->(item_ids) { where("EXISTS (select 1 from line_items li where li.resource_id = #{table_name}.id and li.resource_type = '#{name}' and li.item_id IN (?))", item_ids) } |
.default_attributes(store_id = 1) ⇒ Object
Default attributes.
731 732 733 734 735 736 737 738 |
# File 'app/models/room_configuration.rb', line 731 def self.default_attributes(store_id = 1) env = HeatingElementProductLineOption::ENVIRONMENTS.first rt_id = HeatingElementProductLineOption.get_default_room_type_id_for_environment(env) sft_id = HeatingElementProductLineOption.get_default_subfloor_type_id ft_id = HeatingElementProductLineOption.get_default_floor_type_id_for_environment(env) hs_pl_id = HeatingElementProductLineOption.(:product_line_id, environment: env, sub_floor_type_id: sft_id, floor_type_id: ft_id, is_public: true, store_id:).first { coverage_state: 'full', room_type_id: rt_id, sub_floor_type_id: sft_id, floor_type_id: ft_id, heating_system_product_line_id: hs_pl_id } end |
.determine_style(opportunity, current_opportunity) ⇒ Object
Determine style.
687 688 689 690 691 692 693 |
# File 'app/models/room_configuration.rb', line 687 def self.determine_style(opportunity, current_opportunity) if opportunity.id == current_opportunity.id '' else 'display:none' end end |
.dt_rooms ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are dt rooms. Active Record Scope
506 |
# File 'app/models/room_configuration.rb', line 506 scope :dt_rooms, -> { where(reception_type: 'DesignTool') } |
.formatted_resources_query(room_configurations) ⇒ Object
Formatted resources query.
744 745 746 747 748 749 |
# File 'app/models/room_configuration.rb', line 744 def self.formatted_resources_query(room_configurations) room_configurations .select('room_configurations.id, room_configurations.reference_number, room_configurations.name, ' \ 'room_configurations.created_at, room_configurations.state, opportunities.name as opportunity_name') .order('room_configurations.reference_number desc') end |
.group_name_to_key(group_name) ⇒ Object
Legacy IQ option group methods removed
3040 3041 3042 |
# File 'app/models/room_configuration.rb', line 3040 def self.group_name_to_key(group_name) group_name.to_s.downcase.strip.underscore.tr(' ', '_').gsub('__', '_') end |
.has_no_quotes ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are has no quotes. Active Record Scope
502 |
# File 'app/models/room_configuration.rb', line 502 scope :has_no_quotes, -> { where.missing(:quotes) } |
.has_uploads_of_category ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are has uploads of category. Active Record Scope
503 |
# File 'app/models/room_configuration.rb', line 503 scope :has_uploads_of_category, ->(category) { where("EXISTS(select 1 from uploads where (uploads.resource_id = room_configurations.id and uploads.resource_type = 'RoomConfiguration' and uploads.category = ?) )", category) } |
.heating_element_count_sql ⇒ Object
Builds a correlated subquery for heating element quantity count
Uses ltree with hardcoded path constant for zero DB lookups
313 314 315 316 317 318 319 320 |
# File 'app/models/room_configuration.rb', line 313 def self.heating_element_count_sql LineItem .joins(:item) .where(LineItem.arel_table[:room_configuration_id].eq(arel_table[:id])) .merge(Item.heating_elements) .select(Arel.sql('COALESCE(SUM(line_items.quantity), 0)')) .to_sql end |
.image_needs_re_rendering_with_good_im ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are image needs re rendering with good im. Active Record Scope
509 |
# File 'app/models/room_configuration.rb', line 509 scope :image_needs_re_rendering_with_good_im, -> { where('image_re_rendered_with_good_im IS NOT TRUE') } |
.in_cad_processing ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are in cad processing. Active Record Scope
494 |
# File 'app/models/room_configuration.rb', line 494 scope :in_cad_processing, -> { where(state: 'in_cad_processing').by_created_at } |
.in_quoting ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are in quoting. Active Record Scope
508 |
# File 'app/models/room_configuration.rb', line 508 scope :in_quoting, -> { where(state: %w[in_design awaiting_quality_control]) } |
.is_ditra_cable_spacing?(cs) ⇒ Object
Whether is ditra cable spacing.
1102 1103 1104 1105 1106 1107 1108 |
# File 'app/models/room_configuration.rb', line 1102 def self.is_ditra_cable_spacing?(cs) if PUBLIC_DITRA_CABLE_SPACINGS.index(cs) true else false end end |
.is_membrane_cable_spacing?(cs) ⇒ Object
Whether is membrane cable spacing.
1082 1083 1084 |
# File 'app/models/room_configuration.rb', line 1082 def self.is_membrane_cable_spacing?(cs) is_prodeso_cable_spacing?(cs) || is_ditra_cable_spacing?(cs) end |
.is_prodeso_cable_spacing?(cs) ⇒ Object
Whether is prodeso cable spacing.
1090 1091 1092 1093 1094 1095 1096 |
# File 'app/models/room_configuration.rb', line 1090 def self.is_prodeso_cable_spacing?(cs) if PUBLIC_PRODESO_CABLE_SPACINGS.index(cs) true else false end end |
.last_revision_reference_number(root_reference_number) ⇒ Object
Last revision reference number.
649 650 651 652 653 654 655 |
# File 'app/models/room_configuration.rb', line 649 def self.last_revision_reference_number(root_reference_number) revision_letter = root_reference_number.index('IQR') ? 'V' : 'R' RoomConfiguration.where(RoomConfiguration[:reference_number].matches("#{root_reference_number}-#{revision_letter}%")) .order(:id) .reverse_order .limit(1).pluck(:reference_number).try(:first) end |
.last_revisions ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are last revisions. Active Record Scope
497 |
# File 'app/models/room_configuration.rb', line 497 scope :last_revisions, -> { where(parent_id: nil) } |
.lookup ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are lookup. Active Record Scope
505 |
# File 'app/models/room_configuration.rb', line 505 scope :lookup, ->(q) { where('room_configurations.reference_number like :term_wild', term_wild: "%#{q}%") } |
.non_drafts ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are non drafts. Active Record Scope
498 |
# File 'app/models/room_configuration.rb', line 498 scope :non_drafts, -> { where.not(state: 'draft') } |
.non_revisions ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are non revisions. Active Record Scope
500 |
# File 'app/models/room_configuration.rb', line 500 scope :non_revisions, -> { last_revisions } |
.order_by_heating_elements_count ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are order by heating elements count. Active Record Scope
519 |
# File 'app/models/room_configuration.rb', line 519 scope :order_by_heating_elements_count, -> { order(Arel.sql("(#{heating_element_count_sql})")) } |
.reception_type_for_select ⇒ Object
Reception type for select.
712 713 714 715 716 717 |
# File 'app/models/room_configuration.rb', line 712 def self.reception_type_for_select # Use the centralized constant, adding any model-specific types RoomConfigurationConstants::ACTIVE_RECEPTION_TYPES.merge( 'Room API' => 'RoomAPI' ) end |
.reception_type_valid_values ⇒ Object
Reception type valid values.
2690 2691 2692 |
# File 'app/models/room_configuration.rb', line 2690 def self.reception_type_valid_values @reception_type_valid_values ||= RoomConfiguration.reception_type_for_select.values end |
.rev_tag(rc) ⇒ Object
Rev tag.
669 670 671 672 673 674 675 676 677 678 679 680 |
# File 'app/models/room_configuration.rb', line 669 def self.rev_tag(rc) root_ref_nbr = root_reference_number(rc) last_revision_ref = last_revision_reference_number(root_ref_nbr) new_rev = 1 if last_revision_ref.present? last_revision_split = last_revision_ref.scan(RoomConfiguration::REFERENCE_NUMBER_PATTERN).flatten.compact last_revision_nbr = last_revision_split.try(:[], 2) new_rev += last_revision_nbr.to_i if last_revision_nbr.present? end revision_letter = root_ref_nbr.index('IQR') ? 'V' : 'R' "#{revision_letter}#{new_rev}" end |
.revision_reference_number(rc) ⇒ Object
Revision reference number.
641 642 643 |
# File 'app/models/room_configuration.rb', line 641 def self.revision_reference_number(rc) "#{root_reference_number(rc)}-#{rev_tag(rc)}" end |
.root_reference_number(rc) ⇒ Object
Root reference number.
661 662 663 |
# File 'app/models/room_configuration.rb', line 661 def self.root_reference_number(rc) rc.reference_number.scan(REFERENCE_NUMBER_PATTERN).flatten.compact.try(:[], 0) end |
.rp_rooms ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are rp rooms. Active Record Scope
507 |
# File 'app/models/room_configuration.rb', line 507 scope :rp_rooms, -> { where(reception_type: 'DesignTool2') } |
.states_for_select ⇒ Object
States for select.
617 618 619 |
# File 'app/models/room_configuration.rb', line 617 def self.states_for_select state_machines[:state].states.map { |s| [s.human_name, s.value] } end |
.template_options_for_select ⇒ Object
Template options for select.
631 632 633 |
# File 'app/models/room_configuration.rb', line 631 def self. %w[letter_landscape].map { |s| [s.humanize.gsub('Legacy letter portrait', 'Legacy letter portrait (ONLY USE for legacy plans)'), s] } end |
.update_or_create_from_rhc_args(rhc_args, options, customer, system_name, room_layout_image_params = nil) ⇒ Hash
Creates (or reuses, by share key) a room configuration from
Instant Quote rhc args, calculating the quote and adding the
selected line items.
3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 |
# File 'app/models/room_configuration.rb', line 3094 def self.update_or_create_from_rhc_args(rhc_args, , customer, system_name, room_layout_image_params = nil) return_result = {} begin RoomConfiguration.transaction do if (room = customer.room_configurations.where(additional_notes: [:share_key]).first) && (opportunity = room.opportunity) && (opportunity.opportunity_reception_type == 'IQ') # found a matching room and opportunity, use those rather than creating new ones opportunity.update(name: system_name) if system_name.present? raise AbortUpdateRhc, "opportunity.errors.full_messages: #{opportunity.errors_to_s}" unless opportunity.valid? else rhc_results = RoomConfiguration::CalculateQuote.call(rhc_args).to_hash.deep_symbolize_keys rhc_results[:output].sort_by! { |item| item[:price] } opportunity = customer.opportunities.create(name: system_name || OpportunityConstants::IQ_PROJECT_NAME, opportunity_reception_type: 'IQ') raise AbortUpdateRhc, "opportunity.errors.full_messages: #{opportunity.errors_to_s}" unless opportunity.valid? room_plan = RoomPlan.find(rhc_args[:custom_room_plan]) if rhc_args[:custom_room_plan].present? room_plan_id = room_plan&.owned_or_cloned(customer)&.id # here we just want to make sure that a saved room configuration's room plan is owned by the room configuration's customer. So same room plan if owned otherwise cloned and set to be owned by room configuration's customer. room = opportunity.room_configurations.create( name: opportunity.next_room_name(room_base_name: rhc_args[:room_type].name), room_type: rhc_args[:room_type], sub_floor_type_id: rhc_args[:sub_floor_type_id], floor_type: rhc_args[:floor_type], square_footage: rhc_args[:square_footage], insulation_surface: rhc_args[:insulation_surface], zones: rhc_args[:zones].map { |args| Zone.create(width: args[:width]&.to_s, length: args[:length]&.to_s) }, expansion_joint_spacing: rhc_args[:expansion_joint_spacing], skip_expansion_joint_validation: rhc_args[:skip_expansion_joint].to_b, cable_spacing: rhc_results[:output][[:selected_element_set] || 0][:cable_spacing], voltage: rhc_args[:voltage], coverage_state: rhc_args[:coverage_state], reception_type: rhc_args[:custom_room_plan].to_i.positive? ? 'DesignTool2' : 'IQ', room_plan_id:, additional_notes: [:share_key], heating_system_product_line: ProductLine.find_by( slug_ltree: LtreePaths.slug_ltree_from_legacy_hyphen_url( rhc_results[:output][[:selected_element_set] || 0][:heating_system_type_url] ) ) ) raise AbortUpdateRhc, "room.errors.full_messages: #{room.errors_to_s}" unless room.valid? room.apply_line_items_from_rhc_results(rhc_results, ) room.save raise AbortUpdateRhc, "room.errors.full_messages: #{room.errors_to_s}" unless room.valid? end res = true if room_layout_image_params.present? room.room_layout_image = room_layout_image_params res = room.save end return_result = { success: res, room: } rescue AbortUpdateRhc => e return_result = { success: false, errors: e.to_s } end return_result end end |
.upload_categories_for_select ⇒ Object
Upload categories for select.
698 699 700 701 702 703 704 705 706 707 |
# File 'app/models/room_configuration.rb', line 698 def self.upload_categories_for_select [['Room Layout', 'room_layout'], ['Design Guideline', 'design_guideline'], ['Tracer Solution (CAD)', 'tracer_solution_cad'], ['Tracer Solution (Image)', 'tracer_solution_image'], %w[Other other], ['Installation Plan (CAD)', 'installation_plan_cad'], ['Installation Plan (Image)', 'installation_plan_image'], ['Warranty Card', 'warranty_card']] end |
.vignettes_for_product_line_id ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are vignettes for product line id. Active Record Scope
511 |
# File 'app/models/room_configuration.rb', line 511 scope :vignettes_for_product_line_id, ->(pl_id) { where(vignette: true).where('quoted_heating_system_pl_id = ? OR heating_system_product_line_id = ?', pl_id, pl_id).order(created_at: :desc) } |
.vignettes_for_product_line_url ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are vignettes for product line url. Active Record Scope
512 513 514 515 516 |
# File 'app/models/room_configuration.rb', line 512 scope :vignettes_for_product_line_url, ->(url) { slug = LtreePaths.slug_ltree_from_legacy_hyphen_url(url) pl = ProductLine.find_by(slug_ltree: slug) pl ? vignettes_for_product_line_id(pl.id) : none } |
.with_heating_elements_count ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are with heating elements count. Active Record Scope
520 |
# File 'app/models/room_configuration.rb', line 520 scope :with_heating_elements_count, -> { select_append(Arel.sql("(#{heating_element_count_sql}) as heating_element_count")) } |
.with_item_id ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are with item id. Active Record Scope
517 |
# File 'app/models/room_configuration.rb', line 517 scope :with_item_id, ->(item_id) { where("EXISTS(SELECT 1 FROM line_items rli WHERE rli.resource_type = 'RoomConfiguration' AND rli.resource_id = room_configurations.id AND rli.item_id = ?)", item_id) } |
.with_line_items ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are with line items. Active Record Scope
495 |
# File 'app/models/room_configuration.rb', line 495 scope :with_line_items, -> { includes(line_items: { catalog_item: { store_item: :item } }) } |
.with_single_heating_element ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are with single heating element. Active Record Scope
518 |
# File 'app/models/room_configuration.rb', line 518 scope :with_single_heating_element, -> { where("(#{heating_element_count_sql}) = 1") } |
.with_vignette ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are with vignette. Active Record Scope
510 |
# File 'app/models/room_configuration.rb', line 510 scope :with_vignette, -> { where(vignette: true) } |
.without_revisions ⇒ ActiveRecord::Relation<RoomConfiguration>
A relation of RoomConfigurations that are without revisions. Active Record Scope
499 |
# File 'app/models/room_configuration.rb', line 499 scope :without_revisions, -> { where('NOT EXISTS (select id from room_configurations rc2 where rc2.parent_id = room_configurations.id)') } |
Instance Method Details
#activities ⇒ ActiveRecord::Associations::CollectionProxy
The associated activities.
397 |
# File 'app/models/room_configuration.rb', line 397 has_many :activities, as: :resource, dependent: :nullify |
#add_bom_line_item(bom_item) ⇒ Object
Adds a line item from a BOM hash (from HeatingSystemCalculator)
1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 |
# File 'app/models/room_configuration.rb', line 1714 def add_bom_line_item(bom_item) return if bom_item['cat_id'].blank? cat_item = CatalogItem.find_by(id: bom_item['cat_id']) return unless cat_item add_line_item( catalog_item_id: cat_item.id, quantity: bom_item['qty'] || 1, price: cat_item.amount, discounted_price: cat_item.discounted_price(customer, self), do_not_autosave: true ) end |
#add_line_item(options) ⇒ LineItem
Adds (or increments) a line item for the given catalog item.
1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 |
# File 'app/models/room_configuration.rb', line 1674 def add_line_item() do_not_autosave = .delete(:do_not_autosave) ci = CatalogItem.find [:catalog_item_id] keep_line_items_separate = .delete(:keep_line_items_separate) # any item with sku in SINGLE_QUANTITY_SKUS defaults to be a separate line item unless overridden with keep_line_items_separate option keep_line_items_separate ||= Item::SINGLE_QUANTITY_SKUS.include?(ci.sku) if keep_line_items_separate.nil? [:quantity] ||= 1 line_item = begin line_items.find { |li| li.catalog_item_id == [:catalog_item_id].to_i } rescue StandardError nil end if line_item && !keep_line_items_separate line_item.quantity += [:quantity].to_i else line_item = LineItem.new() line_item.price ||= line_item.catalog_item.amount line_items.build(line_item.attributes) end line_item.save unless do_not_autosave line_item end |
#add_selected_line_items_from_rhc_elements(rhc_results) ⇒ Object
Add selected line items from rhc elements.
3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 |
# File 'app/models/room_configuration.rb', line 3176 def add_selected_line_items_from_rhc_elements(rhc_results) rhc_results[:includedItems].each do |rhc_group| cat_item = CatalogItem.find(rhc_group[:cat_id]) = { quantity: rhc_group[:qty], price: cat_item.amount, discounted_price: cat_item.discounted_price(customer, self), catalog_item_id: cat_item.id, do_not_autosave: true } add_line_item() end end |
#add_selected_line_items_from_rhc_group(rhc_results, group, inds) ⇒ Object
Add selected line items from rhc group.
3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 |
# File 'app/models/room_configuration.rb', line 3194 def add_selected_line_items_from_rhc_group(rhc_results, group, inds) inds.each do |ind| rhc_group = rhc_results[group][ind] || {} (rhc_group[:includedItems] || []).each do |rhc_included_item| cat_item = CatalogItem.find(rhc_included_item[:cat_id]) = { quantity: rhc_included_item[:qty], price: cat_item.amount, discounted_price: cat_item.discounted_price(customer, self), catalog_item_id: cat_item.id, do_not_autosave: true } add_line_item() end end end |
#add_selected_line_items_from_rhc_kits(rhc_results, group, inds) ⇒ Object
Add selected line items from rhc kits.
3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 |
# File 'app/models/room_configuration.rb', line 3215 def add_selected_line_items_from_rhc_kits(rhc_results, group, inds) # here we do not process the kit included items, since those are only for show, just process the single selected kit inds.each do |ind| rhc_group = rhc_results[group][ind] cat_item = CatalogItem.find(rhc_group[:cat_id]) = { quantity: rhc_group[:qty], price: cat_item.amount, discounted_price: cat_item.discounted_price(customer, self), catalog_item_id: cat_item.id, do_not_autosave: true } add_line_item() end end |
#allow_heat_loss_calculation? ⇒ Object
Whether allow heat loss calculation.
2730 2731 2732 |
# File 'app/models/room_configuration.rb', line 2730 def allow_heat_loss_calculation? (area > 0.0) && installation_postal_code.present? && under_floor && under_floor.id.present? && ceiling && ceiling.id.present? end |
#alternate_heplo_names ⇒ Object
Alternate heplo names.
1353 1354 1355 |
# File 'app/models/room_configuration.rb', line 1353 def alternate_heplo_names alternate_heplo_ids.map { |heplo_id| HeatingElementProductLineOption.find(heplo_id).name_with_cable_spacing }.join(', ') end |
#apply_line_items_from_rhc_results(rhc_results, options) ⇒ void
This method returns an undefined value.
Adds line items for the selected element set, control, kit, and
accessories from CalculateQuote results.
3164 3165 3166 3167 3168 3169 3170 |
# File 'app/models/room_configuration.rb', line 3164 def apply_line_items_from_rhc_results(rhc_results, ) rhc_result = rhc_results[:output][[:selected_element_set] || 0] add_selected_line_items_from_rhc_elements(rhc_result) add_selected_line_items_from_rhc_group(rhc_result, :controls, [[:selected_control]].compact) add_selected_line_items_from_rhc_kits(rhc_result, :kits, [[:selected_kit]].compact) add_selected_line_items_from_rhc_group(rhc_result, :accessories, [:selected_accessories] || []) end |
#area ⇒ Object
Area.
2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 |
# File 'app/models/room_configuration.rb', line 2221 def area ((begin under_floor.area rescue StandardError nil end) || (begin ceiling.area rescue StandardError nil end) || insulation_surface || rectangular_area || square_footage).to_f end |
#belongs_only_to_legacy_quotes? ⇒ Object
Whether belongs only to legacy quotes.
1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 |
# File 'app/models/room_configuration.rb', line 1968 def belongs_only_to_legacy_quotes? res = false legacy_quotes_num = 0 quotes.each do |q| next unless q.reference_number legacy_quotes_num += 1 if q.reference_number.to_i < 300_000 end res = true if legacy_quotes_num == quotes.length && legacy_quotes_num.positive? res end |
#billing_entity ⇒ Object
Billing entity.
864 865 866 |
# File 'app/models/room_configuration.rb', line 864 def billing_entity opportunity.customer.billing_entity end |
#build_activity ⇒ Object
Build activity.
771 772 773 |
# File 'app/models/room_configuration.rb', line 771 def build_activity activities.build resource: self, party: primary_party end |
#cable_spacing_mismatch? ⇒ Object
Whether cable spacing mismatch.
845 846 847 848 849 850 |
# File 'app/models/room_configuration.rb', line 845 def cable_spacing_mismatch? return false unless require_cable_spacing? return false if installation_plan_cable_spacing.blank? cable_spacing != installation_plan_cable_spacing end |
#cad_files ⇒ ActiveRecord::Associations::CollectionProxy
The associated cad files.
391 |
# File 'app/models/room_configuration.rb', line 391 has_many :cad_files, -> { where(category: 'installation_plan_cad') }, as: :resource, class_name: 'Upload', dependent: :destroy |
#calculate_heat_loss ⇒ Object
Calculate heat loss.
2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 |
# File 'app/models/room_configuration.rb', line 2796 def calculate_heat_loss # Assumptions: # - Constant hours of comfort/economy operation per weekday/weekend from thermostat defaults # - WY system is primary heat source; warm up/cool off time is negligible # - Heat supplied equals heat loss at ambient temperature in stable state # - Economy mode heat loss is proportional to comfort mode via temperature ratio # - Comfort ambient temperature is user's desired temperature # economy ambient temperature is the default thermostat default ambient setting # use average number of weekdays vs weekends per month, derived from averaging actual number in 4 year cycle # set up results res = {} res['hlc_averages'] = [] res['hlc_ranges'] = [] res['heat_supplied'] = [] res['hlc_by_object'] = [] res['avg_temperatures'] = [] res['avg_temperature_ranges'] = [] res['ambient_temperatures'] = [] res['ambient_temperature_ranges'] = [] res['operating_cost'] = [] res['loss_exceeds_heat_supply'] = [] res['recommendations'] = [] res['recommendation_notes'] = [] res['operating_hrs'] = [] res['operating_cost'] = [] # set initial coldest heat loss for pie chart, want worst case at coldest month of the year at comfort operation tavg_hlh_coldest = nil # choose highest initial temperature tavg_coldest = 1000.0 # decide if we use room's heating system or theoretical based on 80% coverage of room area using the room's heating system, default to TZ Flex Roll if get_heat_supplied == 0.0 hstn = heating_system_type_name.to_s hstn = "#{heating_system_type_name} #{cable_spacing.round}" if cable_spacing.present? && heating_system_type_name.to_s.index('TempZone') heat_supplied = ((WATTS_PER_SQUARE_FOOT[hstn || 'TempZone Flex Roll'] || 12.0) * 0.8 * area * BTU_PER_HOUR_PER_WATT).round else heat_supplied = get_heat_supplied.round end # set up initial counts of when heat supply meets heat loss num_months_heat_supplied_meets_loss = 0 # get average monthly temperature data using room's location temp_data = AverageMonthlyTemperature.get_from_postal_code(installation_postal_code) return { error: temp_data[:message] } if temp_data[:status] != :ok # get utility rate $ cost per kwH using room's location rate_data = ElectricityRate.get_from_postal_code(installation_postal_code) return { error: rate_data[:message] } if rate_data[:status] != :ok # here we favor opportunity rate if defined, fall back to the ElectricityRate from postal code # Default to $0.15/kWh if no rate available (US national average) if opportunity&.electricity_rate avg_cost_per_kwh = opportunity.electricity_rate electricity_rate_blurb = '(from your project settings)' elsif rate_data[:average_rate].present? avg_cost_per_kwh = rate_data[:average_rate] electricity_rate_blurb = '(from government published utility rates based on your location)' else avg_cost_per_kwh = ElectricityRate::US_AVERAGE_RATE electricity_rate_blurb = '(using US national average rate)' end # set up initial operating costs = 0.0 = 0.0 hl_max = 0.0 hl_sources = heat_loss_children_recursive([]) # iterate over the months 12.times do |i| # get average daily outside temperature for the month tavg = temp_data[:average_temperatures][i] # get average daily outside temperature variation for the month and use to calculate average min and max temperatures tdelta = temp_data[:temperature_variations][i] tmin = tavg - tdelta tmax = tavg + tdelta # puts "calculate_heat_loss, tavg: #{tavg}" # puts "calculate_heat_loss, tmin: #{tmin}" # puts "calculate_heat_loss, tmax: #{tmax}" # calculate heat loss per source during comfort heating at desired temperature, this will be used for the pie chart tavg_hlh_comfort = self_and_children_heat_loss_recursive(desired_temperature, tavg, []) # calculte total heat losses at comfort and economy inside temperatures and the avg, min and max outside temperatures hl_avg_comfort = tavg_hlh_comfort.sum { |o| o[:heat_loss] } hl_avg_economy = get_self_and_children_heat_loss(DEFAULT_ECONOMY_AMB_TEMP, tavg) hl_min_comfort = get_self_and_children_heat_loss(desired_temperature, tmax) hl_min_economy = get_self_and_children_heat_loss(DEFAULT_ECONOMY_AMB_TEMP, tmax) hl_max_comfort = get_self_and_children_heat_loss(desired_temperature, tmin) hl_max_economy = get_self_and_children_heat_loss(DEFAULT_ECONOMY_AMB_TEMP, tmin) # then get weighted average for these based on the thermostat default heating periods and number of week days vs week end days hl_avg = get_weighted_average_heat_loss(hl_avg_comfort, hl_avg_economy) hl_min = get_weighted_average_heat_loss(hl_min_comfort, hl_min_economy) hl_max = get_weighted_average_heat_loss(hl_max_comfort, hl_max_economy) # store these heat losses and max WY heat supplied per month res['hlc_averages'] << { 'heat_loss' => hl_avg } res['hlc_ranges'] << { 'range' => [hl_min, hl_max] } res['heat_supplied'] << { 'heat_supplied' => heat_supplied } if (heat_supplied >= hl_avg * (100.0 + HLC_PRIMARY_OK_THRESHOLD[:percent]) / 100.0) && (heat_supplied >= (hl_avg + HLC_PRIMARY_OK_THRESHOLD[:btu_per_hr])) # if we meet or exceed heat loss we are good # increment num_months_heat_supplied_meets_loss num_months_heat_supplied_meets_loss += 1 # store ambient temperature reached as desired res['ambient_temperatures'] << { 'temperature' => desired_temperature } # store ambient temperature range of +- delta of 3 degrees, for fuzziness res['ambient_temperature_ranges'] << { 'range' => [(desired_temperature.to_f - 3.0).round, (desired_temperature.to_f + 3.0).round] } # store loss_exceeds_heat_supply flag as false for hilighting on charts res['loss_exceeds_heat_supply'] << { 'exceeds' => false } else # if we do NOT meet or exceed heat loss # calculate reachable ambient comfort temperature based on steady state where heat loss will equal heat supplied, at that temp, ie based on linear ratio tamb = desired_temperature.to_f * (heat_supplied / hl_avg_comfort).to_f # store ambient temperature reached res['ambient_temperatures'] << { 'temperature' => tamb.round } # store ambient temperature range of +- delta of 3 degrees, for fuzziness res['ambient_temperature_ranges'] << { 'range' => [(tamb - 3.0).round, (tamb + 3.0).round] } # store loss_exceeds_heat_supply flag as true for hilighting on charts res['loss_exceeds_heat_supply'] << { 'exceeds' => true } end # store avg outside temperature with range of +- delta res['avg_temperatures'] << { 'temperature' => tavg } res['avg_temperature_ranges'] << { 'range' => [tmin, tmax] } = RoomConfiguration::OperatingCostsCalculator.get_monthly_operation_kwh(hl_avg_comfort, hl_avg_economy) # accumulate annual operation cost for this month by calculating kwH and using utility rate operation_cost_this_month = [ * avg_cost_per_kwh, 0.0].max res['operating_hrs'] << res['operating_cost'] << operation_cost_this_month += operation_cost_this_month # if this is a colder month store the heat loss at comfort temp next unless tavg < tavg_coldest tavg_hlh_coldest = tavg_hlh_comfort tavg_coldest = tavg = operation_cost_this_month hl_max = hl_max_comfort end # for the coldest month at comfort mode, show each heat loss source, ok_col_ind = 0 flag_col_ind = 0 tavg_hlh_coldest.each do |o| hlc_by_object = { 'name' => o[:object].heat_loss_name.to_s, 'heat_loss' => o[:heat_loss] } if begin (o[:object].get_u_value > Models::HeatLossable::HIGH_U_VALUE_THRESHOLD) rescue StandardError false end hlc_by_object['color'] = Models::HeatLossable::PIE_CHART_FLAG_COLORS[flag_col_ind] flag_col_ind += 1 flag_col_ind = 0 if flag_col_ind >= Models::HeatLossable::PIE_CHART_FLAG_COLORS.length else hlc_by_object['color'] = Models::HeatLossable::PIE_CHART_OK_COLORS[ok_col_ind] ok_col_ind += 1 ok_col_ind = 0 if ok_col_ind >= Models::HeatLossable::PIE_CHART_OK_COLORS.length end res['hlc_by_object'] << hlc_by_object end # append recommendations and results res['recommendations'] << if get_heat_supplied == 0.0 "A WarmlyYours #{heating_system_type_name || 'TempZone Flex Roll'} system with 80% coverage would supply #{heat_supplied} BTU/hour." else "The WarmlyYours #{heating_system_type_name} system in this room can supply #{heat_supplied} BTU/hour." end if num_months_heat_supplied_meets_loss >= RoomConfigurationConstants::MONTHS_FOR_PRIMARY_HEAT res['recommendations'] << 'The WarmlyYours system above can be the primary heat source for this room.' else if num_months_heat_supplied_meets_loss >= RoomConfigurationConstants::MONTHS_FOR_THREE_SEASON_HEAT recos = [] reco_tzfr = (heating_system_type_name != 'TempZone Flex Roll') && heating_system_type_name.to_s.index('TempZone') flex_roll_watts = WATTS_PER_SQUARE_FOOT['TempZone Flex Roll'].to_i recos << "using a TempZone Flex Roll system which can supply #{flex_roll_watts} watts/sq.ft." if reco_tzfr recos << 'increasing the coverage of your heated areas' hs_needed = hl_max - heat_supplied recos << "or adding a supplemental heat source of #{hs_needed.round.abs} BTU/hour (or #{(hs_needed / BTU_PER_HOUR_PER_WATT).round.abs} watts) on the coldest months" res['recommendations'] << "The WarmlyYours system above can be the primary heat source for this room for three seasons. To reach your desired ambient temperature, please consider #{recos.join(', ')}" else res['recommendations'] << 'The WarmlyYours system above can only be a supplemental heat source for this room. You will need a primary heat source to reach your desired ambient temperature.' end hlc_need_insulation = [] hl_sources.each do |o| hlc_need_insulation << o if o.get_u_value > Models::HeatLossable::HIGH_U_VALUE_THRESHOLD end if hlc_need_insulation.any? res['recommendations'] << "You may also consider replacing or adding insulation to the following: #{hlc_need_insulation.map(&:heat_loss_name).join(', ')}. #{hlc_need_insulation.length > 1 ? 'They are' : 'It is'} contributing to a greater than normal heat loss." end if line_items.underlayments.empty? && under_floor.under_floor_type&.needs_underlayment? && insulation_surface.to_i.positive? && (under_floor.get_u_value > Models::HeatLossable::HIGH_U_VALUE_THRESHOLD) underlayment_sugg_lis = HeatingElementProductLineOption.get_suggested_underlayments_for_room(self) underlayment_sugg = underlayment_sugg_lis.map { |k, h| "#{h[:quantity]} X #{h[:name]}, SKU: #{k}" } res['recommendations'] << "You may also consider adding underlayment to your WarmlyYours heating system. We recommend: #{underlayment_sugg.join(', ')}" unless underlayment_sugg.empty? end end res['recommendations'] << "The annual operating costs* of this WarmlyYours system will be: #{ActionController::Base.helpers.number_to_currency(.round(2), unit: currency_symbol)}." res['recommendations'] << "The monthly operating cost of this system on the coldest month will be: #{ActionController::Base.helpers.number_to_currency(.round(2), unit: currency_symbol)}." res['recommendations'] << "Operating costs assume an average annual residential electricity rate of: #{ActionController::Base.helpers.number_to_currency(avg_cost_per_kwh.round(2), unit: currency_symbol)}/kilowatt-hours #{electricity_rate_blurb}." res['recommendations'] << "Operating costs also assume heating hours per day on a monthly basis to achieve the desired 'comfort' ambient temperature for the following warming periods: Monday-Friday: 6:00 a.m.-8:30 a.m. and 5:00 p.m.-11:00 p.m., and Saturday-Sunday: 6:00 a.m.-11:00 p.m. and assuming an 'economy'/non heating hour ambient temperature of #{DEFAULT_ECONOMY_AMB_TEMP} F or #{PresetJob.fahrenheit_to_celsius(DEFAULT_ECONOMY_AMB_TEMP)} C" res['recommendation_notes'] << 'WarmlyYours makes no claim or warrant as to the amount of floor/room temperature rise, the time to reach a given floor/room temperature or final floor/room temperature due to the innumerable variations in building construction and environmental conditions. This heat loss calculation is an estimate based on the inputs given, and average temperature forecast data.' res['operating_cost_annual'] = # hlc_h = hstorify_heat_loss(res) update_attribute(:last_heat_loss, res) res end |
#calculate_operating_cost_rate_using_hep ⇒ Object
Calculate operating cost rate using hep.
2420 2421 2422 2423 2424 2425 2426 2427 2428 |
# File 'app/models/room_configuration.rb', line 2420 def hep_tfr = Item::HeatingElementPlan.new_from_room_configuration(self) res = if hep_tfr.electrical_consumption.nil? nil else hep_tfr.electrical_consumption[:rate] end res.to_f.round(2) end |
#calculate_total_amps ⇒ Object
Calculate total amps.
2069 2070 2071 2072 |
# File 'app/models/room_configuration.rb', line 2069 def calculate_total_amps # Include :item to avoid N+1 when accessing he.item.amps heating_elements.includes(:item).sum { |he| he.quantity * he.item.amps.to_f }.round(2) end |
#calculate_total_kilowatts ⇒ Object
Calculate total kilowatts.
2084 2085 2086 |
# File 'app/models/room_configuration.rb', line 2084 def calculate_total_kilowatts calculate_total_watts / 1000.0 end |
#calculate_total_watts ⇒ Object
Calculate total watts.
2077 2078 2079 |
# File 'app/models/room_configuration.rb', line 2077 def calculate_total_watts heating_elements.to_a.sum { |he| he.quantity * he.item.watts.to_f } end |
#can_add_to_cart? ⇒ Object
Whether can add to cart.
2381 2382 2383 2384 2385 2386 |
# File 'app/models/room_configuration.rb', line 2381 def can_add_to_cart? %w[draft complete in_design].include?(state) && line_items.non_shipping.present? && quotes.any? do |q| q.awaiting_transmission? || q.complete? end end |
#can_calculate_heat_loss? ⇒ Object
Whether can calculate heat loss.
2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 |
# File 'app/models/room_configuration.rb', line 2737 def can_calculate_heat_loss? status = :ok errors = [] self.enter_heat_loss_info = true if valid? heat_loss_children_recursive([]).each do |c| unless c.valid? errors << "#{c.name}: #{c.errors_to_s}" status = :error end end if status == :ok temp_data = AverageMonthlyTemperature.get_from_postal_code(installation_postal_code) if temp_data[:status] != :ok errors << temp_data[:message] status = :error end end if status == :ok rate_data = ElectricityRate.get_from_postal_code(installation_postal_code) if rate_data[:status] != :ok errors << rate_data[:message] status = :error end end else status = :error end { status:, errors: } end |
#can_have_installation_plan? ⇒ Object
Whether can have installation plan.
1256 1257 1258 |
# File 'app/models/room_configuration.rb', line 1256 def can_have_installation_plan? in_design? || awaiting_quality_control? end |
#can_have_room_layout? ⇒ Object
Whether can have room layout.
1249 1250 1251 |
# File 'app/models/room_configuration.rb', line 1249 def can_have_room_layout? draft? || in_design? end |
#cancelable? ⇒ Object
Whether cancelable.
1240 1241 1242 1243 1244 |
# File 'app/models/room_configuration.rb', line 1240 def cancelable? (state.nil? || CANCELABLE_STATES.include?(state.to_sym)) && quotes.active.empty? && orders.not_cancelled.empty? end |
#catalog ⇒ Object
Alias for Customer#catalog
484 |
# File 'app/models/room_configuration.rb', line 484 delegate :catalog, to: :customer |
#ceiling ⇒ Ceiling?
The associated ceiling.
416 |
# File 'app/models/room_configuration.rb', line 416 has_one :ceiling, dependent: :destroy |
#check_room_layout_or_note_attached ⇒ Object
Check room layout or note attached.
1170 1171 1172 1173 1174 1175 |
# File 'app/models/room_configuration.rb', line 1170 def check_room_layout_or_note_attached # puts "reception_type: #{reception_type}" result = room_layout_or_note_attached? errors.add(:base, 'Room Layout or some design guide note or dimensions must be attached to room for engineering.') if result == false result end |
#company ⇒ Object
Alias for Customer#company
483 |
# File 'app/models/room_configuration.rb', line 483 delegate :company, to: :customer |
#config_name ⇒ Object
Config name.
1601 1602 1603 1604 1605 1606 1607 1608 1609 |
# File 'app/models/room_configuration.rb', line 1601 def config_name new_name = [] new_name << floor_type.name.to_s if floor_type new_name << ", #{pretty_coverage_state_description}" if coverage_state new_name << ", #{heplo_summary}" if heplo_summary new_name << " (#{voltage_id}V)" if voltage_id new_name << " #{revision}" if revision new_name.compact.uniq.join end |
#config_pretty ⇒ Object
Config pretty.
1614 1615 1616 1617 1618 1619 |
# File 'app/models/room_configuration.rb', line 1614 def config_pretty new_name = [] new_name << heplo_summary(true).to_s if heplo_summary(true) new_name << " (#{voltage_id}V)" if voltage_id new_name.compact.uniq.join end |
#control_voltage ⇒ Object
Control voltage.
2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 |
# File 'app/models/room_configuration.rb', line 2099 def control_voltage res = nil rc = controlled_by || self # yeesh, we moved old smartstats etc out of thermostats! thermostats = (rc.line_items.thermostats.to_a + rc.line_items.smartstats.to_a + rc.line_items.easystats.to_a) if thermostats.any? && thermostats.to_a.all? { |li| !li.item.is_dual_voltage? } && (thermostats.filter_map { |li| li.item.voltage }.uniq.length == 1) tstat = thermostats.first.item res = tstat.voltage elsif rc.line_items.integration_kits&.to_a&.all? { |li| !li.item.is_dual_voltage? } && (rc.line_items.integration_kits.map { |li| li.item.voltage }.uniq.length == 1) int_kit = rc.line_items.integration_kits.first.item res = int_kit.voltage end res end |
#controlled_by ⇒ RoomConfiguration?
The associated controlled by.
339 |
# File 'app/models/room_configuration.rb', line 339 belongs_to :controlled_by, class_name: 'RoomConfiguration', optional: true |
#controlled_rooms ⇒ ActiveRecord::Associations::CollectionProxy
The associated controlled rooms.
382 |
# File 'app/models/room_configuration.rb', line 382 has_many :controlled_rooms, class_name: 'RoomConfiguration', foreign_key: 'controlled_by_id', dependent: :nullify |
#controlled_rooms_by_quote(quote) ⇒ Object
Controlled rooms by quote.
1273 1274 1275 |
# File 'app/models/room_configuration.rb', line 1273 def controlled_rooms_by_quote(quote) controlled_rooms.select { |r| quote.room_configurations.include? r } end |
#coverage_percentage ⇒ Object
Coverage percentage.
3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 |
# File 'app/models/room_configuration.rb', line 3047 def coverage_percentage max_pct = RoomConfigurationConstants::MAX_COVERAGE_PERCENTAGE if last_bom.present? && last_bom['coverage_percentage'].present? last_bom['coverage_percentage'] elsif square_footage.present? && installation_sqft.present? && square_footage.positive? && installation_sqft.positive? [(max_pct * installation_sqft / square_footage).round, max_pct.to_i].min elsif installation_sqft.present? && installation_sqft.positive? max_pct end end |
#create_and_link_vignette_installation_plan_image ⇒ Object
Create and link vignette installation plan image.
3061 3062 3063 |
# File 'app/models/room_configuration.rb', line 3061 def create_and_link_vignette_installation_plan_image update(vignette: true) end |
#create_heatloss_followup_activity(user, upload_link) ⇒ Object
Create heatloss followup activity.
2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 |
# File 'app/models/room_configuration.rb', line 2312 def create_heatloss_followup_activity(user, upload_link) # unless you've already got one return if activities.open_activities.where(activity_type_id: ActivityTypeConstants::HEATLOS).any? Activity.create(lock_target_datetime: true, activity_type_id: ActivityTypeConstants::HEATLOS, target_datetime: 30.seconds.from_now, assigned_resource: user, party: customer, resource: self, notes: "Heat Loss Customer Form, please generate a Heat Loss Report, see attachments tab or #{upload_link}.") end |
#create_revision(copy_line_items = false, copy_room_layout = false, copy_installation_plan = false) ⇒ Object
Create revision.
1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 |
# File 'app/models/room_configuration.rb', line 1835 def create_revision(copy_line_items = false, copy_room_layout = false, copy_installation_plan = false) new_rc = nil RoomConfiguration.transaction do new_rc = deep_dup new_rc.plan_created_at = copy_installation_plan ? Date.current : nil new_rc.save! if copy_line_items line_items.parents_only.each do |li| new_li = li.deep_dup new_li.children_count = nil new_li.room_configuration = new_rc new_rc.line_items << new_li end end if copy_room_layout && (room_layout_upload = uploads.room_layouts.first) new_room_layout_upload = room_layout_upload.clone_with_file(new_rc) new_room_layout_upload&.save! end if copy_installation_plan if (old_install_plan_cad = begin uploads.installation_plan_cads.first rescue StandardError nil end) install_plan_cad = old_install_plan_cad.clone_with_file(new_rc) install_plan_cad&.save! end if (old_install_plan_image = uploads.installation_plan_images.first) install_plan_image = old_install_plan_image.clone_with_file(new_rc) install_plan_image&.save! end end end new_rc end |
#crm_link ⇒ Object
Crm link.
2055 2056 2057 |
# File 'app/models/room_configuration.rb', line 2055 def crm_link UrlHelper.instance.room_configuration_path(self) end |
#currency_symbol ⇒ Object
Currency symbol.
2023 2024 2025 |
# File 'app/models/room_configuration.rb', line 2023 def currency_symbol Money::Currency.new(currency).symbol end |
#customer ⇒ Object
Alias for Opportunity#customer
482 |
# File 'app/models/room_configuration.rb', line 482 delegate :customer, to: :opportunity |
#deep_dup ⇒ Object
Deep dup.
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'app/models/room_configuration.rb', line 190 def deep_dup deep_clone( include: :zones, except: %i[reference_number parent_id plan_created_at created_at creator_id updated_at updater_id floorplanner_employee_id designer_employee_id labeler_employee_id installation_plan_qc_employee_id quoted_heating_system_pl_id installation_plan_cable_spacing] ) do |original, copy| if copy.is_a?(RoomConfiguration) copy.state = 'draft' copy.vignette = false copy.parent_id = original.id copy.reference_number = RoomConfiguration.revision_reference_number(original) end end end |
#deletable?(current_user) ⇒ Object
Whether deletable.
1233 1234 1235 |
# File 'app/models/room_configuration.rb', line 1233 def deletable?(current_user) (state != 'complete') || current_user.has_role?('engineering_manager') end |
#design_tool_params_hsh ⇒ Object
Design tool params hsh.
2367 2368 2369 |
# File 'app/models/room_configuration.rb', line 2367 def design_tool_params_hsh DesignTool::Configurator.new(room_configuration: self).to_hsh end |
#designer_employee ⇒ Employee?
The associated designer employee.
345 |
# File 'app/models/room_configuration.rb', line 345 belongs_to :designer_employee, class_name: 'Employee', optional: true |
#dimension_label ⇒ Object
Dimension label.
2199 2200 2201 2202 2203 2204 2205 2206 2207 |
# File 'app/models/room_configuration.rb', line 2199 def dimension_label if room_length && room_width "#{room_length_raw} x #{room_width_raw}" elsif room_length room_length_raw.to_s elsif room_width room_width_raw.to_s end end |
#dimensions_label ⇒ Object
Dimensions label.
1591 1592 1593 1594 1595 1596 |
# File 'app/models/room_configuration.rb', line 1591 def dimensions_label res = nil res_arr = zones.map(&:dimension_label) res = res_arr.join(', ') unless res_arr.empty? res end |
#easy_mat? ⇒ Object
Alias for Heating_system_product_line#easy_mat?
487 |
# File 'app/models/room_configuration.rb', line 487 delegate :flex_roll?, :easy_mat?, :environ_flex_roll?, to: :heating_system_product_line |
#editing_locked? ⇒ Object
Whether editing locked.
947 948 949 |
# File 'app/models/room_configuration.rb', line 947 def editing_locked? complete? || cancelled? || orders.room_not_pickable.exists? end |
#effective_voltage(voltage_only = false) ⇒ Object
Effective voltage.
835 836 837 838 839 840 |
# File 'app/models/room_configuration.rb', line 835 def effective_voltage(voltage_only = false) v = line_items.primary_heating_system_voltage return (v || RoomConfigurationConstants::DEFAULT_VOLTAGE).round if voltage_only "#{(v || RoomConfigurationConstants::DEFAULT_VOLTAGE).round} Volts" end |
#electrical_file_name(with_extension = true) ⇒ Object
Electrical file name.
2092 2093 2094 |
# File 'app/models/room_configuration.rb', line 2092 def electrical_file_name(with_extension = true) "electrical_plan_#{reference_number}#{'.pdf' if with_extension}" end |
#electrical_plan_pdf ⇒ Object
Electrical plan pdf.
1530 1531 1532 |
# File 'app/models/room_configuration.rb', line 1530 def electrical_plan_pdf uploads.electrical_plan_pdfs.sorted_by_position.first end |
#electrician ⇒ Customer?
The associated electrician.
367 |
# File 'app/models/room_configuration.rb', line 367 belongs_to :electrician, class_name: 'Customer', optional: true, deprecated: true |
#element_pole_assignments ⇒ ActiveRecord::Associations::CollectionProxy
The associated element pole assignments.
412 |
# File 'app/models/room_configuration.rb', line 412 has_many :element_pole_assignments, dependent: :destroy |
#email_for_plan_request_confirmation ⇒ Object
Email for plan request confirmation.
2295 2296 2297 |
# File 'app/models/room_configuration.rb', line 2295 def email_for_plan_request_confirmation party_for_plan_request_confirmation.email || customer.email || party_for_plan_request_confirmation.account&.email || customer.account&.email end |
#engineer_signature_tag ⇒ Object
Creates an engineer signature tag for installation plan
1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 |
# File 'app/models/room_configuration.rb', line 1981 def engineer_signature_tag tag = [] begin tag << floorplanner_employee.short_name rescue StandardError '-' end begin tag << designer_employee.short_name rescue StandardError '-' end begin tag << labeler_employee.short_name rescue StandardError '-' end begin tag << installation_plan_qc_employee.short_name rescue StandardError '-' end tag.join('/') end |
#entering_heat_loss_info? ⇒ Object
Whether entering heat loss info.
2697 2698 2699 |
# File 'app/models/room_configuration.rb', line 2697 def entering_heat_loss_info? enter_heat_loss_info end |
#environ_flex_roll? ⇒ Object
Alias for Heating_system_product_line#environ_flex_roll?
487 |
# File 'app/models/room_configuration.rb', line 487 delegate :flex_roll?, :easy_mat?, :environ_flex_roll?, to: :heating_system_product_line |
#environment ⇒ Object
Alias for Room_type#environment
485 |
# File 'app/models/room_configuration.rb', line 485 delegate :environment, to: :room_type |
#ev2_volume_discount(msrp = false) ⇒ Object
Ev2 volume discount.
1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 |
# File 'app/models/room_configuration.rb', line 1799 def ev2_volume_discount(msrp = false) discount = BigDecimal(0) ev2_subtotal = subtotal_ev2(msrp) if (ev2_subtotal >= RoomConfigurationConstants::EV2_VOLUME_DISCOUNT_THRESHOLD_LOW) && (ev2_subtotal < RoomConfigurationConstants::EV2_VOLUME_DISCOUNT_THRESHOLD_HIGH) discount = (ev2_subtotal * RoomConfigurationConstants::EV2_VOLUME_DISCOUNT_PERCENT_LOW) / 100 elsif ev2_subtotal >= RoomConfigurationConstants::EV2_VOLUME_DISCOUNT_THRESHOLD_HIGH discount = (ev2_subtotal * RoomConfigurationConstants::EV2_VOLUME_DISCOUNT_PERCENT_HIGH) / 100 end discount end |
#event_flow_name ⇒ Object
Legacy iqd_total method removed - IQ system deprecated
1359 1360 1361 |
# File 'app/models/room_configuration.rb', line 1359 def event_flow_name event_flow.try(:name) end |
#exclude_manually_initiated_event?(_event) ⇒ Object
Whether exclude manually initiated event.
610 611 612 |
# File 'app/models/room_configuration.rb', line 610 def exclude_manually_initiated_event?(_event) false end |
#exterior_walls ⇒ ActiveRecord::Associations::CollectionProxy
The associated exterior walls.
422 |
# File 'app/models/room_configuration.rb', line 422 has_many :exterior_walls, -> { order('exterior_walls.id ASC NULLS LAST') }, dependent: :destroy |
#file_name(with_extension = true) ⇒ Object
File name.
2676 2677 2678 |
# File 'app/models/room_configuration.rb', line 2676 def file_name(with_extension = true) "installation_plan_#{reference_number}#{'.pdf' if with_extension}" end |
#find_recommended_accessories(options = {}) ⇒ Array
Finds accessories recommended for this room's heating elements and
controls.
2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 |
# File 'app/models/room_configuration.rb', line 2456 def find_recommended_accessories( = {}) return [] if get_heating_system_type.blank? hsc = HeatingSystemCalculator::BaseCalculator.new(room_configuration: self) return [] if hsc.heating_system_items.nil? || hsc.heating_system_items.error elements = hsc.heating_system_items.line_items_to_bom_elements(line_items.heating_elements.with_associations) controlled_rooms_to_use = controlled_rooms controlled_rooms_to_use = controlled_rooms.select { |rc| [:container].room_configuration_ids.include?(rc.id) } if [:container].respond_to?(:room_configurations) controlled_rooms_to_use.each do |rc| elements += hsc.heating_system_items.line_items_to_bom_elements(rc.line_items.heating_elements.with_associations) end high_voltage_control_line_items = if line_items.power_modules.any? line_items.power_modules elsif line_items.integration_kits.any? line_items.integration_kits else line_items.thermostats end controls = hsc.heating_system_items.line_items_to_bom_controls(high_voltage_control_line_items.with_associations) accessories_res = hsc.find_accessories(elements, controls) return [] if accessories_res.error accessories_res.accessories end |
#flex_roll? ⇒ Object
Alias for Heating_system_product_line#flex_roll?
487 |
# File 'app/models/room_configuration.rb', line 487 delegate :flex_roll?, :easy_mat?, :environ_flex_roll?, to: :heating_system_product_line |
#floor_plan ⇒ Object
Floor plan.
1434 1435 1436 |
# File 'app/models/room_configuration.rb', line 1434 def floor_plan installation_plan_image || room_layout_image end |
#floor_plan_display_room_configurations ⇒ ActiveRecord::Associations::CollectionProxy
The associated floor plan display room configurations.
406 |
# File 'app/models/room_configuration.rb', line 406 has_many :floor_plan_display_room_configurations, dependent: :destroy |
#floor_plan_displays ⇒ ActiveRecord::Associations::CollectionProxy
The associated floor plan displays.
409 |
# File 'app/models/room_configuration.rb', line 409 has_many :floor_plan_displays, through: :floor_plan_display_room_configurations |
#floor_type ⇒ FloorType?
The associated floor type.
324 |
# File 'app/models/room_configuration.rb', line 324 belongs_to :floor_type, optional: true |
#floor_type_name ⇒ Object
Floor type name.
1366 1367 1368 |
# File 'app/models/room_configuration.rb', line 1366 def floor_type_name floor_type.try(:name) end |
#floorplan_quote_parent_line_items ⇒ Object
Floorplan quote parent line items.
1294 1295 1296 1297 1298 1299 |
# File 'app/models/room_configuration.rb', line 1294 def floorplan_quote_parent_line_items # quotes.last_revisions.first.line_items.non_shipping.parents_only.product_category_sorted quotes.first.line_items.non_shipping.parents_only.product_category_sorted rescue StandardError nil end |
#floorplanner_employee ⇒ Employee?
The associated floorplanner employee.
342 |
# File 'app/models/room_configuration.rb', line 342 belongs_to :floorplanner_employee, class_name: 'Employee', optional: true |
#generate_all_plans ⇒ Object
Generate all plans.
2497 2498 2499 2500 2501 2502 2503 2504 |
# File 'app/models/room_configuration.rb', line 2497 def generate_all_plans %i[generate_installation_plan_pdf generate_electrical_plan_pdf generate_multizone_plan_pdf].each do |method| public_send(method) rescue StandardError => e Rails.logger.error "[RoomConfiguration#generate_all_plans] #{method} failed for RC #{id}: #{e.class} - #{e.}" Appsignal.send_error(e) end end |
#generate_bill_of_materials ⇒ Object
Generate bill of materials.
2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 |
# File 'app/models/room_configuration.rb', line 2328 def generate_bill_of_materials bill_of_materials = HeatingSystemCalculator::BaseCalculator.new( room_configuration: self ).calculate_system unless line_items.empty? line_items.destroy_all reload end return false unless bill_of_materials['found_solution'] self.last_bom = hstorify_bom(bill_of_materials) populate_line_items_from_bom_results(bill_of_materials) true end |
#generate_electrical_plan_pdf(suggested_skus = [], preview = false, version: 'v2') ⇒ Object
Generate electrical plan pdf.
2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 |
# File 'app/models/room_configuration.rb', line 2654 def generate_electrical_plan_pdf(suggested_skus = [], preview = false, version: 'v2') return nil if is_countertop? || line_items.empty? uploads.electrical_plan_pdfs.destroy_all unless preview klass = version == 'v1' ? Pdf::Document::ElectricalPlanLegacy : Pdf::Document::ElectricalPlan pdf_data = klass.new(suggested_skus, self).call return pdf_data if preview.to_b save_path = File.join(Rails.application.config.x.temp_storage_path.to_s, electrical_file_name) File.binwrite(save_path, pdf_data) upload = Upload.uploadify(save_path, 'electrical_plan_pdf', self, electrical_file_name) uploads << upload upload end |
#generate_individual_install_plan_pdf(plan, version: 'v2') ⇒ Object
Generate individual install plan pdf.
2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 |
# File 'app/models/room_configuration.rb', line 2559 def generate_individual_install_plan_pdf(plan, version: 'v2') klass = version == 'v1' ? Pdf::Document::RoomConfigurationLegacy : Pdf::Document::RoomConfiguration pdf_data = klass.call(self, plan).pdf file_name = "installation_plan_#{id}-#{plan.id}.pdf" Rails.root.join('tmp', file_name).binwrite(pdf_data) pdf_data rescue StandardError => e Rails.logger.error "[RoomConfiguration#generate_individual_install_plan_pdf] " \ "Failed for RC #{id}, Upload #{plan.id}: #{e.class} - #{e.}" Appsignal.send_error(e) nil end |
#generate_installation_plan_pdf(version: 'v2') ⇒ Object
Generate installation plan pdf.
2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 |
# File 'app/models/room_configuration.rb', line 2532 def generate_installation_plan_pdf(version: 'v2') return unless uploads.installation_plan_images.present? || uploads.installation_heated_areas.present? pdf = PdfCombinator.new uploads.installation_plan_images.each do |plan| pdf_data = generate_individual_install_plan_pdf(plan, version: version) pdf << pdf_data if pdf_data end uploads.installation_heated_areas.each do |plan| pdf_data = generate_individual_install_plan_pdf(plan, version: version) pdf << pdf_data if pdf_data end return if pdf.pages.empty? pdf.save old_upload_ids = uploads.installation_plan_pdfs.ids upload = Upload.uploadify_from_data(file_name:, data: pdf.to_pdf, category: 'installation_plan_pdf', resource: self) uploads << upload Upload.destroy_by(id: old_upload_ids) if old_upload_ids.present? upload end |
#generate_multizone_plan_pdf(version: 'v2') ⇒ Object
Generate multizone plan pdf.
2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 |
# File 'app/models/room_configuration.rb', line 2598 def generate_multizone_plan_pdf(version: 'v2') return if uploads.multizone_plans.blank? pdf = PdfCombinator.new uploads.multizone_plans.each do |plan| pdf_data = generate_individual_install_plan_pdf(plan, version: version) pdf << pdf_data if pdf_data end return if pdf.pages.empty? pdf.save old_upload_ids = uploads.multizone_plan_pdfs.ids upload = Upload.uploadify_from_data(file_name:, data: pdf.to_pdf, category: 'multizone_plan_pdf', resource: self) uploads << upload Upload.destroy_by(id: old_upload_ids) if old_upload_ids.present? upload end |
#get_bom_elements_from_line_items ⇒ Object
Get bom elements from line items.
2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 |
# File 'app/models/room_configuration.rb', line 2130 def get_bom_elements_from_line_items bom_elements = [] heating_elements.each do |he| cat_item = he.catalog_item helem = cat_item.item bom_helement = { 'sku' => helem.sku, 'family_name' => (begin helem.product_lines.first.name rescue StandardError '' end), 'width' => helem.width.to_f, 'length' => helem['length'].to_f, # don't ask me why 'area' => helem.width.to_f * helem['length'].to_f / 144.0, # sq ft 'watts' => helem.watts.to_f, 'volts' => helem.voltage.to_f, 'is_dual_voltage' => helem.is_dual_voltage?, 'amps' => helem.amps.to_f, 'description' => helem.name, 'price' => cat_item.bom_price.to_f, 'class' => helem.class.to_s, 'third_party_part_number' => cat_item.third_party_part_number, 'third_party_sku' => cat_item.third_party_sku, 'qty' => he.quantity, 'cat_id' => cat_item.id } bom_elements << bom_helement end { 'elements' => bom_elements } end |
#get_file(plan, resource, category, files_transferred) ⇒ Object
Get file.
1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 |
# File 'app/models/room_configuration.rb', line 1315 def get_file(plan, resource, category, files_transferred) file = plan.get_file unless file.nil? upload = Upload.new(resource:, attachment: file, category:, created_at: plan.date_uploaded) if upload.save plan.new_upload_id = upload.id files_transferred << upload end end plan.transfer_attempted = true plan.save files_transferred end |
#get_heat_loss(inside_temperature, outside_temperature) ⇒ Object
Get heat loss.
2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 |
# File 'app/models/room_configuration.rb', line 2773 def get_heat_loss(inside_temperature, outside_temperature) fireplace_factor = INFILTRATION_FIREPLACE_FACTORS[sealing_factor.to_sym] hl_area = [ceiling.area, under_floor.area].max area_factor = nil INFILTRATION_AREA_FACTORS[:area_thresholds].each_with_index do |a, i| area_factor = INFILTRATION_AREA_FACTORS[sealing_factor.to_sym][i] if hl_area >= a end # puts "get_heat_loss, outside_temperature, area_factor, fireplace_factor: #{outside_temperature}, #{area_factor}, #{fireplace_factor}" # puts "get_heat_loss, hl_area, number_fireplaces, desired_temperature: #{hl_area}, #{number_fireplaces}, #{desired_temperature}" # puts "get_heat_loss, ceiling.height: #{ceiling.height}" (area_factor + (number_fireplaces * fireplace_factor)) * hl_area * ceiling.height * 0.0167 * 1.1 * (inside_temperature - outside_temperature) end |
#get_heat_supplied ⇒ Object
Get heat supplied.
2789 2790 2791 |
# File 'app/models/room_configuration.rb', line 2789 def get_heat_supplied calculate_total_watts * BTU_PER_HOUR_PER_WATT end |
#get_heating_system_type ⇒ Object
Get heating system type.
1123 1124 1125 |
# File 'app/models/room_configuration.rb', line 1123 def get_heating_system_type heating_system_product_line || line_items.primary_heating_system_product_line || quoted_heating_system_pl end |
#get_name_with_config ⇒ Object
Get name with config.
1572 1573 1574 1575 1576 |
# File 'app/models/room_configuration.rb', line 1572 def get_name_with_config new_name = name&.squish.to_s new_name += " - #{config_name}" new_name end |
#get_operating_costs ⇒ Object
Get operating costs.
2399 2400 2401 2402 |
# File 'app/models/room_configuration.rb', line 2399 def occ = RoomConfiguration::OperatingCostsCalculator.new(self) occ. end |
#get_or_generate_electrical_plan_pdf(version: 'v2', force: false) ⇒ Object
Get or generate electrical plan pdf.
2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 |
# File 'app/models/room_configuration.rb', line 2633 def get_or_generate_electrical_plan_pdf(version: 'v2', force: false) return generate_electrical_plan_pdf([], false, version: version) if version == 'v1' || force plan = uploads.electrical_plan_pdfs.first return generate_electrical_plan_pdf([], false, version: version) unless plan&. # Verify the file still exists in storage - regenerate if missing plan..data plan rescue Dragonfly::Job::Fetch::NotFound Rails.logger.warn "Electrical plan PDF missing from storage for room #{reference_number}, regenerating..." plan.destroy generate_electrical_plan_pdf([], false, version: version) end |
#get_or_generate_installation_plan_pdf(version: 'v2', force: false) ⇒ Object
+version+ — 'v2' (default, current/modern generator) or 'v1' (LEGACY generator).
v1 always regenerates (cache is keyed by category, not by style) so we never
serve a v2-style cached PDF when v1 was requested.
+force+ — skip the cache and rebuild from current data (e.g. after a
plan-template code change). Off by default; the cached upload is served.
2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 |
# File 'app/models/room_configuration.rb', line 2513 def get_or_generate_installation_plan_pdf(version: 'v2', force: false) return generate_installation_plan_pdf(version: version) if version == 'v1' || force plan = uploads.installation_plan_pdfs.first return generate_installation_plan_pdf(version: version) unless plan&. # Verify the file still exists in storage - regenerate if missing plan..data plan rescue Dragonfly::Job::Fetch::NotFound Rails.logger.warn "Installation plan PDF missing from storage for room #{reference_number}, regenerating..." plan.destroy generate_installation_plan_pdf(version: version) end |
#get_or_generate_multizone_plan_pdf(version: 'v2', force: false) ⇒ Object
Get or generate multizone plan pdf.
2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 |
# File 'app/models/room_configuration.rb', line 2579 def get_or_generate_multizone_plan_pdf(version: 'v2', force: false) return generate_multizone_plan_pdf(version: version) if version == 'v1' || force plan = uploads.multizone_plan_pdfs.first return generate_multizone_plan_pdf(version: version) unless plan&. # Verify the file still exists in storage - regenerate if missing plan..data plan rescue Dragonfly::Job::Fetch::NotFound Rails.logger.warn "Multizone plan PDF missing from storage for room #{reference_number}, regenerating..." plan.destroy generate_multizone_plan_pdf(version: version) end |
#get_recommended_materials(options = {}) ⇒ Array
Recommended accessories for this room's heating elements, or an
empty array when not applicable.
2438 2439 2440 2441 2442 2443 2444 2445 2446 |
# File 'app/models/room_configuration.rb', line 2438 def get_recommended_materials( = {}) recommended_accessories = [] # does the room have heating elements? if line_items.present? && line_items.heating_elements.present? && controlled_by.blank? && get_heating_system_type.present? # yes, so test if recommended accessories are all present recommended_accessories = find_recommended_accessories() end recommended_accessories end |
#get_selected_floor_warming_line_items ⇒ Object
Get selected floor warming line items.
1786 1787 1788 1789 1790 1791 1792 1793 |
# File 'app/models/room_configuration.rb', line 1786 def get_selected_floor_warming_line_items l_items = get_selected_line_items selected_floor_warming_line_items = [] l_items.each do |li| selected_floor_warming_line_items << li if li.is_floor_heating_product? end selected_floor_warming_line_items end |
#get_selected_line_items ⇒ Object
Get selected line items.
1779 1780 1781 |
# File 'app/models/room_configuration.rb', line 1779 def get_selected_line_items line_items.where('is_checked = true') end |
#get_weighted_average_heat_loss(hl_comfort, hl_economy) ⇒ Object
Get weighted average heat loss.
3007 3008 3009 3010 3011 |
# File 'app/models/room_configuration.rb', line 3007 def get_weighted_average_heat_loss(hl_comfort, hl_economy) # use weighted average by calculating heat loss times hours at comfort vs economy then divide by total hours in a given month res = RoomConfigurationConstants::AVERAGE_HOURS ((hl_comfort * res[:avg_num_comfort_hrs_per_month]) + (hl_economy * res[:avg_num_economy_hrs_per_month])) / res[:avg_num_hrs_per_month] end |
#grouped_cable_spacing_options_for_select ⇒ Object
Grouped cable spacing options for select.
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 |
# File 'app/models/room_configuration.rb', line 1003 def # here we want to return a single cable spacing for non TZ cable systems = { heating_system_product_line.name.to_s => [["#{HeatingElementProductLineOption::CABLE_SPACING_BY_HEATING_SYSTEM_LIST[heating_system_type_name_with_tz_cable_spacing]}'' Spacing with #{begin heating_system_product_line.name rescue StandardError 'n/a' end}", 3.0]] } if cable_spacing.present? && heating_system_type_name.to_s.index('TempZone') && heating_system_type_name.to_s.index('Cable') # Here we return either fixing strip spacings, or the membrane spacings if RoomConfiguration.is_membrane_cable_spacing?(cable_spacing) included_blurb = '' if RoomConfiguration.is_prodeso_cable_spacing?(cable_spacing) included_blurb = '(not included)' included_blurb = '(included)' if has_prodeso? end = { 'Install with Prodeso Membrane' => PUBLIC_PRODESO_CABLE_SPACINGS.map { |cs| ["#{cs}'' for Prodeso Membrane #{included_blurb}", cs] }, 'Install with DITRA-HEAT Membrane' => PUBLIC_DITRA_CABLE_SPACINGS.map { |cs| ["#{cs}'' for DITRA-HEAT Membrane (sold separately)", cs] } } else included_blurb = '(not included)' included_blurb = '(included)' if has_strips? = { 'Install with Fixing Strips' => PUBLIC_TZ_CABLE_SPACINGS.map { |cs| ["#{cs}'' for Fixing Strips #{included_blurb}", cs] } } end end end |
#guess_under_floor_type_id ⇒ Object
Guess under floor type id.
3016 3017 3018 3019 3020 3021 3022 3023 3024 |
# File 'app/models/room_configuration.rb', line 3016 def guess_under_floor_type_id res = nil if sub_floor_type && sub_floor_type.name.downcase.index('concrete') res = UnderFloorType.where(UnderFloorType[:name].matches('%concrete%')).limit(1).first.id elsif room_type && room_type.name.downcase.index('basement') res = UnderFloorType.where(UnderFloorType[:name].matches('%basement floor%')).limit(1).first.id end res end |
#has_heat_loss_report_pdf? ⇒ Object
Whether has heat loss report pdf.
1523 1524 1525 |
# File 'app/models/room_configuration.rb', line 1523 def has_heat_loss_report_pdf? uploads.exists?(category: 'heat_loss_report') end |
#has_installation_plan_cad? ⇒ Object
Whether has installation plan cad.
1565 1566 1567 |
# File 'app/models/room_configuration.rb', line 1565 def has_installation_plan_cad? installation_plan_cad.present? end |
#has_installation_plan_image? ⇒ Object
Whether has installation plan image.
1558 1559 1560 |
# File 'app/models/room_configuration.rb', line 1558 def has_installation_plan_image? installation_plan_image.present? end |
#has_installation_plans? ⇒ Object
Whether has installation plans.
1551 1552 1553 |
# File 'app/models/room_configuration.rb', line 1551 def has_installation_plans? has_installation_plan_image? && has_installation_plan_cad? end |
#has_items_that_require_cable_spacing? ⇒ Object
Whether has items that require cable spacing.
989 990 991 |
# File 'app/models/room_configuration.rb', line 989 def has_items_that_require_cable_spacing? line_items.any_require_cable_spacing? end |
#has_notes? ⇒ Object
Whether has notes.
1201 1202 1203 |
# File 'app/models/room_configuration.rb', line 1201 def has_notes? new_note.present? || activities.notes_only.exists? end |
#has_plans? ⇒ Object
Whether has plans.
2619 2620 2621 2622 2623 2624 2625 2626 |
# File 'app/models/room_configuration.rb', line 2619 def has_plans? # Optimize to avoid N+1: use a single query when uploads aren't preloaded if uploads.loaded? uploads.any? { |u| %w[installation_plan_image multizone_plan electrical_plan_pdf].include?(u.category) } else uploads.exists?(category: %w[installation_plan_image multizone_plan electrical_plan_pdf]) end end |
#has_prodeso? ⇒ Object
Whether has prodeso.
1036 1037 1038 |
# File 'app/models/room_configuration.rb', line 1036 def has_prodeso? line_items.membranes.any? end |
#has_room_layout_file? ⇒ Object
Whether has room layout file.
1544 1545 1546 |
# File 'app/models/room_configuration.rb', line 1544 def has_room_layout_file? room_layout_image.present? end |
#has_strips? ⇒ Object
Whether has strips.
1043 1044 1045 |
# File 'app/models/room_configuration.rb', line 1043 def has_strips? line_items.accessories.any? { |li| ItemConstants::TZ_CABLE_STRIP_SKUS.include?(li.sku) } end |
#has_zone_information? ⇒ Object
Whether has zone information.
1208 1209 1210 |
# File 'app/models/room_configuration.rb', line 1208 def has_zone_information? zones.exists? || (room_length.present? && room_width.present?) end |
#heat_loss_children ⇒ Object
Heat loss children.
2715 2716 2717 2718 |
# File 'app/models/room_configuration.rb', line 2715 def heat_loss_children # room must have an under_floor and ceiling to proceed [under_floor || build_under_floor, ceiling || build_ceiling] + exterior_walls end |
#heat_loss_name ⇒ Object
Heat loss name.
2723 2724 2725 |
# File 'app/models/room_configuration.rb', line 2723 def heat_loss_name 'Misc. Infiltration' end |
#heat_loss_report_pdf ⇒ Object
Heat loss report pdf.
1516 1517 1518 |
# File 'app/models/room_configuration.rb', line 1516 def heat_loss_report_pdf uploads.where(category: 'heat_loss_report').order(:created_at).first end |
#heating_elements ⇒ Object
Alias for Line_items#heating_elements
481 |
# File 'app/models/room_configuration.rb', line 481 delegate :heating_elements, :others, to: :line_items |
#heating_system_product_line ⇒ ProductLine
where product line is marked as a heating_element_system, optional: true
371 |
# File 'app/models/room_configuration.rb', line 371 belongs_to :heating_system_product_line, class_name: 'ProductLine', optional: true |
#heating_system_type_name ⇒ Object
Heating system type name.
1130 1131 1132 |
# File 'app/models/room_configuration.rb', line 1130 def heating_system_type_name get_heating_system_type&.heating_system_type_name end |
#heating_system_type_name_includes?(product) ⇒ Object
Whether heating system type name includes.
1147 1148 1149 |
# File 'app/models/room_configuration.rb', line 1147 def heating_system_type_name_includes?(product) heating_system_type_name.present? && heating_system_type_name.to_s.index(product) end |
#heating_system_type_name_with_tz_cable_spacing ⇒ Object
Heating system type name with tz cable spacing.
1137 1138 1139 1140 1141 |
# File 'app/models/room_configuration.rb', line 1137 def heating_system_type_name_with_tz_cable_spacing res = heating_system_type_name.to_s res = "#{heating_system_type_name} #{cable_spacing}" if cable_spacing.present? && heating_system_type_name.to_s.index('TempZone') && heating_system_type_name.to_s.index('Cable') res end |
#heplo_summary(pretty = nil) ⇒ Object
Heplo summary.
1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 |
# File 'app/models/room_configuration.rb', line 1641 def heplo_summary(pretty = nil) return unless heating_system_type_name res = heating_system_type_name if cable_spacing res += " @#{cable_spacing}''" unless pretty res += " at #{cable_spacing}'' cable spacing #{HeatingElementProductLineOption::CABLE_SPACING_EXTRA_COPY[cable_spacing.to_s]}" if pretty end res end |
#ideal_cable_spacing ⇒ Object
Ideal cable spacing.
996 997 998 |
# File 'app/models/room_configuration.rb', line 996 def ideal_cable_spacing HeatingElementProductLineOption.(:ideal_cable_spacing, sub_floor_type_id:, floor_type_id:, product_line_id: heating_system_product_line_id).first end |
#in_design_or_later? ⇒ Object
Whether in design or later.
1304 1305 1306 |
# File 'app/models/room_configuration.rb', line 1304 def in_design_or_later? in_design? || awaiting_quality_control? || complete? || cancelled? end |
#installation_address ⇒ Address
Legacy Installation Record data, migrated onto Warranty v2
(doc/tasks/202608051319_INSTALLATION_RECORDS_TO_WARRANTIES.md). Deprecated
to prove them dead in traffic before the columns drop.
358 |
# File 'app/models/room_configuration.rb', line 358 belongs_to :installation_address, class_name: 'Address', optional: true, deprecated: true |
#installation_country_iso ⇒ Object
Alias for Opportunity#installation_country_iso
486 |
# File 'app/models/room_configuration.rb', line 486 delegate :installation_postal_code, :installation_state_code, :installation_country_iso, :installation_country_iso3, to: :opportunity |
#installation_country_iso3 ⇒ Object
Alias for Opportunity#installation_country_iso3
486 |
# File 'app/models/room_configuration.rb', line 486 delegate :installation_postal_code, :installation_state_code, :installation_country_iso, :installation_country_iso3, to: :opportunity |
#installation_heated_area_sqft ⇒ Object
this could be different than the installation sq.ft when we deal with snow melt/slab heat mats
1757 1758 1759 1760 1761 1762 1763 |
# File 'app/models/room_configuration.rb', line 1757 def installation_heated_area_sqft (begin line_items.without_children.heating_elements.sum { |li| li.catalog_item.item.calculate_heating_sqft(cable_spacing: installation_plan_cable_spacing || cable_spacing, heating_area: true) * li.quantity }.ceil rescue StandardError 0 end) end |
#installation_plan_and_bom_attached? ⇒ Object
Whether installation plan and bom attached.
885 886 887 888 889 |
# File 'app/models/room_configuration.rb', line 885 def installation_plan_and_bom_attached? (installation_plans_attached? || installation_plan_not_required) && installation_plan_voltage_id.present? && (require_cable_spacing? ? installation_plan_cable_spacing.present? : true) end |
#installation_plan_blocking_reasons ⇒ Object
Returns human-readable reasons why design_complete / complete cannot fire.
Empty array means the room is ready to advance.
893 894 895 896 897 898 899 900 901 902 903 |
# File 'app/models/room_configuration.rb', line 893 def installation_plan_blocking_reasons return [] unless in_design? return [] if installation_plan_and_bom_attached? reasons = [] reasons << 'Installation plan CAD file and image must be attached' unless installation_plan_not_required || installation_plans_attached? reasons << 'Installation plan voltage must be selected' if installation_plan_voltage_id.blank? reasons << 'Installation plan cable spacing must be set' if require_cable_spacing? && installation_plan_cable_spacing.blank? reasons << "Installation plan cable spacing (#{installation_plan_cable_spacing}\") does not match the room cable spacing (#{cable_spacing}\")" if cable_spacing_mismatch? reasons end |
#installation_plan_cad ⇒ Object
Installation plan cad.
1492 1493 1494 |
# File 'app/models/room_configuration.rb', line 1492 def installation_plan_cad uploads.installation_plan_cads.sorted_by_position.first end |
#installation_plan_cad=(attributes = {}) ⇒ Object
Installation plan cad.
1500 1501 1502 1503 1504 |
# File 'app/models/room_configuration.rb', line 1500 def installation_plan_cad=(attributes = {}) return if attributes['attachment'].blank? uploads.build(attributes.merge(category: 'installation_plan_cad')) end |
#installation_plan_image ⇒ Object
Installation plan image.
1475 1476 1477 |
# File 'app/models/room_configuration.rb', line 1475 def installation_plan_image uploads.installation_plan_images.sorted_by_position.first end |
#installation_plan_image=(attributes = {}) ⇒ Object
Installation plan image.
1483 1484 1485 1486 1487 |
# File 'app/models/room_configuration.rb', line 1483 def installation_plan_image=(attributes = {}) return if attributes['attachment'].blank? uploads.build(attributes.merge(category: 'installation_plan_image')) end |
#installation_plan_pdf ⇒ Object
Installation plan pdf.
1509 1510 1511 |
# File 'app/models/room_configuration.rb', line 1509 def installation_plan_pdf uploads.installation_plan_pdfs.sorted_by_position.first end |
#installation_plan_qc_employee ⇒ Employee?
The associated installation plan qc employee.
351 |
# File 'app/models/room_configuration.rb', line 351 belongs_to :installation_plan_qc_employee, class_name: 'Employee', optional: true |
#installation_plan_reference_number ⇒ Object
Installation plan reference number.
1945 1946 1947 1948 1949 |
# File 'app/models/room_configuration.rb', line 1945 def installation_plan_reference_number installation_plan_cad.reference_number rescue StandardError nil end |
#installation_plan_voltage ⇒ Voltage?
The associated installation plan voltage.
336 |
# File 'app/models/room_configuration.rb', line 336 belongs_to :installation_plan_voltage, class_name: 'Voltage', optional: true |
#installation_plans_attached? ⇒ Object
Whether installation plans attached.
908 909 910 |
# File 'app/models/room_configuration.rb', line 908 def installation_plans_attached? uploads.installation_plan_cads.any? && uploads.installation_plan_images.any? end |
#installation_postal_code ⇒ Object
Alias for Opportunity#installation_postal_code
486 |
# File 'app/models/room_configuration.rb', line 486 delegate :installation_postal_code, :installation_state_code, :installation_country_iso, :installation_country_iso3, to: :opportunity |
#installation_sqft ⇒ Object
Installation sqft.
1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 |
# File 'app/models/room_configuration.rb', line 1743 def installation_sqft (begin # Use in-memory filter to avoid extra queries when associations are eager loaded. effective_cable_spacing = installation_plan_cable_spacing || cable_spacing line_items .to_a .select { |li| (li.children_count.nil? || li.children_count.zero?) && li.item&.is_heating_element? }.sum { |li| li.item.calculate_sqft(cable_spacing: effective_cable_spacing) * li.quantity } .ceil rescue StandardError 0 end) end |
#installation_state_code ⇒ Object
Alias for Opportunity#installation_state_code
486 |
# File 'app/models/room_configuration.rb', line 486 delegate :installation_postal_code, :installation_state_code, :installation_country_iso, :installation_country_iso3, to: :opportunity |
#installed_items ⇒ ActiveRecord::Associations::CollectionProxy
The associated installed items.
403 |
# File 'app/models/room_configuration.rb', line 403 has_many :installed_items, deprecated: true |
#installed_product_lines ⇒ ActiveRecord::Associations::CollectionProxy
The associated installed product lines.
435 |
# File 'app/models/room_configuration.rb', line 435 has_and_belongs_to_many :installed_product_lines, class_name: 'ProductLine', join_table: :installed_product_lines, association_foreign_key: :product_line_id, deprecated: true |
#installer ⇒ Customer?
The associated installer.
364 |
# File 'app/models/room_configuration.rb', line 364 belongs_to :installer, class_name: 'Customer', optional: true, deprecated: true |
#invalidate_design_guidelines ⇒ Object
Invalidate design guidelines.
1263 1264 1265 1266 1267 |
# File 'app/models/room_configuration.rb', line 1263 def invalidate_design_guidelines uploads.where(category: 'design_guideline').find_each do |ip| ip.update(category: "invalid_#{ip.category}") end end |
#is_cable_with_options?(options = {}) ⇒ Boolean
Whether this configuration is a cable system matching the given
installation type and cable spacing.
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 |
# File 'app/models/room_configuration.rb', line 1063 def ( = {}) res = false if cable_spacing.present? && heating_system_type_name.to_s.index('TempZone') && heating_system_type_name.to_s.index('Cable') installation_type = if RoomConfiguration.is_membrane_cable_spacing?(cable_spacing) 'membrane' else 'strips' end res = cable_spacing == [:cable_spacing] if [:installation_type] == installation_type elsif cable_spacing.present? && (heating_system_type_name.to_s.index('Snow') || heating_system_type_name.to_s.index('Slab')) && heating_system_type_name.to_s.index('Cable') res = cable_spacing == [:cable_spacing] if %w[snow_melt slab_heat].include?([:installation_type]) end res end |
#is_countertop? ⇒ Object
Whether is countertop.
2683 2684 2685 |
# File 'app/models/room_configuration.rb', line 2683 def is_countertop? heating_system_type_name_includes?('Countertop') || (room_type.environment == 'Countertop') end |
#is_in_a_completed_quote? ⇒ Object
Whether is in a completed quote.
1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 |
# File 'app/models/room_configuration.rb', line 1954 def is_in_a_completed_quote? res = false quotes.each do |q| if q.state == 'complete' res = true break end end res end |
#is_snow_or_ice_melting? ⇒ Object
Whether is snow or ice melting.
1113 1114 1115 1116 1117 1118 |
# File 'app/models/room_configuration.rb', line 1113 def is_snow_or_ice_melting? heating_system_product_line&.self_and_ancestors&.any? do |pl| slt = pl.slug_ltree.to_s slt.include?('snow_melting') || slt.start_with?('roof_and_gutter_deicing') end end |
#labeler_employee ⇒ Employee?
The associated labeler employee.
348 |
# File 'app/models/room_configuration.rb', line 348 belongs_to :labeler_employee, class_name: 'Employee', optional: true |
#main_rep ⇒ Object
Main rep.
1287 1288 1289 |
# File 'app/models/room_configuration.rb', line 1287 def main_rep opportunity&.primary_sales_rep end |
#material_alerts ⇒ ActiveRecord::Associations::CollectionProxy
The associated material alerts.
400 |
# File 'app/models/room_configuration.rb', line 400 has_many :material_alerts, dependent: :destroy |
#max_ambient_temperature ⇒ Object
Max ambient temperature.
2704 2705 2706 2707 2708 2709 2710 |
# File 'app/models/room_configuration.rb', line 2704 def max_ambient_temperature if floor_type&.is_temperature_limited? RoomConfigurationConstants::MAX_AMBIENT_TEMP_LIMITED else RoomConfigurationConstants::MAX_AMBIENT_TEMP_DEFAULT end end |
#meta_description ⇒ Object
Meta description.
1398 |
# File 'app/models/room_configuration.rb', line 1398 def ; end |
#meta_title ⇒ Object
Meta title.
1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 |
# File 'app/models/room_configuration.rb', line 1380 def n = opportunity.name.titleize.singularize.squish n << " #{name}." size = '' if installation_sqft.positive? size = "#{installation_sqft} sq.ft." elsif insulation_surface.present? size = "#{insulation_surface} sq.ft." end n << " #{size}" if size.present? n << " #{room_type.name.titleize.squish}" unless n.downcase.include?(room_type.name.downcase) n << " with #{heplo_summary}" n end |
#name_with_customer_opp_and_room ⇒ Object
Name with customer opp and room.
1346 1347 1348 |
# File 'app/models/room_configuration.rb', line 1346 def name_with_customer_opp_and_room "#{opportunity.try(:customer).try(:full_name)} - #{name_with_room_and_opp}" end |
#name_with_dimensions ⇒ Object
Name with dimensions.
1581 1582 1583 1584 1585 1586 |
# File 'app/models/room_configuration.rb', line 1581 def name_with_dimensions new_name = "#{name&.squish} - Plan: #{reference_number}" new_name += "(#{dimensions_label})" unless dimensions_label.nil? new_name += " - Spacing = #{cable_spacing}\" o.c" unless cable_spacing.nil? new_name end |
#name_with_room ⇒ Object
Name with room.
1332 1333 1334 |
# File 'app/models/room_configuration.rb', line 1332 def name_with_room "#{name.to_s.strip} (#{reference_number})" end |
#name_with_room_and_opp ⇒ Object
Name with room and opp.
1339 1340 1341 |
# File 'app/models/room_configuration.rb', line 1339 def name_with_room_and_opp "#{opportunity.try(:name)} - #{name_with_room}" end |
#notify_rep_of_room_completion ⇒ Object
Notify rep of room completion.
2374 2375 2376 |
# File 'app/models/room_configuration.rb', line 2374 def notify_rep_of_room_completion TrainingMailer.same_day_design_complete(self).deliver_later end |
#ok_to_customer_cancel? ⇒ Object
Whether ok to customer cancel.
1187 1188 1189 |
# File 'app/models/room_configuration.rb', line 1187 def ok_to_customer_cancel? CUSTOMER_CANCELABLE_STATES.include?(state.to_sym) && quotes.active.empty? && orders.not_cancelled.empty? end |
#ok_to_delete? ⇒ Object
Whether ok to delete.
1180 1181 1182 |
# File 'app/models/room_configuration.rb', line 1180 def ok_to_delete? draft? && quotes.empty? && orders.empty? end |
#operating_cost_in_cents_per_day ⇒ Object
Operating cost in cents per day.
2407 2408 2409 2410 2411 2412 2413 2414 2415 |
# File 'app/models/room_configuration.rb', line 2407 def # Fallback calculation: hours * kilowatts * cents_per_kwh hours = RoomConfigurationConstants::ASSUMED_OPERATING_HOURS_PER_DAY rate_cents = ElectricityRate::US_AVERAGE_RATE * RoomConfigurationConstants::CENTS_PER_DOLLAR res = (hours * calculate_total_kilowatts * rate_cents).round oc = res = (RoomConfigurationConstants::CENTS_PER_DOLLAR * oc[:operating_cost_by_coldest_month] / RoomConfigurationConstants::SIMPLE_DAYS_PER_MONTH).round if oc[:status] == 'ok' res end |
#opportunity ⇒ Opportunity?
The associated opportunity.
354 |
# File 'app/models/room_configuration.rb', line 354 belongs_to :opportunity, inverse_of: :room_configurations |
#order ⇒ Object
Order.
1410 1411 1412 1413 1414 |
# File 'app/models/room_configuration.rb', line 1410 def order return nil if line_items.empty? line_items.where.not(order_id: nil).first&.order end |
#orderable? ⇒ Object
Whether orderable.
1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 |
# File 'app/models/room_configuration.rb', line 1215 def orderable? # If someone on IQ wants to order a room without installation plan why not? # room_can_be_ordered = true # if line_items.goods.empty? # # room can't be ordered unless it has goods line items # room_can_be_ordered = false # elsif web_room? and room_layout_attached? and !installation_plans_attached? # # otherwise if it's a web room and has a room layout, it should also have an installation plan # room_can_be_ordered = false # end # return room_can_be_ordered line_items.goods.present? || line_items.services.present? end |
#orders ⇒ ActiveRecord::Associations::CollectionProxy
The associated orders.
429 |
# File 'app/models/room_configuration.rb', line 429 has_and_belongs_to_many :orders |
#other_revisions_and_configurations ⇒ Object
Other revisions and configurations.
2048 2049 2050 |
# File 'app/models/room_configuration.rb', line 2048 def other_revisions_and_configurations opportunity.room_configurations.to_a - [self] end |
#others ⇒ Object
Alias for Line_items#others
481 |
# File 'app/models/room_configuration.rb', line 481 delegate :heating_elements, :others, to: :line_items |
#party_for_plan_request_confirmation ⇒ Object
Party for plan request confirmation.
2286 2287 2288 2289 2290 |
# File 'app/models/room_configuration.rb', line 2286 def party_for_plan_request_confirmation p = opportunity.contact unless opportunity.contact&.inactive? p ||= opportunity.customer p end |
#plan_thumbnail ⇒ Object
Plan thumbnail.
802 803 804 805 806 807 808 |
# File 'app/models/room_configuration.rb', line 802 def plan_thumbnail if (upload = floor_plan && upload && upload..present? && upload.is_image? && (img_url = upload.image_url('92x61>'))) return { path: img_url, id: upload.id } end { path: nil, id: nil } end |
#pole_assignments_possible? ⇒ Object
Whether pole assignments possible.
1050 1051 1052 |
# File 'app/models/room_configuration.rb', line 1050 def pole_assignments_possible? line_items.heating_elements.present? && line_items.relay_panels.present? end |
#populate_line_items_from_bom_results(bom_results) ⇒ Object
Populates line items from HeatingSystemCalculator BOM results
2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 |
# File 'app/models/room_configuration.rb', line 2345 def populate_line_items_from_bom_results(bom_results) # Add heating elements (bom_results['elements'] || []).each do |element| add_bom_line_item(element) end # Add controls (thermostats, relays, etc.) (bom_results['controls'] || []).each do |control| add_bom_line_item(control) end # Add accessories (bom_results['accessories'] || []).each do |accessory| add_bom_line_item(accessory) end save end |
#pretty_coverage_state_description ⇒ Object
Pretty coverage state description.
1633 1634 1635 |
# File 'app/models/room_configuration.rb', line 1633 def pretty_coverage_state_description coverage_state.to_s.humanize.titleize end |
#primary_party ⇒ Object
Primary party.
933 934 935 |
# File 'app/models/room_configuration.rb', line 933 def primary_party opportunity.try(:primary_party) end |
#priority_urgency_factor ⇒ Object
Priority urgency factor.
1280 1281 1282 |
# File 'app/models/room_configuration.rb', line 1280 def priority_urgency_factor PRIORITIES.index(priority) end |
#promotion_discount(msrp = false) ⇒ Object
Promotion discount.
1814 1815 1816 1817 1818 1819 |
# File 'app/models/room_configuration.rb', line 1814 def promotion_discount(msrp = false) discount = BigDecimal(0) promo = promotion_that_applies discount = promo.apply_to(subtotal_floor_warming(msrp) - ev2_volume_discount(msrp), party.store.id) if promo discount end |
#promotion_that_applies(msrp = false) ⇒ Object
Promotion that applies.
1825 1826 1827 |
# File 'app/models/room_configuration.rb', line 1825 def promotion_that_applies(msrp = false) Promotion.that_applies(subtotal_floor_warming(msrp) - ev2_volume_discount(msrp), party.store.id) end |
#public_path ⇒ Object
Public path.
2062 2063 2064 |
# File 'app/models/room_configuration.rb', line 2062 def public_path UrlHelper.instance.my_room_path(self) end |
#quoted_heating_system_pl ⇒ ProductLine
where product line is marked as a heating_element_system, optional: true
372 |
# File 'app/models/room_configuration.rb', line 372 belongs_to :quoted_heating_system_pl, class_name: 'ProductLine', optional: true |
#quotes ⇒ ActiveRecord::Associations::CollectionProxy
The associated quotes.
426 |
# File 'app/models/room_configuration.rb', line 426 has_and_belongs_to_many :quotes |
#ready_for_engineering? ⇒ Object
Whether ready for engineering.
827 828 829 |
# File 'app/models/room_configuration.rb', line 827 def ready_for_engineering? check_room_layout_or_note_attached end |
#rectangular_area ⇒ Object
Rectangular area.
2212 2213 2214 2215 2216 |
# File 'app/models/room_configuration.rb', line 2212 def rectangular_area (RubyUnits::Unit.new(room_width) * RubyUnits::Unit.new(room_length)).to_s('%0.2f') rescue StandardError nil end |
#refresh_plans(delay: nil) ⇒ Object
Refresh plans.
2486 2487 2488 2489 2490 2491 2492 |
# File 'app/models/room_configuration.rb', line 2486 def refresh_plans(delay: nil) if delay&.positive? GenerateRoomPlansWorker.perform_in(delay, id) else GenerateRoomPlansWorker.perform_async(id) end end |
#release_orders_awaiting_completed_installation_plans ⇒ Object
Release orders awaiting completed installation plans.
968 969 970 |
# File 'app/models/room_configuration.rb', line 968 def release_orders_awaiting_completed_installation_plans reload.orders.awaiting_completed_installation_plans.each(&:release_order) end |
#remove_line_item(line_item, quantity = 1) ⇒ Object
Remove line item.
1702 1703 1704 1705 1706 1707 1708 1709 1710 |
# File 'app/models/room_configuration.rb', line 1702 def remove_line_item(line_item, quantity = 1) if line_item.quantity > quantity line_item.quantity -= quantity line_item.save else line_items.delete(line_item) line_item.destroy end end |
#require_cable_spacing? ⇒ Object
Whether require cable spacing.
982 983 984 |
# File 'app/models/room_configuration.rb', line 982 def require_cable_spacing? HeatingElementProductLineOption.(:require_cable_spacing, sub_floor_type_id:, floor_type_id:, product_line_id: heating_system_product_line_id).first end |
#require_expansion_joint? ⇒ Object
Whether require expansion joint.
975 976 977 |
# File 'app/models/room_configuration.rb', line 975 def require_expansion_joint? HeatingElementProductLineOption.(:require_expansion_joint, sub_floor_type_id:, floor_type_id:, room_type_id:).first end |
#reset_last_heat_loss ⇒ Object
Reset last heat loss.
2995 2996 2997 2998 2999 3000 |
# File 'app/models/room_configuration.rb', line 2995 def reset_last_heat_loss logger.info "reset_last_heat_loss: desired_temperature_changed?: #{desired_temperature_changed?}" logger.info "reset_last_heat_loss: sealing_factor_changed?: #{sealing_factor_changed?}" logger.info "reset_last_heat_loss: number_fireplaces_changed?: #{number_fireplaces_changed?}" self.last_heat_loss = nil end |
#retail_outlet ⇒ Customer?
The associated retail outlet.
370 |
# File 'app/models/room_configuration.rb', line 370 belongs_to :retail_outlet, class_name: 'Customer', optional: true, deprecated: true |
#reusable_layouts ⇒ Object
Reusable layouts.
813 814 815 816 817 818 819 820 821 822 |
# File 'app/models/room_configuration.rb', line 813 def reusable_layouts return Upload.none unless opportunity_id layouts = [] layouts += Upload.room_layouts.joins("INNER JOIN room_configurations ON room_configurations.id = uploads.resource_id AND uploads.resource_type = 'RoomConfiguration'").where( 'room_configurations.opportunity_id = ? AND room_configurations.id <> ?', opportunity_id, id.to_i ) layouts += Upload.room_layouts.where("resource_type = 'Opportunity' and resource_id = ?", opportunity_id) layouts.sort_by(&:created_at).reverse end |
#revision ⇒ Object
Revision.
1624 1625 1626 1627 1628 |
# File 'app/models/room_configuration.rb', line 1624 def revision reference_number.split('-')[1] rescue StandardError nil end |
#room_configurations_for_control ⇒ Object
Room configurations for control.
1154 1155 1156 1157 1158 |
# File 'app/models/room_configuration.rb', line 1154 def room_configurations_for_control return RoomConfiguration.none if controlled_rooms.present? opportunity.room_configurations.where.not(id: id.to_i).where(controlled_by_id: nil).order(:name, :reference_number) end |
#room_configurations_for_control_select ⇒ Object
Room configurations for control select.
1163 1164 1165 |
# File 'app/models/room_configuration.rb', line 1163 def room_configurations_for_control_select room_configurations_for_control.pluck(:name, :reference_number, :id).map { |(r0, r1, r2)| ["#{r0} (#{r1})", r2] } end |
#room_layout_attached? ⇒ Boolean
This validation is called on new object, hence you must parse the array instead of using activerecord
920 921 922 |
# File 'app/models/room_configuration.rb', line 920 def room_layout_attached? uploads.find { |u| u.category == 'room_layout' } || room_plan_attached? end |
#room_layout_image ⇒ Object
Room layout image.
1441 1442 1443 |
# File 'app/models/room_configuration.rb', line 1441 def room_layout_image room_layout_images.first end |
#room_layout_image=(attributes = {}) ⇒ Object
Room layout image.
1449 1450 1451 1452 1453 |
# File 'app/models/room_configuration.rb', line 1449 def room_layout_image=(attributes = {}) return if attributes['attachment'].blank? uploads.build(attributes.merge(category: 'room_layout')) end |
#room_layout_images ⇒ ActiveRecord::Associations::CollectionProxy
The associated room layout images.
388 |
# File 'app/models/room_configuration.rb', line 388 has_many :room_layout_images, -> { room_layouts.most_recent_first }, as: :resource, class_name: 'Upload' |
#room_layout_or_note_attached? ⇒ Object
Whether room layout or note attached.
1194 1195 1196 |
# File 'app/models/room_configuration.rb', line 1194 def room_layout_or_note_attached? room_layout_attached? || has_notes? || has_zone_information? end |
#room_length_raw ⇒ Object
Room length raw.
2190 2191 2192 2193 2194 |
# File 'app/models/room_configuration.rb', line 2190 def room_length_raw RubyUnits::Unit.new(room_length) rescue StandardError '' end |
#room_length_raw=(measurement) ⇒ Object
Room length raw.
2183 2184 2185 |
# File 'app/models/room_configuration.rb', line 2183 def room_length_raw=(measurement) self.room_length = measurement end |
#room_plan ⇒ RoomPlan?
The associated room plan.
375 |
# File 'app/models/room_configuration.rb', line 375 belongs_to :room_plan, inverse_of: :room_configurations, optional: true |
#room_plan_attached? ⇒ Object
Whether room plan attached.
915 916 917 |
# File 'app/models/room_configuration.rb', line 915 def room_plan_attached? room_plan.present? && room_plan.is_designable? end |
#room_plan_editing_locked? ⇒ Object
Whether room plan editing locked.
954 955 956 |
# File 'app/models/room_configuration.rb', line 954 def room_plan_editing_locked? in_design? || awaiting_quality_control? || complete? || cancelled? || orders.room_not_pickable.exists? end |
#room_prefix ⇒ Object
Room prefix.
2040 2041 2042 2043 |
# File 'app/models/room_configuration.rb', line 2040 def room_prefix # Legacy IQ rooms keep 'IQR' prefix for reference number consistency, new rooms use 'IP' reception_type == 'IQ' ? 'IQR' : 'IP' end |
#room_type ⇒ RoomType?
The associated room type.
330 |
# File 'app/models/room_configuration.rb', line 330 belongs_to :room_type, optional: true |
#room_width_raw ⇒ Object
Room width raw.
2173 2174 2175 2176 2177 |
# File 'app/models/room_configuration.rb', line 2173 def room_width_raw RubyUnits::Unit.new(room_width) rescue StandardError '' end |
#room_width_raw=(measurement) ⇒ Object
Room width raw.
2166 2167 2168 |
# File 'app/models/room_configuration.rb', line 2166 def room_width_raw=(measurement) self.room_width = measurement end |
#select_default_line_items ⇒ Object
Select default line items.
1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 |
# File 'app/models/room_configuration.rb', line 1419 def select_default_line_items line_items.each do |line_item| line_item.update(is_checked: true) end return unless thermostats.length > 1 thermostats.each do |t| t.update(is_checked: false) end thermostats.first.update(is_checked: true) end |
#send_online_plan_request_confirmation ⇒ Object
Send online plan request confirmation.
2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 |
# File 'app/models/room_configuration.rb', line 2260 def send_online_plan_request_confirmation if email_for_plan_request_confirmation sender = customer.primary_sales_rep co = CommunicationBuilder.new( resource: self, sender_party: sender, sender: (sender.nil? ? INFO_EMAIL : nil), recipient_party: party_for_plan_request_confirmation, emails: email_for_plan_request_confirmation, recipient_name: party_for_plan_request_confirmation.name, template_system_code: 'PLAN_REQUEST_CONF', bcc: sender&.email ).create if co.draft? { status_code: :error, status_message: co.errors_to_s } else { status_code: :ok, status_message: "Online Plan Request confirmation e-mail sent to #{customer.name} #{email_for_plan_request_confirmation}." } end else { status_code: :error, status_message: "Can't send: contact/customer e-mail is blank!" } end end |
#send_same_day_design_alert ⇒ Object
Send same day design alert.
2302 2303 2304 2305 |
# File 'app/models/room_configuration.rb', line 2302 def send_same_day_design_alert TrainingMailer.same_day_design_request(self).deliver_later update(wyi_alert_sent: true) end |
#send_to_engineering_and_create_crm_quote ⇒ Object
Send to engineering and create crm quote.
2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 |
# File 'app/models/room_configuration.rb', line 2241 def send_to_engineering_and_create_crm_quote res = false send_to_engineering unless (q = quotes.open_quotes.last) q = Quote.auto_quote_from_room(self, state_event: 'reset_to_pending', force_single_origin: true, do_not_set_shipping_address: true) end q.ready_for_design unless q.awaiting_completed_installation_plans? res = true if in_design? && quotes.open_quotes.any?(&:awaiting_completed_installation_plans?) && valid? && q.valid? # send a confirmation email and account invite if they don't already have one if res send_online_plan_request_confirmation party_for_plan_request_confirmation.online_account_invite(email_for_plan_request_confirmation, ignore_if_exist: true) unless party_for_plan_request_confirmation.account.present? && email_for_plan_request_confirmation.present? end res end |
#set_currency ⇒ Object
Set currency.
2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 |
# File 'app/models/room_configuration.rb', line 2009 def set_currency return if currency.present? # Skip if already set to avoid loading opportunity cur = begin customer.store.currency rescue StandardError nil end self.currency = cur if cur end |
#set_quoted_heating_system_product_line ⇒ Object
Set quoted heating system product line.
3029 3030 3031 3032 3033 3034 3035 |
# File 'app/models/room_configuration.rb', line 3029 def set_quoted_heating_system_product_line li_hs_pl = line_items.primary_heating_system_product_line self.quoted_heating_system_pl_id = li_hs_pl.id if li_hs_pl.present? hs_pl = HeatingElementProductLineOption.get_product_line_for_room(self) self.quoted_heating_system_pl_id ||= hs_pl.id if hs_pl.present? save end |
#set_reference_number ⇒ Object
Set reference number.
2030 2031 2032 2033 2034 2035 |
# File 'app/models/room_configuration.rb', line 2030 def set_reference_number return if reference_number.present? seq = RoomConfiguration.next_sequence_value('installation_plan_reference_numbers_seq') self.reference_number = "#{room_prefix}#{seq}" end |
#should_generate_new_friendly_id? ⇒ Object
Whether should generate new friendly id.
1403 1404 1405 |
# File 'app/models/room_configuration.rb', line 1403 def should_generate_new_friendly_id? slug.nil? || name_changed? || super end |
#show_cable_spacing_message? ⇒ Object
Whether show cable spacing message.
878 879 880 |
# File 'app/models/room_configuration.rb', line 878 def in_design? && require_cable_spacing? && installation_plan_cable_spacing.nil? end |
#show_voltage_message? ⇒ Object
Whether show voltage message.
871 872 873 |
# File 'app/models/room_configuration.rb', line 871 def in_design? && installation_plan_voltage_id.nil? end |
#slug_candidates ⇒ Object
Slug candidates.
1655 1656 1657 1658 1659 1660 |
# File 'app/models/room_configuration.rb', line 1655 def slug_candidates [ [:name_with_config], %i[name_with_config id] ] end |
#state_description(describe_state = nil) ⇒ Object
State description.
779 780 781 |
# File 'app/models/room_configuration.rb', line 779 def state_description(describe_state = nil) RoomConfigurationConstants::STATE_DESCRIPTION[describe_state || state] end |
#status ⇒ Object
Status.
1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 |
# File 'app/models/room_configuration.rb', line 1931 def status case state when 'new' 'new' when 'complete' 'complete' else 'in_design' end end |
#sub_floor_type ⇒ SubFloorType?
The associated sub floor type.
327 |
# File 'app/models/room_configuration.rb', line 327 belongs_to :sub_floor_type, optional: true |
#sub_floor_type_name ⇒ Object
Sub floor type name.
1373 1374 1375 |
# File 'app/models/room_configuration.rb', line 1373 def sub_floor_type_name sub_floor_type.try(:name) end |
#support_cases ⇒ ActiveRecord::Associations::CollectionProxy
The associated support cases.
432 |
# File 'app/models/room_configuration.rb', line 432 has_and_belongs_to_many :support_cases |
#synchronization_targets ⇒ Object
Retrieves valid synchronization targets when a room's line item are changed, which records
get the updated items.
926 927 928 |
# File 'app/models/room_configuration.rb', line 926 def synchronization_targets [quotes.reject(&:editing_locked?), orders.reject(&:editing_locked?)].flatten.compact end |
#system_owner ⇒ Customer?
The associated system owner.
361 |
# File 'app/models/room_configuration.rb', line 361 belongs_to :system_owner, class_name: 'Customer', optional: true, deprecated: true |
#temperature_options_for_select ⇒ Object
Temperature options for select.
2391 2392 2393 2394 |
# File 'app/models/room_configuration.rb', line 2391 def temps = *(TEMPERATURE_OPTIONS.first.last.to_i..TEMPERATURE_OPTIONS.last.last.to_i) # get more fine tuned selection here temps.select { |t| t < max_ambient_temperature }.map { |t| ["#{t.round}°F / #{PresetJob.fahrenheit_to_celsius(t)}°C", t] } end |
#template_options_for_select ⇒ Object
Alias for Class#template_options_for_select
635 |
# File 'app/models/room_configuration.rb', line 635 delegate :template_options_for_select, to: :class |
#to_param ⇒ Object
This prevents friendly id from automatically using slug when passing object, slug
should be manually set
2123 2124 2125 |
# File 'app/models/room_configuration.rb', line 2123 def to_param id.to_s end |
#to_s ⇒ Object
To s.
2117 2118 2119 |
# File 'app/models/room_configuration.rb', line 2117 def to_s name_with_room end |
#total ⇒ Object
implement total for a room configuration which is just the subtotal
2234 2235 2236 |
# File 'app/models/room_configuration.rb', line 2234 def total subtotal end |
#total_length ⇒ Object
Total length.
1768 1769 1770 1771 1772 1773 1774 |
# File 'app/models/room_configuration.rb', line 1768 def total_length (begin line_items.without_children.heating_elements.sum { |li| li.catalog_item.item.length.to_f * li.quantity } rescue StandardError nil end) end |
#tracer_solutions ⇒ Object
Tracer solutions.
1537 1538 1539 |
# File 'app/models/room_configuration.rb', line 1537 def tracer_solutions uploads.tracer_solutions.sorted_by_position.first end |
#transmittable? ⇒ Object
Whether transmittable.
754 755 756 |
# File 'app/models/room_configuration.rb', line 754 def transmittable? !state.in?(%w[cancelled in_design awaiting_quality_control]) end |
#transmittable_and_settled? ⇒ Object
Whether transmittable and settled.
761 762 763 764 765 766 |
# File 'app/models/room_configuration.rb', line 761 def transmittable_and_settled? transmittable? && (updated_at <= 2.minutes.ago) && # prevent multiple changes from causing multiple pre-packs, assume a transmittable room that hasn't chamged, nor its line items, in ~2 min line_items.goods.parents_only.all? do |li| li.updated_at <= 2.minutes.ago end end |
#tz_installation_sqft ⇒ Object
Tz installation sqft.
1732 1733 1734 1735 1736 1737 1738 |
# File 'app/models/room_configuration.rb', line 1732 def tz_installation_sqft (begin line_items.without_children.tempzone_only.sum { |li| li.catalog_item.item.calculate_sqft(cable_spacing:) * li.quantity }.ceil rescue StandardError 0 end) end |
#under_floor ⇒ UnderFloor?
The associated under floor.
419 |
# File 'app/models/room_configuration.rb', line 419 has_one :under_floor, dependent: :destroy |
#unlink_vignette_installation_plan_image ⇒ Object
Unlink vignette installation plan image.
3068 3069 3070 |
# File 'app/models/room_configuration.rb', line 3068 def unlink_vignette_installation_plan_image update(vignette: false) end |
#update_quote_status ⇒ Object
Update quote status.
961 962 963 |
# File 'app/models/room_configuration.rb', line 961 def update_quote_status reload.quotes.open_quotes.each { |quote| quote.adjust_status_based_on_room_status(self) } end |
#uploads ⇒ ActiveRecord::Associations::CollectionProxy
The associated uploads.
385 |
# File 'app/models/room_configuration.rb', line 385 has_many :uploads, -> { order(position: :asc, created_at: :desc) }, as: :resource, dependent: :destroy |
#valid_cable_spacing ⇒ Object
Valid cable spacing.
1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 |
# File 'app/models/room_configuration.rb', line 1889 def valid_cable_spacing # puts "valid_cable_spacing: require_cable_spacing?: #{require_cable_spacing?}" return unless require_cable_spacing? if !draft? && !in_design? && !awaiting_quality_control? min = RoomConfigurationConstants::CABLE_SPACING_MIN_INCHES max = RoomConfigurationConstants::CABLE_SPACING_MAX_INCHES errors.add(:cable_spacing, "must be within #{min} and #{max} inches for #{heating_system_type_name}.") if (cable_spacing.to_f < min) || (cable_spacing.to_f > max) end return unless installation_plan_cable_spacing.nil? && updating_installation_plans == true errors.add(:installation_cable_spacing, "must be present for #{heating_system_type_name}.") end |
#valid_expansion_joint_spacing ⇒ Object
Valid expansion joint spacing.
1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 |
# File 'app/models/room_configuration.rb', line 1906 def valid_expansion_joint_spacing # puts "valid_expansion_joint_spacing: require_expansion_joint?: #{require_expansion_joint?}" # puts "valid_expansion_joint_spacing: must be within #{min} and #{max} feet for #{floor_type.name}" # puts "valid_expansion_joint_spacing: expansion_joint_spacing.to_f: #{expansion_joint_spacing.to_f}" if require_expansion_joint? && (skip_expansion_joint_validation != true) && ((expansion_joint_spacing.to_f < RoomConfigurationConstants::MIN_CONCRETE_EXPANSION_JOINT_SPACING) || (expansion_joint_spacing.to_f > RoomConfigurationConstants::MAX_CONCRETE_EXPANSION_JOINT_SPACING)) errors.add(:expansion_joint_spacing, "must be within #{RoomConfigurationConstants::MIN_CONCRETE_EXPANSION_JOINT_SPACING} and #{RoomConfigurationConstants::MAX_CONCRETE_EXPANSION_JOINT_SPACING} feet for #{floor_type.name}.") return false end true end |
#valid_insulation_surface ⇒ Object
Valid insulation surface.
1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 |
# File 'app/models/room_configuration.rb', line 1875 def valid_insulation_surface # Legacy Flash Design Tool rooms store the total room footprint in square_footage # (copied from the Instant Quote), not the heated area. The comparison is only # meaningful for DesignTool2 and zone-based rooms where square_footage is the # actual heated area. Skip for any room that carries a Flash DT floorplan_xml. return if floorplan_xml.present? return unless room_type&.is_indoor? && insulation_surface.present? && square_footage.present? && (square_footage > insulation_surface) errors.add(:insulation_surface, "must be greater than heated area square footage of #{square_footage.round(1)}.") end |
#versions_for_audit_trail(_params = {}) ⇒ Object
Versions for audit trail.
787 788 789 790 791 792 793 794 795 796 797 |
# File 'app/models/room_configuration.rb', line 787 def versions_for_audit_trail(_params = {}) query_sql = %q{ (item_type = 'RoomConfiguration' AND item_id = :id) OR ( item_type = 'LineItem' AND reference_data @> '{"resource_type": "RoomConfiguration"}' AND reference_data @> :resource_id_json ) } RecordVersion.where(query_sql, id:, resource_id_json: { resource_id: id }.to_json) end |
#vignette_valid_only_for_completed_rooms_with_plans ⇒ Object
Vignette valid only for completed rooms with plans.
1920 1921 1922 1923 1924 1925 1926 |
# File 'app/models/room_configuration.rb', line 1920 def vignette_valid_only_for_completed_rooms_with_plans vignette_ok = false vignette_ok = true if complete? && has_installation_plans? return unless vignette && !vignette_ok errors.add(:vignette, 'can only be set for completed rooms with plans.') end |
#visit ⇒ Visit?
The associated visit.
378 |
# File 'app/models/room_configuration.rb', line 378 belongs_to :visit, optional: true |
#voltage ⇒ Voltage?
The associated voltage.
333 |
# File 'app/models/room_configuration.rb', line 333 belongs_to :voltage, optional: true |
#voltage_mismatch? ⇒ Object
Whether voltage mismatch.
855 856 857 858 859 |
# File 'app/models/room_configuration.rb', line 855 def voltage_mismatch? return false if installation_plan_voltage_id.nil? effective_voltage(true) != installation_plan_voltage_id end |
#warranty_card ⇒ Object
Warranty card.
1458 1459 1460 |
# File 'app/models/room_configuration.rb', line 1458 def warranty_card uploads.warranty_cards.first end |
#warranty_card=(attributes = {}) ⇒ Object
Warranty card.
1466 1467 1468 1469 1470 |
# File 'app/models/room_configuration.rb', line 1466 def warranty_card=(attributes = {}) return if attributes['attachment'].blank? uploads.build(attributes.merge(category: 'warranty_card')) end |
#web_room? ⇒ Object
Whether web room.
940 941 942 |
# File 'app/models/room_configuration.rb', line 940 def web_room? (creator.is_a?(Customer) || creator.nil?) && ((parent && root.web_room?) || parent.nil?) && %w[DesignTool2 DesignTool QuoteBuilder Upload MeasureComp IQ].include?(reception_type) # quote rooms have a slightly different more rep driven workflow end |
#zones ⇒ ActiveRecord::Associations::CollectionProxy
The associated zones.
394 |
# File 'app/models/room_configuration.rb', line 394 has_many :zones, dependent: :destroy |