paypal-sdk-rest-pmrb 1.8.0

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 (72) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +15 -0
  3. data/README.md +265 -0
  4. data/Rakefile +15 -0
  5. data/data/DigiCertHighAssuranceEVRootCA.pem +23 -0
  6. data/data/DigiCertSHA2ExtendedValidationServerCA.pem +28 -0
  7. data/data/paypal.crt +193 -0
  8. data/lib/generators/paypal/sdk/USAGE +3 -0
  9. data/lib/generators/paypal/sdk/install_generator.rb +17 -0
  10. data/lib/generators/paypal/sdk/templates/paypal.rb +2 -0
  11. data/lib/generators/paypal/sdk/templates/paypal.yml +29 -0
  12. data/lib/paypal-sdk-core.rb +38 -0
  13. data/lib/paypal-sdk-rest.rb +2 -0
  14. data/lib/paypal-sdk/core/api.rb +20 -0
  15. data/lib/paypal-sdk/core/api/base.rb +169 -0
  16. data/lib/paypal-sdk/core/api/data_types/array_with_block.rb +44 -0
  17. data/lib/paypal-sdk/core/api/data_types/base.rb +225 -0
  18. data/lib/paypal-sdk/core/api/data_types/enum.rb +26 -0
  19. data/lib/paypal-sdk/core/api/data_types/simple_types.rb +52 -0
  20. data/lib/paypal-sdk/core/api/ipn.rb +66 -0
  21. data/lib/paypal-sdk/core/api/rest.rb +177 -0
  22. data/lib/paypal-sdk/core/authentication.rb +66 -0
  23. data/lib/paypal-sdk/core/config.rb +253 -0
  24. data/lib/paypal-sdk/core/credential.rb +16 -0
  25. data/lib/paypal-sdk/core/credential/base.rb +27 -0
  26. data/lib/paypal-sdk/core/credential/certificate.rb +32 -0
  27. data/lib/paypal-sdk/core/credential/signature.rb +22 -0
  28. data/lib/paypal-sdk/core/credential/third_party/subject.rb +25 -0
  29. data/lib/paypal-sdk/core/credential/third_party/token.rb +39 -0
  30. data/lib/paypal-sdk/core/exceptions.rb +112 -0
  31. data/lib/paypal-sdk/core/logging.rb +50 -0
  32. data/lib/paypal-sdk/core/openid_connect.rb +140 -0
  33. data/lib/paypal-sdk/core/openid_connect/api.rb +50 -0
  34. data/lib/paypal-sdk/core/openid_connect/data_types.rb +73 -0
  35. data/lib/paypal-sdk/core/openid_connect/get_api.rb +28 -0
  36. data/lib/paypal-sdk/core/openid_connect/request_data_type.rb +52 -0
  37. data/lib/paypal-sdk/core/openid_connect/set_api.rb +36 -0
  38. data/lib/paypal-sdk/core/util.rb +11 -0
  39. data/lib/paypal-sdk/core/util/http_helper.rb +171 -0
  40. data/lib/paypal-sdk/core/util/oauth_signature.rb +64 -0
  41. data/lib/paypal-sdk/core/util/ordered_hash.rb +165 -0
  42. data/lib/paypal-sdk/rest.rb +39 -0
  43. data/lib/paypal-sdk/rest/api.rb +23 -0
  44. data/lib/paypal-sdk/rest/data_types.rb +2597 -0
  45. data/lib/paypal-sdk/rest/error_hash.rb +39 -0
  46. data/lib/paypal-sdk/rest/get_api.rb +20 -0
  47. data/lib/paypal-sdk/rest/request_data_type.rb +53 -0
  48. data/lib/paypal-sdk/rest/set_api.rb +42 -0
  49. data/lib/paypal-sdk/rest/version.rb +7 -0
  50. data/spec/README.md +22 -0
  51. data/spec/config/cacert.pem +171 -0
  52. data/spec/config/cert_key.pem +33 -0
  53. data/spec/config/paypal.yml +35 -0
  54. data/spec/config/sample_data.yml +3 -0
  55. data/spec/core/api/data_type_spec.rb +289 -0
  56. data/spec/core/api/rest_spec.rb +211 -0
  57. data/spec/core/config_spec.rb +192 -0
  58. data/spec/core/logging_spec.rb +28 -0
  59. data/spec/core/openid_connect_spec.rb +153 -0
  60. data/spec/invoice_examples_spec.rb +38 -0
  61. data/spec/log/http.log +175 -0
  62. data/spec/log/rest_http.log +0 -0
  63. data/spec/payments_examples_spec.rb +437 -0
  64. data/spec/payouts_examples_spec.rb +74 -0
  65. data/spec/rest/data_types_spec.rb +62 -0
  66. data/spec/rest/error_hash_spec.rb +83 -0
  67. data/spec/spec_helper.rb +37 -0
  68. data/spec/subscription_examples_spec.rb +227 -0
  69. data/spec/support/sample_data.rb +5 -0
  70. data/spec/web_profile_examples_spec.rb +106 -0
  71. data/spec/webhooks_examples_spec.rb +93 -0
  72. metadata +177 -0
