Class: Crm::PaymentsController

Inherits:
CrmController show all
Includes:
StripeCustomerManagement
Defined in:
app/controllers/crm/payments_controller.rb

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

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

#approveObject



122
123
124
125
126
127
128
129
130
131
# File 'app/controllers/crm/payments_controller.rb', line 122

def approve
  @payment = Payment.find(params[:id])
  @payment.update(payment_approved: true)
  @order = @payment.order
  if @order and @order.pending_release_authorization?
    # @order.release_order  #For now we don't release automatically. We let accounting decide
  end
  flash[:info] = 'Payment has been approved.'
  redirect_to_return_path_or_default(order_url(@order))
end

#approve_fraud_reportObject



133
134
135
136
137
138
139
140
# File 'app/controllers/crm/payments_controller.rb', line 133

def approve_fraud_report
  @payment = Payment.find(params[:id])
  @payment.update(payment_approved: true)
  @order = @payment.order
  @order.release_order if @order && @order.pending_release_authorization?
  flash[:info] = 'Fraud report has been approved.'
  redirect_to_return_path_or_default(order_url(@order))
end

#capture_fundsObject



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
# File 'app/controllers/crm/payments_controller.rb', line 406

def capture_funds
  @payment = Payment.find(params[:id])
  @order = @payment.order

  if request.get?
    @max_capturable = @payment.amount - @payment.total_captured
    @capture_amount = @max_capturable
    render :capture_funds
  else
    max_capturable = @payment.amount - @payment.total_captured

    if @payment.supports_multicapture?
      begin
        capture_amount = BigDecimal(params[:capture_amount].to_s)
      rescue ArgumentError
        flash[:error] = "Invalid amount format"
        redirect_to capture_funds_payment_path(@payment) and return
      end

      if capture_amount <= 0
        flash[:error] = 'Capture amount must be greater than zero.'
        redirect_to capture_funds_payment_path(@payment)
        return
      end

      if capture_amount > max_capturable
        flash[:error] = "Capture amount cannot exceed the remaining authorized amount (#{helpers.number_to_currency(max_capturable, unit: @order.currency_symbol)})."
        redirect_to capture_funds_payment_path(@payment)
        return
      end
    else
      capture_amount = max_capturable
    end

    is_partial = @payment.supports_multicapture? && capture_amount < max_capturable
    res = @payment.gateway_class.new(@payment).capture(capture_amount, final_capture: !is_partial)
    if res.success
      flash[:info] = "#{helpers.number_to_currency(capture_amount, unit: @order.currency_symbol)} captured successfully."
    else
      flash[:error] = res.message.presence || "Couldn't capture this payment."
    end
    redirect_to order_path(@order, tab: 'payments')
  end
end

#check_invoice_statusObject



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'app/controllers/crm/payments_controller.rb', line 142

def check_invoice_status
  if @order.pending_release_authorization?
    @payment = @order.payments.find(params[:id])
    paid = @payment.check_paypal_invoice_payment_status
    if paid
      flash[:info] = 'Invoice has been paid, releasing order'
    else
      flash[:error] = 'Invoice has not yet been paid'
    end
    #   @order.reload
    #   if @order.payments.all_authorized.any? {|pp| pp.category == Payment::PAYPAL_INVOICE and !pp.captured?}
    #     flash[:info] = "Order has another PayPal Invoice which needs to be paid before order can be released."
    #   else
    #     @order.release_order_from_pending_release_authorization
    #     flash[:info] = "Invoice has been paid, releasing order"
    #   end
    # else
    #   flash[:error] = "Invoice has not yet been paid"
    # end
  else
    flash[:info] = 'Order has already been released'
  end
  redirect_to order_url(@order)
end

#check_stripe_statusObject

On-demand sync: Heatwave authorized CC payments against Stripe (e.g. captured in Dashboard only).



246
247
248
249
250
251
252
253
254
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
# File 'app/controllers/crm/payments_controller.rb', line 246

