Class: OpportunitiesController

Inherits:
CrmController show all
Includes:
Controllers::Attachable, Controllers::DigitalAssetLinkable, Controllers::Workflowable
Defined in:
app/controllers/opportunities_controller.rb

Constant Summary collapse

EDIT_PARTICIPANTS_ACTION =
'Edit Participants'
EDIT_ROOMS_ACTION =
'Edit Rooms'

Constants included from Controllers::Attachable

Controllers::Attachable::PUBLICATIONS_PER_PAGE

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

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 included from Controllers::DigitalAssetLinkable

#link_images, #link_videos

Methods included from Controllers::Attachable

#attach, #publication_modal, #remove_attachment, #search_library

Methods included from Controllers::Workflowable

#render_workflow_error_stream, #render_workflow_success_stream, #workflow_action, #workflow_action_complete

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, #initialize_crm_lazy_chunks, #record_not_found, #redirect_to_job_or_fallback, #render_edit_action, #set_context, #set_download_path, #stash_file_for_temp_download

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

#assign_plansObject



381
382
383
# File 'app/controllers/opportunities_controller.rb', line 381

def assign_plans
  render layout: 'crm/crm'
end

#attach_ordersObject



198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'app/controllers/opportunities_controller.rb', line 198

def attach_orders
  attach_order_ids = params[:order_ids] || []
  success = []
  @opportunity.unattached_orders.where(id: attach_order_ids).each do |order|
    order.update_attribute(:opportunity_id, @opportunity.id)
    success << order.reference_number
  end
  flash[:info] = if success.present?
                   "Order(s) #{success.join(', ')} were attached to opportunity #{@opportunity.name}. "
                 else
                   +'No orders were attached. '
                 end
  if params[:mark_as_won].to_b
    if @opportunity.win
      flash[:info] = "#{flash[:info]} Opportunity was marked as won. "
    else
      flash[:error] = 'Opportunity could not be marked as won. '
    end
  end
  redirect_to opportunity_path(@opportunity)
end

#batch_mergeObject



313
314
315
316
317
# File 'app/controllers/opportunities_controller.rb', line 313

def batch_merge
  @opportunities = @customer.opportunities
  @opportunities = @opportunities.open_opportunities.not_cancelled unless params[:show_all_opportunities]
  @opportunities = @opportunities.most_recent_first
end

#cancelObject



143
144
145
146
# File 'app/controllers/opportunities_controller.rb', line 143

def cancel
  @opportunity.cancel if @opportunity.cancelable?
  redirect_to_return_path_or_default opportunity_path(@opportunity)
end

#choose_next_installationObject



422
423
424
# File 'app/controllers/opportunities_controller.rb', line 422

def choose_next_installation
  @room_configuration = RoomConfiguration.find(params[:room_id])
end

#complete_assign_plansObject



385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
# File 'app/controllers/opportunities_controller.rb', line 385

def complete_assign_plans
  @opportunity = Opportunity.find(params[:id])
  counter = 0
  msg = []
  params[:uploads].each do |upload_id, upload_attrs|
    next if upload_attrs[:resource_combo].blank?

    upload = Upload.find(upload_id)
    counter += 1 if upload.update(upload_attrs)
    msg << upload.errors.full_messages if upload.errors.present?
  end
  if counter.positive?
    flash[:info] = "Re-assignment complete, #{counter} room(s) updated."
    redirect_to opportunity_path(@opportunity)
  else
    flash.now[:error] = "No files were re-assigned. #{msg.join(',')}"
    render :assign_plans, layout: 'crm/crm', status: :unprocessable_entity
  end
end

#complete_new_installationObject



73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'app/controllers/opportunities_controller.rb', line 73

def complete_new_installation
  @opportunity = Opportunity.new(params[:opportunity])
  @customer.opportunities << @opportunity

  if @opportunity.new_record?
    render :new_installation, status: :unprocessable_entity
  else
    redirect_to installation_record_room_configuration_path(@opportunity.room_configurations.first)
  end
