Skip to content

Instantly share code, notes, and snippets.

@urielhdz
Created March 5, 2025 15:19
Show Gist options
  • Save urielhdz/057ae041a2f1f4f27f7521250d0bb401 to your computer and use it in GitHub Desktop.
Save urielhdz/057ae041a2f1f4f27f7521250d0bb401 to your computer and use it in GitHub Desktop.
├── .github
└── ISSUE_TEMPLATE.md
├── .gitignore
├── .releasinator.rb
├── .rspec
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Gemfile
├── LICENSE
├── README.md
├── Rakefile
├── data
├── DigiCertHighAssuranceEVRootCA.pem
├── DigiCertSHA2ExtendedValidationServerCA.pem
└── paypal.crt
├── lib
├── generators
│ └── paypal
│ │ └── sdk
│ │ ├── USAGE
│ │ ├── install_generator.rb
│ │ └── templates
│ │ ├── paypal.rb
│ │ └── paypal.yml
├── paypal-sdk-core.rb
├── paypal-sdk-rest.rb
└── paypal-sdk
│ ├── core
│ ├── api.rb
│ ├── api
│ │ ├── base.rb
│ │ ├── data_types
│ │ │ ├── array_with_block.rb
│ │ │ ├── base.rb
│ │ │ ├── enum.rb
│ │ │ └── simple_types.rb
│ │ ├── ipn.rb
│ │ └── rest.rb
│ ├── authentication.rb
│ ├── config.rb
│ ├── credential.rb
│ ├── credential
│ │ ├── base.rb
│ │ ├── certificate.rb
│ │ ├── signature.rb
│ │ └── third_party
│ │ │ ├── subject.rb
│ │ │ └── token.rb
│ ├── exceptions.rb
│ ├── logging.rb
│ ├── openid_connect.rb
│ ├── openid_connect
│ │ ├── api.rb
│ │ ├── data_types.rb
│ │ ├── get_api.rb
│ │ ├── request_data_type.rb
│ │ └── set_api.rb
│ ├── util.rb
│ └── util
│ │ ├── http_helper.rb
│ │ ├── oauth_signature.rb
│ │ └── ordered_hash.rb
│ ├── rest.rb
│ └── rest
│ ├── api.rb
│ ├── data_types.rb
│ ├── error_hash.rb
│ ├── get_api.rb
│ ├── request_data_type.rb
│ ├── set_api.rb
│ └── version.rb
├── paypal-sdk-rest.gemspec
├── samples
├── Gemfile
├── README.md
├── app.rb
├── authorization
│ ├── capture.rb
│ ├── find.rb
│ ├── reauthorize.rb
│ └── void.rb
├── capture
│ ├── find.rb
│ └── refund.rb
├── config.ru
├── config
│ └── paypal.yml
├── invoice
│ ├── cancel.rb
│ ├── create.rb
│ ├── get.rb
│ ├── get_all.rb
│ ├── remind.rb
│ ├── send_invoice.rb
│ └── third_party_invoice.rb
├── invoice_template
│ ├── create.rb
│ ├── delete.rb
│ ├── get.rb
│ ├── get_all.rb
│ └── update.rb
├── notifications
│ ├── create.rb
│ ├── delete_webhook.rb
│ ├── get_all_webhooks.rb
│ ├── get_subscribed_webhooks_event_types.rb
│ ├── get_webhook.rb
│ ├── get_webhook_event.rb
│ ├── get_webhooks_event_types.rb
│ ├── resend_webhook_event.rb
│ ├── search_webhook_event.rb
│ ├── simulate_event.rb
│ ├── update_webhook.rb
│ └── verify_webhook_event.rb
├── payment
│ ├── all.rb
│ ├── create_future_payment.rb
│ ├── create_third_party_with_paypal.rb
│ ├── create_with_paypal.rb
│ ├── execute.rb
│ ├── find.rb
│ └── update.rb
├── payouts
│ ├── cancel.rb
│ ├── create.rb
│ ├── createSync.rb
│ ├── createVenmo.rb
│ ├── get_batch_status.rb
│ └── get_item_status.rb
├── public
│ └── images
│ │ ├── edt-format-source-button.png
│ │ └── play_button.png
├── runner.rb
├── sale
│ ├── find.rb
│ └── refund.rb
└── views
│ ├── display_hash.haml
│ └── index.haml
└── spec
├── README.md
├── config
├── cacert.pem
├── cert_key.pem
├── paypal.yml
└── sample_data.yml
├── core
├── api
│ ├── data_type_spec.rb
│ └── rest_spec.rb
├── config_spec.rb
├── logging_spec.rb
└── openid_connect_spec.rb
├── invoice_examples_spec.rb
├── log
└── .gitkeep
├── payments_examples_spec.rb
├── payouts_examples_spec.rb
├── rest
├── data_types_spec.rb
└── error_hash_spec.rb
├── spec_helper.rb
├── subscription_examples_spec.rb
├── support
└── sample_data.rb
├── web_profile_examples_spec.rb
└── webhooks_examples_spec.rb
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | <!-- ** General notice: if you have an API issue, see our [REST API issues](https://github.com/paypal/PayPal-REST-API-issues) repository, or contact [PayPal Tech Support](https://developer.paypal.com/support/). ** -->
2 | ### General information
3 |
4 | * SDK/Library version: <!-- Example: 4.7.2 -->
5 | * Environment: <!-- Is this issue in Sandbox or Production? -->
6 | * `PayPal-Debug-ID` values: <!-- Report PayPal-Debug-IDs from any logs -->
7 | * Language, language version, and OS: <!-- Example: Java 1.8.0_101-b13 on Ubuntu 16.10 -->
8 |
9 | ### Issue description
10 |
11 | <!-- To help us quickly reproduce your issue, include as many details as possible, such as logs, steps to reproduce, and so on. If the issue reports a new feature, follow the [user story](https://en.wikipedia.org/wiki/User_story) format to clearly describe the use case. -->
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.gem
3 | *.rbc
4 | *.log
5 | *.swp
6 | .bundle
7 | .config
8 | .yardoc
9 | samples/Gemfile.lock
10 | InstalledFiles
11 | _yardoc
12 | coverage
13 | doc/
14 | lib/bundler/man
15 | pkg
16 | rdoc
17 | spec/reports
18 | test/tmp
19 | test/version_tmp
20 | tmp
21 | .idea
22 | Gemfile.lock
23 |
--------------------------------------------------------------------------------
/.releasinator.rb:
--------------------------------------------------------------------------------
1 | #### releasinator config ####
2 | configatron.product_name = "PayPal Ruby SDK"
3 |
4 | # List of items to confirm from the person releasing. Required, but empty list is ok.
5 | configatron.prerelease_checklist_items = [
6 | "Sanity check the master branch."
7 | ]
8 |
9 | def validate_version_match()
10 | if 'v' + package_version() != @current_release.version
11 | Printer.fail("Package.json version #{package_version} does not match changelog version #{@current_release.version}.")
12 | abort()
13 | end
14 | Printer.success("Package.json version #{package_version} matches latest changelog version #{@current_release.version}.")
15 | end
16 |
17 | def validate_paths
18 | @validator.validate_in_path("jq")
19 | end
20 |
21 | configatron.custom_validation_methods = [
22 | method(:validate_paths),
23 | method(:validate_version_match)
24 | ]
25 |
26 | def build_method
27 | CommandProcessor.command("bundle exec rspec", live_output=true)
28 | # at present functional tests are failing , so we are skipping functional test execution temporally
29 | #CommandProcessor.command("bundle exec rspec --tag integration", live_output=true)
30 | Rake::Task["build"].invoke
31 | Rake::Task["release:guard_clean"].invoke
32 | end
33 |
34 | # The command that builds the sdk. Required.
35 | configatron.build_method = method(:build_method)
36 |
37 | def publish_to_package_manager(version)
38 | Rake::Task["release:rubygem_push"].invoke
39 | end
40 |
41 | # The method that publishes the sdk to the package manager. Required.
42 | configatron.publish_to_package_manager_method = method(:publish_to_package_manager)
43 |
44 |
45 | def wait_for_package_manager(version)
46 | CommandProcessor.wait_for("wget -U \"non-empty-user-agent\" -qO- https://rubygems.org/gems/paypal-sdk-rest/versions/#{package_version} | cat")
47 | end
48 |
49 | # The method that waits for the package manager to be done. Required
50 | configatron.wait_for_package_manager_method = method(:wait_for_package_manager)
51 |
52 | # Whether to publish the root repo to GitHub. Required.
53 | configatron.release_to_github = true
54 |
55 | def package_version()
56 | File.open("lib/paypal-sdk/rest/version.rb", 'r') do |f|
57 | f.each_line do |line|
58 | if line.match (/VERSION = \"\d*\.\d*\.\d*\"/)
59 | return line.strip.split('=')[1].strip.split('"')[1]
60 | end
61 | end
62 | end
63 | end
64 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --color
2 | --require spec_helper
3 | --tty
4 | --format documentation
5 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 | dist: trusty
3 | language: ruby
4 | rvm:
5 | - "2.0.0"
6 | - "2.2.5"
7 | - "2.3.1"
8 | script: "bundle exec rspec"
9 |
10 | sudo: false
11 |
12 | notifications:
13 | recipients:
14 | - [email protected]
15 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | PayPal Ruby SDK release notes
2 | =============================
3 |
4 | v1.7.4
5 | ------
6 | * Update Payouts API for latest schema [#388](https://github.com/paypal/PayPal-Ruby-SDK/pull/388).
7 |
8 | v1.7.3
9 | ------
10 | * Adding disputes in data_types.rb.
11 | * Fix issue `no implicit conversion of Array into String` [#363](https://github.com/paypal/PayPal-Ruby-SDK/pull/363).
12 |
13 | v1.7.2
14 | ------
15 | * Remove logging of unknown fields.
16 | * Fix issue with `require net/http` [#331](https://github.com/paypal/PayPal-Ruby-SDK/pull/331). Thanks Borzik.
17 |
18 | v1.7.1
19 | ------
20 | * Use `NET` library to fetch webhook ceritifcate. Thanks Kramer.
21 |
22 | v1.7.0
23 | ------
24 | * Add `invoice_address` field on Invoice's BillingInfo and ShippingInfo types [#322](https://github.com/paypal/PayPal-Ruby-SDK/pull/322) and [#326](https://github.com/paypal/PayPal-Ruby-SDK/pull/326).
25 | * Fix issue with capitalization for encType in Links attribute [#314](https://github.com/paypal/PayPal-Ruby-SDK/issues/314).
26 |
27 | v1.6.1
28 | ------
29 | * Fix issue with wrong method declared for `WebhookEvent.find` and `WebHookEvent.all` [#270](https://github.com/paypal/PayPal-Ruby-SDK/pull/270) and [#306](https://github.com/paypal/PayPal-Ruby-SDK/pull/306).
30 | * Fix issue with invalid JSON handling. [#302](https://github.com/paypal/PayPal-Ruby-SDK/issues/302).
31 | * Fix issue with missing `ResourceInvalid` type [#298](https://github.com/paypal/PayPal-Ruby-SDK/issues/298).
32 | * Fix issue with `ErrorHash.convert` for nested hashes [#257](https://github.com/paypal/PayPal-Ruby-SDK/issues/257).
33 | * Update code to find PayPal approval redirect URL using relationship identifier instead of by method.
34 |
35 | v1.6.0
36 | ------
37 | * Update Payments API for latest schema [#246](https://github.com/paypal/PayPal-Ruby-SDK/pull/246).
38 | * Changed no method found log to debug [#245](https://github.com/paypal/PayPal-Ruby-SDK/pull/245).
39 |
40 | v1.5.0
41 | ------
42 | * Update Payments Experience API for latest schema [#242](https://github.com/paypal/PayPal-Ruby-SDK/pull/242).
43 | * Update Webhooks for latest schema [#238](https://github.com/paypal/PayPal-Ruby-SDK/pull/238).
44 | * Flatten error hashes [#240](https://github.com/paypal/PayPal-Ruby-SDK/pull/240).
45 | * Use SecureRandom instead of uuidtools [#237](https://github.com/paypal/PayPal-Ruby-SDK/pull/237).
46 | * Update Invoicing Templates for latest schema [#235](https://github.com/paypal/PayPal-Ruby-SDK/pull/235).
47 | * Update OpenID Connect signin URL [#225](https://github.com/paypal/PayPal-Ruby-SDK/pull/225).
48 |
49 | v1.4.9
50 | ------
51 | * Use String.force_encoding to force conversion to UTF-8 [#220](https://github.com/paypal/PayPal-Ruby-SDK/pull/220).
52 | * Fix WebProfile GET/retrieve to return a WebProfile instance [#219](https://github.com/paypal/PayPal-Ruby-SDK/pull/219).
53 |
54 | v1.4.8
55 | ------
56 | * Added (optional) exception raising on API errors [#216](https://github.com/paypal/PayPal-Ruby-SDK/pull/216).
57 | * Use UTF-8 as the character set when generating CRC32 checksum when validating webhook events [#215](https://github.com/paypal/PayPal-Ruby-SDK/pull/215).
58 | * Added Payment convenience methods [#212](https://github.com/paypal/PayPal-Ruby-SDK/pull/212).
59 |
60 | v1.4.7
61 | ------
62 | * Enabled third party invoicing for all invoicing API operations [#209](https://github.com/paypal/PayPal-Ruby-SDK/pull/209).
63 |
64 | v1.4.6
65 | ------
66 | * Enabled Third Party Invoicing [#204](https://github.com/paypal/PayPal-Ruby-SDK/pull/204).
67 | * Enable Passing Custom Headers [#197](https://github.com/paypal/PayPal-Ruby-SDK/pull/197).
68 |
69 | v1.4.5
70 | ------
71 | * Log error responses in live mode [#192](https://github.com/paypal/PayPal-Ruby-SDK/pull/192).
72 | * Fixed patch_requests by Array in update method of CreditCard [#193](https://github.com/paypal/PayPal-Ruby-SDK/pull/193).
73 |
74 | v1.4.4
75 | ------
76 | * Update on Invoicing API changes [#189](https://github.com/paypal/PayPal-Ruby-SDK/pull/189).
77 |
78 | v1.4.3
79 | ------
80 | * Fix issue where uninitialized constant PayPal::SDK::Core::API::Merchant occurs for merchant-sdk-ruby issue [#184](https://github.com/paypal/PayPal-Ruby-SDK/issues/184).
81 |
82 | v1.4.2
83 | ------
84 | * Fix test category [#178](https://github.com/paypal/PayPal-Ruby-SDK/issues/178).
85 | * Delete code irrelevant to REST APIs [#179](https://github.com/paypal/PayPal-Ruby-SDK/issues/179).
86 | * Fix OpenSSL::X509::StoreError: system lib error for webhook validation [#170](https://github.com/paypal/PayPal-Ruby-SDK/issues/170).
87 | * Fix incorrect warning message when using DEBUG logging on live [#182](https://github.com/paypal/PayPal-Ruby-SDK/pull/182).
88 |
89 | v1.4.1
90 | ------
91 | * Fix Webhook common name verification.
92 |
93 | v1.4.0
94 | ------
95 | * Fix CreditCard.update().
96 | * Payment API support.
97 | * Updated TLS warning message.
98 |
99 | v1.3.4
100 | ------
101 | * Fix payment.update() [#163](https://github.com/paypal/PayPal-Ruby-SDK/issues/163).
102 | * Include openssl version in user-agent header.
103 | * Add TLS v1.2 support.
104 |
105 | v1.3.3
106 | ------
107 | * Added failover for capturing debug ID.
108 | * Enabled verbose payload logging [#146](https://github.com/paypal/PayPal-Ruby-SDK/issues/146).
109 | * Removed `time_updated` field in agreement_transaction per [API change](https://developer.paypal.com/webapps/developer/docs/api/#agreementtransaction-object).
110 | * Removed `payment_details` field in invoice per [API change](https://developer.paypal.com/webapps/developer/docs/api/#invoice-object).
111 | * Added `payment_options` field to Transaction per [API change](https://developer.paypal.com/webapps/developer/docs/api/#transaction-object).
112 | * Added secure logging to avoid logging confidential data (e.g., credit card number).
113 |
114 | v1.3.2
115 | ------
116 | * Fixed webprofile.create().
117 | * Fixed webprofile.get_list().
118 | * Updated webprofile test cases.
119 |
120 | v1.3.1
121 | ------
122 | * Added CreditCard list() support.
123 | * Added request/response body debugging statements.
124 | * Fixed future payment support, moved sample code, and added docs [#137](https://github.com/paypal/PayPal-Ruby-SDK/issues/137).
125 |
126 | v1.3.0 - June 30, 2015
127 | ----------------------
128 | * Added Webhook validation.
129 |
130 | v1.2.2 - June 17, 2015
131 | ---------------------
132 | * Fixed NameError due to underscore in variable name.
133 | * Fixed Vault endpoints.
134 |
135 | v1.2.1 - May 21, 2015
136 | --------------------
137 | * Paypal-Debug-Id printed for any exception.
138 |
139 | v1.2.0 - March 3, 2015
140 | ----------------------
141 | * Webhook management API support added.
142 |
143 | v1.1.2 - March 3, 2015
144 | ----------------------
145 | * Updated payment data models.
146 |
147 | v1.1.1 - February 5, 2015
148 | -------------------------
149 | * Packaged paypal cert in gem.
150 |
151 | v1.1.0 - February 4, 2015
152 | ------------------------
153 | * Added Payouts support.
154 | * Improved sample page layout.
155 |
156 | v1.0.0 - January 27, 2015
157 | -----------------------
158 | * Merged sdk-core-ruby with paypal-ruby-sdk.
159 |
160 | v0.10.0 - January 7, 2015
161 | ------------------------
162 | * Added subscription (billing plan and agreement) support.
163 |
164 | v0.9.1 - December 19, 2014
165 | -------------------------
166 | * Separated out extended data types (future payment).
167 |
168 | v0.9.0 - December 15, 2014
169 | -------------------------
170 | * Added payment-experience (web profiles) support.
171 | * Added test execution guide.
172 |
173 | v0.8.0 - December 11, 2014
174 | -------------------------
175 | * Added order/auth/capture support.
176 | * Grouped tests in 2 categories: unit tests, integration(functional) tests.
177 | * Disabled some tests that involve manual steps (e.g., log in to PayPal website).
178 |
179 | v0.7.3 - November 21, 2014
180 | -------------------------
181 | * Changed Correlation ID header for future payment.
182 | * Added data model for Order/Auth/Capture.
183 |
184 | v0.7.2 - October 20, 2014
185 | ------------------------
186 | * Added Order support.
187 |
188 | v0.7.1 - October 8, 2014
189 | -----------------------
190 | * Added Auth support.
191 |
192 | v0.7.0 - July 1, 2014
193 | --------------------
194 | * Added future payment support.
195 |
196 | v0.6.1 - Apr 04, 2014
197 | --------------------
198 | * Added support for Invoice APIs.
199 |
200 | v0.6.0 - May 30, 2013
201 | --------------------
202 | * Added support for Auth and Capture APIs.
203 |
204 | v0.5.1 - Apr 26, 2013
205 | --------------------
206 | * Update core version to 0.2.3 for OpenID Connect.
207 |
208 | v0.5.0 - Mar 07, 2013
209 | --------------------
210 | * Initial Release.
211 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contribute to the PayPal Ruby SDK
2 |
3 | ### *Pull requests are welcome!*
4 |
5 |
6 | General Guidelines
7 | ------------------
8 |
9 | * **Code style.** Please follow local code style. Ask if you're unsure.
10 | * **No warnings.** All generated code must compile without warnings.
11 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gemspec
4 |
5 | #gem 'paypal-sdk-core', :git => "https://github.com/paypal/sdk-core-ruby.git"
6 |
7 | gem 'rake', :require => false
8 |
9 | group :test do
10 | gem 'simplecov', :require => false
11 | gem 'rspec'
12 | gem 'webmock'
13 | end
14 |
15 | gem 'releasinator', '~> 0.6'
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The PayPal Ruby SDK is released under the following license:
2 |
3 | Copyright (c) 2013-2016 PAYPAL, INC.
4 |
5 | SDK LICENSE
6 |
7 | NOTICE TO USER: PayPal, Inc. is providing the Software and Documentation for use under the terms of
8 | this Agreement. Any use, reproduction, modification or distribution of the Software or Documentation,
9 | or any derivatives or portions hereof, constitutes your acceptance of this Agreement.
10 |
11 | As used in this Agreement, "PayPal" means PayPal, Inc. "Software" means the software code accompanying
12 | this agreement. "Documentation" means the documents, specifications and all other items accompanying
13 | this Agreement other than the Software.
14 |
15 | 1. LICENSE GRANT Subject to the terms of this Agreement, PayPal hereby grants you a non-exclusive,
16 | worldwide, royalty free license to use, reproduce, prepare derivative works from, publicly display,
17 | publicly perform, distribute and sublicense the Software for any purpose, provided the copyright notice
18 | below appears in a conspicuous location within the source code of the distributed Software and this
19 | license is distributed in the supporting documentation of the Software you distribute. Furthermore,
20 | you must comply with all third party licenses in order to use the third party software contained in the
21 | Software.
22 |
23 | Subject to the terms of this Agreement, PayPal hereby grants you a non-exclusive, worldwide, royalty free
24 | license to use, reproduce, publicly display, publicly perform, distribute and sublicense the Documentation
25 | for any purpose. You may not modify the Documentation.
26 |
27 | No title to the intellectual property in the Software or Documentation is transferred to you under the
28 | terms of this Agreement. You do not acquire any rights to the Software or the Documentation except as
29 | expressly set forth in this Agreement.
30 |
31 | If you choose to distribute the Software in a commercial product, you do so with the understanding that
32 | you agree to defend, indemnify and hold harmless PayPal and its suppliers against any losses, damages and
33 | costs arising from the claims, lawsuits or other legal actions arising out of such distribution. You may
34 | distribute the Software in object code form under your own license, provided that your license agreement:
35 |
36 | (a) complies with the terms and conditions of this license agreement;
37 |
38 | (b) effectively disclaims all warranties and conditions, express or implied, on behalf of PayPal;
39 |
40 | (c) effectively excludes all liability for damages on behalf of PayPal;
41 |
42 | (d) states that any provisions that differ from this Agreement are offered by you alone and not PayPal; and
43 |
44 | (e) states that the Software is available from you or PayPal and informs licensees how to obtain it in a
45 | reasonable manner on or through a medium customarily used for software exchange.
46 |
47 | 2. DISCLAIMER OF WARRANTY
48 | PAYPAL LICENSES THE SOFTWARE AND DOCUMENTATION TO YOU ONLY ON AN "AS IS" BASIS WITHOUT WARRANTIES OR CONDITIONS
49 | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY WARRANTIES OR CONDITIONS OF TITLE,
50 | NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. PAYPAL MAKES NO WARRANTY THAT THE
51 | SOFTWARE OR DOCUMENTATION WILL BE ERROR-FREE. Each user of the Software or Documentation is solely responsible
52 | for determining the appropriateness of using and distributing the Software and Documentation and assumes all
53 | risks associated with its exercise of rights under this Agreement, including but not limited to the risks and
54 | costs of program errors, compliance with applicable laws, damage to or loss of data, programs, or equipment,
55 | and unavailability or interruption of operations. Use of the Software and Documentation is made with the
56 | understanding that PayPal will not provide you with any technical or customer support or maintenance. Some
57 | states or jurisdictions do not allow the exclusion of implied warranties or limitations on how long an implied
58 | warranty may last, so the above limitations may not apply to you. To the extent permissible, any implied
59 | warranties are limited to ninety (90) days.
60 |
61 |
62 | 3. LIMITATION OF LIABILITY
63 | PAYPAL AND ITS SUPPLIERS SHALL NOT BE LIABLE FOR LOSS OR DAMAGE ARISING OUT OF THIS AGREEMENT OR FROM THE USE
64 | OF THE SOFTWARE OR DOCUMENTATION. IN NO EVENT WILL PAYPAL OR ITS SUPPLIERS BE LIABLE TO YOU OR ANY THIRD PARTY
65 | FOR ANY DIRECT, INDIRECT, CONSEQUENTIAL, INCIDENTAL, OR SPECIAL DAMAGES INCLUDING LOST PROFITS, LOST SAVINGS,
66 | COSTS, FEES, OR EXPENSES OF ANY KIND ARISING OUT OF ANY PROVISION OF THIS AGREEMENT OR THE USE OR THE INABILITY
67 | TO USE THE SOFTWARE OR DOCUMENTATION, HOWEVER CAUSED AND UNDER ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
68 | STRICT LIABILITY OR TORT INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
69 | PAYPAL'S AGGREGATE LIABILITY AND THAT OF ITS SUPPLIERS UNDER OR IN CONNECTION WITH THIS AGREEMENT SHALL BE
70 | LIMITED TO THE AMOUNT PAID BY YOU FOR THE SOFTWARE AND DOCUMENTATION.
71 |
72 | 4. TRADEMARK USAGE
73 | PayPal is a trademark PayPal, Inc. in the United States and other countries. Such trademarks may not be used
74 | to endorse or promote any product unless expressly permitted under separate agreement with PayPal.
75 |
76 | 5. TERM
77 | Your rights under this Agreement shall terminate if you fail to comply with any of the material terms or
78 | conditions of this Agreement and do not cure such failure in a reasonable period of time after becoming
79 | aware of such noncompliance. If all your rights under this Agreement terminate, you agree to cease use
80 | and distribution of the Software and Documentation as soon as reasonably practicable.
81 |
82 | 6. GOVERNING LAW AND JURISDICTION. This Agreement is governed by the statutes and laws of the State of
83 | California, without regard to the conflicts of law principles thereof. If any part of this Agreement is
84 | found void and unenforceable, it will not affect the validity of the balance of the Agreement, which shall
85 | remain valid and enforceable according to its terms. Any dispute arising out of or related to this Agreement
86 | shall be brought in the courts of Santa Clara County, California, USA.
87 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require "bundler/gem_tasks"
2 |
3 | # release will instead be declared by the releasinator
4 | Rake::Task["release"].clear
5 |
6 | spec = Gem::Specification.find_by_name 'releasinator'
7 | load "#{spec.gem_dir}/lib/tasks/releasinator.rake"
8 |
9 | desc "Run tests"
10 | task :rspec do
11 | cmd = "bundle exec rspec -f d"
12 | system(cmd) || raise("#{cmd} failed")
13 | end
14 |
15 | task :default => :rspec
16 |
--------------------------------------------------------------------------------
/data/DigiCertHighAssuranceEVRootCA.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
3 | MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
4 | d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
5 | ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
6 | MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
7 | LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
8 | RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
9 | +9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
10 | PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
11 | xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
12 | Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
13 | hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
14 | EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
15 | MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
16 | FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
17 | nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
18 | eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
19 | hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
20 | Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
21 | vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
22 | +OkuE6N36B9K
23 | -----END CERTIFICATE-----
--------------------------------------------------------------------------------
/data/DigiCertSHA2ExtendedValidationServerCA.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIEtjCCA56gAwIBAgIQDHmpRLCMEZUgkmFf4msdgzANBgkqhkiG9w0BAQsFADBs
3 | MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
4 | d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
5 | ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowdTEL
6 | MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
7 | LmRpZ2ljZXJ0LmNvbTE0MDIGA1UEAxMrRGlnaUNlcnQgU0hBMiBFeHRlbmRlZCBW
8 | YWxpZGF0aW9uIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
9 | ggEBANdTpARR+JmmFkhLZyeqk0nQOe0MsLAAh/FnKIaFjI5j2ryxQDji0/XspQUY
10 | uD0+xZkXMuwYjPrxDKZkIYXLBxA0sFKIKx9om9KxjxKws9LniB8f7zh3VFNfgHk/
11 | LhqqqB5LKw2rt2O5Nbd9FLxZS99RStKh4gzikIKHaq7q12TWmFXo/a8aUGxUvBHy
12 | /Urynbt/DvTVvo4WiRJV2MBxNO723C3sxIclho3YIeSwTQyJ3DkmF93215SF2AQh
13 | cJ1vb/9cuhnhRctWVyh+HA1BV6q3uCe7seT6Ku8hI3UarS2bhjWMnHe1c63YlC3k
14 | 8wyd7sFOYn4XwHGeLN7x+RAoGTMCAwEAAaOCAUkwggFFMBIGA1UdEwEB/wQIMAYB
15 | Af8CAQAwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF
16 | BQcDAjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp
17 | Z2ljZXJ0LmNvbTBLBgNVHR8ERDBCMECgPqA8hjpodHRwOi8vY3JsNC5kaWdpY2Vy
18 | dC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMD0GA1UdIAQ2
19 | MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5j
20 | b20vQ1BTMB0GA1UdDgQWBBQ901Cl1qCt7vNKYApl0yHU+PjWDzAfBgNVHSMEGDAW
21 | gBSxPsNpA/i/RwHUmCYaCALvY2QrwzANBgkqhkiG9w0BAQsFAAOCAQEAnbbQkIbh
22 | hgLtxaDwNBx0wY12zIYKqPBKikLWP8ipTa18CK3mtlC4ohpNiAexKSHc59rGPCHg
23 | 4xFJcKx6HQGkyhE6V6t9VypAdP3THYUYUN9XR3WhfVUgLkc3UHKMf4Ib0mKPLQNa
24 | 2sPIoc4sUqIAY+tzunHISScjl2SFnjgOrWNoPLpSgVh5oywM395t6zHyuqB8bPEs
25 | 1OG9d4Q3A84ytciagRpKkk47RpqF/oOi+Z6Mo8wNXrM9zwR4jxQUezKcxwCmXMS1
26 | oVWNWlZopCJwqjyBcdmdqEU79OX2olHdx3ti6G8MdOu42vi/hw15UJGQmxg7kVkn
27 | 8TUoE6smftX3eg==
28 | -----END CERTIFICATE-----
--------------------------------------------------------------------------------
/lib/generators/paypal/sdk/USAGE:
--------------------------------------------------------------------------------
1 | To copy a PayPal SDK default configuration and initializer to your Rails App.
2 |
3 | rails g paypal-sdk:install
4 |
--------------------------------------------------------------------------------
/lib/generators/paypal/sdk/install_generator.rb:
--------------------------------------------------------------------------------
1 | module Paypal
2 | module Sdk
3 | module Generators
4 | class InstallGenerator < Rails::Generators::Base
5 | source_root File.expand_path('../templates', __FILE__)
6 |
7 | def copy_config_file
8 | copy_file "paypal.yml", "config/paypal.yml"
9 | end
10 |
11 | def copy_initializer_file
12 | copy_file "paypal.rb", "config/initializers/paypal.rb"
13 | end
14 | end
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/lib/generators/paypal/sdk/templates/paypal.rb:
--------------------------------------------------------------------------------
1 | PayPal::SDK.load("config/paypal.yml", Rails.env)
2 | PayPal::SDK.logger = Rails.logger
3 |
--------------------------------------------------------------------------------
/lib/generators/paypal/sdk/templates/paypal.yml:
--------------------------------------------------------------------------------
1 | test: &default
2 |
3 | # Credentials for REST APIs
4 | client_id: EBWKjlELKMYqRNQ6sYvFo64FtaRLRR5BdHEESmha49TM
5 | client_secret: EO422dn3gQLgDbuwqTjzrFgFtaRLRR5BdHEESmha49TM
6 |
7 | # Mode can be 'live' or 'sandbox'
8 | mode: sandbox
9 |
10 | # Credentials for Classic APIs
11 | app_id: APP-80W284485P519543T
12 | username: jb-us-seller_api1.paypal.com
13 | password: WX4WTU3S8MY44S7F
14 | signature: AFcWxV21C7fd0v3bYYYRCpSSRl31A7yDhhsPUU2XhtMoZXsWHFxu-RWy
15 | # # With Certificate
16 | # cert_path: "config/cert_key.pem"
17 | sandbox_email_address: [email protected]
18 |
19 | # # IP Address
20 | # ip_address: 127.0.0.1
21 | # # HTTP Proxy
22 | # http_proxy: http://proxy-ipaddress:3129/
23 |
24 | development:
25 | <<: *default
26 |
27 | production:
28 | <<: *default
29 | mode: live
30 |
--------------------------------------------------------------------------------
/lib/paypal-sdk-core.rb:
--------------------------------------------------------------------------------
1 | module PayPal
2 | module SDK
3 | module Core
4 |
5 | autoload :VERSION, "paypal-sdk/rest/version"
6 | autoload :Config, "paypal-sdk/core/config"
7 | autoload :Configuration, "paypal-sdk/core/config"
8 | autoload :Logging, "paypal-sdk/core/logging"
9 | autoload :Authentication, "paypal-sdk/core/authentication"
10 | autoload :Exceptions, "paypal-sdk/core/exceptions"
11 | autoload :OpenIDConnect, "paypal-sdk/core/openid_connect"
12 | autoload :API, "paypal-sdk/core/api"
13 | autoload :Util, "paypal-sdk/core/util"
14 | autoload :Credential, "paypal-sdk/core/credential"
15 |
16 | end
17 |
18 | autoload :OpenIDConnect, "paypal-sdk/core/openid_connect"
19 |
20 | class << self
21 | def configure(options = {}, &block)
22 | Core::Config.configure(options, &block)
23 | end
24 |
25 | def load(*args)
26 | Core::Config.load(*args)
27 | end
28 |
29 | def logger
30 | Core::Config.logger
31 | end
32 |
33 | def logger=(log)
34 | Core::Config.logger = log
35 | end
36 | end
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/lib/paypal-sdk-rest.rb:
--------------------------------------------------------------------------------
1 | require "paypal-sdk/rest"
2 |
3 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/api.rb:
--------------------------------------------------------------------------------
1 | module PayPal
2 | module SDK
3 | module Core
4 | module API
5 | autoload :Base, "paypal-sdk/core/api/base"
6 | autoload :Merchant, "paypal-sdk/core/api/merchant"
7 | autoload :Platform, "paypal-sdk/core/api/platform"
8 | autoload :REST, "paypal-sdk/core/api/rest"
9 | autoload :IPN, "paypal-sdk/core/api/ipn"
10 |
11 | module DataTypes
12 | autoload :Base, "paypal-sdk/core/api/data_types/base"
13 | autoload :Enum, "paypal-sdk/core/api/data_types/enum"
14 | autoload :SimpleTypes, "paypal-sdk/core/api/data_types/simple_types"
15 | autoload :ArrayWithBlock, "paypal-sdk/core/api/data_types/array_with_block"
16 | end
17 | end
18 | end
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/api/base.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk/rest/version'
2 |
3 | module PayPal::SDK::Core
4 |
5 | module API
6 | # API class provide default functionality for accessing the API web services.
7 | # == Example
8 | # api = API::Base.new("AdaptivePayments")
9 | # response = api.request("GetPaymentOptions", "")
10 | class Base
11 |
12 | include Util::HTTPHelper
13 |
14 | attr_accessor :http, :uri, :service_name
15 |
16 | DEFAULT_API_MODE = :sandbox
17 | API_MODES = [ :live, :sandbox ]
18 |
19 | # Initialize API object
20 | # === Argument
21 | # * <tt>service_name</tt> -- (Optional) Service name
22 | # * <tt>environment</tt> -- (Optional) Configuration environment to load
23 | # * <tt>options</tt> -- (Optional) Override configuration.
24 | # === Example
25 | # new("AdaptivePayments")
26 | # new("AdaptivePayments", :development)
27 | # new(:wsdl_service) # It load wsdl_service configuration
28 | def initialize(service_name = "", environment = nil, options = {})
29 | unless service_name.is_a? String
30 | environment, options, service_name = service_name, environment || {}, ""
31 | end
32 | @service_name = service_name
33 | set_config(environment, options)
34 | end
35 |
36 | def uri
37 | @uri ||=
38 | begin
39 | uri = URI.parse("#{service_endpoint}/#{service_name}")
40 | uri.path = uri.path.gsub(/\/+/, "/")
41 | uri
42 | end
43 | end
44 |
45 | def http
46 | @http ||= create_http_connection(uri)
47 | end
48 |
49 | # Override set_config method to create http connection on changing the configuration.
50 | def set_config(*args)
51 | @http = @uri = nil
52 | super
53 | end
54 |
55 | # Get configured API mode( sandbox or live)
56 | def api_mode
57 | if config.mode and API_MODES.include? config.mode.to_sym
58 | config.mode.to_sym
59 | else
60 | DEFAULT_API_MODE
61 | end
62 | end
63 |
64 | # Get service end point
65 | def service_endpoint
66 | config.endpoint
67 | end
68 |
69 | # Default Http header
70 | def default_http_header
71 | { "User-Agent" => self.class.user_agent }
72 | end
73 |
74 | # Generate HTTP request for given action and parameters
75 | # === Arguments
76 | # * <tt>http_method</tt> -- HTTP method(get/put/post/delete/patch)
77 | # * <tt>action</tt> -- Action to perform
78 | # * <tt>params</tt> -- (Optional) Parameters for the action
79 | # * <tt>initheader</tt> -- (Optional) HTTP header
80 | def api_call(payload)
81 | payload[:header] = default_http_header.merge(payload[:header])
82 | payload[:uri] ||= uri.dup
83 | payload[:http] ||= http.dup
84 | payload[:uri].query = encode_www_form(payload[:query]) if payload[:query] and payload[:query].any?
85 | format_request(payload)
86 | payload[:response] = http_call(payload)
87 | format_response(payload)
88 | payload[:data]
89 | end
90 |
91 | # Generate HTTP request for given action and parameters
92 | # === Arguments
93 | # * <tt>action</tt> -- Action to perform
94 | # * <tt>params</tt> -- (Optional) Parameters for the action
95 | # * <tt>initheader</tt> -- (Optional) HTTP header
96 | def post(action, params = {}, header = {}, query = {})
97 | action, params, header = "", action, params if action.is_a? Hash
98 | api_call(:method => :post, :action => action, :query => query, :params => params, :header => header)
99 | end
100 | alias_method :request, :post
101 |
102 | def get(action, params = {}, header = {})
103 | action, params, header = "", action, params if action.is_a? Hash
104 | api_call(:method => :get, :action => action, :query => params, :params => nil, :header => header)
105 | end
106 |
107 | def patch(action, params = {}, header = {})
108 | action, params, header = "", action, params if action.is_a? Hash
109 | api_call(:method => :patch, :action => action, :params => params, :header => header)
110 | end
111 |
112 | def put(action, params = {}, header = {})
113 | action, params, header = "", action, params if action.is_a? Hash
114 | api_call(:method => :put, :action => action, :params => params, :header => header)
115 | end
116 |
117 | def delete(action, params = {}, header = {})
118 | action, params, header = "", action, params if action.is_a? Hash
119 | api_call(:method => :delete, :action => action, :params => params, :header => header)
120 | end
121 |
122 | # Format Request data. It will be override by child class
123 | # == Arguments
124 | # * <tt>action</tt> -- Request action
125 | # * <tt>params</tt> -- Request parameters
126 | # == Return
127 | # * <tt>path</tt> -- Formated request uri object
128 | # * <tt>params</tt> -- Formated request Parameters
129 | # * <tt>header</tt> -- HTTP Header
130 | def format_request(payload)
131 | payload[:uri].path = url_join(payload[:uri].path, payload[:action])
132 | payload[:body] = payload[:params].to_s
133 | payload
134 | end
135 |
136 | # Format Response object. It will be override by child class
137 | # == Argument
138 | # * <tt>action</tt> -- Request action
139 | # * <tt>response</tt> -- HTTP response object
140 | def format_response(payload)
141 | payload[:data] = payload[:response].body
142 | payload
143 | end
144 |
145 | # Format Error object. It will be override by child class.
146 | # == Arguments
147 | # * <tt>exception</tt> -- Exception object.
148 | # * <tt>message</tt> -- Readable error message.
149 | def format_error(exception, message)
150 | raise exception
151 | end
152 |
153 | class << self
154 | def sdk_library_details
155 | @library_details ||= "paypal-sdk-core #{PayPal::SDK::REST::VERSION}; ruby #{RUBY_VERSION}p#{RUBY_PATCHLEVEL}-#{RUBY_PLATFORM}"
156 | begin
157 | @library_details << ";#{OpenSSL::OPENSSL_LIBRARY_VERSION}"
158 | rescue NameError
159 | @library_details << ";OpenSSL #{OpenSSL::OPENSSL_VERSION}"
160 | end
161 | end
162 |
163 | def user_agent
164 | @user_agent ||= "PayPalSDK/rest-sdk-ruby #{PayPal::SDK::REST::VERSION} (#{sdk_library_details})"
165 | end
166 | end
167 | end
168 | end
169 | end
170 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/api/data_types/array_with_block.rb:
--------------------------------------------------------------------------------
1 | module PayPal::SDK::Core
2 | module API
3 | module DataTypes
4 | # Create Array with block.
5 | # === Example
6 | # ary = ArrayWithBlock.new{|val| val.to_i }
7 | # ary.push("123") # [ 123 ]
8 | # ary.merge!(["1", "3"]) # [ 123, 1, 3 ]
9 | class ArrayWithBlock < ::Array
10 | def initialize(&block)
11 | @block = block
12 | super()
13 | end
14 |
15 | def [](key)
16 | super(key) || send(:"[]=", key, nil)
17 | end
18 |
19 | def []=(key, value)
20 | super(key, @block ? @block.call(value) : value)
21 | end
22 |
23 | def push(value)
24 | super(@block ? @block.call(value) : value)
25 | end
26 |
27 | def merge!(array)
28 | if array.is_a? Array
29 | array.each do |object|
30 | push(object)
31 | end
32 | elsif array.is_a? Hash and array.keys.first.to_s =~ /^\d+$/
33 | array.each do |key, object|
34 | self[key.to_i] = object
35 | end
36 | else
37 | push(array)
38 | end
39 | self
40 | end
41 | end
42 | end
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/api/data_types/base.rb:
--------------------------------------------------------------------------------
1 | require 'date'
2 |
3 | module PayPal::SDK::Core
4 | module API
5 |
6 | module DataTypes
7 |
8 | # Create attributes and restrict the object type.
9 | # == Example
10 | # class ConvertCurrencyRequest < Core::API::DataTypes::Base
11 | # object_of :baseAmountList, CurrencyList
12 | # object_of :convertToCurrencyList, CurrencyCodeList
13 | # object_of :countryCode, String
14 | # object_of :conversionType, String
15 | # end
16 | class Base
17 |
18 | HashOptions = { :attribute => true, :namespace => true, :symbol => false }
19 | ContentKey = :value
20 |
21 | include SimpleTypes
22 | include Logging
23 |
24 | class << self
25 |
26 | # Add attribute
27 | # === Arguments
28 | # * <tt>name</tt> -- attribute name
29 | # * <tt>options</tt> -- options
30 | def add_attribute(name, options = {})
31 | add_member(name, SimpleTypes::String, options.merge( :attribute => true ))
32 | end
33 |
34 | # Fields list for the DataTye
35 | def members
36 | @members ||=
37 | begin
38 | superclass.load_members if defined? superclass.load_members
39 | parent_members = superclass.instance_variable_get("@members")
40 | parent_members ? parent_members.dup : Util::OrderedHash.new
41 | end
42 | end
43 |
44 | # Add Field to class variable hash and generate methods
45 | # === Example
46 | # add_member(:errorMessage, String) # Generate Code
47 | # # attr_reader :errorMessage
48 | # # alias_method :error_message, :errorMessage
49 | # # alias_method :error_message=, :errorMessage=
50 | def add_member(member_name, klass, options = {})
51 | member_name = member_name.to_sym
52 | return if members[member_name]
53 | members[member_name] = options.merge( :type => klass )
54 | member_variable_name = "@#{member_name}"
55 | define_method "#{member_name}=" do |value|
56 | object = options[:array] ? convert_array(value, klass) : convert_object(value, klass)
57 | instance_variable_set(member_variable_name, object)
58 | end
59 | default_value = ( options[:array] ? [] : ( klass < Base ? Util::OrderedHash.new : nil ) )
60 | define_method member_name do |&block|
61 | value = instance_variable_get(member_variable_name) || ( default_value && send("#{member_name}=", default_value) )
62 | value.instance_eval(&block) if block
63 | value
64 | end
65 | define_alias_methods(member_name, options)
66 | end
67 |
68 | # Define alias methods for getter and setter
69 | def define_alias_methods(member_name, options)
70 | snakecase_name = snakecase(member_name)
71 | alias_method snakecase_name, member_name
72 | alias_method "#{snakecase_name}=", "#{member_name}="
73 | alias_method "#{options[:namespace]}:#{member_name}=", "#{member_name}=" if options[:namespace]
74 | if options[:attribute]
75 | alias_method "@#{member_name}=", "#{member_name}="
76 | alias_method "@#{options[:namespace]}:#{member_name}=", "#{member_name}=" if options[:namespace]
77 | end
78 | end
79 |
80 | # define method for given member and the class name
81 | # === Example
82 | # object_of(:errorMessage, ErrorMessage) # Generate Code
83 | # # def errorMessage=(options)
84 | # # @errorMessage = ErrorMessage.new(options)
85 | # # end
86 | # # add_member :errorMessage, ErrorMessage
87 | def object_of(key, klass, options = {})
88 | add_member(key, klass, options)
89 | end
90 |
91 | # define method for given member and the class name
92 | # === Example
93 | # array_of(:errorMessage, ErrorMessage) # It Generate below code
94 | # # def errorMessage=(array)
95 | # # @errorMessage = array.map{|options| ErrorMessage.new(options) }
96 | # # end
97 | # # add_member :errorMessage, ErrorMessage
98 | def array_of(key, klass, options = {})
99 | add_member(key, klass, options.merge(:array => true))
100 | end
101 |
102 | # Generate snakecase string.
103 | # === Example
104 | # snakecase("errorMessage")
105 | # # error_message
106 | def snakecase(string)
107 | string.to_s.gsub(/([a-z])([A-Z])/, '\1_\2').gsub(/([A-Z])([A-Z][a-z])/, '\1_\2').downcase
108 | end
109 |
110 | end
111 |
112 | # Initialize options.
113 | def initialize(options = {}, &block)
114 | merge!(options, &block)
115 | end
116 |
117 | # Merge values
118 | def merge!(options, &block)
119 | if options.is_a? Hash
120 | options.each do |key, value|
121 | set(key, value)
122 | end
123 | elsif members[ContentKey]
124 | set(ContentKey, options)
125 | else
126 | raise ArgumentError, "invalid data(#{options.inspect}) for #{self.class.name} class"
127 | end
128 | self.instance_eval(&block) if block
129 | self
130 | end
131 |
132 | # Set value for given member
133 | # === Arguments
134 | # * <tt>key</tt> -- member name
135 | # * <tt>value</tt> -- value for member
136 | def set(key, value)
137 | send("#{key}=", value)
138 | rescue NoMethodError => error
139 | # Uncomment to see missing fields
140 | # logger.debug error.message
141 | rescue TypeError, ArgumentError => error
142 | raise TypeError, "#{error.message}(#{value.inspect}) for #{self.class.name}.#{key} member"
143 | end
144 |
145 | # Create array of objects.
146 | # === Example
147 | # covert_array([{ :amount => "55", :code => "USD"}], CurrencyType)
148 | # covert_array({ "0" => { :amount => "55", :code => "USD"} }, CurrencyType)
149 | # covert_array({ :amount => "55", :code => "USD"}, CurrencyType)
150 | # # @return
151 | # # [ <CurrencyType#object @amount="55" @code="USD" > ]
152 | def convert_array(array, klass)
153 | default_value = ( klass < Base ? Util::OrderedHash.new : nil )
154 | data_type_array = ArrayWithBlock.new{|object| convert_object(object || default_value, klass) }
155 | data_type_array.merge!(array)
156 | end
157 |
158 | # Create object based on given data.
159 | # === Example
160 | # covert_object({ :amount => "55", :code => "USD"}, CurrencyType )
161 | # # @return
162 | # # <CurrencyType#object @amount="55" @code="USD" >
163 | def convert_object(object, klass)
164 | object.is_a?(klass) ? object : ( ( object.nil? or object == "" ) ? nil : klass.new(object) )
165 | end
166 |
167 | # Alias instance method for the class method.
168 | def members
169 | self.class.members
170 | end
171 |
172 | # Get configured member names
173 | def member_names
174 | members.keys
175 | end
176 |
177 | # Create Hash based configured members
178 | def to_hash(options = {})
179 | options = HashOptions.merge(options)
180 | hash = Util::OrderedHash.new
181 | member_names.each do |member|
182 | value = value_to_hash(instance_variable_get("@#{member}"), options)
183 | hash[hash_key(member, options)] = value unless skip_value?(value)
184 | end
185 | hash
186 | end
187 |
188 | # Skip nil, empty array and empty hash.
189 | def skip_value?(value)
190 | value.nil? || ( ( value.is_a?(Array) || value.is_a?(Hash) ) && value.empty? )
191 | end
192 |
193 | # Generate Hash key for given member name based on configuration
194 | # === Example
195 | # hash_key(:amount) # @return :"ebl:amount"
196 | # hash_key(:type) # @return :"@type"
197 | def hash_key(key, options = {})
198 | unless key == ContentKey
199 | member_option = members[key]
200 | key = member_option[:name] if member_option.include? :name
201 | if !member_option[:attribute] and member_option[:namespace] and options[:namespace]
202 | key = "#{member_option[:namespace]}:#{key}"
203 | end
204 | key = "@#{key}" if member_option[:attribute] and options[:attribute]
205 | end
206 | options[:symbol] ? key.to_sym : key.to_s
207 | end
208 |
209 | # Covert the object to hash based on class.
210 | def value_to_hash(value, options = {})
211 | case value
212 | when Array
213 | value = value.map{|object| value_to_hash(object, options) }
214 | value.delete_if{|v| skip_value?(v) }
215 | value
216 | when Base
217 | value.to_hash(options)
218 | else
219 | value
220 | end
221 | end
222 | end
223 | end
224 | end
225 | end
226 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/api/data_types/enum.rb:
--------------------------------------------------------------------------------
1 | module PayPal::SDK::Core
2 | module API
3 | module DataTypes
4 |
5 | class Enum < SimpleTypes::String
6 | class << self
7 | def options
8 | @options ||= []
9 | end
10 |
11 | def options=(options)
12 | if options.is_a? Hash
13 | options.each do |const_name, value|
14 | const_set(const_name, value)
15 | end
16 | @options = options.values
17 | else
18 | @options = options
19 | end
20 | end
21 | end
22 | end
23 |
24 | end
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/api/data_types/simple_types.rb:
--------------------------------------------------------------------------------
1 | require 'date'
2 |
3 | module PayPal::SDK::Core
4 | module API
5 | module DataTypes
6 |
7 | module SimpleTypes
8 | class String < ::String
9 | def self.new(string = "")
10 | string.is_a?(::String) ? super : super(string.to_s)
11 | end
12 |
13 | def to_yaml_type
14 | "!tag:yaml.org,2002:str"
15 | end
16 | end
17 |
18 | class Integer < ::Integer
19 | def self.new(number)
20 | number.to_i
21 | end
22 | end
23 |
24 | class Float < ::Float
25 | def self.new(float)
26 | float.to_f
27 | end
28 | end
29 |
30 | class Boolean
31 | def self.new(boolean)
32 | ( boolean == 0 || boolean == "" || boolean =~ /^(false|f|no|n|0)$/i ) ? false : !!boolean
33 | end
34 | end
35 |
36 | class Date < ::Date
37 | def self.new(date)
38 | date.is_a?(::Date) ? date : Date.parse(date.to_s)
39 | end
40 | end
41 |
42 | class DateTime < ::DateTime
43 | def self.new(date_time)
44 | date_time = "0001-01-01T00:00:00" if date_time.to_s == "0"
45 | date_time.is_a?(::DateTime) ? date_time : parse(date_time.to_s)
46 | end
47 | end
48 | end
49 |
50 | end
51 | end
52 | end
53 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/api/ipn.rb:
--------------------------------------------------------------------------------
1 | module PayPal
2 | module SDK
3 | module Core
4 | module API
5 | module IPN
6 |
7 | END_POINTS = {
8 | :sandbox => "https://www.sandbox.paypal.com/cgi-bin/webscr",
9 | :live => "https://ipnpb.paypal.com/cgi-bin/webscr"
10 | }
11 | VERIFIED = "VERIFIED"
12 | INVALID = "INVALID"
13 |
14 | class Message
15 | include Util::HTTPHelper
16 |
17 | attr_accessor :message
18 |
19 | def initialize(message, env = nil, options = {})
20 | @message = message
21 | set_config(env, options)
22 | end
23 |
24 | # Fetch end point
25 | def ipn_endpoint
26 | config.ipn_endpoint || default_ipn_endpoint
27 | end
28 |
29 | # Default IPN end point
30 | def default_ipn_endpoint
31 | endpoint = END_POINTS[(config.mode || :sandbox).to_sym] rescue nil
32 | endpoint || END_POINTS[:sandbox]
33 | end
34 |
35 | # Request IPN service for validating the content
36 | # === Return
37 | # return http response object
38 | def request
39 | uri = URI(ipn_endpoint)
40 | query_string = "cmd=_notify-validate&#{message}"
41 | http_call(:method => :post, :uri => uri, :body => query_string)
42 | end
43 |
44 | # Validate the given content
45 | # === Return
46 | # return true or false
47 | def valid?
48 | request.body == VERIFIED
49 | end
50 | end
51 |
52 | class << self
53 | def valid?(*args)
54 | Message.new(*args).valid?
55 | end
56 |
57 | def request(*args)
58 | Message.new(*args).request
59 | end
60 | end
61 |
62 | end
63 | end
64 | end
65 | end
66 | end
67 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/api/rest.rb:
--------------------------------------------------------------------------------
1 | require 'multi_json'
2 |
3 | module PayPal::SDK::Core
4 | module API
5 | class REST < Base
6 | NVP_AUTH_HEADER = {
7 | :sandbox_email_address => "X-PAYPAL-SANDBOX-EMAIL-ADDRESS",
8 | :device_ipaddress => "X-PAYPAL-DEVICE-IPADDRESS"
9 | }
10 | DEFAULT_HTTP_HEADER = {
11 | "Content-Type" => "application/json"
12 | }
13 |
14 | DEFAULT_REST_END_POINTS = {
15 | :sandbox => "https://api.sandbox.paypal.com",
16 | :live => "https://api.paypal.com",
17 | }
18 | TOKEN_REQUEST_PARAMS = "grant_type=client_credentials"
19 |
20 | # Get REST service end point
21 | def service_endpoint
22 | config.rest_endpoint || super || DEFAULT_REST_END_POINTS[api_mode]
23 | end
24 |
25 | # Token endpoint
26 | def token_endpoint
27 | config.rest_token_endpoint || service_endpoint
28 | end
29 |
30 | # Clear cached values.
31 | def set_config(*args)
32 | @token_uri = nil
33 | @token_hash = nil
34 | super
35 | end
36 |
37 | # URI object token endpoint
38 | def token_uri
39 | @token_uri ||=
40 | begin
41 | new_uri = URI.parse(token_endpoint)
42 | new_uri.path = "/v1/oauth2/token" if new_uri.path =~ /^\/?$/
43 | new_uri
44 | end
45 | end
46 |
47 | # Generate Oauth token or Get cached
48 | def token_hash(auth_code=nil, headers=nil)
49 | validate_token_hash
50 | @token_hash ||=
51 | begin
52 | @token_request_at = Time.now
53 | basic_auth = ["#{config.client_id}:#{config.client_secret}"].pack('m').delete("\r\n")
54 | token_headers = default_http_header.merge({
55 | "Content-Type" => "application/x-www-form-urlencoded",
56 | "Authorization" => "Basic #{basic_auth}" }).merge(headers)
57 | if auth_code != nil
58 | TOKEN_REQUEST_PARAMS.replace "grant_type=authorization_code&response_type=token&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&code="
59 | TOKEN_REQUEST_PARAMS << auth_code
60 | end
61 | response = http_call( :method => :post, :uri => token_uri, :body => TOKEN_REQUEST_PARAMS, :header => token_headers )
62 | MultiJson.load(response.body, :symbolize_keys => true)
63 | end
64 | end
65 | attr_writer :token_hash
66 |
67 | # Get access token
68 | def token(auth_code=nil, headers={})
69 | token_hash(auth_code, headers)[:access_token]
70 | end
71 |
72 | # Get access token type
73 | def token_type(headers={})
74 | token_hash(nil, headers)[:token_type] || "Bearer"
75 | end
76 |
77 | # token setter
78 | def token=(new_token)
79 | @token_hash = { :access_token => new_token, :token_type => "Bearer" }
80 | end
81 |
82 | # Check token expired or not
83 | def validate_token_hash
84 | if @token_request_at and
85 | @token_hash and @token_hash[:expires_in] and
86 | (Time.now - @token_request_at) > @token_hash[:expires_in].to_i
87 | @token_hash = nil
88 | end
89 | end
90 |
91 | # Override the API call to handle Token Expire
92 | def api_call(payload)
93 | backup_payload = payload.dup
94 | begin
95 | response = super(payload)
96 | rescue UnauthorizedAccess => error
97 | if @token_hash and config.client_id
98 | # Reset cached token and Retry api request
99 | @token_hash = nil
100 | response = super(backup_payload)
101 | else
102 | raise error
103 | end
104 | end
105 | response
106 | end
107 |
108 | # Validate HTTP response
109 | def handle_response(response)
110 | super
111 | rescue BadRequest => error
112 | # Catch BadRequest to get validation error message from the response.
113 | error.response
114 | end
115 |
116 | # Format request payload
117 | # === Argument
118 | # * payload( uri, action, params, header)
119 | # === Generate
120 | # * payload( uri, body, header )
121 | def format_request(payload)
122 | # Request URI
123 | payload[:uri].path = url_join(payload[:uri].path, payload[:action])
124 | # HTTP Header
125 | credential_properties = credential(payload[:uri].to_s).properties
126 | header = map_header_value(NVP_AUTH_HEADER, credential_properties)
127 | payload[:header] = header.merge("Authorization" => "#{token_type(payload[:header])} #{token(nil, payload[:header])}").
128 | merge(DEFAULT_HTTP_HEADER).merge(payload[:header])
129 | # Post Data
130 | payload[:body] = MultiJson.dump(payload[:params])
131 | payload
132 | end
133 |
134 | # Format response payload
135 | # === Argument
136 | # * payload( response )
137 | # === Generate
138 | # * payload( data )
139 | def format_response(payload)
140 | response = payload[:response]
141 | payload[:data] =
142 | if response.body && response.body.strip == ""
143 | {}
144 | elsif response.code >= "200" and response.code <= "299"
145 | response.body && response.content_type == "application/json" ? MultiJson.load(response.body) : {}
146 | elsif response.content_type == "application/json"
147 | { "error" => flat_hash(MultiJson.load(response.body)) }
148 | else
149 | { "error" => { "name" => response.code, "message" => response.message,
150 | "developer_msg" => response } }
151 | end
152 | payload
153 | end
154 |
155 | def flat_hash(h)
156 | new_hash = {}
157 | h.each_pair do |key, val|
158 | if val.is_a?(Hash)
159 | new_hash.merge!(flat_hash(val))
160 | else
161 | new_hash[key] = val
162 | end
163 | end
164 | new_hash
165 | end
166 |
167 | # Log PayPal-Request-Id header
168 | def log_http_call(payload)
169 | if payload[:header] and payload[:header]["PayPal-Request-Id"]
170 | logger.info "PayPal-Request-Id: #{payload[:header]["PayPal-Request-Id"]}"
171 | end
172 | super
173 | end
174 |
175 | end
176 | end
177 | end
178 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/authentication.rb:
--------------------------------------------------------------------------------
1 |
2 | module PayPal::SDK::Core
3 |
4 | # Contains methods to format credentials for HTTP protocol.
5 | # == Example
6 | # include Authentication
7 | # credential(url)
8 | # base_credential
9 | # third_party_credential(url)
10 | #
11 | # add_certificate(http)
12 | module Authentication
13 |
14 | include Configuration
15 |
16 | # Get credential object
17 | # === Argument
18 | # * <tt>url</tt> -- API request url
19 | def credential(url)
20 | third_party_credential(url) || base_credential
21 | end
22 |
23 | # Get base credential
24 | def base_credential
25 | @base_credential ||=
26 | if config.cert_path
27 | Credential::Certificate.new(config)
28 | else
29 | Credential::Signature.new(config)
30 | end
31 | end
32 |
33 | # Get base credential type
34 | def base_credential_type
35 | config.cert_path ? :certificate : :three_token
36 | end
37 |
38 | # Get third party credential
39 | def third_party_credential(url)
40 | if config.token and config.token_secret
41 | Credential::ThirdParty::Token.new(base_credential, config, url)
42 | elsif config.subject
43 | Credential::ThirdParty::Subject.new(base_credential, config)
44 | end
45 | end
46 |
47 | # Clear cached variables on changing the configuration.
48 | def set_config(*args)
49 | @base_credential = nil
50 | super
51 | end
52 |
53 | # Configure ssl certificate to HTTP object
54 | # === Argument
55 | # * <tt>http</tt> -- Net::HTTP object
56 | def add_certificate(http)
57 | if base_credential.is_a? Credential::Certificate
58 | http.cert = base_credential.cert
59 | http.key = base_credential.key
60 | else
61 | http.cert = nil
62 | http.key = nil
63 | end
64 | end
65 | end
66 | end
67 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/config.rb:
--------------------------------------------------------------------------------
1 | require 'erb'
2 | require 'yaml'
3 |
4 | module PayPal::SDK::Core
5 |
6 | # Include Configuration module to access configuration from any object
7 | # == Examples
8 | # # Include in any class
9 | # include Configuration
10 | #
11 | # # Access config object and attributes
12 | # config
13 | # config.username
14 | #
15 | # # Change configuration
16 | # set_config(:development)
17 | module Configuration
18 |
19 | # To get default Config object.
20 | def config
21 | @config ||= Config.config
22 | end
23 |
24 | # To change the configuration to given environment or configuration
25 | # === Arguments
26 | # * <tt>env</tt> -- Environment
27 | # * <tt>override_configurations</tt> (Optional) -- To override the default configuration.
28 | # === Examples
29 | # obj.set_config(api.config)
30 | # obj.set_config(:http_timeout => 30)
31 | # obj.set_config(:development)
32 | # obj.set_config(:development, :http_timeout => 30)
33 | def set_config(env, override_configurations = {})
34 | @config =
35 | case env
36 | when Config
37 | env
38 | when Hash
39 | begin
40 | config.dup.merge!(env)
41 | rescue Errno::ENOENT => error
42 | Config.new(env)
43 | end
44 | else
45 | Config.config(env, override_configurations)
46 | end
47 | end
48 |
49 | alias_method :config=, :set_config
50 | end
51 |
52 | # Config class is used to hold the configurations.
53 | # == Examples
54 | # # To load configurations from file
55 | # Config.load('config/paypal.yml', 'development')
56 | #
57 | # # Get configuration
58 | # Config.config # load default configuration
59 | # Config.config(:development) # load development configuration
60 | # Config.config(:development, :app_id => "XYZ") # Override configuration
61 | #
62 | # # Read configuration attributes
63 | # config = Config.config
64 | # config.username
65 | # config.endpoint
66 | class Config
67 |
68 | include Logging
69 | include Exceptions
70 |
71 | attr_accessor :username, :password, :signature, :app_id, :cert_path,
72 | :token, :token_secret, :subject,
73 | :http_timeout, :http_proxy,
74 | :device_ipaddress, :sandbox_email_address,
75 | :mode, :endpoint, :merchant_endpoint, :platform_endpoint, :ipn_endpoint,
76 | :rest_endpoint, :rest_token_endpoint, :client_id, :client_secret,
77 | :openid_endpoint, :openid_redirect_uri, :openid_client_id, :openid_client_secret,
78 | :verbose_logging
79 |
80 | alias_method :end_point=, :endpoint=
81 | alias_method :end_point, :endpoint
82 | alias_method :platform_end_point=, :platform_endpoint=
83 | alias_method :platform_end_point, :platform_endpoint
84 | alias_method :merchant_end_point=, :merchant_endpoint=
85 | alias_method :merchant_end_point, :merchant_endpoint
86 | alias_method :ipn_end_point=, :ipn_endpoint=
87 | alias_method :ipn_end_point, :ipn_endpoint
88 | alias_method :rest_end_point, :rest_endpoint
89 | alias_method :rest_end_point=, :rest_endpoint=
90 | alias_method :rest_token_end_point, :rest_token_endpoint
91 | alias_method :rest_token_end_point=, :rest_token_endpoint=
92 |
93 | # Create Config object
94 | # === Options(Hash)
95 | # * <tt>username</tt> -- Username
96 | # * <tt>password</tt> -- Password
97 | # * <tt>signature</tt> (Optional if certificate present) -- Signature
98 | # * <tt>app_id</tt> -- Application ID
99 | # * <tt>cert_path</tt> (Optional if signature present) -- Certificate file path
100 | def initialize(options)
101 | merge!(options)
102 | end
103 |
104 | def logfile=(filename)
105 | logger.warn '`logfile=` is deprecated, Please use `PayPal::SDK::Core::Config.logger = Logger.new(STDERR)`'
106 | end
107 |
108 | def redirect_url=(redirect_url)
109 | logger.warn '`redirect_url=` is deprecated.'
110 | end
111 |
112 | def dev_central_url=(dev_central_url)
113 | logger.warn '`dev_central_url=` is deprecated.'
114 | end
115 |
116 | def ssl_options
117 | @ssl_options ||= {}.freeze
118 | end
119 |
120 | def ssl_options=(options)
121 | options = Hash[options.map{|key, value| [key.to_sym, value] }]
122 | @ssl_options = ssl_options.merge(options).freeze
123 | end
124 |
125 | def ca_file=(ca_file)
126 | logger.warn '`ca_file=` is deprecated, Please configure `ca_file=` under `ssl_options`'
127 | self.ssl_options = { :ca_file => ca_file }
128 | end
129 |
130 | def http_verify_mode=(verify_mode)
131 | logger.warn '`http_verify_mode=` is deprecated, Please configure `verify_mode=` under `ssl_options`'
132 | self.ssl_options = { :verify_mode => verify_mode }
133 | end
134 |
135 | # Override configurations
136 | def merge!(options)
137 | options.each do |key, value|
138 | send("#{key}=", value)
139 | end
140 | self
141 | end
142 |
143 | # Validate required configuration
144 | def required!(*names)
145 | names = names.select{|name| send(name).nil? }
146 | raise MissingConfig.new("Required configuration(#{names.join(", ")})") if names.any?
147 | end
148 |
149 | class << self
150 |
151 | @@config_cache = {}
152 |
153 | # Load configurations from file
154 | # === Arguments
155 | # * <tt>file_name</tt> -- Configuration file path
156 | # * <tt>default_environment</tt> (Optional) -- default environment configuration to load
157 | # === Example
158 | # Config.load('config/paypal.yml', 'development')
159 | def load(file_name, default_env = default_environment)
160 | @@config_cache = {}
161 | @@configurations = read_configurations(file_name)
162 | @@default_environment = default_env
163 | config
164 | end
165 |
166 | # Get default environment name
167 | def default_environment
168 | @@default_environment ||= ENV['PAYPAL_ENV'] || ENV['RACK_ENV'] || ENV['RAILS_ENV'] || "development"
169 | end
170 |
171 | # Set default environment
172 | def default_environment=(env)
173 | @@default_environment = env.to_s
174 | end
175 |
176 | def configure(options = {}, &block)
177 | begin
178 | self.config.merge!(options)
179 | rescue Errno::ENOENT
180 | self.configurations = { default_environment => options }
181 | end
182 | block.call(self.config) if block
183 | self.config
184 | end
185 | alias_method :set_config, :configure
186 |
187 | # Create or Load Config object based on given environment and configurations.
188 | # === Attributes
189 | # * <tt>env</tt> (Optional) -- Environment name
190 | # * <tt>override_configuration</tt> (Optional) -- Override the configuration given in file.
191 | # === Example
192 | # Config.config
193 | # Config.config(:development)
194 | # Config.config(:development, { :app_id => "XYZ" })
195 | def config(env = default_environment, override_configuration = {})
196 | if env.is_a? Hash
197 | override_configuration = env
198 | env = default_environment
199 | end
200 | if override_configuration.nil? or override_configuration.empty?
201 | default_config(env)
202 | else
203 | default_config(env).dup.merge!(override_configuration)
204 | end
205 | end
206 |
207 | def default_config(env = nil)
208 | env = (env || default_environment).to_s
209 | if configurations[env]
210 | @@config_cache[env] ||= new(configurations[env])
211 | else
212 | raise Exceptions::MissingConfig.new("Configuration[#{env}] NotFound")
213 | end
214 | end
215 |
216 | # Set logger
217 | def logger=(logger)
218 | Logging.logger = logger
219 | end
220 |
221 | # Get logger
222 | def logger
223 | if @@configurations[:mode] == 'live' and Logging.logger.level == Logger::DEBUG
224 | Logging.logger.warn "DEBUG log level not allowed in live mode for security of confidential information. Changing log level to INFO..."
225 | Logging.logger.level = Logger::INFO
226 | end
227 | Logging.logger
228 | end
229 |
230 | # Get raw configurations in Hash format.
231 | def configurations
232 | @@configurations ||= read_configurations
233 | end
234 |
235 | # Set configuration
236 | def configurations=(configs)
237 | @@config_cache = {}
238 | @@configurations = configs && Hash[configs.map{|k,v| [k.to_s, v] }]
239 | end
240 |
241 | private
242 | # Read configurations from the given file name
243 | # === Arguments
244 | # * <tt>file_name</tt> (Optional) -- Configuration file path
245 | def read_configurations(file_name = "config/paypal.yml")
246 | erb = ERB.new(File.read(file_name))
247 | erb.filename = file_name
248 | YAML.load(erb.result)
249 | end
250 |
251 | end
252 | end
253 | end
254 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/credential.rb:
--------------------------------------------------------------------------------
1 | module PayPal
2 | module SDK
3 | module Core
4 | module Credential
5 | autoload :Base, "paypal-sdk/core/credential/base"
6 | autoload :Certificate, "paypal-sdk/core/credential/certificate"
7 | autoload :Signature, "paypal-sdk/core/credential/signature"
8 |
9 | module ThirdParty
10 | autoload :Token, "paypal-sdk/core/credential/third_party/token"
11 | autoload :Subject, "paypal-sdk/core/credential/third_party/subject"
12 | end
13 | end
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/credential/base.rb:
--------------------------------------------------------------------------------
1 | module PayPal::SDK::Core
2 | module Credential
3 |
4 | # Base credential Class for authentication
5 | class Base
6 | attr_accessor :username, :password, :app_id, :device_ipaddress, :sandbox_email_address
7 |
8 | # Initialize authentication configurations
9 | # === Arguments
10 | # * <tt>config</tt> -- Configuration object
11 | def initialize(config)
12 | self.username = config.username
13 | self.password = config.password
14 | self.app_id = config.app_id
15 | self.device_ipaddress = config.device_ipaddress
16 | self.sandbox_email_address = config.sandbox_email_address
17 | end
18 |
19 | # Return credential properties
20 | def properties
21 | { :username => username, :password => password, :app_id => app_id,
22 | :device_ipaddress => device_ipaddress, :sandbox_email_address => sandbox_email_address }
23 | end
24 |
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/credential/certificate.rb:
--------------------------------------------------------------------------------
1 | module PayPal::SDK::Core
2 | module Credential
3 |
4 | # Certificate class for SSL Certificate authentication
5 | class Certificate < Base
6 |
7 | attr_reader :cert_path
8 |
9 | def initialize(config)
10 | super
11 | @cert_path = config.cert_path
12 | end
13 |
14 | # Return SSL certificate
15 | def cert
16 | @cert ||= OpenSSL::X509::Certificate.new(cert_content)
17 | end
18 |
19 | # Return SSL certificate key
20 | def key
21 | @key = OpenSSL::PKey::RSA.new(cert_content)
22 | end
23 |
24 | private
25 | # Return certificate content from the configured file.
26 | def cert_content
27 | @cert_content ||= File.read(cert_path)
28 | end
29 |
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/credential/signature.rb:
--------------------------------------------------------------------------------
1 | module PayPal::SDK::Core
2 | module Credential
3 | class Signature < Base
4 |
5 | attr_accessor :signature
6 |
7 | # Initialize configuration
8 | # === Argument
9 | # * <tt>config</tt> -- Configuration object
10 | def initialize(config)
11 | super
12 | self.signature = config.signature
13 | end
14 |
15 | # Return properties for authentication
16 | def properties
17 | super.merge({ :signature => signature })
18 | end
19 |
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/credential/third_party/subject.rb:
--------------------------------------------------------------------------------
1 | module PayPal::SDK::Core
2 | module Credential
3 | module ThirdParty
4 | class Subject
5 |
6 | attr_accessor :subject, :credential
7 |
8 | # Initialize configuration
9 | # === Arguments
10 | # * <tt>credential</tt> -- Credential object
11 | # * <tt>config</tt> -- Configuration object
12 | def initialize(credential, config)
13 | @credential = credential
14 | @subject = config.subject
15 | end
16 |
17 | # Return properties for authentication.
18 | def properties
19 | credential.properties.merge( :subject => subject )
20 | end
21 |
22 | end
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/credential/third_party/token.rb:
--------------------------------------------------------------------------------
1 | module PayPal::SDK::Core
2 | module Credential
3 | module ThirdParty
4 | class Token
5 |
6 | attr_accessor :token, :token_secret, :credential, :url
7 |
8 | # Initialize Token credentials
9 | # === Arguments
10 | # * <tt>credential</tt> -- Credential Object
11 | # * <tt>config</tt> -- Configuration object
12 | # * <tt>url</tt> -- Request url
13 | def initialize(credential, config, url)
14 | @credential = credential
15 | @token = config.token
16 | @token_secret = config.token_secret
17 | @url = url
18 | end
19 |
20 | RemoveProperties = [ :username, :password, :signature ]
21 |
22 | # Return credential properties for authentication.
23 | def properties
24 | credential_properties = credential.properties
25 | credential_properties.delete_if{|k,v| RemoveProperties.include? k }
26 | credential_properties.merge( :authorization => oauth_authentication )
27 | end
28 |
29 | private
30 | # Return OAuth authentication string.
31 | def oauth_authentication
32 | Util::OauthSignature.new(credential.username, credential.password, token, token_secret, url).
33 | authorization_string
34 | end
35 |
36 | end
37 | end
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/exceptions.rb:
--------------------------------------------------------------------------------
1 | require 'json'
2 | require 'pp'
3 |
4 | module PayPal::SDK::Core
5 | module Exceptions
6 | class ConnectionError < StandardError # :nodoc:
7 | attr_reader :response
8 |
9 | def initialize(response, message = nil)
10 | @response = response
11 | @message = message
12 | end
13 |
14 | def to_s
15 | begin
16 | response_body = JSON.parse(response.body)
17 | debug_id = response["paypal-debug-id"]
18 | debug_id = response["correlation-id"] if debug_id.to_s == ''
19 | debug_id = response_body["debug_id"] if debug_id.to_s == ''
20 | rescue
21 | end
22 | message = "Failed."
23 | message << " Response code = #{response.code}." if response.respond_to?(:code)
24 | message << " Response message = #{response.message}." if response.respond_to?(:message)
25 | message << " Response debug ID = #{debug_id}." if debug_id
26 | message
27 | end
28 | end
29 |
30 | # Raised when a Timeout::Error occurs.
31 | class TimeoutError < ConnectionError
32 | def initialize(message)
33 | @message = message
34 | end
35 | def to_s; @message ;end
36 | end
37 |
38 | # Raised when a OpenSSL::SSL::SSLError occurs.
39 | class SSLError < ConnectionError
40 | def initialize(message)
41 | @message = message
42 | end
43 | def to_s; @message ;end
44 | end
45 |
46 | # 3xx Redirection
47 | class Redirection < ConnectionError # :nodoc:
48 | def to_s
49 | response['Location'] ? "#{super} => #{response['Location']}" : super
50 | end
51 | end
52 |
53 | class MissingParam < ArgumentError # :nodoc:
54 | end
55 |
56 | class MissingConfig < StandardError # :nodoc:
57 | end
58 |
59 | # 4xx Client Error
60 | class ClientError < ConnectionError # :nodoc:
61 | end
62 |
63 | # 400 Bad Request
64 | class BadRequest < ClientError # :nodoc:
65 | end
66 |
67 | # 401 Unauthorized
68 | class UnauthorizedAccess < ClientError # :nodoc:
69 | end
70 |
71 | # 403 Forbidden
72 | class ForbiddenAccess < ClientError # :nodoc:
73 | end
74 |
75 | # 404 Not Found
76 | class ResourceNotFound < ClientError # :nodoc:
77 | end
78 |
79 | # 409 Conflict
80 | class ResourceConflict < ClientError # :nodoc:
81 | end
82 |
83 | # 410 Gone
84 | class ResourceGone < ClientError # :nodoc:
85 | end
86 |
87 | # 422 Unprocessable Entity
88 | class ResourceInvalid < ClientError # :nodoc:
89 | end
90 |
91 | # 5xx Server Error
92 | class ServerError < ConnectionError # :nodoc:
93 | end
94 |
95 | # 405 Method Not Allowed
96 | class MethodNotAllowed < ClientError # :nodoc:
97 | def allowed_methods
98 | @response['Allow'].split(',').map { |verb| verb.strip.downcase.to_sym }
99 | end
100 | end
101 |
102 | # API error: returned as 200 + "error" key in response.
103 | class UnsuccessfulApiCall < RuntimeError
104 | attr_reader :api_error
105 |
106 | def initialize(api_error)
107 | super(api_error['message'])
108 | @api_error = api_error
109 | end
110 | end
111 | end
112 | end
113 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/logging.rb:
--------------------------------------------------------------------------------
1 | require 'logger'
2 |
3 | module PayPal::SDK::Core
4 |
5 | # Include Logging module to provide logger functionality.
6 | # == Configure logger
7 | # Logging.logger = Logger.new(STDERR)
8 | #
9 | # == Example
10 | # include Logger
11 | # logger.info "Debug message"
12 | module Logging
13 |
14 | # Get logger object
15 | def logger
16 | @logger ||= Logging.logger
17 | end
18 |
19 | def log_event(message, &block)
20 | start_time = Time.now
21 | block.call
22 | ensure
23 | logger.info sprintf("[%.3fs] %s", Time.now - start_time, message)
24 | end
25 |
26 | class << self
27 |
28 | # Get or Create configured logger based on the default environment configuration
29 | def logger
30 | @logger ||= Logger.new(STDERR)
31 | end
32 |
33 | # Set logger directly and clear the loggers cache.
34 | # === Attributes
35 | # * <tt>logger</tt> -- Logger object
36 | # === Example
37 | # Logging.logger = Logger.new(STDERR)
38 | def logger=(logger)
39 | @logger = logger
40 | if Config.config.mode.eql? 'live' and @logger.level == Logger::DEBUG
41 | @logger.warn "DEBUG log level not allowed in sandbox mode for security of confidential information. Changing log level to INFO..."
42 | @logger.level = Logger::INFO
43 | end
44 | end
45 |
46 | end
47 | end
48 |
49 | end
50 |
51 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/openid_connect.rb:
--------------------------------------------------------------------------------
1 |
2 | module PayPal::SDK
3 | module Core
4 | module OpenIDConnect
5 | autoload :API, "paypal-sdk/core/openid_connect/api"
6 | autoload :SetAPI, "paypal-sdk/core/openid_connect/set_api"
7 | autoload :GetAPI, "paypal-sdk/core/openid_connect/get_api"
8 | autoload :RequestDataType, "paypal-sdk/core/openid_connect/request_data_type"
9 | autoload :DataTypes, "paypal-sdk/core/openid_connect/data_types"
10 |
11 | include DataTypes
12 |
13 | class << self
14 | def api
15 | RequestDataType.api
16 | end
17 |
18 | def set_config(*args)
19 | RequestDataType.set_config(*args)
20 | end
21 | alias_method :config=, :set_config
22 |
23 | AUTHORIZATION_URL = "paypal.com/signin/authorize"
24 | ENDSESSION_URL = "paypal.com/webapps/auth/protocol/openidconnect/v1/endsession"
25 | DEFAULT_SCOPE = "openid"
26 |
27 | def authorize_url(params = {})
28 | uri = URI(url_for_mode(AUTHORIZATION_URL))
29 | uri.query = api.encode_www_form({
30 | :response_type => "code",
31 | :scope => DEFAULT_SCOPE,
32 | :client_id => RequestDataType.client_id,
33 | :redirect_uri => api.config.openid_redirect_uri
34 | }.merge(params))
35 | uri.to_s
36 | end
37 |
38 | def logout_url(params = {})
39 | uri = URI(url_for_mode(ENDSESSION_URL))
40 | uri.query = api.encode_www_form({
41 | :logout => "true",
42 | :redirect_uri => api.config.openid_redirect_uri
43 | }.merge(params))
44 | uri.to_s
45 | end
46 |
47 | private
48 |
49 | def url_for_mode(url)
50 | "https://www.#{"sandbox." if api.api_mode == :sandbox}#{url}"
51 | end
52 | end
53 |
54 | module DataTypes
55 | class Tokeninfo < Base
56 | include RequestDataType
57 | PATH = "v1/identity/openidconnect/tokenservice"
58 | FP_PATH = "v1/oauth2/token"
59 |
60 | class << self
61 |
62 | def basic_auth_header(options)
63 | credentials = options[:client_id].to_s + ":" + options[:client_secret].to_s
64 | encoded = Base64.encode64(credentials.force_encoding('UTF-8')).gsub!(/\n/, "")
65 | "Basic #{encoded}"
66 | end
67 |
68 | def create_from_authorization_code(options, http_header = {})
69 | options = { :code => options } if options.is_a? String
70 | options = options.merge( :grant_type => "authorization_code" )
71 | Tokeninfo.new(api.post(PATH, with_credentials(options), http_header))
72 | end
73 | alias_method :create, :create_from_authorization_code
74 |
75 | def create_from_refresh_token(options, http_header = {})
76 | options = { :refresh_token => options } if options.is_a? String
77 | options = options.merge( :grant_type => "refresh_token" )
78 | http_header = http_header.merge( { "Content-Type" => "application/x-www-form-urlencoded", "Authorization" => basic_auth_header(with_credentials(options)) } )
79 | Tokeninfo.new(api.post(PATH, options, http_header))
80 | end
81 | alias_method :refresh, :create_from_refresh_token
82 |
83 | def create_from_future_payment_auth_code(options, http_header = {})
84 | options = { :code => options } if options.is_a? String
85 | options = options.merge( { :grant_type => "authorization_code", :response_type => "token", :redirect_uri => "urn:ietf:wg:oauth:2.0:oob" } )
86 | http_header = http_header.merge( { "Content-Type" => "application/x-www-form-urlencoded", "Authorization" => basic_auth_header(with_credentials(options)) } )
87 | Tokeninfo.new(api.post(FP_PATH, options, http_header))
88 | end
89 | alias_method :token_hash, :create_from_future_payment_auth_code
90 | alias_method :create_fp, :create_from_future_payment_auth_code
91 |
92 | def with_credentials(options = {})
93 | options = options.dup
94 | [ :client_id, :client_secret ].each do |key|
95 | options[key] = self.send(key) unless options[key] or options[key.to_s]
96 | end
97 | options
98 | end
99 |
100 | def authorize_url(options = {})
101 | OpenIDConnect.authorize_url(options)
102 | end
103 | end
104 |
105 | def refresh(options = {})
106 | tokeninfo = self.class.refresh({
107 | :refresh_token => self.refresh_token}.merge(options))
108 | self.merge!(tokeninfo.to_hash)
109 | end
110 |
111 | def userinfo(options = {})
112 | Userinfo.get({ :access_token => self.access_token }.merge(options))
113 | end
114 |
115 | def logout_url(options = {})
116 | OpenIDConnect.logout_url({ :id_token => self.id_token }.merge(options))
117 | end
118 |
119 | end
120 |
121 | class Userinfo < Base
122 | include RequestDataType
123 | PATH = "v1/identity/openidconnect/userinfo"
124 |
125 | class << self
126 | def get_userinfo(options = {}, http_header = {})
127 | options = { :access_token => options } if options.is_a? String
128 | options = options.merge( :schema => "openid" ) unless options[:schema] or options["schema"]
129 | Userinfo.new(api.post(PATH, options, http_header))
130 | end
131 | alias_method :get, :get_userinfo
132 | end
133 | end
134 | end
135 | end
136 | end
137 |
138 | # Alias for the Core::OpenIDConnect constant
139 | OpenIDConnect = Core::OpenIDConnect
140 | end
141 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/openid_connect/api.rb:
--------------------------------------------------------------------------------
1 | require 'multi_json'
2 | require 'paypal-sdk/rest/version'
3 |
4 | module PayPal::SDK
5 | module Core
6 | module OpenIDConnect
7 | class API < Core::API::Base
8 |
9 | DEFAULT_OPENID_ENDPOINT = {
10 | :sandbox => "https://api.sandbox.paypal.com",
11 | :live => "https://api.paypal.com" }
12 |
13 | def initialize(environment = nil, options = {})
14 | super("", environment, options)
15 | end
16 |
17 | def service_endpoint
18 | self.config.openid_endpoint || DEFAULT_OPENID_ENDPOINT[self.api_mode] || DEFAULT_OPENID_ENDPOINT[:sandbox]
19 | end
20 |
21 | def format_request(payload)
22 | payload[:uri].path = url_join(payload[:uri].path, payload[:action])
23 | payload[:body] = encode_www_form(payload[:params]) if payload[:params]
24 | payload[:header] = {"Content-Type" => "application/x-www-form-urlencoded" }.merge(payload[:header])
25 | payload
26 | end
27 |
28 | def format_response(payload)
29 | payload[:data] =
30 | if payload[:response].code >= "200" and payload[:response].code <= "299"
31 | MultiJson.load(payload[:response].body)
32 | elsif payload[:response].content_type == "application/json"
33 | { "error" => MultiJson.load(payload[:response].body) }
34 | else
35 | { "error" => { "name" => payload[:response].code, "message" => payload[:response].message,
36 | "developer_msg" => payload[:response] } }
37 | end
38 | payload
39 | end
40 |
41 | class << self
42 | def user_agent
43 | @user_agent ||= "PayPalSDK/openid-connect-ruby #{PayPal::SDK::REST::VERSION} (#{sdk_library_details})"
44 | end
45 | end
46 |
47 | end
48 | end
49 | end
50 | end
51 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/openid_connect/data_types.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-core'
2 |
3 | module PayPal::SDK::Core
4 | module OpenIDConnect
5 | module DataTypes
6 | class Base < PayPal::SDK::Core::API::DataTypes::Base
7 | end
8 |
9 | class Address < Base
10 | def self.load_members
11 | object_of :street_address, String
12 | object_of :locality, String
13 | object_of :region, String
14 | object_of :postal_code, String
15 | object_of :country, String
16 | end
17 | end
18 |
19 | class Userinfo < Base
20 | def self.load_members
21 | object_of :user_id, String
22 | object_of :sub, String
23 | object_of :name, String
24 | object_of :given_name, String
25 | object_of :family_name, String
26 | object_of :middle_name, String
27 | object_of :picture, String
28 | object_of :email, String
29 | object_of :email_verified, Boolean
30 | object_of :gender, String
31 | object_of :birthday, String
32 | object_of :zoneinfo, String
33 | object_of :locale, String
34 | object_of :language, String
35 | object_of :verified, Boolean
36 | object_of :phone_number, String
37 | object_of :address, Address
38 | object_of :verified_account, Boolean
39 | object_of :account_type, String
40 | object_of :account_creation_date, String
41 | object_of :age_range, String
42 | object_of :payer_id, String
43 | end
44 | end
45 |
46 | class Tokeninfo < Base
47 | def self.load_members
48 | object_of :scope, String
49 | object_of :access_token, String
50 | object_of :refresh_token, String
51 | object_of :token_type, String
52 | object_of :id_token, String
53 | object_of :expires_in, Integer
54 | end
55 | end
56 |
57 | class Error < Base
58 | def self.load_members
59 | object_of :error, String
60 | object_of :error_description, String
61 | object_of :error_uri, String
62 | end
63 | end
64 |
65 |
66 | constants.each do |data_type_klass|
67 | data_type_klass = const_get(data_type_klass)
68 | data_type_klass.load_members if defined? data_type_klass.load_members
69 | end
70 |
71 | end
72 | end
73 | end
74 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/openid_connect/get_api.rb:
--------------------------------------------------------------------------------
1 | module PayPal::SDK
2 | module Core
3 | module OpenIDConnect
4 | module GetAPI
5 | # Get API object
6 | # === Example
7 | # Payment.api
8 | # payment.api
9 | def api
10 | @api || parent_api
11 | end
12 |
13 | # Parent API object
14 | def parent_api
15 | superclass.respond_to?(:api) ? superclass.api : RequestDataType.api
16 | end
17 |
18 | def client_id
19 | api.config.openid_client_id || api.config.client_id
20 | end
21 |
22 | def client_secret
23 | api.config.openid_client_secret || api.config.client_secret
24 | end
25 | end
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/openid_connect/request_data_type.rb:
--------------------------------------------------------------------------------
1 | module PayPal::SDK
2 | module Core
3 | module OpenIDConnect
4 | module RequestDataType
5 |
6 | # Get a local API object or Class level API object
7 | def api
8 | @api || self.class.api
9 | end
10 |
11 | class << self
12 | # Global API object
13 | # === Example
14 | # RequestDataType.api
15 | def api
16 | @api ||= API.new({})
17 | end
18 |
19 | def client_id
20 | api.config.openid_client_id || api.config.client_id
21 | end
22 |
23 | def client_secret
24 | api.config.openid_client_secret || api.config.client_secret
25 | end
26 |
27 | # Setter for RequestDataType.api
28 | # === Example
29 | # RequestDataType.set_config(..)
30 | include SetAPI
31 |
32 | # Configure depended module, when RequestDataType is include.
33 | # === Example
34 | # class Payment < DataTypes
35 | # include RequestDataType
36 | # end
37 | # Payment.set_config(..)
38 | # payment.set_config(..)
39 | # Payment.api
40 | # payment.api
41 | def included(klass)
42 | klass.class_eval do
43 | extend GetAPI
44 | extend SetAPI
45 | include SetAPI
46 | end
47 | end
48 | end
49 | end
50 | end
51 | end
52 | end
53 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/openid_connect/set_api.rb:
--------------------------------------------------------------------------------
1 | module PayPal::SDK
2 | module Core
3 | module OpenIDConnect
4 | module SetAPI
5 | # Set new api
6 | # === Examples
7 | # payment.set_config(:development)
8 | # payment.set_config(:client_id => "XYZ", :client_secret => "SECRET")
9 | # payment.set_config
10 | # payment.api = API.new(:development)
11 | def set_config(*args)
12 | if args[0].is_a?(API)
13 | @api = args[0]
14 | else
15 | @api ||= API.new({})
16 | @api.set_config(*args) # Just override the configuration and Not
17 | @api
18 | end
19 | end
20 | alias_method :config=, :set_config
21 | alias_method :set_api, :set_config
22 | alias_method :api=, :set_config
23 |
24 | # Override client id
25 | def client_id=(client_id)
26 | set_config(:client_id => client_id)
27 | end
28 |
29 | # Override client secret
30 | def client_secret=(client_secret)
31 | set_config(:client_secret => client_secret)
32 | end
33 | end
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/util.rb:
--------------------------------------------------------------------------------
1 | module PayPal
2 | module SDK
3 | module Core
4 | module Util
5 | autoload :OauthSignature, "paypal-sdk/core/util/oauth_signature"
6 | autoload :OrderedHash, "paypal-sdk/core/util/ordered_hash"
7 | autoload :HTTPHelper, "paypal-sdk/core/util/http_helper"
8 | end
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/util/http_helper.rb:
--------------------------------------------------------------------------------
1 | require 'net/https'
2 | require 'uri'
3 | require 'cgi'
4 |
5 | module PayPal::SDK::Core
6 | module Util
7 | module HTTPHelper
8 |
9 | include Configuration
10 | include Logging
11 | include Authentication
12 | include Exceptions
13 |
14 | # Create HTTP connection based on given service name or configured end point
15 | def create_http_connection(uri)
16 | new_http(uri).tap do |http|
17 | if config.http_timeout
18 | http.open_timeout = config.http_timeout
19 | http.read_timeout = config.http_timeout
20 | end
21 | configure_ssl(http) if uri.scheme == "https"
22 | end
23 | end
24 |
25 | # New raw HTTP object
26 | def new_http(uri)
27 | if config.http_proxy
28 | proxy = URI.parse(config.http_proxy)
29 | Net::HTTP.new(uri.host, uri.port, proxy.host, proxy.port, proxy.user, proxy.password)
30 | else
31 | Net::HTTP.new(uri.host, uri.port)
32 | end
33 | end
34 |
35 | # Default ca file
36 | def default_ca_file
37 | File.expand_path("../../../../../data/paypal.crt", __FILE__)
38 | end
39 |
40 | # Apply ssl configuration to http object
41 | def configure_ssl(http)
42 | http.tap do |https|
43 | https.use_ssl = true
44 | https.ca_file = default_ca_file
45 | https.verify_mode = OpenSSL::SSL::VERIFY_PEER
46 | begin
47 | https.ssl_version = :TLSv1_2
48 | rescue => error
49 | logger.warn("WARNING: Your system does not support TLSv1.2. Per PCI Security Council mandate (https://github.com/paypal/TLS-update), you MUST update to latest security library.")
50 | end
51 | config.ssl_options.each do |key, value|
52 | http.send("#{key}=", value)
53 | end
54 | add_certificate(https)
55 | end
56 | end
57 |
58 | # Join url
59 | def url_join(path, action)
60 | path.sub(/\/?$/, "/#{action}")
61 | end
62 |
63 | # Make Http call
64 | # * payload - Hash(:http, :method, :uri, :body, :header)
65 | def http_call(payload)
66 | response =
67 | log_http_call(payload) do
68 | http = payload[:http] || create_http_connection(payload[:uri])
69 | http.start do |session|
70 | if [ :get, :delete, :head ].include? payload[:method]
71 | session.send(payload[:method], payload[:uri].request_uri, payload[:header])
72 | else
73 | session.send(payload[:method], payload[:uri].request_uri, payload[:body], payload[:header])
74 | end
75 | end
76 | end
77 |
78 | handle_response(response)
79 | end
80 |
81 | # Log Http call
82 | # * payload - Hash(:http, :method, :uri, :body, :header)
83 | def log_http_call(payload)
84 | logger.info "Request[#{payload[:method]}]: #{payload[:uri].to_s}"
85 |
86 | logger.debug "Request.body=#{payload[:body]}\trequest.header=#{payload[:header]}"
87 |
88 | start_time = Time.now
89 | response = yield
90 | logger.info sprintf("Response[%s]: %s, Duration: %.3fs", response.code,
91 | response.message, Time.now - start_time)
92 |
93 | logger.add(
94 | response_details_log_level(response),
95 | "Response.body=#{response.body}\tResponse.header=#{response.to_hash}"
96 | )
97 |
98 | response
99 | end
100 |
101 | # Generate header based on given header keys and properties
102 | # === Arguments
103 | # * <tt>header_keys</tt> -- List of Header keys for the properties
104 | # * <tt>properties</tt> -- properties
105 | # === Return
106 | # Hash with header as key property as value
107 | # === Example
108 | # map_header_value( { :username => "X-PAYPAL-USERNAME"}, { :username => "guest" })
109 | # # Return: { "X-PAYPAL-USERNAME" => "guest" }
110 | def map_header_value(header_keys, properties)
111 | header = {}
112 | properties.each do |key, value|
113 | key = header_keys[key]
114 | header[key] = value.to_s if key and value
115 | end
116 | header
117 | end
118 |
119 | def encode_www_form(hash)
120 | if defined? URI.encode_www_form
121 | URI.encode_www_form(hash)
122 | else
123 | hash.map{|key, value| "#{CGI.escape(key.to_s)}=#{CGI.escape(value.to_s)}" }.join("&")
124 | end
125 | end
126 |
127 | # Handles response and error codes from the remote service.
128 | def handle_response(response)
129 | case response.code.to_i
130 | when 301, 302, 303, 307
131 | raise(Redirection.new(response))
132 | when 200...400
133 | response
134 | when 400
135 | raise(BadRequest.new(response))
136 | when 401
137 | raise(UnauthorizedAccess.new(response))
138 | when 403
139 | raise(ForbiddenAccess.new(response))
140 | when 404
141 | raise(ResourceNotFound.new(response))
142 | when 405
143 | raise(MethodNotAllowed.new(response))
144 | when 409
145 | raise(ResourceConflict.new(response))
146 | when 410
147 | raise(ResourceGone.new(response))
148 | when 422
149 | raise(ResourceInvalid.new(response))
150 | when 401...500
151 | raise(ClientError.new(response))
152 | when 500...600
153 | raise(ServerError.new(response))
154 | else
155 | raise(ConnectionError.new(response, "Unknown response code: #{response.code}"))
156 | end
157 | end
158 |
159 | private
160 |
161 | def response_details_log_level(response)
162 | if (400...600).cover?(response.code.to_i)
163 | Logger::WARN
164 | else
165 | Logger::DEBUG
166 | end
167 | end
168 |
169 | end
170 | end
171 | end
172 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/util/oauth_signature.rb:
--------------------------------------------------------------------------------
1 | require 'uri'
2 | require 'cgi'
3 | require 'openssl'
4 | require 'base64'
5 |
6 | module PayPal::SDK::Core
7 | module Util
8 | class OauthSignature
9 | attr_accessor :username, :password, :token, :token_secret, :url, :timestamp
10 |
11 | def initialize(username, password, token, token_secret, url, timestamp = nil)
12 | @username = username
13 | @password = password
14 | @token = token
15 | @token_secret = token_secret
16 | @url = url
17 | @timestamp = timestamp || Time.now.to_i.to_s
18 | end
19 |
20 | def authorization_string
21 | signature = oauth_signature
22 | "token=#{token},signature=#{signature},timestamp=#{timestamp}"
23 | end
24 |
25 | def oauth_signature
26 | key = [
27 | paypal_encode(password),
28 | paypal_encode(token_secret),
29 | ].join("&").gsub(/%[0-9A-F][0-9A-F]/, &:downcase )
30 |
31 | digest = OpenSSL::HMAC.digest('sha1', key, base_string)
32 | Base64.encode64(digest).chomp
33 | end
34 |
35 | def base_string
36 | params = {
37 | "oauth_consumer_key" => username,
38 | "oauth_version" => "1.0",
39 | "oauth_signature_method" => "HMAC-SHA1",
40 | "oauth_token" => token,
41 | "oauth_timestamp" => timestamp,
42 | }
43 | sorted_query_string = params.sort.map{|v| v.join("=") }.join("&")
44 |
45 | base = [
46 | "POST",
47 | paypal_encode(url),
48 | paypal_encode(sorted_query_string)
49 | ].join("&")
50 | base = base.gsub(/%[0-9A-F][0-9A-F]/, &:downcase )
51 | end
52 |
53 | # The PayPalURLEncoder java class percent encodes everything other than 'a-zA-Z0-9 _'.
54 | # Then it converts ' ' to '+'.
55 | # Ruby's CGI.encode takes care of the ' ' and '*' to satisfy PayPal
56 | # (but beware, URI.encode percent encodes spaces, and does nothing with '*').
57 | # Finally, CGI.encode does not encode '.-', which we need to do here.
58 | def paypal_encode str
59 | CGI.escape(str.to_s).gsub('.', '%2E').gsub('-', '%2D')
60 | end
61 | end
62 | end
63 | end
64 |
65 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/core/util/ordered_hash.rb:
--------------------------------------------------------------------------------
1 | module PayPal::SDK::Core
2 | module Util
3 | class OrderedHash < ::Hash #:nodoc:
4 |
5 | def to_yaml_type
6 | "!tag:yaml.org,2002:map"
7 | end
8 |
9 | # Hash is ordered in Ruby 1.9!
10 | if RUBY_VERSION < '1.9'
11 |
12 | # In MRI the Hash class is core and written in C. In particular, methods are
13 | # programmed with explicit C function calls and polymorphism is not honored.
14 | #
15 | # For example, []= is crucial in this implementation to maintain the @keys
16 | # array but hash.c invokes rb_hash_aset() originally. This prevents method
17 | # reuse through inheritance and forces us to reimplement stuff.
18 | #
19 | # For instance, we cannot use the inherited #merge! because albeit the algorithm
20 | # itself would work, our []= is not being called at all by the C code.
21 |
22 | def initialize(*args, &block)
23 | super
24 | @keys = []
25 | end
26 |
27 | def self.[](*args)
28 | ordered_hash = new
29 |
30 | if (args.length == 1 && args.first.is_a?(Array))
31 | args.first.each do |key_value_pair|
32 | next unless (key_value_pair.is_a?(Array))
33 | ordered_hash[key_value_pair[0]] = key_value_pair[1]
34 | end
35 |
36 | return ordered_hash
37 | end
38 |
39 | unless (args.size % 2 == 0)
40 | raise ArgumentError.new("odd number of arguments for Hash")
41 | end
42 |
43 | args.each_with_index do |val, ind|
44 | next if (ind % 2 != 0)
45 | ordered_hash[val] = args[ind + 1]
46 | end
47 |
48 | ordered_hash
49 | end
50 |
51 | def initialize_copy(other)
52 | super
53 | # make a deep copy of keys
54 | @keys = other.keys
55 | end
56 |
57 | def []=(key, value)
58 | @keys << key if !has_key?(key)
59 | super
60 | end
61 |
62 | def delete(key)
63 | if has_key? key
64 | index = @keys.index(key)
65 | @keys.delete_at index
66 | end
67 | super
68 | end
69 |
70 | def delete_if
71 | super
72 | sync_keys!
73 | self
74 | end
75 |
76 | def reject!
77 | super
78 | sync_keys!
79 | self
80 | end
81 |
82 | def reject(&block)
83 | dup.reject!(&block)
84 | end
85 |
86 | def keys
87 | @keys.dup
88 | end
89 |
90 | def values
91 | @keys.collect { |key| self[key] }
92 | end
93 |
94 | def to_hash
95 | self
96 | end
97 |
98 | def to_a
99 | @keys.map { |key| [ key, self[key] ] }
100 | end
101 |
102 | def each_key
103 | @keys.each { |key| yield key }
104 | end
105 |
106 | def each_value
107 | @keys.each { |key| yield self[key]}
108 | end
109 |
110 | def each
111 | @keys.each {|key| yield [key, self[key]]}
112 | end
113 |
114 | alias_method :each_pair, :each
115 |
116 | def clear
117 | super
118 | @keys.clear
119 | self
120 | end
121 |
122 | def shift
123 | k = @keys.first
124 | v = delete(k)
125 | [k, v]
126 | end
127 |
128 | def merge!(other_hash)
129 | if block_given?
130 | other_hash.each { |k, v| self[k] = key?(k) ? yield(k, self[k], v) : v }
131 | else
132 | other_hash.each { |k, v| self[k] = v }
133 | end
134 | self
135 | end
136 |
137 | alias_method :update, :merge!
138 |
139 | def merge(other_hash, &block)
140 | dup.merge!(other_hash, &block)
141 | end
142 |
143 | # When replacing with another hash, the initial order of our keys must come from the other hash -ordered or not.
144 | def replace(other)
145 | super
146 | @keys = other.keys
147 | self
148 | end
149 |
150 | def invert
151 | OrderedHash[self.to_a.map!{|key_value_pair| key_value_pair.reverse}]
152 | end
153 |
154 | def inspect
155 | "#<OrderedHash #{super}>"
156 | end
157 |
158 | private
159 | def sync_keys!
160 | @keys.delete_if {|k| !has_key?(k)}
161 | end
162 | end
163 | end
164 | end
165 | end
166 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/rest.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-core'
2 |
3 | module PayPal
4 | module SDK
5 | module REST
6 | autoload :VERSION, "paypal-sdk/rest/version"
7 | autoload :DataTypes, "paypal-sdk/rest/data_types"
8 | autoload :API, "paypal-sdk/rest/api"
9 | autoload :RequestDataType, "paypal-sdk/rest/request_data_type"
10 | autoload :SetAPI, "paypal-sdk/rest/set_api"
11 | autoload :GetAPI, "paypal-sdk/rest/get_api"
12 | autoload :ErrorHash, "paypal-sdk/rest/error_hash"
13 |
14 | include DataTypes
15 | include Core::Exceptions
16 |
17 | module ClassMethods
18 | def method_missing(name, *args)
19 | RequestDataType.send(name, *args)
20 | end
21 | end
22 |
23 | class << self
24 | def new(*args)
25 | API.new(*args)
26 | end
27 |
28 | include ClassMethods
29 |
30 | def included(klass)
31 | if klass.is_a? Module
32 | klass.extend(ClassMethods)
33 | end
34 | end
35 | end
36 |
37 | end
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/rest/api.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-core'
2 | require 'paypal-sdk/rest/version'
3 |
4 | module PayPal
5 | module SDK
6 | module REST
7 | class API < Core::API::REST
8 | # include Services
9 |
10 | def initialize(environment = nil, options = {})
11 | super("", environment, options)
12 | end
13 |
14 | class << self
15 | def user_agent
16 | @user_agent ||= "PayPalSDK/PayPal-Ruby-SDK #{PayPal::SDK::REST::VERSION} (#{sdk_library_details})"
17 | end
18 | end
19 | end
20 | end
21 | end
22 | end
23 |
24 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/rest/error_hash.rb:
--------------------------------------------------------------------------------
1 | module PayPal
2 | module SDK
3 | module REST
4 | class ErrorHash < Core::Util::OrderedHash
5 | def self.convert(hash)
6 | error_hash = new
7 | hash.each{|key, value|
8 | error_hash[key] = value
9 | }
10 | error_hash
11 | end
12 |
13 | def []=(key, value)
14 | value =
15 | if value.is_a? Hash
16 | ErrorHash.convert(value)
17 | elsif value.is_a? Array and value[0].is_a? Hash
18 | value.map{|array_value| ErrorHash.convert(array_value) }
19 | else
20 | value
21 | end
22 | super(key, value)
23 | end
24 |
25 | def [](name)
26 | super(name.to_s) || super(name.to_sym)
27 | end
28 |
29 | def method_missing(name, *args)
30 | if keys.include?(name) or keys.include?(name.to_s)
31 | self[name]
32 | else
33 | super
34 | end
35 | end
36 | end
37 | end
38 | end
39 | end
40 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/rest/get_api.rb:
--------------------------------------------------------------------------------
1 | module PayPal
2 | module SDK
3 | module REST
4 | module GetAPI
5 | # Get API object
6 | # === Example
7 | # Payment.api
8 | # payment.api
9 | def api
10 | @api || parent_api
11 | end
12 |
13 | # Parent API object
14 | def parent_api
15 | superclass.respond_to?(:api) ? superclass.api : RequestDataType.api
16 | end
17 | end
18 | end
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/rest/request_data_type.rb:
--------------------------------------------------------------------------------
1 | module PayPal
2 | module SDK
3 | module REST
4 | module RequestDataType
5 | # Get a local API object or Class level API object
6 | def api
7 | @api || self.class.api
8 | end
9 |
10 | # Convert Hash object to ErrorHash object
11 | def error=(hash)
12 | @error =
13 | if hash.is_a? Hash
14 | ErrorHash.convert(hash)
15 | else
16 | hash
17 | end
18 | end
19 |
20 | class << self
21 | # Global API object
22 | # === Example
23 | # RequestDataType.api
24 | def api
25 | @api ||= API.new
26 | end
27 |
28 | # Setter for RequestDataType.api
29 | # === Example
30 | # RequestDataType.set_config(..)
31 | include SetAPI
32 |
33 | # Configure depended module, when RequestDataType is include.
34 | # === Example
35 | # class Payment < DataTypes
36 | # include RequestDataType
37 | # end
38 | # Payment.set_config(..)
39 | # payment.set_config(..)
40 | # Payment.api
41 | # payment.api
42 | def included(klass)
43 | klass.class_eval do
44 | extend GetAPI
45 | extend SetAPI
46 | include SetAPI
47 | end
48 | end
49 | end
50 | end
51 | end
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/rest/set_api.rb:
--------------------------------------------------------------------------------
1 | module PayPal
2 | module SDK
3 | module REST
4 | module SetAPI
5 | # Set new api
6 | # === Examples
7 | # payment.set_config(:development)
8 | # payment.set_config(:client_id => "XYZ", :client_secret => "SECRET")
9 | # payment.set_config
10 | # payment.api = API.new(:development)
11 | def set_config(*args)
12 | if args[0].is_a?(API)
13 | @api = args[0]
14 | else
15 | @api ||= API.new({})
16 | @api.set_config(*args) # Just override the configuration and Not
17 | @api
18 | end
19 | end
20 | alias_method :config=, :set_config
21 | alias_method :set_api, :set_config
22 | alias_method :api=, :set_config
23 |
24 | # Override token
25 | def token=(token)
26 | set_config( :client_id => nil, :client_secret => nil ).token = token
27 | end
28 | alias_method :"auth=", :"token="
29 |
30 | # Override client id
31 | def client_id=(client_id)
32 | set_config(:client_id => client_id).token = nil
33 | end
34 |
35 | # Override client secret
36 | def client_secret=(client_secret)
37 | set_config(:client_secret => client_secret).token = nil
38 | end
39 | end
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/lib/paypal-sdk/rest/version.rb:
--------------------------------------------------------------------------------
1 | module PayPal
2 | module SDK
3 | module REST
4 | VERSION = "1.7.4"
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/paypal-sdk-rest.gemspec:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 | lib = File.expand_path('../lib', __FILE__)
3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4 | require 'paypal-sdk/rest/version'
5 |
6 | Gem::Specification.new do |gem|
7 | gem.name = "paypal-sdk-rest"
8 | gem.version = PayPal::SDK::REST::VERSION
9 | gem.authors = ["PayPal"]
10 | gem.email = ["[email protected]"]
11 | gem.summary = %q{The PayPal REST SDK provides Ruby APIs to create, process and manage payment.}
12 | gem.description = %q{The PayPal REST SDK provides Ruby APIs to create, process and manage payment.}
13 | gem.homepage = "https://developer.paypal.com"
14 |
15 | gem.license = "PayPal SDK License"
16 |
17 | gem.files = Dir["{bin,spec,lib}/**/*"] + ["Rakefile", "README.md", "Gemfile"] + Dir["data/*"]
18 | gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
19 | gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
20 | gem.require_paths = ["lib"]
21 |
22 | gem.add_development_dependency('coveralls')
23 | gem.add_dependency('xml-simple')
24 | gem.add_dependency('multi_json', '~> 1.0')
25 | end
26 |
--------------------------------------------------------------------------------
/samples/Gemfile:
--------------------------------------------------------------------------------
1 |
2 | source "https://rubygems.org"
3 |
4 | if File.exists? "../paypal-sdk-rest.gemspec"
5 | # gem 'paypal-sdk-core', :git => "https://github.com/paypal/sdk-core-ruby.git"
6 | gem 'paypal-sdk-rest', :path => ".."
7 | else
8 | gem 'paypal-sdk-rest'
9 | end
10 |
11 | gem 'multi_json'
12 | gem 'coderay'
13 | gem 'sinatra'
14 | gem 'haml'
15 |
--------------------------------------------------------------------------------
/samples/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Run Sample App
3 |
4 | bundle install
5 | bundle exec rackup -p 3000
6 |
7 | ## Run Sample in console
8 |
9 | bundle exec ruby payment/create_with_credit_card.rb
10 |
11 | ## Samples directory
12 |
13 | 1. payment/
14 | 2. sale/
15 | 3. credit_card/
16 |
17 | ## Configuration
18 |
19 | Configuration in `config/paypal.yml`
20 |
21 | ```yaml
22 | test: &default
23 | mode: sandbox
24 | client_id: EBWKjlELKMYqRNQ6sYvFo64FtaRLRR5BdHEESmha49TM
25 | client_secret: EO422dn3gQLgDbuwqTjzrFgFtaRLRR5BdHEESmha49TM
26 |
27 | development:
28 | <<: *default
29 |
30 | production:
31 | mode: live
32 | client_id: CLIENT_ID
33 | client_secret: CLIENT_SECRET
34 | ```
35 |
36 |
37 |
--------------------------------------------------------------------------------
/samples/authorization/capture.rb:
--------------------------------------------------------------------------------
1 | # #Capture Sample
2 | # Sample showing how to capture an authorized payment.
3 | # API used: POST /v1/payments/authorization/{authorization_id}/capture
4 | require 'paypal-sdk-rest'
5 | include PayPal::SDK::REST
6 | include PayPal::SDK::Core::Logging
7 | begin
8 | @authorization = Authorization.find("84H59271K1950474X")
9 | @capture = @authorization.capture({
10 | :amount => {
11 | :currency => "USD",
12 | :total => "1.00" },
13 | :is_final_capture => true })
14 |
15 | if @capture.success? # Return true or false
16 | logger.info "Capture[#{@capture.id}]"
17 | else
18 | logger.error @capture.error.inspect
19 | end
20 | rescue ResourceNotFound => err
21 | # It will throw ResourceNotFound exception if the payment not found
22 | logger.error "Authorization Not Found"
23 | end
24 |
25 |
--------------------------------------------------------------------------------
/samples/authorization/find.rb:
--------------------------------------------------------------------------------
1 | # #GetAuthorization Sample
2 | # Sample showing how to retrieve authorized payment details.
3 | # API used: GET /v1/payments/authorization/{authorization_id}
4 | require 'paypal-sdk-rest'
5 | include PayPal::SDK::REST
6 | include PayPal::SDK::Core::Logging
7 |
8 | begin
9 | @authorization = Authorization.find("7WU36907W63353628")
10 | logger.info "Got Authorization[#{@authorization.id}]"
11 | rescue ResourceNotFound => err
12 | logger.error "Authorization Not Found"
13 | end
14 |
--------------------------------------------------------------------------------
/samples/authorization/reauthorize.rb:
--------------------------------------------------------------------------------
1 | # #Reauthorization Sample
2 | # Sample showing how to do a reauthorization.
3 | # API used: POST /v1/payments/authorization/{authorization_id}/reauthorize
4 | require 'paypal-sdk-rest'
5 | require 'paypal-sdk-rest'
6 | include PayPal::SDK::REST
7 | include PayPal::SDK::Core::Logging
8 | begin
9 | # ###Reauthorization
10 | # Retrieve a authorization id from authorization object
11 | # by making a Payment with payment type as `PayPal` with intent
12 | # as `authorize`. You can reauthorize a payment only once 4 to 29
13 | # days after 3-day honor period for the original authorization
14 | # expires.
15 | @authorization = Authorization.find("7GH53639GA425732B")
16 |
17 | @authorization.amount = {
18 | :currency => "USD",
19 | :total => "7.00" };
20 |
21 | if @authorization.reauthorize # Return true or false
22 | logger.info "Reauthorization[#{@authorization.id}]"
23 | else
24 | logger.error @authorization.error.inspect
25 | end
26 | rescue ResourceNotFound => err
27 | # It will throw ResourceNotFound exception if the payment not found
28 | logger.error "Authorization Not Found"
29 | end
30 |
--------------------------------------------------------------------------------
/samples/authorization/void.rb:
--------------------------------------------------------------------------------
1 | # #Void Sample
2 | # Sample showing how to void an authorized payment.
3 | # API used: POST /v1/payments/authorization/{authorization_id}/void
4 | require 'paypal-sdk-rest'
5 | include PayPal::SDK::REST
6 | include PayPal::SDK::Core::Logging
7 | begin
8 | @authorization = Authorization.find("1SU1944563257711X")
9 |
10 | if @authorization.void # Return true or false
11 | logger.info "Void an Authorization[#{@authorization.id}]"
12 | else
13 | logger.error @authorization.error.inspect
14 | end
15 | rescue ResourceNotFound => err
16 | # It will throw ResourceNotFound exception if the payment not found
17 | logger.error "Authorization Not Found"
18 | end
19 |
--------------------------------------------------------------------------------
/samples/capture/find.rb:
--------------------------------------------------------------------------------
1 | # #GetCapture Sample
2 | # Sample showing how to retrieve captured payment details.
3 | # API used: GET /v1/payments/capture/{capture_id}
4 | require 'paypal-sdk-rest'
5 | include PayPal::SDK::REST
6 | include PayPal::SDK::Core::Logging
7 |
8 | begin
9 | @capture = Capture.find("7YR91301C22810733")
10 | logger.info "Got Capture[#{@sale.id}]"
11 | rescue ResourceNotFound => err
12 | logger.error "Capture Not Found"
13 | end
14 |
--------------------------------------------------------------------------------
/samples/capture/refund.rb:
--------------------------------------------------------------------------------
1 | # #RefundCapture Sample
2 | # Sample showing how to refund captured payment.
3 | # API used: GET /v1/payments/capture/{capture_id}/refund
4 | require 'paypal-sdk-rest'
5 | include PayPal::SDK::REST
6 | include PayPal::SDK::Core::Logging
7 |
8 | begin
9 | @capture = Capture.find("9YB06173L6274542A")
10 | @refund = @capture.refund_request({
11 | :amount => {
12 | :currency => "USD",
13 | :total => "0.01" }
14 | })
15 |
16 | # Check refund status
17 | if @refund.success?
18 | logger.info "Refund[#{@refund.id}] Success"
19 | else
20 | logger.error "Unable to Refund"
21 | logger.error @refund.error.inspect
22 | end
23 | rescue ResourceNotFound => err
24 | # It will throw ResourceNotFound exception if the payment not found
25 | logger.error "Authorization Not Found"
26 | end
27 |
--------------------------------------------------------------------------------
/samples/config.ru:
--------------------------------------------------------------------------------
1 | require './app'
2 |
3 | run App
4 |
--------------------------------------------------------------------------------
/samples/config/paypal.yml:
--------------------------------------------------------------------------------
1 | test: &default
2 | # change mode to "security-test-sandbox" to test TLSv1.2 connection
3 | mode: sandbox
4 | client_id: AYSq3RDGsmBLJE-otTkBtM-jBRd1TCQwFf9RGfwddNXWz0uFU9ztymylOhRS
5 | client_secret: EGnHDxD_qRPdaLdZz8iCr8N7_MzF-YHPTkjs6NKYQvQSBngp4PTTVWkPZRbL
6 | #Your OpenID redirect URI must be the same value as your app's return URL. It is configured in the PayPal Developer Dashboard ( https://developer.paypal.com/developer/applications/ ).
7 | openid_redirect_uri: http://localhost/paypal/PayPal-PHP-SDK/sample/lipp/UserConsentRedirect.php?success=true
8 |
9 | development:
10 | <<: *default
11 |
12 | production:
13 | mode: live
14 | client_id: CLIENT_ID
15 | client_secret: CLIENT_SECRET
16 | # rest_endpoint: "https://api.paypal.com"
17 |
--------------------------------------------------------------------------------
/samples/invoice/cancel.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | include PayPal::SDK::REST
3 | include PayPal::SDK::Core::Logging
4 |
5 | begin
6 | # Create an invoice
7 | @invoice = RunSample.run('invoice/send_invoice.rb', '@invoice')
8 |
9 | options = {
10 | "subject" => "Past due",
11 | "note" => "Canceling invoice",
12 | "send_to_merchant" => true,
13 | "send_to_payer" => true
14 | }
15 |
16 | if @invoice.cancel(options)
17 | logger.info "Invoice[#{@invoice.id}] cancel successfully"
18 | else
19 | logger.error @invoice.error.inspect
20 | end
21 |
22 | rescue ResourceNotFound => err
23 | logger.error "Invoice Not Found"
24 | end
25 |
--------------------------------------------------------------------------------
/samples/invoice/create.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | include PayPal::SDK::REST
3 | include PayPal::SDK::Core::Logging
4 |
5 | @invoice = Invoice.new({
6 | "merchant_info" => {
7 | "email" => "[email protected]",
8 | "first_name" => "Dennis",
9 | "last_name" => "Doctor",
10 | "business_name" => "Medical Professionals, LLC",
11 | "phone" => {
12 | "country_code" => "001",
13 | "national_number" => "5032141716"
14 | },
15 | "address" => {
16 | "line1" => "1234 Main St.",
17 | "city" => "Portland",
18 | "state" => "OR",
19 | "postal_code" => "97217",
20 | "country_code" => "US"
21 | }
22 | },
23 | "billing_info" => [ { "email" => "[email protected]" } ],
24 | "items" => [
25 | {
26 | "name" => "Sutures",
27 | "quantity" => 100,
28 | "unit_price" => {
29 | "currency" => "USD",
30 | "value" => 5
31 | }
32 | }
33 | ],
34 | "note" => "Medical Invoice 16 Jul, 2013 PST",
35 | "payment_term" => {
36 | "term_type" => "NET_45"
37 | },
38 | "shipping_info" => {
39 | "first_name" => "Sally",
40 | "last_name" => "Patient",
41 | "business_name" => "Not applicable",
42 | "phone" => {
43 | "country_code" => "001",
44 | "national_number" => "5039871234"
45 | },
46 | "address" => {
47 | "line1" => "1234 Broad St.",
48 | "city" => "Portland",
49 | "state" => "OR",
50 | "postal_code" => "97216",
51 | "country_code" => "US"
52 | }
53 | }
54 | })
55 |
56 | if @invoice.create
57 | logger.info "Invoice[#{@invoice.id}] created successfully"
58 | else
59 | logger.error @invoice.error.inspect
60 | end
61 |
--------------------------------------------------------------------------------
/samples/invoice/get.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | include PayPal::SDK::REST
3 | include PayPal::SDK::Core::Logging
4 |
5 | begin
6 | # Create an invoice
7 | @invoice = RunSample.run('invoice/create.rb', '@invoice')
8 |
9 | @invoice= Invoice.find(@invoice.id)
10 | logger.info "Got Invoice Details for Invoice[#{@invoice.id}]"
11 |
12 | rescue ResourceNotFound => err
13 | logger.error "Invoice Not Found"
14 | end
15 |
--------------------------------------------------------------------------------
/samples/invoice/get_all.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | include PayPal::SDK::REST
3 | include PayPal::SDK::Core::Logging
4 |
5 | @invoices = Invoice.get_all( :total_count_required => true )
6 | logger.info "Invoices: #{@invoices.total_count}"
7 |
--------------------------------------------------------------------------------
/samples/invoice/remind.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | include PayPal::SDK::REST
3 | include PayPal::SDK::Core::Logging
4 |
5 |
6 | begin
7 | # Create an invoice
8 | @invoice = RunSample.run('invoice/send_invoice.rb', '@invoice')
9 |
10 | options = {
11 | "subject" => "Past due",
12 | "note" => "Please pay soon",
13 | "send_to_merchant" => true
14 | }
15 |
16 | if @invoice.remind(options)
17 | logger.info "Invoice[#{@invoice.id}] remind successfully"
18 | else
19 | logger.error @invoice.error.inspect
20 | end
21 |
22 | rescue ResourceNotFound => err
23 | logger.error "Invoice Not Found"
24 | end
25 |
--------------------------------------------------------------------------------
/samples/invoice/send_invoice.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | include PayPal::SDK::REST
3 | include PayPal::SDK::Core::Logging
4 |
5 | begin
6 | # Create an invoice
7 | @invoice = RunSample.run('invoice/create.rb', '@invoice')
8 |
9 | if @invoice.send_invoice
10 | logger.info "Invoice[#{@invoice.id}] send successfully"
11 | else
12 | logger.error @invoice.error.inspect
13 | end
14 | rescue ResourceNotFound => err
15 | logger.error "Invoice Not Found"
16 | end
17 |
--------------------------------------------------------------------------------
/samples/invoice/third_party_invoice.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | include PayPal::SDK::REST
3 | include PayPal::SDK::Core::Logging
4 |
5 | # Using Log In with PayPal, third party merchants can authorize your application to create and submit invoices on their behalf.
6 | # See https://developer.paypal.com/docs/integration/direct/identity/log-in-with-paypal/ for more details about Log In with PayPal.
7 |
8 |
9 | # Step 1. Generate a Log In with PayPal authorization URL. The third party merchant will need to visit this URL and authorize your request. You should use the `openid`, `https://uri.paypal.com/services/invoicing`, and `email` scopes at the minimum.
10 | #logger.info(PayPal::SDK::OpenIDConnect.authorize_url({'scope': 'openid https://uri.paypal.com/services/invoicing email'}))
11 |
12 | # For example, the URL to redirect the third party merchant may be like:
13 | # https://www.sandbox.paypal.com/signin/authorize?client_id=AYSq3RDGsmBLJE-otTkBtM-jBRd1TCQwFf9RGfwddNXWz0uFU9ztymylOhRS&scope=openid%20https%3A%2F%2Furi.paypal.com%2Fservices%2Finvoicing%20email&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%2Fpaypal%2FPayPal-PHP-SDK%2Fsample%2Flipp%2FUserConsentRedirect.php%3Fsuccess%3Dtrue
14 |
15 | # Step 2. After the third party merchant authorizes your request, Log In with PayPal will redirect the browser to your configured openid_redirect_uri with an authorization code query parameter value.
16 |
17 | # For example, after the merchant successfully authorizes your request, they will be redirected to the merchant's website configured via `openid_redirect_uri` like:
18 | # http://localhost/paypal/PayPal-PHP-SDK/sample/lipp/UserConsentRedirect.php?success=true&scope=https%3A%2F%2Furi.paypal.com%2Fservices%2Finvoicing+openid+email&code=q6DV3YTMUDquwMQ88I7VyE_Ou1ksKcKVo1b_a8zqUQ7fGCxLoLajHIBROQ5yxcM0dNWVWPQaovH35dJmdmunNYrNKao8UlpY5LVMuTgnxZ6ce6UL3XuEd3JXuuPtdg-4feXyMA25oh2aM5o5HTtSeSG1Ag596q9tk90dfJQ8gxhFTw1bV
19 |
20 | # Step 3. Your web app should parse the query parameters for the authorization `code` value. You should use the `code` value to get a refresh token and securely save it for later use.
21 | =begin
22 | authorization_code = "q6DV3YTMUDquwMQ88I7VyE_Ou1ksKcKVo1b_a8zqUQ7fGCxLoLajHIBROQ5yxcM0dNWVWPQaovH35dJmdmunNYrNKao8UlpY5LVMuTgnxZ6ce6UL3XuEd3JXuuPtdg-4feXyMA25oh2aM5o5HTtSeSG1Ag596q9tk90dfJQ8gxhFTw1bV"
23 | tokeninfo = PayPal::SDK::OpenIDConnect::Tokeninfo.create(authorization_code)
24 | logger.info(tokeninfo);
25 | # Response 200
26 | tokeninfo = {
27 | token_type: 'Bearer',
28 | expires_in: '28800',
29 | refresh_token: 'J5yFACP3Y5dqdWCdN3o9lNYz0XyR01IHNMQn-E4r6Ss38rqbQ1C4rC6PSBhJvB_tte4WZsWe8ealMl-U_GMSz30dIkKaovgN41Xf8Sz0EGU55da6tST5I6sg3Rw',
30 | id_token: '<some value>',
31 | access_token: '<some value>'
32 | }
33 | =end
34 |
35 | # Step 4. You can use the refresh token to get the third party merchant's email address to use in the invoice, and then you can create an invoice on behalf of the third party merchant.
36 |
37 | refresh_token = "J5yFACP3Y5dqdWCdN3o9lNYz0XyR01IHNMQn-E4r6Ss38rqbQ1C4rC6PSBhJvB_tte4WZsWe8ealMl-U_GMSz30dIkKaovgN41Xf8Sz0EGU55da6tST5I6sg3Rw"
38 |
39 | tokeninfo = PayPal::SDK::OpenIDConnect::DataTypes::Tokeninfo.create_from_refresh_token(refresh_token)
40 | access_token = tokeninfo.access_token
41 | userinfo = PayPal::SDK::OpenIDConnect::Userinfo.get(tokeninfo.access_token)
42 |
43 | # more attribute available in tokeninfo
44 | logger.info tokeninfo.to_hash
45 | logger.info userinfo.email
46 |
47 | @invoice = Invoice.new({
48 | "merchant_info" => {
49 | "email" => userinfo.email,
50 | "first_name" => "Dennis",
51 | "last_name" => "Doctor",
52 | "business_name" => "Medical Professionals, LLC",
53 | "phone" => {
54 | "country_code" => "001",
55 | "national_number" => "5032141716"
56 | },
57 | "address" => {
58 | "line1" => "1234 Main St.",
59 | "city" => "Portland",
60 | "state" => "OR",
61 | "postal_code" => "97217",
62 | "country_code" => "US"
63 | }
64 | },
65 | "billing_info" => [ { "email" => "[email protected]" } ],
66 | "items" => [
67 | {
68 | "name" => "Sutures",
69 | "quantity" => 100,
70 | "unit_price" => {
71 | "currency" => "USD",
72 | "value" => 5
73 | }
74 | }
75 | ],
76 | "note" => "Medical Invoice 16 Jul, 2013 PST",
77 | "payment_term" => {
78 | "term_type" => "NET_45"
79 | },
80 | "shipping_info" => {
81 | "first_name" => "Sally",
82 | "last_name" => "Patient",
83 | "business_name" => "Not applicable",
84 | "phone" => {
85 | "country_code" => "001",
86 | "national_number" => "5039871234"
87 | },
88 | "address" => {
89 | "line1" => "1234 Broad St.",
90 | "city" => "Portland",
91 | "state" => "OR",
92 | "postal_code" => "97216",
93 | "country_code" => "US"
94 | }
95 | }
96 | }.merge( :token => access_token )
97 | )
98 |
99 | # create and send invoice
100 | if @invoice.create
101 | logger.info "Invoice[#{@invoice.id}] created successfully"
102 | if @invoice.send_invoice == true
103 | logger.info "Invoice[#{@invoice.id}] sent successfully"
104 | # To find invoice please use access token generated from refresh token
105 | if @invoice= Invoice.find("#{@invoice.id}", access_token)
106 | logger.info "Got Invoice Details for Invoice[#{@invoice.id}]"
107 | else
108 | logger.error @invoice.error.inspect
109 | end
110 | else
111 | logger.error @invoice.error.inspect
112 | end
113 | else
114 | logger.error @invoice.error.inspect
115 | end
116 |
117 |
118 |
--------------------------------------------------------------------------------
/samples/invoice_template/create.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | include PayPal::SDK::REST
3 | require 'securerandom'
4 | include PayPal::SDK::Core::Logging
5 |
6 | @template = Template.new(
7 | {
8 | "name" => SecureRandom.uuid,
9 | "default"=> true,
10 | "unit_of_measure"=> "HOURS",
11 | "template_data"=> {
12 | "tax_calculated_after_discount"=> false,
13 | "tax_inclusive"=> false,
14 | "note"=> "Thank you for your business",
15 | "logo_url"=> "https://pics.paypal.com/v1/images/redDot.jpeg",
16 | "items"=> [
17 | {
18 | "name"=> "Nutri Bullet",
19 | "quantity"=> "1",
20 | "unit_price"=> {
21 | "currency"=> "USD",
22 | "value"=> "50.00"
23 | }
24 | }
25 | ],
26 | "merchant_info"=> {
27 | "email"=> "[email protected]"
28 | }
29 | },
30 | "settings"=> [
31 | {
32 | "field_name"=> "custom",
33 | "display_preference"=> {
34 | "hidden"=> true
35 | }
36 | },
37 | {
38 | "field_name"=> "items.date",
39 | "display_preference"=> {
40 | "hidden"=> true
41 | }
42 | }
43 | ]
44 | })
45 |
46 | if @template.create
47 | logger.info "Tempalte[#{@template.template_id}] created successfully"
48 | else
49 | logger.error @template.error.inspect
50 | end
51 |
--------------------------------------------------------------------------------
/samples/invoice_template/delete.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | include PayPal::SDK::REST
3 | include PayPal::SDK::Core::Logging
4 |
5 | begin
6 | # Create an invoice template
7 | @template = RunSample.run('invoice_template/create.rb', '@template')
8 |
9 | if @template.delete
10 | logger.info "Deleted invoice template : [#{@template.template_id}]"
11 | else
12 | logger.info "Deleting failed"
13 | end
14 | rescue ResourceNotFound => err
15 | logger.error "Template Not Found"
16 | end
17 |
--------------------------------------------------------------------------------
/samples/invoice_template/get.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | include PayPal::SDK::REST
3 | include PayPal::SDK::Core::Logging
4 |
5 | begin
6 | # Create an invoice template
7 | @template = RunSample.run('invoice_template/create.rb', '@template')
8 |
9 | @template= Template.get(@template.template_id)
10 | logger.info "Got Template Details for [#{@template.template_id}]"
11 |
12 | rescue ResourceNotFound => err
13 | logger.error "Template Not Found"
14 | end
15 |
--------------------------------------------------------------------------------
/samples/invoice_template/get_all.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | include PayPal::SDK::REST
3 | include PayPal::SDK::Core::Logging
4 |
5 | @templates = Templates.get_all( :fields => "all" )
6 | logger.info "Fetched all templates"
7 |
--------------------------------------------------------------------------------
/samples/invoice_template/update.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | include PayPal::SDK::REST
3 | include PayPal::SDK::Core::Logging
4 |
5 | begin
6 | # Create an invoice template
7 | @template = RunSample.run('invoice_template/create.rb', '@template')
8 |
9 | @template.custom = nil
10 | @template.template_data.note = "Something else"
11 |
12 | @template.update
13 | rescue ResourceNotFound => err
14 | logger.error "Template Not Found"
15 | end
16 |
--------------------------------------------------------------------------------
/samples/notifications/create.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | require './runner.rb'
3 | require "securerandom"
4 |
5 | include PayPal::SDK::REST
6 | include PayPal::SDK::Core::Logging
7 |
8 | @webhook = Webhook.new({
9 | :url => "https://www.yeowza.com/paypal_webhook_"+SecureRandom.hex(8),
10 | :event_types => [
11 | {
12 | :name => "PAYMENT.AUTHORIZATION.CREATED"
13 | },
14 | {
15 | :name => "PAYMENT.AUTHORIZATION.VOIDED"
16 | }
17 | ]
18 | })
19 |
20 | begin
21 | @webhook = @webhook.create
22 | logger.info "Webhook[#{@webhook.id}] created successfully"
23 | rescue ResourceNotFound => err
24 | logger.error @webhook.error.inspect
25 | end
26 |
--------------------------------------------------------------------------------
/samples/notifications/delete_webhook.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | require './runner.rb'
3 |
4 | include PayPal::SDK::REST
5 | include PayPal::SDK::Core::Logging
6 |
7 | begin
8 |
9 | @webhook = RunSample.run('notifications/get_webhook.rb', '@webhook')
10 |
11 | if @webhook.delete
12 | logger.info "Webhook[#{@webhook.id}] deleted successfully"
13 | else
14 | logger.error "Unable to delete Webhook[#{@webhook.id}]"
15 | logger.error @webhook.error.inspect
16 | end
17 | rescue ResourceNotFound => err
18 | logger.error "Webhook Not Found"
19 | end
20 |
--------------------------------------------------------------------------------
/samples/notifications/get_all_webhooks.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | require './runner.rb'
3 |
4 | include PayPal::SDK::REST
5 | include PayPal::SDK::Core::Logging
6 |
7 | begin
8 |
9 | RunSample.run('notifications/get_webhook.rb', '@webhook')
10 | RunSample.run('notifications/get_webhook.rb', '@webhook')
11 |
12 | # Get webhooks
13 | @webhooks_list = Webhook.all()
14 |
15 | logger.info "List Webhooks:"
16 | @webhooks_list.webhooks.each do |webhook|
17 | logger.info " -> Webhook Event Name[#{webhook.id}]"
18 | end
19 |
20 | rescue ResourceNotFound => err
21 | logger.error "Webhooks not found"
22 | ensure
23 | # Clean up webhooks as not to get into a bad state
24 | @webhooks_list.webhooks.each do |webhook|
25 | webhook.delete
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/samples/notifications/get_subscribed_webhooks_event_types.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | require './runner.rb'
3 |
4 | include PayPal::SDK::REST
5 | include PayPal::SDK::Core::Logging
6 |
7 | begin
8 |
9 | @webhook = RunSample.run('notifications/create.rb', '@webhook')
10 |
11 | # Get Payout Batch Status
12 | @webhook_event_types = Webhook.get_event_types(@webhook.id)
13 | logger.info "List Webhook Subscribed Events:"
14 | @webhook_event_types.event_types.each do |event|
15 | logger.info " -> Webhook Event Name[#{event.name}]"
16 | end
17 |
18 | rescue ResourceNotFound => err
19 | logger.error "Webhook Events not found"
20 | end
21 |
--------------------------------------------------------------------------------
/samples/notifications/get_webhook.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | require './runner.rb'
3 |
4 | include PayPal::SDK::REST
5 | include PayPal::SDK::Core::Logging
6 |
7 | begin
8 |
9 | @webhook = RunSample.run('notifications/create.rb', '@webhook')
10 |
11 | @webhook = Webhook.get(@webhook.id)
12 | logger.info "Got Webhook[#{@webhook.id}]"
13 |
14 | rescue ResourceNotFound => err
15 | logger.error "Payout Batch not Found"
16 | end
17 |
--------------------------------------------------------------------------------
/samples/notifications/get_webhook_event.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | require './runner.rb'
3 |
4 | include PayPal::SDK::REST
5 | include PayPal::SDK::Core::Logging
6 |
7 | begin
8 | @webhook_event = WebhookEvent.get("WH-7Y7254563A4550640-11V2185806837105M")
9 | @resource = @webhook_event.get_resource()
10 |
11 | rescue ResourceNotFound => err
12 | logger.error @webhook.error.inspect
13 | end
14 |
--------------------------------------------------------------------------------
/samples/notifications/get_webhooks_event_types.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | require './runner.rb'
3 |
4 | include PayPal::SDK::REST
5 | include PayPal::SDK::Core::Logging
6 |
7 | begin
8 |
9 | # Get webhooks event types
10 | @webhooks_event_types = WebhooksEventType.all()
11 |
12 | logger.info "List Webhook Events:"
13 | @webhooks_event_types.event_types.each do |event|
14 | logger.info " -> Webhook Event Name[#{event.name}]"
15 | end
16 |
17 | rescue ResourceNotFound => err
18 | logger.error "Webhook Events not found"
19 | end
20 |
--------------------------------------------------------------------------------
/samples/notifications/resend_webhook_event.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | require './runner.rb'
3 |
4 | include PayPal::SDK::REST
5 | include PayPal::SDK::Core::Logging
6 |
7 | begin
8 | @webhook_event = WebhookEvent.resend("WH-7Y7254563A4550640-11V2185806837105M")
9 | logger.info "Resent Webhook Event[#{@webhook_event.id}]"
10 |
11 | rescue ResourceNotFound => err
12 | logger.error @webhook.error.inspect
13 | end
14 |
--------------------------------------------------------------------------------
/samples/notifications/search_webhook_event.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | require './runner.rb'
3 |
4 | include PayPal::SDK::REST
5 | include PayPal::SDK::Core::Logging
6 |
7 | begin
8 |
9 | # Get webhooks event types
10 | @webhooks_events = WebhookEvent.search(10, "2013-03-06T11:00:00Z", "2013-04-06T11:00:00Z")
11 |
12 | logger.info "List Webhook Events:"
13 | @webhooks_events.events.each do |event|
14 | logger.info " -> Webhook Event Name[#{event.name}]"
15 | end
16 |
17 | rescue ResourceNotFound => err
18 | logger.error "Webhook Events not found"
19 | end
20 |
--------------------------------------------------------------------------------
/samples/notifications/simulate_event.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | require './runner.rb'
3 |
4 | include PayPal::SDK::REST
5 | include PayPal::SDK::Core::Logging
6 |
7 | begin
8 |
9 | @webhook_event = Webhook.simulate_event(nil, "https://requestb.in/1jbk3uv1", "PAYMENT.CAPTURE.COMPLETED")
10 |
11 | @resource = @webhook_event.get_resource()
12 |
13 | rescue ResourceNotFound => err
14 | logger.error "Payout Batch not Found"
15 | end
16 |
--------------------------------------------------------------------------------
/samples/notifications/update_webhook.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | require './runner.rb'
3 | require "securerandom"
4 |
5 | include PayPal::SDK::REST
6 | include PayPal::SDK::Core::Logging
7 |
8 | begin
9 | @webhook = RunSample.run('notifications/create.rb', '@webhook')
10 |
11 | # set up a patch request
12 | patch = Patch.new
13 | patch.op = "replace"
14 | patch.path = "/url"
15 | patch.value = "https://www.yeowza.com/paypal_webhook_new_url_"+SecureRandom.hex(8)
16 |
17 | if @webhook.update(patch)
18 | logger.info "Webhook[#{@webhook.id}] updated successfully"
19 | else
20 | logger.error @webhook.error.inspect
21 | end
22 | rescue ResourceNotFound => err
23 | logger.error @webhook.error.inspect
24 | end
25 |
--------------------------------------------------------------------------------
/samples/notifications/verify_webhook_event.rb:
--------------------------------------------------------------------------------
1 | # webhook validation (see https://developer.paypal.com/docs/integration/direct/rest-webhooks-overview/#event-signature )
2 |
3 | require 'paypal-sdk-rest'
4 | include PayPal::SDK::REST
5 | include PayPal::SDK::Core::Logging
6 |
7 | # Below code demonstrates how to parse information from the request coming from PayPal webhook servers.
8 | # For more information: https://github.com/paypal/PayPal-Ruby-SDK/issues/205#issuecomment-249051953
9 | # webhook headers required for event verification
10 |
11 | # actual_signature = request.headers["Paypal-Transmission-Sig"]
12 | # auth_algo = request.headers["Paypal-Auth-Algo"]
13 | # auth_algo.sub!(/withRSA/i, "")
14 | # cert_url = request.headers["Paypal-Cert-Url"]
15 | # transmission_id = request.headers["Paypal-Transmission-Id"]
16 | # timestamp = request.headers["Paypal-Transmission-Time"]
17 | # webhook_id = ENV['PAYPAL_WEBHOOK_ID'] #The webhook_id provided by PayPal when webhook is created on the PayPal developer site
18 | # event_body = params["paypal"].to_json
19 |
20 | # MOCK DATA for Sample purpose only. Please use above code for real use cases.
21 | # Paypal-Transmission-Sig header
22 | actual_signature = "thy4/U002quzxFavHPwbfJGcc46E8rc5jzgyeafWm5mICTBdY/8rl7WJpn8JA0GKA+oDTPsSruqusw+XXg5RLAP7ip53Euh9Xu3UbUhQFX7UgwzE2FeYoY6lyRMiiiQLzy9BvHfIzNIVhPad4KnC339dr6y2l+mN8ALgI4GCdIh3/SoJO5wE64Bh/ueWtt8EVuvsvXfda2Le5a2TrOI9vLEzsm9GS79hAR/5oLexNz8UiZr045Mr5ObroH4w4oNfmkTaDk9Rj0G19uvISs5QzgmBpauKr7Nw++JI0pr/v5mFctQkoWJSGfBGzPRXawrvIIVHQ9Wer48GR2g9ZiApWg=="
23 | # Paypal-Auth-Algo header
24 | auth_algo = "sha256"
25 | # Paypal-Cert-Url header
26 | cert_url = "https://api.sandbox.paypal.com/v1/notifications/certs/CERT-360caa42-fca2a594-a5cafa77"
27 | # other required items for event verification
28 | transmission_id = "dfb3be50-fd74-11e4-8bf3-77339302725b"
29 | timestamp = "2015-05-18T15:45:13Z"
30 | webhook_id = "4JH86294D6297924G"
31 | event_body = '{"id":"WH-0G2756385H040842W-5Y612302CV158622M","create_time":"2015-05-18T15:45:13Z","resource_type":"sale","event_type":"PAYMENT.SALE.COMPLETED","summary":"Payment completed for $ 20.0 USD","resource":{"id":"4EU7004268015634R","create_time":"2015-05-18T15:44:02Z","update_time":"2015-05-18T15:44:21Z","amount":{"total":"20.00","currency":"USD"},"payment_mode":"INSTANT_TRANSFER","state":"completed","protection_eligibility":"ELIGIBLE","protection_eligibility_type":"ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE","parent_payment":"PAY-86C81811X5228590KKVNARQQ","transaction_fee":{"value":"0.88","currency":"USD"},"links":[{"href":"https://api.sandbox.paypal.com/v1/payments/sale/4EU7004268015634R","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/payments/sale/4EU7004268015634R/refund","rel":"refund","method":"POST"},{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-86C81811X5228590KKVNARQQ","rel":"parent_payment","method":"GET"}]},"links":[{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-0G2756385H040842W-5Y612302CV158622M","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-0G2756385H040842W-5Y612302CV158622M/resend","rel":"resend","method":"POST"}]}'
32 |
33 | # verify webhook
34 | # pass all the field to `WebhookEvent.verify()` method which returns true or false based on validation
35 | valid = WebhookEvent.verify(transmission_id, timestamp, webhook_id, event_body, cert_url, actual_signature, auth_algo)
36 |
37 | if valid
38 | logger.info "webhook event #{webhook_id} has been verified"
39 | else
40 | logger.info "webhook event #{webhook_id} validation failed"
41 | end
42 |
--------------------------------------------------------------------------------
/samples/payment/all.rb:
--------------------------------------------------------------------------------
1 | # #GetPaymentList Sample
2 | # This sample code demonstrate how you can
3 | # retrieve a list of all Payment resources
4 | # you've created using the Payments API.
5 | # Note various query parameters that you can
6 | # use to filter, and paginate through the
7 | # payments list.
8 | # API used: GET /v1/payments/payments
9 | require 'paypal-sdk-rest'
10 | include PayPal::SDK::REST
11 | include PayPal::SDK::Core::Logging
12 |
13 | # ###Retrieve
14 | # Retrieve the PaymentHistory by calling the
15 | # `all` method
16 | # on the Payment class
17 | # Refer the API documentation
18 | # for valid values for keys
19 | # Supported paramters are :count, :next_id
20 | @payment_history = Payment.all( :count => 5 )
21 |
22 | # List Payments
23 | logger.info "List Payment:"
24 | @payment_history.payments.each do |payment|
25 | logger.info " -> Payment[#{payment.id}]"
26 | end
27 |
--------------------------------------------------------------------------------
/samples/payment/create_future_payment.rb:
--------------------------------------------------------------------------------
1 | # #Future Payment Sample
2 | # This sample code demonstrate how you can
3 | # create a Future Payment.
4 | # This is a console application, so run it with `bundle exec ruby payment/create_future_payment.rb` on terminal
5 | # API used: CREATE /v1/payments/payments
6 | # /v1/oauth2/token
7 |
8 | require 'paypal-sdk-rest'
9 | include PayPal::SDK::REST::DataTypes
10 | include PayPal::SDK::Core::Logging
11 |
12 |
13 | # authorization code from mobile sdk
14 | authorization_code = ''
15 |
16 | # correlation ID from mobile sdk
17 | correlation_id = ''
18 |
19 | # Initialize the payment object
20 | payment = {
21 | "intent" => "authorize",
22 | "payer" => {
23 | "payment_method" => "paypal" },
24 | "transactions" => [ {
25 | "amount" => {
26 | "total" => "1.00",
27 | "currency" => "USD" },
28 | "description" => "This is the payment transaction description." } ] }
29 |
30 | # exchange authorization code with refresh/access token
31 | logger.info "Exchange authorization code with refresh/access token"
32 | tokeninfo = FuturePayment.exch_token(authorization_code)
33 |
34 | # get access_token, refresh_token from tokeninfo. refresh_token can be exchanged with access token. See https://github.com/paypal/PayPal-Ruby-SDK#openidconnect-samples
35 | access_token = tokeninfo.access_token
36 | logger.info "Successfully retrieved access_token=#{access_token} refresh_token=#{tokeninfo.refresh_token}"
37 |
38 | # more attribute available in tokeninfo
39 | logger.info tokeninfo.to_hash
40 |
41 | # Create Payments
42 | logger.info "Create Future Payment"
43 | future_payment = FuturePayment.new(payment.merge( :token => access_token ))
44 | success = future_payment.create(correlation_id)
45 |
46 | # check response for status
47 | if success
48 | logger.info "future payment successfully created"
49 | else
50 | logger.info "future payment creation failed"
51 | end
52 |
--------------------------------------------------------------------------------
/samples/payment/create_third_party_with_paypal.rb:
--------------------------------------------------------------------------------
1 | # #Create Third Party Payment Using PayPal Sample
2 | # This sample code demonstrates how you can process a
3 | # PayPal Account based Payment.
4 | # API used: /v1/payments/payment
5 | require 'paypal-sdk-rest'
6 | include PayPal::SDK::REST
7 | include PayPal::SDK::Core::Logging
8 |
9 | # ###Payment
10 | # A Payment Resource; create one using
11 | # the above types and intent as 'sale'
12 | @payment = Payment.new({
13 | :intent => "sale",
14 |
15 | # ###Payer
16 | # A resource representing a Payer that funds a payment
17 | # Payment Method as 'paypal'
18 | :payer => {
19 | :payment_method => "paypal" },
20 |
21 | # ###Redirect URLs
22 | :redirect_urls => {
23 | :return_url => "http://localhost:3000/payment/execute",
24 | :cancel_url => "http://localhost:3000/" },
25 |
26 | # ###Transaction
27 | # A transaction defines the contract of a
28 | # payment - what is the payment for and who
29 | # is fulfilling it.
30 | :transactions => [{
31 |
32 | # ### Payee
33 | # Specify a payee with that user's email or merchant id
34 | # Merchant Id can be found at https://www.paypal.com/businessprofile/settings/
35 | :payee => {
36 | :email => "[email protected]"
37 | },
38 |
39 | # Item List
40 | :item_list => {
41 | :items => [{
42 | :name => "item",
43 | :sku => "item",
44 | :price => "5",
45 | :currency => "USD",
46 | :quantity => 1 }]},
47 |
48 | # ###Amount
49 | # Let's you specify a payment amount.
50 | :amount => {
51 | :total => "5",
52 | :currency => "USD" },
53 | :description => "This is the payment transaction description." }]})
54 |
55 | # Create Payment and return status
56 | if @payment.create
57 | # Redirect the user to given approval url
58 | @redirect_url = @payment.links.find{|v| v.rel == "approval_url" }.href
59 | logger.info "Payment[#{@payment.id}]"
60 | logger.info "Redirect: #{@redirect_url}"
61 | else
62 | logger.error @payment.error.inspect
63 | end
64 |
--------------------------------------------------------------------------------
/samples/payment/create_with_paypal.rb:
--------------------------------------------------------------------------------
1 | # #Create Payment Using PayPal Sample
2 | # This sample code demonstrates how you can process a
3 | # PayPal Account based Payment.
4 | # API used: /v1/payments/payment
5 | require 'paypal-sdk-rest'
6 | include PayPal::SDK::REST
7 | include PayPal::SDK::Core::Logging
8 |
9 | # ###Payment
10 | # A Payment Resource; create one using
11 | # the above types and intent as 'sale'
12 | @payment = Payment.new({
13 | :intent => "sale",
14 |
15 | # ###Payer
16 | # A resource representing a Payer that funds a payment
17 | # Payment Method as 'paypal'
18 | :payer => {
19 | :payment_method => "paypal" },
20 |
21 | # ###Redirect URLs
22 | :redirect_urls => {
23 | :return_url => "http://localhost:3000/payment/execute",
24 | :cancel_url => "http://localhost:3000/" },
25 |
26 | # ###Transaction
27 | # A transaction defines the contract of a
28 | # payment - what is the payment for and who
29 | # is fulfilling it.
30 | :transactions => [{
31 |
32 | # Item List
33 | :item_list => {
34 | :items => [{
35 | :name => "item",
36 | :sku => "item",
37 | :price => "5",
38 | :currency => "USD",
39 | :quantity => 1 }]},
40 |
41 | # ###Amount
42 | # Let's you specify a payment amount.
43 | :amount => {
44 | :total => "5",
45 | :currency => "USD" },
46 | :description => "This is the payment transaction description." }]})
47 |
48 | # Create Payment and return status
49 | if @payment.create
50 | # Redirect the user to given approval url
51 | @redirect_url = @payment.links.find{|v| v.rel == "approval_url" }.href
52 | logger.info "Payment[#{@payment.id}]"
53 | logger.info "Redirect: #{@redirect_url}"
54 | else
55 | logger.error @payment.error.inspect
56 | end
57 |
--------------------------------------------------------------------------------
/samples/payment/execute.rb:
--------------------------------------------------------------------------------
1 | # # Execute an approved PayPal payment
2 | # Use this call to execute (complete) a PayPal payment that has been approved by the payer.
3 | # You can optionally update transaction information by passing in one or more transactions.
4 | # API used: /v1/payments/payment
5 | require 'paypal-sdk-rest'
6 | include PayPal::SDK::REST
7 | include PayPal::SDK::Core::Logging
8 |
9 | # ID of the payment. This ID is provided when creating payment.
10 | payment_id = ENV["PAYMENT_ID"] || "PAY-83Y70608H1071210EKES5UNA"
11 | @payment = Payment.find(payment_id)
12 |
13 | # PayerID is required to approve the payment.
14 | if @payment.execute( :payer_id => ENV["PAYER_ID"] || "DUFRQ8GWYMJXC" ) # return true or false
15 | logger.info "Payment[#{@payment.id}] execute successfully"
16 | else
17 | logger.error @payment.error.inspect
18 | end
19 |
20 |
--------------------------------------------------------------------------------
/samples/payment/find.rb:
--------------------------------------------------------------------------------
1 | # #GetPayment Sample
2 | # This sample code demonstrates how you can retrieve
3 | # the details of a payment resource.
4 | # API used: /v1/payments/payment/{payment-id}
5 | require 'paypal-sdk-rest'
6 | include PayPal::SDK::REST
7 | include PayPal::SDK::Core::Logging
8 |
9 | begin
10 | # Retrieve the payment object by calling the
11 | # `find` method
12 | # on the Payment class by passing Payment ID
13 | @payment = Payment.find("PAY-0XL713371A312273YKE2GCNI")
14 | logger.info "Got Payment Details for Payment[#{@payment.id}]"
15 |
16 | rescue ResourceNotFound => err
17 | # It will throw ResourceNotFound exception if the payment not found
18 | logger.error "Payment Not Found"
19 | end
20 |
--------------------------------------------------------------------------------
/samples/payment/update.rb:
--------------------------------------------------------------------------------
1 | # #GetPayment Sample
2 | # This sample code demonstrates how you can retrieve
3 | # the details of a payment resource.
4 | # API used: /v1/payments/payment/{payment-id}
5 | require 'paypal-sdk-rest'
6 | include PayPal::SDK::REST
7 | include PayPal::SDK::Core::Logging
8 |
9 | begin
10 | # Retrieve the payment object by calling the
11 | # `find` method
12 | # on the Payment class by passing Payment ID
13 | @payment = Payment.find("PAY-6BB05346FG6727110KYZEGNQ")
14 | logger.info "Got Payment Details for Payment[#{@payment.id}]"
15 | updated_payment = {
16 | :op=> "replace",
17 | :path=> "/transactions/0/amount",
18 | :value=> {
19 | :total=> "40.00",
20 | :currency=> "BRL",
21 | :details=> {:shipping=>"25.00", :subtotal=>"15.00"}
22 | }
23 | }
24 | patch_request = Patch.new(updated_payment)
25 | @payment.update(updated_payment)
26 |
27 | rescue ResourceNotFound => err
28 | # It will throw ResourceNotFound exception if the payment not found
29 | logger.error "Payment Not Found"
30 | end
31 |
--------------------------------------------------------------------------------
/samples/payouts/cancel.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | require './runner.rb'
3 |
4 | include PayPal::SDK::REST
5 | include PayPal::SDK::Core::Logging
6 |
7 | begin
8 |
9 | # Create a Single Synchronous Payout with Invalid (Unclaimable Email Address)
10 | @payout_batch = RunSample.run('payouts/createSync.rb', '@payout_batch')
11 |
12 | # Cancel the item
13 | @payout_item_detail= PayoutItem.cancel(@payout_batch.items[0].payout_item_id)
14 | logger.info "Cancelled Unclaimed Payout with Item ID [#{@payout_item_detail.payout_item_id}]"
15 |
16 | rescue ResourceNotFound => err
17 | logger.error "Payout Item could not be cancelled"
18 | end
19 |
--------------------------------------------------------------------------------
/samples/payouts/create.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | require 'securerandom'
3 | require './runner.rb'
4 |
5 | include PayPal::SDK::REST
6 | include PayPal::SDK::Core::Logging
7 |
8 | @payout = Payout.new({
9 | :sender_batch_header => {
10 | :sender_batch_id => SecureRandom.hex(8),
11 | :email_subject => 'You have a Payout!'
12 | },
13 | :items => [
14 | {
15 | :recipient_type => 'EMAIL',
16 | :amount => {
17 | :value => '1.0',
18 | :currency => 'USD'
19 | },
20 | :note => 'Thanks for your patronage!',
21 | :sender_item_id => '2014031400023',
22 | :receiver => '[email protected]'
23 | }
24 | ]
25 | })
26 | begin
27 | @payout_batch = @payout.create
28 | logger.info "Created Payout with [#{@payout_batch.batch_header.payout_batch_id}]"
29 | rescue ResourceNotFound => err
30 | logger.error @payout.error.inspect
31 | end
32 |
--------------------------------------------------------------------------------
/samples/payouts/createSync.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | require 'securerandom'
3 | require './runner.rb'
4 |
5 | include PayPal::SDK::REST
6 | include PayPal::SDK::Core::Logging
7 |
8 | @payouts = Payout.new({
9 | :sender_batch_header => {
10 | :sender_batch_id => SecureRandom.hex(8),
11 | :email_subject => 'You have a Payout!'
12 | },
13 | :items => [
14 | {
15 | :recipient_type => 'EMAIL',
16 | :amount => {
17 | :value => '1.0',
18 | :currency => 'USD'
19 | },
20 | :note => 'Thanks for your patronage!',
21 | :sender_item_id => '2014031400023',
22 | :receiver => '[email protected]'
23 | }
24 | ]
25 | })
26 | begin
27 | @payout_batch = @payouts.create(true)
28 | logger.info "Created Synchronous Payout with [#{@payout_batch.batch_header.payout_batch_id}]"
29 | rescue ResourceNotFound => err
30 | logger.error @payouts.error.inspect
31 | end
32 |
--------------------------------------------------------------------------------
/samples/payouts/createVenmo.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | require 'securerandom'
3 | require './runner.rb'
4 |
5 | include PayPal::SDK::REST
6 | include PayPal::SDK::Core::Logging
7 |
8 | @payout = Payout.new({
9 | :sender_batch_header => {
10 | :sender_batch_id => SecureRandom.hex(8),
11 | :email_subject => 'You have a Payout!'
12 | },
13 | :items => [
14 | {
15 | :recipient_type => 'PHONE',
16 | :amount => {
17 | :value => '1.0',
18 | :currency => 'USD'
19 | },
20 | :note => 'Thanks for your patronage!',
21 | :sender_item_id => '2014031400023',
22 | :receiver => '5551232368',
23 | :recipient_wallet => 'VENMO'
24 | }
25 | ]
26 | })
27 | begin
28 | @payout_batch = @payout.create
29 | logger.info "Created Venmo Payout with [#{@payout_batch.batch_header.payout_batch_id}]"
30 | rescue ResourceNotFound => err
31 | logger.error @payout.error.inspect
32 | end
33 |
--------------------------------------------------------------------------------
/samples/payouts/get_batch_status.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | require './runner.rb'
3 |
4 | include PayPal::SDK::REST
5 | include PayPal::SDK::Core::Logging
6 |
7 | begin
8 |
9 | # Create a Batch Payout.
10 | @payout_batch = RunSample.run('payouts/create.rb', '@payout_batch')
11 |
12 | # Get Payout Batch Status
13 | @payout_batch= Payout.get(@payout_batch.batch_header.payout_batch_id)
14 | logger.info "Got Payout Batch Status[#{@payout_batch.batch_header.payout_batch_id}]"
15 |
16 | rescue ResourceNotFound => err
17 | logger.error "Payout Batch not Found"
18 | end
19 |
--------------------------------------------------------------------------------
/samples/payouts/get_item_status.rb:
--------------------------------------------------------------------------------
1 | require 'paypal-sdk-rest'
2 | require './runner.rb'
3 | include PayPal::SDK::REST
4 | include PayPal::SDK::Core::Logging
5 |
6 | begin
7 |
8 | # Create a Batch Payout.
9 | @payout_batch = RunSample.run('payouts/get_batch_status.rb', '@payout_batch')
10 |
11 | # Get Payout Item Status
12 | @payout_item_details= PayoutItem.get(@payout_batch.items[0].payout_item_id)
13 | logger.info "Got Payout Item Status[#{@payout_item_details.payout_item_id}]"
14 |
15 | rescue ResourceNotFound => err
16 | logger.error "Payout Item not Found"
17 | end
18 |
--------------------------------------------------------------------------------
/samples/public/images/edt-format-source-button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codigofacilito/PayPal-Ruby-SDK/b116bacbf4c43f056193fcd9b62c3131d482065d/samples/public/images/edt-format-source-button.png
--------------------------------------------------------------------------------
/samples/public/images/play_button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codigofacilito/PayPal-Ruby-SDK/b116bacbf4c43f056193fcd9b62c3131d482065d/samples/public/images/play_button.png
--------------------------------------------------------------------------------
/samples/runner.rb:
--------------------------------------------------------------------------------
1 | # Run Samples on different scope
2 | module RunSample
3 | def self.logger
4 | PayPal::SDK::Core::Config.logger
5 | end
6 |
7 | def self.run(file, variable)
8 | object_binding = binding
9 | object_binding.eval(File.read("./#{file}"))
10 | object_binding.eval(variable)
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/samples/sale/find.rb:
--------------------------------------------------------------------------------
1 | # # Get Details of a Sale Transaction Sample
2 | # This sample code demonstrates how you can retrieve
3 | # details of completed Sale Transaction.
4 | # API used: /v1/payments/sale/{sale-id}
5 | require 'paypal-sdk-rest'
6 | include PayPal::SDK::REST
7 | include PayPal::SDK::Core::Logging
8 |
9 | begin
10 | # Get Sale object by passing sale id
11 | @sale = Sale.find("7DY409201T7922549")
12 | logger.info "Got Sale[#{@sale.id}]"
13 | rescue ResourceNotFound => err
14 | logger.error "Sale Not Found"
15 | end
16 |
--------------------------------------------------------------------------------
/samples/sale/refund.rb:
--------------------------------------------------------------------------------
1 | # #SaleRefund Sample
2 | # This sample code demonstrate how you can
3 | # process a refund on a sale transaction created
4 | # using the Payments API.
5 | # API used: /v1/payments/sale/{sale-id}/refund
6 | require 'paypal-sdk-rest'
7 | include PayPal::SDK::REST
8 | include PayPal::SDK::Core::Logging
9 |
10 | @sale = Sale.find("7DY409201T7922549")
11 |
12 | # Make Refund API call
13 | # Set amount only if the refund is partial
14 | @refund = @sale.refund_request({
15 | :amount => {
16 | :total => "0.01",
17 | :currency => "USD" } })
18 |
19 | # Check refund status
20 | if @refund.success?
21 | logger.info "Refund[#{@refund.id}] Success"
22 | else
23 | logger.error "Unable to Refund"
24 | logger.error @refund.error.inspect
25 | end
26 |
--------------------------------------------------------------------------------
/samples/views/display_hash.haml:
--------------------------------------------------------------------------------
1 | !!!
2 | %html
3 | %head
4 | %title PayPal Rest API Samples
5 | %body
6 | %a{:href => ".."} Back
7 | - if display_hash.success?
8 | %h3= header
9 | .display-hash
10 | = CodeRay.scan(MultiJson.dump(display_hash.to_hash, :pretty => true), "json").div
11 | - else
12 | %h3 Error while #{header}
13 | .display-hash
14 | = CodeRay.scan(MultiJson.dump(display_hash.error, :pretty => true), "json").div
15 | %a{:href => ".."} Back
16 |
17 |
--------------------------------------------------------------------------------
/spec/README.md:
--------------------------------------------------------------------------------
1 | How to run tests
2 | ================
3 |
4 | The SDK tests are composed of two groups: unit test group and integration (functional) test group. Integration test group is by default set not to run.
5 |
6 | - run a single test
7 | - `$ bundle exec rspec <test-file>:<line-number>`
8 | - e.g., to run payment create test,
9 | - `$ bundle exec rspec spec/payments_examples_spec.rb:53`
10 |
11 | - run multiple tests in the same file
12 | - Add `:<line-number>` to the above command. For example, in order to execute payment create and payment list tests,
13 | - `$ bundle exec rspec spec/payments_examples_spec.rb:53:95`
14 |
15 | - run integration tests
16 | - This will set the 'integration' flag and will execute functional tests against sandbox.
17 | - `$ bundle exec rspec --tag integration`
18 |
19 | - run tests with a specific String
20 | - `$ bundle exec rspec -e "<string>"`
21 | - e.g., to run any tests with "Sa" in test description (for the time being, it will be "Sale" tests)
22 | - `$ bundle exec rspec -e "Sa"`
23 |
--------------------------------------------------------------------------------
/spec/config/cert_key.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIICXAIBAAKBgQCx/rJhKDRYhs9WZj66FA+HidsrKwvep3g+YNbm1fXmjcg2rEmC
3 | kq71+Ftw9rx0Uz7vmg6vcsASUgOyeNG7mVB1SsXc6j+JAzZsmpzxHI0QKm+nBNTS
4 | OAp5NWn6NZQfu3BNAJ/Mok/iL3am2DWXV6dU74J66rBpwIJfzs9kmw8ZGwIDAQAB
5 | AoGAa/V1sCQ4i7FItLjTNv3P5X+h5W74hhXBguQttFj2Ct7YHwEknQPnBt2aaMve
6 | xhdvxtgELDpHcVU5VNifLU/yUg3+DSr/YkpBWOcNTCt1seW/z5s+jr2fQERQKbyf
7 | SXWMTqwrQ19iQoCPYaj7Drf68JhksQCaYN650g7+B/QmSBECQQDp6r75fzDtEWrr
8 | O4Sl9plK6CRLqQQ3LveAw4JV31N2UAqgAYtzRqD6K+SviAVtX9xxuv983qQxsfX4
9 | ozE9sGXPAkEAwsxwR1s2Acuy10h3Xj6VtnFB3PpUrkSI9c9ZxF4CMf/+AS/b2UEe
10 | QhH60WHY8ccgKT/DoPWBcEu2o0f9nPw29QJBAI480zHNeMe/Hp+5iliM0fvtmxxy
11 | wwB3S8L9n4RuD0dTNpLDPbO0D/DvvdhKwtoWP2rcxbx9eaRKTYKKYUfcupsCQAkP
12 | SQmIjHJ47tBkZmjTsFLT4aRNYDLarSQBiMNBPAjnRwD3INpx1N5tx6SFUHmuMSi5
13 | 9nc9888tNklRx9HNSSECQHgs9ExBpA6WbRVcgiizOKH7fmNxAB5f6TQ2W1QHMUb+
14 | UhZpwuDelOIfzJAQUZGTZk8a8uVmyXU5hTf3ZDbrnJ8=
15 | -----END RSA PRIVATE KEY-----
16 |
17 | -----BEGIN CERTIFICATE-----
18 | MIICpjCCAg+gAwIBAgIDD96nMA0GCSqGSIb3DQEBBQUAMIGfMQswCQYDVQQGEwJV
19 | UzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIU2FuIEpvc2UxFTATBgNV
20 | BAoTDFBheVBhbCwgSW5jLjEWMBQGA1UECxQNc2FuZGJveF9jZXJ0czEbMBkGA1UE
21 | AxQSc2FuZGJveF9jYW1lcmNoYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwu
22 | Y29tMB4XDTA5MTAxNTA2Mzg1N1oXDTE5MTAxMzA2Mzg1N1owgYAxLTArBgNVBAMU
23 | JHBsYXRmb18xMjU1MTcwNjk0X2Jpel9hcGkxLmdtYWlsLmNvbTEiMCAGA1UEChMZ
24 | cGxhdGZvcm0gc2RrJ3MgVGVzdCBTdG9yZTERMA8GA1UEBxMIU2FuIEpvc2UxCzAJ
25 | BgNVBAgTAkNBMQswCQYDVQQGEwJVUzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
26 | gYEAsf6yYSg0WIbPVmY+uhQPh4nbKysL3qd4PmDW5tX15o3INqxJgpKu9fhbcPa8
27 | dFM+75oOr3LAElIDsnjRu5lQdUrF3Oo/iQM2bJqc8RyNECpvpwTU0jgKeTVp+jWU
28 | H7twTQCfzKJP4i92ptg1l1enVO+CeuqwacCCX87PZJsPGRsCAwEAAaMNMAswCQYD
29 | VR0TBAIwADANBgkqhkiG9w0BAQUFAAOBgQCgH3kwXMJtcAaCBQLKz5TGFogJp/C3
30 | 06MvjYzdbDrx9Rjf/252UhD8dMPUP5FhU1KXduL+KIEYawPbDQ9+lV58JgM12R0p
31 | EhCODDI/lDvzbfxUnYgkJ5cnFhTZpcAqVzWuinUnG8jAL9XKiEyu/C73ePMPWPbt
32 | otoWi+Tk828Qlw==
33 | -----END CERTIFICATE-----
34 |
--------------------------------------------------------------------------------
/spec/config/paypal.yml:
--------------------------------------------------------------------------------
1 | test: &default
2 | client_id: AYSq3RDGsmBLJE-otTkBtM-jBRd1TCQwFf9RGfwddNXWz0uFU9ztymylOhRS
3 | client_secret: EGnHDxD_qRPdaLdZz8iCr8N7_MzF-YHPTkjs6NKYQvQSBngp4PTTVWkPZRbL
4 | username: jb-us-seller_api1.paypal.com
5 | password: WX4WTU3S8MY44S7F
6 | signature: AFcWxV21C7fd0v3bYYYRCpSSRl31A7yDhhsPUU2XhtMoZXsWHFxu-RWy
7 | app_id: APP-80W284485P519543T
8 | http_timeout: 120
9 | mode: sandbox
10 | sandbox_email_address: [email protected]
11 |
12 | development:
13 | <<: *default
14 |
15 | with_authentication:
16 | <<: *default
17 | client_id: AYSq3RDGsmBLJE-otTkBtM-jBRd1TCQwFf9RGfwddNXWz0uFU9ztymylOhRS
18 | client_secret: EGnHDxD_qRPdaLdZz8iCr8N7_MzF-YHPTkjs6NKYQvQSBngp4PTTVWkPZRbL
19 |
20 | with_certificate:
21 | <<: *default
22 | username: platfo_1255170694_biz_api1.gmail.com
23 | password: 2DPPKUPKB7DQLXNR
24 | signature:
25 | cert_path: <%= File.expand_path("../cert_key.pem", __FILE__) %>
26 | app_id: APP-80W284485P519543T
27 |
28 | with_oauth_token:
29 | <<: *default
30 | token: 3rMSi3kCmK1Q3.BKxkH29I53R0TRLrSuCO..l8AMOAFM6cQhPTTrfQ
31 | token_secret: RuE1j8RNRlSuL5T-PSSpVWLvOlI
32 |
33 | with_proxy:
34 | <<: *default
35 | http_proxy: <%= ENV['http_proxy'] %>
36 |
--------------------------------------------------------------------------------
/spec/config/sample_data.yml:
--------------------------------------------------------------------------------
1 | ipn:
2 | valid_message: item_number=&residence_country=US&verify_sign=AFcWxV21C7fd0v3bYYYRCpSSRl31AXi5tzp0u2U-8QDyy.oC2A1Dhx04&address_country=United+States&address_city=San+Jose&address_status=unconfirmed&business=platfo_1255077030_biz%40gmail.com&payment_status=Pending&transaction_subject=&protection_eligibility=Ineligible&shipping=0.00&payer_id=934EKX9W68RRU&first_name=John&mc_fee=0.38&txn_id=5AL16697HX185734U&quantity=1&receiver_email=platfo_1255077030_biz%40gmail.com&notify_version=3.7&txn_type=web_accept&mc_gross=1.00&payer_status=unverified&mc_currency=USD&test_ipn=1&custom=&payment_date=01%3A48%3A31+Dec+04%2C+2012+PST&payment_fee=0.38&charset=windows-1252&address_country_code=US&payment_gross=1.00&address_zip=95131&ipn_track_id=af0f53159f21e&address_state=CA&receipt_id=4050-1771-4106-3070&pending_reason=paymentreview&tax=0.00&handling_amount=0.00&item_name=&address_name=John+Doe&last_name=Doe&payment_type=instant&receiver_id=HZH2W8NPXUE5W&address_street=1+Main+St
3 | invalid_message: invalid=invalid
4 |
--------------------------------------------------------------------------------
/spec/core/api/rest_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe PayPal::SDK::Core::API::REST do
4 |
5 | module PayPalRest
6 | class API < PayPal::SDK::Core::API::REST
7 | end
8 | end
9 |
10 | def create_api(*args)
11 | api = PayPalRest::API.new(*args)
12 | @log_file ||= File.open("spec/log/rest_http.log", "w")
13 | api.http.set_debug_output(@log_file)
14 | api
15 | end
16 |
17 | before :all do
18 | @api = create_api("v1/payments/", :with_authentication)
19 | @vault_api = create_api("v1/vault/", :with_authentication)
20 | end
21 |
22 | describe "Configuration" do
23 | it "create api with prefix" do
24 | api = create_api("v1/payments")
25 | expect(api.uri.path).to eql "/v1/payments"
26 | end
27 |
28 | it "service endpoint for sandbox" do
29 | api = create_api
30 | expect(api.service_endpoint).to eql "https://api.sandbox.paypal.com"
31 | expect(api.token_endpoint).to eql "https://api.sandbox.paypal.com"
32 | api = create_api( :mode => "sandbox" )
33 | expect(api.service_endpoint).to eql "https://api.sandbox.paypal.com"
34 | expect(api.token_endpoint).to eql "https://api.sandbox.paypal.com"
35 | api = create_api( :mode => :sandbox )
36 | expect(api.service_endpoint).to eql "https://api.sandbox.paypal.com"
37 | expect(api.token_endpoint).to eql "https://api.sandbox.paypal.com"
38 | api = create_api( :mode => "invalid" )
39 | expect(api.service_endpoint).to eql "https://api.sandbox.paypal.com"
40 | expect(api.token_endpoint).to eql "https://api.sandbox.paypal.com"
41 | api = create_api( :mode => nil )
42 | expect(api.service_endpoint).to eql "https://api.sandbox.paypal.com"
43 | expect(api.token_endpoint).to eql "https://api.sandbox.paypal.com"
44 | end
45 |
46 | it "service endpoint for live" do
47 | api = create_api( :mode => "live" )
48 | expect(api.service_endpoint).to eql "https://api.paypal.com"
49 | expect(api.token_endpoint).to eql "https://api.paypal.com"
50 | api = create_api( :mode => :live )
51 | expect(api.service_endpoint).to eql "https://api.paypal.com"
52 | expect(api.token_endpoint).to eql "https://api.paypal.com"
53 | end
54 |
55 | it "override service endpoint" do
56 | api = create_api( :rest_endpoint => "https://testing.api.paypal.com" )
57 | expect(api.service_endpoint).to eql "https://testing.api.paypal.com"
58 | expect(api.token_endpoint).to eql "https://testing.api.paypal.com"
59 | api = create_api( :endpoint => "https://testing.api.paypal.com" )
60 | expect(api.service_endpoint).to eql "https://testing.api.paypal.com"
61 | expect(api.token_endpoint).to eql "https://testing.api.paypal.com"
62 | end
63 |
64 | it "override token endpoint" do
65 | api = create_api( :rest_token_endpoint => "https://testing.api.paypal.com" )
66 | expect(api.service_endpoint).to eql "https://api.sandbox.paypal.com"
67 | expect(api.token_endpoint).to eql "https://testing.api.paypal.com"
68 | end
69 | end
70 |
71 | describe "Validation" do
72 | it "Invalid client_id and client_secret" do
73 | api = create_api(:with_authentication, :client_id => "XYZ", :client_secret => "ABC")
74 | expect {
75 | api.token
76 | }.to raise_error PayPal::SDK::Core::Exceptions::UnauthorizedAccess
77 | end
78 |
79 | it "Should handle expired token" do
80 | old_token = @api.token
81 | @api.token_hash[:expires_in] = 0
82 | new_token = @api.token
83 | expect(@api.token_hash[:expires_in]).not_to eql 0
84 | end
85 |
86 | it "Get token" do
87 | expect(@api.token).not_to be_nil
88 | end
89 | end
90 |
91 | describe "Success request", :integration => true do
92 |
93 | it "Create Payment" do
94 | response = @api.post("payment", {
95 | "intent" => "sale",
96 | "payer" => {
97 | "payment_method" => "credit_card",
98 | "funding_instruments" => [{
99 | "credit_card" => {
100 | "type" => "visa",
101 | "number" => "4567516310777851",
102 | "expire_month" => "11", "expire_year" => "2018",
103 | "first_name" => "Joe", "last_name" => "Shopper" }}]},
104 | "transactions" => [{
105 | "amount" => {
106 | "total" => "7.47",
107 | "currency" => "USD" }}]})
108 | expect(response["error"]).to be_nil
109 | end
110 |
111 | it "List Payments" do
112 | response = @api.get("payment", { "count" => 10 })
113 | expect(response["error"]).to be_nil
114 | expect(response["count"]).not_to be_nil
115 | end
116 |
117 | it "Execute Payment"
118 |
119 | it "Create FundingInstrument" do
120 | new_funding_instrument = @vault_api.post("credit-card", {
121 | "type" => "visa",
122 | "number" => "4111111111111111",
123 | "expire_month" => "11", "expire_year" => "2018",
124 | "cvv2" => "874",
125 | "first_name" => "Joe", "last_name" => "Shopper" })
126 | expect(new_funding_instrument["error"]).to be_nil
127 | expect(new_funding_instrument["id"]).not_to be_nil
128 |
129 | funding_instrument = @vault_api.get("credit-card/#{new_funding_instrument["id"]}")
130 | expect(funding_instrument["error"]).to be_nil
131 | expect(funding_instrument["id"]).to eql new_funding_instrument["id"]
132 | end
133 |
134 | end
135 |
136 | describe "Failure request", :integration => true do
137 | it "Invalid Resource ID" do
138 | expect {
139 | response = @api.get("payment/PAY-1234")
140 | }.to raise_error PayPal::SDK::Core::Exceptions::ResourceNotFound
141 | end
142 |
143 | it "Invalid parameters" do
144 | response = @api.post("payment")
145 | expect(response["error"]["name"]).to eql "VALIDATION_ERROR"
146 | end
147 | end
148 |
149 | describe "format response" do
150 | before :each do
151 | @response = instance_double(Net::HTTPResponse)
152 | allow(@response).to receive(:code) { "200" }
153 | allow(@response).to receive(:content_type) { "application/json" }
154 | end
155 |
156 | it "parses empty object JSON correctly" do
157 | allow(@response).to receive(:body) { "{}" }
158 | payload = {
159 | :response => @response
160 | }
161 |
162 | formatted_response = @api.format_response(payload)
163 | expect(formatted_response).to_not be_nil
164 | expect(formatted_response[:data]).to eq({})
165 | end
166 |
167 | it "parses empty string JSON correctly" do
168 | allow(@response).to receive(:body) { '""' }
169 | payload = {
170 | :response => @response
171 | }
172 |
173 | formatted_response = @api.format_response(payload)
174 | expect(formatted_response).to_not be_nil
175 | expect(formatted_response[:data]).to eq("")
176 | end
177 |
178 | it "parses whitespace body correctly" do
179 | allow(@response).to receive(:body) { ' ' }
180 | payload = {
181 | :response => @response
182 | }
183 |
184 | formatted_response = @api.format_response(payload)
185 | expect(formatted_response).to_not be_nil
186 | expect(formatted_response[:data]).to eq({})
187 | end
188 |
189 | it "parses nil body correctly" do
190 | allow(@response).to receive(:body) { nil }
191 | payload = {
192 | :response => @response
193 | }
194 |
195 | formatted_response = @api.format_response(payload)
196 | expect(formatted_response).to_not be_nil
197 | expect(formatted_response[:data]).to eq({})
198 | end
199 |
200 | it "parses with whitespace around JSON correctly" do
201 | allow(@response).to receive(:body) { ' { "test": "value" } ' }
202 | payload = {
203 | :response => @response
204 | }
205 |
206 | formatted_response = @api.format_response(payload)
207 | expect(formatted_response).to_not be_nil
208 | expect(formatted_response[:data]).to eq({ "test" => "value" })
209 | end
210 | end
211 | end
212 |
--------------------------------------------------------------------------------
/spec/core/config_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe PayPal::SDK::Core::Config do
4 |
5 | Config = PayPal::SDK::Core::Config
6 |
7 | it "load configuration file and default environment" do
8 | expect {
9 | Config.load("spec/config/paypal.yml", "test")
10 | expect(Config.default_environment).to eql "test"
11 | }.not_to raise_error
12 | end
13 |
14 | it "Set default environment" do
15 | begin
16 | backup_default_environment = Config.default_environment
17 | Config.default_environment = "new_env"
18 | expect(Config.default_environment).to eql "new_env"
19 | ensure
20 | Config.default_environment = backup_default_environment
21 | end
22 | end
23 |
24 | it "Set configurations" do
25 | begin
26 | backup_configurations = Config.configurations
27 | Config.configurations = { Config.default_environment => { :username => "direct", :password => "direct" } }
28 | expect(Config.config.username).to eql "direct"
29 | expect(Config.config.password).to eql "direct"
30 | expect(Config.config.signature).to be_nil
31 | ensure
32 | Config.configurations = backup_configurations
33 | end
34 | end
35 |
36 | it "Configure with parameters" do
37 | begin
38 | backup_configurations = Config.configurations
39 | Config.configurations = nil
40 | Config.configure( :username => "Testing" )
41 | expect(Config.config.username).to eql "Testing"
42 | expect(Config.config.app_id).to be_nil
43 | ensure
44 | Config.configurations = backup_configurations
45 | end
46 | end
47 |
48 | it "Configure with block" do
49 | begin
50 | backup_configurations = Config.configurations
51 | Config.configurations = nil
52 | Config.configure do |config|
53 | config.username = "Testing"
54 | end
55 | expect(Config.config.username).to eql "Testing"
56 | expect(Config.config.app_id).to be_nil
57 | ensure
58 | Config.configurations = backup_configurations
59 | end
60 | end
61 |
62 | it "Configure with default values" do
63 | begin
64 | backup_configurations = Config.configurations
65 | default_config = Config.config
66 | Config.configure do |config|
67 | config.username = "Testing"
68 | end
69 | expect(Config.config.username).to eql "Testing"
70 | expect(Config.config.app_id).not_to be_nil
71 | expect(Config.config.app_id).to eql default_config.app_id
72 | ensure
73 | Config.configurations = backup_configurations
74 | end
75 | end
76 |
77 | it "validate configuration" do
78 | config = Config.new( :username => "XYZ")
79 | expect {
80 | config.required!(:username)
81 | }.not_to raise_error
82 | expect {
83 | config.required!(:password)
84 | }.to raise_error "Required configuration(password)"
85 | expect {
86 | config.required!(:username, :password)
87 | }.to raise_error "Required configuration(password)"
88 | expect {
89 | config.required!(:password, :signature)
90 | }.to raise_error "Required configuration(password, signature)"
91 | end
92 |
93 | it "return default environment configuration" do
94 | expect(Config.config).to be_a Config
95 | end
96 |
97 | it "return configuration based on environment" do
98 | expect(Config.config(:development)).to be_a Config
99 | end
100 |
101 | it "override default configuration" do
102 | override_configuration = { :username => "test.example.com", :app_id => "test"}
103 | config = Config.config(override_configuration)
104 |
105 | expect(config.username).to eql(override_configuration[:username])
106 | expect(config.app_id).to eql(override_configuration[:app_id])
107 | end
108 |
109 | it "get cached config" do
110 | expect(Config.config(:test)).to eql Config.config(:test)
111 | expect(Config.config(:test)).not_to eql Config.config(:development)
112 | end
113 |
114 | it "should raise error on invalid environment" do
115 | expect {
116 | Config.config(:invalid_env)
117 | }.to raise_error "Configuration[invalid_env] NotFound"
118 | end
119 |
120 | it "set logger" do
121 | require 'logger'
122 | my_logger = Logger.new(STDERR)
123 | Config.logger = my_logger
124 | expect(Config.logger).to eql my_logger
125 | end
126 |
127 | it "Access PayPal::SDK methods" do
128 | expect(PayPal::SDK.configure).to eql PayPal::SDK::Core::Config.config
129 | expect(PayPal::SDK.logger).to eql PayPal::SDK::Core::Config.logger
130 | PayPal::SDK.logger = PayPal::SDK.logger
131 | expect(PayPal::SDK.logger).to eql PayPal::SDK::Core::Config.logger
132 | end
133 |
134 | describe "include Configuration" do
135 | class TestConfig
136 | include PayPal::SDK::Core::Configuration
137 | end
138 |
139 | it "Get default configuration" do
140 | test_object = TestConfig.new
141 | expect(test_object.config).to be_a Config
142 | end
143 |
144 | it "Change environment" do
145 | test_object = TestConfig.new
146 | test_object.set_config("test")
147 | expect(test_object.config).to eql Config.config("test")
148 | expect(test_object.config).not_to eql Config.config("development")
149 | end
150 |
151 | it "Override environment configuration" do
152 | test_object = TestConfig.new
153 | test_object.set_config("test", :username => "test")
154 | expect(test_object.config).not_to eql Config.config("test")
155 | end
156 |
157 | it "Override default/current configuration" do
158 | test_object = TestConfig.new
159 | test_object.set_config( :username => "test")
160 | expect(test_object.config.username).to eql "test"
161 | test_object.set_config( :password => "test")
162 | expect(test_object.config.password).to eql "test"
163 | expect(test_object.config.username).to eql "test"
164 | end
165 |
166 | it "Append ssl_options" do
167 | test_object = TestConfig.new
168 | test_object.set_config( :ssl_options => { :ca_file => "test_path" } )
169 | expect(test_object.config.ssl_options[:ca_file]).to eql "test_path"
170 | test_object.set_config( :ssl_options => { :verify_mode => 1 } )
171 | expect(test_object.config.ssl_options[:verify_mode]).to eql 1
172 | expect(test_object.config.ssl_options[:ca_file]).to eql "test_path"
173 | end
174 |
175 | it "Set configuration without loading configuration File" do
176 | backup_configurations = Config.configurations
177 | begin
178 | Config.configurations = nil
179 | test_object = TestConfig.new
180 | expect {
181 | test_object.config
182 | }.to raise_error
183 | test_object.set_config( :username => "test" )
184 | expect(test_object.config).to be_a Config
185 | ensure
186 | Config.configurations = backup_configurations
187 | end
188 | end
189 |
190 | end
191 |
192 | end
193 |
--------------------------------------------------------------------------------
/spec/core/logging_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 | require 'stringio'
3 |
4 | describe PayPal::SDK::Core::Logging do
5 | Logging = PayPal::SDK::Core::Logging
6 |
7 | class TestLogging
8 | include Logging
9 | end
10 |
11 | before :each do
12 | @logger_file = StringIO.new
13 | Logging.logger = Logger.new(@logger_file)
14 | @test_logging = TestLogging.new
15 | end
16 |
17 | it "get logger object" do
18 | expect(@test_logging.logger).to be_a Logger
19 | end
20 |
21 | it "write message to logger" do
22 | test_message = "Example log message!!!"
23 | @test_logging.logger.info(test_message)
24 | @logger_file.rewind
25 | expect(@logger_file.read).to match test_message
26 | end
27 |
28 | end
29 |
--------------------------------------------------------------------------------
/spec/core/openid_connect_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe PayPal::SDK::OpenIDConnect do
4 | OpenIDConnect = PayPal::SDK::OpenIDConnect
5 |
6 | before :all do
7 | OpenIDConnect.set_config( :client_id => "client_id", :openid_redirect_uri => "http://google.com" )
8 | end
9 |
10 | it "Validate user_agent" do
11 | expect(OpenIDConnect::API.user_agent).to match "PayPalSDK/openid-connect-ruby"
12 | end
13 |
14 | describe "generate_authorize_url" do
15 |
16 | it "generate autorize_url" do
17 | url = OpenIDConnect::Tokeninfo.authorize_url
18 | expect(url).to match "client_id=client_id"
19 | expect(url).to match Regexp.escape("redirect_uri=#{CGI.escape("http://google.com")}")
20 | expect(url).to match "scope=openid"
21 | end
22 |
23 | describe "sandbox" do
24 | before do
25 | PayPal::SDK.configure(:mode => "sandbox")
26 | end
27 |
28 | it "generates a sandbox authorize url" do
29 | url = OpenIDConnect::Tokeninfo.authorize_url
30 | expect(url).to match "sandbox.paypal.com"
31 | end
32 | end
33 | end
34 |
35 | it "Override authorize_url params" do
36 | url = OpenIDConnect.authorize_url(
37 | :client_id => "new_client_id",
38 | :redirect_uri => "http://example.com",
39 | :scope => "openid profile")
40 | expect(url).to match "client_id=new_client_id"
41 | expect(url).to match Regexp.escape("redirect_uri=#{CGI.escape("http://example.com")}")
42 | expect(url).to match Regexp.escape("scope=#{CGI.escape("openid profile")}")
43 | end
44 |
45 | it "Generate logout_url" do
46 | url = OpenIDConnect.logout_url
47 | expect(url).to match "logout=true"
48 | expect(url).to match Regexp.escape("redirect_uri=#{CGI.escape("http://google.com")}")
49 | expect(url).not_to match "id_token"
50 | end
51 |
52 | it "Override logout_url params" do
53 | url = OpenIDConnect.logout_url({
54 | :redirect_uri => "http://example.com",
55 | :id_token => "testing" })
56 | expect(url).to match Regexp.escape("redirect_uri=#{CGI.escape("http://example.com")}")
57 | expect(url).to match "id_token=testing"
58 | end
59 |
60 | describe "Validation" do
61 | it "Create token" do
62 | expect{
63 | tokeninfo = OpenIDConnect::Tokeninfo.create("invalid-autorize-code")
64 | }.to raise_error PayPal::SDK::Core::Exceptions::BadRequest
65 | end
66 |
67 | it "Refresh token" do
68 | expect{
69 | tokeninfo = OpenIDConnect::Tokeninfo.refresh("invalid-refresh-token")
70 | }.to raise_error PayPal::SDK::Core::Exceptions::BadRequest
71 | end
72 |
73 | it "Get userinfo" do
74 | expect{
75 | userinfo = OpenIDConnect::Userinfo.get("invalid-access-token")
76 | }.to raise_error PayPal::SDK::Core::Exceptions::UnauthorizedAccess
77 | end
78 | end
79 |
80 | describe "Tokeninfo" do
81 | before do
82 | @tokeninfo = OpenIDConnect::Tokeninfo.new( :access_token => "test_access_token",
83 | :refresh_token => "test_refresh_token",
84 | :id_token => "test_id_token" )
85 | end
86 |
87 | it "create" do
88 | allow(OpenIDConnect::Tokeninfo.api).to receive_messages( :post => { :access_token => "access_token" } )
89 | tokeninfo = OpenIDConnect::Tokeninfo.create("authorize_code")
90 | expect(tokeninfo).to be_a OpenIDConnect::Tokeninfo
91 | expect(tokeninfo.access_token).to eql "access_token"
92 | end
93 |
94 | it "refresh" do
95 | allow(@tokeninfo.api).to receive_messages( :post => { :access_token => "new_access_token" } )
96 | expect(@tokeninfo.access_token).to eql "test_access_token"
97 | @tokeninfo.refresh
98 | expect(@tokeninfo.access_token).to eql "new_access_token"
99 | end
100 |
101 | it "userinfo" do
102 | allow(@tokeninfo.api).to receive_messages( :post => { :name => "Testing" } )
103 | userinfo = @tokeninfo.userinfo
104 | expect(userinfo).to be_a OpenIDConnect::Userinfo
105 | expect(userinfo.name).to eql "Testing"
106 | end
107 |
108 | describe "logout_url" do
109 | it "Generate logout_url" do
110 | url = @tokeninfo.logout_url
111 | expect(url).to match "id_token=test_id_token"
112 | expect(url).to match "logout=true"
113 | expect(url).to match Regexp.escape("redirect_uri=#{CGI.escape("http://google.com")}")
114 | end
115 |
116 | describe "sandbox" do
117 | before do
118 | PayPal::SDK.configure(:mode => "sandbox")
119 | end
120 |
121 | it "generates a sandbox logout url" do
122 | url = @tokeninfo.logout_url
123 | expect(url).to match "sandbox.paypal.com"
124 | end
125 | end
126 | end
127 | end
128 |
129 | describe "Userinfo" do
130 | it "get" do
131 | allow(OpenIDConnect::Userinfo.api).to receive_messages( :post => { :name => "Testing" } )
132 |
133 | userinfo = OpenIDConnect::Userinfo.get("access_token")
134 | userinfo = OpenIDConnect::Userinfo.new( { :name => "Testing" } )
135 | expect(userinfo).to be_a OpenIDConnect::Userinfo
136 | expect(userinfo.name).to eql "Testing"
137 |
138 | userinfo = OpenIDConnect::Userinfo.get( :access_token => "access_token" )
139 | expect(userinfo).to be_a OpenIDConnect::Userinfo
140 | expect(userinfo.name).to eql "Testing"
141 | end
142 |
143 | it "get", :integration => true do
144 | api = PayPal::SDK::REST::API.new
145 | access_token = api.token_hash()
146 | userinfo = OpenIDConnect::Userinfo.get( access_token )
147 | expect(userinfo).to be_a OpenIDConnect::Userinfo
148 | expect(userinfo.email).to eql "[email protected]"
149 | end
150 | end
151 |
152 |
153 | end
154 |
--------------------------------------------------------------------------------
/spec/invoice_examples_spec.rb:
--------------------------------------------------------------------------------
1 | require "spec_helper"
2 |
3 | describe "Invoice", :integration => true do
4 |
5 | InvoiceAttributes = {
6 | "merchant_info" => {
7 | "email" => "[email protected]"
8 | },
9 | "billing_info" => [ { "email" => "[email protected]" } ],
10 | "items" => [
11 | {
12 | "name" => "Sutures",
13 | "quantity" => 100,
14 | "unit_price" => {
15 | "currency" => "USD",
16 | "value" => 5
17 | }
18 | }
19 | ],
20 | "note" => "Medical Invoice 16 Jul, 2013 PST"
21 | }
22 |
23 | it "create invoice" do
24 | invoice = PayPal::SDK::REST::Invoice.new(InvoiceAttributes)
25 | expect(invoice.create).to be_truthy
26 | end
27 |
28 | it "list invoice" do
29 | history = PayPal::SDK::REST::Invoice.get_all( :total_count_required =>true )
30 | expect(history.total_count).not_to be_nil
31 | end
32 |
33 | it "get invoice" do
34 | invoice = PayPal::SDK::REST::Invoice.find("INV2-6KYE-67GV-8AJR-SAER")
35 | expect(invoice).to be_a PayPal::SDK::REST::Invoice
36 | expect(invoice.id).to eql "INV2-6KYE-67GV-8AJR-SAER"
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/spec/log/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codigofacilito/PayPal-Ruby-SDK/b116bacbf4c43f056193fcd9b62c3131d482065d/spec/log/.gitkeep
--------------------------------------------------------------------------------
/spec/payouts_examples_spec.rb:
--------------------------------------------------------------------------------
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 => '[email protected]'
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
75 |
--------------------------------------------------------------------------------
/spec/rest/data_types_spec.rb:
--------------------------------------------------------------------------------
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
63 |
--------------------------------------------------------------------------------
/spec/rest/error_hash_spec.rb:
--------------------------------------------------------------------------------
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
84 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
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!
38 |
--------------------------------------------------------------------------------
/spec/subscription_examples_spec.rb:
--------------------------------------------------------------------------------
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
228 |
--------------------------------------------------------------------------------
/spec/support/sample_data.rb:
--------------------------------------------------------------------------------
1 | module SampleData
2 | def samples
3 | @@samples ||= YAML.load(File.read(File.expand_path("../../config/sample_data.yml", __FILE__)))
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/spec/web_profile_examples_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe "WebProfiles" do
4 |
5 | WebProfileAttributes = {
6 | "name" => "YeowZa! T-Shirt Shop",
7 | "presentation" => {
8 | "brand_name" => "YeowZa! Paypal",
9 | "logo_image" => "http://www.yeowza.com",
10 | "locale_code" => "US"
11 | },
12 | "input_fields" => {
13 | "allow_note" => true,
14 | "no_shipping" => 0,
15 | "address_override" => 1
16 | },
17 | "flow_config" => {
18 | "landing_page_type" => "billing",
19 | "bank_txn_pending_url" => "http://www.yeowza.com"
20 | }
21 | }
22 |
23 | describe "Examples" do
24 | describe "WebProfile", :integration => true do
25 | it "Create" do
26 |
27 | api = API.new
28 | $webprofile = WebProfile.new(WebProfileAttributes.merge( :token => api.token ))
29 |
30 | # generate a random number and append it to name
31 | suffix = Random.rand(1000000000).to_s
32 | $randname = $webprofile.name + suffix
33 | $webprofile.name = $randname
34 |
35 | # create webhook
36 | $webprofile.create
37 | expect($webprofile).to be_an_instance_of(WebProfile)
38 | expect($webprofile.name.to_s).to eq($randname)
39 | end
40 |
41 | it "List" do
42 | list = WebProfile.get_list
43 | expect(list.size).to be > 1
44 | expect(list.first).to be_an_instance_of(WebProfileList)
45 | end
46 |
47 | it "Retrieve" do
48 | webprofile = WebProfile.find($webprofile.id)
49 | expect(webprofile).to be_an_instance_of(WebProfile)
50 | expect(webprofile.name.to_s).to eq($randname)
51 | end
52 |
53 | it "Update" do
54 | # append "-test" to web profile name
55 | webprofile = WebProfile.find($webprofile.id)
56 | webprofile.name += "-test"
57 | webprofile.update
58 |
59 | # check whether the name was updated
60 | webprofile = WebProfile.find($webprofile.id)
61 | expect(webprofile.name).to eq($randname + "-test")
62 | webprofile.name = $randname
63 | webprofile.update
64 |
65 | # revert updated profile name for next test run
66 | webprofile = WebProfile.find($webprofile.id)
67 | expect(webprofile.name).to eq($randname)
68 | end
69 |
70 | it "Partial update" do
71 | # retrieve web profile to perform partial update on
72 | webprofile = WebProfile.find($webprofile.id)
73 |
74 | # set up partial update
75 | h = {"op" => "replace",
76 | "path" => "/presentation/brand_name",
77 | "value" => "new_brand_name"}
78 |
79 | # do partial update by sending a patch request
80 | expect(webprofile.partial_update( [h] )).to be_truthy
81 | webprofile = WebProfile.find($webprofile.id)
82 | expect(webprofile.presentation.brand_name).to eq("new_brand_name")
83 |
84 | # restore original value for the next test run
85 | h = {"op" => "replace",
86 | "path" => "/presentation/brand_name",
87 | "value" => "brand_name"}
88 | expect(webprofile.partial_update( [h] )).to be_truthy
89 | expect(WebProfile.find($webprofile.id).presentation.brand_name).to eq("brand_name")
90 | end
91 |
92 | it "Delete" do
93 | # delete newly created web profile from above create test
94 | expect($webprofile.delete).to be_truthy
95 |
96 | # make sure it is not retrieved from the system
97 | begin
98 | webprofile = WebProfile.find($webprofile.id)
99 | expect(webprofile).to be_nil
100 | fail "WebProfile with ID=#{$webprofile.id} has not been deleted"
101 | rescue ResourceNotFound
102 | end
103 | end
104 | end
105 | end
106 | end
107 |
--------------------------------------------------------------------------------
/spec/webhooks_examples_spec.rb:
--------------------------------------------------------------------------------
1 | require "spec_helper"
2 | require "securerandom"
3 |
4 | describe "Webhooks" do
5 |
6 | webhookAttributes = {
7 | :url => "https://www.yeowza.com/paypal_webhook_"+SecureRandom.hex(8),
8 | :event_types => [
9 | {
10 | :name => "PAYMENT.AUTHORIZATION.CREATED"
11 | },
12 | {
13 | :name => "PAYMENT.AUTHORIZATION.VOIDED"
14 | }
15 | ]
16 | }
17 |
18 | describe "PayPal::SDK::Core::API::DataTypes::WebhookEvent" do
19 | describe "get event by id via .find" do
20 | it "exists" do
21 | expect(WebhookEvent).to respond_to(:find)
22 | end
23 | end
24 | end
25 |
26 | describe "Notifications", :integration => true do
27 | it "create webhook" do
28 | $webhook = PayPal::SDK::REST::Webhook.new(webhookAttributes)
29 | expect($webhook.create).to be_truthy
30 | end
31 |
32 | it "get webhook" do
33 | $result = PayPal::SDK::REST::Webhook.get($webhook.id)
34 | expect($result).to be_a PayPal::SDK::REST::Webhook
35 | expect($result.id).to eql $webhook.id
36 | end
37 |
38 | it "get all webhooks" do
39 | $webhooks_list = PayPal::SDK::REST::Webhook.all()
40 | expect($webhooks_list.webhooks.length).not_to be_nil
41 | end
42 |
43 | it "get subscribed webhook event types" do
44 | $webhook_event_types = PayPal::SDK::REST::Webhook.get_event_types($webhook.id)
45 | expect($webhook_event_types.event_types.length).to eql $webhook.event_types.length
46 | end
47 |
48 | it "delete webhook" do
49 | expect($webhook.delete).to be_truthy
50 | end
51 | end
52 |
53 | describe "Validation", :integration => true do
54 |
55 | transmission_id = "dfb3be50-fd74-11e4-8bf3-77339302725b"
56 | timestamp = "2015-05-18T15:45:13Z"
57 | webhook_id = "4JH86294D6297924G"
58 | actual_signature = "thy4/U002quzxFavHPwbfJGcc46E8rc5jzgyeafWm5mICTBdY/8rl7WJpn8JA0GKA+oDTPsSruqusw+XXg5RLAP7ip53Euh9Xu3UbUhQFX7UgwzE2FeYoY6lyRMiiiQLzy9BvHfIzNIVhPad4KnC339dr6y2l+mN8ALgI4GCdIh3/SoJO5wE64Bh/ueWtt8EVuvsvXfda2Le5a2TrOI9vLEzsm9GS79hAR/5oLexNz8UiZr045Mr5ObroH4w4oNfmkTaDk9Rj0G19uvISs5QzgmBpauKr7Nw++JI0pr/v5mFctQkoWJSGfBGzPRXawrvIIVHQ9Wer48GR2g9ZiApWg=="
59 | event_body = '{"id":"WH-0G2756385H040842W-5Y612302CV158622M","create_time":"2015-05-18T15:45:13Z","resource_type":"sale","event_type":"PAYMENT.SALE.COMPLETED","summary":"Payment completed for $ 20.0 USD","resource":{"id":"4EU7004268015634R","create_time":"2015-05-18T15:44:02Z","update_time":"2015-05-18T15:44:21Z","amount":{"total":"20.00","currency":"USD"},"payment_mode":"INSTANT_TRANSFER","state":"completed","protection_eligibility":"ELIGIBLE","protection_eligibility_type":"ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE","parent_payment":"PAY-86C81811X5228590KKVNARQQ","transaction_fee":{"value":"0.88","currency":"USD"},"links":[{"href":"https://api.sandbox.paypal.com/v1/payments/sale/4EU7004268015634R","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/payments/sale/4EU7004268015634R/refund","rel":"refund","method":"POST"},{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-86C81811X5228590KKVNARQQ","rel":"parent_payment","method":"GET"}]},"links":[{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-0G2756385H040842W-5Y612302CV158622M","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-0G2756385H040842W-5Y612302CV158622M/resend","rel":"resend","method":"POST"}]}'
60 | cert_url = "https://api.sandbox.paypal.com/v1/notifications/certs/CERT-360caa42-fca2a594-a5cafa77"
61 |
62 | it "verify common name" do
63 | cert = PayPal::SDK::REST::WebhookEvent.get_cert(cert_url)
64 | valid = PayPal::SDK::REST::WebhookEvent.verify_common_name(cert)
65 | expect(valid).to be_truthy
66 | end
67 |
68 | it "verify get expected signature" do
69 | expected_sig = PayPal::SDK::REST::WebhookEvent.get_expected_sig(transmission_id, timestamp, webhook_id, event_body)
70 | expect(expected_sig).eql?("dfb3be50-fd74-11e4-8bf3-77339302725b|2015-05-18T15:45:13Z|4JH86294D6297924G|2771810304")
71 | end
72 |
73 | it "verify expiry" do
74 | cert = PayPal::SDK::REST::WebhookEvent.get_cert(cert_url)
75 | valid = PayPal::SDK::REST::WebhookEvent.verify_expiration(cert)
76 | expect(valid).to be_truthy
77 | end
78 |
79 | it "verify cert chain" do
80 | cert = PayPal::SDK::REST::WebhookEvent.get_cert(cert_url)
81 | cert_store = PayPal::SDK::REST::WebhookEvent.get_cert_chain
82 | valid = PayPal::SDK::REST::WebhookEvent.verify_cert_chain(cert_store, cert)
83 | expect(valid).to be_truthy
84 | end
85 |
86 | it "verify" do
87 | valid = PayPal::SDK::REST::WebhookEvent.verify(transmission_id, timestamp, webhook_id, event_body, cert_url, actual_signature)
88 | expect(valid).to be_truthy
89 | end
90 | end
91 |
92 |
93 | end
94 |
--------------------------------------------------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment