sendcloud-ruby 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +1 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +38 -0
- data/Rakefile +1 -0
- data/lib/sendcloud.rb +5 -0
- data/lib/sendcloud/base.rb +30 -0
- data/lib/sendcloud/parcel_resource.rb +61 -0
- data/lib/sendcloud/shipment_address.rb +5 -0
- data/lib/sendcloud/shipping_method.rb +18 -0
- data/lib/sendcloud/version.rb +3 -0
- data/sendcloud.gemspec +30 -0
- data/spec/lib/sendcloud/base_spec.rb +12 -0
- data/spec/lib/sendcloud/parcel_resource_spec.rb +96 -0
- data/spec/lib/sendcloud/shipping_method_spec.rb +57 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/vcr_cassettes/adjust_parcel.yml +84 -0
- data/spec/vcr_cassettes/adjust_with_wrong_parcel_id.yml +40 -0
- data/spec/vcr_cassettes/create_parcel.yml +43 -0
- data/spec/vcr_cassettes/get_label_for_parcel.yml +122 -0
- data/spec/vcr_cassettes/get_label_for_parcel_with_invalid_id.yml +40 -0
- data/spec/vcr_cassettes/get_parcel_error_with_invalid_pracel_id.yml +38 -0
- data/spec/vcr_cassettes/get_parcel_info.yml +81 -0
- data/spec/vcr_cassettes/get_shipping_method.yml +46 -0
- data/spec/vcr_cassettes/get_shipping_methods.yml +55 -0
- data/spec/vcr_cassettes/get_wrong_shipping_method.yml +44 -0
- data/spec/vcr_cassettes/wrong_create_parcel_without_name.yml +40 -0
- data/wercker.yml +25 -0
- metadata +201 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 925c78de85ca4fb2cf19a3c3f3c405bd75317b99
|
4
|
+
data.tar.gz: 6ac99e7ad7e5afbbfd070fedb88df7e67548352b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f05aa4716beacaaf2918fd93b2aa02d45c1b69d7e3ff2553a766d9cadfcc1e77fec8479928a2d3036c4010a6bd4d9d16b30f3a71201ea22bd91c0d5b9e671541
|
7
|
+
data.tar.gz: 3edc1714714bf6477ff289078e74075a99a084068c47eade006a159f5e89163ae00f8b81c5d16d1bc464222f170353f6af0af84936f3bfe43cd1d68594948413
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014-2015 PeRo ICT Solutions
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# Sendcloud
|
2
|
+
|
3
|
+
***WORK IN PROGRESS***
|
4
|
+
|
5
|
+
[](https://app.wercker.com/project/bykey/03866f33222cc05a0e18eb2aac723f5c)
|
6
|
+
[](http://badge.fury.io/rb/sendcloud)
|
7
|
+
[](https://codeclimate.com/github/pero-ict-solutions/sendcloud)
|
8
|
+
[](https://codeclimate.com/github/pero-ict-solutions/sendcloud)
|
9
|
+
|
10
|
+
Documentation on [RubyDoc](http://www.rubydoc.info/github/pero-ict-solutions/sendcloud/master)
|
11
|
+
|
12
|
+
Ruby API Client for the [SendCloud](https://www.sendcloud.nl) delivery platform.
|
13
|
+
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
Add this line to your application's Gemfile:
|
18
|
+
|
19
|
+
gem 'sendcloud-ruby'
|
20
|
+
|
21
|
+
And then execute:
|
22
|
+
|
23
|
+
$ bundle
|
24
|
+
|
25
|
+
Or install it yourself as:
|
26
|
+
|
27
|
+
$ gem install sendcloud-ruby
|
28
|
+
|
29
|
+
## Contributing
|
30
|
+
|
31
|
+
1. Fork it ( http://github.com/pero-ict-solutions/sendcloud/fork )
|
32
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
33
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
34
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
35
|
+
5. Create new Pull Request
|
36
|
+
|
37
|
+
|
38
|
+
Copyright (c) 2014-2015 PeRo ICT Solutions
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/sendcloud.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
|
3
|
+
module Sendcloud
|
4
|
+
class Base
|
5
|
+
include HTTParty
|
6
|
+
format :json
|
7
|
+
base_uri 'https://panel.sendcloud.nl/api/v2/'
|
8
|
+
|
9
|
+
attr_accessor :api_key, :api_secret
|
10
|
+
|
11
|
+
#
|
12
|
+
# @param api_key [String] the `apikey` from your account settings
|
13
|
+
# @param api_secret [String] the `apisecret` from your account settings
|
14
|
+
def initialize(api_key, api_secret)
|
15
|
+
self.api_key = api_key
|
16
|
+
self.api_secret = api_secret
|
17
|
+
end
|
18
|
+
|
19
|
+
# get the auth hash to use for all the requests
|
20
|
+
# since the sendcloud api uses basic authentication
|
21
|
+
# it will be used in the subclasses like this:
|
22
|
+
# `HTTParty.get("http://twitter.com/statuses/public_timeline.json", :basic_auth => auth)`
|
23
|
+
#
|
24
|
+
# @return [Hash] the basic auth hash based on the api_key and api_secret
|
25
|
+
def auth
|
26
|
+
{ username: api_key, password: api_secret}
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Sendcloud
|
2
|
+
class ParcelResourceException < StandardError; end
|
3
|
+
|
4
|
+
class ParcelResource < Base
|
5
|
+
def create_parcel(name, shipment_address, shipment = {id: 1, options: []}, method_params = {})
|
6
|
+
response = self.class.post('/parcels',
|
7
|
+
body: {
|
8
|
+
parcel: {
|
9
|
+
name: name,
|
10
|
+
address: shipment_address.address,
|
11
|
+
city: shipment_address.city,
|
12
|
+
postal_code: shipment_address.postal_code,
|
13
|
+
country: shipment_address.country,
|
14
|
+
shipment: shipment,
|
15
|
+
requestShipment: false
|
16
|
+
}.merge(method_params).
|
17
|
+
merge(telephone: '', email: '', data: [])
|
18
|
+
}.to_json,
|
19
|
+
basic_auth: auth,
|
20
|
+
headers: {'Content-Type' => 'application/json'}
|
21
|
+
)
|
22
|
+
handle_response_error(response)
|
23
|
+
response['parcel']
|
24
|
+
end
|
25
|
+
|
26
|
+
def adjust_parcel(parcel_id)
|
27
|
+
response = self.class.put('/parcels',
|
28
|
+
body: {
|
29
|
+
parcel: {
|
30
|
+
id: parcel_id,
|
31
|
+
requestShipment: true
|
32
|
+
}
|
33
|
+
}.to_json,
|
34
|
+
basic_auth: auth,
|
35
|
+
headers: {'Content-Type' => 'application/json'}
|
36
|
+
)
|
37
|
+
handle_response_error(response)
|
38
|
+
response['parcel']
|
39
|
+
end
|
40
|
+
|
41
|
+
def show_parcel(parcel_id)
|
42
|
+
response = self.class.get("/parcels/#{parcel_id}", basic_auth: auth)
|
43
|
+
handle_response_error(response)
|
44
|
+
response['parcel']
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_label_parcel(parcel_id)
|
48
|
+
response = self.class.get("/labels/#{parcel_id}", basic_auth: auth,
|
49
|
+
headers: {'Content-Type' => 'application/json'})
|
50
|
+
handle_response_error(response)
|
51
|
+
response['label']
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def handle_response_error(response)
|
56
|
+
if response['error']
|
57
|
+
raise ParcelResourceException.new(response['error']['message'])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Sendcloud
|
2
|
+
class ShippingMethodException < StandardError; end
|
3
|
+
|
4
|
+
class ShippingMethod < Base
|
5
|
+
def list
|
6
|
+
response = self.class.get("/shipping_methods", :basic_auth => auth)
|
7
|
+
response["shipping_methods"]
|
8
|
+
end
|
9
|
+
|
10
|
+
def get(shipping_id)
|
11
|
+
response = self.class.get("/shipping_methods/#{shipping_id}", :basic_auth => auth)
|
12
|
+
if response["error"]
|
13
|
+
raise ShippingMethodException.new(response["error"]["message"])
|
14
|
+
end
|
15
|
+
response["shipping_method"]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/sendcloud.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'sendcloud/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "sendcloud-ruby"
|
8
|
+
spec.version = Sendcloud::VERSION
|
9
|
+
spec.authors = ["Peter Berkenbosch"]
|
10
|
+
spec.email = ["peter@pero-ict.nl"]
|
11
|
+
spec.summary = %q{ruby client for the sendcloud api}
|
12
|
+
spec.description = spec.summary
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "httparty"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency 'rspec'
|
26
|
+
spec.add_development_dependency 'vcr'
|
27
|
+
spec.add_development_dependency 'webmock'
|
28
|
+
spec.add_development_dependency 'pry'
|
29
|
+
spec.add_development_dependency 'yard'
|
30
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sendcloud::Base do
|
4
|
+
|
5
|
+
context ".auth" do
|
6
|
+
it "returns a hash for basic_auth with api key and secret" do
|
7
|
+
basic_auth_hash = {username: "key", password: "secret"}
|
8
|
+
expect(Sendcloud::Base.new("key","secret").auth).to eql basic_auth_hash
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sendcloud::ParcelResource do
|
4
|
+
let!(:new_parcel){
|
5
|
+
{
|
6
|
+
"name"=>"Rob van den Heuvel",
|
7
|
+
"shipment_address" => Sendcloud::ShipmentAddress.new('Torenallee', 'Eindhoven', '5617BC', 'NL')
|
8
|
+
}
|
9
|
+
}
|
10
|
+
context 'create Parcel' do
|
11
|
+
|
12
|
+
it 'with valid params' do
|
13
|
+
pr = Sendcloud::ParcelResource.new('D74gAPTNto4N28N', 'Yb6m0YVBXtWm2zTdk')
|
14
|
+
VCR.use_cassette('create_parcel') do
|
15
|
+
parcel = pr.create_parcel(new_parcel['name'], new_parcel['shipment_address'], {id: 1})
|
16
|
+
expect(parcel).not_to be_empty
|
17
|
+
expect(parcel).to include('name'=>'Rob van den Heuvel')
|
18
|
+
expect(parcel).to include('id')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'without name' do
|
23
|
+
it 'will return a error' do
|
24
|
+
pr = Sendcloud::ParcelResource.new('D74gAPTNto4N28N', 'Yb6m0YVBXtWm2zTdk')
|
25
|
+
VCR.use_cassette('wrong_create_parcel_without_name') do
|
26
|
+
expect{pr.create_parcel(nil, new_parcel['shipment_address'], {id: 1})}.
|
27
|
+
to raise_error(Sendcloud::ParcelResourceException, 'Name is required')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'adjust Parcel' do
|
34
|
+
it 'with valid parcel_id' do
|
35
|
+
pr = Sendcloud::ParcelResource.new('D74gAPTNto4N28N', 'Yb6m0YVBXtWm2zTdk')
|
36
|
+
VCR.use_cassette('adjust_parcel') do
|
37
|
+
parcel = pr.create_parcel(new_parcel['name'], new_parcel['shipment_address'], {id: 1})
|
38
|
+
adjust_parcel = pr.adjust_parcel(parcel['id'])
|
39
|
+
expect(adjust_parcel).not_to be_empty
|
40
|
+
expect(adjust_parcel['status']).not_to be_empty
|
41
|
+
expect(adjust_parcel).to include('id')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
it 'with invalid parcel_id' do
|
45
|
+
pr = Sendcloud::ParcelResource.new('D74gAPTNto4N28N', 'Yb6m0YVBXtWm2zTdk')
|
46
|
+
VCR.use_cassette('adjust_with_wrong_parcel_id') do
|
47
|
+
parcel_id = 123456
|
48
|
+
expect{pr.adjust_parcel(parcel_id)}.to raise_error(Sendcloud::ParcelResourceException,
|
49
|
+
"Parcel is not found with ID: #{parcel_id}")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'get parcel' do
|
55
|
+
it 'with valid parcel_id' do
|
56
|
+
pr = Sendcloud::ParcelResource.new('D74gAPTNto4N28N', 'Yb6m0YVBXtWm2zTdk')
|
57
|
+
VCR.use_cassette('get_parcel_info') do
|
58
|
+
parcel = pr.create_parcel(new_parcel['name'], new_parcel['shipment_address'], {id: 1})
|
59
|
+
info = pr.show_parcel(parcel['id'])
|
60
|
+
expect(info).not_to be_empty
|
61
|
+
expect(info['id']).to eql(parcel['id'])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'with invalid parcel_id' do
|
66
|
+
pr = Sendcloud::ParcelResource.new('D74gAPTNto4N28N', 'Yb6m0YVBXtWm2zTdk')
|
67
|
+
VCR.use_cassette('get_parcel_error_with_invalid_pracel_id') do
|
68
|
+
parcel_id = 123456
|
69
|
+
expect{pr.show_parcel(parcel_id)}.to raise_error(Sendcloud::ParcelResourceException,
|
70
|
+
"You aren't authorized to get this parcel")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'get label' do
|
76
|
+
it 'with valid parcel_id' do
|
77
|
+
pr = Sendcloud::ParcelResource.new('D74gAPTNto4N28N', 'Yb6m0YVBXtWm2zTdk')
|
78
|
+
VCR.use_cassette('get_label_for_parcel') do
|
79
|
+
parcel = pr.create_parcel(new_parcel['name'], new_parcel['shipment_address'], {id: 1})
|
80
|
+
adjust_parcel = pr.adjust_parcel(parcel['id'])
|
81
|
+
label = pr.get_label_parcel(adjust_parcel['id'])
|
82
|
+
expect(label['normal_printer']).not_to be_empty
|
83
|
+
expect(label['label_printer']).not_to be_empty
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'with invalid parcel_id' do
|
88
|
+
pr = Sendcloud::ParcelResource.new('D74gAPTNto4N28N', 'Yb6m0YVBXtWm2zTdk')
|
89
|
+
VCR.use_cassette('get_label_for_parcel_with_invalid_id') do
|
90
|
+
parcel_id = 123456
|
91
|
+
expect{pr.get_label_parcel(parcel_id)}.to raise_error(Sendcloud::ParcelResourceException,
|
92
|
+
"Cannot find parcel with given Parcel ID (#{parcel_id})")
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sendcloud::ShippingMethod do
|
4
|
+
|
5
|
+
context ".list" do
|
6
|
+
it "returns the list of available shipping methods" do
|
7
|
+
sm = Sendcloud::ShippingMethod.new("key", "secret")
|
8
|
+
VCR.use_cassette('get_shipping_methods') do
|
9
|
+
methods = sm.list
|
10
|
+
expect(methods).to_not be_empty
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context ".get" do
|
16
|
+
|
17
|
+
context "with correct shipping_method id" do
|
18
|
+
|
19
|
+
let(:post_nl_shipping_method_hash) {
|
20
|
+
{
|
21
|
+
"id"=>1,
|
22
|
+
"name"=>"Pakket Nederland (PostNL)",
|
23
|
+
"countries"=>[
|
24
|
+
{
|
25
|
+
"id"=>2,
|
26
|
+
"iso_3"=>"NLD",
|
27
|
+
"iso_2"=>"NL",
|
28
|
+
"name"=>"Nederland",
|
29
|
+
"price"=>5.8
|
30
|
+
}
|
31
|
+
],
|
32
|
+
"price"=>5.8,
|
33
|
+
"options"=>[],
|
34
|
+
"combinations"=>[{"id"=>1, "name"=>"Normaal pakket"}]
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
it "will return the shipping method details" do
|
39
|
+
sm = Sendcloud::ShippingMethod.new("D74gAPTNto4N28N", "Yb6m0YVBXtWm2zTdk")
|
40
|
+
VCR.use_cassette('get_shipping_method') do
|
41
|
+
shipping_method = sm.get(1)
|
42
|
+
expect(shipping_method).to eql post_nl_shipping_method_hash
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "with invalid shipping_method id" do
|
48
|
+
it "will return a proper message" do
|
49
|
+
sm = Sendcloud::ShippingMethod.new("key", "secret")
|
50
|
+
VCR.use_cassette('get_wrong_shipping_method') do
|
51
|
+
expect{sm.get(99)}.to raise_error(Sendcloud::ShippingMethodException, "Can't find shipping method with given ID (99)")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require "codeclimate-test-reporter"
|
2
|
+
CodeClimate::TestReporter.start
|
3
|
+
|
4
|
+
require 'sendcloud'
|
5
|
+
require 'pry'
|
6
|
+
require 'vcr'
|
7
|
+
require 'webmock'
|
8
|
+
|
9
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
10
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
11
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
12
|
+
# loaded once.
|
13
|
+
#
|
14
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
15
|
+
RSpec.configure do |config|
|
16
|
+
config.run_all_when_everything_filtered = true
|
17
|
+
config.filter_run :focus
|
18
|
+
|
19
|
+
# Run specs in random order to surface order dependencies. If you find an
|
20
|
+
# order dependency and want to debug it, you can fix the order by providing
|
21
|
+
# the seed, which is printed after each run.
|
22
|
+
# --seed 1234
|
23
|
+
config.order = 'random'
|
24
|
+
end
|
25
|
+
|
26
|
+
VCR.configure do |c|
|
27
|
+
c.cassette_library_dir = 'spec/vcr_cassettes'
|
28
|
+
c.hook_into :webmock # or :fakeweb
|
29
|
+
c.ignore_hosts 'codeclimate.com'
|
30
|
+
end
|