shipping-calc 0.1.2 → 0.1.3
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/History.txt +13 -0
- data/Manifest.txt +2 -1
- data/README.markdown +88 -0
- data/examples/fq_example.rb +1 -0
- data/lib/shipping_calc.rb +1 -1
- data/lib/shipping_calc/freight_quote.rb +112 -33
- data/test/freight_quote/freight_quote_test.rb +48 -1
- metadata +5 -4
data/History.txt
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
=== 0.1.3 / 2008-03-17
|
2
|
+
|
3
|
+
* FreightQuote support improved
|
4
|
+
|
5
|
+
Now you can query FQ's API with information for:
|
6
|
+
|
7
|
+
* Liftgates
|
8
|
+
* Loading docks
|
9
|
+
* Different types of shipping and receiving locations
|
10
|
+
* Inside deliveries
|
11
|
+
|
12
|
+
* Minor bugfixes
|
13
|
+
|
1
14
|
=== 0.1.2
|
2
15
|
|
3
16
|
* Freight quote now supports FQ's classes. With this the shipment's
|
data/Manifest.txt
CHANGED
data/README.markdown
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
ShippingCalc
|
2
|
+
============
|
3
|
+
|
4
|
+
* http://github.com/febuiles/shipping_calc/
|
5
|
+
* mailto:federico.builes@gmail.com
|
6
|
+
|
7
|
+
DESCRIPTION:
|
8
|
+
-----------
|
9
|
+
|
10
|
+
Shipping Calculator written in Ruby to get quick quotes from the major
|
11
|
+
carriers (UPS, DHL, FedEX, FreightQuote).
|
12
|
+
|
13
|
+
FEATURES/PROBLEMS:
|
14
|
+
-----------------
|
15
|
+
- Current version only supports DHL and FreightQuote
|
16
|
+
|
17
|
+
SYNOPSIS:
|
18
|
+
--------
|
19
|
+
You can find an example of each carrier's API under the /examples directory.
|
20
|
+
|
21
|
+
A simple DHL example:
|
22
|
+
|
23
|
+
require 'rubygems'
|
24
|
+
require 'shipping_calc'
|
25
|
+
|
26
|
+
include ShippingCalc
|
27
|
+
|
28
|
+
opts = {
|
29
|
+
:api_user => "your_user",
|
30
|
+
:api_password => "your_pwd",
|
31
|
+
:shipping_key => "your_key",
|
32
|
+
:account_num => "your_accnt",
|
33
|
+
:date => Time.now, # or something...
|
34
|
+
:service_code => "E", # check the docs to find out what this means
|
35
|
+
:shipment_code => "P", # check the docs to find out what this means
|
36
|
+
:weight => 34, # weight in lbs
|
37
|
+
:to_zip => 10001,
|
38
|
+
:to_state => "NY"
|
39
|
+
}
|
40
|
+
|
41
|
+
d = DHL.new
|
42
|
+
a = d.quote(opts)
|
43
|
+
p a
|
44
|
+
|
45
|
+
REQUIREMENTS:
|
46
|
+
---------------
|
47
|
+
* You must obtain all the DHL ShipIt data (user, password, key and account) from http://www.dhl-usa.com/TechTools/detail/TTDetail.asp?nav=TechnologyTools/Shipping/OwnSoln
|
48
|
+
* REXML
|
49
|
+
|
50
|
+
INSTALL:
|
51
|
+
-------
|
52
|
+
* sudo gem install shipping-calc
|
53
|
+
|
54
|
+
TEST:
|
55
|
+
-----
|
56
|
+
To run the DHL tests you'll need to have a .dhl_info.yml file in your home directory with your auth info like this:
|
57
|
+
~/.dhl_info.yml
|
58
|
+
|
59
|
+
api_user: your_user
|
60
|
+
api_password: your_password
|
61
|
+
shipping_key: your_key
|
62
|
+
account_num: your_accnt_num
|
63
|
+
|
64
|
+
This is necessary only for the tests and it'll be ignored for the actual
|
65
|
+
usage of the the library.
|
66
|
+
|
67
|
+
LICENSE:
|
68
|
+
-------
|
69
|
+
Copyright (c) 2008 Federico Builes
|
70
|
+
|
71
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
72
|
+
a copy of this software and associated documentation files (the
|
73
|
+
'Software'), to deal in the Software without restriction, including
|
74
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
75
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
76
|
+
permit persons to whom the Software is furnished to do so, subject to
|
77
|
+
the following conditions:
|
78
|
+
|
79
|
+
The above copyright notice and this permission notice shall be
|
80
|
+
included in all copies or substantial portions of the Software.
|
81
|
+
|
82
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
83
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
84
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
85
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
86
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
87
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
88
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/examples/fq_example.rb
CHANGED
data/lib/shipping_calc.rb
CHANGED
@@ -32,7 +32,7 @@ require 'shipping_calc/freight_quote'
|
|
32
32
|
module ShippingCalc
|
33
33
|
class ShippingCalcError < StandardError
|
34
34
|
end
|
35
|
-
VERSION = "0.1.
|
35
|
+
VERSION = "0.1.3"
|
36
36
|
|
37
37
|
US_STATES = ['AK', 'AL', 'AR', 'AZ', 'CA', 'CO', 'CT', 'DC',
|
38
38
|
'DE', 'FL', 'GA', 'HI', 'IA', 'ID', 'IL', 'IN',
|
@@ -49,28 +49,19 @@ module ShippingCalc
|
|
49
49
|
# :*from_zip*:: Sender's zip code.
|
50
50
|
# :*to_zip*:: Recipient's zip code.
|
51
51
|
# :*weight*:: Total weight of the order in lbs.
|
52
|
-
# :*dimensions*::
|
53
|
-
# :*description*::
|
54
|
-
# :*class*::
|
55
|
-
#
|
56
|
-
#
|
52
|
+
# :*dimensions*:: _Optional_ - Length, width and height of the shipment, described as a string: "[Length]x[Width]x[Height]" (e.g. "23x32x15").
|
53
|
+
# :*description*:: _Optional_ - Description of the stuff that's being shipped. Defaults to "NODESC".
|
54
|
+
# :*class*:: _Optional_ - Freightquote's shipping class. Defaults to nil.
|
55
|
+
# :*from_conditions*:: _Optional_ - String that indicates if the sending location is a residence ("RES"), a business with a forklift or dock ("BIZ_WITH") or a business without a forklift or dock ("BIZ_WITHOUT"). Defaults to "RES".
|
56
|
+
# :*to_conditions*:: _Optional_ - String that indicates if the receiving location is a residence ("RES"), a business with a forklift or dock ("BIZ_WITH") or a business without a forklift or dock ("BIZ_WITHOUT"). Defaults to "RES".
|
57
|
+
# :*liftgate*:: _Optional_ - A boolean indicating if a liftgate's required at the receiving location (API page 10). Defaults to false.
|
58
|
+
# :*inside_delivery*:: _Optional_ - A boolean indicating if inside delivery's required at the receiving location (API page 10). Defaults to false.
|
59
|
+
# *Note* Both dimensions or class are optional but one of them has to be there. If both parameters are filled then priority will be given to class.
|
57
60
|
def quote(params)
|
58
|
-
|
59
|
-
:weight]
|
60
|
-
|
61
|
-
raise ShippingCalcError.new("Nil parameters for FreightQuote quote.") if params.nil?
|
62
|
-
raise ShippingCalcError.new("Invalid shipment dimensions") unless
|
63
|
-
((params[:dimensions] =~ /\d+x\d+x\d+/) || (!params[:class].nil?))
|
64
|
-
|
65
|
-
required_fields.each do |f|
|
66
|
-
if params.has_key?(f) && !params[f].nil? # Cover all the mandatory fields
|
67
|
-
next
|
68
|
-
else
|
69
|
-
raise ShippingCalcError.new("Required field \"#{f}\" not found.")
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
61
|
+
validate params
|
73
62
|
params[:description] ||= "NODESC"
|
63
|
+
params[:from_conditions] ||= "RES"
|
64
|
+
params[:to_conditions] ||= "RES"
|
74
65
|
|
75
66
|
@xml = xml = Document.new
|
76
67
|
xml << XMLDecl.new("1.0' encoding='UTF-8")
|
@@ -89,19 +80,9 @@ module ShippingCalc
|
|
89
80
|
# We're only getting a quote, let's pretend the shipper's paying.
|
90
81
|
root.attributes["BILLTO"] = "SHIPPER"
|
91
82
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
origin << orig_zip
|
97
|
-
root << origin
|
98
|
-
|
99
|
-
dest = Element.new("DESTINATION")
|
100
|
-
dest_zip = Element.new("ZIPCODE")
|
101
|
-
dest_zip.text = params[:from_zip]
|
102
|
-
|
103
|
-
dest << dest_zip
|
104
|
-
root << dest
|
83
|
+
root << destination(params[:from_zip], params[:from_conditions],
|
84
|
+
params[:liftgate], params[:inside_delivery])
|
85
|
+
root << origin(params[:from_zip], params[:from_conditions])
|
105
86
|
|
106
87
|
root << shipment_item(params[:weight], params[:dimensions],
|
107
88
|
params[:description], params[:class])
|
@@ -131,6 +112,67 @@ module ShippingCalc
|
|
131
112
|
quotes
|
132
113
|
end
|
133
114
|
|
115
|
+
# TODO Merge this method with destination's.
|
116
|
+
def origin (zip, conditions)
|
117
|
+
origin = Element.new("ORIGIN")
|
118
|
+
orig_zip = Element.new("ZIPCODE")
|
119
|
+
orig_zip.text = zip
|
120
|
+
origin << orig_zip
|
121
|
+
|
122
|
+
case conditions
|
123
|
+
when "RES"
|
124
|
+
residence = Element.new("RESIDENCE")
|
125
|
+
residence.text = "TRUE"
|
126
|
+
origin << residence
|
127
|
+
when "BIZ_WITH"
|
128
|
+
dock = Element.new("LOADINGDOCK")
|
129
|
+
dock.text = "TRUE"
|
130
|
+
origin << dock
|
131
|
+
when "BIZ_WITHOUT"
|
132
|
+
dock = Element.new("LOADINGDOCK")
|
133
|
+
dock.text = "FALSE"
|
134
|
+
origin << dock
|
135
|
+
end
|
136
|
+
|
137
|
+
origin
|
138
|
+
end
|
139
|
+
|
140
|
+
def destination(zip, conditions, liftgate, inside)
|
141
|
+
dest = Element.new("DESTINATION")
|
142
|
+
dest_zip = Element.new("ZIPCODE")
|
143
|
+
dest_zip.text = zip
|
144
|
+
dest << dest_zip
|
145
|
+
|
146
|
+
case conditions
|
147
|
+
when "RES"
|
148
|
+
residence = Element.new("RESIDENCE")
|
149
|
+
residence.text = "TRUE"
|
150
|
+
dest << residence
|
151
|
+
when "BIZ_WITH"
|
152
|
+
dock = Element.new("LOADINGDOCK")
|
153
|
+
dock.text = "TRUE"
|
154
|
+
dest << dock
|
155
|
+
when "BIZ_WITHOUT"
|
156
|
+
dock = Element.new("LOADINGDOCK")
|
157
|
+
dock.text = "FALSE"
|
158
|
+
dest << dock
|
159
|
+
end
|
160
|
+
|
161
|
+
if !liftgate.nil? && liftgate
|
162
|
+
liftgate = Element.new("LIFTGATEDELIVERY")
|
163
|
+
liftgate.text = "TRUE"
|
164
|
+
dest << liftgate
|
165
|
+
end
|
166
|
+
|
167
|
+
if !inside.nil? && inside
|
168
|
+
inside = Element.new("INSIDEDELIVERY")
|
169
|
+
inside.text = "TRUE"
|
170
|
+
dest << inside
|
171
|
+
end
|
172
|
+
|
173
|
+
dest
|
174
|
+
end
|
175
|
+
|
134
176
|
# Create a shipment item based on the weight, dimension and description.
|
135
177
|
def shipment_item(weight_, dim, desc, s_class = nil)
|
136
178
|
raise ShippingCalcError.new("Invalid weight") if !(weight_ > 0)
|
@@ -169,5 +211,42 @@ module ShippingCalc
|
|
169
211
|
|
170
212
|
shipment
|
171
213
|
end
|
214
|
+
|
215
|
+
def validate(params)
|
216
|
+
required_fields = [:api_email, :api_password, :to_zip, :from_zip,
|
217
|
+
:weight]
|
218
|
+
|
219
|
+
raise ShippingCalcError.new("Nil parameters for FreightQuote quote.") if params.nil?
|
220
|
+
raise ShippingCalcError.new("Invalid shipment dimensions") unless
|
221
|
+
((params[:dimensions] =~ /\d+x\d+x\d+/) || (!params[:class].nil?))
|
222
|
+
|
223
|
+
raise ShippingCalcError.new("Invalid receiving conditions") unless
|
224
|
+
valid_conditions(params[:to_conditions])
|
225
|
+
raise ShippingCalcError.new("Invalid shipping conditions") unless
|
226
|
+
valid_conditions(params[:from_conditions])
|
227
|
+
|
228
|
+
if !(params[:liftgate].nil?)
|
229
|
+
raise ShippingCalcError.new("Invalid liftgate option, only boolean values.") unless
|
230
|
+
(params[:liftgate].class == TrueClass || params[:liftgate].class == FalseClass)
|
231
|
+
end
|
232
|
+
|
233
|
+
if !(params[:inside_delivery].nil?)
|
234
|
+
raise ShippingCalcError.new("Invalid inside delivery option, only boolean values.") unless
|
235
|
+
(params[:inside_delivery].class == TrueClass || params[:inside_delivery].class == FalseClass)
|
236
|
+
end
|
237
|
+
|
238
|
+
required_fields.each do |f|
|
239
|
+
if params.has_key?(f) && !params[f].nil? # Cover all the mandatory fields
|
240
|
+
next
|
241
|
+
else
|
242
|
+
raise ShippingCalcError.new("Required field \"#{f}\" not found.")
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
247
|
+
|
248
|
+
def valid_conditions(cond)
|
249
|
+
cond.nil? || ((cond =~ /^(BIZ_WITH|RES|BIZ_WITHOUT)$/) == 0)
|
250
|
+
end
|
172
251
|
end
|
173
252
|
end
|
@@ -14,7 +14,6 @@ class FreightQuoteTest < Test::Unit::TestCase
|
|
14
14
|
:weight => 150,
|
15
15
|
:dimensions => "12x23x12"
|
16
16
|
}
|
17
|
-
|
18
17
|
end
|
19
18
|
|
20
19
|
def test_invalid_params
|
@@ -32,6 +31,54 @@ class FreightQuoteTest < Test::Unit::TestCase
|
|
32
31
|
assert q.size > 0
|
33
32
|
end
|
34
33
|
|
34
|
+
def test_quote_with_conditions
|
35
|
+
@opts[:to_conditions] = "BIZ_WITH"
|
36
|
+
@opts[:from_conditions] = "BIZ_WITHOUT"
|
37
|
+
f = FreightQuote.new
|
38
|
+
q = f.quote(@opts)
|
39
|
+
assert q.size > 0
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_invalid_conditions
|
43
|
+
@opts[:to_conditions] = "BIZ_WITH"
|
44
|
+
@opts[:from_conditions] = "something weird goes here"
|
45
|
+
f = FreightQuote.new
|
46
|
+
assert_raise ShippingCalcError do
|
47
|
+
f.quote(@opts)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_with_liftgate_and_inside_delivery
|
52
|
+
@opts[:inside_delivery] = false
|
53
|
+
@opts[:liftgate] = true
|
54
|
+
f = FreightQuote.new
|
55
|
+
q = f.quote(@opts)
|
56
|
+
assert q.size > 0
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_invalid_liftgate
|
60
|
+
@opts[:liftgate] = "something"
|
61
|
+
f = FreightQuote.new
|
62
|
+
assert_raise ShippingCalcError do
|
63
|
+
f.quote(@opts)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_invalid_inside_delivery
|
68
|
+
@opts[:inside_delivery] = 3
|
69
|
+
f = FreightQuote.new
|
70
|
+
assert_raise ShippingCalcError do
|
71
|
+
f.quote(@opts)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_quote_with_class_and_dimensions
|
76
|
+
@opts[:class] = 92.5
|
77
|
+
f = FreightQuote.new
|
78
|
+
q = f.quote(@opts)
|
79
|
+
assert q.size > 0
|
80
|
+
end
|
81
|
+
|
35
82
|
def test_invalid_dimension
|
36
83
|
@opts[:dimensions] = "12x3"
|
37
84
|
f = FreightQuote.new
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shipping-calc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Federico Builes
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-03-
|
12
|
+
date: 2008-03-17 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -29,13 +29,14 @@ executables: []
|
|
29
29
|
extensions: []
|
30
30
|
|
31
31
|
extra_rdoc_files:
|
32
|
+
- README.txt
|
32
33
|
- History.txt
|
33
34
|
- Manifest.txt
|
34
|
-
- README.txt
|
35
35
|
files:
|
36
|
+
- README.txt
|
36
37
|
- History.txt
|
37
38
|
- Manifest.txt
|
38
|
-
- README.
|
39
|
+
- README.markdown
|
39
40
|
- Rakefile
|
40
41
|
- lib/shipping_calc.rb
|
41
42
|
- lib/shipping_calc/dhl.rb
|