brownie 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/Gemfile.lock +10 -7
- data/README.markdown +11 -2
- data/VERSION +1 -1
- data/brownie.gemspec +9 -6
- data/lib/brownie/common.rb +25 -0
- data/lib/brownie/package.rb +64 -0
- data/lib/brownie/ship_from.rb +32 -1
- data/lib/brownie/ship_to.rb +29 -0
- data/lib/brownie/shipment.rb +98 -0
- data/lib/brownie/shipper.rb +33 -0
- data/lib/brownie.rb +22 -162
- data/xml/ship_confirm.xml +6 -3
- metadata +10 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5272fa1331a8f96bfbb00999011a2434a37339f7
|
4
|
+
data.tar.gz: 640b647d7426a7b7c4c3f918badff18029e551bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 30875b266eef846deb71d47104a2afbedfd38c26c6afe355e58da5403d549f183f969cad03fdbe6660e1d90c0cafcbdc95a3442feb930fd0ab9bc99c587c1403
|
7
|
+
data.tar.gz: 888e25e2689fec4c31f8e557459802ae3881906d5802389c66a4060fb7766f88ca0a85f2c8ca8e06972875fac1cd533593e2043c74358879a21cabb3832bf612
|
data/Gemfile
CHANGED
@@ -7,7 +7,7 @@ gem "rest_client", ">= 1.7"
|
|
7
7
|
# Add dependencies to develop your gem here.
|
8
8
|
# Include everything needed to run rake, tests, features, etc.
|
9
9
|
group :development do
|
10
|
-
gem "
|
10
|
+
gem "rspec", "~> 2.8.0"
|
11
11
|
gem "rdoc", "~> 3.12"
|
12
12
|
gem "bundler", "~> 1.0"
|
13
13
|
gem "jeweler", "~> 2.0.1"
|
data/Gemfile.lock
CHANGED
@@ -12,6 +12,7 @@ GEM
|
|
12
12
|
builder (3.2.2)
|
13
13
|
descendants_tracker (0.0.4)
|
14
14
|
thread_safe (~> 0.3, >= 0.3.1)
|
15
|
+
diff-lcs (1.1.3)
|
15
16
|
docile (1.1.3)
|
16
17
|
faraday (0.9.0)
|
17
18
|
multipart-post (>= 1.2, < 3)
|
@@ -59,12 +60,14 @@ GEM
|
|
59
60
|
json (~> 1.4)
|
60
61
|
rest_client (1.7.3)
|
61
62
|
netrc (~> 0.7.7)
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
63
|
+
rspec (2.8.0)
|
64
|
+
rspec-core (~> 2.8.0)
|
65
|
+
rspec-expectations (~> 2.8.0)
|
66
|
+
rspec-mocks (~> 2.8.0)
|
67
|
+
rspec-core (2.8.0)
|
68
|
+
rspec-expectations (2.8.0)
|
69
|
+
diff-lcs (~> 1.1.2)
|
70
|
+
rspec-mocks (2.8.0)
|
68
71
|
simplecov (0.8.2)
|
69
72
|
docile (~> 1.1.0)
|
70
73
|
multi_json
|
@@ -83,5 +86,5 @@ DEPENDENCIES
|
|
83
86
|
jeweler (~> 2.0.1)
|
84
87
|
rdoc (~> 3.12)
|
85
88
|
rest_client (>= 1.7)
|
86
|
-
|
89
|
+
rspec (~> 2.8.0)
|
87
90
|
simplecov
|
data/README.markdown
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# brownie
|
2
2
|
|
3
|
-
Brownie helps you create shipments via UPS.com's developer api. You can create shipments, and labels.
|
3
|
+
Brownie helps you create shipments via UPS.com's developer api. This gem is a work in progress. You can create shipments, and labels.
|
4
4
|
|
5
5
|
Future releasess will have address valdation, and tracking
|
6
6
|
|
7
7
|
## Install
|
8
|
-
gem 'brownie', '~> 0.1.
|
8
|
+
gem 'brownie', '~> 0.1.1'
|
9
9
|
|
10
10
|
|
11
11
|
## Usage
|
@@ -48,6 +48,8 @@ Future releasess will have address valdation, and tracking
|
|
48
48
|
b.package_type = Brownie::Package::BOX
|
49
49
|
b.declared_value = 100
|
50
50
|
|
51
|
+
b.environment = "production" # defaulted to development
|
52
|
+
|
51
53
|
# Confirm and Validate Shipment
|
52
54
|
if b.confirm
|
53
55
|
puts b.tracking_number
|
@@ -60,6 +62,13 @@ Future releasess will have address valdation, and tracking
|
|
60
62
|
b.label(b.shipment_digest,"/path/to/save/label.gif")
|
61
63
|
|
62
64
|
|
65
|
+
## TODO
|
66
|
+
|
67
|
+
* Spruce up Shipping class so population of xml fields is cleaner
|
68
|
+
* Add addresss validation
|
69
|
+
* Run rspec tests on shipping confirmation and shipping acceptance.
|
70
|
+
* Add more local validations and error checking
|
71
|
+
|
63
72
|
|
64
73
|
|
65
74
|
## Contributing to brownie
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/brownie.gemspec
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: brownie 0.
|
5
|
+
# stub: brownie 0.2.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "brownie"
|
9
|
-
s.version = "0.
|
9
|
+
s.version = "0.2.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.authors = ["Michael Jaffe"]
|
13
|
-
s.date = "2014-
|
13
|
+
s.date = "2014-04-18"
|
14
14
|
s.description = "Creates UPS shipments and labels via UPS.com's developer api."
|
15
15
|
s.email = "mike@mikewritescode.com"
|
16
16
|
s.extra_rdoc_files = [
|
@@ -27,9 +27,12 @@ Gem::Specification.new do |s|
|
|
27
27
|
"VERSION",
|
28
28
|
"brownie.gemspec",
|
29
29
|
"lib/brownie.rb",
|
30
|
+
"lib/brownie/common.rb",
|
30
31
|
"lib/brownie/credentials.rb",
|
32
|
+
"lib/brownie/package.rb",
|
31
33
|
"lib/brownie/ship_from.rb",
|
32
34
|
"lib/brownie/ship_to.rb",
|
35
|
+
"lib/brownie/shipment.rb",
|
33
36
|
"lib/brownie/shipper.rb",
|
34
37
|
"test/helper.rb",
|
35
38
|
"test/test_brownie.rb",
|
@@ -47,7 +50,7 @@ Gem::Specification.new do |s|
|
|
47
50
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
48
51
|
s.add_runtime_dependency(%q<activesupport>, [">= 3.2.2"])
|
49
52
|
s.add_runtime_dependency(%q<rest_client>, [">= 1.7"])
|
50
|
-
s.add_development_dependency(%q<
|
53
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
|
51
54
|
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
52
55
|
s.add_development_dependency(%q<bundler>, ["~> 1.0"])
|
53
56
|
s.add_development_dependency(%q<jeweler>, ["~> 2.0.1"])
|
@@ -55,7 +58,7 @@ Gem::Specification.new do |s|
|
|
55
58
|
else
|
56
59
|
s.add_dependency(%q<activesupport>, [">= 3.2.2"])
|
57
60
|
s.add_dependency(%q<rest_client>, [">= 1.7"])
|
58
|
-
s.add_dependency(%q<
|
61
|
+
s.add_dependency(%q<rspec>, ["~> 2.8.0"])
|
59
62
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
60
63
|
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
61
64
|
s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
|
@@ -64,7 +67,7 @@ Gem::Specification.new do |s|
|
|
64
67
|
else
|
65
68
|
s.add_dependency(%q<activesupport>, [">= 3.2.2"])
|
66
69
|
s.add_dependency(%q<rest_client>, [">= 1.7"])
|
67
|
-
s.add_dependency(%q<
|
70
|
+
s.add_dependency(%q<rspec>, ["~> 2.8.0"])
|
68
71
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
69
72
|
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
70
73
|
s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Brownie
|
2
|
+
class Common
|
3
|
+
def self.domain
|
4
|
+
staging = "wwwcie.ups.com"
|
5
|
+
production = "onlinetools.ups.com"
|
6
|
+
return staging if ENV["RAILS_ENV"]
|
7
|
+
|
8
|
+
if self.environment.nil?
|
9
|
+
staging
|
10
|
+
elsif self.environment == "production"
|
11
|
+
production
|
12
|
+
else
|
13
|
+
staging
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.template_to_hash(template,root="ShipmentConfirmRequest")
|
18
|
+
xml_path = File.join(File.dirname(File.expand_path(__FILE__)), "../../xml/#{template}.xml")
|
19
|
+
digest_xml_file = File.open(xml_path, "rb")
|
20
|
+
xml = digest_xml_file.read
|
21
|
+
hash = Hash.from_xml(xml)
|
22
|
+
hash[root]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Brownie
|
2
|
+
class Package
|
3
|
+
|
4
|
+
LETTER = "01"
|
5
|
+
CUSTOMER_SUPPLIED_PACKAGE = "02"
|
6
|
+
TUBE = "03"
|
7
|
+
PAK = "04"
|
8
|
+
UPS_EXPRESS_BOX = "21"
|
9
|
+
UPS_25KG_BOX = "24"
|
10
|
+
UPS_10KG_BOX = "25"
|
11
|
+
PALLET = "30"
|
12
|
+
SMALL_EXPRESS_BOX = "2a"
|
13
|
+
MEDIUM_EXPRESS_BOX = "2b"
|
14
|
+
LARGE_EXPRESS_BOX = "2c"
|
15
|
+
FLATS = "56"
|
16
|
+
PARCELS = "57"
|
17
|
+
BPM = "58"
|
18
|
+
FIRST_CLASS = "59"
|
19
|
+
PRIORITY = "60"
|
20
|
+
MACHINABLES = "61"
|
21
|
+
IRREGULARS = "62"
|
22
|
+
PARCEL_POST = "63"
|
23
|
+
BPM_PARCEL = "64"
|
24
|
+
MEDIA_MAIL = "65"
|
25
|
+
BPM_FLAT = "66"
|
26
|
+
STANDARD_FLAT = "67"
|
27
|
+
|
28
|
+
|
29
|
+
attr_accessor :package_type,:unit_of_measurement,:length,:width,:height,:weight,:declared_value
|
30
|
+
|
31
|
+
|
32
|
+
def create
|
33
|
+
data = Hash.from_xml(template)["Package"]
|
34
|
+
data["PackagingType"]["Code"] = self.package_type
|
35
|
+
data["PackageServiceOptions"]["InsuredValue"]["MonetaryValue"] = self.declared_value.to_s
|
36
|
+
data["PackageWeight"]["Weight"] = self.weight.nil? ? 1.0.to_s : self.weight.to_s
|
37
|
+
data["Dimensions"]["UnitOfMeasurement"]["Code"] = self.unit_of_measurement
|
38
|
+
data["Dimensions"]["Length"] = self.length
|
39
|
+
data["Dimensions"]["Width"] = self.width
|
40
|
+
data["Dimensions"]["Height"] = self.height
|
41
|
+
return data
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def template
|
46
|
+
'<Package>
|
47
|
+
<PackagingType>
|
48
|
+
<Code></Code>
|
49
|
+
</PackagingType>
|
50
|
+
<Dimensions>
|
51
|
+
<UnitOfMeasurement> <Code></Code> </UnitOfMeasurement>
|
52
|
+
<Length></Length> <Width></Width> <Height></Height>
|
53
|
+
</Dimensions>
|
54
|
+
<PackageWeight>
|
55
|
+
<Weight></Weight>
|
56
|
+
</PackageWeight>
|
57
|
+
<PackageServiceOptions>
|
58
|
+
<InsuredValue> <MonetaryValue></MonetaryValue>
|
59
|
+
</InsuredValue>
|
60
|
+
</PackageServiceOptions>
|
61
|
+
</Package>'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/brownie/ship_from.rb
CHANGED
@@ -1,8 +1,39 @@
|
|
1
1
|
module Brownie
|
2
|
-
class ShipFrom
|
2
|
+
class ShipFrom
|
3
3
|
attr_accessor :company_name,:attention_name,:phone_number,:attention_name,:address_line1,:address_line2,:city,:state_province_code,:postal_code,:country_code
|
4
4
|
|
5
5
|
|
6
|
+
def create
|
7
|
+
data = Hash.from_xml(template)["ShipFrom"]
|
8
|
+
data["CompanyName"] = self.company_name
|
9
|
+
data["AttentionName"] = self.attention_name
|
10
|
+
data["PhoneNumber"] = self.phone_number
|
11
|
+
data["AttentionName"] = self.attention_name
|
12
|
+
data["Address"]["AddressLine1"] = self.address_line1
|
13
|
+
data["Address"]["AddressLine2"] = self.address_line2 if !self.address_line2.nil?
|
14
|
+
data["Address"]["City"] = self.city
|
15
|
+
data["Address"]["StateProvinceCode"] = self.state_province_code
|
16
|
+
data["Address"]["PostalCode"] = self.postal_code
|
17
|
+
data["Address"]["CountryCode"] = self.country_code
|
18
|
+
return data
|
19
|
+
end
|
6
20
|
|
21
|
+
private
|
22
|
+
def template
|
23
|
+
'<ShipFrom>
|
24
|
+
<CompanyName></CompanyName>
|
25
|
+
<AttentionName></AttentionName>
|
26
|
+
<PhoneNumber></PhoneNumber>
|
27
|
+
<TaxIdentificationNumber></TaxIdentificationNumber>
|
28
|
+
<Address>
|
29
|
+
<AddressLine1></AddressLine1>
|
30
|
+
<City></City>
|
31
|
+
<StateProvinceCode></StateProvinceCode>
|
32
|
+
<PostalCode></PostalCode>
|
33
|
+
<CountryCode></CountryCode>
|
34
|
+
</Address>
|
35
|
+
</ShipFrom>'
|
36
|
+
end
|
7
37
|
end
|
38
|
+
|
8
39
|
end
|
data/lib/brownie/ship_to.rb
CHANGED
@@ -2,6 +2,35 @@ module Brownie
|
|
2
2
|
class ShipTo
|
3
3
|
attr_accessor :company_name,:attention_name,:phone_number,:attention_name,:address_line1,:address_line2,:city,:state_province_code,:postal_code,:country_code
|
4
4
|
|
5
|
+
def create
|
6
|
+
data = Hash.from_xml(template)["ShipTo"]
|
7
|
+
data["CompanyName"] = self.company_name
|
8
|
+
data["AttentionName"] = self.attention_name
|
9
|
+
data["PhoneNumber"] = self.phone_number
|
10
|
+
data["AttentionName"] = self.attention_name
|
11
|
+
data["Address"]["AddressLine1"] = self.address_line1
|
12
|
+
data["Address"]["AddressLine2"] = self.address_line2 if !self.address_line2.nil?
|
13
|
+
data["Address"]["City"] = self.city
|
14
|
+
data["Address"]["StateProvinceCode"] = self.state_province_code
|
15
|
+
data["Address"]["PostalCode"] = self.postal_code
|
16
|
+
data["Address"]["CountryCode"] = self.country_code
|
17
|
+
return data
|
18
|
+
end
|
5
19
|
|
20
|
+
private
|
21
|
+
def template
|
22
|
+
'<ShipTo>
|
23
|
+
<CompanyName></CompanyName>
|
24
|
+
<AttentionName></AttentionName>
|
25
|
+
<PhoneNumber></PhoneNumber>
|
26
|
+
<Address>
|
27
|
+
<AddressLine1></AddressLine1>
|
28
|
+
<City></City>
|
29
|
+
<StateProvinceCode></StateProvinceCode>
|
30
|
+
<PostalCode></PostalCode>
|
31
|
+
<CountryCode></CountryCode>
|
32
|
+
</Address>
|
33
|
+
</ShipTo>'
|
34
|
+
end
|
6
35
|
end
|
7
36
|
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'active_support/all'
|
2
|
+
require 'rest_client'
|
3
|
+
module Brownie
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
class Shipment
|
8
|
+
attr_accessor :request,:errors,:account_number,:tracking_number,:shipment_digest,:credentials,:shipper,:ship_to,
|
9
|
+
:ship_from,:response,:service_code,:label_binary,:api_domain,
|
10
|
+
:environment,:data,:shipment_xml,:template,:package
|
11
|
+
|
12
|
+
|
13
|
+
def initialize(shipment=nil)
|
14
|
+
self.shipment_data = shipment if !shipment.nil?
|
15
|
+
self.credentials = Credentials.new
|
16
|
+
self.shipper = Shipper.new
|
17
|
+
self.ship_to = ShipTo.new
|
18
|
+
self.ship_from = ShipFrom.new
|
19
|
+
self.package = Package.new
|
20
|
+
self.template = Common::template_to_hash(:ship_confirm)
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
def confirm
|
27
|
+
|
28
|
+
data = self.template["Shipment"]
|
29
|
+
data["PaymentInformation"]["Prepaid"]["BillShipper"]["AccountNumber"] = self.account_number
|
30
|
+
data["Service"]["Code"] = self.service_code
|
31
|
+
data["Package"] = self.package.create
|
32
|
+
data["Shipper"] = self.shipper.create
|
33
|
+
data["ShipTo"] = self.ship_to.create
|
34
|
+
data["ShipFrom"] = self.ship_from.create
|
35
|
+
|
36
|
+
self.template["Shipment"] = data
|
37
|
+
request_template = {"ShipmentConfirmRequest" => self.template}
|
38
|
+
shipment_xml_str = request_template["ShipmentConfirmRequest"].to_xml(:root => "ShipmentConfirmRequest")
|
39
|
+
|
40
|
+
self.response = RestClient.post("https://#{Common::domain}/ups.app/xml/ShipConfirm","#{access_request_header}#{shipment_xml_str}")
|
41
|
+
if self.response.code.eql?(200)
|
42
|
+
response_hash = Hash.from_xml(response)
|
43
|
+
if response_hash["ShipmentConfirmResponse"]["Response"]["ResponseStatusCode"].eql?("0")
|
44
|
+
self.errors = response_hash["ShipmentConfirmResponse"]["Response"]["Error"]
|
45
|
+
return false
|
46
|
+
end
|
47
|
+
|
48
|
+
self.tracking_number = response_hash["ShipmentConfirmResponse"]["ShipmentIdentificationNumber"]
|
49
|
+
self.shipment_digest = response_hash["ShipmentConfirmResponse"]["ShipmentDigest"]
|
50
|
+
return true
|
51
|
+
|
52
|
+
else
|
53
|
+
raise "In-valid request #{response}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def label(_shipment_digest,path)
|
58
|
+
shipment_digest = _shipment_digest.nil? ? @shipment_digest : _shipment_digest
|
59
|
+
label_xml = '<?xml version="1.0" encoding="ISO-8859-1"?>
|
60
|
+
<ShipmentAcceptRequest>
|
61
|
+
<Request>
|
62
|
+
<TransactionReference>
|
63
|
+
<CustomerContext></CustomerContext>
|
64
|
+
</TransactionReference>
|
65
|
+
<RequestAction>ShipAccept</RequestAction>
|
66
|
+
<RequestOption>1</RequestOption>
|
67
|
+
</Request>
|
68
|
+
<ShipmentDigest>' + shipment_digest + '</ShipmentDigest>
|
69
|
+
</ShipmentAcceptRequest>'
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
label_response = RestClient.post("https://#{Common::domain}/ups.app/xml/ShipAccept","#{access_request_header}#{label_xml}")
|
75
|
+
label_hash = Hash.from_xml(label_response)
|
76
|
+
self.label_binary = label_hash["ShipmentAcceptResponse"]["ShipmentResults"]["PackageResults"]["LabelImage"]["GraphicImage"]
|
77
|
+
File.open(path, 'wb') do|f|
|
78
|
+
f.write(Base64.decode64(self.label_binary))
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
private
|
85
|
+
def access_request_header
|
86
|
+
'<?xml version="1.0"?>
|
87
|
+
<AccessRequest xml:lang="en-US">
|
88
|
+
<AccessLicenseNumber>' + self.credentials.license_number + '</AccessLicenseNumber>
|
89
|
+
<UserId>' + self.credentials.user_id + '</UserId>
|
90
|
+
<Password>' + self.credentials.password + '</Password>
|
91
|
+
</AccessRequest>'
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
end
|
data/lib/brownie/shipper.rb
CHANGED
@@ -5,5 +5,38 @@ module Brownie
|
|
5
5
|
:address_line1,:address_line2,:city,:state_province_code,:postal_code,:country_code
|
6
6
|
|
7
7
|
|
8
|
+
|
9
|
+
def create
|
10
|
+
data = Hash.from_xml(template)["Shipper"]
|
11
|
+
data["Name"] = self.name
|
12
|
+
data["PhoneNumber"] = self.phone_number
|
13
|
+
data["ShipperNumber"] = self.account_number
|
14
|
+
data["TaxIdentificationNumber"] = self.tax_identification_number
|
15
|
+
data["Address"]["AddressLine1"] = self.address_line1
|
16
|
+
data["Address"]["AddressLine2"] = self.address_line2 if !self.address_line2.nil?
|
17
|
+
data["Address"]["City"] = self.city
|
18
|
+
data["Address"]["StateProvinceCode"] = self.state_province_code
|
19
|
+
data["Address"]["PostalCode"] = self.postal_code
|
20
|
+
data["Address"]["CountryCode"] = self.country_code
|
21
|
+
return data
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def template
|
26
|
+
' <Shipper>
|
27
|
+
<Name></Name>
|
28
|
+
<PhoneNumber></PhoneNumber>
|
29
|
+
<ShipperNumber></ShipperNumber>
|
30
|
+
<TaxIdentificationNumber></TaxIdentificationNumber>
|
31
|
+
<Address>
|
32
|
+
<AddressLine1></AddressLine1>
|
33
|
+
<City></City>
|
34
|
+
<StateProvinceCode></StateProvinceCode>
|
35
|
+
<PostalCode></PostalCode>
|
36
|
+
<PostcodeExtendedLow />
|
37
|
+
<CountryCode></CountryCode>
|
38
|
+
</Address>
|
39
|
+
</Shipper>'
|
40
|
+
end
|
8
41
|
end
|
9
42
|
end
|
data/lib/brownie.rb
CHANGED
@@ -1,180 +1,40 @@
|
|
1
1
|
require 'active_support/all'
|
2
2
|
require 'rest_client'
|
3
|
+
require 'brownie/common'
|
3
4
|
require 'brownie/credentials'
|
4
5
|
require 'brownie/shipper'
|
5
6
|
require 'brownie/ship_to'
|
6
7
|
require 'brownie/ship_from'
|
8
|
+
require 'brownie/package'
|
9
|
+
require 'brownie/shipment'
|
7
10
|
module Brownie
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
class Shipment
|
12
|
-
attr_accessor :request,:errors,:account_number,:tracking_number,:shipment_digest,:credentials,:shipper,:ship_to,
|
13
|
-
:ship_from,:response,:service_code,:package_type,:declared_value,:package_weight,:label_binary,:api_domain,:environment
|
14
|
-
|
15
|
-
attr_writer :shipment_data,:shipment_xml
|
16
|
-
|
17
11
|
|
18
|
-
def initialize(shipment=nil)
|
19
|
-
self.shipment_data = shipment if !shipment.nil?
|
20
|
-
self.credentials = Credentials.new
|
21
|
-
self.shipper = Shipper.new
|
22
|
-
self.ship_to = ShipTo.new
|
23
|
-
self.ship_from = ShipFrom.new
|
24
|
-
|
25
|
-
end
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
def confirm
|
30
|
-
test = template_hash
|
31
|
-
shipment = test["ShipmentConfirmRequest"]["Shipment"]
|
32
|
-
|
33
|
-
shipment["PaymentInformation"]["Prepaid"]["BillShipper"]["AccountNumber"] = self.account_number
|
34
|
-
shipment["Service"]["Code"] = self.service_code
|
35
|
-
shipment["Package"]["PackagingType"]["Code"] = self.package_type
|
36
|
-
shipment["Package"]["PackageServiceOptions"]["InsuredValue"]["MonetaryValue"] = self.declared_value.to_s
|
37
|
-
shipment["Package"]["PackageWeight"]["Weight"] = self.package_weight.nil? ? 1.0.to_s : self.package_weight.to_s
|
38
|
-
|
39
|
-
shipment["Shipper"]["Name"] = self.shipper.name
|
40
|
-
shipment["Shipper"]["PhoneNumber"] = self.shipper.phone_number
|
41
|
-
shipment["Shipper"]["ShipperNumber"] = self.account_number
|
42
|
-
shipment["Shipper"]["TaxIdentificationNumber"] = self.shipper.tax_identification_number
|
43
|
-
shipment["Shipper"]["Address"]["AddressLine1"] = self.shipper.address_line1
|
44
|
-
shipment["Shipper"]["Address"]["AddressLine2"] = self.shipper.address_line2 if !self.shipper.address_line2.nil?
|
45
|
-
shipment["Shipper"]["Address"]["City"] = self.shipper.city
|
46
|
-
shipment["Shipper"]["Address"]["StateProvinceCode"] = self.shipper.state_province_code
|
47
|
-
shipment["Shipper"]["Address"]["PostalCode"] = self.shipper.postal_code
|
48
|
-
shipment["Shipper"]["Address"]["CountryCode"] = self.shipper.country_code
|
49
|
-
|
50
|
-
|
51
|
-
shipto = shipment["ShipTo"]
|
52
|
-
shipto["CompanyName"] = self.ship_to.company_name
|
53
|
-
shipto["AttentionName"] = self.ship_to.attention_name
|
54
|
-
shipto["PhoneNumber"] = self.ship_to.phone_number
|
55
|
-
shipto["AttentionName"] = self.ship_to.attention_name
|
56
|
-
shipto["Address"]["AddressLine1"] = self.ship_to.address_line1
|
57
|
-
shipto["Address"]["AddressLine2"] = self.ship_to.address_line2 if !self.ship_to.address_line2.nil?
|
58
|
-
shipto["Address"]["City"] = self.ship_to.city
|
59
|
-
shipto["Address"]["StateProvinceCode"] = self.ship_to.state_province_code
|
60
|
-
shipto["Address"]["PostalCode"] = self.ship_to.postal_code
|
61
|
-
shipto["Address"]["CountryCode"] = self.ship_to.country_code
|
62
|
-
|
63
|
-
|
64
|
-
shipfrom = shipment["ShipFrom"]
|
65
|
-
shipfrom["CompanyName"] = self.ship_from.company_name
|
66
|
-
shipfrom["AttentionName"] = self.ship_from.attention_name
|
67
|
-
shipfrom["PhoneNumber"] = self.ship_from.phone_number
|
68
|
-
shipfrom["AttentionName"] = self.ship_from.attention_name
|
69
|
-
shipfrom["Address"]["AddressLine1"] = self.ship_from.address_line1
|
70
|
-
shipfrom["Address"]["AddressLine2"] = self.ship_from.address_line2 if !self.ship_from.address_line2.nil?
|
71
|
-
shipfrom["Address"]["City"] = self.ship_from.city
|
72
|
-
shipfrom["Address"]["StateProvinceCode"] = self.ship_from.state_province_code
|
73
|
-
shipfrom["Address"]["PostalCode"] = self.ship_from.postal_code
|
74
|
-
shipfrom["Address"]["CountryCode"] = self.ship_from.country_code
|
75
|
-
|
76
|
-
|
77
|
-
shipment_xml_str = test["ShipmentConfirmRequest"].to_xml(:root => "ShipmentConfirmRequest")
|
78
|
-
|
79
|
-
self.response = RestClient.post("https://#{domain}/ups.app/xml/ShipConfirm","#{access_request_header}#{shipment_xml_str}")
|
80
|
-
if self.response.code.eql?(200)
|
81
|
-
response_hash = Hash.from_xml(response)
|
82
|
-
if response_hash["ShipmentConfirmResponse"]["Response"]["ResponseStatusCode"].eql?("0")
|
83
|
-
self.errors = response_hash["ShipmentConfirmResponse"]["Response"]["Error"]
|
84
|
-
return false
|
85
|
-
end
|
86
|
-
|
87
|
-
self.tracking_number = response_hash["ShipmentConfirmResponse"]["ShipmentIdentificationNumber"]
|
88
|
-
self.shipment_digest = response_hash["ShipmentConfirmResponse"]["ShipmentDigest"]
|
89
|
-
return true
|
90
|
-
|
91
|
-
else
|
92
|
-
raise "In-valid request #{response}"
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
def label(_shipment_digest,path)
|
97
|
-
shipment_digest = _shipment_digest.nil? ? @shipment_digest : _shipment_digest
|
98
|
-
label_xml = '<?xml version="1.0" encoding="ISO-8859-1"?>
|
99
|
-
<ShipmentAcceptRequest>
|
100
|
-
<Request>
|
101
|
-
<TransactionReference>
|
102
|
-
<CustomerContext></CustomerContext>
|
103
|
-
</TransactionReference>
|
104
|
-
<RequestAction>ShipAccept</RequestAction>
|
105
|
-
<RequestOption>1</RequestOption>
|
106
|
-
</Request>
|
107
|
-
<ShipmentDigest>' + shipment_digest + '</ShipmentDigest>
|
108
|
-
</ShipmentAcceptRequest>'
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
label_response = RestClient.post("https://#{domain}/ups.app/xml/ShipAccept","#{access_request_header}#{label_xml}")
|
114
|
-
label_hash = Hash.from_xml(label_response)
|
115
|
-
self.label_binary = label_hash["ShipmentAcceptResponse"]["ShipmentResults"]["PackageResults"]["LabelImage"]["GraphicImage"]
|
116
|
-
File.open(path, 'wb') do|f|
|
117
|
-
f.write(Base64.decode64(self.label_binary))
|
118
|
-
end
|
119
|
-
|
120
|
-
end
|
121
|
-
|
122
|
-
|
123
|
-
private
|
124
|
-
def domain
|
125
|
-
if self.environment.nil?
|
126
|
-
"wwwcie.ups.com"
|
127
|
-
elsif self.environment == "production"
|
128
|
-
"onlinetools.ups.com"
|
129
|
-
else
|
130
|
-
"wwwcie.ups.com"
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
def template_hash
|
135
|
-
xml_path = File.join(File.dirname(File.expand_path(__FILE__)), "../xml/ship_confirm.xml")
|
136
|
-
digest_xml_file = File.open(xml_path, "rb")
|
137
|
-
@shipment_xml = digest_xml_file.read
|
138
|
-
Hash.from_xml(@shipment_xml)
|
139
|
-
end
|
140
|
-
|
141
|
-
def access_request_header
|
142
|
-
'<?xml version="1.0"?>
|
143
|
-
<AccessRequest xml:lang="en-US">
|
144
|
-
<AccessLicenseNumber>' + self.credentials.license_number + '</AccessLicenseNumber>
|
145
|
-
<UserId>' + self.credentials.user_id + '</UserId>
|
146
|
-
<Password>' + self.credentials.password + '</Password>
|
147
|
-
</AccessRequest>'
|
148
|
-
end
|
149
12
|
|
13
|
+
class Dimensions
|
14
|
+
INCHES = "IN"
|
15
|
+
CENTIMETERS = "CM"
|
16
|
+
METRIC_UNITS_OF_MEASUREMENT = "00"
|
17
|
+
ENGLISH_UNITS_OF_MEASUREMENT = "01"
|
150
18
|
end
|
151
19
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
CRATE = "04"
|
158
|
-
DRUM = "05"
|
159
|
-
PALLET = "06"
|
160
|
-
ROLL = "07"
|
161
|
-
TUBE = "08"
|
20
|
+
class Weight
|
21
|
+
POUNDS = "LBS"
|
22
|
+
KILOGRAMS = "KGS"
|
23
|
+
METRIC_UNITS_OF_MEASUREMENT = "00"
|
24
|
+
ENGLISH_UNITS_OF_MEASUREMENT = "01"
|
162
25
|
end
|
163
26
|
|
164
27
|
class ServiceCodes
|
165
|
-
|
28
|
+
NEXT_DAY_AIR = "01"
|
29
|
+
SECOND_DAY_AIR = "02"
|
166
30
|
GROUND = "03"
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
WORLDWIDEEXPRESSPLUS = "54"
|
175
|
-
UPSWORDWIDESAVER = "65"
|
176
|
-
UPSWORLDWIDEEXPEDITED = "08"
|
177
|
-
|
31
|
+
EXPRESS = "07"
|
32
|
+
Expedited = "08"
|
33
|
+
Ups_Standard = "11"
|
34
|
+
THREE_DAY_SELECT = "12"
|
35
|
+
NEXT_DAY_AIR_SAVER = "13"
|
36
|
+
NEXT_DAY_AIR_EARLY_AM = "14"
|
37
|
+
EXPRESS_PLUS = "54"
|
178
38
|
end
|
179
39
|
|
180
40
|
|
data/xml/ship_confirm.xml
CHANGED
@@ -77,10 +77,13 @@
|
|
77
77
|
<PackagingType>
|
78
78
|
<Code></Code>
|
79
79
|
</PackagingType>
|
80
|
+
<Dimensions>
|
81
|
+
<UnitOfMeasurement> <Code></Code> </UnitOfMeasurement>
|
82
|
+
<Length></Length> <Width></Width> <Height></Height>
|
83
|
+
</Dimensions>
|
80
84
|
<PackageWeight>
|
81
|
-
|
82
|
-
</PackageWeight>
|
83
|
-
|
85
|
+
<Weight></Weight>
|
86
|
+
</PackageWeight>
|
84
87
|
<PackageServiceOptions>
|
85
88
|
<InsuredValue> <MonetaryValue></MonetaryValue>
|
86
89
|
</InsuredValue>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: brownie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Jaffe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-04-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -39,19 +39,19 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.7'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ~>
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 2.8.0
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: 2.8.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rdoc
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -125,9 +125,12 @@ files:
|
|
125
125
|
- VERSION
|
126
126
|
- brownie.gemspec
|
127
127
|
- lib/brownie.rb
|
128
|
+
- lib/brownie/common.rb
|
128
129
|
- lib/brownie/credentials.rb
|
130
|
+
- lib/brownie/package.rb
|
129
131
|
- lib/brownie/ship_from.rb
|
130
132
|
- lib/brownie/ship_to.rb
|
133
|
+
- lib/brownie/shipment.rb
|
131
134
|
- lib/brownie/shipper.rb
|
132
135
|
- test/helper.rb
|
133
136
|
- test/test_brownie.rb
|