Class: MyQuotesController

Inherits:
BasePortalController show all
Defined in:
app/controllers/my_quotes_controller.rb

Overview

Controller: my quotes.

Constant Summary

Constants included from Controllers::MasqueradeGuarded

Controllers::MasqueradeGuarded::DEFAULT_BLOCK_MESSAGE

Constants included from Controllers::AnalyticsEvents

Controllers::AnalyticsEvents::MAX_QUEUED_EVENTS, Controllers::AnalyticsEvents::SESSION_KEY

Constants included from Controllers::ErrorRendering

Controllers::ErrorRendering::NON_CONTENT_PATH_PREFIXES

Constants included from Www::SeoHelper

Www::SeoHelper::AWARDS, Www::SeoHelper::CA_ADDRESS, Www::SeoHelper::CA_BUSINESS_HOURS, Www::SeoHelper::CA_CONTACT_POINT, Www::SeoHelper::CA_CURRENCIES, Www::SeoHelper::CA_DESCRIPTION, Www::SeoHelper::CA_FOUNDING_DATE, Www::SeoHelper::CA_GLOBAL_LOCATION_NUMBER, Www::SeoHelper::CA_LEGAL_NAME, Www::SeoHelper::CA_LOCAL_BUSINESS, Www::SeoHelper::CA_ONLINE_STORE, Www::SeoHelper::CA_RETURN_POLICY, Www::SeoHelper::CA_SALES_DEPARTMENT, Www::SeoHelper::CA_SERVICE_AREA, Www::SeoHelper::CA_URL, Www::SeoHelper::CA_VAT_ID, Www::SeoHelper::CA_WAREHOUSE_DEPARTMENT, Www::SeoHelper::CA_WAREHOUSE_HOURS, Www::SeoHelper::COMPANY_EMAIL, Www::SeoHelper::COMPANY_LOGO, Www::SeoHelper::COMPANY_NAME, Www::SeoHelper::COMPANY_SLOGAN, Www::SeoHelper::EXPERTISE, Www::SeoHelper::FAX_NUMBER, Www::SeoHelper::GS1_COMPANY_PREFIX, Www::SeoHelper::ISO6523_CODE, Www::SeoHelper::PAYMENT_METHODS, Www::SeoHelper::PHONE_NUMBER, Www::SeoHelper::PRIMARY_NAICS, Www::SeoHelper::REFUND_TYPE, Www::SeoHelper::RETURN_FEES, Www::SeoHelper::RETURN_METHOD, Www::SeoHelper::RETURN_POLICY_CATEGORY, Www::SeoHelper::SECONDARY_NAICS, Www::SeoHelper::SOCIAL_PROFILES, Www::SeoHelper::US_ADDRESS, Www::SeoHelper::US_BUSINESS_HOURS, Www::SeoHelper::US_CONTACT_POINT, Www::SeoHelper::US_CURRENCIES, Www::SeoHelper::US_DESCRIPTION, Www::SeoHelper::US_FOUNDING_DATE, Www::SeoHelper::US_GLOBAL_LOCATION_NUMBER, Www::SeoHelper::US_IMAGE, Www::SeoHelper::US_LEGAL_NAME, Www::SeoHelper::US_LOCAL_BUSINESS, Www::SeoHelper::US_ONLINE_STORE, Www::SeoHelper::US_RETURN_POLICY, Www::SeoHelper::US_SALES_DEPARTMENT, Www::SeoHelper::US_SERVICE_AREA, Www::SeoHelper::US_TAX_ID, Www::SeoHelper::US_URL, Www::SeoHelper::US_WAREHOUSE_DEPARTMENT, Www::SeoHelper::US_WAREHOUSE_HOURS

Constants included from IconHelper

IconHelper::CUSTOM_ICON_MAP, IconHelper::CUSTOM_SVG_DIR, IconHelper::DEFAULT_FAMILY

Instance Method Summary collapse

Methods inherited from BasePortalController

#current_ability, #portal_party, #set_catalog, #set_webpack

Methods included from Controllers::MasqueradeGuarded

block_while_masquerading, #masquerade_blocks?

Methods inherited from ApplicationController

#account_impersonated?, #add_to_flash, #after_sign_in_path_for, #bypass_forgery_protection?, #chat_enabled?, #cloudflare_cleared?, #default_catalog, #default_url_options, #enable_turbo_frames, #find_publication, #fix_invalid_accept_header, #init_js_utils, #is_globals_call?, #layout_by_resource, #locale_store, #redirect_to, #require_employee_for_crm, #set_base_host, #set_real_ip, #set_report_errors_for, #should_render_layout?, #stamp_impersonation_context, #warmlyyours_canada_ip?, #warmlyyours_ip?, #y

