workarea-paypal 2.0.12 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.eslintrc.json +2 -1
- data/.gitignore +16 -11
- data/CHANGELOG.md +29 -5
- data/README.md +100 -6
- data/Rakefile +4 -5
- data/app/assets/javascripts/workarea/storefront/paypal/config.js.erb +44 -0
- data/app/assets/javascripts/workarea/storefront/paypal/modules/paypal_buttons.js +71 -0
- data/app/assets/javascripts/workarea/storefront/paypal/modules/paypal_hosted_fields.js +96 -0
- data/app/assets/javascripts/workarea/storefront/paypal/modules/update_checkout_submit_text.js +11 -5
- data/app/assets/javascripts/workarea/storefront/paypal/templates/paypal_fields.jst.ejs +43 -0
- data/app/controllers/workarea/storefront/checkout/place_order_controller.decorator +6 -4
- data/app/controllers/workarea/storefront/paypal_controller.rb +32 -26
- data/app/helpers/workarea/storefront/paypal_helper.rb +38 -0
- data/app/models/workarea/payment/authorize/paypal.rb +13 -13
- data/app/models/workarea/payment/capture/paypal.rb +10 -20
- data/app/models/workarea/payment/null_address.rb +37 -0
- data/app/models/workarea/payment/purchase/paypal.rb +1 -25
- data/app/models/workarea/payment/refund/paypal.rb +3 -6
- data/app/models/workarea/payment/tender/paypal.rb +14 -2
- data/app/models/workarea/payment.decorator +17 -3
- data/app/services/workarea/paypal/approve_order.rb +104 -0
- data/app/services/workarea/paypal/create_order.rb +177 -0
- data/app/services/workarea/paypal/update_order.rb +44 -0
- data/app/views/workarea/admin/orders/tenders/_paypal.html.haml +5 -2
- data/app/views/workarea/api/orders/tenders/_paypal.json.jbuilder +7 -1
- data/app/views/workarea/storefront/carts/_paypal_checkout.html.haml +6 -1
- data/app/views/workarea/storefront/checkouts/_paypal_payment.html.haml +16 -5
- data/app/views/workarea/storefront/order_mailer/tenders/_paypal.html.haml +5 -3
- data/app/views/workarea/storefront/orders/tenders/_paypal.html.haml +9 -2
- data/app/views/workarea/storefront/paypal/_paypal_sdk.html.haml +1 -0
- data/app/workers/workarea/paypal/handle_webhook_event.rb +64 -0
- data/config/initializers/append_points.rb +17 -5
- data/config/initializers/fields.rb +27 -0
- data/config/initializers/workarea.rb +41 -5
- data/config/locales/en.yml +14 -4
- data/config/routes.rb +3 -2
- data/lib/tasks/workarea/create_webhooks.rake +28 -0
- data/lib/workarea/paypal/engine.rb +4 -0
- data/lib/workarea/paypal/gateway.rb +200 -0
- data/lib/workarea/paypal/requests/create_webhook.rb +21 -0
- data/lib/workarea/paypal/requests/delete_webhook.rb +17 -0
- data/lib/workarea/paypal/requests/generate_token.rb +21 -0
- data/lib/workarea/paypal/requests/list_webhooks.rb +17 -0
- data/lib/workarea/paypal/version.rb +1 -1
- data/lib/workarea/paypal.rb +22 -19
- data/package.json +9 -0
- data/test/dummy/config/initializers/workarea.rb +1 -1
- data/test/factories/workarea/capture_completed_webhook.json +70 -0
- data/test/factories/workarea/capture_denied_webhook.json +68 -0
- data/test/factories/workarea/paypal.rb +34 -0
- data/test/helpers/workarea/storefront/paypal_helper_test.rb +35 -0
- data/test/integration/workarea/storefront/papyal_place_order_integration_test.rb +42 -0
- data/test/integration/workarea/storefront/paypal_integration_test.rb +104 -294
- data/test/lib/workarea/paypal/gateway_test.rb +236 -0
- data/test/models/workarea/payment/authorize/paypal_test.rb +57 -46
- data/test/models/workarea/payment/capture/paypal_test.rb +9 -51
- data/test/models/workarea/payment/null_address_test.rb +53 -0
- data/test/models/workarea/payment/refund/paypal_test.rb +39 -38
- data/test/models/workarea/paypal_payment_test.rb +65 -0
- data/test/models/workarea/search/paypal_order_text_test.rb +14 -0
- data/test/services/workarea/paypal/approve_order_test.rb +35 -0
- data/test/services/workarea/paypal/create_order_test.rb +127 -0
- data/test/services/workarea/paypal/update_order_test.rb +73 -0
- data/test/support/workarea/paypal_setup.rb +49 -0
- data/test/system/workarea/storefront/cart_system_test.decorator +1 -1
- data/test/system/workarea/storefront/logged_in_checkout_system_test.decorator +1 -1
- data/test/vcr_cassettes/paypal_approve_order.yml +106 -0
- data/test/vcr_cassettes/paypal_create_order.yml +110 -0
- data/test/vcr_cassettes/paypal_gateway_create_order.yml +105 -0
- data/test/vcr_cassettes/paypal_gateway_generate_token.yml +103 -0
- data/test/vcr_cassettes/paypal_gateway_get_order.yml +103 -0
- data/test/vcr_cassettes/paypal_gateway_update_order.yml +199 -0
- data/test/vcr_cassettes/paypal_gateway_webhooks.yml +403 -0
- data/test/vcr_cassettes/paypal_update_order.yml +204 -0
- data/test/workers/workarea/paypal/handle_webhook_event_test.rb +60 -0
- data/workarea-paypal.gemspec +2 -1
- metadata +64 -16
- data/app/services/workarea/paypal/setup.rb +0 -114
- data/app/services/workarea/paypal/update.rb +0 -69
- data/app/views/workarea/storefront/checkouts/_paypal_error.html.haml +0 -6
- data/app/views/workarea/storefront/order_mailer/tenders/_paypal.text.haml +0 -2
- data/lib/workarea/paypal/ext/active_merchant/paypal_express_gateway.rb +0 -9
- data/test/dummy/config/initializers/session_store.rb +0 -3
- data/test/integration/workarea/storefront/place_order_integration_test.decorator +0 -11
- data/test/models/workarea/payment/purchase/paypal_test.rb +0 -94
- data/test/models/workarea/payment_test.decorator +0 -34
- data/test/models/workarea/search/admin/order_test.decorator +0 -32
- data/test/services/workarea/paypal/setup_test.rb +0 -120
- data/test/services/workarea/paypal/update_test.rb +0 -221
- data/test/workarea/paypal/ext/active_merchant/paypal_express_gateway_test.rb +0 -17
@@ -1,2 +1,9 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
- if tender.direct_payment?
|
2
|
+
= render 'workarea/storefront/orders/tenders/credit_card', tender: tender
|
3
|
+
- else
|
4
|
+
.data-card
|
5
|
+
.data-card__cell
|
6
|
+
%p.data-card__line
|
7
|
+
= t('workarea.storefront.paypal.paid_with_paypal')
|
8
|
+
%p.data-card__line
|
9
|
+
= number_to_currency(tender.amount)
|
@@ -0,0 +1 @@
|
|
1
|
+
= include_paypal_javascript_tag
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Paypal
|
3
|
+
class HandleWebhookEvent
|
4
|
+
include Sidekiq::Worker
|
5
|
+
|
6
|
+
def perform(event, resource)
|
7
|
+
event_method = event.optionize
|
8
|
+
return send(event_method, resource) if respond_to?(event_method)
|
9
|
+
|
10
|
+
logger.error("FAILED: #{event} webhook is not supported.")
|
11
|
+
end
|
12
|
+
|
13
|
+
def payment_capture_completed(resource)
|
14
|
+
transaction = Payment::Transaction.where(
|
15
|
+
'response.params.id' => resource['id']
|
16
|
+
).first
|
17
|
+
|
18
|
+
if transaction.nil?
|
19
|
+
logger.error("FAILED: Transaction with capture ID of #{resource['id']} does not exist.")
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
23
|
+
tender = transaction.payment.tenders.detect do |t|
|
24
|
+
t.id.to_s == transaction.tender_id
|
25
|
+
end
|
26
|
+
return unless tender.present?
|
27
|
+
|
28
|
+
amount = resource['amount']
|
29
|
+
txn = tender.build_transaction(
|
30
|
+
action: 'capture',
|
31
|
+
success: true,
|
32
|
+
reference: transaction,
|
33
|
+
amount: amount['value'].to_m(amount['currency_code']),
|
34
|
+
response: ActiveMerchant::Billing::Response.new(
|
35
|
+
true,
|
36
|
+
'Paypal capture was confirmed.',
|
37
|
+
resource
|
38
|
+
)
|
39
|
+
)
|
40
|
+
|
41
|
+
txn.save!
|
42
|
+
end
|
43
|
+
|
44
|
+
def payment_capture_denied(resource)
|
45
|
+
transaction = Payment::Transaction.where(
|
46
|
+
'response.params.id' => resource['id']
|
47
|
+
).first
|
48
|
+
|
49
|
+
if transaction.nil?
|
50
|
+
logger.error("FAILED: Transaction with capture ID of #{resource['id']} does not exist.")
|
51
|
+
return
|
52
|
+
end
|
53
|
+
|
54
|
+
transaction.cancellation = ActiveMerchant::Billing::Response.new(
|
55
|
+
true,
|
56
|
+
"PayPal capture was denied",
|
57
|
+
resource
|
58
|
+
)
|
59
|
+
transaction.canceled_at = Time.current
|
60
|
+
transaction.save!
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
Workarea::Plugin.append_partials(
|
2
|
-
'storefront.
|
3
|
-
'workarea/storefront/
|
2
|
+
'storefront.document_head',
|
3
|
+
'workarea/storefront/paypal/paypal_sdk'
|
4
4
|
)
|
5
5
|
|
6
6
|
Workarea::Plugin.append_partials(
|
7
|
-
'storefront.
|
8
|
-
'workarea/storefront/
|
7
|
+
'storefront.cart_show',
|
8
|
+
'workarea/storefront/carts/paypal_checkout'
|
9
9
|
)
|
10
10
|
|
11
11
|
Workarea::Plugin.append_partials(
|
@@ -13,7 +13,19 @@ Workarea::Plugin.append_partials(
|
|
13
13
|
'workarea/storefront/checkouts/paypal_payment'
|
14
14
|
)
|
15
15
|
|
16
|
+
Workarea::Plugin.append_javascripts(
|
17
|
+
'storefront.config',
|
18
|
+
'workarea/storefront/paypal/config'
|
19
|
+
)
|
20
|
+
|
21
|
+
Workarea::Plugin.append_javascripts(
|
22
|
+
'storefront.templates',
|
23
|
+
'workarea/storefront/paypal/templates/paypal_fields'
|
24
|
+
)
|
25
|
+
|
16
26
|
Workarea::Plugin.append_javascripts(
|
17
27
|
'storefront.modules',
|
18
|
-
'workarea/storefront/paypal/modules/update_checkout_submit_text'
|
28
|
+
'workarea/storefront/paypal/modules/update_checkout_submit_text',
|
29
|
+
'workarea/storefront/paypal/modules/paypal_buttons',
|
30
|
+
'workarea/storefront/paypal/modules/paypal_hosted_fields'
|
19
31
|
)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Workarea::Configuration.define_fields do
|
2
|
+
fieldset 'PayPal', namespaced: false do
|
3
|
+
# PayPal credentials can be configured via environment variables:
|
4
|
+
# WORKAREA_PAYPAL_CLIENT_ID
|
5
|
+
# WORKAREA_PAYPAL_CLIENT_SECRET
|
6
|
+
#
|
7
|
+
# via rails credentials:
|
8
|
+
# paypal:
|
9
|
+
# client_id: YOUR_CLIENT_ID
|
10
|
+
# client_secret: YOUR_CLIENT_SECRET
|
11
|
+
#
|
12
|
+
# Or through the workarea admin configuration. Setting credentials through
|
13
|
+
# the configuration allows for dyanmically changing credentials if, for
|
14
|
+
# example, you are using the multi-site plugin and wish to use different
|
15
|
+
# PayPal accounts for some or all sites.
|
16
|
+
#
|
17
|
+
field 'Client ID',
|
18
|
+
type: :string,
|
19
|
+
id: 'paypal_client_id',
|
20
|
+
description: 'Your Paypal Merchant Account Application Client ID'
|
21
|
+
field 'Client Secret',
|
22
|
+
type: :string,
|
23
|
+
id: 'paypal_client_secret',
|
24
|
+
encrypted: true,
|
25
|
+
description: 'Your Paypal Merchant Account Application Client Secret'
|
26
|
+
end
|
27
|
+
end
|
@@ -1,7 +1,43 @@
|
|
1
|
-
Workarea.config.tender_types << :paypal
|
2
1
|
|
3
|
-
|
4
|
-
|
5
|
-
ActiveMerchant::Billing::PaypalGateway.application_id = 'Workarea_SP'
|
2
|
+
Workarea.configure do |config|
|
3
|
+
config.tender_types << :paypal
|
6
4
|
|
7
|
-
|
5
|
+
# Determines which environment class to use. The PayPal SDK requires the
|
6
|
+
# use of different classes depending on the type of environment you are
|
7
|
+
# interacting with. By default, sandbox will be used unless in production.
|
8
|
+
# This behavior can be changed within your application by redefining this
|
9
|
+
# configuration.
|
10
|
+
#
|
11
|
+
config.paypal_environment =
|
12
|
+
if Rails.env.production?
|
13
|
+
'Paypal::LiveEnvironment'
|
14
|
+
else
|
15
|
+
'PayPal::SandboxEnvironment'
|
16
|
+
end
|
17
|
+
|
18
|
+
# Parameters passed as a query string to the paypal javascript sdk script
|
19
|
+
# when loaded on the storefront. This can be used to customize settings and
|
20
|
+
# display options.
|
21
|
+
# See https://developer.paypal.com/docs/checkout/reference/customize-sdk/
|
22
|
+
# for more information.
|
23
|
+
#
|
24
|
+
config.paypal_sdk_params = {
|
25
|
+
commit: false,
|
26
|
+
debug: Rails.env.development?
|
27
|
+
}
|
28
|
+
|
29
|
+
# Enable/Disable paypal as your credit card processor. This will enable
|
30
|
+
# code that takes over the credit card fields during checkout and submits
|
31
|
+
# payment info directly to paypal. You will need to enable unbranded credit
|
32
|
+
# cards through PayPal. Contact PayPal directly for more information.
|
33
|
+
#
|
34
|
+
config.use_paypal_hosted_fields = false
|
35
|
+
|
36
|
+
# Events to register a webhook for when running the rake tasks to setup
|
37
|
+
# webhooks, workarea:payal:create_webhooks.
|
38
|
+
#
|
39
|
+
config.default_webhook_events = %w(
|
40
|
+
PAYMENT.CAPTURE.COMPLETED
|
41
|
+
PAYMENT.CAPTURE.DENIED
|
42
|
+
)
|
43
|
+
end
|
data/config/locales/en.yml
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
---
|
2
1
|
en:
|
3
2
|
workarea:
|
4
3
|
admin:
|
@@ -6,13 +5,24 @@ en:
|
|
6
5
|
tenders:
|
7
6
|
paypal:
|
8
7
|
title: PayPal
|
8
|
+
payment:
|
9
|
+
paypal_capture: Paypal funding is pending capture and cannot be completed manually. Capture will be recorded after an update from PayPal.
|
10
|
+
paypal:
|
11
|
+
gateway:
|
12
|
+
http_error: "%{status} : PayPal request error, debug ID %{debug_id}"
|
13
|
+
capture_error: Select a new payment option and try again.
|
9
14
|
storefront:
|
10
15
|
paypal:
|
11
|
-
address_error: We can not ship to this address. Please enter a new address.
|
12
16
|
check_out: Check Out with PayPal
|
13
|
-
checkout_submit_text:
|
14
|
-
|
17
|
+
checkout_submit_text: Select a PayPal payment option to continue
|
18
|
+
checkout_review_text: Submit Payment and Review
|
19
|
+
errors:
|
20
|
+
order_incomplete: Your checkout is incomplete. Please review your shipping and billing information and try again.
|
21
|
+
place_order: You must complete your paypal transaction before submitting your order.
|
22
|
+
request_failed: There was a problem contacting PayPal. Please try again. If the problem persists, try a different payment method or contact customer support.
|
23
|
+
on_continue: Select a PayPal payment option.
|
15
24
|
paid_with_paypal: Paid with PayPal
|
25
|
+
payment_failed: Your submitted PayPal payment could not be completed. Select a new method and try again.
|
16
26
|
payment_recieved: Thank You! We have received your information back from PayPal.
|
17
27
|
Please confirm that the shipping address and shipping method are correct,
|
18
28
|
then click on 'Place Order'.
|
data/config/routes.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
Workarea::Storefront::Engine.routes.draw do
|
2
|
-
|
3
|
-
|
2
|
+
post 'paypal' => 'paypal#create'
|
3
|
+
put 'paypal/:id/approved' => 'paypal#update', as: :paypal_approved
|
4
|
+
post 'paypal/event' => 'paypal#event', as: :paypal_event
|
4
5
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
namespace :workarea do
|
2
|
+
namespace :paypal do
|
3
|
+
desc 'Register webhook listeners for PayPal'
|
4
|
+
task create_webhooks: :environment do
|
5
|
+
puts 'Unsubscribing existing webhooks...'
|
6
|
+
webhooks = Workarea::Paypal.gateway.list_webhooks.result.webhooks
|
7
|
+
|
8
|
+
|
9
|
+
webhooks.each do |webhook|
|
10
|
+
begin
|
11
|
+
Workarea::Paypal.gateway.delete_webhook(webhook.id)
|
12
|
+
rescue Workarea::Paypal::Gateway::RequestError => e
|
13
|
+
puts "Webhook deletion #{id} failed. #{e.message}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
puts 'Subscribing to PayPal webhook events...'
|
18
|
+
Workarea::Paypal.gateway.create_webhook(
|
19
|
+
url: Workarea::Storefront::Engine.routes.url_helpers.paypal_event_url(
|
20
|
+
host: Workarea.config.host
|
21
|
+
),
|
22
|
+
event_types: Workarea.config.default_webhook_events
|
23
|
+
)
|
24
|
+
|
25
|
+
puts 'completed successfully!'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Paypal
|
3
|
+
class Gateway
|
4
|
+
class RequestError < StandardError; end
|
5
|
+
|
6
|
+
def environment
|
7
|
+
@environment =
|
8
|
+
Workarea.config.paypal_environment.constantize.new(
|
9
|
+
client_id,
|
10
|
+
client_secret
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
def client
|
15
|
+
PayPal::PayPalHttpClient.new(environment)
|
16
|
+
end
|
17
|
+
|
18
|
+
def send_request(request)
|
19
|
+
# Do not change this
|
20
|
+
request.headers["PayPal-Partner-Attribution-Id"] = 'Workarea_SP_PCP'
|
21
|
+
|
22
|
+
client.execute(request)
|
23
|
+
end
|
24
|
+
|
25
|
+
# This gets a token required to render hosted fields. Not used for
|
26
|
+
# smart payment buttons.
|
27
|
+
def generate_token(user: nil)
|
28
|
+
request = Workarea::Paypal::Requests::GenerateToken.new
|
29
|
+
id = user&.id.to_s.last(22) # length limit
|
30
|
+
request.request_body(customer_id: id) if user.present?
|
31
|
+
|
32
|
+
handle_connection_errors { send_request(request) }
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_order(order_id)
|
36
|
+
request = PayPalCheckoutSdk::Orders::OrdersGetRequest.new(order_id)
|
37
|
+
handle_connection_errors { send_request(request) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def create_order(body:)
|
41
|
+
request = PayPalCheckoutSdk::Orders::OrdersCreateRequest.new
|
42
|
+
request.request_body(body)
|
43
|
+
|
44
|
+
handle_connection_errors do
|
45
|
+
response = send_request(request)
|
46
|
+
response.result
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def update_order(order_id, body: {})
|
51
|
+
request = PayPalCheckoutSdk::Orders::OrdersPatchRequest.new(order_id)
|
52
|
+
request.request_body(body)
|
53
|
+
|
54
|
+
handle_connection_errors do
|
55
|
+
response = send_request(request)
|
56
|
+
response.result
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def capture(order_id)
|
61
|
+
request = PayPalCheckoutSdk::Orders::OrdersCaptureRequest.new(order_id)
|
62
|
+
request.prefer("return=representation")
|
63
|
+
|
64
|
+
if ENV['PAYPAL_MOCK_RESPONSE'].present? && Rails.env.in?(%w(test development))
|
65
|
+
request.headers['PayPal-Mock-Response'] = ENV['PAYPAL_MOCK_RESPONSE']
|
66
|
+
end
|
67
|
+
|
68
|
+
handle_transaction_errors do
|
69
|
+
response = send_request(request)
|
70
|
+
result = response.result
|
71
|
+
capture = result&.purchase_units&.first&.payments&.captures&.last
|
72
|
+
success = response.status_code == 201 && capture&.status != 'DECLINED'
|
73
|
+
|
74
|
+
ActiveMerchant::Billing::Response.new(
|
75
|
+
success,
|
76
|
+
"PayPal capture #{success ? 'succeeded' : 'failed'}",
|
77
|
+
Paypal.transform_values(success ? capture : result)
|
78
|
+
)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# No body means refunding the entire captured amount, otherwise an amount
|
83
|
+
# object needs to be supplied.
|
84
|
+
#
|
85
|
+
def refund(capture_id, amount: nil)
|
86
|
+
request = PayPalCheckoutSdk::Payments::CapturesRefundRequest.new(capture_id)
|
87
|
+
request.prefer("return=representation")
|
88
|
+
|
89
|
+
if amount.present?
|
90
|
+
request.request_body(
|
91
|
+
amount: {
|
92
|
+
value: amount.to_s,
|
93
|
+
currency: amount.currency.iso_code
|
94
|
+
}
|
95
|
+
)
|
96
|
+
end
|
97
|
+
|
98
|
+
handle_transaction_errors do
|
99
|
+
response = send_request(request)
|
100
|
+
refund = response.result
|
101
|
+
success = response.status_code == 201 && refund.status != 'CANCELLED'
|
102
|
+
|
103
|
+
ActiveMerchant::Billing::Response.new(
|
104
|
+
success,
|
105
|
+
"PayPal refund #{success ? 'succeeded' : 'failed'}",
|
106
|
+
{
|
107
|
+
id: refund.id,
|
108
|
+
status: refund.status,
|
109
|
+
status_details: refund.status_details.to_h,
|
110
|
+
capture_id: capture_id,
|
111
|
+
amount: amount.to_s
|
112
|
+
}
|
113
|
+
)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def create_webhook(url:, event_types:)
|
118
|
+
request = Workarea::Paypal::Requests::CreateWebhook.new
|
119
|
+
request.request_body(
|
120
|
+
url: url,
|
121
|
+
event_types: Array.wrap(event_types).map { |type| { name: type } }
|
122
|
+
)
|
123
|
+
|
124
|
+
response = handle_connection_errors { send_request(request) }
|
125
|
+
|
126
|
+
throw_request_error(response) unless response.status_code == 201
|
127
|
+
response
|
128
|
+
end
|
129
|
+
|
130
|
+
def delete_webhook(webhook_id)
|
131
|
+
request = Workarea::Paypal::Requests::DeleteWebhook.new(webhook_id)
|
132
|
+
response = handle_connection_errors { send_request(request) }
|
133
|
+
|
134
|
+
throw_request_error(response) unless response.status_code == 204
|
135
|
+
response
|
136
|
+
end
|
137
|
+
|
138
|
+
def list_webhooks
|
139
|
+
request = Workarea::Paypal::Requests::ListWebhooks.new
|
140
|
+
response = handle_connection_errors { send_request(request) }
|
141
|
+
|
142
|
+
throw_request_error(response) unless response.status_code == 200
|
143
|
+
response
|
144
|
+
end
|
145
|
+
|
146
|
+
def configured?
|
147
|
+
client_id.present? && client_secret.present?
|
148
|
+
end
|
149
|
+
|
150
|
+
def client_id
|
151
|
+
ENV['WORKAREA_PAYPAL_CLIENT_ID'].presence ||
|
152
|
+
Rails.application.credentials.paypal.try(:[], :client_id) ||
|
153
|
+
Workarea.config.paypal_client_id
|
154
|
+
end
|
155
|
+
|
156
|
+
private
|
157
|
+
|
158
|
+
def client_secret
|
159
|
+
ENV['WORKAREA_PAYPAL_CLIENT_SECRET'].presence ||
|
160
|
+
Rails.application.credentials.paypal.try(:[], :client_secret) ||
|
161
|
+
Workarea.config.paypal_client_secret
|
162
|
+
end
|
163
|
+
|
164
|
+
def throw_request_error(error)
|
165
|
+
raise RequestError.new(
|
166
|
+
I18n.t(
|
167
|
+
'workarea.paypal.gateway.http_error',
|
168
|
+
status: error.status_code,
|
169
|
+
debug_id: error.headers['paypal-debug-id']
|
170
|
+
)
|
171
|
+
)
|
172
|
+
end
|
173
|
+
|
174
|
+
def handle_connection_errors
|
175
|
+
begin
|
176
|
+
yield
|
177
|
+
rescue PayPalHttp::HttpError => error
|
178
|
+
Rails.logger.error(error.message)
|
179
|
+
Rails.logger.error(error.result)
|
180
|
+
throw_request_error(error)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def handle_transaction_errors
|
185
|
+
begin
|
186
|
+
yield
|
187
|
+
rescue PayPalHttp::HttpError => error
|
188
|
+
ActiveMerchant::Billing::Response.new(
|
189
|
+
false,
|
190
|
+
I18n.t('workarea.paypal.gateway.capture_error'),
|
191
|
+
status_code: error.status_code,
|
192
|
+
debug_id: error.headers['paypal-debug-id']
|
193
|
+
)
|
194
|
+
rescue StandardError => error
|
195
|
+
ActiveMerchant::Billing::Response.new(false, error.message, {})
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Paypal
|
3
|
+
module Requests
|
4
|
+
class CreateWebhook
|
5
|
+
attr_accessor :path, :body, :headers, :verb
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@headers = {}
|
9
|
+
@body = nil
|
10
|
+
@verb = "POST"
|
11
|
+
@path = "/v1/notifications/webhooks"
|
12
|
+
@headers["Content-Type"] = "application/json"
|
13
|
+
end
|
14
|
+
|
15
|
+
def request_body(body)
|
16
|
+
@body = body
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Paypal
|
3
|
+
module Requests
|
4
|
+
class DeleteWebhook
|
5
|
+
attr_accessor :path, :body, :headers, :verb
|
6
|
+
|
7
|
+
def initialize(id)
|
8
|
+
@headers = {}
|
9
|
+
@body = nil
|
10
|
+
@verb = "DELETE"
|
11
|
+
@path = "/v1/notifications/webhooks/#{id}"
|
12
|
+
@headers["Content-Type"] = "application/json"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Paypal
|
3
|
+
module Requests
|
4
|
+
class GenerateToken
|
5
|
+
attr_accessor :path, :body, :headers, :verb
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@headers = {}
|
9
|
+
@body = nil
|
10
|
+
@verb = "POST"
|
11
|
+
@path = "/v1/identity/generate-token"
|
12
|
+
@headers["Content-Type"] = "application/json"
|
13
|
+
end
|
14
|
+
|
15
|
+
def request_body(body)
|
16
|
+
@body = body
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Paypal
|
3
|
+
module Requests
|
4
|
+
class ListWebhooks
|
5
|
+
attr_accessor :path, :body, :headers, :verb
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@headers = {}
|
9
|
+
@body = nil
|
10
|
+
@verb = "GET"
|
11
|
+
@path = "/v1/notifications/webhooks"
|
12
|
+
@headers["Content-Type"] = "application/json"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/workarea/paypal.rb
CHANGED
@@ -1,31 +1,34 @@
|
|
1
1
|
require 'workarea'
|
2
2
|
require 'workarea/storefront'
|
3
3
|
require 'workarea/admin'
|
4
|
-
|
4
|
+
|
5
|
+
require 'paypal-checkout-sdk'
|
6
|
+
require 'workarea/paypal/requests/generate_token'
|
7
|
+
require 'workarea/paypal/requests/list_webhooks'
|
8
|
+
require 'workarea/paypal/requests/create_webhook'
|
9
|
+
require 'workarea/paypal/requests/delete_webhook'
|
10
|
+
require 'workarea/paypal/gateway'
|
5
11
|
|
6
12
|
module Workarea
|
7
13
|
module Paypal
|
8
|
-
|
9
|
-
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.gateway=(gateway)
|
13
|
-
Workarea.config.gateways.paypal = gateway
|
14
|
-
end
|
14
|
+
class << self
|
15
|
+
delegate :client, to: :gateway
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
self.gateway = ActiveMerchant::Billing::PaypalExpressGateway.new(
|
19
|
-
Rails.application.secrets.paypal.deep_symbolize_keys
|
20
|
-
)
|
21
|
-
elsif gateway.blank?
|
22
|
-
self.gateway = ActiveMerchant::Billing::BogusGateway.new
|
17
|
+
def gateway
|
18
|
+
Workarea::Paypal::Gateway.new
|
23
19
|
end
|
24
20
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
21
|
+
def transform_values(value)
|
22
|
+
case value
|
23
|
+
when OpenStruct
|
24
|
+
transform_values(value.to_h)
|
25
|
+
when Hash
|
26
|
+
value.transform_values(&method(:transform_values))
|
27
|
+
when Array
|
28
|
+
value.map(&method(:transform_values))
|
29
|
+
else
|
30
|
+
value
|
31
|
+
end
|
29
32
|
end
|
30
33
|
end
|
31
34
|
end
|
data/package.json
ADDED