shipengine_sdk 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +8 -0
- data/README.md +96 -0
- data/lib/faraday/raise_http_exception.rb +77 -0
- data/lib/shipengine/configuration.rb +43 -0
- data/lib/shipengine/constants/base.rb +22 -0
- data/lib/shipengine/constants/countries.rb +16 -0
- data/lib/shipengine/constants.rb +4 -0
- data/lib/shipengine/domain/addresses/address_validation.rb +118 -0
- data/lib/shipengine/domain/addresses.rb +76 -0
- data/lib/shipengine/domain/carriers/list_carriers.rb +140 -0
- data/lib/shipengine/domain/carriers.rb +93 -0
- data/lib/shipengine/domain/labels/create_from_rate.rb +163 -0
- data/lib/shipengine/domain/labels/create_from_shipment_details.rb +163 -0
- data/lib/shipengine/domain/labels/void_label.rb +18 -0
- data/lib/shipengine/domain/labels.rb +297 -0
- data/lib/shipengine/domain/rates/get_with_shipment_details.rb +347 -0
- data/lib/shipengine/domain/rates.rb +379 -0
- data/lib/shipengine/domain/tracking/track_using_carrier_code_and_tracking_number.rb +45 -0
- data/lib/shipengine/domain/tracking/track_using_label_id.rb +45 -0
- data/lib/shipengine/domain/tracking.rb +103 -0
- data/lib/shipengine/domain.rb +7 -0
- data/lib/shipengine/exceptions/error_code.rb +254 -0
- data/lib/shipengine/exceptions/error_type.rb +49 -0
- data/lib/shipengine/exceptions.rb +132 -0
- data/lib/shipengine/internal_client.rb +91 -0
- data/lib/shipengine/utils/base58.rb +109 -0
- data/lib/shipengine/utils/pretty_print.rb +29 -0
- data/lib/shipengine/utils/request_id.rb +16 -0
- data/lib/shipengine/utils/user_agent.rb +24 -0
- data/lib/shipengine/utils/validate.rb +106 -0
- data/lib/shipengine/version.rb +5 -0
- data/lib/shipengine.rb +164 -0
- metadata +117 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d370ae8b38bb9f56249210fe89f0cbddc5258aee3ab9e820023fadcf90c9f0f5
|
4
|
+
data.tar.gz: de99f00ab5f8c44a9c9efdf051507cf1bc0095c56a4c37cf4480fdb0a1306e05
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fc676b66315b85a71794755904ccc3f97b9bc6b2258b1da034e0f585487dbec81bfd20c0aa84d853e54156996d3656434039395d76245e80bd4506ccd1ad4bbe
|
7
|
+
data.tar.gz: 04d3117b6ae9bf6c19990c1edd34a186c37d94643f771dd1aa0c5e1beee8256e1f3531f3401af9d27cef1602c00340830af33a447e5aca8e22dc0f040a7734d8
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## [1.0.3](https://github.com/ShipEngine/shipengine-ruby/compare/v1.0.2...v1.0.3) (2023-06-16)
|
4
|
+
|
5
|
+
|
6
|
+
### Bug Fixes
|
7
|
+
|
8
|
+
* Update publish to Gem API Key ([3f9c8e5](https://github.com/ShipEngine/shipengine-ruby/commit/3f9c8e5eec8147e2fb1b38a114fa0e2ff24a5f9e))
|
data/README.md
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
[![ShipEngine](https://shipengine.github.io/img/shipengine-logo-wide.png)](https://shipengine.com)
|
2
|
+
|
3
|
+
ShipEngine Ruby SDK
|
4
|
+
===================
|
5
|
+
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/ShipEngine/shipengine-ruby/CI?label=shipengine-ruby&logo=github)
|
6
|
+
![GitHub](https://img.shields.io/github/license/ShipEngine/shipengine-ruby?color=teal)
|
7
|
+
|
8
|
+
The Official Ruby SDK for [ShipEngine API](https://shipengine.com) offering low-level access as well as convenience methods.
|
9
|
+
|
10
|
+
Quick Start
|
11
|
+
===========
|
12
|
+
|
13
|
+
Install ShipEngine via [RubyGems](https://rubygems.org/)
|
14
|
+
```bash
|
15
|
+
gem install shipengine_sdk
|
16
|
+
```
|
17
|
+
- The only configuration requirement is an [API Key](https://www.shipengine.com/docs/auth/#api-keys).
|
18
|
+
|
19
|
+
Methods
|
20
|
+
-------
|
21
|
+
* [`create_label_from_rate`](./docs/create-label-from-rate.md) - When retrieving rates for shipments using the `get_rates` method, the returned information contains a `rate_id` property that can be used to purchase a label without having to refill in the shipment information repeatedly.
|
22
|
+
* [`create_label_from_shipment_details`](./docs/create-label-from-shipment-details.md) - Purchase and print a label for shipment.
|
23
|
+
* [`get_rates`](./docs/get-rates.md) - Given some shipment details and rate options, this method returns a list of rate quotes.
|
24
|
+
* [`list_carrier_accounts`](./docs/list-carrier-accounts.md) - Returns a list of carrier accounts that have been connected through
|
25
|
+
the [ShipEngine dashboard](https://www.shipengine.com/docs/carriers/setup/).
|
26
|
+
* [`track_by_label_id`](./docs/track-by-label-id.md) - Track a package by its associated label ID.
|
27
|
+
* [`track_using_carrier_code_and_tracking_number`](./docs/track-by-tracking-number.md) - Track a package by its associated trackng number.
|
28
|
+
* [`validate_addresses`](./docs/validate-addresses.md) - Indicates whether the provided addresses are valid. If the addresses are valid, the method returns a normalized version based on the standards of the country in which the address resides. If an address cannot be normalized, an error is returned.
|
29
|
+
* [`void_label_by_id`](./docs/void-label-by-id.md) - Void a label by its ID.
|
30
|
+
|
31
|
+
Class Objects
|
32
|
+
-------------
|
33
|
+
- [ShipEngine]() - A configurable entry point to the ShipEngine API SDK, this class provides convenience methods
|
34
|
+
for various ShipEngine API Services.
|
35
|
+
|
36
|
+
Instantiate ShipEngine Class
|
37
|
+
----------------------------
|
38
|
+
```ruby
|
39
|
+
require "shipengine"
|
40
|
+
|
41
|
+
api_key = ENV["SHIPENGINE_API_KEY"]
|
42
|
+
|
43
|
+
shipengine = ShipEngine.new(api_key)
|
44
|
+
```
|
45
|
+
|
46
|
+
Contributing
|
47
|
+
============
|
48
|
+
|
49
|
+
Install dependencies
|
50
|
+
--------------------
|
51
|
+
- You will need to `gem install bundler` before using the following command to install dependencies from the Gemfile.
|
52
|
+
```bash
|
53
|
+
./bin/setup
|
54
|
+
```
|
55
|
+
|
56
|
+
Committing
|
57
|
+
-------------------------
|
58
|
+
This project adheres to the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification.
|
59
|
+
|
60
|
+
Pre-Commit/Pre-Push Hooks
|
61
|
+
-------------------------
|
62
|
+
This project makes use of [Overcommit](https://github.com/sds/overcommit#usage) to enforce `pre-commit/push hooks`.
|
63
|
+
Overcommit will be downloaded and initialized as part of running the `./bin/setup` script, as outlined in the previous section.
|
64
|
+
|
65
|
+
- From then on when you commit code `rake lint` will run, and when you push code `rake test` and `rake lint` will run.
|
66
|
+
Upon failure of either of these, you can run `rake fix` to auto-fix lint issues and format code, and re-commit/push.
|
67
|
+
|
68
|
+
Testing & Development
|
69
|
+
---------------------
|
70
|
+
- While you are writing tests as you contribute code you can run tests ad-hoc via `rake` using the following command:
|
71
|
+
```bash
|
72
|
+
rake test
|
73
|
+
```
|
74
|
+
- You can run tests and have them re-run when you save changes to a given file with `guard`.
|
75
|
+
```bash
|
76
|
+
guard
|
77
|
+
```
|
78
|
+
Lastly, you can `format code & auto-fix lint errors` with the following:
|
79
|
+
```bash
|
80
|
+
rake fix
|
81
|
+
```
|
82
|
+
|
83
|
+
> Note: `guard` also provides a repl after tests run for quick repl development.
|
84
|
+
|
85
|
+
Repl Development
|
86
|
+
----------------
|
87
|
+
- You can start a `pry` repl that already has `shipengine` required bun running the following command.
|
88
|
+
```bash
|
89
|
+
./bin/console
|
90
|
+
```
|
91
|
+
> If you prefer `irb` over `pry`, you can follow the instructions in the [./bin/console](./bin/console) file. Please
|
92
|
+
DO NOT commit any changes you make to that file, unless they are improvements to the console workflow.
|
93
|
+
|
94
|
+
Publishing
|
95
|
+
-------------------------
|
96
|
+
Publishing new versions of the SDK to [RubyGems](https://rubygems.org/) is handled on GitHub via the [Release Please](https://github.com/googleapis/release-please) GitHub Actions workflow. Learn more about about Release PRs, updating the changelog, and commit messages [here](https://github.com/googleapis/release-please#how-should-i-write-my-commits).
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'faraday'
|
4
|
+
# @private
|
5
|
+
module FaradayMiddleware
|
6
|
+
# @private
|
7
|
+
class RaiseHttpException < Faraday::Middleware
|
8
|
+
def call(env)
|
9
|
+
@app.call(env).on_complete do |response|
|
10
|
+
case response[:status].to_i
|
11
|
+
when 400, 401, 404, 500, 502, 503, 504
|
12
|
+
raise ShipEngine::Exceptions::ShipEngineError.new(
|
13
|
+
message: error_body(response[:body]),
|
14
|
+
source: error_source(response[:body]),
|
15
|
+
type: error_type(response[:body]),
|
16
|
+
code: error_code(response[:body]),
|
17
|
+
request_id: response[:body]['request_id'],
|
18
|
+
url: response[:url].to_s
|
19
|
+
)
|
20
|
+
when 429
|
21
|
+
raise ShipEngine::Exceptions::RateLimitError.new(retries: env.request_headers['Retries'].to_i, source: error_source(response[:body]), request_id: response[:body]['request_id'])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(app)
|
27
|
+
super(app)
|
28
|
+
@parser = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def error_message_400(response) # rubocop:todo Naming/VariableNumber
|
34
|
+
"#{response[:method].to_s.upcase} #{response[:url]}: #{response[:status]}#{error_body(response[:body])}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def error_body(body)
|
38
|
+
body = ::JSON.parse(body) if !body.nil? && !body.empty? && body.is_a?(String)
|
39
|
+
|
40
|
+
if body.nil?
|
41
|
+
nil
|
42
|
+
elsif body['errors'] && !body['errors'].empty?
|
43
|
+
body['errors'][0]['message']
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def error_source(body)
|
48
|
+
body = ::JSON.parse(body) if !body.nil? && !body.empty? && body.is_a?(String)
|
49
|
+
|
50
|
+
if body.nil?
|
51
|
+
nil
|
52
|
+
elsif body['errors'] && !body['errors'].empty?
|
53
|
+
body['errors'][0]['error_source']
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def error_type(body)
|
58
|
+
body = ::JSON.parse(body) if !body.nil? && !body.empty? && body.is_a?(String)
|
59
|
+
|
60
|
+
if body.nil?
|
61
|
+
nil
|
62
|
+
elsif body['errors'] && !body['errors'].empty?
|
63
|
+
body['errors'][0]['error_type']
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def error_code(body)
|
68
|
+
body = ::JSON.parse(body) if !body.nil? && !body.empty? && body.is_a?(String)
|
69
|
+
|
70
|
+
if body.nil?
|
71
|
+
nil
|
72
|
+
elsif body['errors'] && !body['errors'].empty?
|
73
|
+
body['errors'][0]['error_code']
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShipEngine
|
4
|
+
class Configuration
|
5
|
+
attr_accessor :api_key, :retries, :base_url, :timeout, :page_size
|
6
|
+
|
7
|
+
def initialize(api_key:, retries: nil, timeout: nil, page_size: nil, base_url: nil)
|
8
|
+
@api_key = api_key
|
9
|
+
@base_url = base_url || Constants.base_url
|
10
|
+
@retries = retries || 1
|
11
|
+
@timeout = timeout || 30_000
|
12
|
+
@page_size = page_size || 50
|
13
|
+
validate
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param opts [Hash] the options to create a message with.
|
17
|
+
# @option opts [String] :ap The subject
|
18
|
+
# @option opts [String] :from ('nobody') From address
|
19
|
+
# @option opts [String] :to Recipient email
|
20
|
+
# @option opts [String] :body ('') The email's bod
|
21
|
+
def merge(config)
|
22
|
+
copy = clone
|
23
|
+
copy.api_key = config[:api_key] if config.key?(:api_key)
|
24
|
+
copy.base_url = config[:base_url] if config.key?(:base_url)
|
25
|
+
copy.retries = config[:retries] if config.key?(:retries)
|
26
|
+
copy.timeout = config[:timeout] if config.key?(:timeout)
|
27
|
+
copy.page_size = config[:page_size] if config.key?(:page_size)
|
28
|
+
copy.validate
|
29
|
+
copy
|
30
|
+
end
|
31
|
+
|
32
|
+
# since the fields in the class are mutable, we should be able to validate them at any time.
|
33
|
+
protected
|
34
|
+
|
35
|
+
def validate
|
36
|
+
Utils::Validate.str('A ShipEngine API key', @api_key)
|
37
|
+
Utils::Validate.str('Base URL', @base_url)
|
38
|
+
Utils::Validate.non_neg_int('Retries', @retries)
|
39
|
+
Utils::Validate.positive_int('Timeout', @timeout)
|
40
|
+
Utils::Validate.positive_int('Page size', @page_size)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShipEngine
|
4
|
+
module Constants
|
5
|
+
# A stub API Key to use in the test suite.
|
6
|
+
API_KEY = 'TEST_ycvJAgX6tLB1Awm9WGJmD8mpZ8wXiQ20WhqFowCk32s'
|
7
|
+
|
8
|
+
# The base_url for the ShipEngine SDK - for use in production environment.
|
9
|
+
PROD_URL = 'https://api.shipengine.com'
|
10
|
+
|
11
|
+
# Regex pattern to match a valid *ISO-8601* string with timezone.
|
12
|
+
VALID_ISO_STRING = /^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?(Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?$/
|
13
|
+
|
14
|
+
# Regex pattern to match a valid *ISO-8601* string with no timezone.
|
15
|
+
VALID_ISO_STRING_WITH_NO_TZ = /^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?([+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?$/
|
16
|
+
|
17
|
+
# Check env variables to set the appropriate base_url.
|
18
|
+
def self.base_url
|
19
|
+
ShipEngine::Constants::PROD_URL
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShipEngine
|
4
|
+
module Constants
|
5
|
+
class Country
|
6
|
+
# rubocop:disable Layout/LineLength
|
7
|
+
@countries = %w[AF AX AL DZ AS AD AO AI AQ AG AR AM AW AU AT AZ BS BH BD BB BY BE BZ BJ BM BT BO BA BW BV BR IO BN BG BF BI KH CM CA CV KY CF TD CL CN CX CC CO KM CG CD CK CR CI HR CU CY CZ DK DJ DM DO EC EG SV GQ ER EE ET FK FO FJ FI FR GF PF TF GA GM GE DE GH GI GR GL GD GP GU GT GG GN GW GY HT HM VA HN HK HU IS IN ID IR IQ IE IM IL IT JM JP JE JO KZ KE KI KR KW KG LA LV LB LS LR LY LI LT LU MO MK MG MW MY MV ML MT MH MQ MR MU YT MX FM MD MC MN ME MS MA MZ MM NA NR NP NL NC NZ NI NE NG NU NF MP NO OM PK PW PS PA PG PY PE PH PN PL PT PR QA RE RO RU RW BL SH KN LC MF PM VC WS SM ST SA SN RS SC SL SG SK SI SB SO ZA GS ES LK SD SR SJ SZ SE CH SY TW TJ TZ TH TL TG TK TO TT TN TR TM TC TV UG UA AE GB US UM UY UZ VU VE VN VG VI WF EH YE ZM ZW].freeze
|
8
|
+
# rubocop:enable Layout/LineLength
|
9
|
+
|
10
|
+
# @param [String] country - 2 letter country code
|
11
|
+
def self.valid?(country)
|
12
|
+
@countries.include?(country.upcase)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShipEngine
|
4
|
+
module Domain
|
5
|
+
class Addresses
|
6
|
+
module AddressValidation
|
7
|
+
class Response
|
8
|
+
attr_reader :status, :original_address, :matched_address, :messages
|
9
|
+
|
10
|
+
# type ["unverified" | "verified" | "warning" | "error"] status
|
11
|
+
# @param [NormalizedAddress] original_address
|
12
|
+
# @param [NormalizedAddress?] matched_address
|
13
|
+
# @param [Array<Response>] messages
|
14
|
+
def initialize(status:, original_address:, matched_address:, messages:)
|
15
|
+
@status = status
|
16
|
+
@original_address = original_address
|
17
|
+
@matched_address = matched_address
|
18
|
+
@messages = messages
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Request
|
23
|
+
attr_reader :address_line1,
|
24
|
+
:address_line2,
|
25
|
+
:address_line3,
|
26
|
+
:name,
|
27
|
+
:company_name,
|
28
|
+
:phone,
|
29
|
+
:city_locality,
|
30
|
+
:state_province,
|
31
|
+
:postal_code,
|
32
|
+
:country_code,
|
33
|
+
:address_residential_indicator
|
34
|
+
|
35
|
+
# @param [String] address_line1 - e.g. ["123 FAKE ST."]
|
36
|
+
# @param [String?] address_line2 - e.g. ["123 FAKE ST."]
|
37
|
+
# @param [String?] address_line3 - e.g. ["123 FAKE ST."]
|
38
|
+
# @param [String] country_code - e.g. "US". @see https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes
|
39
|
+
# @param [String] postal_code - e.g "78751"
|
40
|
+
# @param [String?] name - e.g. "John Smith"
|
41
|
+
# @param [String?] company_name - e.g. "ShipEngine"
|
42
|
+
# @param [String?] phone - e.g. 5551234567
|
43
|
+
# @param [String?] city_locality - e.g. "AUSTIN"
|
44
|
+
# @param [String?] state_province - e.g. "TX"
|
45
|
+
# @param [String?] address_residential_indicator
|
46
|
+
def initialize(address_line1:, address_line2:, address_line3:, name:, company_name:, phone:, city_locality:, state_province:, postal_code:, # rubocop:todo Metrics/ParameterLists
|
47
|
+
country_code:, address_residential_indicator:)
|
48
|
+
|
49
|
+
@name = name
|
50
|
+
@company_name = company_name
|
51
|
+
@address_line1 = address_line1
|
52
|
+
@address_line2 = address_line2
|
53
|
+
@address_line3 = address_line3
|
54
|
+
@phone = phone
|
55
|
+
@city_locality = city_locality
|
56
|
+
@state_province = state_province
|
57
|
+
@postal_code = postal_code
|
58
|
+
@country_code = country_code
|
59
|
+
@address_residential_indicator = address_residential_indicator
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class Address
|
64
|
+
attr_reader :address_line1,
|
65
|
+
:address_line2,
|
66
|
+
:address_line3,
|
67
|
+
:name,
|
68
|
+
:company_name,
|
69
|
+
:phone,
|
70
|
+
:city_locality,
|
71
|
+
:state_province,
|
72
|
+
:postal_code,
|
73
|
+
:country_code,
|
74
|
+
:address_residential_indicator
|
75
|
+
|
76
|
+
# @param [String] address_line1 - e.g. ["123 FAKE ST."]
|
77
|
+
# @param [String?] address_line2 - e.g. ["123 FAKE ST."]
|
78
|
+
# @param [String?] address_line3 - e.g. ["123 FAKE ST."]
|
79
|
+
# @param [String] country_code - e.g. "US". @see https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes
|
80
|
+
# @param [String] postal_code - e.g "78751"
|
81
|
+
# @param [String?] name - e.g. "John Smith"
|
82
|
+
# @param [String?] company_name - e.g. "ShipEngine"
|
83
|
+
# @param [String?] phone - e.g. 5551234567
|
84
|
+
# @param [String?] city_locality - e.g. "AUSTIN"
|
85
|
+
# @param [String?] state_province - e.g. "TX"
|
86
|
+
# @param [String?] address_residential_indicator
|
87
|
+
def initialize(address_line1:, address_line2:, address_line3:, name:, company_name:, phone:, city_locality:, state_province:, postal_code:, # rubocop:todo Metrics/ParameterLists
|
88
|
+
country_code:, address_residential_indicator:)
|
89
|
+
|
90
|
+
@name = name
|
91
|
+
@company_name = company_name
|
92
|
+
@address_line1 = address_line1
|
93
|
+
@address_line2 = address_line2
|
94
|
+
@address_line3 = address_line3
|
95
|
+
@phone = phone
|
96
|
+
@city_locality = city_locality
|
97
|
+
@state_province = state_province
|
98
|
+
@postal_code = postal_code
|
99
|
+
@country_code = country_code
|
100
|
+
@address_residential_indicator = address_residential_indicator
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class Message
|
105
|
+
attr_reader :type, :code, :message
|
106
|
+
|
107
|
+
# @param type [:info" | :warning | :error"]
|
108
|
+
# @param code [String] = e.g. "suite_missing"
|
109
|
+
def initialize(type:, code:, message:)
|
110
|
+
@type = type
|
111
|
+
@code = code
|
112
|
+
@message = message
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'hashie'
|
4
|
+
require_relative 'addresses/address_validation'
|
5
|
+
|
6
|
+
module ShipEngine
|
7
|
+
module Domain
|
8
|
+
class Addresses
|
9
|
+
require 'shipengine/constants'
|
10
|
+
|
11
|
+
# @param [ShipEngine::InternalClient] internal_client
|
12
|
+
def initialize(internal_client)
|
13
|
+
@internal_client = internal_client
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param addresses [ShipEngine::Domain::Addresses::AddressValidationRequest]
|
17
|
+
# @param config [Hash?]
|
18
|
+
#
|
19
|
+
# @return [Array<ShipEngine::Domain::Addresses::AddressValidationResponse>]
|
20
|
+
#
|
21
|
+
# @see https://shipengine.github.io/shipengine-openapi/#operation/validate_address
|
22
|
+
def validate(addresses, config)
|
23
|
+
addresses_array = addresses.map(&:compact)
|
24
|
+
|
25
|
+
response = @internal_client.post('/v1/addresses/validate', addresses_array, config)
|
26
|
+
address_api_result = response.body
|
27
|
+
|
28
|
+
address_api_result.map do |result|
|
29
|
+
mash_result = Hashie::Mash.new(result)
|
30
|
+
normalized_original_address_api_result = AddressValidation::Address.new(
|
31
|
+
address_line1: mash_result.original_address.address_line1,
|
32
|
+
address_line2: mash_result.original_address.address_line2,
|
33
|
+
address_line3: mash_result.original_address.address_line3,
|
34
|
+
name: mash_result.original_address.name,
|
35
|
+
company_name: mash_result.original_address.company_name,
|
36
|
+
phone: mash_result.original_address.phone,
|
37
|
+
city_locality: mash_result.original_address.city_locality,
|
38
|
+
state_province: mash_result.original_address.state_province,
|
39
|
+
postal_code: mash_result.original_address.postal_code,
|
40
|
+
country_code: mash_result.original_address.country_code,
|
41
|
+
address_residential_indicator: mash_result.original_address.address_residential_indicator
|
42
|
+
)
|
43
|
+
|
44
|
+
normalized_matched_address_api_result = if mash_result.matched_address
|
45
|
+
AddressValidation::Address.new(
|
46
|
+
address_line1: mash_result.matched_address.address_line1,
|
47
|
+
address_line2: mash_result.matched_address.address_line2,
|
48
|
+
address_line3: mash_result.matched_address.address_line3,
|
49
|
+
name: mash_result.matched_address.name,
|
50
|
+
company_name: mash_result.matched_address.company_name,
|
51
|
+
phone: mash_result.matched_address.phone,
|
52
|
+
city_locality: mash_result.matched_address.city_locality,
|
53
|
+
state_province: mash_result.matched_address.state_province,
|
54
|
+
postal_code: mash_result.matched_address.postal_code,
|
55
|
+
country_code: mash_result.matched_address.country_code,
|
56
|
+
address_residential_indicator: mash_result.matched_address.address_residential_indicator
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
status = mash_result.status
|
61
|
+
|
62
|
+
messages_classes = mash_result.messages.map do |msg|
|
63
|
+
AddressValidation::Message.new(type: msg['type'], code: msg['code'], message: msg['message'])
|
64
|
+
end
|
65
|
+
|
66
|
+
AddressValidation::Response.new(
|
67
|
+
status:,
|
68
|
+
messages: messages_classes,
|
69
|
+
original_address: normalized_original_address_api_result,
|
70
|
+
matched_address: normalized_matched_address_api_result
|
71
|
+
)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShipEngine
|
4
|
+
module Domain
|
5
|
+
class Carriers
|
6
|
+
module ListCarriers
|
7
|
+
class Response
|
8
|
+
attr_reader :carriers, :request_id, :errors
|
9
|
+
|
10
|
+
# @param [Carrier] carriers
|
11
|
+
# @param [String?] request_id
|
12
|
+
# @param [Array<Error>?] carriers
|
13
|
+
def initialize(carriers:, request_id:, errors:)
|
14
|
+
@carriers = carriers
|
15
|
+
@request_id = request_id
|
16
|
+
@errors = errors
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Error
|
21
|
+
attr_reader :error_source, :error_type, :error_code, :message
|
22
|
+
|
23
|
+
# type ["carrier" | "order_source" | "shipengine"] error_source
|
24
|
+
# type ["account_status" | "business_rules" | "validation" | "security" | "system" | "integrations"] error_type
|
25
|
+
# @param [String] error_code
|
26
|
+
# @param [String] message
|
27
|
+
def initialize(error_source:, error_type:, error_code:, message:)
|
28
|
+
@error_source = error_source
|
29
|
+
@error_type = error_type
|
30
|
+
@error_code = error_code
|
31
|
+
@message = message
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Carrier
|
36
|
+
attr_reader :carrier_id, :carrier_code, :account_number, :requires_funded_amount, :balance, :nickname, :friendly_name, :primary, :has_multi_package_supporting_services, :supports_label_messages, :services, :packages, :options
|
37
|
+
|
38
|
+
# @param [String] carrier_id - e.g. "se-28529731"
|
39
|
+
# @param [String] carrier_code - e.g. "se-28529731"
|
40
|
+
# @param [String] account_number - e.g. "account_570827"
|
41
|
+
# @param [Boolean] requires_funded_amount - e.g. true
|
42
|
+
# @param [Float] balance - e.g. 3799.52
|
43
|
+
# @param [String] nickname - e.g. "ShipEngine Account - Stamps.com"
|
44
|
+
# @param [String] friendly_name - e.g. "Stamps.com",
|
45
|
+
# @param [Boolean] primary - e.g. true,
|
46
|
+
# @param [Boolean] has_multi_package_supporting_services - e.g. true,
|
47
|
+
# @param [Boolean] supports_label_messages - e.g. true,
|
48
|
+
# @param [Array<Carrier::Service>] services
|
49
|
+
# @param [Array<Carrier::Package>] packages
|
50
|
+
# @param [Array<Carrier::Option>] options
|
51
|
+
def initialize(carrier_id:, carrier_code:, account_number:, requires_funded_amount:, balance:, nickname:, friendly_name:, primary:, has_multi_package_supporting_services:, supports_label_messages:, services:, packages:, options:) # rubocop:todo Metrics/ParameterLists
|
52
|
+
@carrier_id = carrier_id
|
53
|
+
@carrier_code = carrier_code
|
54
|
+
@account_number = account_number
|
55
|
+
@requires_funded_amount = requires_funded_amount
|
56
|
+
@balance = balance
|
57
|
+
@nickname = nickname
|
58
|
+
@friendly_name = friendly_name
|
59
|
+
@primary = primary
|
60
|
+
@has_multi_package_supporting_services = has_multi_package_supporting_services
|
61
|
+
@supports_label_messages = supports_label_messages
|
62
|
+
@services = services
|
63
|
+
@packages = packages
|
64
|
+
@options = options
|
65
|
+
end
|
66
|
+
|
67
|
+
class Service
|
68
|
+
attr_reader :carrier_id, :carrier_code, :service_code, :name, :domestic, :international, :is_multi_package_supported
|
69
|
+
|
70
|
+
# @param [String] carrier_id - e.g. "se-28529731"
|
71
|
+
# @param [String] carrier_code - e.g. "se-28529731"
|
72
|
+
# @param [String] service_code - e.g. "usps_media_mail"
|
73
|
+
# @param [String] name - e.g. "USPS First Class Mail"
|
74
|
+
# @param [Boolean] domestic - e.g. true
|
75
|
+
# @param [Boolean] international - e.g. true
|
76
|
+
# @param [Boolean] is_multi_package_supported - e.g. true
|
77
|
+
|
78
|
+
def initialize(carrier_id:, carrier_code:, service_code:, name:, domestic:, international:, is_multi_package_supported:) # rubocop:todo Metrics/ParameterLists
|
79
|
+
@carrier_id = carrier_id
|
80
|
+
@carrier_code = carrier_code
|
81
|
+
@service_code = service_code
|
82
|
+
@name = name
|
83
|
+
@domestic = domestic
|
84
|
+
@international = international
|
85
|
+
@is_multi_package_supported = is_multi_package_supported
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class Package
|
90
|
+
attr_reader :package_id, :package_code, :name, :dimensions, :description
|
91
|
+
|
92
|
+
# @param [String?] package_id - e.g. "se-28529731"
|
93
|
+
# @param [String] package_code - e.g. "small_flat_rate_box"
|
94
|
+
# @param [name] name - e.g. "laptop_box"
|
95
|
+
# @param [Package::Dimensions?] dimensions - e.g. true
|
96
|
+
# @param [String?] description - e.g. true
|
97
|
+
|
98
|
+
def initialize(package_id:, package_code:, name:, dimensions:, description:)
|
99
|
+
@package_id = package_id
|
100
|
+
@package_code = package_code
|
101
|
+
@name = name
|
102
|
+
@dimensions = dimensions
|
103
|
+
@description = description
|
104
|
+
end
|
105
|
+
|
106
|
+
class Dimensions
|
107
|
+
attr_reader :unit, :length, :width, :height
|
108
|
+
|
109
|
+
# type ["inch" | "centimeter"] unit
|
110
|
+
# @param [Double] length - e.g. 1.0
|
111
|
+
# @param [Double] width - e.g. 1.0
|
112
|
+
# @param [Double] height - e.g. 1.0
|
113
|
+
|
114
|
+
def initialize(unit:, length:, width:, height:)
|
115
|
+
@unit = unit
|
116
|
+
@length = length
|
117
|
+
@width = width
|
118
|
+
@height = height
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
class Option
|
124
|
+
attr_reader :name, :default_value, :description
|
125
|
+
|
126
|
+
# @param [String] name - e.g. "contains_alcohol"
|
127
|
+
# @param [String] default_value - e.g. "false"
|
128
|
+
# @param [String?] description - e.g. "Option"
|
129
|
+
|
130
|
+
def initialize(name:, default_value:, description:)
|
131
|
+
@name = name
|
132
|
+
@default_value = default_value
|
133
|
+
@description = description
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|