Class: Crm::CustomerOutletPurchasesController
- Inherits:
-
CrmController
- Object
- ActionController::Base
- ApplicationController
- CrmController
- Crm::CustomerOutletPurchasesController
- Defined in:
- app/controllers/crm/customer_outlet_purchases_controller.rb
Overview
Controller: customer outlet purchases.
Reps and the nightly sweep propose links between an opportunity and the
retailer invoice a customer actually generated; the rep confirms whether the
order relates to the project. Nothing here writes to the Opportunity except
through the explicit close_opportunity action — see
doc/tasks/202608081330_OUTLET_PURCHASE_ATTRIBUTION.md § 3.
Constant Summary
Constants included from Controllers::ReferenceFindable
Controllers::ReferenceFindable::ID_EMBEDDED_PATTERNS
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
Instance Method Summary collapse
-
#close_opportunity ⇒ void
Mark the opportunity won against this purchase.
- #create ⇒ void
- #destroy ⇒ void
-
#index ⇒ void
The review queue: every swept match nobody has ruled on yet.
-
#reject ⇒ void
Orders team rules the order out — it is not part of that project.
-
#show ⇒ void
The analysis behind a match: what was quoted, what was bought, which SKUs overlap, and how the confidence score was arrived at.
-
#verify ⇒ void
Orders team accepts a swept match — advances it to
pending.
Methods inherited from CrmController
#access_denied, #context_id, #context_object, #crm_home_path, #current_ability, #default_url_options, #download_temp, #get_tempfile_path_for_download, #init_status_job_collector, #initialize_crm_lazy_chunks, #persist_enqueued_status_jobs, #record_not_found, #redirect_to_job_or_fallback, #render_edit_action, #set_context, #set_download_path, #stash_file_for_temp_download, #sync_admin_presence_cookie, #touch_employee_last_seen
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?, #skip_layout_for_turbo_frame?, #stamp_impersonation_context, #tab_frame_breakout_request?, #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, #registration_lead_type, #track_event
Methods included from Controllers::DeviceDetection
Methods included from Controllers::SubdomainDetection
#is_crm_request?, #is_www_request?, #json_request?
Methods included from Controllers::TurboSafeRedirect
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 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?
Instance Method Details
#close_opportunity ⇒ void
This method returns an undefined value.
Mark the opportunity won against this purchase. Deliberately explicit —
28% of matched purchases are under a quarter of the quoted value and won
cancels every follow-up, so this is never automatic.
68 69 70 71 72 73 74 75 76 |
# File 'app/controllers/crm/customer_outlet_purchases_controller.rb', line 68 def close_opportunity (:close_opportunity, @purchase) if @purchase.close_opportunity! redirect_back_to_context(notice: 'Opportunity marked won against this outlet purchase.') else redirect_back_to_context(alert: 'Could not mark that opportunity won.') end end |
#create ⇒ void
This method returns an undefined value.
51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'app/controllers/crm/customer_outlet_purchases_controller.rb', line 51 def create @purchase = CustomerOutletPurchase.new(link_attributes) (:create, @purchase) return unresolved_invoice if invoice_reference.present? && @purchase.invoice_id.nil? if @purchase.save redirect_back_to_context(notice: 'Outlet purchase linked and accepted.') else redirect_back_to_context(alert: @purchase.errors..to_sentence) end end |
#destroy ⇒ void
This method returns an undefined value.
107 108 109 110 111 112 113 114 |
# File 'app/controllers/crm/customer_outlet_purchases_controller.rb', line 107 def destroy (:destroy, @purchase) # A `before_destroy` can abort — `Opportunity#collapse_colliding_outlet_purchases` # prepends one — and a success flash over a surviving row is a lie. return redirect_back_to_context(notice: 'Outlet purchase link removed.') if @purchase.destroy redirect_back_to_context(alert: 'Could not remove that outlet purchase link.') end |
#index ⇒ void
This method returns an undefined value.
The review queue: every swept match nobody has ruled on yet.
Exists because the daily digest was the only way to see these, so a row
missed on the morning it was proposed was effectively invisible — the
12-month backfill landed 86 at once and none of them appear in any one
day's email.
Ordered by confidence, but the column that decides most rulings is
engagement, and the two are near-independent (r = 0.09 across the backlog).
The disagreement is the point: a certain match nobody worked is the case
that must not be waved through.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'app/controllers/crm/customer_outlet_purchases_controller.rb', line 26 def index (:read, CustomerOutletPurchase) # ponytail: RepEngagement scores each row through six counts and a quotes # lookup — a measured 7 queries a row, and no `includes` can reach them # (`.count`/`.order` reissue, and two signals are class-level scopes on # Communication / CallRecord). Fine at 86 and ~90/year, and the backlog # shrinks as it is ruled on. Batching means reimplementing the per-row # credit window in Ruby, which would let the queue and the analysis page # disagree; if this ever runs to thousands, store the score on the row at # match time instead. `the review queue cost per row stays bounded` holds # the ceiling at 8. @purchases = CustomerOutletPurchaseQuery.new.awaiting_verification .for_review @backlog_value = CustomerOutletPurchaseQuery.new.awaiting_verification.total_revenue end |
#reject ⇒ void
This method returns an undefined value.
Orders team rules the order out — it is not part of that project.
95 96 97 98 99 100 101 102 103 104 |
# File 'app/controllers/crm/customer_outlet_purchases_controller.rb', line 95 def reject (:reject, @purchase) record_decision_note if @purchase.reject(current_user) redirect_back_to_context(notice: 'Outlet purchase rejected.') else redirect_back_to_context(alert: 'Could not reject that outlet purchase.') end end |
#show ⇒ void
This method returns an undefined value.
The analysis behind a match: what was quoted, what was bought, which SKUs
overlap, and how the confidence score was arrived at. The table row carries
the verdict; this page carries the working.
46 47 48 |
# File 'app/controllers/crm/customer_outlet_purchases_controller.rb', line 46 def show (:read, @purchase) end |
#verify ⇒ void
This method returns an undefined value.
Orders team accepts a swept match — advances it to pending.
81 82 83 84 85 86 87 88 89 90 |
# File 'app/controllers/crm/customer_outlet_purchases_controller.rb', line 81 def verify (:verify, @purchase) record_decision_note if @purchase.verify(current_user) redirect_back_to_context(notice: 'Outlet purchase verified.') else redirect_back_to_context(alert: 'Could not verify that outlet purchase.') end end |