ups_shipping 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.
- data/lib/ups_shipping.rb +190 -0
- data/lib/ups_shipping/address.rb +39 -0
- data/lib/ups_shipping/organization.rb +39 -0
- data/lib/ups_shipping/package.rb +45 -0
- data/lib/ups_shipping/pickup.rb +49 -0
- data/spec/ups_shipping_spec.rb +42 -0
- metadata +84 -0
data/lib/ups_shipping.rb
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
require "httparty"
|
3
|
+
require 'ups_shipping/address'
|
4
|
+
require 'ups_shipping/organization'
|
5
|
+
require 'ups_shipping/package'
|
6
|
+
require 'ups_shipping/pickup'
|
7
|
+
|
8
|
+
module Shipping
|
9
|
+
|
10
|
+
VERSION = '1.0.0'
|
11
|
+
|
12
|
+
class UPS
|
13
|
+
|
14
|
+
TEST_URL = "https://wwwcie.ups.com"
|
15
|
+
LIVE_URL = "https://onlinetools.ups.com"
|
16
|
+
|
17
|
+
class Http
|
18
|
+
include HTTParty
|
19
|
+
base_uri LIVE_URL
|
20
|
+
|
21
|
+
def initialize(access_request, options={})
|
22
|
+
@access_request = access_request
|
23
|
+
|
24
|
+
if (options[:test])
|
25
|
+
self.class.base_uri TEST_URL
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def commit(url, request)
|
30
|
+
request = @access_request + request
|
31
|
+
self.class.post(url, :body => request).parsed_response
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(user, password, license, options={})
|
36
|
+
@options = options
|
37
|
+
@shipper = options[:shipper]
|
38
|
+
@access_request = access_request(user, password, license)
|
39
|
+
@http = Http.new(@access_request, :test => @options[:test])
|
40
|
+
|
41
|
+
@services = {
|
42
|
+
"01" => "Next Day Air",
|
43
|
+
"02" => "2nd Day Air",
|
44
|
+
"03" => "Ground",
|
45
|
+
"07" => "Express",
|
46
|
+
"08" => "Expedited",
|
47
|
+
"11" => "UPS Standard",
|
48
|
+
"12" => "3 Day Select",
|
49
|
+
"13" => "Next Day Air Saver",
|
50
|
+
"14" => "Next Day Air Early AM",
|
51
|
+
"54" => "Express Plus",
|
52
|
+
"59" => "2nd Day Air A.M.",
|
53
|
+
"65" => "UPS Saver",
|
54
|
+
"82" => "UPS Today Standard",
|
55
|
+
"83" => "UPS Today Dedicated Courier",
|
56
|
+
"84" => "UPS Today Intercity",
|
57
|
+
"85" => "UPS Today Express",
|
58
|
+
"86" => "UPS Today Express Saver"
|
59
|
+
}
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
def validate_address(address)
|
64
|
+
validate_request = Nokogiri::XML::Builder.new do |xml|
|
65
|
+
xml.AddressValidationRequest {
|
66
|
+
xml.Request {
|
67
|
+
xml.RequestAction "XAV"
|
68
|
+
xml.RequestOption "3"
|
69
|
+
}
|
70
|
+
xml.AddressKeyFormat {
|
71
|
+
xml.AddressLine address.address_line[0]
|
72
|
+
xml.PoliticalDivision2 address.city
|
73
|
+
xml.PoliticalDivision1 address.state
|
74
|
+
xml.PostcodePrimaryLow address.zip
|
75
|
+
xml.CountryCode address.country
|
76
|
+
}
|
77
|
+
}
|
78
|
+
end
|
79
|
+
@http.commit("/ups.app/xml/XAV", validate_request.to_xml)
|
80
|
+
end
|
81
|
+
|
82
|
+
def find_rates(package, origin, destination, options={})
|
83
|
+
rate_request = Nokogiri::XML::Builder.new do |xml|
|
84
|
+
xml.RatingServiceSelectionRequest {
|
85
|
+
xml.Request {
|
86
|
+
xml.RequestAction "Rate"
|
87
|
+
xml.RequestOption "Rate"
|
88
|
+
}
|
89
|
+
if options[:pickup]
|
90
|
+
@options[:pickup].build_type(xml)
|
91
|
+
end
|
92
|
+
@shipper.build(xml, "Shipper")
|
93
|
+
destination.build(xml, "ShipTo")
|
94
|
+
origin.build(xml, "ShipFrom")
|
95
|
+
xml.PaymentInformation {
|
96
|
+
xml.Prepaid {
|
97
|
+
xml.BillShipper {
|
98
|
+
xml.AccountNumber "Ship Number"
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
package.build(xml)
|
103
|
+
}
|
104
|
+
end
|
105
|
+
@http.commit("/ups.app/xml/Rate", rate_request.to_xml)
|
106
|
+
end
|
107
|
+
|
108
|
+
def request_shipment(package, origin, destination, service, options={})
|
109
|
+
shipment_request = Nokogiri::XML::Builder.new do |xml|
|
110
|
+
xml.ShipmentConfirmRequest {
|
111
|
+
xml.Request {
|
112
|
+
xml.RequestAction "ShipConfirm"
|
113
|
+
xml.RequestOptions "validate"
|
114
|
+
}
|
115
|
+
if options[:label]
|
116
|
+
xml.LabelSpecification {
|
117
|
+
xml.LabelPrintMethod {
|
118
|
+
xml.Code "GIF"
|
119
|
+
xml.Description "gif file"
|
120
|
+
}
|
121
|
+
xml.HTTPUserAgent "Mozilla/4.5"
|
122
|
+
xml.LabelImageFormat {
|
123
|
+
xml.Code "GIF"
|
124
|
+
xml.Description "gif"
|
125
|
+
}
|
126
|
+
}
|
127
|
+
end
|
128
|
+
@shipper.build(xml, "Shipper")
|
129
|
+
destination.build(xml, "ShipTo")
|
130
|
+
origin.build(xml, "ShipFrom")
|
131
|
+
xml.PaymentInformation {
|
132
|
+
xml.Prepaid {
|
133
|
+
xml.BillShipper {
|
134
|
+
xml.AccountNumber "Ship Number"
|
135
|
+
}
|
136
|
+
}
|
137
|
+
}
|
138
|
+
xml.Service {
|
139
|
+
xml.Code service
|
140
|
+
xml.Description @services[service]
|
141
|
+
}
|
142
|
+
package.build(xml)
|
143
|
+
}
|
144
|
+
end
|
145
|
+
@http.commit("/ups.app/xml/ShipConfirm", shipment_request.to_xml)
|
146
|
+
end
|
147
|
+
|
148
|
+
def cancel_shipment(shipment_id)
|
149
|
+
cancel_request = Nokogiri::XML::Builder.new do |xml|
|
150
|
+
xml.VoidShipmentRequest {
|
151
|
+
xml.Request {
|
152
|
+
xml.RequestAction "1"
|
153
|
+
xml.RequestOption "1"
|
154
|
+
}
|
155
|
+
xml.ShipmentIdentificationNumber shipment_id
|
156
|
+
}
|
157
|
+
end
|
158
|
+
@http.commit("/ups.app/xml/Void", cancel_request.to_xml)
|
159
|
+
end
|
160
|
+
|
161
|
+
def track_shipment(tracking_number)
|
162
|
+
track_request = Nokogiri::XML::Builder.new do
|
163
|
+
TrackRequest {
|
164
|
+
Request {
|
165
|
+
RequestAction "Track"
|
166
|
+
RequestOption "activity"
|
167
|
+
}
|
168
|
+
TrackingNumber tracking_number
|
169
|
+
}
|
170
|
+
end
|
171
|
+
|
172
|
+
@http.commit("/ups.app/xml/Track", track_request.to_xml)
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
private
|
177
|
+
def access_request(user, password, license)
|
178
|
+
access_request = Nokogiri::XML::Builder.new do
|
179
|
+
AccessRequest {
|
180
|
+
AccessLicenseNumber license
|
181
|
+
UserId user
|
182
|
+
Password password
|
183
|
+
}
|
184
|
+
end
|
185
|
+
|
186
|
+
access_request.to_xml
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
|
3
|
+
module Shipping
|
4
|
+
class Address
|
5
|
+
ADDRESS_TYPES = %w{residential commercial po_box}
|
6
|
+
attr_accessor :address_lines
|
7
|
+
:city
|
8
|
+
:state
|
9
|
+
:zip
|
10
|
+
:country
|
11
|
+
:type
|
12
|
+
|
13
|
+
def initialize(options={})
|
14
|
+
@address_lines = options[:address_lines]
|
15
|
+
@city = options[:city]
|
16
|
+
@state = options[:state]
|
17
|
+
@zip = options[:zip]
|
18
|
+
@country = options[:country]
|
19
|
+
@type = options[:type]
|
20
|
+
end
|
21
|
+
|
22
|
+
def build(xml)
|
23
|
+
xml.Address {
|
24
|
+
xml.AddressLine1 @address_lines[0]
|
25
|
+
xml.City @city
|
26
|
+
xml.StateProvinceCode @state
|
27
|
+
xml.PostalCode @zip
|
28
|
+
xml.CountryCode @country
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_xml()
|
33
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
34
|
+
build(xml)
|
35
|
+
end
|
36
|
+
builder.to_xml
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
|
3
|
+
module Shipping
|
4
|
+
class Organization
|
5
|
+
attr_accessor :name
|
6
|
+
:phone
|
7
|
+
:email
|
8
|
+
:address
|
9
|
+
:shipper_number
|
10
|
+
|
11
|
+
|
12
|
+
def initialize(options={})
|
13
|
+
@name = options[:name]
|
14
|
+
@phone = options[:phone]
|
15
|
+
@address = options[:address]
|
16
|
+
if options[:shipper_number]
|
17
|
+
@shipper_number = options[:shipper_number]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def build(xml, rootname)
|
22
|
+
xml.send(rootname) {
|
23
|
+
xml.CompanyName @name
|
24
|
+
xml.PhoneNumber @phone
|
25
|
+
if @shipper_number
|
26
|
+
xml.ShipperNumber @shipper_number
|
27
|
+
end
|
28
|
+
@address.build(xml)
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_xml(rootname)
|
33
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
34
|
+
build(xml, rootname)
|
35
|
+
end
|
36
|
+
builder.to_xml
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
|
3
|
+
module Shipping
|
4
|
+
class Package
|
5
|
+
attr_accessor :large
|
6
|
+
:weight
|
7
|
+
:description
|
8
|
+
:monetary_value
|
9
|
+
|
10
|
+
def initialize(options={})
|
11
|
+
@large = options[:large]
|
12
|
+
@weight = options[:weight]
|
13
|
+
@description = options[:description]
|
14
|
+
@monetary_value = options[:monetary_value]
|
15
|
+
end
|
16
|
+
|
17
|
+
def build(xml)
|
18
|
+
xml.Package {
|
19
|
+
xml.PackagingType {
|
20
|
+
xml.Code "02"
|
21
|
+
xml.Description "Customer Supplied"
|
22
|
+
}
|
23
|
+
xml.Description @description
|
24
|
+
xml.ReferenceNumber {
|
25
|
+
xml.Code "00"
|
26
|
+
xml.Value "Package"
|
27
|
+
}
|
28
|
+
xml.PackageWeight {
|
29
|
+
xml.UnitOfMeasurement
|
30
|
+
xml.Weight @weight
|
31
|
+
}
|
32
|
+
if @large
|
33
|
+
xml.LargePackageIndicator
|
34
|
+
end
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_xml()
|
39
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
40
|
+
build(xml)
|
41
|
+
end
|
42
|
+
builder.to_xml
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
|
3
|
+
module Shipping
|
4
|
+
class Pickup
|
5
|
+
attr_accessor :address_lines
|
6
|
+
:pickup_day
|
7
|
+
:contact_method
|
8
|
+
:type
|
9
|
+
|
10
|
+
def initialize(options={})
|
11
|
+
@type = options[:type]
|
12
|
+
if options[:pickup_day]
|
13
|
+
@pickup_day = options[:pickup_day]
|
14
|
+
end
|
15
|
+
if options[:contact_method]
|
16
|
+
@contact_method = options[:contact_method]
|
17
|
+
end
|
18
|
+
|
19
|
+
@pickupTypes = {
|
20
|
+
"01" => "Daily Pickup",
|
21
|
+
"03" => "Customer Counter",
|
22
|
+
"06" => "One Time Pickup",
|
23
|
+
"07" => "On Call Air",
|
24
|
+
"19" => "Letter Center",
|
25
|
+
"20" => "Air Service Center"
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def build_schedule(xml)
|
30
|
+
xml.OnCallAir {
|
31
|
+
xml.Schedule {
|
32
|
+
if @pickup_day
|
33
|
+
xml.PickupDay @pickup_day
|
34
|
+
end
|
35
|
+
if @contact_method
|
36
|
+
xml.Method @contact_method
|
37
|
+
end
|
38
|
+
}
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def build_type(xml)
|
43
|
+
xml.PickupType {
|
44
|
+
xml.Code type
|
45
|
+
xml.Description @pickupTypes[type]
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "rspec"
|
2
|
+
require "ups_shipping"
|
3
|
+
require "address"
|
4
|
+
require "organization"
|
5
|
+
|
6
|
+
describe Shipping::UPS do
|
7
|
+
before(:all) do
|
8
|
+
@ups = Shipping::UPS.new("deanchen", "Transcriptic#1", "EC96D31A8D672E28", :test => true)
|
9
|
+
@address = Shipping::Address.new(
|
10
|
+
:address_lines => ["1402 Faber St."],
|
11
|
+
:city => "Durham",
|
12
|
+
:state => "NC",
|
13
|
+
:zip => "27705",
|
14
|
+
:country => "US"
|
15
|
+
)
|
16
|
+
end
|
17
|
+
it "address object" do
|
18
|
+
@address.to_xml.gsub(/^\s+/, "").gsub(/\s+$/, $/).should == '
|
19
|
+
<?xml version="1.0"?>
|
20
|
+
<Address>
|
21
|
+
<AddressLine1>1402 Faber St.</AddressLine1>
|
22
|
+
<City>Durham</City>
|
23
|
+
<StateProvinceCode>NC</StateProvinceCode>
|
24
|
+
<PostalCode>27705</PostalCode>
|
25
|
+
<CountryCode>US</CountryCode>
|
26
|
+
</Address>
|
27
|
+
'.gsub(/^\s+/, "").gsub(/\s+$/, $/)
|
28
|
+
end
|
29
|
+
it "organization object" do
|
30
|
+
@organization = Shipping::Organization.new(
|
31
|
+
:name => "Transcriptic",
|
32
|
+
:phone => "1233455678",
|
33
|
+
:address => @address
|
34
|
+
)
|
35
|
+
puts @organization.to_xml("Shipper")
|
36
|
+
end
|
37
|
+
it "#track_shipment" do
|
38
|
+
tracking_result = @ups.track_shipment("1ZXX31290231000092")
|
39
|
+
tracking_result.should have_key("TrackResponse")
|
40
|
+
tracking_result["TrackResponse"]["Response"]["ResponseStatusCode"].should == "1"
|
41
|
+
end
|
42
|
+
end
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ups_shipping
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Transcriptic, Inc
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-04 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: nokogiri
|
16
|
+
requirement: &70314021897160 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70314021897160
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec
|
27
|
+
requirement: &70314021896740 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70314021896740
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: httparty
|
38
|
+
requirement: &70314021896320 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70314021896320
|
47
|
+
description: UPS shipping gem for integrating UPS's API into a Ruby script.
|
48
|
+
email: team@transcriptic.com
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- lib/ups_shipping.rb
|
54
|
+
- lib/ups_shipping/address.rb
|
55
|
+
- lib/ups_shipping/organization.rb
|
56
|
+
- lib/ups_shipping/package.rb
|
57
|
+
- lib/ups_shipping/pickup.rb
|
58
|
+
- spec/ups_shipping_spec.rb
|
59
|
+
homepage: http://www.github.com/transcriptic/ups-shipping
|
60
|
+
licenses: []
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 1.8.6
|
80
|
+
signing_key:
|
81
|
+
specification_version: 3
|
82
|
+
summary: UPS shipping API integration.
|
83
|
+
test_files: []
|
84
|
+
has_rdoc:
|