Methods included from Controllers::ReturnPathHandling

#check_for_return_path, #redirect_to_return_path_or_default

Methods included from Controllers::AnalyticsEvents

#consume_queued_analytics_events, #track_event

Methods included from Controllers::DeviceDetection

#device_detector, #is_ie?

Methods included from Controllers::SubdomainDetection

#is_crm_request?, #is_www_request?, #json_request?

Methods included from Controllers::TurboSafeRedirect

#redirect_to

Methods included from Controllers::TrackingDetection

#bot_request?, #gdpr_country?, #gdpr_country_data, #prevent_bots, #set_tracking_cookie, #track_visitor?

Methods included from Controllers::AcceleratedFileSending

#send_file_accelerated, #send_upload_accelerated

Methods included from Controllers::ErrorRendering

#excp_string, #mail_to_for_error_reporting, #render_400, #render_404, #render_406, #render_410, #render_500, #render_invalid_authenticity_token, #render_ip_spoof_error, #render_unpermitted_parameters, #safe_referer_or_fallback

Methods included from Controllers::TurnstileVerification

#load_turnstile_script_tag, #turnstile_lazy_widget, #turnstile_script_tag, #turnstile_widget, #validate_turnstile!

Methods included from Controllers::CloudflareCaching

edge_cached, #edge_cached_action?, #reset_cloudflare_cache, #set_cloudflare_cache, #skip_edge_cache!, #skip_session

Methods included from Controllers::Webpackable

#preload_webpack_fonts, #webpack_css_include, #webpack_css_url, #webpack_js_include, #wpd_is_running?

Methods included from Controllers::Localizable

#cloudflare_country_locale, #determine_request_locale, #geocoder_locale, #guest_user_locale_check, #locale_optional_www_auth_path?, #param_locale, #set_locale, #set_request_locale, #skip_localization?, #warmlyyours_ip_locale

Methods included from Controllers::Authenticable

#access_denied, #authenticate_account, #authenticate_account!, #authenticate_account_from_login_token!, #check_is_a_manager, #check_is_a_sales_manager, #check_is_an_admin, #check_is_an_employee, #check_party, #clear_mismatched_guest_user, #create_guest_user, #credentials?, #current_or_guest_user, #current_or_guest_user_id_read_only, #current_user, #devise_mapping, #fully_logged_in?, #generate_bot_id, #guest_user, #identifiable?, #init_current_user, #initialize_guest, #load_context_user, #logging_in, #resource, #resource_name, #restrict_access_for_non_employees, #scrubbed_request_path, #user_object, #warn_on_session_guest_id_leak

Methods included from ApplicationHelper

#better_number_to_currency, #check_force_logout, #check_or_cross, #check_or_times, #embedded_tab_frame_id, #error_messages, #general_disclaimer_on_product_installation_and_local_codes, #gridjs_from_html_table, #gridjs_table, #is_wy_ip, #line_break, #parent_layout, #pass_or_fail, #render_error_messages_list, #render_video_card, #resolved_auth_form_turbo_frame, #return_path_or, #safe_css_color, #set_return_path_if_present, #set_section_if_present, #tab_frame_id, #to_underscore, #track_page?, #turbo_section_wrapper, #turbo_tabs_request?, #url_on_same_domain_as_request, #widget_index_daily_focus_index_path, #working_hours?, #yes_or_no, #yes_or_no_highlighted, #yes_or_no_with_check_or_cross, #youtube_video

Methods included from UppyUploaderHelper

#file_uploader, #image_uploader, #large_file_uploader_s3, #lead_sketch_uploader, #rma_image_uploader, #rma_image_uploader_s3, #uppy_uploader, #video_uploader

Methods included from Www::ImagesHelper

#image_asset_tag, #image_asset_url

Methods included from Www::SeoHelper

#add_page_schema, #add_webpage_schema, #canada?, #company_social_links, #ensure_context_json, #json_ld_script_tag, #local_business_schema, #online_store_id, #online_store_schema, #page_main_entity, #page_main_entity_json, #render_auto_collection_page_schema, #render_collection_page_schema, #render_local_business_schema, #render_online_store_schema, #render_page_schemas, #render_page_video_schemas, #render_webpage_schema, #render_webpage_schema_with_collections, #usa?

