solidus_paypal_commerce_platform 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +41 -0
  3. data/.gem_release.yml +5 -0
  4. data/.github/stale.yml +17 -0
  5. data/.gitignore +20 -0
  6. data/.rspec +2 -0
  7. data/.rubocop.yml +56 -0
  8. data/Gemfile +33 -0
  9. data/LICENSE +26 -0
  10. data/README.md +173 -0
  11. data/Rakefile +6 -0
  12. data/app/assets/javascripts/spree/backend/solidus_paypal_commerce_platform.js +2 -0
  13. data/app/assets/javascripts/spree/backend/solidus_paypal_commerce_platform/namespace.js +1 -0
  14. data/app/assets/javascripts/spree/backend/solidus_paypal_commerce_platform/wizard.js +28 -0
  15. data/app/assets/javascripts/spree/frontend/solidus_paypal_commerce_platform.js +3 -0
  16. data/app/assets/javascripts/spree/frontend/solidus_paypal_commerce_platform/button_actions.js +191 -0
  17. data/app/assets/javascripts/spree/frontend/solidus_paypal_commerce_platform/buttons.js +26 -0
  18. data/app/assets/javascripts/spree/frontend/solidus_paypal_commerce_platform/namespace.js +1 -0
  19. data/app/assets/stylesheets/spree/backend/solidus_paypal_commerce_platform.css +4 -0
  20. data/app/assets/stylesheets/spree/frontend/solidus_paypal_commerce_platform.css +17 -0
  21. data/app/controllers/solidus_paypal_commerce_platform/orders_controller.rb +83 -0
  22. data/app/controllers/solidus_paypal_commerce_platform/payments_controller.rb +44 -0
  23. data/app/controllers/solidus_paypal_commerce_platform/paypal_orders_controller.rb +19 -0
  24. data/app/controllers/solidus_paypal_commerce_platform/shipping_rates_controller.rb +31 -0
  25. data/app/controllers/solidus_paypal_commerce_platform/wizard_controller.rb +47 -0
  26. data/app/decorators/solidus_paypal_commerce_platform/remove_required_phone_from_address.rb +13 -0
  27. data/app/helpers/solidus_paypal_commerce_platform/button_options_helper.rb +21 -0
  28. data/app/jobs/solidus_paypal_commerce_platform/application_job.rb +6 -0
  29. data/app/jobs/solidus_paypal_commerce_platform/webhook_job.rb +22 -0
  30. data/app/models/solidus_paypal_commerce_platform/gateway.rb +88 -0
  31. data/app/models/solidus_paypal_commerce_platform/payment_method.rb +75 -0
  32. data/app/models/solidus_paypal_commerce_platform/payment_source.rb +27 -0
  33. data/app/models/solidus_paypal_commerce_platform/paypal_address.rb +81 -0
  34. data/app/models/solidus_paypal_commerce_platform/paypal_order.rb +107 -0
  35. data/app/models/solidus_paypal_commerce_platform/pricing_options.rb +9 -0
  36. data/app/models/solidus_paypal_commerce_platform/wizard.rb +40 -0
  37. data/app/overrides/spree/admin/payment_methods/form/insert_email_verification_notification.rb +9 -0
  38. data/app/overrides/spree/admin/payment_methods/index/insert_setup_wizards.rb +17 -0
  39. data/app/overrides/spree/admin/payments/log_entries/add_paypal_debug_id.rb +9 -0
  40. data/app/overrides/spree/orders/edit/insert_cart_buttons.rb +9 -0
  41. data/app/overrides/spree/payments/payment/add_paypal_email_to_payment.rb +9 -0
  42. data/app/overrides/spree/products/cart_form/insert_product_buttons.rb +10 -0
  43. data/app/views/solidus_paypal_commerce_platform/admin/payment_methods/_available_to_users.html.erb +6 -0
  44. data/app/views/solidus_paypal_commerce_platform/admin/payment_methods/_paypal_wizard.html.erb +16 -0
  45. data/app/views/solidus_paypal_commerce_platform/admin/payment_methods/_setup_wizards.html.erb +16 -0
  46. data/app/views/solidus_paypal_commerce_platform/admin/payments/_log_entries.html.erb +32 -0
  47. data/bin/console +17 -0
  48. data/bin/rails +7 -0
  49. data/bin/rails-engine +13 -0
  50. data/bin/rails-sandbox +18 -0
  51. data/bin/rake +7 -0
  52. data/bin/sandbox +86 -0
  53. data/bin/setup +8 -0
  54. data/codecov.yml +14 -0
  55. data/config/locales/en.yml +37 -0
  56. data/config/routes.rb +12 -0
  57. data/db/migrate/20200521190038_add_paypal_commerce_platform_sources.rb +13 -0
  58. data/lib/generators/solidus_paypal_commerce_platform/install/install_generator.rb +38 -0
  59. data/lib/solidus_paypal_commerce_platform.rb +21 -0
  60. data/lib/solidus_paypal_commerce_platform/access_token_authorization_request.rb +21 -0
  61. data/lib/solidus_paypal_commerce_platform/client.rb +84 -0
  62. data/lib/solidus_paypal_commerce_platform/configuration.rb +64 -0
  63. data/lib/solidus_paypal_commerce_platform/engine.rb +45 -0
  64. data/lib/solidus_paypal_commerce_platform/factories.rb +14 -0
  65. data/lib/solidus_paypal_commerce_platform/fetch_merchant_credentials_request.rb +17 -0
  66. data/lib/solidus_paypal_commerce_platform/version.rb +5 -0
  67. data/lib/views/api/spree/api/payments/source_views/_paypal_commerce_platform.json.jbuilder +3 -0
  68. data/lib/views/backend/spree/admin/payments/source_forms/_paypal_commerce_platform.html.erb +1 -0
  69. data/lib/views/backend/spree/admin/payments/source_views/_paypal_commerce_platform.html.erb +18 -0
  70. data/lib/views/backend/spree/admin/shared/preference_fields/_paypal_select.html.erb +13 -0
  71. data/lib/views/frontend/solidus_paypal_commerce_platform/cart/_cart_buttons.html.erb +3 -0
  72. data/lib/views/frontend/solidus_paypal_commerce_platform/payments/_payment.html.erb +4 -0
  73. data/lib/views/frontend/solidus_paypal_commerce_platform/product/_product_buttons.html.erb +3 -0
  74. data/lib/views/frontend/spree/checkout/payment/_paypal_commerce_platform.html.erb +13 -0
  75. data/lib/views/frontend/spree/orders/payment/_paypal_commerce_platform.html.erb +17 -0
  76. data/lib/views/frontend/spree/products/payment/_paypal_commerce_platform.html.erb +15 -0
  77. data/solidus_paypal_commerce_platform.gemspec +39 -0
  78. data/spec/features/backend/new_payment_method_spec.rb +40 -0
  79. data/spec/features/frontend/cart_spec.rb +38 -0
  80. data/spec/features/frontend/checkout_spec.rb +81 -0
  81. data/spec/features/frontend/product_spec.rb +79 -0
  82. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/CHECKOUT.ORDER.COMPLETED.v2.json +121 -0
  83. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/CHECKOUT.ORDER.PROCESSED.v2.json +121 -0
  84. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.COMPLETED.v1.json +50 -0
  85. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.COMPLETED.v2.json +72 -0
  86. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.DENIED.v1.json +50 -0
  87. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.DENIED.v2.json +68 -0
  88. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.REFUNDED.v1.json +51 -0
  89. data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.REFUNDED.v2.json +63 -0
  90. data/spec/jobs/solidus_paypal_commerce_platform/webhook_job_spec.rb +44 -0
  91. data/spec/lib/solidus_paypal_commerce_platform/client_spec.rb +21 -0
  92. data/spec/lib/solidus_paypal_commerce_platform/configuration_spec.rb +67 -0
  93. data/spec/models/solidus_paypal_commerce_platform/payment_method_spec.rb +102 -0
  94. data/spec/models/solidus_paypal_commerce_platform/payment_source_spec.rb +62 -0
  95. data/spec/models/solidus_paypal_commerce_platform/paypal_address_spec.rb +55 -0
  96. data/spec/models/solidus_paypal_commerce_platform/wizard_spec.rb +9 -0
  97. data/spec/requests/solidus_paypal_commerce_platform/orders_controller_spec.rb +36 -0
  98. data/spec/requests/solidus_paypal_commerce_platform/shipping_rates_controller_spec.rb +44 -0
  99. data/spec/requests/solidus_paypal_commerce_platform/wizard_controller_spec.rb +44 -0
  100. data/spec/spec_helper.rb +30 -0
  101. metadata +258 -0