def check_stripe_status
  @payment = Payment.find(params[:id])
  authorize! :read, @payment

  unless @payment.authorization_type == 'credit_card'
    flash[:error] = 'Checking Stripe status applies to credit card payments only.'
    redirect_to transactions_payment_path(@payment) and return
  end

  unless @payment.authorized?
    flash[:info] = "Payment is #{@payment.state}; Stripe sync only runs for authorized card payments."
    redirect_to transactions_payment_path(@payment) and return
  end

  if @payment.authorization_code.blank? && @payment.stripe_payment_intent_id.to_s.start_with?('pi_')
    @payment.update_columns(authorization_code: @payment.stripe_payment_intent_id)
  end

  if @payment.authorization_code.blank?
    flash[:error] = 'No Stripe PaymentIntent ID is linked to this payment.'
    redirect_to transactions_payment_path(@payment) and return
  end

  previous_state = @payment.state
  @payment.check_cc_payment_status
  @payment.reload

  if @payment.state != previous_state
    flash[:info] = "Updated from #{previous_state} to #{@payment.state} based on Stripe."
  else
    flash[:info] = "Stripe check complete; payment remains #{@payment.human_state_name.downcase}."
  end
  redirect_to transactions_payment_path(@payment)
rescue StandardError => e
  ErrorReporting.error(e)
  flash[:error] = "Could not check Stripe: #{e.message}"
  redirect_to transactions_payment_path(@payment)
end

#confirm_voidObject



96
97
98
99
100
101
102
103
104
105
106
# File 'app/controllers/crm/payments_controller.rb', line 96

def confirm_void
  result = @payment.gateway_class.new(@payment).void
  if result.success
    flash[:info] = 'Payment has been successfully voided.'
    redirect_to order_path(@order, tab: 'payments')
  else
    flash.now[:error] = void_failure_message(result)
    load_void_confirmation_data
    render :void_confirmation, status: :unprocessable_entity
  end
end

#confirm_void_sharedObject



108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'app/controllers/crm/payments_controller.rb', line 108

def confirm_void_shared
  siblings = @payment.shared_pi_siblings
  result = @payment.gateway_class.new(@payment).void
  if result.success
    siblings.each { |sib| sib.payment_voided! }
    flash[:info] = "Voided #{siblings.count + 1} payments sharing the same authorization."
    redirect_to order_url(@order)
  else
    flash.now[:error] = void_failure_message(result)
    load_void_confirmation_data
    render :void_confirmation, status: :unprocessable_entity
  end
end

#createObject



31
32
33
34
35
36
37
38
39
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
# File 'app/controllers/crm/payments_controller.rb', line 31

def create
  if ppaa = params.dig(:payment)
    ppaa['remote_ip_address'] = NetworkConstants::HEATWAVE_PUBLIC_IP
    ppaa['skip_minfraud'] = true
    if ppaa['category'] == 'PayPal Invoice' && ppaa['amount'].present?
      begin
        ppaa['amount'] = [BigDecimal(ppaa['amount'].to_s), @order.balance].min
      rescue ArgumentError
        flash[:error] = "Invalid amount format"
        redirect_to order_url(@order) and return
      end
    end
  end
  @payment = @order.payments.build(params[:payment])
  @upload = Upload.new
  # Check if the PO was already used on this customer's orders
  if @payment.po_number.present? && (order_numbers = @order.customer.orders.active.joins(:payments).where.not(Payment[:state].eq('voided')).where(Payment[:po_number].matches(@payment.po_number)).pluck(:reference_number)) && order_numbers.present?
    flash[:warning] = "PO ##{@payment.po_number} was already used on order(s) #{order_numbers.join(', ')}"
  end
  if params.dig(:purchase_order_upload, :attachment).present?
    # The PO upload is an optional attachment — we don't want a wrong mime
    # type (e.g. user uploaded a JPG by mistake) to 500 the whole payment
    # flow. Surface the validation error as a flash and continue processing
    # the payment. (AppSignal #4726.)
    po_upload = @order.uploads.build(params[:purchase_order_upload])
    unless po_upload.save
      upload_warning = "Purchase order attachment was not saved: #{po_upload.errors.full_messages.to_sentence}"
      flash[:warning] = [flash[:warning].presence, upload_warning].compact.join(' ')
    end
  end

  res = Payment::OrderProcessor.new(@order, params[:payment]).process
  if res.result == 'invalid' || res.result == 'failed'
    flash.now[:error] = res.error
    flash.now[:notice] = res.notice
    # @payment = res.payment || @order.payments.build(params[:payment])
    @report_errors_for = [@payment]
    @payment_options = @order.payment_options('crm')
    set_incrementable_authorizations
    @payment_preference = @customer&.preferred_payment_method
    render :new, status: :unprocessable_entity
  elsif res.result == 'partially_authorized'
    redirect_to new_order_payment_path(@order), info: res.notice, error: res.error
  elsif res.result == 'fully_authorized'
    redirect_to order_path(@order), info: res.notice, error: res.error
  end