rescue ActiveRecord::RangeError => e
  @opportunity.errors.add(:base, "A numeric value is out of range. Please check your inputs and try again.")
  render :new_installation, status: :unprocessable_entity
end

#complete_promiseObject



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

def complete_promise
  if @opportunity.can_promise?
    @opportunity.attributes = params[:opportunity]
    if @opportunity.promise # save
      flash[:info] = 'Opportunity marked as promised'
      redirect_to opportunity_path(@opportunity)
    else
      flash.now[:error] = @opportunity.errors_to_s.presence || 'Could not mark opportunity as promised.'
      render :promise, status: :unprocessable_entity
    end
  else
    flash[:error] = 'Opportunity is not in a state that can transition to promised'
    redirect_to opportunity_path(@opportunity)
  end
end

#confirm_participantsObject



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'app/controllers/opportunities_controller.rb', line 28

def confirm_participants
  if @opportunity.update(params[:opportunity])
    if @opportunity.contact_id.nil?
      first_participant = @opportunity.opportunity_participants.first
      if first_participant && first_participant.party.customer&.id == @opportunity.customer_id && first_participant.party.is_a?(Contact)
        @opportunity.contact_id = first_participant.party.id
        first_participant.party.job_title ||= first_participant.role
        first_participant.party.save
        if @opportunity.save
          first_participant.destroy
          flash[:info] = "Participant #{first_participant.party.full_name} was moved to primary contact of opportunity"
        else
          flash[:error] = "Could not automatically make #{first_participant.party.full_name} primary contact of opportunity. #{@opportunity.errors_to_s}"
        end
      end
    end
    handle_next_action
  else
    flash.now[:error] = @opportunity.errors_to_s.presence || 'Could not update participants.'
    render :participants, status: :unprocessable_entity
  end
rescue ActiveRecord::InvalidForeignKey
  flash[:error] = "One of the selected participants no longer exists. Please refresh and try again."
  redirect_to participants_opportunity_path(@opportunity)
end

#copyObject



251
252
253
# File 'app/controllers/opportunities_controller.rb', line 251

def copy
  @target_opportunities = @opportunity.customer.opportunities.to_a.dup - [@opportunity]
end

#createObject

PUT /customers/1/opportunities



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'app/controllers/opportunities_controller.rb', line 94

def create
  @opportunity = Opportunity.new(params[:opportunity])
  authorize! :create, @opportunity
  @customer.opportunities << @opportunity
  if @opportunity.new_record?
    set_default_electricity_rate
    render :new, status: :unprocessable_entity
  else
    handle_next_action
  end
rescue ActiveRecord::RangeError => e
  @opportunity.errors.add(:base, "A numeric value is out of range. Please check your inputs and try again.")
  set_default_electricity_rate
  render :new, status: :unprocessable_entity
end

#destroyObject

DELETE /customers/1/opportunities/1



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'app/controllers/opportunities_controller.rb', line 126

def destroy
  if @opportunity.ok_to_delete?
    @opportunity.destroy
    redirect_to customer_path(@customer)
  else
    deps = []
    @opportunity.quotes.limit(10).each do |q|
      deps << view_context.link_to("Quote #{q.reference_number}", quote_path(q))
    end
    @opportunity.room_configurations.limit(10).each do |rc|
      deps << view_context.link_to("Room #{rc.name}", room_configuration_path(rc))
    end
    flash[:error] = "Opportunity cannot be deleted because it is referenced by: #{deps.join(', ')} (limited to first 10 of each type)"
    redirect_to opportunity_path(@opportunity)
  end
end

#do_batch_mergeObject



319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
# File 'app/controllers/opportunities_controller.rb', line 319