@@ -0,0 +1,51 @@
1
+ {
2
+ "id": "WH-2JG62852X9350413N-40V56408FN023574K",
3
+ "create_time": "2014-10-22T23:49:03Z",
4
+ "resource_type": "capture",
5
+ "event_type": "PAYMENT.CAPTURE.REFUNDED",
6
+ "summary": "A $ 0.15 USD capture payment was refunded",
7
+ "resource": {
8
+ "parent_payment": "PAY-7PD36489JY0066936KREEERQ",
9
+ "update_time": "2014-10-22T23:48:57Z",
10
+ "amount": {
11
+ "total": "-0.15",
12
+ "currency": "USD"
13
+ },
14
+ "create_time": "2014-10-22T23:48:57Z",
15
+ "links": [
16
+ {
17
+ "href": "https://api.paypal.com/v1/payments/refund/8VC964970N548345V",
18
+ "rel": "self",
19
+ "method": "GET"
20
+ },
21
+ {
22
+ "href": "https://api.paypal.com/v1/payments/payment/PAY-7PD36489JY0066936KREEERQ",
23
+ "rel": "parent_payment",
24
+ "method": "GET"
25
+ },
26
+ {
27
+ "href": "https://api.paypal.com/v1/payments/capture/5LK72275CG489890D",
28
+ "rel": "capture",
29
+ "method": "GET"
30
+ }
31
+ ],
32
+ "id": "8VC964970N548345V",
33
+ "state": "completed",
34
+ "capture_id": "5LK72275CG489890D"
35
+ },
36
+ "links": [
37
+ {
38
+ "href": "https://api.paypal.com/v1/notifications/webhooks-events/WH-2JG62852X9350413N-40V56408FN023574K",
39
+ "rel": "self",
40
+ "method": "GET",
41
+ "encType": "application/json"
42
+ },
43
+ {
44
+ "href": "https://api.paypal.com/v1/notifications/webhooks-events/WH-2JG62852X9350413N-40V56408FN023574K/resend",
45
+ "rel": "resend",
46
+ "method": "POST",
47
+ "encType": "application/json"
48
+ }
49
+ ],
50
+ "event_version": "1.0"
51
+ }
@@ -0,0 +1,63 @@
1
+ {
2
+ "id": "WH-1GE84257G0350133W-6RW800890C634293G",
3
+ "create_time": "2018-08-15T19:14:04.543Z",
4
+ "resource_type": "refund",
5
+ "event_type": "PAYMENT.CAPTURE.REFUNDED",
6
+ "summary": "A $ 0.99 USD capture payment was refunded",
7
+ "resource": {
8
+ "seller_payable_breakdown": {
9
+ "gross_amount": {
10
+ "currency_code": "USD",
11
+ "value": "0.99"
12
+ },
13
+ "paypal_fee": {
14
+ "currency_code": "USD",
15
+ "value": "0.02"
16
+ },
17
+ "net_amount": {
18
+ "currency_code": "USD",
19
+ "value": "0.97"
20
+ },
21
+ "total_refunded_amount": {
22
+ "currency_code": "USD",
23
+ "value": "1.98"
24
+ }
25
+ },
26
+ "amount": {
27
+ "currency_code": "USD",
28
+ "value": "0.99"
29
+ },
30
+ "update_time": "2018-08-15T12:13:29-07:00",
31
+ "create_time": "2018-08-15T12:13:29-07:00",
32
+ "links": [
33
+ {
34
+ "href": "https://api.paypal.com/v2/payments/refunds/1Y107995YT783435V",
35
+ "rel": "self",
36
+ "method": "GET"
37
+ },
38
+ {
39
+ "href": "https://api.paypal.com/v2/payments/captures/0JF852973C016714D",
40
+ "rel": "up",
41
+ "method": "GET"
42
+ }
43
+ ],
44
+ "id": "1Y107995YT783435V",
45
+ "status": "COMPLETED"
46
+ },
47
+ "links": [
48
+ {
49
+ "href": "https://api.paypal.com/v1/notifications/webhooks-events/WH-1GE84257G0350133W-6RW800890C634293G",
50
+ "rel": "self",
51
+ "method": "GET",
52
+ "encType": "application/json"
53
+ },
54
+ {
55
+ "href": "https://api.paypal.com/v1/notifications/webhooks-events/WH-1GE84257G0350133W-6RW800890C634293G/resend",
56
+ "rel": "resend",
57
+ "method": "POST",
58
+ "encType": "application/json"
59
+ }
60
+ ],
61
+ "event_version": "1.0",
62
+ "resource_version": "2.0"
63
+ }
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe SolidusPaypalCommercePlatform::WebhookJob do
4
+ let(:paypal_order_id) { SecureRandom.uuid }
5
+ let(:capture_id) { SecureRandom.uuid }
6
+ let(:refund_id) { SecureRandom.uuid }
7
+
8
+ let(:payment_source) {
9
+ SolidusPaypalCommercePlatform::PaymentSource.new(
10
+ paypal_order_id: paypal_order_id,
11
+ capture_id: capture_id,
12
+ refund_id: refund_id,
13
+ payment_method: create(:paypal_payment_method),
14
+ )
15
+ }
16
+
17
+ let(:payment) {
18
+ create(:order).payments.create!(
19
+ payment_method: payment_source.payment_method,
20
+ source: payment_source,
21
+ )
22
+ }
23
+
24
+ [
25
+ ["CHECKOUT.ORDER.COMPLETED.v2", "paypal_order_id"],
26
+ ["CHECKOUT.ORDER.PROCESSED.v2", "paypal_order_id"],
27
+ ["PAYMENT.CAPTURE.COMPLETED.v1", "capture_id"],
28
+ ["PAYMENT.CAPTURE.COMPLETED.v2", "capture_id"],
29
+ ["PAYMENT.CAPTURE.DENIED.v1", "capture_id"],
30
+ ["PAYMENT.CAPTURE.DENIED.v2", "capture_id"],
31
+ ["PAYMENT.CAPTURE.REFUNDED.v1", "capture_id"],
32
+ ["PAYMENT.CAPTURE.REFUNDED.v2", "refund_id"],
33
+ ].each do |(event, source_attr)|
34
+ describe event do
35
+ let(:payload) { JSON.parse(File.read("#{__dir__}/fixtures/#{event}.json")) }
36
+ let(source_attr) { payload.dig("resource", "id") }
37
+
38
+ it 'inserts a log entry for the corresponding payment source' do
39
+ expect { described_class.perform_now(payload) }.to change(payment.log_entries, :count).by(1)
40
+ expect(YAML.load(payment.log_entries.last.details)).to eq(payload)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe SolidusPaypalCommercePlatform::Client do
4
+ subject(:client) { described_class.new(client_id: "1234") }
5
+
6
+ describe '#execute_with_response' do
7
+ let(:request_class) { SolidusPaypalCommercePlatform::Gateway::OrdersCaptureRequest }
8
+ let(:paypal_request) { double(:request, class: request_class) }
9
+ let(:paypal_response) { double(:response, status_code: status_code, result: nil, headers: {}) }
10
+ let(:status_code) { 201 }
11
+
12
+ it 'forwards to the upstream client adding i18n response messages' do
13
+ expect_any_instance_of(PayPal::PayPalHttpClient)
14
+ .to receive(:execute).with(paypal_request).and_return(paypal_response)
15
+
16
+ response = subject.execute_with_response(paypal_request)
17
+
18
+ expect(response.message).to eq("Payment captured")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe SolidusPaypalCommercePlatform::Configuration do
4
+ let(:subject) { described_class.new }
5
+
6
+ describe '#default_env' do
7
+ it "uses ENV['PAYPAL_ENV'] when present" do
8
+ expect(ENV).to receive(:[]).with("PAYPAL_ENV").and_return("foo").at_least(:once)
9
+ expect(subject.default_env).to eq("foo")
10
+ end
11
+
12
+ it "falls back to Rails.env if ENV['PAYPAL_ENV'] is not set" do
13
+ expect(ENV).to receive(:[]).with("PAYPAL_ENV").and_return(nil).at_least(:once)
14
+
15
+ expect(Rails).to receive(:env).and_return("development".inquiry)
16
+ expect(subject.default_env).to eq("sandbox")
17
+
18
+ expect(Rails).to receive(:env).and_return("test".inquiry)
19
+ expect(subject.default_env).to eq("sandbox")
20
+
21
+ expect(Rails).to receive(:env).and_return("production".inquiry)
22
+ expect(subject.default_env).to eq("live")
23
+
24
+ expect(Rails).to receive(:env).and_return("staging".inquiry)
25
+ expect{ subject.default_env }.to raise_error(described_class::InvalidEnvironment)
26
+ end
27
+ end
28
+
29
+ describe '#env' do
30
+ it 'returns a string inquirer' do
31
+ expect(subject.env).to eq("sandbox")
32
+ expect(subject.env).to be_sandbox
33
+
34
+ subject.env = "live"
35
+ expect(subject.env).to eq("live")
36
+ expect(subject.env).to be_live
37
+
38
+ subject.env = "sandbox"
39
+ expect(subject.env).to eq("sandbox")
40
+ expect(subject.env).to be_sandbox
41
+ end
42
+
43
+ it 'raises an error when assigned an unsupported value' do
44
+ expect{ subject.env = "foo" }.to raise_error(described_class::InvalidEnvironment)
45
+ end
46
+ end
47
+
48
+ describe '#env_class' do
49
+ it 'changes based on the current env' do
50
+ subject.env = "live"
51
+ expect(subject.env_class).to eq(PayPal::LiveEnvironment)
52
+
53
+ subject.env = "sandbox"
54
+ expect(subject.env_class).to eq(PayPal::SandboxEnvironment)
55
+ end
56
+ end
57
+
58
+ describe '#env_domain' do
59
+ it 'changes based on the current env' do
60
+ subject.env = "live"
61
+ expect(subject.env_domain).to eq("www.paypal.com")
62
+
63
+ subject.env = "sandbox"
64
+ expect(subject.env_domain).to eq("www.sandbox.paypal.com")
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe SolidusPaypalCommercePlatform::PaymentMethod, type: :model do
4
+ let(:paypal_payment_method) { create(:paypal_payment_method) }
5
+ let(:payment) { create(:payment) }
6
+ let(:completed_payment) { create(:payment, :completed) }
7
+ let(:response) { Struct(status_code: status_code, result: result, headers: headers) }
8
+ let(:status_code) { 201 }
9
+ let(:result) { nil }
10
+ let(:headers) { {} }
11
+
12
+ def Struct(data) # rubocop:disable Naming/MethodName
13
+ Struct.new(*data.keys, keyword_init: true).new(data)
14
+ end
15
+
16
+ before { allow_any_instance_of(PayPal::PayPalHttpClient).to receive(:execute) { response } }
17
+
18
+ describe "#purchase" do
19
+ let(:result) { Struct(purchase_units: [Struct(payments: payments)]) }
20
+ let(:payments) { Struct(captures: [Struct(id: SecureRandom.hex(4))]) }
21
+
22
+ it "sends a purchase request to paypal" do
23
+ paypal_order_id = SecureRandom.hex(8)
24
+ source = paypal_payment_method.payment_source_class.create(paypal_order_id: paypal_order_id)
25
+ expect_request(:OrdersCaptureRequest).to receive(:new).with(paypal_order_id).and_call_original
26
+ paypal_payment_method.purchase(1000, source, {})
27
+ end
28
+ end
29
+
30
+ describe "#authorize" do
31
+ let(:result) { Struct(purchase_units: [Struct(payments: payments)]) }
32
+ let(:payments) { Struct(authorizations: [Struct(id: SecureRandom.hex(4))]) }
33
+
34
+ it "sends an authorize request to paypal" do
35
+ paypal_order_id = SecureRandom.hex(8)
36
+ source = paypal_payment_method.payment_source_class.create(paypal_order_id: paypal_order_id)
37
+ expect_request(:OrdersAuthorizeRequest).to receive(:new).with(paypal_order_id)
38
+ paypal_payment_method.authorize(1000, source, {})
39
+ end
40
+ end
41
+
42
+ describe "#capture" do
43
+ let(:result) { Struct(id: SecureRandom.hex(4)) }
44
+
45
+ it "sends a capture request to paypal" do
46
+ authorization_id = SecureRandom.hex(8)
47
+ source = paypal_payment_method.payment_source_class.create(authorization_id: authorization_id)
48
+ payment.source = source
49
+ expect_request(:AuthorizationsCaptureRequest).to receive(:new).with(authorization_id).and_call_original
50
+ paypal_payment_method.capture(1000, {}, originator: payment)
51
+ end
52
+ end
53
+
54
+ describe "#void" do
55
+ it "sends a void request to paypal" do
56
+ authorization_id = SecureRandom.hex(8)
57
+ source = paypal_payment_method.payment_source_class.create(authorization_id: authorization_id)
58
+ payment.source = source
59
+ expect_request(:AuthorizationsVoidRequest).to receive(:new).with(authorization_id)
60
+ paypal_payment_method.void(nil, originator: payment)
61
+ end
62
+ end
63
+
64
+ describe "#credit" do
65
+ let(:result) { Struct(id: SecureRandom.hex(4)) }
66
+
67
+ it "sends a refund request to paypal" do
68
+ capture_id = SecureRandom.hex(4)
69
+ source = paypal_payment_method.payment_source_class.create(capture_id: capture_id)
70
+ completed_payment.source = source
71
+ expect_request(:CapturesRefundRequest).to receive(:new).with(capture_id).and_call_original
72
+ paypal_payment_method.credit(1000, {}, originator: completed_payment.refunds.new(amount: 12))
73
+ expect(source.refund_id).not_to be_blank
74
+ end
75
+ end
76
+
77
+ describe '.javascript_sdk_url' do
78
+ subject(:url) { URI(paypal_payment_method.javascript_sdk_url(order: order)) }
79
+
80
+ context 'when checkout_steps include "confirm"' do
81
+ let(:order) { instance_double(Spree::Order, checkout_steps: { "confirm" => "bar" }) }
82
+
83
+ it 'sets autocommit' do
84
+ expect(url.query.split("&")).to include("commit=false")
85
+ end
86
+ end
87
+
88
+ context 'when checkout_steps does not include "confirm"' do
89
+ let(:order) { instance_double(Spree::Order, checkout_steps: { "foo" => "bar" }) }
90
+
91
+ it 'disables autocommit' do
92
+ expect(url.query.split("&")).to include("commit=true")
93
+ end
94
+ end
95
+ end
96
+
97
+ private
98
+
99
+ def expect_request(name)
100
+ expect(SolidusPaypalCommercePlatform::Gateway.const_get(name))
101
+ end
102
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe SolidusPaypalCommercePlatform::PaymentSource, type: :model do
4
+ let(:order) { Spree::TestingSupport::OrderWalkthrough.up_to(:payment) }
5
+ let(:paypal_payment_method) { create(:paypal_payment_method) }
6
+ let(:paypal_order_id) { "foo-123" }
7
+ let(:payment_source) {
8
+ described_class.new(
9
+ paypal_order_id: paypal_order_id,
10
+ payment_method: paypal_payment_method,
11
+ )
12
+ }
13
+ let(:payment) {
14
+ order.payments.create!(
15
+ payment_method: paypal_payment_method,
16
+ source: payment_source
17
+ )
18
+ }
19
+ let(:paypal_order_status) { "COMPLETED" }
20
+
21
+ before do
22
+ allow_any_instance_of(SolidusPaypalCommercePlatform::Client).to receive(:execute) do |_client, request|
23
+ expect(request).to be_a(SolidusPaypalCommercePlatform::Gateway::OrdersGetRequest) # rubocop:disable RSpec/ExpectInHook
24
+ OpenStruct.new(result: OpenStruct.new(status: paypal_order_status))
25
+ end
26
+ end
27
+
28
+ describe '#actions' do
29
+ context 'when the payment is not yet completed' do
30
+ it 'shows "capture" and "void"' do
31
+ expect(payment.actions).to contain_exactly("capture", "void")
32
+ end
33
+ end
34
+
35
+ context 'when the payment is completed and captured' do
36
+ before do
37
+ payment.update!(state: :completed, amount: 123)
38
+ payment_source.update!(capture_id: 1234)
39
+ end
40
+
41
+ it 'shows "credit"' do
42
+ expect(payment.actions).to contain_exactly("credit")
43
+ end
44
+
45
+ context 'when the PayPal order status is not COMPLETED' do
46
+ let(:paypal_order_status) { "FOOBAR" }
47
+
48
+ it 'hides the "credit" action' do
49
+ expect(payment.actions).not_to include("credit")
50
+ end
51
+ end
52
+ end
53
+
54
+ context 'when it cannot capture' do
55
+ it 'also cannot void' do
56
+ # One for "capture", and one for "void"
57
+ expect(payment_source).to receive(:can_capture?).and_return(false).twice
58
+ expect(payment.actions).not_to include("void")
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe SolidusPaypalCommercePlatform::PaypalAddress, type: :model do
4
+ let(:order) { create(:order) }
5
+ let(:original_address) { create(:address) }
6
+ let(:address) { create(:address) }
7
+ let(:params) {
8
+ {
9
+ updated_address: {
10
+ admin_area_1: address.state.abbr,
11
+ admin_area_2: address.city,
12
+ address_line_1: address.address1,
13
+ address_line_2: address.address2,
14
+ postal_code: address.zipcode,
15
+ country_code: address.country.iso
16
+ },
17
+ recipient: {
18
+ name: {
19
+ given_name: address.firstname,
20
+ surname: address.lastname
21
+ }
22
+ }
23
+ }
24
+ }
25
+
26
+ describe "#update_address" do
27
+ subject{ order.ship_address }
28
+
29
+ it "formats PayPal addresses correctly" do
30
+ order.ship_address = original_address
31
+
32
+ described_class.new(order).update(params)
33
+
34
+ expect(subject.state).to eq address.state
35
+ expect(subject.city).to eq address.city
36
+ expect(subject.address1).to eq address.address1
37
+ expect(subject.address2).to eq address.address2
38
+ expect(subject.zipcode).to eq address.zipcode
39
+ expect(subject.country).to eq address.country
40
+ expect(subject.firstname).to eq address.firstname
41
+ expect(subject.lastname).to eq address.lastname
42
+ expect(subject.phone).to eq original_address.phone
43
+ end
44
+
45
+ context "when no address exists" do
46
+ it "produce a valid address" do
47
+ order.ship_address = nil
48
+
49
+ described_class.new(order).update(params)
50
+
51
+ expect(subject).to be_present
52
+ end
53
+ end
54
+ end
55
+ end