mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-08 22:56:06 +00:00
120 lines
3.7 KiB
Ruby
120 lines
3.7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'paypal-sdk-merchant'
|
|
|
|
module Spree
|
|
class Gateway
|
|
class PayPalExpress < Gateway
|
|
preference :login, :string
|
|
preference :password, :password
|
|
preference :signature, :string
|
|
preference :server, :string, default: 'sandbox'
|
|
preference :solution, :string, default: 'Mark'
|
|
preference :landing_page, :string, default: 'Billing'
|
|
preference :logourl, :string, default: ''
|
|
|
|
def external_gateway?
|
|
true
|
|
end
|
|
|
|
def external_payment_url(_options)
|
|
Rails.application.routes.url_helpers.
|
|
payment_gateways_paypal_express_path(payment_method_id: id)
|
|
end
|
|
|
|
def supports?(_source)
|
|
true
|
|
end
|
|
|
|
def provider_class
|
|
::PayPal::SDK::Merchant::API
|
|
end
|
|
|
|
def provider
|
|
::PayPal::SDK.configure(
|
|
mode: preferred_server.presence || "sandbox",
|
|
username: preferred_login,
|
|
password: preferred_password,
|
|
signature: preferred_signature
|
|
)
|
|
provider_class.new
|
|
end
|
|
|
|
def method_type
|
|
'paypal'
|
|
end
|
|
|
|
def purchase(_amount, express_checkout, _gateway_options = {})
|
|
pp_details_request = provider.build_get_express_checkout_details(
|
|
Token: express_checkout.token
|
|
)
|
|
pp_details_response = provider.get_express_checkout_details(pp_details_request)
|
|
|
|
pp_request = provider.build_do_express_checkout_payment(
|
|
DoExpressCheckoutPaymentRequestDetails: {
|
|
PaymentAction: "Sale",
|
|
Token: express_checkout.token,
|
|
PayerID: express_checkout.payer_id,
|
|
PaymentDetails: pp_details_response.
|
|
get_express_checkout_details_response_details.PaymentDetails
|
|
}
|
|
)
|
|
|
|
pp_response = provider.do_express_checkout_payment(pp_request)
|
|
if pp_response.success?
|
|
# We need to store the transaction id for the future.
|
|
# This is mainly so we can use it later on to refund the payment if the user wishes.
|
|
transaction_id = pp_response.do_express_checkout_payment_response_details.
|
|
payment_info.first.transaction_id
|
|
express_checkout.update_column(:transaction_id, transaction_id)
|
|
# This is rather hackish, required for payment/processing handle_response code.
|
|
Class.new do
|
|
def success?; true; end
|
|
|
|
def authorization; nil; end
|
|
end.new
|
|
else
|
|
class << pp_response
|
|
def to_s
|
|
errors.map(&:long_message).join(" ")
|
|
end
|
|
end
|
|
pp_response
|
|
end
|
|
end
|
|
|
|
def refund(payment, amount)
|
|
refund_type = payment.amount == amount.to_d ? "Full" : "Partial"
|
|
refund_transaction = provider.build_refund_transaction(
|
|
TransactionID: payment.source.transaction_id,
|
|
RefundType: refund_type,
|
|
Amount: {
|
|
currencyID: payment.currency,
|
|
value: amount
|
|
},
|
|
RefundSource: "any"
|
|
)
|
|
refund_transaction_response = provider.refund_transaction(refund_transaction)
|
|
if refund_transaction_response.success?
|
|
payment.source.update(
|
|
refunded_at: Time.zone.now,
|
|
refund_transaction_id: refund_transaction_response.RefundTransactionID,
|
|
state: "refunded",
|
|
refund_type:
|
|
)
|
|
|
|
payment.class.create!(
|
|
order: payment.order,
|
|
source: payment,
|
|
payment_method: payment.payment_method,
|
|
amount: amount.to_f.abs * -1,
|
|
response_code: refund_transaction_response.RefundTransactionID,
|
|
state: 'completed'
|
|
)
|
|
end
|
|
refund_transaction_response
|
|
end
|
|
end
|
|
end
|
|
end
|