shipping-calc 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -1,6 +1,7 @@
1
+ README.txt
1
2
  History.txt
2
3
  Manifest.txt
3
- README.txt
4
+ README.markdown
4
5
  Rakefile
5
6
  lib/shipping_calc.rb
6
7
  lib/shipping_calc/dhl.rb
@@ -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.
@@ -10,6 +10,7 @@ opts = {
10
10
  :to_zip => 33166,
11
11
  :weight => 5,
12
12
  :dimensions => "1x1x1"
13
+ :to_conditions => "BIZ_WITHOUT"
13
14
  }
14
15
 
15
16
  f = FreightQuote.new
@@ -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.2"
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*:: 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 - Freight quote class. Defaults to nil.
55
- #
56
- # *Note* Both dimensions or class are optional but one of them has to be there. If both parameters are filled then priority will be give to class.
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
- required_fields = [:api_email, :api_password, :to_zip, :from_zip,
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
- origin = Element.new("ORIGIN")
93
- orig_zip = Element.new("ZIPCODE")
94
- orig_zip.text = params[:to_zip]
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.2
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-16 00:00:00 -05:00
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.txt
39
+ - README.markdown
39
40
  - Rakefile
40
41
  - lib/shipping_calc.rb
41
42
  - lib/shipping_calc/dhl.rb