end

#create_payment_intentObject



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
# File 'app/controllers/crm/payments_controller.rb', line 451

def create_payment_intent
  currency = @order.currency
  max_cents = (@order.balance * 100).to_i
  requested_cents = params[:amount_cents].present? ? params[:amount_cents].to_i : max_cents
  amount_cents = [requested_cents, max_cents].min
  amount_cents = [amount_cents, 50].max # Stripe minimum is 50 cents

  ensure_stripe_customer_id!(@customer, currency) if @customer.present?

  description = @order.reference_number.present? ? "Order #{@order.reference_number}" : "Order ID #{@order.id}"
  statement_descriptor = @order.reference_number.present? ? "WarmlyYours #{@order.reference_number}".truncate(22) : nil

  pi_params = {
    amount_cents: amount_cents,
    currency: currency,
    capture_method: 'manual',
    payment_method_types: ['card'],
    description: description,
    statement_descriptor: statement_descriptor,
    metadata: {
      order_id: @order.id,
      customer_id: @customer&.id
    }
  }
  pi_params[:customer_id] = @customer.stripe_customer_id if @customer&.stripe_customer_id.present?
  pi_params[:setup_future_usage] = 'off_session' if pi_params[:customer_id].present?

  pi = Payment::Apis::Stripe.create_payment_intent(**pi_params)
  render json: { client_secret: pi.client_secret, payment_intent_id: pi.id }
rescue ::Stripe::StripeError => e
  render json: { error: e.message }, status: :unprocessable_entity
end

#create_paypal_from_vaultObject



332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
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
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
# File 'app/controllers/crm/payments_controller.rb', line 332

def create_paypal_from_vault
  customer = @order.customer
  unless customer&.paypal_vault_token_id.present?
    flash[:error] = 'Customer does not have a saved PayPal wallet.'
    return redirect_to new_order_payment_path(@order)
  end

  @order.reload
  unless @order.balance.positive?
    flash[:error] = 'Order has no outstanding balance.'
    return redirect_to order_path(@order)
  end

  deliveries_to_pay = @order.deliveries.select { |d| d.balance.positive? }
  if deliveries_to_pay.empty?
    flash[:error] = 'No deliveries with outstanding balance.'
    return redirect_to order_path(@order, tab: 'payments')
  end

  amount_remaining = @order.balance
  total_authorized = BigDecimal("0")
  payments_created = []

  deliveries_to_pay.each do |delivery|
    break unless amount_remaining.positive?

    amount = [delivery.balance, amount_remaining].min
    next unless amount.positive?

    payment = @order.payments.create!(
      currency: @order.currency,
      category: Payment::PAYPAL,
      authorization_type: 'paypal',
      amount: amount,
      email: customer.email,
      customer: customer,
      delivery: delivery,
      paypal_metadata: {
        'vault_authorized' => true,
        'vault_token_id' => customer.paypal_vault_token_id
      }
    )

    result = Payment::Gateways::Paypal.new(payment).authorize_from_vault(customer.paypal_vault_token_id)
    payments_created << { payment: payment, success: result.success, message: result.message, amount: amount }

    if result.success
      total_authorized += amount
      amount_remaining -= amount
    end
  end

  if payments_created.empty?
    flash[:error] = 'No payments could be created. Check delivery balances.'
    return redirect_to order_path(@order, tab: 'payments')
  end

  successes = payments_created.count { |p| p[:success] }
  failures = payments_created.count { |p| !p[:success] }

  if failures.zero? && successes.positive?
    flash[:info] = "PayPal vault authorization successful for #{helpers.number_to_currency(total_authorized, unit: @order.currency_symbol)}."
    @order.reload
    @order.payment_complete if @order.balance <= 0
    redirect_to order_path(@order, tab: 'payments')
  elsif successes.positive?
    flash[:warning] = "#{successes} payment(s) authorized (#{helpers.number_to_currency(total_authorized, unit: @order.currency_symbol)}), #{failures} failed. Check payment details."
    redirect_to order_path(@order, tab: 'payments')
  else
    flash[:error] = "PayPal vault authorization failed: #{payments_created.first&.dig(:message)}"
    redirect_to new_order_payment_path(@order)
  end
