Class: MyCartsController
- Inherits:
-
BasePortalController
- Object
- ActionController::Base
- ApplicationController
- BasePortalController
- MyCartsController
- Includes:
- MyAccountHelper
- Defined in:
- app/controllers/my_carts_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
-
#add_coupon(coupon_code) ⇒ Object
protected
Attempts to apply a coupon to the cart Returns error message string if failed, nil if successful.
- #add_item ⇒ Object
- #add_multiple_items ⇒ Object
- #adjust_sku_quantity ⇒ Object
- #apply_coupon ⇒ Object
- #cart_add_item(sku, qty = nil, room_configuration_id = nil) ⇒ Object protected
-
#cart_conflict ⇒ Object
Display cart conflict resolution page when user logs in with items in both guest and account carts.
- #check_address_and_locale ⇒ Object
- #check_existing_account ⇒ Object
- #check_inventory_levels ⇒ Object
- #checkout ⇒ Object
- #checkout_update ⇒ Object
- #customer_info ⇒ Object
- #payment ⇒ Object
- #remove_all_line_items ⇒ Object
- #remove_coupon ⇒ Object
- #remove_from ⇒ Object
- #remove_item ⇒ Object
- #remove_room ⇒ Object
-
#resolve_cart_conflict ⇒ Object
Handle user's choice for cart conflict resolution.
- #retrieve ⇒ Object
- #schedule_service ⇒ Object
- #schedule_service_update ⇒ Object
- #set_cart_qty ⇒ Object
- #shipping ⇒ Object
- #shipping_address ⇒ Object
- #shipping_update ⇒ Object
- #show ⇒ Object
- #update ⇒ Object
- #update_from_payment ⇒ Object
- #update_shipping_address ⇒ Object
- #update_shipping_address_from_modal ⇒ Object
Methods included from MyAccountHelper
#account_nav_active?, #can_list_contact_resources?, #is_current_user_or_customer_login_email?, #setup_contact, #setup_customer_account, #sorted_contact_points
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
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_coupon(coupon_code) ⇒ Object (protected)
Attempts to apply a coupon to the cart
Returns error message string if failed, nil if successful
693 694 695 696 697 698 699 700 701 702 703 704 705 706 |
# File 'app/controllers/my_carts_controller.rb', line 693 protected def add_coupon(coupon_code) return nil if coupon_code.blank? res = @cart.customer_can_apply_coupon?(coupon_code) coupon = res[:coupon] msg = res[:message] return msg || "Coupon '#{coupon_code}' is invalid" unless coupon result = Coupon::ApplyCoupon.new.perform(@cart, { coupon_id: coupon.id }) return result.errors unless result.success? nil # Success - no error end |
#add_item ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'app/controllers/my_carts_controller.rb', line 108 def add_item sku_array = [{ sku: params[:sku], qty: params[:quantity], room_configuration_id: params[:room_configuration_id] }] begin @recently_added = @cart.add_multiple_items(sku_array) rescue Order::ItemNotFound => e flash.now[:error] = e..presence || 'We could not find that product in the catalog.' @recently_added = [] end @added_item = @recently_added&.first # Reload line_items to get fresh count after add_multiple_items saves @cart.line_items.reload # Store product info for analytics and toast display # Use ViewProductCatalog for proper pricing/category data catalog = Catalog.locale_to_catalog vpc = ViewProductCatalog.find_by(item_sku: params[:sku], catalog_id: catalog.id) @product_info = { sku: params[:sku], name: vpc&.item_name, image: vpc&.item&.primary_image_url(size: '100x100'), category: vpc&.product_category_name, price: vpc&.effective_price&.to_f, quantity: params[:quantity] || 1 } respond_to do |format| format.turbo_stream format.json do render json: cart_array end format.html do redirect_to my_cart_path end end end |
#add_multiple_items ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'app/controllers/my_carts_controller.rb', line 72 def add_multiple_items sku_array = [] if params[:items].present? sku_array = Array(params[:items]).map do |item| sku, qty = item.split('|') { sku:, qty: } end elsif (payload = request.body.read).present? skus = MultiJson.load(payload, symbolize_names: true) sku_array = skus.map { |sku:, qty:| { sku:, qty: } } end resolved_items, skipped_items = resolve_skus_for_cart(sku_array) @cart.add_multiple_items(resolved_items) if resolved_items.present? if skipped_items.present? skipped_skus = skipped_items.pluck(:sku).join(', ') flash[:warning] = "We could not add the following items to your cart: #{skipped_skus}." end if params[:coupon_code] coupon_error = add_coupon(params[:coupon_code]) flash[:error] = coupon_error if coupon_error end respond_to do |format| format.json do render json: cart_array end format.html do redirect_to my_cart_path end end end |
#adjust_sku_quantity ⇒ Object
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'app/controllers/my_carts_controller.rb', line 145 def adjust_sku_quantity if params[:sku].present? sku = params[:sku] quantity = params[:quantity].to_i room_configuration_id = params[:room_configuration_id] if sku.present? && quantity.positive? && quantity < 100 # find catalog by locale if (ci = @cart.catalog.catalog_items.public_catalog_items.by_skus(sku).first) @cart.recalculate_shipping = true # doesn't hurt to set it @cart.recalculate_discounts = true # ensure tier2 and auto-apply discounts are calculated @cart.force_total_reset = true if quantity.positive? @new_line = @cart.add_line_item(catalog_item_id: ci.id, quantity:, room_configuration_id:) # , :do_not_autosave => true) logger.debug "my_carts_controller#adjust_sku_quantity: Add SKU: #{sku} #{quantity} @new_line.inspect: #{@new_line.inspect}" logger.debug "my_carts_controller#adjust_sku_quantity: Add SKU: #{sku} #{quantity} @new_line.item.inspect: #{@new_line.item.inspect}" @cart.save! else if room_configuration_id && (room = RoomConfiguration.find(room_configuration_id)) container = room container_name = 'room' else container = @cart container_name = 'cart' end li = container.line_items.detect { |l| l.sku == sku } if li container.remove_line_item(li, quantity.abs) logger.debug "my_carts_controller#adjust_sku_quantity: Remove SKU: #{sku} #{quantity.abs} li.inspect: #{li.inspect}" logger.debug "my_carts_controller#adjust_sku_quantity: Remove SKU: #{sku} #{quantity.abs} li.item.inspect: #{li.item.inspect}" @cart.save else flash[:error] = "We could not find sku #{sku} in #{container_name} line items." end end else flash[:error] = "We could not find sku #{sku} in catalog." end else flash[:error] = "sku #{sku} not found in catalog or invalid quantities specified." end end respond_to do |format| format.turbo_stream format.html do redirect_to my_cart_path end format.json do render json: cart_array end end end |
#apply_coupon ⇒ Object
664 665 666 667 668 669 670 671 672 673 674 675 676 677 |
# File 'app/controllers/my_carts_controller.rb', line 664 def apply_coupon if params[:coupon_code] = add_coupon(params[:coupon_code]) flash[:error] = if end respond_to do |format| # TurboStreamFlashable will automatically append flash messages format.turbo_stream do render turbo_stream: turbo_stream.update('cart_discounts', partial: 'coupon_entry') end format.html { redirect_back_or_to(my_cart_path) } end end |
#cart_add_item(sku, qty = nil, room_configuration_id = nil) ⇒ Object (protected)
679 680 681 682 683 684 685 686 687 688 689 |
# File 'app/controllers/my_carts_controller.rb', line 679 protected def cart_add_item(sku, qty = nil, room_configuration_id = nil) # add item return if sku.blank? @recently_added_items ||= [] begin @recently_added_items = @cart.add_multiple_items([{ sku:, qty:, room_configuration_id: }]) rescue Order::ItemNotFound flash[:error] = "We could not find sku #{sku} in catalog." end end |
#cart_conflict ⇒ Object
Display cart conflict resolution page when user logs in with items in both guest and account carts
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 |
# File 'app/controllers/my_carts_controller.rb', line 336 def cart_conflict @guest_cart_id = session[:cart_conflict_guest_cart_id] @return_path = params[:return_path] || session[:cart_conflict_return_path] || customer_info_my_cart_path session[:cart_conflict_return_path] = @return_path prepare_cart_conflict_state return if performed? @resolver = Cart::ConflictResolver.new(account_cart: @account_cart, guest_cart: @guest_cart) if @resolver.conflict? @conflict_summary = @resolver.conflict_summary render 'my_carts/cart_conflict' else auto_resolve_cart_conflict end end |
#check_address_and_locale ⇒ Object
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'app/controllers/my_carts_controller.rb', line 199 def check_address_and_locale if params[:locale].downcase.include?(params[:country]) head :ok else logger.info "[set_locale] -> check_address_and_locale wants to assign new catalog, guest user locale: #{@context_user.locale}, requested locale #{I18n.locale}" new_catalog = params[:country] == 'ca' ? Catalog.find(2) : Catalog.find(1) result = @context_user.change_catalog(new_catalog) || {} if result.catalog_assigned? logger.info "[set_locale] -> check_address_and_locale, assigned new catalog #{new_catalog.id}" @context_user.reload locale = params[:country] == 'ca' ? :'en-CA' : :'en-US' redirect_url = cms_link(URI(request.referer).path, locale, host: WEB_HOSTNAME, scheme: 'https') render json: { redirect_url: redirect_url } else logger.error "[set_locale] -> check_address_and_locale, assigned new catalog #{new_catalog.id} failed #{result..to_sentence}" render json: { error: result..to_sentence }, status: :unprocessable_entity end end end |
#check_existing_account ⇒ Object
652 653 654 655 656 657 658 659 660 661 662 |
# File 'app/controllers/my_carts_controller.rb', line 652 def check_existing_account email = params[:email] return nil if fully_logged_in? return nil if email.blank? return unless Account.where(email:).any? respond_to do |format| format.json { head :ok } end end |
#check_inventory_levels ⇒ Object
631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 |
# File 'app/controllers/my_carts_controller.rb', line 631 def check_inventory_levels # Only check inventory levels of b-stock return false if @cart.line_items.bstock.blank? @items_in_cart = @cart.line_items.bstock.parents_only.non_shipping items_below_inventory = false @items_in_cart.each do |li| available_stock = li&.catalog_item&.qty_available || 0 if li.quantity <= available_stock # All good, we have inventory else ErrorReporting.error("Not enough inventory for an item in the cart. Item #{li.sku}. Qty added #{li.quantity}. Qty available #{available_stock}") # We update the cart to max out the available inventory li.update(quantity: available_stock) flash[:warning] = "Unfortunately we don't have enough stock available for the product '<i>#{li.name}</i>'. We updated the quantity in your cart to reflect the maximun stock available.".html_safe items_below_inventory = true end end items_below_inventory end |
#checkout ⇒ Object
322 323 324 325 326 327 328 329 330 331 332 333 |
# File 'app/controllers/my_carts_controller.rb', line 322 def checkout if @cart.empty? redirect_to my_cart_path elsif check_inventory_levels flash.keep(:warning) redirect_to my_cart_path elsif @cart.includes_schedulable_service? redirect_to schedule_service_my_cart_path else redirect_to customer_info_my_cart_path end end |
#checkout_update ⇒ Object
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 |
# File 'app/controllers/my_carts_controller.rb', line 537 def checkout_update params[:checkout_form] ||= {} params[:checkout_form][:order_id] = @cart.id address_option = params['customer-addresses'] params[:checkout_form][:shipping_address][:recipient] = "#{params[:shipping_first_name]} #{params[:shipping_last_name]}" if params[:checkout_form][:shipping_address].present? params[:checkout_form][:billing_address][:recipient] = params[:checkout_form][:contact_name].to_s params[:checkout_form][:address_id] = address_option @checkout_form = Checkout::CheckoutForm.new(params[:checkout_form]) spam_checker = SpamCheck.new is_spam = spam_checker.process(request:, author_email: @checkout_form.email, phone_number: @checkout_form.phone) success = !is_spam && @checkout_form.save if is_spam # We don't want to say why its spam @checkout_form.errors.add(:checkout, ": An unknown error occurred, please contact us to complete your order. Reference cart number SC#{@cart.id}") @cart.quick_note spam_checker.spam_results_to_s end logger.info "Saving cart #{@cart.id}, is_spam: #{is_spam}, cart save: #{success}, errors are #{@checkout_form.errors_to_s}" initialize_address_book # Make sure all addresses are set up if success @cart = @cart.reload begin logger.info 'Cart successfully saved.' if @cart.shipping_address.nil? @cart.update(shipping_address_id: @addresses.first.id) @cart.save end @cart = @cart.reload redirect_to shipping_my_cart_path rescue StandardError => e ErrorReporting.error(e) redirect_to shipping_my_cart_path end else @cancel_path = checkout_my_cart_path @new_address = true if address_option.present? && address_option == 'new' msg = "Error during checkout with cart #{@cart.id}. The form could not be saved. is_spam: #{is_spam}. #{@checkout_form.errors_to_s}. Params sent by the customer are: #{params[:checkout_form]}" ErrorReporting.warning(msg) logger.warn msg # Force HTML format - Turbo Drive handles 422 HTML responses by replacing page content render 'my_carts/new_checkout/customer_info', status: :unprocessable_entity, formats: [:html] end end |
#customer_info ⇒ Object
385 386 387 388 389 390 391 392 393 394 395 |
# File 'app/controllers/my_carts_controller.rb', line 385 def customer_info if @cart.empty? redirect_to my_cart_path else logger.info "Checkout for cart #{@cart.id}" @show_tab = params[:show_tab] @material_alerts = @cart.get_material_alerts(for_www: true, for_cart: true) setup_checkout render 'my_carts/new_checkout/customer_info' end end |
#payment ⇒ Object
509 510 511 512 513 514 515 516 517 518 519 520 |
# File 'app/controllers/my_carts_controller.rb', line 509 def payment if @cart.empty? redirect_to my_cart_path else @cart.reload.reset_discount # Temporary fix while we fix the underlying issues with the total amount not being correct @cart.reload # Reload after reset_discount to pick up DB-calculated total @hide_shipping = false @payment_options = @cart.('cart') @payment = @cart.payments.build(category: 'Credit Card') render 'my_carts/new_checkout/payment' end end |
#remove_all_line_items ⇒ Object
255 256 257 258 259 |
# File 'app/controllers/my_carts_controller.rb', line 255 def remove_all_line_items @cart.reset_cart flash[:info] = 'Your shopping cart was emptied.' redirect_to_return_path_or_default my_cart_path end |
#remove_coupon ⇒ Object
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 |
# File 'app/controllers/my_carts_controller.rb', line 601 def remove_coupon coupon_code = params[:coupon_code] coupon = @cart.customer_applied_coupons.where(code: coupon_code).first discount = nil discount = @cart.discounts.where(coupon_id: coupon.id).first if coupon.present? if coupon && discount res = Coupon::DeleteDiscount.new.perform(discount) if res.success? flash[:info] = "Coupon code #{coupon_code} removed." else flash[:error] ||= '' flash[:error] += res.errors end else flash[:error] ||= '' flash[:error] += "No customer applied coupons with code #{coupon_code} found!" end respond_to do |format| format.html { redirect_to request.referer || my_cart_path } end end |
#remove_from ⇒ Object
599 |
# File 'app/controllers/my_carts_controller.rb', line 599 def remove_from; end |
#remove_item ⇒ Object
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
# File 'app/controllers/my_carts_controller.rb', line 219 def remove_item line_item = LineItem.find_by(id: params[:line_item_id].to_i) if line_item if line_item.is_smartinstall_service? @cart.line_items.select { |li| li.id == line_item.id || li.(line_item.sku) }.each(&:destroy) else @cart.line_items.select { |li| li.id == params[:line_item_id].to_i }.each(&:destroy) end @cart.set_for_recalc begin @cart.save! rescue StandardError => e ErrorReporting.error(e) end @cart.line_items.reload else ErrorReporting.warning("Line item #{params[:line_item_id]} not found in cart #{@cart.id}") flash[:error] = 'We could not remove the requested line item from your cart.' end respond_to do |format| format.html { redirect_to my_cart_path } format.json { render json: cart_array } end end |
#remove_room ⇒ Object
244 245 246 247 248 249 250 251 252 253 |
# File 'app/controllers/my_carts_controller.rb', line 244 def remove_room @room = RoomConfiguration.find(params[:room_id]) res_hash = @cart.remove_room_configuration(@room) if res_hash[:status] flash[:info] = res_hash[:message] else flash[:error] = res_hash[:message] end redirect_to_return_path_or_default my_cart_path end |
#resolve_cart_conflict ⇒ Object
Handle user's choice for cart conflict resolution
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 |
# File 'app/controllers/my_carts_controller.rb', line 355 def resolve_cart_conflict strategy = params[:strategy]&.to_sym @guest_cart_id = session[:cart_conflict_guest_cart_id] @return_path = session[:cart_conflict_return_path] || customer_info_my_cart_path unless @guest_cart_id && strategy flash[:error] = 'Unable to resolve cart conflict. Please try again.' redirect_to my_cart_path return end @guest_cart = Order.find_by(id: @guest_cart_id) @account_cart = @cart resolver = Cart::ConflictResolver.new(account_cart: @account_cart, guest_cart: @guest_cart) result = resolver.resolve(strategy:) if result[:success] clear_cart_conflict_session flash[:success] = (result[:strategy]) redirect_to @return_path else # Preserve session[:cart_conflict_guest_cart_id] / :cart_conflict_return_path # so the customer lands back on the merge UI and can retry a different # strategy instead of losing their guest cart silently. flash[:error] = 'Unable to resolve cart conflict. Please try again.' redirect_to cart_conflict_my_cart_path end end |
#retrieve ⇒ Object
36 37 38 39 |
# File 'app/controllers/my_carts_controller.rb', line 36 def retrieve # redirect after trying to authenticate token in before action redirect_to my_cart_path(referral_code: params[:referral_code]) end |
#schedule_service ⇒ Object
397 398 399 400 401 402 403 404 |
# File 'app/controllers/my_carts_controller.rb', line 397 def schedule_service if @cart.empty? redirect_to my_cart_path else @service_form = Checkout::ServiceForm.new_from_cart(@cart) render 'my_carts/new_checkout/schedule_service' end end |
#schedule_service_update ⇒ Object
522 523 524 525 526 527 528 529 530 531 532 533 534 535 |
# File 'app/controllers/my_carts_controller.rb', line 522 def schedule_service_update params[:service_form][:order_id] = @cart.id @service_form = Checkout::ServiceForm.new(params[:service_form]) success = @service_form.save if success redirect_to customer_info_my_cart_path else @cancel_path = schedule_service_my_cart_path ErrorReporting.error("Error while scheduling service with cart #{@cart.id}. The form could not be saved. #{@service_form.errors_to_s}. Params sent by the customer are: #{params[:service_form]}") logger.info "Error while scheduling service with cart #{@cart.id}. The form could not be saved. #{@service_form.errors_to_s}." # Force HTML format - Turbo Drive handles 422 HTML responses by replacing page content render 'my_carts/new_checkout/schedule_service', status: :unprocessable_entity, formats: [:html] end end |
#set_cart_qty ⇒ Object
623 624 625 626 627 628 629 |
# File 'app/controllers/my_carts_controller.rb', line 623 def set_cart_qty @material_alerts = @cart.get_material_alerts(for_www: true, for_cart: true) @items_in_cart = @cart.line_items.parents_only.non_shipping.sum(:quantity) @items_in_cart ||= 0 session[:cart_id_number] = @cart&.id session[:cart_qty] = @items_in_cart end |
#shipping ⇒ Object
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 |
# File 'app/controllers/my_carts_controller.rb', line 406 def shipping if @cart.empty? redirect_to my_cart_path else unless @cart.is_warehouse_pickup? @cart.retrieve_shipping_costs if @cart.deliveries.empty? || @cart.deliveries.nil? @deliveries = {} @hide_shipping = false @cart.need_to_recalculate_shipping @cart.reload.deliveries.each_with_index do |delivery, index| shipping_costs_hash = delivery&.sorted_shipping_costs_www_hash economy_shipping_costs = shipping_costs_hash.fetch(:economy, []) ground_shipping_costs = shipping_costs_hash.fetch(:ground, []) faster_shipping_costs = shipping_costs_hash.fetch(:faster, []) freight_shipping_costs = shipping_costs_hash.fetch(:freight, []) @deliveries[:"delivery_#{index}"] = { ships_from: delivery.ships_from_text, delivery_id: delivery.id, economy_shipping_costs:, ground_shipping_costs:, faster_shipping_costs:, freight_shipping_costs:, selected_shipping_cost_id: delivery.selected_shipping_cost_id } end @has_ground_shipping_options = begin @deliveries.map { |a| a[1][:ground_shipping_costs].present? }.uniq.include?(true) rescue StandardError false end @found_check = false # Ensure ships_economy flag reflects the current selection when a selection already exists # This guarantees the FREE_ECONOMY_ONLINE coupon logic runs without requiring a new click @cart.deliveries.each do |dq| next if dq.selected_shipping_cost_id.blank? # CRITICAL: Ensure shipping line item exists BEFORE updating economy status # The FREE_ECONOMY_ONLINE coupon needs a shipping line to discount. # Without this, reset_discount calculates $0 discount (no shipping line) and deletes it. if dq.selected_shipping_cost && dq.line_items.none?(&:is_shipping?) dq.apply_selected_shipping_cost!(dq.selected_shipping_cost, persist: true) dq.reload end should_be_economy = dq.shipping_option&.is_override? && !dq.ships_ltl_freight? next unless @cart.respond_to?(:ships_economy) && (@cart.state == 'cart') if should_be_economy && !@cart.ships_economy Shipping::UpdateShippingMethod.new.update_economy_status(@cart, true) elsif !should_be_economy && @cart.ships_economy Shipping::UpdateShippingMethod.new.update_economy_status(@cart, false) end # Auto-select shipping options only if none are selected yet next if dq.selected_shipping_cost_id.present? shipping_costs_hash = dq.sorted_shipping_costs_www_hash if !dq.shipping_option&.is_override? || dq.ships_ltl_freight? # Freight orders: disable economy and select freight option Shipping::UpdateShippingMethod.new.update_economy_status(@cart, false) freight_shipping_costs = shipping_costs_hash.fetch(:freight, []) dq.selected_shipping_cost_id = freight_shipping_costs&.first&.id dq.save elsif !@cart.should_ship_freight? # Non-freight orders: customer qualifies for economy shipping # Auto-select first economy option and apply free shipping discount Shipping::UpdateShippingMethod.new.update_economy_status(@cart, true) economy_shipping_costs = shipping_costs_hash.fetch(:economy, []) if economy_shipping_costs.any? first_economy = economy_shipping_costs.first result = Shipping::UpdateShippingMethod.new.update_from_shipping_cost(dq, first_economy, @cart) Rails.logger.info "Auto-selected economy shipping: #{result.success? ? 'success' : result.errors}" end end end # Reload cart and deliveries data structure after auto-selection so sidebar totals reflect discounts @cart.reload @deliveries = {} @cart.deliveries.each_with_index do |delivery, index| shipping_costs_hash = delivery&.sorted_shipping_costs_www_hash economy_shipping_costs = shipping_costs_hash.fetch(:economy, []) ground_shipping_costs = shipping_costs_hash.fetch(:ground, []) faster_shipping_costs = shipping_costs_hash.fetch(:faster, []) freight_shipping_costs = shipping_costs_hash.fetch(:freight, []) @deliveries[:"delivery_#{index}"] = { ships_from: delivery.ships_from_text, delivery_id: delivery.id, economy_shipping_costs:, ground_shipping_costs:, faster_shipping_costs:, freight_shipping_costs:, selected_shipping_cost_id: delivery.selected_shipping_cost_id } end end render 'my_carts/new_checkout/shipping' end end |
#shipping_address ⇒ Object
583 584 585 586 587 |
# File 'app/controllers/my_carts_controller.rb', line 583 def shipping_address @addresses = @addresses.find_all { |a| a.country_iso3 == @cart.store.country_iso3 }.sort_by { |a| a.default_shipping ? -10 : 0 } @addresses << @cart.store.warehouse_address @hide_new_address_form = true end |
#shipping_update ⇒ Object
589 |
# File 'app/controllers/my_carts_controller.rb', line 589 def shipping_update; end |
#show ⇒ Object
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 |
# File 'app/controllers/my_carts_controller.rb', line 41 def show @cart.first_cart_view_date ||= Time.current @cart.save flash.keep(:warning) if params[:quote_id].present? msg = nil @quote = (begin @context_user.customer.quotes.find(params[:quote_id]) rescue StandardError nil end) msg = 'Could not find quote. Your session may have expired.' if @quote.nil? if @quote.present? && params[:room_id].present? @room = (begin @quote.room_configurations.find(params[:room_id]) rescue StandardError nil end) msg = 'Could not find room. Your session may have expired.' if @room.nil? end flash[:info] = msg if msg.present? end check_material_alerts respond_to do |format| format.html format.json do render json: cart_array end end end |
#update ⇒ Object
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
# File 'app/controllers/my_carts_controller.rb', line 301 def update update_cart @cart.save @cart.prune_cart_rooms set_cart_qty @redirect_to_checkout = /CheckOut|Coupon/i.match?(params['commit']) respond_to do |format| format.turbo_stream format.html do if @redirect_to_checkout redirect_to checkout_my_cart_path else redirect_to my_cart_path end end format.json do render json: cart_array end end end |
#update_from_payment ⇒ Object
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 |
# File 'app/controllers/my_carts_controller.rb', line 261 def update_from_payment if params.dig(:cart, :shipping_cost_id).blank? respond_to do |format| format.turbo_stream { head :unprocessable_entity } format.html { redirect_to my_cart_path } end return end # Use service to handle shipping selection # Pass params directly - the service will extract what it needs result = Shipping::UpdateShippingMethod.new.update_from_params(@cart, params) unless result.success? Rails.logger.error "Failed to update shipping: #{result.errors}" respond_to do |format| format.turbo_stream { head :unprocessable_entity } format.html { redirect_to my_cart_path, alert: result.errors } end return end result..each { |msg| Rails.logger.info msg } @cart = @cart.reload if @cart.deliveries.empty? Rails.logger.error "update_from_payment: cart #{@cart.id} has no deliveries after shipping update" respond_to do |format| format.turbo_stream { head :unprocessable_entity } format.html { redirect_to shipping_my_cart_path } end return end respond_to do |format| format.turbo_stream format.html { redirect_to my_cart_path } end end |
#update_shipping_address ⇒ Object
591 592 593 |
# File 'app/controllers/my_carts_controller.rb', line 591 def update_shipping_address update_method_for_cart end |
#update_shipping_address_from_modal ⇒ Object
595 596 597 |
# File 'app/controllers/my_carts_controller.rb', line 595 def update_shipping_address_from_modal update_method_for_cart end |