sendcloud-ruby 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![wercker status](https://app.wercker.com/status/03866f33222cc05a0e18eb2aac723f5c/m "wercker status")](https://app.wercker.com/project/bykey/03866f33222cc05a0e18eb2aac723f5c)
|
6
|
+
[![Gem Version](https://badge.fury.io/rb/sendcloud.svg)](http://badge.fury.io/rb/sendcloud)
|
7
|
+
[![Code Climate](https://codeclimate.com/github/pero-ict-solutions/sendcloud/badges/gpa.svg)](https://codeclimate.com/github/pero-ict-solutions/sendcloud)
|
8
|
+
[![Test Coverage](https://codeclimate.com/github/pero-ict-solutions/sendcloud/badges/coverage.svg)](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
|