shippinglogic 1.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/CHANGELOG.rdoc +55 -0
- data/LICENSE +20 -0
- data/README.rdoc +175 -0
- data/Rakefile +37 -0
- data/VERSION.yml +5 -0
- data/init.rb +1 -0
- data/lib/shippinglogic.rb +3 -0
- data/lib/shippinglogic/attributes.rb +121 -0
- data/lib/shippinglogic/error.rb +22 -0
- data/lib/shippinglogic/fedex.rb +84 -0
- data/lib/shippinglogic/fedex/cancel.rb +47 -0
- data/lib/shippinglogic/fedex/enumerations.rb +348 -0
- data/lib/shippinglogic/fedex/error.rb +47 -0
- data/lib/shippinglogic/fedex/rate.rb +229 -0
- data/lib/shippinglogic/fedex/request.rb +134 -0
- data/lib/shippinglogic/fedex/response.rb +72 -0
- data/lib/shippinglogic/fedex/service.rb +11 -0
- data/lib/shippinglogic/fedex/ship.rb +238 -0
- data/lib/shippinglogic/fedex/signature.rb +68 -0
- data/lib/shippinglogic/fedex/track.rb +124 -0
- data/lib/shippinglogic/proxy.rb +23 -0
- data/lib/shippinglogic/service.rb +42 -0
- data/lib/shippinglogic/ups.rb +83 -0
- data/lib/shippinglogic/ups/cancel.rb +52 -0
- data/lib/shippinglogic/ups/enumerations.rb +56 -0
- data/lib/shippinglogic/ups/error.rb +42 -0
- data/lib/shippinglogic/ups/label.rb +50 -0
- data/lib/shippinglogic/ups/rate.rb +228 -0
- data/lib/shippinglogic/ups/request.rb +49 -0
- data/lib/shippinglogic/ups/response.rb +58 -0
- data/lib/shippinglogic/ups/service.rb +11 -0
- data/lib/shippinglogic/ups/ship_accept.rb +53 -0
- data/lib/shippinglogic/ups/ship_confirm.rb +170 -0
- data/lib/shippinglogic/ups/track.rb +118 -0
- data/lib/shippinglogic/validation.rb +32 -0
- data/shippinglogic.gemspec +120 -0
- data/spec/attributes_spec.rb +67 -0
- data/spec/config/fedex_credentials.example.yml +4 -0
- data/spec/config/ups_credentials.example.yml +3 -0
- data/spec/error_spec.rb +43 -0
- data/spec/fedex/cancel_spec.rb +10 -0
- data/spec/fedex/error_spec.rb +26 -0
- data/spec/fedex/rate_spec.rb +87 -0
- data/spec/fedex/request_spec.rb +15 -0
- data/spec/fedex/responses/blank.xml +0 -0
- data/spec/fedex/responses/cancel_not_found.xml +7 -0
- data/spec/fedex/responses/failed_authentication.xml +7 -0
- data/spec/fedex/responses/malformed.xml +8 -0
- data/spec/fedex/responses/rate_defaults.xml +7 -0
- data/spec/fedex/responses/rate_insurance.xml +9 -0
- data/spec/fedex/responses/rate_no_services.xml +7 -0
- data/spec/fedex/responses/rate_non_custom_packaging.xml +7 -0
- data/spec/fedex/responses/ship_defaults.xml +7 -0
- data/spec/fedex/responses/ship_with_no_signature.xml +7 -0
- data/spec/fedex/responses/signature_defaults.xml +7 -0
- data/spec/fedex/responses/track_defaults.xml +7 -0
- data/spec/fedex/responses/unexpected.xml +1 -0
- data/spec/fedex/service_spec.rb +19 -0
- data/spec/fedex/ship_spec.rb +37 -0
- data/spec/fedex/signature_spec.rb +11 -0
- data/spec/fedex/spec_helper.rb +84 -0
- data/spec/fedex/track_spec.rb +37 -0
- data/spec/fedex_spec.rb +16 -0
- data/spec/lib/interceptor.rb +17 -0
- data/spec/proxy_spec.rb +42 -0
- data/spec/service_spec.rb +23 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/ups/responses/blank.xml +0 -0
- data/spec/ups/responses/track_defaults.xml +2 -0
- data/spec/ups/spec_helper.rb +43 -0
- data/spec/ups_spec.rb +16 -0
- data/spec/validation_spec.rb +49 -0
- metadata +163 -0
@@ -0,0 +1,238 @@
|
|
1
|
+
require "base64"
|
2
|
+
|
3
|
+
module Shippinglogic
|
4
|
+
class FedEx
|
5
|
+
# An interface to the shipe services provided by FedEx. Allows you to create shipments and get various information on the shipment
|
6
|
+
# created. Such as the tracking number, the label image, barcode image, delivery date, etc.
|
7
|
+
#
|
8
|
+
# == Options
|
9
|
+
# === Shipper options
|
10
|
+
#
|
11
|
+
# * <tt>shipper_name</tt> - name of the shipper.
|
12
|
+
# * <tt>shipper_title</tt> - title of the shipper.
|
13
|
+
# * <tt>shipper_company_name</tt> - company name of the shipper.
|
14
|
+
# * <tt>shipper_phone_number</tt> - phone number of the shipper.
|
15
|
+
# * <tt>shipper_email</tt> - email of the shipper.
|
16
|
+
# * <tt>shipper_streets</tt> - street part of the address, separate multiple streets with a new line, dont include blank lines.
|
17
|
+
# * <tt>shipper_city</tt> - city part of the address.
|
18
|
+
# * <tt>shipper_state_</tt> - state part of the address, use state abreviations.
|
19
|
+
# * <tt>shipper_postal_code</tt> - postal code part of the address. Ex: zip for the US.
|
20
|
+
# * <tt>shipper_country</tt> - country code part of the address. FedEx expects abbreviations, but Shippinglogic will convert full names to abbreviations for you.
|
21
|
+
# * <tt>shipper_residential</tt> - a boolean value representing if the address is redential or not (default: false)
|
22
|
+
#
|
23
|
+
# === Recipient options
|
24
|
+
#
|
25
|
+
# * <tt>recipient_name</tt> - name of the recipient.
|
26
|
+
# * <tt>recipient_title</tt> - title of the recipient.
|
27
|
+
# * <tt>recipient_company_name</tt> - company name of the recipient.
|
28
|
+
# * <tt>recipient_phone_number</tt> - phone number of the recipient.
|
29
|
+
# * <tt>recipient_email</tt> - email of the recipient.
|
30
|
+
# * <tt>recipient_streets</tt> - street part of the address, separate multiple streets with a new line, dont include blank lines.
|
31
|
+
# * <tt>recipient_city</tt> - city part of the address.
|
32
|
+
# * <tt>recipient_state</tt> - state part of the address, use state abreviations.
|
33
|
+
# * <tt>recipient_postal_code</tt> - postal code part of the address. Ex: zip for the US.
|
34
|
+
# * <tt>recipient_country</tt> - country code part of the address. FedEx expects abbreviations, but Shippinglogic will convert full names to abbreviations for you.
|
35
|
+
# * <tt>recipient_residential</tt> - a boolean value representing if the address is redential or not (default: false)
|
36
|
+
#
|
37
|
+
# === Label options
|
38
|
+
#
|
39
|
+
# * <tt>label_format</tt> - one of Enumerations::LABEL_FORMATS. (default: COMMON2D)
|
40
|
+
# * <tt>label_file_type</tt> - one of Enumerations::LABEL_FILE_TYPES. (default: PDF)
|
41
|
+
# * <tt>label_stock_type</tt> - one of Enumerations::LABEL_STOCK_TYPES. (default: PAPER_8.5X11_TOP_HALF_LABEL)
|
42
|
+
#
|
43
|
+
# === Packaging options
|
44
|
+
#
|
45
|
+
# One thing to note is that FedEx does support multiple package shipments. The problem is that all of the packages must be identical.
|
46
|
+
# FedEx specifically notes in their documentation that mutiple package specifications are not allowed. So your only option for a
|
47
|
+
# multi package shipment is to increase the package_count option and keep the dimensions and weight the same for all packages. Then again,
|
48
|
+
# the documentation for the FedEx web services is terrible, so I could be wrong. Any tests I tried resulted in an error though.
|
49
|
+
#
|
50
|
+
# * <tt>packaging_type</tt> - one of Enumerations::PACKAGE_TYPES. (default: YOUR_PACKAGING)
|
51
|
+
# * <tt>package_count</tt> - the number of packages in your shipment. (default: 1)
|
52
|
+
# * <tt>package_weight</tt> - a single packages weight.
|
53
|
+
# * <tt>package_weight_units</tt> - either LB or KG. (default: LB)
|
54
|
+
# * <tt>package_length</tt> - a single packages length, only required if using YOUR_PACKAGING for packaging_type.
|
55
|
+
# * <tt>package_width</tt> - a single packages width, only required if using YOUR_PACKAGING for packaging_type.
|
56
|
+
# * <tt>package_height</tt> - a single packages height, only required if using YOUR_PACKAGING for packaging_type.
|
57
|
+
# * <tt>package_dimension_units</tt> - either IN or CM. (default: IN)
|
58
|
+
#
|
59
|
+
# === Monetary options
|
60
|
+
#
|
61
|
+
# * <tt>currency_type</tt> - the type of currency. (default: nil, because FedEx will default to your account preferences)
|
62
|
+
# * <tt>insured_value</tt> - the value you want to insure, if any. (default: nil)
|
63
|
+
# * <tt>payment_type</tt> - one of Enumerations::PAYMENT_TYPES. (default: SENDER)
|
64
|
+
# * <tt>payor_account_number</tt> - if the account paying for this ship is different than the account you specified then
|
65
|
+
# you can specify that here. (default: your account number)
|
66
|
+
# * <tt>payor_country</tt> - the country code for the account number. (default: US)
|
67
|
+
#
|
68
|
+
# === Delivery options
|
69
|
+
#
|
70
|
+
# * <tt>ship_time</tt> - a Time object representing when you want to ship the package. (default: Time.now)
|
71
|
+
# * <tt>service_type</tt> - one of Enumerations::SERVICE_TYPES, this is optional, leave this blank if you want a list of all
|
72
|
+
# available services. (default: nil)
|
73
|
+
# * <tt>dropoff_type</tt> - one of Enumerations::DROP_OFF_TYPES. (default: REGULAR_PICKUP)
|
74
|
+
# * <tt>special_services_requested</tt> - any exceptions or special services FedEx needs to be aware of, this should be
|
75
|
+
# one or more of Enumerations::SPECIAL_SERVICES. (default: nil)
|
76
|
+
# * <tt>signature</tt> - one of Enumerations::SIGNATURE_OPTION_TYPES. (default: nil, which defaults to the service default)
|
77
|
+
#
|
78
|
+
# === Misc options
|
79
|
+
#
|
80
|
+
# * <tt>just_validate</tt> - will tell FedEx to ONLY validate the shipment, not actually create it. (default: false)
|
81
|
+
# * <tt>rate_request_types</tt> - one or more of Enumerations::RATE_REQUEST_TYPES. (default: ACCOUNT)
|
82
|
+
#
|
83
|
+
# == Simple Example
|
84
|
+
#
|
85
|
+
# Here is a very simple example. Mix and match the options above to get more accurate rates:
|
86
|
+
#
|
87
|
+
# fedex = Shippinglogic::FedEx.new(key, password, account, meter)
|
88
|
+
# shipment = fedex.ship(
|
89
|
+
# :shipper_postal_code => "10007",
|
90
|
+
# :shipper_country => "US",
|
91
|
+
# :recipient_postal_code => "75201",
|
92
|
+
# :recipient_country_code => "US",
|
93
|
+
# :package_weight => 24,
|
94
|
+
# :package_length => 12,
|
95
|
+
# :package_width => 12,
|
96
|
+
# :package_height => 12
|
97
|
+
# )
|
98
|
+
#
|
99
|
+
# shipment.inspect
|
100
|
+
# #<Shippinglogic::FedEx::Ship::Shipment rate:decimal, currency:string, delivery_date:date, tracking_number:string,
|
101
|
+
# label:string(base64 decoded), barcode:string(base64 decoded) >
|
102
|
+
#
|
103
|
+
# # to show accessor methods
|
104
|
+
# shipment.tracking_number
|
105
|
+
# # => "XXXXXXXXXXXXXX"
|
106
|
+
class Ship < Service
|
107
|
+
# The shipment result is an object of this class
|
108
|
+
class Shipment; attr_accessor :rate, :currency, :delivery_date, :tracking_number, :label, :barcode; end
|
109
|
+
|
110
|
+
VERSION = {:major => 6, :intermediate => 0, :minor => 0}
|
111
|
+
|
112
|
+
# shipper options
|
113
|
+
attribute :shipper_name, :string
|
114
|
+
attribute :shipper_title, :string
|
115
|
+
attribute :shipper_company_name, :string
|
116
|
+
attribute :shipper_phone_number, :string
|
117
|
+
attribute :shipper_email, :string
|
118
|
+
attribute :shipper_streets, :string
|
119
|
+
attribute :shipper_city, :string
|
120
|
+
attribute :shipper_state, :string
|
121
|
+
attribute :shipper_postal_code, :string
|
122
|
+
attribute :shipper_country, :string
|
123
|
+
attribute :shipper_residential, :boolean, :default => false
|
124
|
+
|
125
|
+
# recipient options
|
126
|
+
attribute :recipient_name, :string
|
127
|
+
attribute :recipient_title, :string
|
128
|
+
attribute :recipient_company_name, :string
|
129
|
+
attribute :recipient_phone_number, :string
|
130
|
+
attribute :recipient_email, :string
|
131
|
+
attribute :recipient_streets, :string
|
132
|
+
attribute :recipient_city, :string
|
133
|
+
attribute :recipient_state, :string
|
134
|
+
attribute :recipient_postal_code, :string
|
135
|
+
attribute :recipient_country, :string
|
136
|
+
attribute :recipient_residential, :boolean, :default => false
|
137
|
+
|
138
|
+
# label options
|
139
|
+
attribute :label_format, :string, :default => "COMMON2D"
|
140
|
+
attribute :label_file_type, :string, :default => "PDF"
|
141
|
+
attribute :label_stock_type, :string, :default => "PAPER_8.5X11_TOP_HALF_LABEL"
|
142
|
+
|
143
|
+
# packaging options
|
144
|
+
attribute :packaging_type, :string, :default => "YOUR_PACKAGING"
|
145
|
+
attribute :packaging_type, :string, :default => "YOUR_PACKAGING"
|
146
|
+
attribute :package_count, :integer, :default => 1
|
147
|
+
attribute :package_weight, :float
|
148
|
+
attribute :package_weight_units, :string, :default => "LB"
|
149
|
+
attribute :package_length, :integer
|
150
|
+
attribute :package_width, :integer
|
151
|
+
attribute :package_height, :integer
|
152
|
+
attribute :package_dimension_units, :string, :default => "IN"
|
153
|
+
|
154
|
+
# monetary options
|
155
|
+
attribute :currency_type, :string
|
156
|
+
attribute :insured_value, :decimal
|
157
|
+
attribute :payment_type, :string, :default => "SENDER"
|
158
|
+
attribute :payor_account_number, :string, :default => lambda { |shipment| shipment.base.account }
|
159
|
+
attribute :payor_country, :string
|
160
|
+
|
161
|
+
# delivery options
|
162
|
+
attribute :ship_time, :datetime, :default => lambda { |shipment| Time.now }
|
163
|
+
attribute :service_type, :string
|
164
|
+
attribute :dropoff_type, :string, :default => "REGULAR_PICKUP"
|
165
|
+
attribute :special_services_requested, :array
|
166
|
+
attribute :signature, :string
|
167
|
+
|
168
|
+
# misc options
|
169
|
+
attribute :just_validate, :boolean, :default => false
|
170
|
+
attribute :rate_request_types, :array, :default => ["ACCOUNT"]
|
171
|
+
|
172
|
+
private
|
173
|
+
def target
|
174
|
+
@target ||= parse_response(request(build_request))
|
175
|
+
end
|
176
|
+
|
177
|
+
# Just building some XML to send off to FedEx using our various options
|
178
|
+
def build_request
|
179
|
+
b = builder
|
180
|
+
xml = b.tag!(just_validate ? "ValidateShipmentRequest" : "ProcessShipmentRequest", :xmlns => "http://fedex.com/ws/ship/v#{VERSION[:major]}") do
|
181
|
+
build_authentication(b)
|
182
|
+
build_version(b, "ship", VERSION[:major], VERSION[:intermediate], VERSION[:minor])
|
183
|
+
|
184
|
+
b.RequestedShipment do
|
185
|
+
b.ShipTimestamp ship_time.xmlschema if ship_time
|
186
|
+
b.DropoffType dropoff_type if dropoff_type
|
187
|
+
b.ServiceType service_type if service_type
|
188
|
+
b.PackagingType packaging_type if packaging_type
|
189
|
+
build_insured_value(b)
|
190
|
+
|
191
|
+
b.Shipper do
|
192
|
+
build_contact(b, :shipper)
|
193
|
+
build_address(b, :shipper)
|
194
|
+
end
|
195
|
+
|
196
|
+
b.Recipient do
|
197
|
+
build_contact(b, :recipient)
|
198
|
+
build_address(b, :recipient)
|
199
|
+
end
|
200
|
+
|
201
|
+
b.ShippingChargesPayment do
|
202
|
+
b.PaymentType payment_type if payment_type
|
203
|
+
b.Payor do
|
204
|
+
b.AccountNumber payor_account_number if payor_account_number
|
205
|
+
b.CountryCode payor_country if payor_country
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
b.LabelSpecification do
|
210
|
+
b.LabelFormatType label_format if label_format
|
211
|
+
b.ImageType label_file_type if label_file_type
|
212
|
+
b.LabelStockType label_stock_type if label_stock_type
|
213
|
+
end
|
214
|
+
|
215
|
+
b.RateRequestTypes rate_request_types.join(",")
|
216
|
+
build_package(b)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Making sense of the reponse and grabbing the information we need.
|
222
|
+
def parse_response(response)
|
223
|
+
details = response[:completed_shipment_detail]
|
224
|
+
rate = details[:shipment_rating][:shipment_rate_details].first[:total_net_charge]
|
225
|
+
package_details = details[:completed_package_details]
|
226
|
+
|
227
|
+
shipment = Shipment.new
|
228
|
+
shipment.rate = BigDecimal.new(rate[:amount])
|
229
|
+
shipment.currency = rate[:currency]
|
230
|
+
shipment.delivery_date = Date.parse(details[:routing_detail][:delivery_date])
|
231
|
+
shipment.tracking_number = package_details[:tracking_id][:tracking_number]
|
232
|
+
shipment.label = package_details[:label][:parts][:image] && Base64.decode64(package_details[:label][:parts][:image])
|
233
|
+
shipment.barcode = package_details[:barcodes][:common2_d_barcode] && Base64.decode64(package_details[:barcodes][:common2_d_barcode])
|
234
|
+
shipment
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require "base64"
|
2
|
+
|
3
|
+
module Shippinglogic
|
4
|
+
class FedEx
|
5
|
+
# An interface to the signature proof of delivery services provided by FedEx. Allows you to get an image
|
6
|
+
# of the signature, or you can tell fedex to fax it to a fax number.
|
7
|
+
#
|
8
|
+
# == Accessor methods / options
|
9
|
+
#
|
10
|
+
# * <tt>tracking_number</tt> - the tracking number
|
11
|
+
# * <tt>image_type</tt> - one of Enumerations::SIGNATURE_IMAGE_TYPES. (default: LETTER)
|
12
|
+
# * <tt>image_file_type</tt> - one of Enumerations::LABEL_FILE_TYPES. (default: PDF)
|
13
|
+
# * <tt>fax_number</tt> - if image_type is set to FAX you must provide a fax number here. (default: nil)
|
14
|
+
#
|
15
|
+
# === Simple Example
|
16
|
+
#
|
17
|
+
# Here is a very simple example:
|
18
|
+
#
|
19
|
+
# fedex = Shippinglogic::FedEx.new(key, password, account, meter)
|
20
|
+
# signature = fedex.signature(:tracking_number => "my number")
|
21
|
+
#
|
22
|
+
# signature.inspect
|
23
|
+
# # => #<Shippinglogic::FedEx::Signature::Signature image:string(base64 decoded) >
|
24
|
+
#
|
25
|
+
# signature.image
|
26
|
+
# # => "a bunch of garble (write this to a file and save it)"
|
27
|
+
class Signature < Service
|
28
|
+
# Each tracking result is an object of this class
|
29
|
+
class Signature; attr_accessor :image; end
|
30
|
+
|
31
|
+
VERSION = {:major => 3, :intermediate => 0, :minor => 0}
|
32
|
+
|
33
|
+
attribute :image_type, :string, :default => "LETTER"
|
34
|
+
attribute :image_file_type, :string, :default => "PDF"
|
35
|
+
attribute :tracking_number, :string
|
36
|
+
attribute :fax_number, :string
|
37
|
+
|
38
|
+
private
|
39
|
+
# The parent class Service requires that we define this method. This is our kicker. This method is only
|
40
|
+
# called when we need to deal with information from FedEx. Notice the caching into the @target variable.
|
41
|
+
def target
|
42
|
+
@target ||= parse_response(request(build_request))
|
43
|
+
end
|
44
|
+
|
45
|
+
# Just building some XML to send off to FedEx. FedEx require this particualr format.
|
46
|
+
def build_request
|
47
|
+
b = builder
|
48
|
+
xml = b.SignatureProofOfDeliveryRequest(:xmlns => "http://fedex.com/ws/track/v#{VERSION[:major]}") do
|
49
|
+
build_authentication(b)
|
50
|
+
build_version(b, "trck", VERSION[:major], VERSION[:intermediate], VERSION[:minor])
|
51
|
+
|
52
|
+
b.Type image_type
|
53
|
+
b.TrackingNumber tracking_number
|
54
|
+
b.FaxDetail fax_number if fax_number
|
55
|
+
b.LetterFormat image_file_type
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Grabbing the response from FedEx and making sense of it. There is a lot of unneeded information
|
60
|
+
# in the response.
|
61
|
+
def parse_response(response)
|
62
|
+
signature = Signature.new
|
63
|
+
signature.image = response[:letter] && Base64.decode64(response[:letter])
|
64
|
+
signature
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module Shippinglogic
|
2
|
+
class FedEx
|
3
|
+
# An interface to the track services provided by FedEx. Allows you to get an array of events for a specific
|
4
|
+
# tracking number.
|
5
|
+
#
|
6
|
+
# == Accessor methods / options
|
7
|
+
#
|
8
|
+
# * <tt>tracking_number</tt> - the tracking number
|
9
|
+
#
|
10
|
+
# === Simple Example
|
11
|
+
#
|
12
|
+
# Here is a very simple example:
|
13
|
+
#
|
14
|
+
# fedex = Shippinglogic::FedEx.new(key, password, account, meter)
|
15
|
+
# tracking_details = fedex.track(:tracking_number => "my number")
|
16
|
+
#
|
17
|
+
# tracking.status
|
18
|
+
# # => "Delivered"
|
19
|
+
#
|
20
|
+
# tracking.signature_name
|
21
|
+
# # => "KKING"
|
22
|
+
#
|
23
|
+
# tracking.events.first
|
24
|
+
# # => #<Shippinglogic::FedEx::Track::Event @postal_code="95817", @name="Delivered", @state="CA", @residential=false,
|
25
|
+
# # @city="Sacramento", @type="DL", @country="US", @occured_at=Mon Dec 08 10:43:37 -0500 2008>
|
26
|
+
#
|
27
|
+
# tracking.events.first.name
|
28
|
+
# # => "Delivered"
|
29
|
+
#
|
30
|
+
# === Note
|
31
|
+
#
|
32
|
+
# FedEx does support locating packages through means other than a tracking number.
|
33
|
+
# These are not supported and probably won't be until someone needs them. It should
|
34
|
+
# be fairly simple to add, but I could not think of a reason why anyone would want to track
|
35
|
+
# a package with anything other than a tracking number.
|
36
|
+
class Track < Service
|
37
|
+
class Details
|
38
|
+
# Each tracking result is an object of this class
|
39
|
+
class Event; attr_accessor :name, :type, :occured_at, :city, :state, :postal_code, :country, :residential; end
|
40
|
+
|
41
|
+
attr_accessor :origin_city,
|
42
|
+
:origin_state,
|
43
|
+
:origin_country,
|
44
|
+
:origin_residential,
|
45
|
+
:destination_city,
|
46
|
+
:destination_state,
|
47
|
+
:destination_country,
|
48
|
+
:destination_residential,
|
49
|
+
:signature_name,
|
50
|
+
:service_type,
|
51
|
+
:status,
|
52
|
+
:delivery_at,
|
53
|
+
:events
|
54
|
+
|
55
|
+
def origin_residential?
|
56
|
+
origin_residential == true
|
57
|
+
end
|
58
|
+
|
59
|
+
def destination_residential?
|
60
|
+
destination_residential == true
|
61
|
+
end
|
62
|
+
|
63
|
+
def initialize(response)
|
64
|
+
details = response[:track_details]
|
65
|
+
|
66
|
+
self.origin_city = details[:origin_location_address][:city]
|
67
|
+
self.origin_state = details[:origin_location_address][:state_or_province_code]
|
68
|
+
self.origin_country = details[:origin_location_address][:country_code]
|
69
|
+
self.origin_residential = details[:origin_location_address][:residential] == "true"
|
70
|
+
|
71
|
+
self.destination_city = details[:destination_address][:city]
|
72
|
+
self.destination_state = details[:destination_address][:state_or_province_code]
|
73
|
+
self.destination_country = details[:destination_address][:country_code]
|
74
|
+
self.destination_residential = details[:destination_address][:residential] == "true"
|
75
|
+
|
76
|
+
self.signature_name = details[:delivery_signature_name]
|
77
|
+
self.service_type = details[:service_type]
|
78
|
+
self.status = details[:status_description]
|
79
|
+
self.delivery_at = Time.parse(details[:actual_delivery_timestamp])
|
80
|
+
|
81
|
+
self.events = response[:track_details][:events].collect do |details|
|
82
|
+
event = Event.new
|
83
|
+
event.name = details[:event_description]
|
84
|
+
event.type = details[:event_type]
|
85
|
+
event.occured_at = Time.parse(details[:timestamp])
|
86
|
+
event.city = details[:address][:city]
|
87
|
+
event.state = details[:address][:state_or_province_code]
|
88
|
+
event.postal_code = details[:address][:postal_code]
|
89
|
+
event.country = details[:address][:country_code]
|
90
|
+
event.residential = details[:address][:residential] == "true"
|
91
|
+
event
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
VERSION = {:major => 3, :intermediate => 0, :minor => 0}
|
97
|
+
|
98
|
+
attribute :tracking_number, :string
|
99
|
+
|
100
|
+
private
|
101
|
+
# The parent class Service requires that we define this method. This is our kicker. This method is only
|
102
|
+
# called when we need to deal with information from FedEx. Notice the caching into the @target variable.
|
103
|
+
def target
|
104
|
+
@target ||= Details.new(request(build_request))
|
105
|
+
end
|
106
|
+
|
107
|
+
# Just building some XML to send off to FedEx. FedEx require this particualr format.
|
108
|
+
def build_request
|
109
|
+
b = builder
|
110
|
+
xml = b.TrackRequest(:xmlns => "http://fedex.com/ws/track/v#{VERSION[:major]}") do
|
111
|
+
build_authentication(b)
|
112
|
+
build_version(b, "trck", VERSION[:major], VERSION[:intermediate], VERSION[:minor])
|
113
|
+
|
114
|
+
b.PackageIdentifier do
|
115
|
+
b.Value tracking_number
|
116
|
+
b.Type "TRACKING_NUMBER_OR_DOORTAG"
|
117
|
+
end
|
118
|
+
|
119
|
+
b.IncludeDetailedScans true
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Shippinglogic
|
2
|
+
class Proxy
|
3
|
+
alias_method :real_class, :class
|
4
|
+
instance_methods.each do |m|
|
5
|
+
if (m =~ /^(__|respond_to_missing\?|real_class$|send$|object_id|respond_to\?$)/).nil?
|
6
|
+
undef_method(m)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_accessor :target
|
11
|
+
|
12
|
+
def initialize(target)
|
13
|
+
self.target = target
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
# We undefined a lot of methods at the beginning of this class. The only methods present in this
|
18
|
+
# class are ones that we need, everything else is delegated to our target object.
|
19
|
+
def method_missing(name, *args, &block)
|
20
|
+
target.send(name, *args, &block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|