@@ -0,0 +1,74 @@
1
+ require "spec_helper"
2
+
3
+ describe "Payouts", :integration => true do
4
+
5
+ PayoutVenmoAttributes = {
6
+ :sender_batch_header => {
7
+ :sender_batch_id => SecureRandom.hex(8)
8
+ },
9
+ :items => [
10
+ {
11
+ :recipient_type => 'PHONE',
12
+ :amount => {
13
+ :value => '1.0',
14
+ :currency => 'USD'
15
+ },
16
+ :note => 'Thanks for your patronage!',
17
+ :sender_item_id => '2014031400023',
18
+ :receiver => '5551232368',
19
+ :recipient_wallet => 'VENMO'
20
+ }
21
+ ]
22
+ }
23
+
24
+ PayoutAttributes = {
25
+ :sender_batch_header => {
26
+ :sender_batch_id => SecureRandom.hex(8),
27
+ :email_subject => 'You have a Payout!'
28
+ },
29
+ :items => [
30
+ {
31
+ :recipient_type => 'EMAIL',
32
+ :amount => {
33
+ :value => '1.0',
34
+ :currency => 'USD'
35
+ },
36
+ :note => 'Thanks for your patronage!',
37
+ :sender_item_id => '2014031400023',
38
+ :receiver => 'shirt-supplier-one@mail.com'
39
+ }
40
+ ]
41
+ }
42
+
43
+ it "create venmo payout" do
44
+ $payout = PayPal::SDK::REST::Payout.new(PayoutVenmoAttributes)
45
+ $payout_batch = $payout.create
46
+ expect($payout_batch).to be_truthy
47
+ end
48
+
49
+ it "create payout sync" do
50
+ $payout = PayPal::SDK::REST::Payout.new(PayoutAttributes)
51
+ $payout_batch = $payout.create(true)
52
+ expect($payout_batch).to be_truthy
53
+ end
54
+
55
+ it "get payout batch status" do
56
+ $result = PayPal::SDK::REST::Payout.get($payout_batch.batch_header.payout_batch_id)
57
+ expect($result).to be_a PayPal::SDK::REST::PayoutBatch
58
+ expect($payout_batch.batch_header.payout_batch_id).to eql $result.batch_header.payout_batch_id
59
+ end
60
+
61
+ it "get payout item status" do
62
+ $payout_item_details= PayoutItem.get($payout_batch.items[0].payout_item_id)
63
+ expect($payout_item_details).to be_a PayPal::SDK::REST::PayoutItemDetails
64
+ expect($payout_item_details.payout_item_id).to eql $payout_batch.items[0].payout_item_id
65
+ end
66
+
67
+ it "cancel unclaimed payouts" do
68
+ $payout_item_details= PayoutItem.cancel($payout_batch.items[0].payout_item_id)
69
+ expect($payout_item_details).to be_a PayPal::SDK::REST::PayoutItemDetails
70
+ expect($payout_item_details.payout_item_id).to eql $payout_batch.items[0].payout_item_id
71
+ expect($payout_item_details.transaction_status).to eql 'RETURNED'
72
+ end
73
+
74
+ end
@@ -0,0 +1,62 @@
1
+ module PayPal::SDK::REST::DataTypes
2
+ describe Base do
3
+ let(:error_object) {
4
+ {
5
+ "name" => "INVALID_EXPERIENCE_PROFILE_ID",
6
+ "message" => "The requested experience profile ID was not found",
7
+ "information_link" => "https://developer.paypal.com/docs/api/#INVALID_EXPERIENCE_PROFILE_ID",
8
+ "debug_id" => "1562931a79fd2"
9
+ }
10
+ }
11
+
12
+ context '#raise_error!' do
13
+ context 'when there is error' do
14
+ subject { described_class.new(error: error_object) }
15
+
16
+ it 'raises error on request with all API information' do
17
+ expect { subject.raise_error! }
18
+ .to raise_error { |err|
19
+ expect(err).to be_a(PayPal::SDK::Core::Exceptions::UnsuccessfulApiCall)
20
+ expect(err.message).to eq("The requested experience profile ID was not found")
21
+ expect(err.api_error).to eq(error_object)
22
+ }
23
+ end
24
+ end
25
+
26
+ context 'when there is no error' do
27
+ subject { described_class.new(error: nil) }
28
+
29
+ it { expect { subject.raise_error! }.not_to raise_error }
30
+ end
31
+ end
32
+
33
+ context '.raise_on_api_error' do
34
+ let(:klass) {
35
+ Class.new(described_class) do
36
+ def some_call
37
+ end
38
+
39
+ raise_on_api_error :some_call
40
+ end
41
+ }
42
+
43
+ subject { klass.new }
44
+
45
+ context 'when call is successful' do
46
+ before {
47
+ expect(subject).to receive(:some_call).and_return(true)
48
+ }
49
+ it { expect { subject.some_call! }.not_to raise_error }
50
+ end
51
+
52
+ context 'when call is unsuccessful' do
53
+ before {
54
+ expect(subject).to receive(:some_call).and_return(false)
55
+ expect(subject).to receive(:error).twice.and_return(error_object)
56
+ }
57
+
58
+ it { expect { subject.some_call! }.to raise_error(PayPal::SDK::Core::Exceptions::UnsuccessfulApiCall) }
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,83 @@
1
+ module PayPal::SDK::REST
2
+ describe ErrorHash do
3
+ it 'converts Hashes to ErrorHashes' do
4
+ hash = ErrorHash.convert({
5
+ nested_hash: { bing: 'bong' },
6
+ empty_array: [],
7
+ array_with_hashes: [
8
+ { foo: 'boo' },
9
+ { biz: 'boz' }
10
+ ],
11
+ array_without_hashes: [1, 2, 3],
12
+ nilly: nil,
13
+ stringy: 'cheese'
14
+ })
15
+
16
+ expect(hash).to be_a(ErrorHash)
17
+ expect(hash.nested_hash).to be_a(ErrorHash)
18
+ expect(hash.empty_array).to eq([])
19
+ expect(hash.array_with_hashes[0]).to be_a(ErrorHash)
20
+ expect(hash.array_with_hashes[1]).to be_a(ErrorHash)
21
+ expect(hash.array_without_hashes).to eq([1, 2, 3])
22
+ expect(hash.nilly).to be_nil
23
+ expect(hash.stringy).to eq('cheese')
24
+ end
25
+
26
+ it 'can access string keys as properties, strings, or symbols' do
27
+ hash = ErrorHash.convert({ 'foo' => 5 })
28
+ hash['boo'] = 'grue'
29
+
30
+ expect(hash.foo).to eq(5)
31
+ expect(hash['foo']).to eq(5)
32
+ expect(hash[:foo]).to eq(5)
33
+ expect(hash.boo).to eq('grue')
34
+ expect(hash['boo']).to eq('grue')
35
+ expect(hash[:boo]).to eq('grue')
36
+ end
37
+
38
+ it 'can access symbol keys as properties, strings, or symbols' do
39
+ hash = ErrorHash.convert({ :foo => 5 })
40
+ hash[:boo] = 'grue'
41
+
42
+ expect(hash.foo).to eq(5)
43
+ expect(hash['foo']).to eq(5)
44
+ expect(hash[:foo]).to eq(5)
45
+ expect(hash.boo).to eq('grue')
46
+ expect(hash['boo']).to eq('grue')
47
+ expect(hash[:boo]).to eq('grue')
48
+ end
49
+
50
+ it 'converts Hashes to ErrorHashes on assignment' do
51
+ hash = ErrorHash.new
52
+ hash['foo'] = { bing: 'bong' }
53
+
54
+ expect(hash['foo']).to be_a(ErrorHash)
55
+ expect(hash['foo'].bing).to eq('bong')
56
+ end
57
+
58
+ it 'converts Hashes inside of Arrays to ErrorHashes on assignment' do
59
+ hash = ErrorHash.new
60
+ hash['foo'] = [{ bing: 'bong' }]
61
+
62
+ expect(hash['foo'][0]).to be_a(ErrorHash)
63
+ expect(hash['foo'][0].bing).to eq('bong')
64
+ end
65
+
66
+ it "doesn't convert Hashes inside of Arrays if the first element of the array isn't a Hash" do
67
+ hash = ErrorHash.new
68
+ hash['foo'] = [100, { bing: 'bong' }]
69
+
70
+ expect(hash['foo'][1]).to be_a(Hash)
71
+ expect(hash['foo'][1]).not_to be_a(ErrorHash)
72
+ end
73
+
74
+ it 'gets and sets numbers and strings' do
75
+ hash = ErrorHash.new
76
+ hash['foo'] = 123
77
+ hash['boo'] = 'baa'
78
+
79
+ expect(hash['foo']).to eq(123)
80
+ expect(hash['boo']).to eq('baa')
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,37 @@
1
+ require 'bundler/setup'
2
+
3
+ if ENV['COVERAGE']
4
+ require 'simplecov'
5
+ require 'coveralls'
6
+ Coveralls.wear!
7
+ SimpleCov.start do
8
+ add_filter "/spec/"
9
+ end
10
+ end
11
+
12
+ Bundler.require :default, :test
13
+ PayPal::SDK::Core::Config.load(File.expand_path('../config/paypal.yml', __FILE__), 'test')
14
+
15
+ require 'paypal-sdk-rest'
16
+
17
+ include PayPal::SDK::REST
18
+ include PayPal::SDK::Core::Logging
19
+
20
+ require 'logger'
21
+ PayPal::SDK.load('spec/config/paypal.yml', 'test')
22
+ PayPal::SDK.logger = Logger.new(STDERR)
23
+
24
+ Dir[File.expand_path("../support/**/*.rb", __FILE__)].each {|f| require f }
25
+
26
+ # Set logger for http
27
+ http_log = File.open(File.expand_path('../log/http.log', __FILE__), "w")
28
+ Payment.api.http.set_debug_output(http_log)
29
+
30
+ RSpec.configure do |config|
31
+ config.filter_run_excluding :integration => true
32
+ config.filter_run_excluding :disabled => true
33
+ config.include SampleData
34
+ # config.include PayPal::SDK::REST::DataTypes
35
+ end
36
+
37
+ WebMock.allow_net_connect!
@@ -0,0 +1,227 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Subscription" do
4
+
5
+ PlanAttributes = {
6
+ "name" => "T-Shirt of the Month Club Plan",
7
+ "description" => "Template creation.",
8
+ "type" => "fixed",
9
+ "payment_definitions" => [
10
+ {
11
+ "name" => "Regular Payments",
12
+ "type" => "REGULAR",
13
+ "frequency" => "MONTH",
14
+ "frequency_interval" => "2",
15
+ "amount" => {
16
+ "value" => "100",
17
+ "currency" => "USD"
18
+ },
19
+ "cycles" => "12",
20
+ "charge_models" => [
21
+ {
22
+ "type" => "SHIPPING",
23
+ "amount" => {
24
+ "value" => "10",
25
+ "currency" => "USD"
26
+ }
27
+ },
28
+ {
29
+ "type" => "TAX",
30
+ "amount" => {
31
+ "value" => "12",
32
+ "currency" => "USD"
33
+ }
34
+ }
35
+ ]
36
+ }
37
+ ],
38
+ "merchant_preferences" => {
39
+ "setup_fee" => {
40
+ "value" => "1",
41
+ "currency" => "USD"
42
+ },
43
+ "return_url" => "http://www.return.com",
44
+ "cancel_url" => "http://www.cancel.com",
45
+ "auto_bill_amount" => "YES",
46
+ "initial_fail_amount_action" => "CONTINUE",
47
+ "max_fail_attempts" => "0"
48
+ }
49
+ }
50
+
51
+ AgreementAttributes = {
52
+ "name" => "T-Shirt of the Month Club Agreement",
53
+ "description" => "Agreement for T-Shirt of the Month Club Plan",
54
+ "start_date" => "2015-02-19T00:37:04Z",
55
+ "payer" => {
56
+ "payment_method" => "paypal"
57
+ },
58
+ "shipping_address" => {
59
+ "line1" => "111 First Street",
60
+ "city" => "Saratoga",
61
+ "state" => "CA",
62
+ "postal_code" => "95070",
63
+ "country_code" => "US"
64
+ }
65
+ }
66
+
67
+ describe "BillingPlan", :integration => true do
68
+ it "Create" do
69
+ # create access token and then create a plan
70
+ $api = API.new
71
+ plan = Plan.new(PlanAttributes.merge( :token => $api.token ))
72
+ expect(Plan.api).not_to eql plan.api
73
+ plan.create
74
+
75
+ # make sure the transaction was successful
76
+ $plan_id = plan.id
77
+ expect(plan.error).to be_nil
78
+ expect(plan.id).not_to be_nil
79
+ end
80
+
81
+ it "Update" do
82
+ # create a new plan to update
83
+ plan = Plan.new(PlanAttributes)
84
+ expect(plan.create).to be_truthy
85
+
86
+ # set up a patch request
87
+ patch = Patch.new
88
+ patch.op = "replace"
89
+ patch.path = "/";
90
+ patch.value = { :state => "ACTIVE" }
91
+
92
+ # the patch request should be successful
93
+ expect(plan.update( patch )).to be_truthy
94
+ end
95
+
96
+ it "List" do
97
+ # list all billing plans
98
+ plan_list = Plan.all
99
+ expect(plan_list.error).to be_nil
100
+ expect(plan_list.plans.count).to be > 1
101
+ end
102
+
103
+ it "Delete" do
104
+ # create a plan to delete
105
+ plan = Plan.new(PlanAttributes.merge( :token => $api.token ))
106
+ plan.create
107
+ plan_id = plan.id
108
+
109
+ # construct a patch object that will be used for deletion
110
+ patch = Patch.new
111
+ patch.op = "replace"
112
+ patch.path = "/"
113
+ patch.value = { "state" => "DELETED" }
114
+
115
+ # send delete request
116
+ plan.update(patch)
117
+
118
+ # make sure the plan has been deleted
119
+ plan = Plan.find(plan_id)
120
+ expect(plan.id).not_to eq plan_id
121
+ end
122
+ end
123
+
124
+ describe "BillingAgreement", :integration => true do
125
+
126
+ it "Create" do
127
+ # first, create an active plan to be added to agreement
128
+ api = API.new
129
+ plan = Plan.new(PlanAttributes)
130
+ expect(plan.create).to be_truthy
131
+
132
+ # first, create an agreement
133
+ $agreement = Agreement.new(AgreementAttributes)
134
+ $agreement.plan = Plan.new( :id => "P-1K47639161110773GYDKTWIA" )
135
+ $agreement.shipping_address = nil
136
+
137
+ # verify newly created agreement
138
+ expect($agreement.create).to be_truthy
139
+ expect($agreement.id).to be_nil
140
+ expect($agreement.token).not_to be_nil
141
+ expect($agreement.name).to eq("T-Shirt of the Month Club Agreement")
142
+ end
143
+
144
+ #####################################
145
+ # The following tests are disabled due to them requiring an active billing agreement or buyer's approval.
146
+ # Most of them require an agreement ID, which is returned after executing agreement.
147
+ # And agreement execution requires buyer's approval.
148
+ #####################################
149
+
150
+ xit "Execute" do
151
+ # Use this call to execute an agreement after the buyer approves it.
152
+ expect($agreement.execute).to be_truthy
153
+ end
154
+
155
+ xit "Get" do
156
+ # this call needs an agreement ID of the agreement to be retrieved
157
+ agreement = Agreement.find($agreement.id)
158
+ expect(agreement.id).to eq($agreement.id)
159
+ expect(agreement.description).to eq("Agreement for T-Shirt of the Month Club Plan")
160
+ expect(agreement.start_date).to eq("2015-02-19T00:37:04Z")
161
+ expect(agreement.plan).not_to be_nil
162
+ end
163
+
164
+ xit "Update" do
165
+ # get the agreement to update
166
+ api = API.new
167
+ plan = Plan.new(PlanAttributes)
168
+ expect(plan.create).to be_truthy
169
+
170
+ # first, create an agreement
171
+ agreement = Agreement.new(AgreementAttributes)
172
+ agreement.plan = Plan.new( :id => "P-1K47639161110773GYDKTWIA" )
173
+ expect(agreement.create).to be_truthy
174
+
175
+
176
+ # create an update for the agreement
177
+ random_string = (0...8).map { (65 + rand(26)).chr }.join
178
+ patch = Patch.new
179
+ patch.op = "replace"
180
+ patch.path = "/"
181
+ patch.value = { "description" => random_string }
182
+
183
+ # send update request
184
+ response = agreement.update(patch)
185
+
186
+ # verify the agreement update was successful
187
+ expect(response).to be_truthy
188
+ updated_agreement = Agreement.get($agreement.id)
189
+ expect(updated_agreement.id).to eq($agreement.id)
190
+ expect(random_string).to eq(updated_agreement.description)
191
+ end
192
+
193
+ xit "Suspend" do
194
+ # set the id of an active agreement here
195
+ agreement_id = ""
196
+ agreement = Agreement.find(agreement_id)
197
+
198
+ state_descriptor = AgreementStateDescriptor.new( :note => "Suspending the agreement" )
199
+ expect( agreement.suspend(state_descriptor) ).to be_truthy
200
+ end
201
+
202
+ xit "Reactivate" do
203
+ # set the id of a suspended agreement here
204
+ agreement_id = ""
205
+ agreement = Agreement.find(agreement_id)
206
+
207
+ state_descriptor = AgreementStateDescriptor.new( :note => "Re-activating the agreement" )
208
+ expect( agreement.re_activate(state_descriptor) ).to be_truthy
209
+ end
210
+
211
+ xit "Search" do
212
+ transactions = Agreement.transactions($agreement.id, "2015-01-01", "2015-01-10")
213
+ expect(transactions).not_to be_nil
214
+ expect(transactions.agreement_transaction_list).not_to be_empty
215
+ end
216
+
217
+ xit "Cancel" do
218
+ # set the id of an agreement here
219
+ agreement_id = ""
220
+ agreement = Agreement.find(agreement_id)
221
+
222
+ state_descriptor = AgreementStateDescriptor.new( :note => "Cancelling the agreement" )
223
+ expect( agreement.cancel(state_descriptor) ).to be_truthy
224
+ end
225
+
226
+ end
227
+ end