workarea-paypal 2.0.10 → 3.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc.json +2 -1
  3. data/.gitignore +16 -11
  4. data/CHANGELOG.md +86 -2
  5. data/README.md +105 -6
  6. data/Rakefile +1 -2
  7. data/UPGRADE.md +46 -0
  8. data/app/assets/javascripts/workarea/storefront/paypal/config.js.erb +44 -0
  9. data/app/assets/javascripts/workarea/storefront/paypal/modules/paypal_buttons.js +71 -0
  10. data/app/assets/javascripts/workarea/storefront/paypal/modules/paypal_hosted_fields.js +96 -0
  11. data/app/assets/javascripts/workarea/storefront/paypal/modules/update_checkout_submit_text.js +11 -5
  12. data/app/assets/javascripts/workarea/storefront/paypal/templates/paypal_fields.jst.ejs +43 -0
  13. data/app/controllers/workarea/storefront/checkout/place_order_controller.decorator +6 -4
  14. data/app/controllers/workarea/storefront/paypal_controller.rb +32 -26
  15. data/app/helpers/workarea/storefront/paypal_helper.rb +38 -0
  16. data/app/models/workarea/payment.decorator +17 -3
  17. data/app/models/workarea/payment/authorize/paypal.rb +13 -13
  18. data/app/models/workarea/payment/capture/paypal.rb +10 -20
  19. data/app/models/workarea/payment/null_address.rb +37 -0
  20. data/app/models/workarea/payment/purchase/paypal.rb +1 -25
  21. data/app/models/workarea/payment/refund/paypal.rb +3 -6
  22. data/app/models/workarea/payment/tender/paypal.rb +14 -2
  23. data/app/services/workarea/paypal/approve_order.rb +104 -0
  24. data/app/services/workarea/paypal/create_order.rb +177 -0
  25. data/app/services/workarea/paypal/update_order.rb +44 -0
  26. data/app/views/workarea/admin/orders/tenders/_paypal.html.haml +5 -2
  27. data/app/views/workarea/api/orders/tenders/_paypal.json.jbuilder +7 -1
  28. data/app/views/workarea/storefront/carts/_paypal_checkout.html.haml +6 -1
  29. data/app/views/workarea/storefront/checkouts/_paypal_payment.html.haml +17 -6
  30. data/app/views/workarea/storefront/order_mailer/tenders/_paypal.html.haml +5 -3
  31. data/app/views/workarea/storefront/orders/tenders/_paypal.html.haml +9 -2
  32. data/app/views/workarea/storefront/paypal/_paypal_sdk.html.haml +1 -0
  33. data/app/workers/workarea/paypal/handle_webhook_event.rb +64 -0
  34. data/config/initializers/append_points.rb +17 -5
  35. data/config/initializers/fields.rb +27 -0
  36. data/config/initializers/workarea.rb +41 -5
  37. data/config/locales/en.yml +15 -5
  38. data/config/routes.rb +5 -2
  39. data/lib/tasks/workarea/create_webhooks.rake +29 -0
  40. data/lib/workarea/paypal.rb +22 -18
  41. data/lib/workarea/paypal/engine.rb +4 -0
  42. data/lib/workarea/paypal/gateway.rb +200 -0
  43. data/lib/workarea/paypal/requests/create_webhook.rb +21 -0
  44. data/lib/workarea/paypal/requests/delete_webhook.rb +17 -0
  45. data/lib/workarea/paypal/requests/generate_token.rb +21 -0
  46. data/lib/workarea/paypal/requests/list_webhooks.rb +17 -0
  47. data/lib/workarea/paypal/version.rb +1 -1
  48. data/package.json +9 -0
  49. data/test/dummy/config/initializers/workarea.rb +1 -1
  50. data/test/factories/workarea/capture_completed_webhook.json +70 -0
  51. data/test/factories/workarea/capture_denied_webhook.json +68 -0
  52. data/test/factories/workarea/paypal.rb +34 -0
  53. data/test/helpers/workarea/storefront/paypal_helper_test.rb +35 -0
  54. data/test/integration/workarea/storefront/paypal_integration_test.rb +104 -294
  55. data/test/integration/workarea/storefront/paypal_place_order_integration_test.rb +42 -0
  56. data/test/lib/workarea/paypal/gateway_test.rb +236 -0
  57. data/test/models/workarea/payment/authorize/paypal_test.rb +57 -46
  58. data/test/models/workarea/payment/capture/paypal_test.rb +9 -51
  59. data/test/models/workarea/payment/null_address_test.rb +53 -0
  60. data/test/models/workarea/payment/refund/paypal_test.rb +39 -38
  61. data/test/models/workarea/paypal_payment_test.rb +65 -0
  62. data/test/models/workarea/search/paypal_order_text_test.rb +14 -0
  63. data/test/services/workarea/paypal/approve_order_test.rb +35 -0
  64. data/test/services/workarea/paypal/create_order_test.rb +127 -0
  65. data/test/services/workarea/paypal/update_order_test.rb +73 -0
  66. data/test/support/workarea/paypal_setup.rb +49 -0
  67. data/test/system/workarea/storefront/cart_system_test.decorator +1 -1
  68. data/test/system/workarea/storefront/logged_in_checkout_system_test.decorator +1 -1
  69. data/test/vcr_cassettes/paypal_approve_order.yml +106 -0
  70. data/test/vcr_cassettes/paypal_create_order.yml +110 -0
  71. data/test/vcr_cassettes/paypal_gateway_create_order.yml +105 -0
  72. data/test/vcr_cassettes/paypal_gateway_generate_token.yml +103 -0
  73. data/test/vcr_cassettes/paypal_gateway_get_order.yml +103 -0
  74. data/test/vcr_cassettes/paypal_gateway_update_order.yml +199 -0
  75. data/test/vcr_cassettes/paypal_gateway_webhooks.yml +403 -0
  76. data/test/vcr_cassettes/paypal_update_order.yml +204 -0
  77. data/test/workers/workarea/paypal/handle_webhook_event_test.rb +60 -0
  78. data/workarea-paypal.gemspec +2 -1
  79. metadata +64 -13
  80. data/app/services/workarea/paypal/setup.rb +0 -114
  81. data/app/services/workarea/paypal/update.rb +0 -69
  82. data/app/views/workarea/storefront/checkouts/_paypal_error.html.haml +0 -6
  83. data/app/views/workarea/storefront/order_mailer/tenders/_paypal.text.haml +0 -2
  84. data/test/dummy/config/initializers/session_store.rb +0 -3
  85. data/test/integration/workarea/storefront/place_order_integration_test.decorator +0 -11
  86. data/test/models/workarea/payment/purchase/paypal_test.rb +0 -94
  87. data/test/models/workarea/payment_test.decorator +0 -34
  88. data/test/models/workarea/search/admin/order_test.decorator +0 -32
  89. data/test/services/workarea/paypal/setup_test.rb +0 -120
  90. data/test/services/workarea/paypal/update_test.rb +0 -221