Methods included from UrlsHelper

#catalog_breadcrumb_links, #catalog_link, #catalog_link_for_product_line, #catalog_link_for_sku, #cms_link, #delocalized_path, #path_to_sales_product_sku, #path_to_sales_product_sku_for_product_line, #path_to_sales_product_sku_for_product_line_slug, #product_line_from_catalog_link, #protocol_neutral_url, #sanitize_external_url, #valid_external_url?

Methods included from IconHelper

#account_nav_icon, #fa_icon, #star_rating_html

Instance Method Details

#add_to_cartObject



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'app/controllers/my_quotes_controller.rb', line 42

def add_to_cart
  @quote = @context_user.customer.quotes.find(params[:id])
  @room = @quote.room_configurations.find(params[:room_id]) if params[:room_id].present?
  @cart = @context_user.cart
  if (@cart.quote_id == @quote.id) && @cart.line_items.non_shipping.present?
    flash[:warning] = 'This quote is already in your cart.'
    redirect_to_return_path_or_default my_cart_path
  else
    @project = @quote.opportunity
    # @quote.reset_shipping # shipping will be recalculated at checkout
    # @quote.do_not_detect_shipping = true
    # @cart.do_not_detect_shipping = true
    o = @quote.to_order(@cart)
    if o.persisted?
      cart_params = { quote_id: @quote.id }
      if @room
        msg = "Room #{@room.name_with_room}"
        cart_params[:room_id] = @room.id
      else
        msg = "Quote #{@quote.reference_number}"
      end
      flash[:info] = "#{msg} was added to your cart."
      redirect_to_return_path_or_default my_cart_path(cart_params)
    else
      flash[:error] = "Unable to add to cart. #{o.errors_to_s}"
      redirect_to_return_path_or_default my_quote_path(@quote)
    end
  end
rescue ActiveRecord::RecordNotUnique
  @cart&.reload
  if @cart&.quote_id == @quote.id && @cart.line_items.non_shipping.present?
    flash[:warning] = 'This quote is already in your cart.'
    redirect_to_return_path_or_default my_cart_path
  else
    flash[:error] = 'Unable to add to cart. Please try again.'
    redirect_to_return_path_or_default my_quote_path(@quote)
  end
rescue Quote::ConvertToOrder::QuoteUnpurchasable => e
  flash[:error] = "Quote not purchasable. #{e}"
  redirect_to_return_path_or_default my_quote_path(@quote)
rescue ActiveRecord::RecordNotFound
  flash[:error] = 'Quote not found or not authorized'
  redirect_to 
end

#buy_nowObject



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'app/controllers/my_quotes_controller.rb', line 87

def buy_now
  @quote = @context_user.customer.quotes.find(params[:id])
  # Try to find an existing order for that quote that hasn't been modified by checking the line items signature
  o = @quote.orders.order(Order[:created_at].desc).find_by(state: %w[pending cart pending_payment])
  if o && o.line_items.signature != @quote.line_items.signature
    # if signature don't match delete it and start over
    o.destroy
    o = nil
  end
  o ||= @quote.to_order
  url = o.public_payment_link
  redirect_to_return_path_or_default url
rescue ActiveRecord::RecordNotFound
  flash[:error] = 'Quote not found or not authorized'
  redirect_to 
end

#cancelObject



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'app/controllers/my_quotes_controller.rb', line 104

def cancel
  @quote = @context_user.customer.quotes.find(params[:id])
  @project = @quote.opportunity
  if @quote.ok_to_customer_cancel?
    @quote.do_not_detect_shipping = true
    @quote.cancel
    flash[:info] = "Quote #{@quote.name} was cancelled"
    redirect_to_return_path_or_default my_project_path(@project)
  else
    flash[:error] = 'Quote cannot be cancelled because it contains active rooms or orders'
    redirect_to_return_path_or_default my_quote_path(@quote)
  end
rescue ActiveRecord::RecordNotFound
  flash[:error] = 'Quote not found or not authorized'
  redirect_to 
end

#download_pdfObject



33
34
35
36
37
38
39
40
# File 'app/controllers/my_quotes_controller.rb', line 33

def download_pdf
  @quote = @context_user.customer.quotes.find(params[:id])
  if (pdf = @quote.uploads.in_category('organization_quote_pdf').order(created_at: :desc).first)
    send_upload_accelerated(pdf, file_name: "WarmlyYours_Quote_#{@quote.reference_number}.pdf")
  else
    render inline: 'File is missing', status: :not_found
  end
