paypal-sdk-rest-pmrb 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
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