@@ -1,3 +1,5 @@
1
- %p{ style: "margin: 0 0 6px; font: 13px/1.5 arial; color: #{@config.text_color};" }
2
- = t('workarea.storefront.paypal.paid_with_paypal')
3
- = number_to_currency tender.amount
1
+ - if tender.direct_payment?
2
+ = render 'workarea/storefront/order_mailer/tenders/credit_card', tender: tender
3
+ - else
4
+ %p
5
+ = "#{t('workarea.storefront.paypal.paid_with_paypal')}: #{number_to_currency tender.amount}"
@@ -1,2 +1,9 @@
1
- %p= t('workarea.storefront.paypal.paid_with_paypal')
2
- %p= number_to_currency(tender.amount)
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.cart_checkout_actions',
3
- 'workarea/storefront/carts/paypal_checkout'
2
+ 'storefront.document_head',
3
+ 'workarea/storefront/paypal/paypal_sdk'
4
4
  )
5
5
 
6
6
  Workarea::Plugin.append_partials(
7
- 'storefront.payment_error',
8
- 'workarea/storefront/checkouts/paypal_error'
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
- # Gateway application_id is sent as PayPal BN code for revenue sharing
4
- # 'Workarea_SP' should be used for all WebLinc installations
5
- ActiveMerchant::Billing::PaypalGateway.application_id = 'Workarea_SP'
2
+ Workarea.configure do |config|
3
+ config.tender_types << :paypal
6
4
 
7
- Workarea::Paypal.auto_configure_gateway
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
@@ -1,4 +1,3 @@
1
- ---
2
1
  en:
3
2
  workarea:
4
3
  admin:
@@ -6,14 +5,25 @@ 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: Continue to PayPal
14
- on_continue: When you continue, you will be taken to the PayPal website.
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
16
- payment_recieved: Thank You! We have received your information back from PayPal.
25
+ payment_failed: Your submitted PayPal payment could not be completed. Select a new method and try again.
26
+ payment_received: 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'.
19
29
  paypal: PayPal
@@ -1,4 +1,7 @@
1
1
  Workarea::Storefront::Engine.routes.draw do
2
- get 'paypal/start' => 'paypal#start', as: :start_paypal
3
- get 'paypal/complete/:order_id' => 'paypal#complete', as: :complete_paypal
2
+ scope '(:locale)', constraints: Workarea::I18n.routes_constraint do
3
+ post 'paypal' => 'paypal#create'
4
+ put 'paypal/:id/approved' => 'paypal#update', as: :paypal_approved
5
+ post 'paypal/event' => 'paypal#event', as: :paypal_event
6
+ end
4
7
  end
@@ -0,0 +1,29 @@
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
+ protocol: Rails.application.config.force_ssl ? 'https' : 'http'
22
+ ),
23
+ event_types: Workarea.config.default_webhook_events
24
+ )
25
+
26
+ puts 'completed successfully!'
27
+ end
28
+ end
29
+ end
@@ -2,29 +2,33 @@ 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'
11
+
5
12
  module Workarea
6
13
  module Paypal
7
- def self.gateway
8
- Workarea.config.gateways.paypal
9
- end
10
-
11
- def self.gateway=(gateway)
12
- Workarea.config.gateways.paypal = gateway
13
- end
14
+ class << self
15
+ delegate :client, to: :gateway
14
16
 
15
- def self.auto_configure_gateway
16
- if Rails.application.secrets.paypal.present?
17
- self.gateway = ActiveMerchant::Billing::PaypalExpressGateway.new(
18
- Rails.application.secrets.paypal.deep_symbolize_keys
19
- )
20
- elsif gateway.blank?
21
- self.gateway = ActiveMerchant::Billing::BogusGateway.new
17
+ def gateway
18
+ Workarea::Paypal::Gateway.new
22
19
  end
23
20
 
24
- if ENV['HTTP_PROXY'].present? && gateway.present?
25
- parsed = URI.parse(ENV['HTTP_PROXY'])
26
- gateway.proxy_address = parsed.host
27
- gateway.proxy_port = parsed.port
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
28
32
  end
29
33
  end
30
34
  end
@@ -3,6 +3,10 @@ module Workarea
3
3
  class Engine < ::Rails::Engine
4
4
  include Workarea::Plugin
5
5
  isolate_namespace Workarea::Paypal
6
+
7
+ config.to_prepare do
8
+ Storefront::ApplicationController.helper(Storefront::PaypalHelper)
9
+ end
6
10
  end
7
11
  end
8
12
  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'
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_code: 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