end

#find_quoteObject



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'app/controllers/my_quotes_controller.rb', line 157

def find_quote
  @quote = Quote.find_by(reference_number: params[:quote_number])
  if @quote.present?
    redirect_to quote_lookup_path(quote_id: @quote.id)
  else
    # Let's see if we got an encrypted ID
    quote_id = begin
      Encryption.decrypt_string(params[:quote_number].to_s)
    rescue StandardError
      nil
    end
    if quote_id.present? && (@quote = Quote.find(quote_id))
      redirect_to "/quote-viewer/#{params[:quote_number]}"
    else
      flash.now[:info] = "We couldn't find the quote"
      render :quote_lookup, status: :unprocessable_content
    end
  end
end

#finish_moveObject



130
131
132
133
134
135
136
137
138
139
140
141
# File 'app/controllers/my_quotes_controller.rb', line 130

def finish_move
  @quote = @context_user.customer.quotes.find(params[:id])
  if @quote.update(params[:quote])
    flash[:info] = "Quote was moved to #{@quote.opportunity.name}."
  else
    flash[:error] = 'Unable to move quote.'
  end
  redirect_to_return_path_or_default my_quote_path(@quote)
rescue ActiveRecord::RecordNotFound
  flash[:error] = 'Quote not found or not authorized'
  redirect_to 
end

#indexObject



12
13
14
15
16
# File 'app/controllers/my_quotes_controller.rb', line 12

def index
  base_quotes = (@context_user || @party).quotes.active.last_revisions
  @q = base_quotes.ransack(params[:q])
  @pagy, @quotes = pagy(@q.result.order(created_at: :desc))
end

#invite_accountObject



185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'app/controllers/my_quotes_controller.rb', line 185

def 
  return if 

  email = params[:email]
  party = Party.find(params[:party_id])
   = email

  if email.present? && party.present?
    if Account.where(login:).exists?
      name_part, = email.split('@')
       = name_part
      counter = 0
       = 
      while Account.where(login:).exists?
        counter += 1
         = "#{}-#{counter}"
      end
    end
    Account::Inviter.new.process(party:, email:, login:)
    flash[:info] = 'We sent you an email with an invitation to create an account. Please follow the instructions of the email.'
  end
  redirect_to quote_lookup_path
end

#moveObject



121
122
123
124
125
126
127
128
# File 'app/controllers/my_quotes_controller.rb', line 121

def move
  @quote = @context_user.customer.quotes.find(params[:id])
  @project = @quote.opportunity
  @move_to_project_options = (@context_user || @party).opportunities.not_cancelled.to_a.push(@project).uniq.map { |p| [p.name, p.id] }
rescue ActiveRecord::RecordNotFound
  flash[:error] = 'Quote not found or not authorized'
  redirect_to 
end

#quote_lookupObject



143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'app/controllers/my_quotes_controller.rb', line 143

def quote_lookup
  @quote = begin
    Quote.find(params[:quote_id])
  rescue StandardError
    nil
  end
  return if @quote.blank?

  @customer = @quote.customer
  return unless @customer..present? && @context_user. == @customer.

  redirect_to (@quote.id)
end

#quote_viewerObject



177
178
179
180
181
182
183
# File 'app/controllers/my_quotes_controller.rb', line 177

def quote_viewer
  @quote.update_column(:first_view_date, Time.current)
  @project = @quote.opportunity
  @material_alerts = @quote.get_material_alerts(for_www: true) unless @quote.editing_locked?
  @restricted_view = true
  render :show
end

#showObject



18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'app/controllers/my_quotes_controller.rb', line 18

def show
  @quote = @context_user.customer.quotes.find(params[:id])
  @quote.update_column(:first_view_date, Time.current)
  @project = @quote.opportunity
  @restricted_view = @context_user.try(:guest?)
  # For my_quotes, we ABSOLUTELY need share_key in the quote_builder_url -- Ramie
  share_key = params[:share_key].present? ? "?share_key=#{params[:share_key]}" : ''
  @quote_builder_url = cms_link("floor-heating/quote-builder#{share_key}")
  Rails.logger.debug { "MyQuotesController#show: @quote_builder_url: #{@quote_builder_url}" }
  @material_alerts = @quote.get_material_alerts(for_www: true) unless @quote.editing_locked?
rescue ActiveRecord::RecordNotFound
  flash[:error] = 'Quote not found or not authorized'
  redirect_to cms_link('/my_account')
end