shipping 1.2.1 → 1.3.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/Rakefile +158 -3
- data/lib/shipping.rb +3 -0
- data/lib/shipping/base.rb +4 -2
- data/lib/shipping/fedex.rb +207 -82
- data/test/fedex/fedex_test.rb +4 -3
- data/test/ups/ups_test.rb +1 -1
- metadata +2 -2
data/Rakefile
CHANGED
@@ -4,8 +4,14 @@ require 'rake/testtask'
|
|
4
4
|
require 'rake/rdoctask'
|
5
5
|
require 'rake/gempackagetask'
|
6
6
|
require 'rake/contrib/rubyforgepublisher'
|
7
|
+
require File.dirname(__FILE__) + '/lib/shipping'
|
7
8
|
|
8
|
-
PKG_VERSION =
|
9
|
+
PKG_VERSION = Shipping::VERSION
|
10
|
+
PKG_NAME = "shipping"
|
11
|
+
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
12
|
+
RUBY_FORGE_PROJECT = "shipping"
|
13
|
+
RUBY_FORGE_USER = ENV['RUBY_FORGE_USER'] || "cardmagic"
|
14
|
+
RELEASE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
9
15
|
|
10
16
|
PKG_FILES = FileList[
|
11
17
|
"lib/**/*", "bin/*", "test/**/*", "[A-Z]*", "Rakefile", "doc/**/*"
|
@@ -90,7 +96,156 @@ end
|
|
90
96
|
|
91
97
|
desc "Publish new documentation"
|
92
98
|
task :publish do
|
93
|
-
`ssh rufy update-shipping-doc`
|
94
|
-
`scp pkg/shipping-1.0.0.* rufy:www/shipping.rufy.com/docs/`
|
95
99
|
Rake::RubyForgePublisher.new('shipping', 'cardmagic').upload
|
100
|
+
`ssh rufy update-shipping-doc`
|
101
|
+
end
|
102
|
+
|
103
|
+
desc "Publish the release files to RubyForge."
|
104
|
+
task :upload => [:package] do
|
105
|
+
files = ["gem", "tgz", "zip"].map { |ext| "pkg/#{PKG_FILE_NAME}.#{ext}" }
|
106
|
+
|
107
|
+
if RUBY_FORGE_PROJECT then
|
108
|
+
require 'net/http'
|
109
|
+
require 'open-uri'
|
110
|
+
|
111
|
+
project_uri = "http://rubyforge.org/projects/#{RUBY_FORGE_PROJECT}/"
|
112
|
+
project_data = open(project_uri) { |data| data.read }
|
113
|
+
group_id = project_data[/[?&]group_id=(\d+)/, 1]
|
114
|
+
raise "Couldn't get group id" unless group_id
|
115
|
+
|
116
|
+
# This echos password to shell which is a bit sucky
|
117
|
+
if ENV["RUBY_FORGE_PASSWORD"]
|
118
|
+
password = ENV["RUBY_FORGE_PASSWORD"]
|
119
|
+
else
|
120
|
+
password = Proc.new do
|
121
|
+
sync = STDOUT.sync
|
122
|
+
begin
|
123
|
+
echo false
|
124
|
+
STDOUT.sync = true
|
125
|
+
print "#{RUBY_FORGE_USER}@rubyforge.org's password: "
|
126
|
+
STDIN.gets.chomp
|
127
|
+
ensure
|
128
|
+
echo true
|
129
|
+
STDOUT.sync = sync
|
130
|
+
puts
|
131
|
+
end
|
132
|
+
end.call
|
133
|
+
end
|
134
|
+
|
135
|
+
login_response = Net::HTTP.start("rubyforge.org", 80) do |http|
|
136
|
+
data = [
|
137
|
+
"login=1",
|
138
|
+
"form_loginname=#{RUBY_FORGE_USER}",
|
139
|
+
"form_pw=#{password}"
|
140
|
+
].join("&")
|
141
|
+
http.post("/account/login.php", data)
|
142
|
+
end
|
143
|
+
|
144
|
+
cookie = login_response["set-cookie"]
|
145
|
+
raise "Login failed" unless cookie
|
146
|
+
headers = { "Cookie" => cookie }
|
147
|
+
|
148
|
+
release_uri = "http://rubyforge.org/frs/admin/?group_id=#{group_id}"
|
149
|
+
release_data = open(release_uri, headers) { |data| data.read }
|
150
|
+
package_id = release_data[/[?&]package_id=(\d+)/, 1]
|
151
|
+
raise "Couldn't get package id" unless package_id
|
152
|
+
|
153
|
+
first_file = true
|
154
|
+
release_id = ""
|
155
|
+
|
156
|
+
files.each do |filename|
|
157
|
+
basename = File.basename(filename)
|
158
|
+
file_ext = File.extname(filename)
|
159
|
+
file_data = File.open(filename, "rb") { |file| file.read }
|
160
|
+
|
161
|
+
puts "Releasing #{basename}..."
|
162
|
+
|
163
|
+
release_response = Net::HTTP.start("rubyforge.org", 80) do |http|
|
164
|
+
release_date = Time.now.strftime("%Y-%m-%d %H:%M")
|
165
|
+
type_map = {
|
166
|
+
".zip" => "3000",
|
167
|
+
".tgz" => "3110",
|
168
|
+
".gz" => "3110",
|
169
|
+
".gem" => "1400"
|
170
|
+
}; type_map.default = "9999"
|
171
|
+
type = type_map[file_ext]
|
172
|
+
boundary = "rubyqMY6QN9bp6e4kS21H4y0zxcvoor"
|
173
|
+
|
174
|
+
query_hash = if first_file then
|
175
|
+
{
|
176
|
+
"group_id" => group_id,
|
177
|
+
"package_id" => package_id,
|
178
|
+
"release_name" => RELEASE_NAME,
|
179
|
+
"release_date" => release_date,
|
180
|
+
"type_id" => type,
|
181
|
+
"processor_id" => "8000", # Any
|
182
|
+
"release_notes" => "",
|
183
|
+
"release_changes" => "",
|
184
|
+
"preformatted" => "1",
|
185
|
+
"submit" => "1"
|
186
|
+
}
|
187
|
+
else
|
188
|
+
{
|
189
|
+
"group_id" => group_id,
|
190
|
+
"release_id" => release_id,
|
191
|
+
"package_id" => package_id,
|
192
|
+
"step2" => "1",
|
193
|
+
"type_id" => type,
|
194
|
+
"processor_id" => "8000", # Any
|
195
|
+
"submit" => "Add This File"
|
196
|
+
}
|
197
|
+
end
|
198
|
+
|
199
|
+
query = "?" + query_hash.map do |(name, value)|
|
200
|
+
[name, URI.encode(value)].join("=")
|
201
|
+
end.join("&")
|
202
|
+
|
203
|
+
data = [
|
204
|
+
"--" + boundary,
|
205
|
+
"Content-Disposition: form-data; name=\"userfile\"; filename=\"#{basename}\"",
|
206
|
+
"Content-Type: application/octet-stream",
|
207
|
+
"Content-Transfer-Encoding: binary",
|
208
|
+
"", file_data, ""
|
209
|
+
].join("\x0D\x0A")
|
210
|
+
|
211
|
+
release_headers = headers.merge(
|
212
|
+
"Content-Type" => "multipart/form-data; boundary=#{boundary}"
|
213
|
+
)
|
214
|
+
|
215
|
+
target = first_file ? "/frs/admin/qrs.php" : "/frs/admin/editrelease.php"
|
216
|
+
http.post(target + query, data, release_headers)
|
217
|
+
end
|
218
|
+
|
219
|
+
if first_file then
|
220
|
+
release_id = release_response.body[/release_id=(\d+)/, 1]
|
221
|
+
raise("Couldn't get release id") unless release_id
|
222
|
+
end
|
223
|
+
|
224
|
+
first_file = false
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
begin
|
230
|
+
if !defined?(USE_TERMIOS) || USE_TERMIOS
|
231
|
+
require 'termios'
|
232
|
+
else
|
233
|
+
raise LoadError
|
234
|
+
end
|
235
|
+
|
236
|
+
# Enable or disable stdin echoing to the terminal.
|
237
|
+
def echo(enable)
|
238
|
+
term = Termios::getattr(STDIN)
|
239
|
+
|
240
|
+
if enable
|
241
|
+
term.c_lflag |= (Termios::ECHO | Termios::ICANON)
|
242
|
+
else
|
243
|
+
term.c_lflag &= ~Termios::ECHO
|
244
|
+
end
|
245
|
+
|
246
|
+
Termios::setattr(STDIN, Termios::TCSANOW, term)
|
247
|
+
end
|
248
|
+
rescue LoadError
|
249
|
+
def echo(enable)
|
250
|
+
end
|
96
251
|
end
|
data/lib/shipping.rb
CHANGED
@@ -24,6 +24,8 @@
|
|
24
24
|
# Copyright:: Copyright (c) 2005 Lucas Carlson
|
25
25
|
# License:: LGPL
|
26
26
|
|
27
|
+
$:.unshift(File.dirname(__FILE__))
|
28
|
+
|
27
29
|
begin
|
28
30
|
require 'rubygems'
|
29
31
|
rescue LoadError
|
@@ -35,6 +37,7 @@ require 'yaml'
|
|
35
37
|
require 'rexml/document'
|
36
38
|
require 'net/http'
|
37
39
|
require 'net/https'
|
40
|
+
require 'base64'
|
38
41
|
|
39
42
|
require 'extensions'
|
40
43
|
require 'shipping/base'
|
data/lib/shipping/base.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
# License:: LGPL
|
4
4
|
|
5
5
|
module Shipping
|
6
|
+
VERSION = "1.3.0"
|
7
|
+
|
6
8
|
class ShippingError < StandardError; end
|
7
9
|
|
8
10
|
class Base
|
@@ -11,13 +13,13 @@ module Shipping
|
|
11
13
|
attr_writer :ups_account, :ups_user, :ups_password
|
12
14
|
attr_writer :fedex_account, :fedex_meter, :fedex_url
|
13
15
|
|
14
|
-
attr_accessor :name, :phone, :email, :address, :address2, :city, :state, :zip, :country
|
16
|
+
attr_accessor :name, :phone, :company, :email, :address, :address2, :city, :state, :zip, :country
|
15
17
|
attr_accessor :sender_name, :sender_phone, :sender_email, :sender_address, :sender_city, :sender_state, :sender_zip, :sender_country
|
16
18
|
|
17
19
|
attr_accessor :weight, :weight_units, :insured_value, :declared_value, :transaction_type, :description
|
18
20
|
attr_accessor :package_total, :packaging_type, :service_type
|
19
21
|
|
20
|
-
|
22
|
+
attr_accessor :ship_date, :dropoff_type, :pay_type, :currency_code, :image_type, :label_type
|
21
23
|
|
22
24
|
def initialize(options = {})
|
23
25
|
prefs = File.expand_path(options[:prefs] || "~/.shipping.yml")
|
data/lib/shipping/fedex.rb
CHANGED
@@ -6,22 +6,24 @@
|
|
6
6
|
# See http://www.fedex.com/us/solutions/wis/pdf/xml_transguide.pdf?link=4 for the full XML-based API
|
7
7
|
|
8
8
|
module Shipping
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
9
|
+
class FedEx < Base
|
10
|
+
# Gets the list price the regular consumer would have to pay. Discount price is what the
|
11
|
+
# person with this particular account number will pay
|
12
|
+
def price
|
13
|
+
get_price
|
14
|
+
return REXML::XPath.first(@response, "//FDXRateReply/EstimatedCharges/ListCharges/NetCharge").text.to_f
|
15
|
+
rescue
|
16
|
+
raise ShippingError, get_error
|
17
|
+
end
|
18
|
+
|
19
|
+
# Gets the discount price of the shipping (with discounts taken into consideration).
|
20
|
+
# "base price" doesn't include surcharges like fuel cost, so I don't think it is the correct price to get
|
21
|
+
def discount_price
|
22
|
+
get_price
|
23
|
+
return REXML::XPath.first(@response, "//FDXRateReply/EstimatedCharges/DiscountedCharges/NetCharge").text.to_f
|
24
|
+
rescue
|
25
|
+
raise ShippingError, get_error
|
26
|
+
end
|
25
27
|
|
26
28
|
# still not sure what the best way to handle this transaction's return data would be. Possibly a hash of the form {service => delivery_estimate}?
|
27
29
|
def express_service_availability
|
@@ -84,18 +86,159 @@ module Shipping
|
|
84
86
|
|
85
87
|
return REXML::XPath.first(@response, "//FDXSubscriptionReply/MeterNumber").text
|
86
88
|
end
|
87
|
-
|
89
|
+
|
88
90
|
# require 'fileutils'
|
89
91
|
# fedex = Shipping::FedEx.new :name => 'John Doe', ... , :sender_zip => 97202
|
90
92
|
# label = fedex.label
|
91
|
-
# puts label.url
|
92
93
|
# puts label.tracking_number
|
93
|
-
|
94
|
-
#
|
94
|
+
# FileUtils.cp label.image.path, '/path/to/my/images/directory/'
|
95
|
+
#
|
96
|
+
# There are several types of labels that can be returned by changing @image_type.
|
97
|
+
# PNG is selected by default.
|
95
98
|
#
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
+
def label
|
100
|
+
@required = [:phone, :email, :address, :city, :state, :zip ]
|
101
|
+
@required += [:sender_phone, :sender_email, :sender_address, :sender_city, :sender_state, :sender_zip ]
|
102
|
+
@required += [:fedex_account, :fedex_url]
|
103
|
+
|
104
|
+
@transaction_type ||= 'rate_ground'
|
105
|
+
@weight = (@weight.to_f*10).round/10.0
|
106
|
+
@declared_value = (@declared_value.to_f*100).round/100.0 unless @declared_value.blank?
|
107
|
+
state = STATES.has_value?(@state.downcase) ? STATES.index(@state.downcase).upcase : @state.upcase
|
108
|
+
sender_state = STATES.has_value?(@sender_state.downcase) ? STATES.index(@sender_state.downcase).upcase : @sender_state.upcase
|
109
|
+
|
110
|
+
@data = String.new
|
111
|
+
|
112
|
+
b = Builder::XmlMarkup.new :target => @data
|
113
|
+
b.instruct!
|
114
|
+
b.FDXShipRequest('xmlns:api' => 'http://www.fedex.com/fsmapi', 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xsi:noNamespaceSchemaLocation' => 'FDXShipRequest.xsd') { |b|
|
115
|
+
b.RequestHeader { |b|
|
116
|
+
b.AccountNumber @fedex_account
|
117
|
+
b.MeterNumber @fedex_meter
|
118
|
+
b.CarrierCode TransactionTypes[@transaction_type][1]
|
119
|
+
}
|
120
|
+
b.ShipDate((Time.now).strftime("%Y-%m-%d"))
|
121
|
+
b.ShipTime((Time.now).strftime("%H:%M:%S"))
|
122
|
+
b.DropoffType @dropoff_type || 'REGULARPICKUP'
|
123
|
+
b.Service ServiceTypes[@service_type] || ServiceTypes['ground_service'] # default to ground service
|
124
|
+
b.Packaging PackageTypes[@packaging_type] || 'YOURPACKAGING'
|
125
|
+
b.WeightUnits @weight_units || 'LBS' # or KGS
|
126
|
+
b.Weight @weight
|
127
|
+
b.CurrencyCode @currency_code || 'USD'
|
128
|
+
b.Origin { |b|
|
129
|
+
b.Contact { |b|
|
130
|
+
if @sender_name.to_s.size > 2
|
131
|
+
b.PersonName @sender_name
|
132
|
+
b.CompanyName @sender_company unless @sender_company.blank?
|
133
|
+
elsif @sender_company.to_s.size > 2
|
134
|
+
b.PersonName @sender_name unless @sender_name.blank?
|
135
|
+
b.CompanyName @sender_company
|
136
|
+
else
|
137
|
+
raise ShippingError, "Either the sender_name or the sender_company value must be bigger than 2 characters."
|
138
|
+
end
|
139
|
+
b.Department @sender_department unless @sender_department.blank?
|
140
|
+
b.PhoneNumber @sender_phone.gsub(/[^\d]/,"")
|
141
|
+
b.PagerNumber @sender_pager.gsub(/[^\d]/,"") if @sender_pager.class == String
|
142
|
+
b.FaxNumber @sender_fax.gsub(/[^\d]/,"") if @sender_fax.class == String
|
143
|
+
b.tag! :"E-MailAddress", @sender_email
|
144
|
+
}
|
145
|
+
b.Address { |b|
|
146
|
+
b.Line1 @sender_address
|
147
|
+
b.Line2 @sender_address2 unless @sender_address2.blank?
|
148
|
+
b.City @sender_city
|
149
|
+
b.StateOrProvinceCode sender_state
|
150
|
+
b.PostalCode @sender_zip
|
151
|
+
b.CountryCode @sender_country || 'US'
|
152
|
+
}
|
153
|
+
}
|
154
|
+
b.Destination { |b|
|
155
|
+
b.Contact { |b|
|
156
|
+
if @name.to_s.size > 2
|
157
|
+
b.PersonName @name
|
158
|
+
b.CompanyName @company unless @company.blank?
|
159
|
+
elsif @company.to_s.size > 2
|
160
|
+
b.PersonName @name unless @name.blank?
|
161
|
+
b.CompanyName @company
|
162
|
+
else
|
163
|
+
raise ShippingError, "Either the name or the company value must be bigger than 2 characters."
|
164
|
+
end
|
165
|
+
b.Department @department unless @department.blank?
|
166
|
+
b.PhoneNumber @phone.gsub(/[^\d]/,"")
|
167
|
+
b.PagerNumber @pager.gsub(/[^\d]/,"") if @pager.class == String
|
168
|
+
b.FaxNumber @fax.gsub(/[^\d]/,"") if @fax.class == String
|
169
|
+
b.tag! :"E-MailAddress", @email
|
170
|
+
}
|
171
|
+
b.Address { |b|
|
172
|
+
b.Line1 @address
|
173
|
+
b.Line2 @address2 unless @address2.blank?
|
174
|
+
b.City @city
|
175
|
+
b.StateOrProvinceCode state
|
176
|
+
b.PostalCode @zip
|
177
|
+
b.CountryCode @country || 'US'
|
178
|
+
}
|
179
|
+
}
|
180
|
+
b.Payment { |b|
|
181
|
+
b.PayorType PaymentTypes[@pay_type] || 'SENDER'
|
182
|
+
b.Payor { |b|
|
183
|
+
b.AccountNumber @payor_account_number
|
184
|
+
b.CountryCode @payor_country_code unless @payor_country_code.blank?
|
185
|
+
} unless @payor_account_number.blank?
|
186
|
+
}
|
187
|
+
b.RMA { |b|
|
188
|
+
b.Number @rma_number
|
189
|
+
} unless @rma_number.blank?
|
190
|
+
b.SpecialServices { |b|
|
191
|
+
b.EMailNotification { |b|
|
192
|
+
b.ShipAlertOptionalMessage @message
|
193
|
+
b.Shipper { |b|
|
194
|
+
b.ShipAlert @shipper_ship_alert ? 'true' : 'false'
|
195
|
+
b.LanguageCode @shipper_language || 'EN' # FR also available
|
196
|
+
}
|
197
|
+
b.Recipient { |b|
|
198
|
+
b.ShipAlert @recipient_ship_alert ? 'true' : 'false'
|
199
|
+
b.LanguageCode @recipient_language || 'EN' # FR also available
|
200
|
+
}
|
201
|
+
b.Other { |b|
|
202
|
+
b.tag! :"E-MailAddress", @other_email
|
203
|
+
b.ShipAlert @other_ship_alert ? 'true' : 'false'
|
204
|
+
b.LanguageCode @other_language || 'EN' # FR also available
|
205
|
+
} unless @other_email.blank?
|
206
|
+
}
|
207
|
+
} unless @message.blank?
|
208
|
+
b.Label { |b|
|
209
|
+
b.Type @label_type || '2DCOMMON'
|
210
|
+
b.ImageType @image_type || 'PNG'
|
211
|
+
}
|
212
|
+
}
|
213
|
+
get_response @fedex_url
|
214
|
+
|
215
|
+
begin
|
216
|
+
response = Hash.new
|
217
|
+
response[:tracking_number] = REXML::XPath.first(@response, "//FDXShipReply/Tracking/TrackingNumber").text
|
218
|
+
response[:encoded_image] = REXML::XPath.first(@response, "//FDXShipReply/Labels/OutboundLabel").text
|
219
|
+
response[:image] = Tempfile.new("shipping_label")
|
220
|
+
response[:image].write Base64.decode64( response[:encoded_image] )
|
221
|
+
response[:image].rewind
|
222
|
+
rescue
|
223
|
+
raise ShippingError, get_error
|
224
|
+
end
|
225
|
+
|
226
|
+
# allows for things like fedex.label.url
|
227
|
+
def response.method_missing(name, *args)
|
228
|
+
has_key?(name) ? self[name] : super
|
229
|
+
end
|
230
|
+
|
231
|
+
# don't allow people to edit the response
|
232
|
+
response.freeze
|
233
|
+
end
|
234
|
+
|
235
|
+
# require 'fileutils'
|
236
|
+
# fedex = Shipping::FedEx.new :name => 'John Doe', ... , :sender_zip => 97202
|
237
|
+
# label = fedex.email_label
|
238
|
+
# puts label.url
|
239
|
+
# puts label.tracking_number
|
240
|
+
#
|
241
|
+
def return_label
|
99
242
|
@required = [:phone, :email, :address, :city, :state, :zip ]
|
100
243
|
@required += [:sender_phone, :sender_email, :sender_address, :sender_city, :sender_state, :sender_zip ]
|
101
244
|
@required += [:fedex_account, :fedex_url, :weight ]
|
@@ -222,37 +365,18 @@ module Shipping
|
|
222
365
|
response[:userid] = REXML::XPath.first(@response, "//FDXEmailLabelReply/UserID").text
|
223
366
|
response[:password] = REXML::XPath.first(@response, "//FDXEmailLabelReply/Password").text
|
224
367
|
response[:tracking_number] = REXML::XPath.first(@response, "//FDXEmailLabelReply/Package/TrackingNumber").text
|
225
|
-
|
226
|
-
|
227
|
-
|
368
|
+
rescue
|
369
|
+
raise ShippingError, get_error
|
370
|
+
end
|
228
371
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
372
|
+
# allows for things like fedex.label.url
|
373
|
+
def response.method_missing(name, *args)
|
374
|
+
has_key?(name) ? self[name] : super
|
375
|
+
end
|
233
376
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
f = Tempfile.new response.password
|
238
|
-
uri = URI.parse response.url
|
239
|
-
|
240
|
-
http = Net::HTTP.new uri.host, uri.port
|
241
|
-
if uri.port == 443
|
242
|
-
http.use_ssl = true
|
243
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
244
|
-
end
|
245
|
-
req = Net::HTTP::Get.new(uri.path)
|
246
|
-
req.basic_auth response.userid, response.password
|
247
|
-
res = http.request(req)
|
248
|
-
f << res.body
|
249
|
-
f.seek(0)
|
250
|
-
response[:image] = f
|
251
|
-
=end
|
252
|
-
|
253
|
-
# don't allow people to edit the response
|
254
|
-
return response.freeze
|
255
|
-
end
|
377
|
+
# don't allow people to edit the response
|
378
|
+
return response.freeze
|
379
|
+
end
|
256
380
|
|
257
381
|
private
|
258
382
|
|
@@ -278,6 +402,7 @@ module Shipping
|
|
278
402
|
b.Packaging PackageTypes[@packaging_type] || 'YOURPACKAGING'
|
279
403
|
b.WeightUnits @weight_units || 'LBS'
|
280
404
|
b.Weight @weight
|
405
|
+
b.ListRate true #tells fedex to return list rates as well as discounted rates
|
281
406
|
b.OriginAddress { |b|
|
282
407
|
b.StateOrProvinceCode self.class.state_from_zip(@sender_zip)
|
283
408
|
b.PostalCode @sender_zip
|
@@ -297,14 +422,14 @@ module Shipping
|
|
297
422
|
get_response @fedex_url
|
298
423
|
end
|
299
424
|
|
300
|
-
|
301
|
-
|
425
|
+
def get_error
|
426
|
+
return if @response.class != REXML::Document
|
302
427
|
|
303
|
-
|
304
|
-
|
428
|
+
code = REXML::XPath.first(@response, "//Error/Code").text
|
429
|
+
message = REXML::XPath.first(@response, "//Error/Message").text
|
305
430
|
|
306
|
-
|
307
|
-
|
431
|
+
return "Error #{code}: #{message}"
|
432
|
+
end
|
308
433
|
|
309
434
|
# The following type hashes are to allow cross-api data retrieval
|
310
435
|
|
@@ -327,30 +452,30 @@ module Shipping
|
|
327
452
|
"international_ground_service" => "INTERNATIONALGROUND"
|
328
453
|
}
|
329
454
|
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
455
|
+
PackageTypes = {
|
456
|
+
"fedex_envelope" => "FEDEXENVELOPE",
|
457
|
+
"fedex_pak" => "FEDEXPAK",
|
458
|
+
"fedex_box" => "FEDEXBOX",
|
459
|
+
"fedex_tube" => "FEDEXTUBE",
|
460
|
+
"fedex_10_kg_box" => "FEDEX10KGBOX",
|
461
|
+
"fedex_25_kg_box" => "FEDEX25KGBOX",
|
462
|
+
"your_packaging" => "YOURPACKAGING"
|
463
|
+
}
|
464
|
+
|
465
|
+
DropoffTypes = {
|
466
|
+
'regular_pickup' => 'REGULARPICKUP',
|
467
|
+
'request_courier' => 'REQUESTCOURIER',
|
468
|
+
'dropbox' => 'DROPBOX',
|
469
|
+
'business_service_center' => 'BUSINESSSERVICECENTER',
|
470
|
+
'station' => 'STATION'
|
471
|
+
}
|
472
|
+
|
473
|
+
PaymentTypes = {
|
474
|
+
'sender' => 'SENDER',
|
475
|
+
'recipient' => 'RECIPIENT',
|
476
|
+
'third_party' => 'THIRDPARTY',
|
477
|
+
'collect' => 'COLLECT'
|
478
|
+
}
|
354
479
|
|
355
480
|
|
356
481
|
TransactionTypes = {
|
data/test/fedex/fedex_test.rb
CHANGED
@@ -5,11 +5,12 @@ class FedExTest < Test::Unit::TestCase
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def test_price
|
8
|
-
|
8
|
+
assert_in_delta 5.00, @ship.price, 1
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
|
11
|
+
def test_discount_price
|
12
|
+
assert_in_delta 5.00, @ship.discount_price, 1
|
13
|
+
assert @ship.discount_price < @ship.price
|
13
14
|
end
|
14
15
|
|
15
16
|
def test_fails
|
data/test/ups/ups_test.rb
CHANGED
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.10
|
|
3
3
|
specification_version: 1
|
4
4
|
name: shipping
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.
|
7
|
-
date: 2005-09-
|
6
|
+
version: 1.3.0
|
7
|
+
date: 2005-09-24
|
8
8
|
summary: A general shipping module to find out the shipping prices via UPS or FedEx.
|
9
9
|
require_paths:
|
10
10
|
- lib
|