def do_batch_merge
  @opportunity = Opportunity.find(params[:master_opportunity_id])
  authorize! :merge, @opportunity

  success_messages = []
  error_messages = []
  error_messages << 'Nothing selected to merge' if params[:opportunity_action].blank?
  (params[:opportunity_action] || []).each do |opportunity_id, merge_action|
    case merge_action
    when 'M' # Merge
      imported_opportunity = Opportunity.find(opportunity_id)
      result = Opportunity::Merger.new.process(duplicate_opp: imported_opportunity, survivor_opp: @opportunity)
      if result.merged?
        success_messages += result.messages
      else
        error_messages += result.messages
      end
    when 'D' # Delete
      deleted_opportunity = Opportunity.find(opportunity_id)
      deleted_opportunity.destroy
      success_messages << "Opportunity #{deleted_opportunity} was deleted"
    end
  end
  flash[:info] = success_messages.join('. ') if success_messages.present?
  flash[:error] = error_messages.join('. ') if error_messages.present?
  if error_messages.any?
    redirect_to batch_merge_customer_opportunities_path(@opportunity.customer)
  else
    redirect_to_return_path_or_default @opportunity
  end
end

#do_copyObject



255
256
257
258
259
260
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
300
301
302
303
304
305
306
307
308
309
310
311
# File 'app/controllers/opportunities_controller.rb', line 255

def do_copy
  if (customer_id = params.dig(:copy, :customer_id)).present?
    customer_copying_to = Customer.find(customer_id)
  end
  quotes_copying_to = (params[:quote_ids].presence || []).map(&:to_i)

  if customer_copying_to.present? && quotes_copying_to.present?
    current_customer_catalog_id = Customer.find(@opportunity.customer_id).catalog_id
    target_customer_catalog_id = customer_copying_to.catalog_id
    target_customer = params.dig(:copy, :customer_id).to_i
    current_customer = @opportunity.customer_id
    has_same_opportunity = Opportunity.where(customer_id: customer_copying_to.id).where(name: @opportunity.name)

    if target_customer == current_customer
      flash[:error] = 'Cannot copy an opportunity to the same customer.'
      redirect_back_or_to root_path && return
    end

    # if target_customer_catalog_id != current_customer_catalog_id
    #   flash[:error] = 'Cannot copy an opportunity between different customer catalog.'
    #   redirect_back(fallback_location: root_path) && return
    # end

    if has_same_opportunity.present?
      flash[:error] = 'Current opportunity cannot be copied. Target customer already has it.'
      redirect_back_or_to root_path && return
    end

    # if @opportunity.orders.active.non_carts.present?
    #   flash[:error] = 'Cannot copy an opportunity with active orders, cancel them before.'
    #   redirect_back(fallback_location: root_path) && return
    # end

    job_options = {
        customer_id: customer_copying_to.id,
        opportunity_id: @opportunity.id,
        quote_ids: quotes_copying_to,
        notify_email: current_user.email
    }.stringify_keys
    job_id = OpportunityCopyWorker.perform_async(job_options)
    if job_id.blank?
      if job_id = BackgroundJobStatus.search(worker_klass: 'OpportunityCopyWorker', args: job_options).first&.dig(:job_id)
        flash[:warning] = 'A similar job was already enqueued, watching status of that job now'
      end
    end
    if job_id.present?
      redirect_to job_path(job_id)
    else
      flash[:warning] = 'There was a problem queuing the job'
      redirect_to_return_path_or_default opportunity_path(@opportunity)
    end

  else
    flash[:error] = 'Customer or quotes selected are not valid. Remember that you must select the target customer and at least 1 quote.'
    redirect_back_or_to root_path
  end
end

#do_moveObject



229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'app/controllers/opportunities_controller.rb', line 229

def do_move
  if (customer_id = params.dig(:move, :customer_id)).present?
    customer_moving_to = Customer.find(customer_id)
  end

  if customer_moving_to
    om = Opportunity::Mover.new(@opportunity)
    if om.move_to(customer_moving_to)
      flash[:info] = 'Move successful'
      redirect_to opportunity_path(@opportunity)
    else
      flash.now[:error] = om.results.join(',')
      @target_opportunities = @opportunity.customer.opportunities.to_a.dup - [@opportunity]
      render :move, status: :unprocessable_entity
    end
  else
    flash.now[:error] = 'Invalid customer selected'
    @target_opportunities = @opportunity.customer.opportunities.to_a.dup - [@opportunity]
    render :move, status: :unprocessable_entity
  end
end

#editObject



87
88
89
90
91
# File 'app/controllers/opportunities_controller.rb', line 87

def edit
  @opportunity = Opportunity.find(params[:id])
  set_default_electricity_rate
  authorize! :update, @opportunity
end

#enter_roomsObject



430
431
432
# File 'app/controllers/opportunities_controller.rb', line 430

def enter_rooms
  handle_next_action
end

#indexObject



13
14
15
16
17
18
19
20
21
22
# File 'app/controllers/opportunities_controller.rb', line 13

def index
  @context_object = context_object
  scope = @context_object&.try(:all_opportunities) || @context_object&.opportunities || Opportunity.all
  @q = scope.ransack(params[:q])
  @pagy, @opportunities = pagy(:countish, @q.result.order('opportunities.created_at desc'))
  respond_to do |format|
    format.html { render layout: should_render_layout? }
    format.turbo_stream
  end
end

#loseObject



173
174
175
# File 'app/controllers/opportunities_controller.rb', line 173

def lose
  redirect_to lost_reason_opportunity_path(@opportunity)
end

#lost_reasonObject



356
# File 'app/controllers/opportunities_controller.rb', line 356

def lost_reason; end

#lost_reason_updateObject



358
359
360
361
362
363
364
365
366
367
368
# File 'app/controllers/opportunities_controller.rb', line 358

def lost_reason_update
  @opportunity.attributes = opportunity_lost_params

  if transition_to_lost_state
    flash[:info] = "Opportunity marked as #{@opportunity.state.humanize.downcase}."
    redirect_to opportunity_path(@opportunity)
  else
    flash.now[:error] = @opportunity.errors_to_s.presence || 'Could not mark opportunity as lost.'
    render :lost_reason, status: :unprocessable_entity
  end
end

#mergeObject



351
352
353
354
# File 'app/controllers/opportunities_controller.rb', line 351

def merge
  # sending to new page
  redirect_to batch_merge_customer_opportunities_path(@opportunity.customer, master_opportunity_id: @opportunity.id)
end

#moveObject



225
226
227
# File 'app/controllers/opportunities_controller.rb', line 225

def move
  @target_opportunities = @opportunity.customer.opportunities.to_a.dup - [@opportunity]
end

#newObject



62
63
64
65
66
# File 'app/controllers/opportunities_controller.rb', line 62

def new
  @opportunity = @customer.opportunities.build(contact_id: params[:contact_id], source: @customer.source_for_opps_and_orders)
  set_default_electricity_rate
  authorize! :create, @opportunity
end

#new_installationObject



68
69
70
71
# File 'app/controllers/opportunities_controller.rb', line 68

def new_installation
  @opportunity = @customer.opportunities.build
  @opportunity.room_configurations.build(room_type_id: 18) # start with 'Other' here to avoid nil room_type
end

#participant_lookupObject

Used by tom-select field on opportunity/:id/participants
if q is specified a global lookup is run
if party_id is specified, then a single party is looked up (used to initialize form on load typically)



57
58
59
60
# File 'app/controllers/opportunities_controller.rb', line 57

def participant_lookup
  results = OpportunityParticipant.find_participants(@opportunity, params)
  render json: results
end

#participantsObject



26
# File 'app/controllers/opportunities_controller.rb', line 26

def participants; end

#promiseObject



148
149
150
151
152
153
154
155
# File 'app/controllers/opportunities_controller.rb', line 148

def promise
  authorize!(:update, @opportunity)
  if @opportunity.can_promise?
    render :promise
  else
    redirect_to(opportunity_path(@opportunity), flash: { error: 'Opportunity cannot promise from current state' })
  end
end

#refresh_all_room_plansObject



405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
# File 'app/controllers/opportunities_controller.rb', line 405

def refresh_all_room_plans
  @opportunity = Opportunity.find(params[:id])
  room_configuration_ids = @opportunity.room_configurations.select { |rc| rc.has_plans? }.map { |rc| rc.id }
  if room_configuration_ids.any?
    job_id = GenerateMultipleRoomPlansWorker.perform_async({ 'on_finish_redirect_to' => "/opportunities/#{@opportunity.id}", 'room_configuration_ids' => room_configuration_ids })
    if job_id
      redirect_to job_path(job_id)
    else
      flash[:error] = 'Job could not be queued or did not provide status, perhaps a duplicate'
      redirect_to_return_path_or_default opportunity_path(@opportunity)
    end
  else
    flash[:warning] = 'No rooms have plans to refresh'
    redirect_to_return_path_or_default opportunity_path(@opportunity)
  end
end

#reopenObject



370
371
372
373
374
375
376
377
378
379
# File 'app/controllers/opportunities_controller.rb', line 370

def reopen
  @opportunity.update(lost_reason_code: nil, purchase_outlet: nil, purchased_competitor: nil, purchased_system: nil)
  @opportunity.reopen!
  if @opportunity.open_opportunity?
    flash[:info] = 'Opportunity was reopen'
  else
    flash[:error] = 'Opportunity could not be re-opened, contact your system admin'
  end
  redirect_to opportunity_path(@opportunity)
end

#restoreObject



220
221
222
223
# File 'app/controllers/opportunities_controller.rb', line 220

def restore
  @opportunity.reopen
  redirect_to_return_path_or_default opportunity_path(@opportunity)
end

#roomsObject



426
427
428
# File 'app/controllers/opportunities_controller.rb', line 426

def rooms
  redirect_to opportunity_path(@opportunity, tab: "rooms")
end

#showObject



24
# File 'app/controllers/opportunities_controller.rb', line 24

def show; end

#tab_contactsObject



439
440
441
442
# File 'app/controllers/opportunities_controller.rb', line 439

def tab_contacts
  authorize!(:read, @opportunity)
  render layout: should_render_layout?
end

#tab_digital_assetsObject



444
445
446
447
# File 'app/controllers/opportunities_controller.rb', line 444

def tab_digital_assets
  authorize!(:read, @opportunity)
  render layout: should_render_layout?
end

#tab_mainObject



434
435
436
437
# File 'app/controllers/opportunities_controller.rb', line 434

def tab_main
  authorize!(:read, @opportunity)
  render layout: should_render_layout?
end

#unattached_ordersObject



194
195
196
# File 'app/controllers/opportunities_controller.rb', line 194

def unattached_orders
  @unattached_orders = @opportunity.unattached_orders(page: params[:page].presence, per: params[:per].presence)
end

#updateObject

PUT /customers/1/opportunities/1



111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'app/controllers/opportunities_controller.rb', line 111

def update
  authorize! :update, @opportunity
  if @opportunity.update(params[:opportunity])
    handle_next_action
  else
    set_default_electricity_rate
    render :edit, status: :unprocessable_entity
  end
rescue ActiveRecord::RangeError => e
  @opportunity.errors.add(:base, "A numeric value is out of range. Please check your inputs and try again.")
  set_default_electricity_rate
  render :edit, status: :unprocessable_entity
end

#winObject



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'app/controllers/opportunities_controller.rb', line 177

def win
  # If there are no orders linked to the opportunity this is a big no no
  if @opportunity.orders.active.empty?
    if @opportunity.unattached_orders.present?
      # maybe they need to be linked
      flash[:warning] = 'Before you can mark this opportunity won you need to have one order linked.'
      redirect_to unattached_orders_opportunity_path(@opportunity)
    elsif flash[:error] = 'No orders are linked to this opportunity and none are found in the customer, this opportunity cannot be marked as won'
      redirect_to opportunity_path(@opportunity)
    end
  else
    @opportunity.win
    flash[:info] = 'Opportunity marked as won'
    redirect_to opportunity_path(@opportunity)
  end
end