easypost 4.1.2 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.yml +81 -0
- data/.github/ISSUE_TEMPLATE/feature_request.yml +37 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +22 -0
- data/.github/workflows/ci.yml +3 -3
- data/CHANGELOG.md +7 -0
- data/CODE_OF_CONDUCT.md +16 -0
- data/CONTRIBUTING.md +47 -0
- data/README.md +60 -83
- data/SECURITY.md +7 -0
- data/SUPPORT.md +3 -0
- data/VERSION +1 -1
- data/easycop.yml +1 -1
- data/easypost.gemspec +2 -2
- data/lib/easypost/address.rb +10 -20
- data/lib/easypost/beta/beta.rb +6 -0
- data/lib/easypost/beta/beta_referral.rb +96 -0
- data/lib/easypost/order.rb +5 -0
- data/lib/easypost/pickup.rb +5 -0
- data/lib/easypost/report.rb +1 -0
- data/lib/easypost/shipment.rb +32 -42
- data/lib/easypost/util.rb +81 -0
- data/lib/easypost.rb +1 -0
- metadata +18 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 18f330382213345312caf4cb5981ad506f3d882aaf2f78f556598d5201e28d94
|
4
|
+
data.tar.gz: 4a750f473664d70f8d72f252a875e4eab75d256ffe0925fc5027915ecfc4cd3e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 96e3c87b8ff96f797ca25e42e2dc61ce8c814826fca95b7f80506aa96624a5df58fe0f762fb87eab71f0e89422996d31d88f153b434c11268b220893731438a1
|
7
|
+
data.tar.gz: 2ea7ea89d3cedea7222de7cbe41af96ef0b912b23e0409cfa2ffc5576915553ed578f7dfb315d0870bf5e6391ed5a7eff396eed7972db4e814223faa3152bc56
|
@@ -0,0 +1,81 @@
|
|
1
|
+
name: Bug Report
|
2
|
+
description: File a bug report
|
3
|
+
title: "[Bug]: "
|
4
|
+
labels: [ "triage" ]
|
5
|
+
body:
|
6
|
+
- type: markdown
|
7
|
+
attributes:
|
8
|
+
value: |
|
9
|
+
Thank you for taking the time to report an issue in this repository. Please fill out the form below.
|
10
|
+
- type: input
|
11
|
+
id: software-version
|
12
|
+
attributes:
|
13
|
+
label: Software Version
|
14
|
+
# change this description for the specific repo
|
15
|
+
description: |
|
16
|
+
What version of our software are you running?
|
17
|
+
TIP: [Available versions](https://github.com/EasyPost/easypost-ruby/releases)
|
18
|
+
validations:
|
19
|
+
required: true
|
20
|
+
- type: input
|
21
|
+
id: language-version
|
22
|
+
attributes:
|
23
|
+
label: Language Version
|
24
|
+
# change this description for the specific language of the repo
|
25
|
+
description: |
|
26
|
+
What language version and/or framework are you using?
|
27
|
+
TIP: [How to find your Ruby version](https://blog.arkency.com/which-ruby-version-am-i-using-how-to-check/)
|
28
|
+
validations:
|
29
|
+
required: true
|
30
|
+
- type: input
|
31
|
+
id: os
|
32
|
+
attributes:
|
33
|
+
label: Operating System
|
34
|
+
description: What operating system are you running the software on?
|
35
|
+
validations:
|
36
|
+
required: true
|
37
|
+
- type: textarea
|
38
|
+
id: behavior
|
39
|
+
attributes:
|
40
|
+
label: What happened?
|
41
|
+
description: |
|
42
|
+
Please describe what happened in reproducible steps.
|
43
|
+
Include how often you see this issue, and any relevant links (i.e. GitHub issue, Stack Overflow, etc.).
|
44
|
+
value: |
|
45
|
+
1.
|
46
|
+
2.
|
47
|
+
3.
|
48
|
+
...
|
49
|
+
validations:
|
50
|
+
required: true
|
51
|
+
- type: textarea
|
52
|
+
id: expected-behavior
|
53
|
+
attributes:
|
54
|
+
label: What was expected?
|
55
|
+
description: Please describe what was expected to happen instead.
|
56
|
+
validations:
|
57
|
+
required: true
|
58
|
+
- type: textarea
|
59
|
+
id: sample-code
|
60
|
+
attributes:
|
61
|
+
label: Sample Code
|
62
|
+
description: |
|
63
|
+
Please provide any sample code that demonstrates the behavior.
|
64
|
+
This will be automatically formatted into the appropriate language, so no need for backticks.
|
65
|
+
**Do not include any private information such as API keys or passwords.**
|
66
|
+
# change this render to the appropriate language: https://github.com/github/linguist/blob/master/lib/linguist/languages.yml
|
67
|
+
render: rb
|
68
|
+
validations:
|
69
|
+
required: false
|
70
|
+
- type: textarea
|
71
|
+
id: logs
|
72
|
+
attributes:
|
73
|
+
label: Relevant logs
|
74
|
+
description: |
|
75
|
+
Please copy and paste any relevant log output.
|
76
|
+
This will be automatically formatted into shell output, so no need for backticks.
|
77
|
+
If you have screenshots instead, please paste them below.
|
78
|
+
**Do not include any private information such as API keys or passwords.**
|
79
|
+
render: sh
|
80
|
+
validations:
|
81
|
+
required: false
|
@@ -0,0 +1,37 @@
|
|
1
|
+
name: Feature Request
|
2
|
+
description: Request a new feature
|
3
|
+
title: "[Feat]: "
|
4
|
+
labels: [ "triage" ]
|
5
|
+
body:
|
6
|
+
- type: markdown
|
7
|
+
attributes:
|
8
|
+
value: |
|
9
|
+
Thank you for taking the time to request a new feature.
|
10
|
+
Please note, all feature requests are subject to review and approval.
|
11
|
+
We welcome all suggestions and ideas, but we cannot guarantee when or if we will implement them.
|
12
|
+
|
13
|
+
We also welcome pull requests, if you would like to implement the feature yourself.
|
14
|
+
Doing so will likely accelerate the process of implementing the requested feature.
|
15
|
+
- type: checkboxes
|
16
|
+
id: searched
|
17
|
+
attributes:
|
18
|
+
label: Feature Request Is New
|
19
|
+
# change issue link below for the specific repo
|
20
|
+
description: |
|
21
|
+
Before we begin, please confirm that the requested feature does not already exist or has not [already been requested](https://github.com/EasyPost/easypost-ruby/issues).
|
22
|
+
options:
|
23
|
+
- label: I have verified that the requested feature does not already exist or has not already been requested.
|
24
|
+
required: true
|
25
|
+
- type: textarea
|
26
|
+
id: description
|
27
|
+
attributes:
|
28
|
+
label: Description of the feature
|
29
|
+
description: |
|
30
|
+
Please provide a detailed description of the feature, including:
|
31
|
+
- What the feature is
|
32
|
+
- What value it adds to the application
|
33
|
+
- How it should be implemented (i.e. pseudo-code, or a high-level description of the user experience)
|
34
|
+
- Any other relevant information
|
35
|
+
validations:
|
36
|
+
required: true
|
37
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Description
|
2
|
+
|
3
|
+
<!-- Please provide a general summary of your PR changes and link any related issues or other pull requests. -->
|
4
|
+
|
5
|
+
# Testing
|
6
|
+
|
7
|
+
<!--
|
8
|
+
Please provide details on how you tested this code. See below.
|
9
|
+
|
10
|
+
- All pull requests must be tested (unit tests where possible with accompanying cassettes, or provide a screenshot of end-to-end testing when unit tests are not possible)
|
11
|
+
- New features must get a new unit test
|
12
|
+
- Bug fixes/refactors must re-record existing cassettes
|
13
|
+
-->
|
14
|
+
|
15
|
+
# Pull Request Type
|
16
|
+
|
17
|
+
Please select the option(s) that are relevant to this PR.
|
18
|
+
|
19
|
+
- [ ] Bug fix (non-breaking change which fixes an issue)
|
20
|
+
- [ ] New feature (non-breaking change which adds functionality)
|
21
|
+
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
22
|
+
- [ ] Improvement (fixing a typo, updating readme, renaming a variable name, etc)
|
data/.github/workflows/ci.yml
CHANGED
@@ -13,7 +13,7 @@ jobs:
|
|
13
13
|
rubyversion: ["2.5", "2.6", "2.7", "3.0", "3.1"]
|
14
14
|
steps:
|
15
15
|
- name: Checkout Repository
|
16
|
-
uses: actions/checkout@
|
16
|
+
uses: actions/checkout@v3
|
17
17
|
- name: Set up Ruby
|
18
18
|
uses: ruby/setup-ruby@v1
|
19
19
|
with:
|
@@ -25,11 +25,11 @@ jobs:
|
|
25
25
|
runs-on: ubuntu-latest
|
26
26
|
steps:
|
27
27
|
- name: Checkout Repository
|
28
|
-
uses: actions/checkout@
|
28
|
+
uses: actions/checkout@v3
|
29
29
|
- name: Set up Ruby
|
30
30
|
uses: ruby/setup-ruby@v1
|
31
31
|
with:
|
32
|
-
ruby-version: "3.
|
32
|
+
ruby-version: "3.1"
|
33
33
|
- name: Install Dependencies
|
34
34
|
run: bundle install
|
35
35
|
- name: Lint Project
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## v4.2.0 (2022-05-09)
|
4
|
+
|
5
|
+
- Adds a `lowest_rate()` function to Orders and Pickups
|
6
|
+
- Adds a `Shipment.get_lowest_smartrate()` function and a `shipment.lowest_smartrate()` function
|
7
|
+
- Removes the unusable `carrier` param from `Address.create_and_verify` along with the dead `message` conditional check
|
8
|
+
- Add beta Referral class for White Label API with these new functions: `create()`, `update_email()`, `all()`, and `add_credit_card()`
|
9
|
+
|
3
10
|
## v4.1.2 (2022-03-16)
|
4
11
|
|
5
12
|
- Rolls back the original connection behavior of establishing a new connection for every request (restores previous expectations for multithreaded implementations)
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# Code of Conduct
|
2
|
+
|
3
|
+
> Remember the golden rule? Treat others as you'd like to be treated
|
4
|
+
|
5
|
+
## Standards
|
6
|
+
|
7
|
+
- Create a welcoming and safe community for `everyone`
|
8
|
+
- Demonstrate empathy towards others, realize that everyone has a different `level of experience`
|
9
|
+
- Be respectful of others opinions, viewpoints, and experiences
|
10
|
+
- Give and receive respectful constructive feedback
|
11
|
+
- Accept responsibility and apologize when necessary
|
12
|
+
- Focus on what is best for the overall community
|
13
|
+
|
14
|
+
## Failure to Follow Standards
|
15
|
+
|
16
|
+
If there is a failure to follow the standards laid out above, the user will first be warned. If the offending behavior continues, the user may be blocked entirely.
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# Contributing Guide
|
2
|
+
|
3
|
+
Please read this document in its entirety.
|
4
|
+
|
5
|
+
## General
|
6
|
+
|
7
|
+
- Be nice and respectful of maintainers’ and contributors’ time and viewpoints
|
8
|
+
- Be as descriptive as possible! More info is always better than not enough
|
9
|
+
- Be patient, there may be a lot of in-flight work, some of it across multiple projects not related to the repo being contributed to
|
10
|
+
- Have fun!
|
11
|
+
|
12
|
+
## Contributing
|
13
|
+
|
14
|
+
Contributing comes in many forms! We are incredibly grateful to anyone who can do any of the following:
|
15
|
+
|
16
|
+
- Add new features
|
17
|
+
- Fix bugs
|
18
|
+
- Fix typos
|
19
|
+
- Improve docs
|
20
|
+
- Improve tests
|
21
|
+
- Triage issues
|
22
|
+
- Review pull requests
|
23
|
+
- Share opinions and viewpoints on issues
|
24
|
+
|
25
|
+
## Issues
|
26
|
+
|
27
|
+
- If your issue is security related, please follow the [SECURITY guide](https://github.com/easypost/.github/SECURITY.md)
|
28
|
+
- Before opening a new issue, check for existing issues that are related, including closed ones
|
29
|
+
- Provide as much information as possible about the issue, including how to reproduce the problem and the expected behavior
|
30
|
+
- Don't needlessly bump issues (eg: if there hasn’t been progress for more than a few weeks, feel free to reach back out)
|
31
|
+
|
32
|
+
## Pull Requests
|
33
|
+
|
34
|
+
- All Pull Requests should be accompanied first by an issue describing the reason why the Pull Request is needed
|
35
|
+
- Be as descriptive as possible in your PR description about why the changes are being made and what the changes contain
|
36
|
+
- Pull Requests should be as small as possible
|
37
|
+
- Don't make unrelated changes in your Pull Request
|
38
|
+
- Don't open a Pull Request if you don't plan to see it through. PRs submitted by individuals that cannot complete additional work to get a PR merged may be closed without completion
|
39
|
+
- Adhere to the existing code style of the repo, even if it differs from your personal preference
|
40
|
+
- When applicable, add tests that provide ample coverage of the logic added or changed
|
41
|
+
- Pull Requests should come from branches and never the default `master` branch
|
42
|
+
- Pull Requests must pass CI, including linting and testing
|
43
|
+
- Pull Requests must go through code review before they can be merged to the main branch
|
44
|
+
- Do not include "version bump" changes in the same PR as your code changes; these will be handled as a separate PR and releasing process
|
45
|
+
- Make sure the `Allow edits from maintainers` checkbox is checked. That way EasyPost engineers can make certain minor changes as needed, allowing your pull request to be merged sooner.
|
46
|
+
|
47
|
+
You agree and acknowledge that you have necessary intellectual property rights to provide your Contribution and hereby assign to EasyPost all right, title and interest in such Contribution.
|
data/README.md
CHANGED
@@ -3,112 +3,65 @@
|
|
3
3
|
[![Build Status](https://github.com/EasyPost/easypost-ruby/workflows/CI/badge.svg)](https://github.com/EasyPost/easypost-ruby/actions?query=workflow%3ACI)
|
4
4
|
[![Gem Version](https://badge.fury.io/rb/easypost.svg)](https://badge.fury.io/rb/easypost)
|
5
5
|
|
6
|
+
EasyPost, the simple shipping solution. You can sign up for an account at https://easypost.com.
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
## Installation
|
10
|
-
|
11
|
-
Install the gem:
|
8
|
+
## Install
|
12
9
|
|
13
10
|
```bash
|
14
11
|
gem install easypost
|
15
12
|
```
|
16
13
|
|
17
|
-
Import the EasyPost client in your application:
|
18
|
-
|
19
14
|
```ruby
|
15
|
+
# Require the library in your project:
|
20
16
|
require 'easypost'
|
21
17
|
```
|
22
18
|
|
23
|
-
##
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
A simple create & buy shipment example:
|
24
22
|
|
25
23
|
```ruby
|
26
24
|
require 'easypost'
|
27
|
-
EasyPost.api_key = 'API_KEY'
|
28
|
-
|
29
|
-
to_address = EasyPost::Address.create(
|
30
|
-
:name => 'Dr. Steve Brule',
|
31
|
-
:street1 => '179 N Harbor Dr',
|
32
|
-
:city => 'Redondo Beach',
|
33
|
-
:state => 'CA',
|
34
|
-
:zip => '90277',
|
35
|
-
:country => 'US',
|
36
|
-
:phone => '310-808-5243'
|
37
|
-
)
|
38
25
|
|
39
|
-
|
40
|
-
:company => 'EasyPost',
|
41
|
-
:street1 => '118 2nd Street',
|
42
|
-
:street2 => '4th Floor',
|
43
|
-
:city => 'San Francisco',
|
44
|
-
:state => 'CA',
|
45
|
-
:zip => '94105',
|
46
|
-
:phone => '415-456-7890'
|
47
|
-
)
|
48
|
-
|
49
|
-
parcel = EasyPost::Parcel.create(
|
50
|
-
:width => 15.2,
|
51
|
-
:length => 18,
|
52
|
-
:height => 9.5,
|
53
|
-
:weight => 35.1
|
54
|
-
)
|
55
|
-
|
56
|
-
customs_item = EasyPost::CustomsItem.create(
|
57
|
-
:description => 'EasyPost T-shirts',
|
58
|
-
:quantity => 2,
|
59
|
-
:value => 23.56,
|
60
|
-
:weight => 33,
|
61
|
-
:origin_country => 'us',
|
62
|
-
:hs_tariff_number => 123456
|
63
|
-
)
|
64
|
-
|
65
|
-
customs_info = EasyPost::CustomsInfo.create(
|
66
|
-
:integrated_form_type => 'form_2976',
|
67
|
-
:customs_certify => true,
|
68
|
-
:customs_signer => 'Dr. Pepper',
|
69
|
-
:contents_type => 'gift',
|
70
|
-
:contents_explanation => '', # only required when contents_type => 'other'
|
71
|
-
:eel_pfc => 'NOEEI 30.37(a)',
|
72
|
-
:non_delivery_option => 'abandon',
|
73
|
-
:restriction_type => 'none',
|
74
|
-
:restriction_comments => '',
|
75
|
-
:customs_items => [customs_item]
|
76
|
-
)
|
26
|
+
EasyPost.api_key = ENV['EASYPOST_API_KEY']
|
77
27
|
|
78
28
|
shipment = EasyPost::Shipment.create(
|
79
|
-
:
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
29
|
+
from_address: {
|
30
|
+
company: 'EasyPost',
|
31
|
+
street1: '118 2nd Street',
|
32
|
+
street2: '4th Floor',
|
33
|
+
city: 'San Francisco',
|
34
|
+
state: 'CA',
|
35
|
+
zip: '94105',
|
36
|
+
phone: '415-456-7890',
|
37
|
+
},
|
38
|
+
to_address: {
|
39
|
+
name: 'Dr. Steve Brule',
|
40
|
+
street1: '179 N Harbor Dr',
|
41
|
+
city: 'Redondo Beach',
|
42
|
+
state: 'CA',
|
43
|
+
zip: '90277',
|
44
|
+
country: 'US',
|
45
|
+
phone: '310-808-5243',
|
46
|
+
},
|
47
|
+
parcel: {
|
48
|
+
width: 15.2,
|
49
|
+
length: 18,
|
50
|
+
height: 9.5,
|
51
|
+
weight: 35.1,
|
52
|
+
},
|
87
53
|
)
|
88
54
|
|
89
|
-
shipment.
|
55
|
+
shipment.buy(rate: shipment.lowest_rate)
|
90
56
|
|
91
|
-
puts shipment
|
92
|
-
|
93
|
-
puts shipment.postage_label.label_url
|
57
|
+
puts shipment
|
94
58
|
```
|
95
59
|
|
96
|
-
|
97
|
-
|
98
|
-
Up-to-date documentation at: https://easypost.com/docs
|
99
|
-
|
100
|
-
## Development
|
101
|
-
|
102
|
-
```bash
|
103
|
-
# Run tests (coverage is generated on a successful test suite run)
|
104
|
-
EASYPOST_TEST_API_KEY=123... EASYPOST_PROD_API_KEY=123... bundle exec rspec
|
105
|
-
```
|
106
|
-
|
107
|
-
## Custom connections
|
60
|
+
### Custom Connections
|
108
61
|
|
109
62
|
Set `EasyPost.default_connection` to an object that responds to `call(method, path, api_key = nil, body = nil)`
|
110
63
|
|
111
|
-
|
64
|
+
#### Faraday
|
112
65
|
|
113
66
|
```ruby
|
114
67
|
require 'faraday'
|
@@ -134,7 +87,7 @@ EasyPost.default_connection = lambda do |method, path, api_key = nil, body = nil
|
|
134
87
|
end
|
135
88
|
```
|
136
89
|
|
137
|
-
|
90
|
+
#### Typhoeus
|
138
91
|
|
139
92
|
```ruby
|
140
93
|
require 'typhoeus'
|
@@ -154,3 +107,27 @@ EasyPost.default_connection = lambda do |method, path, api_key = nil, body = nil
|
|
154
107
|
}
|
155
108
|
end
|
156
109
|
```
|
110
|
+
|
111
|
+
## Documentation
|
112
|
+
|
113
|
+
API Documentation can be found at: https://easypost.com/docs/api.
|
114
|
+
|
115
|
+
## Development
|
116
|
+
|
117
|
+
```bash
|
118
|
+
# Install dependencies
|
119
|
+
bundle install
|
120
|
+
|
121
|
+
# Run tests (coverage is generated on a successful test suite run)
|
122
|
+
EASYPOST_TEST_API_KEY=123... EASYPOST_PROD_API_KEY=123... bundle exec rspec
|
123
|
+
```
|
124
|
+
|
125
|
+
### Testing
|
126
|
+
|
127
|
+
The test suite in this project was specifically built to produce consistent results on every run, regardless of when they run or who is running them. This project uses [VCR](https://github.com/vcr/vcr) to record and replay HTTP requests and responses via "cassettes". When the suite is run, the HTTP requests and responses for each test function will be saved to a cassette if they do not exist already and replayed from this saved file if they do, which saves the need to make live API calls on every test run.
|
128
|
+
|
129
|
+
If you make an addition to this project, the request/response will get recorded automatically for you. When making changes to this project, you'll need to re-record the associated cassette to force a new live API call for that test which will then record the request/response used on the next run.
|
130
|
+
|
131
|
+
The test suite has been populated with various helpful fixtures that are available for use, each completely independent from a particular user **with the exception of the USPS carrier account ID** which has a fallback value to our internal testing user's ID. If you are a non-EasyPost employee and are re-recording cassettes, you may need to provide the `USPS_CARRIER_ACCOUNT_ID` environment variable with the ID associated with your USPS account (which will be associated with your API keys in use) for tests that use this fixture.
|
132
|
+
|
133
|
+
**Note on dates:** Some fixtures use hard-coded dates that may need to be incremented if cassettes get re-recorded (such as reports or pickups).
|
data/SECURITY.md
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
# Security Guide
|
2
|
+
|
3
|
+
We take security seriously at EasyPost. If you find a security issue or vulnerability in our open source projects, please abide by the following guidelines:
|
4
|
+
|
5
|
+
- Please read our [Responsible Disclosure Policy](https://www.easypost.com/privacy#disclosure-policy).
|
6
|
+
- Do not open an issue on GitHub about the security vulnerability. Doing so draws attention to the issue and exposes it to the public.
|
7
|
+
- Send an email to `security-abuse@easypost.com` including as many details as possible.
|
data/SUPPORT.md
ADDED
@@ -0,0 +1,3 @@
|
|
1
|
+
# Support Guide
|
2
|
+
|
3
|
+
Looking for support for one of our projects? If your question is related to our API, please contact our support team at `support@easypost.com`. If you need support regarding this project, create an issue on GitHub with as many details as possible and we’ll take a look.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
4.
|
1
|
+
4.2.0
|
data/easycop.yml
CHANGED
data/easypost.gemspec
CHANGED
@@ -24,10 +24,10 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.add_development_dependency 'pry', '~> 0.14'
|
25
25
|
spec.add_development_dependency 'rake', '~> 13.0'
|
26
26
|
spec.add_development_dependency 'rspec', '~> 3.10'
|
27
|
-
spec.add_development_dependency 'rubocop', '
|
27
|
+
spec.add_development_dependency 'rubocop', '= 1.27' # rubocop 1.28 requires Ruby 2.6+
|
28
28
|
spec.add_development_dependency 'rubocop-rspec', '~> 2.7'
|
29
29
|
spec.add_development_dependency 'simplecov', '~> 0.21'
|
30
30
|
spec.add_development_dependency 'simplecov-lcov', '~> 0.8'
|
31
|
-
spec.add_development_dependency 'vcr', '
|
31
|
+
spec.add_development_dependency 'vcr', '= 6.0' # VCR 6.1 requires Ruby 2.6+
|
32
32
|
spec.add_development_dependency 'webmock', '~> 3.14'
|
33
33
|
end
|
data/lib/easypost/address.rb
CHANGED
@@ -6,40 +6,30 @@ class EasyPost::Address < EasyPost::Resource
|
|
6
6
|
|
7
7
|
# Create an Address.
|
8
8
|
def self.create(params = {}, api_key = nil)
|
9
|
-
url = self.url
|
10
|
-
|
11
9
|
address = params.reject { |k, _| [:verify, :verify_strict].include?(k) }
|
12
10
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
verify_strict.each do |verification|
|
22
|
-
url += "verify_strict[]=#{verification}&"
|
23
|
-
end
|
11
|
+
wrapped_params = { address: address }
|
12
|
+
|
13
|
+
if params[:verify]
|
14
|
+
wrapped_params[:verify] = params[:verify]
|
15
|
+
end
|
16
|
+
|
17
|
+
if params[:verify_strict]
|
18
|
+
wrapped_params[:verify_strict] = params[:verify_strict]
|
24
19
|
end
|
25
20
|
|
26
|
-
response = EasyPost.make_request(:post, url, api_key,
|
21
|
+
response = EasyPost.make_request(:post, url, api_key, wrapped_params)
|
27
22
|
EasyPost::Util.convert_to_easypost_object(response, api_key)
|
28
23
|
end
|
29
24
|
|
30
25
|
# Create and verify an Address in one call.
|
31
|
-
def self.create_and_verify(params = {},
|
26
|
+
def self.create_and_verify(params = {}, api_key = nil)
|
32
27
|
wrapped_params = {}
|
33
28
|
wrapped_params[class_name.to_sym] = params
|
34
|
-
wrapped_params[:carrier] = carrier
|
35
29
|
response = EasyPost.make_request(:post, "#{url}/create_and_verify", api_key, wrapped_params)
|
36
30
|
|
37
31
|
raise EasyPost::Error.new('Unable to verify address.') unless response.key?('address')
|
38
32
|
|
39
|
-
if response.key?('message')
|
40
|
-
response['address']['message'] = response['message']
|
41
|
-
end
|
42
|
-
|
43
33
|
EasyPost::Util.convert_to_easypost_object(response['address'], api_key)
|
44
34
|
end
|
45
35
|
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class EasyPost::BetaReferral < EasyPost::Resource
|
4
|
+
# Create a referral user. This function requires the Partner User's API key.
|
5
|
+
def self.create(params = {}, api_key = nil)
|
6
|
+
response = EasyPost.make_request(:post, '/beta/referral_customers', api_key, { user: params })
|
7
|
+
EasyPost::Util.convert_to_easypost_object(response, api_key)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Update a referral user. This function requires the Partner User's API key.
|
11
|
+
def self.update_email(email, user_id, api_key = nil)
|
12
|
+
wrapped_params = {
|
13
|
+
user: {
|
14
|
+
email: email,
|
15
|
+
},
|
16
|
+
}
|
17
|
+
_ = EasyPost.make_request(:put, "/beta/referral_customers/#{user_id}", api_key, wrapped_params)
|
18
|
+
|
19
|
+
# return true if API succeeds, else an error is throw if it fails.
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
# Retrieve a list of referral users. This function requires the Partner User's API key.
|
24
|
+
def self.all(params = {}, api_key = nil)
|
25
|
+
response = EasyPost.make_request(:get, '/beta/referral_customers', api_key, params)
|
26
|
+
EasyPost::Util.convert_to_easypost_object(response, api_key)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Add credit card to a referral user. This function requires the Referral User's API key.
|
30
|
+
def self.add_credit_card(referral_api_key, number, expiration_month, expiration_year, cvc, priority = 'primary')
|
31
|
+
easypost_stripe_api_key = retrieve_easypost_stripe_api_key
|
32
|
+
|
33
|
+
begin
|
34
|
+
stripe_credit_card_token = create_stripe_token(
|
35
|
+
number,
|
36
|
+
expiration_month,
|
37
|
+
expiration_year,
|
38
|
+
cvc,
|
39
|
+
easypost_stripe_api_key,
|
40
|
+
)
|
41
|
+
rescue StandardError
|
42
|
+
raise EasyPost::Error.new('Could not send card details to Stripe, please try again later.')
|
43
|
+
end
|
44
|
+
|
45
|
+
response = create_easypost_credit_card(referral_api_key, stripe_credit_card_token, priority)
|
46
|
+
EasyPost::Util.convert_to_easypost_object(response, referral_api_key)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Retrieve EasyPost's Stripe public API key.
|
50
|
+
def self.retrieve_easypost_stripe_api_key
|
51
|
+
response = EasyPost.make_request(:get, '/beta/partners/stripe_public_key', @api_key)
|
52
|
+
response['public_key']
|
53
|
+
end
|
54
|
+
|
55
|
+
# Get credit card token from Stripe.
|
56
|
+
def self.create_stripe_token(number, expiration_month, expiration_year, cvc, easypost_stripe_token)
|
57
|
+
headers = {
|
58
|
+
# This Stripe endpoint only accepts URL form encoded bodies.
|
59
|
+
Authorization: "Bearer #{easypost_stripe_token}",
|
60
|
+
'Content-type': 'application/x-www-form-urlencoded',
|
61
|
+
}
|
62
|
+
|
63
|
+
credit_card_hash = {
|
64
|
+
card: {
|
65
|
+
number: number,
|
66
|
+
exp_month: expiration_month,
|
67
|
+
exp_year: expiration_year,
|
68
|
+
cvc: cvc,
|
69
|
+
},
|
70
|
+
}
|
71
|
+
|
72
|
+
form_encoded_params = EasyPost::Util.form_encode_params(credit_card_hash)
|
73
|
+
|
74
|
+
uri = URI.parse('https://api.stripe.com/v1/tokens')
|
75
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
76
|
+
http.use_ssl = true
|
77
|
+
request = Net::HTTP::Post.new(uri.request_uri, headers)
|
78
|
+
query = URI.encode_www_form(form_encoded_params)
|
79
|
+
|
80
|
+
response = http.request(request, query)
|
81
|
+
response_json = JSON.parse(response.body)
|
82
|
+
response_json['id']
|
83
|
+
end
|
84
|
+
|
85
|
+
# Submit Stripe credit card token to EasyPost.
|
86
|
+
def self.create_easypost_credit_card(referral_api_key, stripe_object_id, priority = 'primary')
|
87
|
+
wrapped_params = {
|
88
|
+
credit_card: {
|
89
|
+
stripe_object_id: stripe_object_id,
|
90
|
+
priority: priority,
|
91
|
+
},
|
92
|
+
}
|
93
|
+
response = EasyPost.make_request(:post, '/beta/credit_cards', referral_api_key, wrapped_params)
|
94
|
+
EasyPost::Util.convert_to_easypost_object(response, referral_api_key)
|
95
|
+
end
|
96
|
+
end
|
data/lib/easypost/order.rb
CHANGED
@@ -29,4 +29,9 @@ class EasyPost::Order < EasyPost::Resource
|
|
29
29
|
def self.all
|
30
30
|
raise NotImplementedError.new('Order.all not implemented.')
|
31
31
|
end
|
32
|
+
|
33
|
+
# Get the lowest rate of an Order (can exclude by having `'!'` as the first element of your optional filter lists).
|
34
|
+
def lowest_rate(carriers = [], services = [])
|
35
|
+
EasyPost::Util.get_lowest_object_rate(self, carriers, services)
|
36
|
+
end
|
32
37
|
end
|
data/lib/easypost/pickup.rb
CHANGED
@@ -29,4 +29,9 @@ class EasyPost::Pickup < EasyPost::Resource
|
|
29
29
|
def self.all
|
30
30
|
raise NotImplementedError.new('Pickup.all not implemented.')
|
31
31
|
end
|
32
|
+
|
33
|
+
# Get the lowest rate of a Pickup (can exclude by having `'!'` as the first element of your optional filter lists).
|
34
|
+
def lowest_rate(carriers = [], services = [])
|
35
|
+
EasyPost::Util.get_lowest_object_rate(self, carriers, services, 'pickup_rates')
|
36
|
+
end
|
32
37
|
end
|
data/lib/easypost/report.rb
CHANGED
data/lib/easypost/shipment.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'set'
|
4
|
+
|
3
5
|
# The workhorse of the EasyPost API, a Shipment is made up of a "to" and "from" Address, the Parcel
|
4
6
|
# being shipped, and any customs forms required for international deliveries.
|
5
7
|
class EasyPost::Shipment < EasyPost::Resource
|
@@ -68,58 +70,46 @@ class EasyPost::Shipment < EasyPost::Resource
|
|
68
70
|
self
|
69
71
|
end
|
70
72
|
|
71
|
-
# Get the lowest rate of a Shipment.
|
73
|
+
# Get the lowest rate of a Shipment (can exclude by having `'!'` as the first element of your optional filter lists).
|
72
74
|
def lowest_rate(carriers = [], services = [])
|
73
|
-
|
74
|
-
|
75
|
-
get_rates unless rates
|
75
|
+
EasyPost::Util.get_lowest_object_rate(self, carriers, services)
|
76
|
+
end
|
76
77
|
|
77
|
-
|
78
|
+
# Get the lowest smartrate of a Shipment.
|
79
|
+
def lowest_smartrate(delivery_days, delivery_accuracy)
|
80
|
+
smartrates = get_smartrates
|
81
|
+
EasyPost::Shipment.get_lowest_smartrate(smartrates, delivery_days, delivery_accuracy)
|
82
|
+
end
|
78
83
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
84
|
+
# Get the lowest smartrate from a list of smartrates.
|
85
|
+
def self.get_lowest_smartrate(smartrates, delivery_days, delivery_accuracy)
|
86
|
+
valid_delivery_accuracy_values = Set[
|
87
|
+
'percentile_50',
|
88
|
+
'percentile_75',
|
89
|
+
'percentile_85',
|
90
|
+
'percentile_90',
|
91
|
+
'percentile_95',
|
92
|
+
'percentile_97',
|
93
|
+
'percentile_99',
|
94
|
+
]
|
95
|
+
lowest_smartrate = nil
|
96
|
+
|
97
|
+
unless valid_delivery_accuracy_values.include?(delivery_accuracy.downcase)
|
98
|
+
raise EasyPost::Error.new("Invalid delivery accuracy value, must be one of: #{valid_delivery_accuracy_values}")
|
86
99
|
end
|
87
100
|
|
88
|
-
|
101
|
+
smartrates.each do |rate|
|
102
|
+
next if rate['time_in_transit'][delivery_accuracy] > delivery_days.to_i
|
89
103
|
|
90
|
-
|
91
|
-
|
92
|
-
services_copy.each do |service|
|
93
|
-
if service[0, 1] == '!'
|
94
|
-
negative_services << service[1..-1]
|
95
|
-
services.delete(service)
|
104
|
+
if lowest_smartrate.nil? || rate['rate'].to_f < lowest_smartrate['rate'].to_f
|
105
|
+
lowest_smartrate = rate
|
96
106
|
end
|
97
107
|
end
|
98
108
|
|
99
|
-
|
100
|
-
|
101
|
-
if carriers.size.positive? && !carriers.include?(rate_carrier)
|
102
|
-
next
|
103
|
-
end
|
104
|
-
if negative_carriers.size.positive? && negative_carriers.include?(rate_carrier)
|
105
|
-
next
|
106
|
-
end
|
107
|
-
|
108
|
-
rate_service = k.service.downcase
|
109
|
-
if services.size.positive? && !services.include?(rate_service)
|
110
|
-
next
|
111
|
-
end
|
112
|
-
if negative_services.size.positive? && negative_services.include?(rate_service)
|
113
|
-
next
|
114
|
-
end
|
115
|
-
|
116
|
-
if lowest.nil? || k.rate.to_f < lowest.rate.to_f
|
117
|
-
lowest = k
|
118
|
-
end
|
109
|
+
if lowest_smartrate.nil?
|
110
|
+
raise EasyPost::Error.new('No rates found.')
|
119
111
|
end
|
120
112
|
|
121
|
-
|
122
|
-
|
123
|
-
lowest
|
113
|
+
lowest_smartrate
|
124
114
|
end
|
125
115
|
end
|
data/lib/easypost/util.rb
CHANGED
@@ -2,6 +2,35 @@
|
|
2
2
|
|
3
3
|
# Internal utilities helpful for this libraries operation.
|
4
4
|
module EasyPost::Util
|
5
|
+
# Form-encode a multi-layer dictionary to a one-layer dictionary.
|
6
|
+
def self.form_encode_params(hash, parent_keys = [], parent_dict = {})
|
7
|
+
result = parent_dict or {}
|
8
|
+
keys = parent_keys or []
|
9
|
+
|
10
|
+
hash.each do |key, value|
|
11
|
+
if value.instance_of?(Hash)
|
12
|
+
keys << key
|
13
|
+
result = form_encode_params(value, keys, result)
|
14
|
+
else
|
15
|
+
dict_key = build_dict_key(keys + [key])
|
16
|
+
result[dict_key] = value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
result
|
20
|
+
end
|
21
|
+
|
22
|
+
# Build a dict key from a list of keys.
|
23
|
+
# Example: [code, number] -> code[number]
|
24
|
+
def self.build_dict_key(keys)
|
25
|
+
result = keys[0].to_s
|
26
|
+
|
27
|
+
keys[1..-1].each do |key|
|
28
|
+
result += "[#{key}]"
|
29
|
+
end
|
30
|
+
|
31
|
+
result
|
32
|
+
end
|
33
|
+
|
5
34
|
# Converts an object to an object ID.
|
6
35
|
def self.objects_to_ids(obj)
|
7
36
|
case obj
|
@@ -110,4 +139,56 @@ module EasyPost::Util
|
|
110
139
|
response
|
111
140
|
end
|
112
141
|
end
|
142
|
+
|
143
|
+
# Gets the lowest rate of an EasyPost object such as a Shipment, Order, or Pickup.
|
144
|
+
# You can exclude by having `'!'` as the first element of your optional filter lists
|
145
|
+
def self.get_lowest_object_rate(easypost_object, carriers = [], services = [], rates_key = 'rates')
|
146
|
+
lowest_rate = nil
|
147
|
+
|
148
|
+
carriers = EasyPost::Util.normalize_string_list(carriers)
|
149
|
+
negative_carriers = []
|
150
|
+
carriers_copy = carriers.clone
|
151
|
+
carriers_copy.each do |carrier|
|
152
|
+
if carrier[0, 1] == '!'
|
153
|
+
negative_carriers << carrier[1..-1]
|
154
|
+
carriers.delete(carrier)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
services = EasyPost::Util.normalize_string_list(services)
|
159
|
+
negative_services = []
|
160
|
+
services_copy = services.clone
|
161
|
+
services_copy.each do |service|
|
162
|
+
if service[0, 1] == '!'
|
163
|
+
negative_services << service[1..-1]
|
164
|
+
services.delete(service)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
easypost_object[rates_key].each do |rate|
|
169
|
+
rate_carrier = rate.carrier.downcase
|
170
|
+
if carriers.size.positive? && !carriers.include?(rate_carrier)
|
171
|
+
next
|
172
|
+
end
|
173
|
+
if negative_carriers.size.positive? && negative_carriers.include?(rate_carrier)
|
174
|
+
next
|
175
|
+
end
|
176
|
+
|
177
|
+
rate_service = rate.service.downcase
|
178
|
+
if services.size.positive? && !services.include?(rate_service)
|
179
|
+
next
|
180
|
+
end
|
181
|
+
if negative_services.size.positive? && negative_services.include?(rate_service)
|
182
|
+
next
|
183
|
+
end
|
184
|
+
|
185
|
+
if lowest_rate.nil? || rate.rate.to_f < lowest_rate.rate.to_f
|
186
|
+
lowest_rate = rate
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
raise EasyPost::Error.new('No rates found.') if lowest_rate.nil?
|
191
|
+
|
192
|
+
lowest_rate
|
193
|
+
end
|
113
194
|
end
|
data/lib/easypost.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: easypost
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- EasyPost Developers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-05-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|
@@ -56,16 +56,16 @@ dependencies:
|
|
56
56
|
name: rubocop
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - '='
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '1.
|
61
|
+
version: '1.27'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - '='
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '1.
|
68
|
+
version: '1.27'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rubocop-rspec
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -112,14 +112,14 @@ dependencies:
|
|
112
112
|
name: vcr
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
|
-
- -
|
115
|
+
- - '='
|
116
116
|
- !ruby/object:Gem::Version
|
117
117
|
version: '6.0'
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
|
-
- -
|
122
|
+
- - '='
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '6.0'
|
125
125
|
- !ruby/object:Gem::Dependency
|
@@ -143,14 +143,21 @@ executables:
|
|
143
143
|
extensions: []
|
144
144
|
extra_rdoc_files: []
|
145
145
|
files:
|
146
|
+
- ".github/ISSUE_TEMPLATE/bug_report.yml"
|
147
|
+
- ".github/ISSUE_TEMPLATE/feature_request.yml"
|
148
|
+
- ".github/PULL_REQUEST_TEMPLATE.md"
|
146
149
|
- ".github/workflows/ci.yml"
|
147
150
|
- ".gitignore"
|
148
151
|
- ".rubocop.yml"
|
149
152
|
- CHANGELOG.md
|
153
|
+
- CODE_OF_CONDUCT.md
|
154
|
+
- CONTRIBUTING.md
|
150
155
|
- Gemfile
|
151
156
|
- LICENSE
|
152
157
|
- README.md
|
153
158
|
- Rakefile
|
159
|
+
- SECURITY.md
|
160
|
+
- SUPPORT.md
|
154
161
|
- UPGRADE_GUIDE.md
|
155
162
|
- VERSION
|
156
163
|
- bin/easypost-irb
|
@@ -160,6 +167,8 @@ files:
|
|
160
167
|
- lib/easypost/address.rb
|
161
168
|
- lib/easypost/api_key.rb
|
162
169
|
- lib/easypost/batch.rb
|
170
|
+
- lib/easypost/beta/beta.rb
|
171
|
+
- lib/easypost/beta/beta_referral.rb
|
163
172
|
- lib/easypost/brand.rb
|
164
173
|
- lib/easypost/carrier_account.rb
|
165
174
|
- lib/easypost/carrier_type.rb
|
@@ -206,7 +215,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
206
215
|
- !ruby/object:Gem::Version
|
207
216
|
version: '0'
|
208
217
|
requirements: []
|
209
|
-
rubygems_version: 3.3.
|
218
|
+
rubygems_version: 3.3.7
|
210
219
|
signing_key:
|
211
220
|
specification_version: 4
|
212
221
|
summary: EasyPost Ruby Client Library
|