shippo 1.0.4 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.atom-build.json +22 -0
  3. data/.codeclimate.yml +30 -0
  4. data/.gitignore +22 -0
  5. data/.rspec +2 -0
  6. data/.rubocop.yml +1156 -0
  7. data/.travis.yml +16 -0
  8. data/CHANGELOG.md +50 -0
  9. data/Gemfile +5 -0
  10. data/Guardfile +39 -0
  11. data/README.md +288 -0
  12. data/Rakefile +24 -0
  13. data/bin/example +114 -0
  14. data/lib/shippo.rb +23 -97
  15. data/lib/shippo/api.rb +52 -0
  16. data/lib/shippo/api/api_object.rb +133 -0
  17. data/lib/shippo/api/category.rb +49 -0
  18. data/lib/shippo/api/category/base.rb +144 -0
  19. data/lib/shippo/api/category/purpose.rb +13 -0
  20. data/lib/shippo/api/category/source.rb +16 -0
  21. data/lib/shippo/api/category/state.rb +13 -0
  22. data/lib/shippo/api/category/status.rb +17 -0
  23. data/lib/shippo/api/extend/operation.rb +21 -0
  24. data/lib/shippo/api/extend/transformers.rb +12 -0
  25. data/lib/shippo/api/extend/url.rb +26 -0
  26. data/lib/shippo/api/operations.rb +8 -0
  27. data/lib/shippo/api/operations/create.rb +33 -0
  28. data/lib/shippo/api/operations/list.rb +22 -0
  29. data/lib/shippo/api/operations/rates.rb +16 -0
  30. data/lib/shippo/api/operations/update.rb +12 -0
  31. data/lib/shippo/api/operations/validate.rb +12 -0
  32. data/lib/shippo/api/request.rb +159 -0
  33. data/lib/shippo/api/resource.rb +104 -0
  34. data/lib/shippo/api/transformers/list.rb +73 -0
  35. data/lib/shippo/api/version.rb +5 -0
  36. data/lib/shippo/exceptions.rb +7 -0
  37. data/lib/shippo/exceptions/api_error.rb +20 -0
  38. data/lib/shippo/exceptions/error.rb +22 -0
  39. data/lib/shippo/model/address.rb +5 -0
  40. data/lib/shippo/model/carrieraccount.rb +5 -0
  41. data/lib/shippo/model/customs_declaration.rb +6 -0
  42. data/lib/shippo/model/customs_item.rb +5 -0
  43. data/lib/shippo/model/manifest.rb +5 -0
  44. data/lib/shippo/model/parcel.rb +5 -0
  45. data/lib/shippo/model/rate.rb +5 -0
  46. data/lib/shippo/model/refund.rb +5 -0
  47. data/lib/shippo/model/shipment.rb +5 -0
  48. data/lib/shippo/model/transaction.rb +5 -0
  49. data/lib/shippo/tasks/shippo.rb +22 -0
  50. data/shippo.gemspec +34 -0
  51. metadata +226 -40
  52. data/example.rb +0 -71
  53. data/lib/shippo/address.rb +0 -10
  54. data/lib/shippo/api_object.rb +0 -89
  55. data/lib/shippo/carrieraccount.rb +0 -8
  56. data/lib/shippo/container_object.rb +0 -28
  57. data/lib/shippo/create.rb +0 -18
  58. data/lib/shippo/customs_declaration.rb +0 -7
  59. data/lib/shippo/customs_item.rb +0 -7
  60. data/lib/shippo/error.rb +0 -18
  61. data/lib/shippo/list.rb +0 -23
  62. data/lib/shippo/manifest.rb +0 -6
  63. data/lib/shippo/parcel.rb +0 -6
  64. data/lib/shippo/rate.rb +0 -5
  65. data/lib/shippo/refund.rb +0 -6
  66. data/lib/shippo/resource.rb +0 -29
  67. data/lib/shippo/shipment.rb +0 -14
  68. data/lib/shippo/transaction.rb +0 -6
  69. data/lib/shippo/update.rb +0 -15
  70. data/test/test.rb +0 -26