end

#editObject



27
28
29
# File 'app/controllers/crm/payments_controller.rb', line 27

def edit
  @payment = @order.payments.find(params[:id])
end

#fraud_reportObject



216
217
218
219
# File 'app/controllers/crm/payments_controller.rb', line 216

def fraud_report
  @payment = Payment.find(params[:id])
  @fraud_report = @payment.fraud_report
end

#increment_authorizationObject



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
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
# File 'app/controllers/crm/payments_controller.rb', line 285

def increment_authorization
  @payment = @order.payments.find(params[:id])
  begin
    new_amount = BigDecimal(params[:amount])
  rescue ArgumentError
    flash[:error] = "Invalid amount format"
    redirect_to order_url(@order) and return
  end

  unless @payment.supports_incremental_authorization?
    flash[:error] = 'This payment does not support incremental authorization.'
    return redirect_to new_order_payment_path(@order)
  end

  unless @payment.authorized?
    flash[:error] = 'Payment must be in authorized state to increment.'
    return redirect_to new_order_payment_path(@order)
  end

  if @payment.total_captured.positive?
    flash[:error] = 'Cannot increment authorization after funds have been captured. Create a new payment instead.'
    return redirect_to new_order_payment_path(@order)
  end

  if @payment.transactions.where(action: 'incremental_authorization').count >= 10
    flash[:error] = 'Maximum of 10 incremental authorization attempts reached. Please create a new payment.'
    return redirect_to new_order_payment_path(@order)
  end

  res = Payment::Gateways::CreditCard.new(@payment).increment_authorization(new_amount)
  if res.success
    flash[:info] = "Authorization incremented to #{number_to_currency(new_amount)}."
    @order.reload
    if @order.balance <= 0 && @order.payment_complete
      redirect_to order_path(@order)
    elsif @order.balance <= 0
      flash[:warning] = "Balance is covered but order could not advance: #{@order.errors_to_s}"
      redirect_to order_path(@order)
    else
      redirect_to new_order_payment_path(@order)
    end
  else
    flash[:error] = "Failed to increment authorization: #{res.message}"
    redirect_to new_order_payment_path(@order)
  end
end

#newObject



12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'app/controllers/crm/payments_controller.rb', line 12

def new
  if @order.valid?
    @payment_options = @order.payment_options('crm')
    @payment = @order.payments.build(category: @payment_options.first, amount: @order.balance, po_number: (@order.rma.present? ? @order.rma.original_po_number : nil))
    @upload = Upload.new

    set_incrementable_authorizations
    CreditCardVault.sync_stripe_status!(@customer)
    @payment_preference = @customer&.preferred_payment_method
  else
    flash[:error] = "Unable to take payment as there are problems with the order. Errors: #{@order.errors_to_s}."
    redirect_to @order
  end
end

#reauthorize_paypalObject



234
235
236
237
238
239
240
241
242
243
# File 'app/controllers/crm/payments_controller.rb', line 234

