Class: MyQuotesController

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

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, #append_token, #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::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, #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_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!, #authenticate_account_from_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, #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, #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



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

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 and @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



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

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



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

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



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

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



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

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_entity
    end
  end
end

#finish_moveObject



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

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



10
11
12
13
14
# File 'app/controllers/my_quotes_controller.rb', line 10

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



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

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



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

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.concat([@project]).uniq.map { |p| [p.name, p.id] }
rescue ActiveRecord::RecordNotFound
  flash[:error] = 'Quote not found or not authorized'
  redirect_to 
end

#quote_lookupObject



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

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

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

  redirect_to (@quote.id)
end

#quote_viewerObject



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

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



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

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