@@ -0,0 +1,16 @@
1
+ language: ruby
2
+ env:
3
+ - CODECLIMATE_REPO_TOKEN=ab88ea1c6e1d5356540704cb4dd58eeaf256f4ac7b454852f256091bf205d9e2
4
+ rvm:
5
+ - 2.2.3
6
+ - 2.3.0
7
+ script: "gem install bundler --no-ri --no-rdoc; bundle exec rspec"
8
+ notifications:
9
+ slack:
10
+ rooms:
11
+ - shippo:JOD4pUgjGlhSJ1s8mNKUTxKB#devcistatus
12
+ email:
13
+ recipients:
14
+ - kigster@gmail.com
15
+ on_success: change
16
+ on_failure: always
@@ -0,0 +1,50 @@
1
+ #### 2.0.0-beta July 7th, 2016
2
+
3
+ - Added a concept of List transformer in order to properly coerce
4
+ received hashes into proper model objects
5
+ - updated to_s and inspect on models and ApiObject
6
+ - added a large number of new tests
7
+
8
+ #### 2.0.0-alpha June, 2016
9
+
10
+ - Library refactoring and reorganization
11
+ - Consolidating operations under the Shippo::API::Operations namespace
12
+ - Instead of doing `include <operation module>` using new `operations :list, :create, ... ` class methods
13
+ - Instead of setting a global class instance variable `@custom_url`, use new class method `url "/custom/uri"` to set the custom URI component
14
+ - Added `actievesupport` gem dependency for `#pluralize` and `#constantize` instead of rolling our own
15
+ - Token should now be set via `Shippo::API.token =`, although `Shippo.api_token = ` is also supported
16
+ - Renamed `Api` to `API` in line with Ruby conventions
17
+ - Consolidated `Resource` and `ContainerObject` into one class
18
+ - Extracted a new class `Shippo::API::Request`
19
+ - Extracted `#validate` and `#rates` into operations
20
+ - Created 2nd-level namspaces to separate models from operations from utility classes such as `Request` and `Resource`
21
+ - Consolidated models under Shippo namespace
22
+ - Converted existing unit test into an RSpec
23
+ - Improved overall exception handling
24
+ - split up and organized Exceptions
25
+ - mapping TCP-specific errors to `ConnectionError`
26
+ - mapping JSON parser and server errors
27
+ - Improved the Example script
28
+ - Added exception handling clause similar to how the API should be used in real life
29
+ - Reading API token from the environment
30
+ - Moved example script into `bin/example`
31
+ - Miscellaneous:
32
+ - Reformatting and updated README
33
+ - Added a rake task for documentation generation `rake shippo:doc`
34
+ - Added Yardoc parameters and class descriptions to key entities
35
+ - Updated syntax for Ruby 2+
36
+ - Renamed the gem from `shippo` to `shippo-api`.
37
+
38
+ #### 1.0.4 June 19th, 2015
39
+
40
+ - added support for Carrier Accounts
41
+
42
+ #### 1.0.3 June 18th, 2015
43
+
44
+ - changed auth to use ShippoToken (vs username and password)
45
+
46
+ #### 1.0.2 Aug 25th, 2014
47
+
48
+ - added optional parameter <currency> for shipment.rates()
49
+ - added validate method to address
50
+ - added manifest, customs_item, customs_declaration, and refund classes
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+ gem "codeclimate-test-reporter", group: :test, require: nil
3
+
4
+ # Specify your gem's dependencies in counter-cache.gemspec
5
+ gemspec
@@ -0,0 +1,39 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ ## Uncomment and set this to only include directories you want to watch
5
+ directories %w(lib spec)
6
+
7
+ ## Note: if you are using the `directories` clause above and you are not
8
+ ## watching the project directory ('.'), then you will want to move
9
+ ## the Guardfile to a watched dir and symlink it back, e.g.
10
+ #
11
+ # $ mkdir config
12
+ # $ mv Guardfile config/
13
+ # $ ln -s config/Guardfile .
14
+ #
15
+ # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
16
+
17
+ # Note: The cmd option is now required due to the increasing number of ways
18
+ # rspec may be run, below are examples of the most common uses.
19
+ # * bundler: 'bundle exec rspec'
20
+ # * bundler binstubs: 'bin/rspec'
21
+ # * spring: 'bin/rspec' (This will use spring if running and you have
22
+ # installed the spring binstubs per the docs)
23
+ # * zeus: 'zeus rspec' (requires the server to be started separately)
24
+ # * 'just' rspec: 'rspec'
25
+
26
+ guard :rspec, cmd: 'bundle exec rspec' do
27
+ require 'guard/rspec/dsl'
28
+ dsl = Guard::RSpec::Dsl.new(self)
29
+
30
+ # RSpec files
31
+ rspec = dsl.rspec
32
+ watch(rspec.spec_helper) { rspec.spec_dir }
33
+ watch(rspec.spec_support) { rspec.spec_dir }
34
+ watch(rspec.spec_files)
35
+
36
+ # Ruby files
37
+ ruby = dsl.ruby
38
+ dsl.watch_spec_files_for(ruby.lib_files)
39
+ end
@@ -0,0 +1,288 @@
1
+
2
+ # Shippo API – Ruby Wrapper for Shippo API
3
+
4
+ [![Build Status](https://travis-ci.org/kigster/shippo-ruby-client.svg?branch=master)](https://travis-ci.org/kigster/shippo-ruby-client)
5
+ [![Code Climate](https://codeclimate.com/github/kigster/shippo-ruby-client/badges/gpa.svg)](https://codeclimate.com/github/kigster/shippo-ruby-client)
6
+ [![Test Coverage](https://codeclimate.com/github/kigster/shippo-ruby-client/badges/coverage.svg?refresh=1)](https://codeclimate.com/github/kigster/shippo-ruby-client/coverage)
7
+ [![Issue Count](https://codeclimate.com/github/kigster/shippo-ruby-client/badges/issue_count.svg?refresh=1)](https://codeclimate.com/github/kigster/shippo-ruby-client)
8
+
9
+ Shippo is a shipping API that connects you with multiple shipping carriers (such as USPS, UPS, DHL, Canada Post, Australia Post, UberRUSH and many [others](https://goshippo.com/shipping-carriers/)) through one interface.
10
+
11
+ Our API provides in depth support of cross-carrier functionality. Here are just some of the features we support for USPS, FedEx, UPS and many others via the API.
12
+
13
+ ## Core Functionality
14
+
15
+ For most major carriers (USPS, UPS, FedEx and most others) our API supports:
16
+
17
+ * Querying for shipping rates
18
+ * Creating and printing labels
19
+ * Tracking shipments
20
+
21
+ #### Additional Features for USPS
22
+
23
+
24
+ For USPS, the API additionally supports:
25
+
26
+ * US Address validation
27
+ * Scan forms
28
+ * Signature
29
+ * Certified mail
30
+ * Delivery confirmation
31
+ * etc.
32
+
33
+ #### FedEx
34
+
35
+ For FedEx, the API additionally supports:
36
+
37
+ * Signature and adult signature confirmation
38
+ * FedEx Smartpost
39
+
40
+ ### UPS
41
+
42
+ For UPS, the API additionally supports:
43
+
44
+ * Signature and adult signature confirmation
45
+ * UPS Mail Innovations
46
+ * UPS SurePost
47
+
48
+ The complete list of carrier supported features is [here](https://goshippo.com/shipping-api/carriers).
49
+
50
+ ### About Shippo
51
+
52
+ Connect with multiple different carriers, get discounted shipping labels, track parcels, and much more with just one integration. You can use your own carrier accounts or take advantage of our deeply discounted rates. Using Shippo makes it easy to deal with multiple carrier integrations, rate shopping, tracking and other parts of the shipping workflow. We provide the API and dashboard for all your shipping needs.
53
+
54
+ The API is free to use. You only pay when you print a live label from a carrier. Use test labels during development to avoid all fees.
55
+
56
+ You do need a Shippo account to use our API. Don't have an account? Sign up at [https://goshippo.com/](https://goshippo.com/).
57
+
58
+ ## Installation
59
+
60
+ This library is distributed as a ruby gem, therefore youcan install it via adding the following line to your `Gemfile`:
61
+
62
+ ```
63
+ gem 'shippo'
64
+ ```
65
+
66
+ If you prefer to use the latest version of the library, just point your Gemfile to our github repo:
67
+
68
+ ```
69
+ gem 'shippo', git: 'https://github.com/goshippo/shippo-ruby-client'
70
+ ```
71
+
72
+ Or you can install the gem using the `gem` command:
73
+
74
+ ```bash
75
+ gem install shippo
76
+ ```
77
+
78
+ ## Usage
79
+
80
+
81
+ ```ruby
82
+ require 'shippo/api'
83
+
84
+ # Setup your API token
85
+ Shippo.api_key = 'aff988f77afa0fdfdfadf' # not an actual valid token
86
+
87
+ # Setup query parameter hash
88
+ params = { object_purpose: 'PURCHASE',
89
+ async: false,
90
+ address_from: {
91
+ object_purpose: 'PURCHASE',
92
+ name: 'Mr Hippo',
93
+ company: 'Shippo',
94
+ street1: '215 Clayton St.',
95
+ street2: '',
96
+ city: 'San Francisco',
97
+ state: 'CA',
98
+ zip: '94117',
99
+ country: 'US',
100
+ phone: '+1 555 341 9393',
101
+ email: 'support@goshippo.com' },
102
+ address_to: {
103
+ object_purpose: 'PURCHASE',
104
+ name: 'Mrs Hippo"',
105
+ company: 'San Diego Zoo',
106
+ street1: '2920 Zoo Drive',
107
+ city: 'San Diego',
108
+ state: 'CA',
109
+ zip: '92101',
110
+ country: 'US',
111
+ phone: '+1 555 341 9393',
112
+ email: 'hippo@goshippo.com' },
113
+ parcel: {
114
+ length: 5,
115
+ width: 2,
116
+ height: 5,
117
+ distance_unit: :in,
118
+ weight: 2,
119
+ mass_unit: :lb }
120
+ }
121
+
122
+ # Make our API call
123
+ @shipment = Shippo::Shipment.create(params)
124
+ @shipment.success?
125
+ # => true
126
+ @shipment.object.status
127
+ # => 'SUCCESS'
128
+ @shipment.status # forwarded to #object
129
+ # => 'SUCCESS'
130
+ @shipment.state
131
+ # => 'VALID'
132
+ ```
133
+
134
+ Let's take a quick look at what the `Address` object looks like:
135
+
136
+ ```ruby
137
+ require 'awesome_print'
138
+ ap @shipment
139
+ # {
140
+ # "carrier_accounts" => [],
141
+ # "address_from" => "a704eada7494bb1be6184ef64b1646db",
142
+ # "address_to" => "92b43fbfa3641644beb32996042eb57a",
143
+ # "parcel" => "92df4baac73ea6131940c0d315d70a7d",
144
+ # "submission_type" => "DROPOFF",
145
+ # "submission_date" => "2016-07-06T20:33:02.211Z",
146
+ # "address_return" => "a1f64ba14b7e41b86a0446de4ebbd769",
147
+ # "return_of" => nil,
148
+ # "customs_declaration" => nil,
149
+ # "insurance_amount" => "0",
150
+ # "insurance_currency" => nil,
151
+ # "extra" => {},
152
+ # "reference_1" => "",
153
+ # "reference_2" => "",
154
+ # "rates_url" => "https://api.goshippo.com/v1/shipments/a336daf87a8e442992a68daa6622758f/rates/",
155
+ # "messages" => [ ] # ommitted for brevity,
156
+ # "rates_list" => [ ] # ommitted for brevity.
157
+ # }
158
+ ```
159
+
160
+ #### List Handling
161
+
162
+ In the case when the API returns a hash with one of the hash values being an array of entities, and if the corresponding key can be mapped into one of the existing API models, then each of the members of the array is coerced from a hash into an object of the model's type.
163
+
164
+ In the example below we are showing the result of such transformation where the `rates_list` contains a list of fully constructed objects of type `Shippo::Rate` after being coerced from a hash.
165
+
166
+ ```ruby
167
+ ap @shipment.rates_list.first
168
+ # =>
169
+ # {
170
+ # "shipment" => "20f25e44b16b4051b6dd910cb66fd27b",
171
+ # "available_shippo" => true,
172
+ # "attributes" => [],
173
+ # "amount" => "8.51",
174
+ # "currency" => "USD",
175
+ # "amount_local" => "8.51",
176
+ # "currency_local" => "USD",
177
+ # "provider" => "FedEx",
178
+ # "provider_image_75" => "https://shippo-static.s3.amazonaws.com/providers/75/FedEx.png",
179
+ # "provider_image_200" => "https://shippo-static.s3.amazonaws.com/providers/200/FedEx.png",
180
+ # "servicelevel_name" => "Ground",
181
+ # "servicelevel_token" => "fedex_ground",
182
+ # "servicelevel_terms" => "",
183
+ # "days" => 2,
184
+ # "arrives_by" => nil,
185
+ # "duration_terms" => "",
186
+ # "trackable" => true,
187
+ # "insurance" => false,
188
+ # "insurance_amount_local" => "0.00",
189
+ # "insurance_currency_local" => nil,
190
+ # "insurance_amount" => "0.00",
191
+ # "insurance_currency" => nil,
192
+ # "delivery_attempts" => nil,
193
+ # "outbound_endpoint" => "door",
194
+ # "inbound_endpoint" => "door",
195
+ # "messages" => [],
196
+ # "carrier_account" => "4b1940bc69524163b669asd361842db",
197
+ # "test" => true
198
+ # }
199
+ @shipment.rates.first.owner
200
+ # ⤷ unittest@gmail.com
201
+ @shipment.rates.first.class
202
+ # ⤷ Shippo::Rate
203
+ ```
204
+
205
+ #### Resource ID and Other Object Fields
206
+
207
+ Shippo API returns several generalized fields for each valid resource, that being with 'object_' – for example, `object_id`, `object_owner`, etc. In this library we move these fields out of the main model, and into an instance of `Shippo::API::ApiObject`. However the fields can still be accessed on the main model via generated accessors.
208
+
209
+ Unfortunately Shippo API also returns `object_id`, which in Ruby has a special meaning: it's the pointer address of any object. Overwriting this field causes all sorts of issues.
210
+
211
+ For this reason we are mapping `object_id` to `resource_id`, as soon as the hash is passed in to initialize `ApiObject`.
212
+
213
+ The following console output demonstrates many ways of accessing `object_` fields:
214
+
215
+ ```ruby
216
+ @shipment.object_id # this is the Ruby object pointer
217
+ # ⤷ 70206221831520
218
+ @shipment.resource_id # this is the API id (note: deprecated accessor)
219
+ # ⤷ 20f25e44b16b4051b6dd910cb66fd27b
220
+ @shipment.object.id # which is actually just this
221
+ # ⤷ 20f25e44b16b4051b6dd910cb66fd27b
222
+ @shipment.id # but it can also be accessed this way too
223
+ # ⤷ 20f25e44b16b4051b6dd910cb66fd27b
224
+ ```
225
+
226
+ And with the rest of the `object_` fields:
227
+
228
+ ``` ruby
229
+ @shipment.object.owner # this is whether 'object_owner' is stored
230
+ # ⤷ valued_customer@gmail.com
231
+ @shipment.object_owner # deprecated accessor method
232
+ # ⤷ valued_customer@gmail.com
233
+ @shipment.owner # forwarded alias to #object.owner
234
+ # ⤷ valued_customer@gmail.com
235
+ ```
236
+
237
+ Here is the fully construted `ApiObject` instance, attached to our `@shipment`:
238
+
239
+ ```ruby
240
+ ap @shipment.object
241
+ # {
242
+ # :created => 2016-07-06 20:44:47 UTC,
243
+ # :updated => 2016-07-06 20:44:47 UTC,
244
+ # :owner => "valued_customer@gmail.com",
245
+ # :state => #<Shippo::API::Category::State:0x007fd88be8aa38 @name=:state, @value=:valid>,
246
+ # :status => #<Shippo::API::Category::Status:0x007fd88be82e28 @name=:status, @value=:success>,
247
+ # :purpose => #<Shippo::API::Category::Purpose:0x007fd88be985e8 @name=:purpose, @value=:purchase>,
248
+ # :id => "20f25e44b16b4051b6dd910cb66fd27b"
249
+ # }
250
+ ```
251
+
252
+ #### Validation
253
+
254
+ In general this gem does not currently perform validation, *except* in the cases when enumerations are used. The gem automatically converts a response containing keys matching one of the known categories (such as `Shippo::API::Category::Status` and it's value into one of the constants, such as `SUCCESS`.
255
+
256
+ ### Using Provided Example File
257
+
258
+ Look at `bin/example` for more code sample.
259
+
260
+ You can actually run this file, but first you should set your API token in the environment:
261
+
262
+ ```bash
263
+ export SHIPPO_TOKEN="<your token here>"
264
+ bin/example
265
+ ```
266
+
267
+ ## Gem Versioning Notes
268
+
269
+ Version 2 and up of this library works with Ruby 2.2 and later, and is not backwards compatible. __Version 1.0.4__ of this library is the last version of the gem `shippo`, and the last version supporting ruby 1.8 and 1.9.
270
+
271
+ The intent, however, is to completely deprecate `shippo` gem in the near future.
272
+
273
+ ### If you are still using Ruby 1.8 or 1.9
274
+
275
+ If you are still using an older version of Ruby, please make sure to use the last 1.X version of this library, which is currently the [tag v1.0.4](https://github.com/goshippo/shippo-ruby-client/tree/v1.0.4).
276
+
277
+ ## Documentation
278
+
279
+ Please see [https://goshippo.com/shipping-api/](https://goshippo.com/shipping-api/) for up-to-date documentation.
280
+
281
+ For Ruby class documentation, please run the following rake task:
282
+
283
+ ```bash
284
+ bundle install
285
+ bundle exec rake doc:read # preview documentation in the browser
286
+ ```
287
+
288
+ This task will generate documentation using [Yard](https://yardoc.org) and then open the browser with the generated index.html.
@@ -0,0 +1,24 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'rake/clean'
4
+ require_relative 'lib/shippo/tasks/shippo'
5
+
6
+ CLEAN.include %w(pkg coverage *.gem)
7
+
8
+ begin
9
+ require 'rspec/core/rake_task'
10
+ RSpec::Core::RakeTask.new(:spec)
11
+ rescue LoadError
12
+ STDERR.puts %Q(Unable to find rspec library.\nPlease run "bundle install" and then "bundle exec rake <task>")
13
+ exit 1
14
+ end
15
+
16
+ begin
17
+ require 'bundler'
18
+ require 'bundler/gem_tasks'
19
+ rescue LoadError
20
+ STDERR.puts %Q(Unable to find Bundler.\nPlease run "gem install bundler" first.)
21
+ exit 2
22
+ end
23
+
24
+ task :default => [:spec]
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # © 2016 Shippo, Inc.
4
+ #
5
+ # License: MIT
6
+ #
7
+ lib = File.expand_path('../../lib', __FILE__)
8
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
9
+
10
+ require 'bundler/setup'
11
+ require 'shippo/api'
12
+ require 'shippo/api/category'
13
+ require 'shippo/exceptions/api_error'
14
+ require 'colored2'
15
+ require 'awesome_print'
16
+ require 'json'
17
+
18
+ # This example demonstrates how to purchase a label for a domestic US shipment.
19
+ # Please set SHIPPO_TOKEN in the environment
20
+ Shippo::API.token = ENV['SHIPPO_TOKEN']
21
+ Shippo::API.debug = false # set to true for debugging output
22
+
23
+ # Create address_from object
24
+ address_from = {
25
+ :object_purpose => 'PURCHASE',
26
+ :name => 'Mr Hippo',
27
+ :company => 'Shippo',
28
+ :street1 => '215 Clayton St.',
29
+ :street2 => '',
30
+ :city => 'San Francisco',
31
+ :state => 'CA',
32
+ :zip => '94117',
33
+ :country => 'US',
34
+ :phone => '+1 555 341 9393',
35
+ :email => 'support@goshippo.com' }
36
+
37
+ # Create address_to object
38
+ address_to = {
39
+ :object_purpose => 'PURCHASE',
40
+ :name => 'Mrs Hippo"',
41
+ :company => 'San Diego Zoo',
42
+ :street1 => '2920 Zoo Drive',
43
+ :city => 'San Diego',
44
+ :state => 'CA',
45
+ :zip => '92101',
46
+ :country => 'US',
47
+ :phone => '+1 555 341 9393',
48
+ :email => 'hippo@goshippo.com' }
49
+
50
+ # Create parcel object
51
+ parcel = {
52
+ :length => 5,
53
+ :width => 2,
54
+ :height => 5,
55
+ :distance_unit => :in,
56
+ :weight => 2,
57
+ :mass_unit => :lb }
58
+
59
+ hash = { :object_purpose => 'PURCHASE',
60
+ :address_from => address_from,
61
+ :address_to => address_to,
62
+ :parcel => parcel,
63
+ :async => false }
64
+ puts 'Making first API call for shipment rates...'.blue.bold
65
+
66
+ begin
67
+ shipment = Shippo::Shipment.create(hash)
68
+ raise Shippo::Exceptions::UnsuccessfulResponseError.new(shipment.object.inspect) unless shipment.success?
69
+ File.open('example-shipment.json', 'w') do |file|
70
+ file.puts JSON.dump(shipment.to_hash)
71
+ end
72
+ rescue Shippo::Exceptions::APIServerError => e
73
+ puts "Server returned an error:\n#{e.inspect}".bold.red
74
+ exit 3
75
+ rescue Shippo::Exceptions::ConnectionError
76
+ puts 'Error connecting to remote host. Is your Internet working?'.bold.red
77
+ exit 2
78
+ rescue Shippo::Exceptions::AuthenticationError
79
+ if Shippo::API.token
80
+ puts "Token '#{Shippo::API.token}' does not appear to be valid.".bold.red
81
+ puts 'Access denied.'
82
+ else
83
+ puts 'Please set authentication token in the environment:'.bold.red
84
+ puts 'export SHIPPO_TOKEN="<your token here>"'
85
+ puts 'and re-run the example.'
86
+ end
87
+ exit 1
88
+ end
89
+
90
+ # Get the desired rate according to your business logic
91
+ # We select the first rate in this example
92
+ rate = shipment.rates_list.first
93
+ puts 'RATES:'.bold.green.underlined
94
+ ap(rate)
95
+
96
+ puts "Purchasing a #{rate} label!"
97
+
98
+ # Purchase the desired rate (create a Transaction object)
99
+ transaction = Shippo::Transaction.create(rate: rate.id, async: false)
100
+
101
+ if transaction.success?
102
+ # noinspection RubyResolve
103
+ puts 'Transaction OK'.bold.green.underlined + "\n"
104
+
105
+ puts "Label URL : #{
106
+ # noinspection RubyResolve
107
+ transaction.label_url.bold.yellow }"
108
+ puts "Tracking NO : #{
109
+ # noinspection RubyResolve
110
+ transaction.tracking_number.to_s.bold.yellow}"
111
+ else
112
+ puts 'Transaction ERROR'.bold.red
113
+ puts transaction.messages.bold.red
114
+ end