def reauthorize_paypal
  @payment = Payment.find(params[:id])
  result = @payment.check_paypal_payment_status
  if result.ok?
    flash[:info] = result.message
  else
    flash[:error] = result.message
  end
  redirect_to_return_path_or_default order_path(@payment.order)
end

#resend_paypal_invoiceObject



167
168
169
170
171
172
173
174
175
176
# File 'app/controllers/crm/payments_controller.rb', line 167

def resend_paypal_invoice
  @payment = @order.payments.find(params[:id])
  res = @payment.resend_paypal_invoice
  if res[:success]
    flash[:info] = 'Invoice successfully resent'
  else
    flash[:error] = "Unable to resend invoice, error message: #{res[:message]}"
  end
  redirect_to order_path(@order)
end

#send_receiptObject



178
179
180
181
182
# File 'app/controllers/crm/payments_controller.rb', line 178

def send_receipt
  @payment = @order.payments.find(params[:id])
  cb = CommunicationBuilder.new(resource: @payment, current_user: current_user)
  redirect_to new_communication_path(cb.to_params)
end

#showObject



7
8
9
10
# File 'app/controllers/crm/payments_controller.rb', line 7

def show
  @payment = Payment.find(params[:id])
  redirect_to transactions_payment_path(@payment)
end

#skip_auto_receiptObject



204
205
206
207
208
209
210
211
212
213
214
# File 'app/controllers/crm/payments_controller.rb', line 204

def skip_auto_receipt
  @payment = Payment.find(params[:id])
  skip = params[:skip]
  if @payment.update(skip_auto_receipt: skip)
    flash[:info] = "Skipping auto receipt set to #{skip}"
    redirect_to_return_path_or_default transactions_payment_path(@payment)
  else
    flash[:error] = "An error occurred. Couldn't set the skip auto receipt vaariable for this payment."
    redirect_to_return_path_or_default transactions_payment_path(@payment)
  end
end

#skip_paymentObject



79
80
81
82
83
84
85
86
87
88
89
# File 'app/controllers/crm/payments_controller.rb', line 79

def skip_payment
  set_variables
  if @order.balance < 0
    flash[:error] = 'Order has negative balance, please correct. '
  elsif @order.balance > 0
    flash[:error] = 'Order has a positive balance, please process payment normally.'
  elsif @order.balance == 0
    flash[:error] = "Order cannot be released to the warehouse. #{@order.errors_to_s} #{@order.shipping_address.errors_to_s}" unless @order.payment_complete
  end
  redirect_to order_url(@order)
end

#transactionsObject



200
201
202
# File 'app/controllers/crm/payments_controller.rb', line 200

def transactions
  @payment = Payment.find(params[:id])
end

#unhide_vaultObject



221
222
223
224
225
226
227
228
229
230
231
232
# File 'app/controllers/crm/payments_controller.rb', line 221

def unhide_vault
  @payment = Payment.find(params[:id])
  authorize! :unhide_vault, @payment
  if @payment.credit_card_vault.nil?
    flash[:error] = 'No vault found'
  else
    new_hidden = !@payment.credit_card_vault.hidden?
    @payment.credit_card_vault.update(hidden: new_hidden)
    flash[:info] = new_hidden ? 'Vault has been hidden' : 'Vault has been unhidden'
  end
  redirect_to_return_path_or_default transactions_payment_path(@payment)
end

#updateObject



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'app/controllers/crm/payments_controller.rb', line 184

def update
  @payment = @order.payments.find(params[:id])
  if @payment.update(params[:payment])
    m = 'Payment information has been updated'
    if params.dig(:purchase_order_upload, :attachment).present?
      u = @order.uploads.build(params[:purchase_order_upload])
      m + ". Unable to save purchase order pdf. #{u.errors_to_s}" unless u.save
    end

    flash[:info] = 'Payment information has been updated'
    redirect_to @order
  else
    render action: :edit, status: :unprocessable_entity
  end
end

#voidObject



91
92
93
94
# File 'app/controllers/crm/payments_controller.rb', line 91

def void
  load_void_confirmation_data
  render :void_confirmation
end