solidus_paypal_commerce_platform 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.circleci/config.yml +41 -0
- data/.gem_release.yml +5 -0
- data/.github/stale.yml +17 -0
- data/.gitignore +20 -0
- data/.rspec +2 -0
- data/.rubocop.yml +56 -0
- data/Gemfile +33 -0
- data/LICENSE +26 -0
- data/README.md +173 -0
- data/Rakefile +6 -0
- data/app/assets/javascripts/spree/backend/solidus_paypal_commerce_platform.js +2 -0
- data/app/assets/javascripts/spree/backend/solidus_paypal_commerce_platform/namespace.js +1 -0
- data/app/assets/javascripts/spree/backend/solidus_paypal_commerce_platform/wizard.js +28 -0
- data/app/assets/javascripts/spree/frontend/solidus_paypal_commerce_platform.js +3 -0
- data/app/assets/javascripts/spree/frontend/solidus_paypal_commerce_platform/button_actions.js +191 -0
- data/app/assets/javascripts/spree/frontend/solidus_paypal_commerce_platform/buttons.js +26 -0
- data/app/assets/javascripts/spree/frontend/solidus_paypal_commerce_platform/namespace.js +1 -0
- data/app/assets/stylesheets/spree/backend/solidus_paypal_commerce_platform.css +4 -0
- data/app/assets/stylesheets/spree/frontend/solidus_paypal_commerce_platform.css +17 -0
- data/app/controllers/solidus_paypal_commerce_platform/orders_controller.rb +83 -0
- data/app/controllers/solidus_paypal_commerce_platform/payments_controller.rb +44 -0
- data/app/controllers/solidus_paypal_commerce_platform/paypal_orders_controller.rb +19 -0
- data/app/controllers/solidus_paypal_commerce_platform/shipping_rates_controller.rb +31 -0
- data/app/controllers/solidus_paypal_commerce_platform/wizard_controller.rb +47 -0
- data/app/decorators/solidus_paypal_commerce_platform/remove_required_phone_from_address.rb +13 -0
- data/app/helpers/solidus_paypal_commerce_platform/button_options_helper.rb +21 -0
- data/app/jobs/solidus_paypal_commerce_platform/application_job.rb +6 -0
- data/app/jobs/solidus_paypal_commerce_platform/webhook_job.rb +22 -0
- data/app/models/solidus_paypal_commerce_platform/gateway.rb +88 -0
- data/app/models/solidus_paypal_commerce_platform/payment_method.rb +75 -0
- data/app/models/solidus_paypal_commerce_platform/payment_source.rb +27 -0
- data/app/models/solidus_paypal_commerce_platform/paypal_address.rb +81 -0
- data/app/models/solidus_paypal_commerce_platform/paypal_order.rb +107 -0
- data/app/models/solidus_paypal_commerce_platform/pricing_options.rb +9 -0
- data/app/models/solidus_paypal_commerce_platform/wizard.rb +40 -0
- data/app/overrides/spree/admin/payment_methods/form/insert_email_verification_notification.rb +9 -0
- data/app/overrides/spree/admin/payment_methods/index/insert_setup_wizards.rb +17 -0
- data/app/overrides/spree/admin/payments/log_entries/add_paypal_debug_id.rb +9 -0
- data/app/overrides/spree/orders/edit/insert_cart_buttons.rb +9 -0
- data/app/overrides/spree/payments/payment/add_paypal_email_to_payment.rb +9 -0
- data/app/overrides/spree/products/cart_form/insert_product_buttons.rb +10 -0
- data/app/views/solidus_paypal_commerce_platform/admin/payment_methods/_available_to_users.html.erb +6 -0
- data/app/views/solidus_paypal_commerce_platform/admin/payment_methods/_paypal_wizard.html.erb +16 -0
- data/app/views/solidus_paypal_commerce_platform/admin/payment_methods/_setup_wizards.html.erb +16 -0
- data/app/views/solidus_paypal_commerce_platform/admin/payments/_log_entries.html.erb +32 -0
- data/bin/console +17 -0
- data/bin/rails +7 -0
- data/bin/rails-engine +13 -0
- data/bin/rails-sandbox +18 -0
- data/bin/rake +7 -0
- data/bin/sandbox +86 -0
- data/bin/setup +8 -0
- data/codecov.yml +14 -0
- data/config/locales/en.yml +37 -0
- data/config/routes.rb +12 -0
- data/db/migrate/20200521190038_add_paypal_commerce_platform_sources.rb +13 -0
- data/lib/generators/solidus_paypal_commerce_platform/install/install_generator.rb +38 -0
- data/lib/solidus_paypal_commerce_platform.rb +21 -0
- data/lib/solidus_paypal_commerce_platform/access_token_authorization_request.rb +21 -0
- data/lib/solidus_paypal_commerce_platform/client.rb +84 -0
- data/lib/solidus_paypal_commerce_platform/configuration.rb +64 -0
- data/lib/solidus_paypal_commerce_platform/engine.rb +45 -0
- data/lib/solidus_paypal_commerce_platform/factories.rb +14 -0
- data/lib/solidus_paypal_commerce_platform/fetch_merchant_credentials_request.rb +17 -0
- data/lib/solidus_paypal_commerce_platform/version.rb +5 -0
- data/lib/views/api/spree/api/payments/source_views/_paypal_commerce_platform.json.jbuilder +3 -0
- data/lib/views/backend/spree/admin/payments/source_forms/_paypal_commerce_platform.html.erb +1 -0
- data/lib/views/backend/spree/admin/payments/source_views/_paypal_commerce_platform.html.erb +18 -0
- data/lib/views/backend/spree/admin/shared/preference_fields/_paypal_select.html.erb +13 -0
- data/lib/views/frontend/solidus_paypal_commerce_platform/cart/_cart_buttons.html.erb +3 -0
- data/lib/views/frontend/solidus_paypal_commerce_platform/payments/_payment.html.erb +4 -0
- data/lib/views/frontend/solidus_paypal_commerce_platform/product/_product_buttons.html.erb +3 -0
- data/lib/views/frontend/spree/checkout/payment/_paypal_commerce_platform.html.erb +13 -0
- data/lib/views/frontend/spree/orders/payment/_paypal_commerce_platform.html.erb +17 -0
- data/lib/views/frontend/spree/products/payment/_paypal_commerce_platform.html.erb +15 -0
- data/solidus_paypal_commerce_platform.gemspec +39 -0
- data/spec/features/backend/new_payment_method_spec.rb +40 -0
- data/spec/features/frontend/cart_spec.rb +38 -0
- data/spec/features/frontend/checkout_spec.rb +81 -0
- data/spec/features/frontend/product_spec.rb +79 -0
- data/spec/jobs/solidus_paypal_commerce_platform/fixtures/CHECKOUT.ORDER.COMPLETED.v2.json +121 -0
- data/spec/jobs/solidus_paypal_commerce_platform/fixtures/CHECKOUT.ORDER.PROCESSED.v2.json +121 -0
- data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.COMPLETED.v1.json +50 -0
- data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.COMPLETED.v2.json +72 -0
- data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.DENIED.v1.json +50 -0
- data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.DENIED.v2.json +68 -0
- data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.REFUNDED.v1.json +51 -0
- data/spec/jobs/solidus_paypal_commerce_platform/fixtures/PAYMENT.CAPTURE.REFUNDED.v2.json +63 -0
- data/spec/jobs/solidus_paypal_commerce_platform/webhook_job_spec.rb +44 -0
- data/spec/lib/solidus_paypal_commerce_platform/client_spec.rb +21 -0
- data/spec/lib/solidus_paypal_commerce_platform/configuration_spec.rb +67 -0
- data/spec/models/solidus_paypal_commerce_platform/payment_method_spec.rb +102 -0
- data/spec/models/solidus_paypal_commerce_platform/payment_source_spec.rb +62 -0
- data/spec/models/solidus_paypal_commerce_platform/paypal_address_spec.rb +55 -0
- data/spec/models/solidus_paypal_commerce_platform/wizard_spec.rb +9 -0
- data/spec/requests/solidus_paypal_commerce_platform/orders_controller_spec.rb +36 -0
- data/spec/requests/solidus_paypal_commerce_platform/shipping_rates_controller_spec.rb +44 -0
- data/spec/requests/solidus_paypal_commerce_platform/wizard_controller_spec.rb +44 -0
- data/spec/spec_helper.rb +30 -0
- 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
|