Module: Spree::PaypalPlatform::Gateway::PaymentSessions

Extended by:
ActiveSupport::Concern
Included in:
Spree::PaypalPlatform::Gateway
Defined in:
app/models/spree/paypal_platform/gateway/payment_sessions.rb

Overview

Payment-session lifecycle used by Spree 5 storefronts.

Instance Method Summary collapse

Instance Method Details

#complete_payment_session(payment_session:, **_unused) ⇒ void

This method returns an undefined value.

Captures the PayPal order and creates the Spree payment.

Does not complete the order — that is handled by Carts::Complete.

Parameters:

  • payment_session (Spree::PaymentSessions::PaypalPlatform)
  • params (Hash)


90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'app/models/spree/paypal_platform/gateway/payment_sessions.rb', line 90

def complete_payment_session(payment_session:, **_unused)
  paypal_order_id = payment_session.external_id

  response = client.orders.capture_order({
                                           'id' => paypal_order_id,
                                           'prefer' => 'return=representation'
                                         })

  payment_session.update!(external_data: response.data.as_json)

  payment_session.order.with_lock do
    if response.data.status == 'COMPLETED'
      payment_session.process if payment_session.can_process?

      payment = payment_session.find_or_create_payment!

      if payment.present? && !payment.completed?
        payment.started_processing! if payment.checkout?
        payment.complete! if payment.can_complete?
      end

      create_profile(payment) if payment&.source.present?

      payment_session.complete unless payment_session.completed?
    elsif payment_session.can_fail?
      payment_session.fail
    end
  end
rescue PaypalServerSdk::APIException => e
  payment_session.fail if payment_session.can_fail?
  raise Spree::Core::GatewayError, "PayPal API error: #{e.message}"
end

#create_payment_session(order:, amount: nil, **_unused) ⇒ Spree::PaymentSessions::PaypalPlatform, NilClass

Creates a PayPal order and persists a payment session.

Also requests a Card Fields client token. Failure is non-fatal — the wallet / Apple Pay buttons still work without it.

Parameters:

  • order (Spree::Order)
  • amount (Numeric, NilClass) (defaults to: nil)
  • external_data (Hash)

Returns:

  • (Spree::PaymentSessions::PaypalPlatform, NilClass)


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
# File 'app/models/spree/paypal_platform/gateway/payment_sessions.rb', line 39

def create_payment_session(order:, amount: nil, **_unused)
  total = amount.presence || order.total_minus_store_credits

  return nil if total.zero?

  protect_from_error do
    order_presenter = OrderPresenter.new(order)
    paypal_response = client.orders.create_order(order_presenter.to_json)

    session_data = paypal_response.data.as_json

    client_token = generate_client_token
    session_data['client_token'] = client_token if client_token.present?

    payment_session_class.create!(
      order: order,
      payment_method: self,
      amount: total,
      currency: order.currency,
      status: 'pending',
      external_id: paypal_response.data.id,
      customer: order.user,
      external_data: session_data
    )
  end
end

#parse_webhook_event(raw_body, headers) ⇒ Hash, NilClass

Parses an incoming PayPal webhook into a payment-session action.

Parameters:

  • raw_body (String)
  • headers (Hash)

Returns:

  • (Hash, NilClass)


130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'app/models/spree/paypal_platform/gateway/payment_sessions.rb', line 130

def parse_webhook_event(raw_body, headers)
  verify_webhook_signature!(raw_body, headers)

  event = JSON.parse(raw_body).with_indifferent_access
  event_type = event[:event_type]
  resource = event[:resource] || {}

  paypal_order_id = extract_order_id_from_webhook(event_type, resource)
  return nil unless paypal_order_id

  payment_session = Spree::PaymentSessions::PaypalPlatform.find_by(
    payment_method: self,
    external_id: paypal_order_id
  )
  return nil unless payment_session

  case event_type
  when 'CHECKOUT.ORDER.APPROVED'
    { action: :authorized, payment_session: payment_session, metadata: { paypal_event: event } }
  when 'PAYMENT.CAPTURE.COMPLETED'
    { action: :captured, payment_session: payment_session, metadata: { paypal_event: event } }
  when 'PAYMENT.CAPTURE.DENIED', 'PAYMENT.CAPTURE.DECLINED'
    { action: :failed, payment_session: payment_session, metadata: { paypal_event: event } }
  when 'PAYMENT.CAPTURE.REVERSED', 'PAYMENT.CAPTURE.REFUNDED'
    { action: :canceled, payment_session: payment_session, metadata: { paypal_event: event } }
  end
end

#payment_session_classClass

Returns:

  • (Class)


24
25
26
# File 'app/models/spree/paypal_platform/gateway/payment_sessions.rb', line 24

def payment_session_class
  Spree::PaymentSessions::PaypalPlatform
end

#session_required?TrueClass, FalseClass

Returns:

  • (TrueClass, FalseClass)


17
18
19
# File 'app/models/spree/paypal_platform/gateway/payment_sessions.rb', line 17

def session_required?
  true
end

#update_payment_session(payment_session:, amount: nil, external_data: {}) ⇒ TrueClass, ...

Parameters:

  • payment_session (Spree::PaymentSessions::PaypalPlatform)
  • amount (Numeric, NilClass) (defaults to: nil)
  • external_data (Hash) (defaults to: {})

Returns:

  • (TrueClass, FalseClass, NilClass)


72
73
74
75
76
77
78
79
# File 'app/models/spree/paypal_platform/gateway/payment_sessions.rb', line 72

def update_payment_session(payment_session:, amount: nil, external_data: {})
  attrs = {}
  attrs[:amount] = amount if amount.present?

  attrs[:external_data] = (payment_session.external_data || {}).merge(external_data.stringify_keys) if external_data.present?

  payment_session.update!(attrs) if attrs.any?
end