binarylogic-shippinglogic 0.9.0 → 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.
@@ -5,7 +5,7 @@ module Shippinglogic
5
5
  private
6
6
  # Convenience method for sending requests to FedEx
7
7
  def request(body)
8
- self.class.post(base.options[:test] ? base.options[:test_url] : base.options[:production_url], :body => body)
8
+ real_class.post(base.options[:test] ? base.options[:test_url] : base.options[:production_url], :body => body)
9
9
  end
10
10
 
11
11
  # Convenience method to create a builder object so that our builder options are consistent across
@@ -42,6 +42,48 @@ module Shippinglogic
42
42
  b.Minor minor
43
43
  end
44
44
  end
45
+
46
+ # A convenience method for building the contact block in your XML request
47
+ def build_contact(b, type)
48
+ b.Contact do
49
+ b.Contact send("#{type}_name") if send("#{type}_name")
50
+ b.CompanyName send("#{type}_company_name") if send("#{type}_company_name")
51
+ b.PhoneNumber send("#{type}_phone_number") if send("#{type}_phone_number")
52
+ end
53
+ end
54
+
55
+ # A convenience method for building the address block in your XML request
56
+ def build_address(b, type)
57
+ b.Address do
58
+ b.StreetLines send("#{type}_streets") if send("#{type}_streets")
59
+ b.City send("#{type}_city") if send("#{type}_city")
60
+ b.StateOrProvinceCode send("#{type}_state") if send("#{type}_state")
61
+ b.PostalCode send("#{type}_postal_code") if send("#{type}_postal_code")
62
+ b.CountryCode send("#{type}_country") if send("#{type}_country")
63
+ b.Residential send("#{type}_residential")
64
+ end
65
+ end
66
+
67
+ # A convenience method for building the package block in your XML request
68
+ def build_package(b)
69
+ b.PackageCount package_count
70
+
71
+ b.RequestedPackages do
72
+ b.SequenceNumber 1
73
+
74
+ b.Weight do
75
+ b.Units package_weight_units
76
+ b.Value package_weight
77
+ end
78
+
79
+ b.Dimensions do
80
+ b.Length package_length
81
+ b.Width package_width
82
+ b.Height package_height
83
+ b.Units package_dimension_units
84
+ end
85
+ end
86
+ end
45
87
  end
46
88
  end
47
89
  end
@@ -16,7 +16,7 @@ module Shippinglogic
16
16
 
17
17
  # Was the response a success?
18
18
  def success?(response)
19
- response.is_a?(Hash) && ["SUCCESS", "NOTE"].include?(response[:highest_severity])
19
+ response.is_a?(Hash) && ["SUCCESS", "NOTE", "WARNING"].include?(response[:highest_severity])
20
20
  end
21
21
 
22
22
  # Cleans the response and returns it in a more 'user friendly' format that is easier
@@ -6,7 +6,8 @@ require "shippinglogic/fedex/validation"
6
6
  module Shippinglogic
7
7
  class FedEx
8
8
  class Service
9
- instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^class$|^send$|proxy_|^object_id$)/ }
9
+ alias_method :real_class, :class
10
+ instance_methods.each { |m| undef_method m unless m =~ /(^__|^real_class$|^send$|^object_id$)/ }
10
11
 
11
12
  include Attributes
12
13
  include HTTParty
@@ -14,6 +15,65 @@ module Shippinglogic
14
15
  include Response
15
16
  include Validation
16
17
 
18
+ # These constants aren't referenced or used anywhere in this library, they are purely for reference and as a tool for your to use.
19
+ # Many of the options that these services accept require a value from one of these arrays. The docs will specify which
20
+ # constant to use. You also might want to include these in a drop down on your interface.
21
+ #
22
+ # Lastly, if you want to make these user friendly use a string inflector (humanize or titlize).
23
+
24
+ # label options
25
+ LABEL_FORMATS = ["COMMON2D", "ERROR", "LABEL_DATA_ONLY", "MAILROOM", "NO_LABEL"]
26
+ LABEL_FILE_TYPES = ["DIB", "DPL", "EPL2", "GIF", "PDF", "PNG", "ZPLII"]
27
+ LABEL_STOCK_TYPES = [
28
+ "PAPER_4X6", "PAPER_4X8", "PAPER_4X9", "PAPER_7X4.75", "PAPER_8.5X11_BOTTOM_HALF_LABEL", "PAPER_8.5X11_TOP_HALF_LABEL",
29
+ "PAPER_LETTER", "STOCK_4X6", "STOCK_4X6.75_LEADING_DOC_TAB", "STOCK_4X6.75_TRAILING_DOC_TAB", "STOCK_4X8",
30
+ "STOCK_4X9_LEADING_DOC_TAB", "STOCK_4X9_TRAILING_DOC_TAB"
31
+ ]
32
+ LABEL_MASK_OPTIONS = [
33
+ "CUSTOMS_VALUE", "DIMENSIONS", "DUTIES_AND_TAXES_PAYOR_ACCOUNT_NUMBER", "FREIGHT_PAYOR_ACCOUNT_NUMBER",
34
+ "PACKAGE_SEQUENCE_AND_COUNT", "SHIPPER_ACCOUNT_NUMBER", "SUPPLEMENTAL_LABEL_DOC_TAB", "TERMS_AND_CONDITIONS",
35
+ "TOTAL_WEIGHT", "TRANSPORTATION_CHARGES_PAYOR_ACCOUNT_NUMBER"
36
+ ]
37
+
38
+ # service options
39
+ REGULAR_SERVICE_TYPES = [
40
+ "GROUND_HOME_DELIVERY", "FEDEX_GROUND", "FEDEX_EXPRESS_SAVER", "FEDEX_2_DAY", "STANDARD_OVERNIGHT",
41
+ "PRIORITY_OVERNIGHT", "FIRST_OVERNIGHT"
42
+ ]
43
+ REGULAR_SATURDAY_SERVICE_TYPES = ["FEDEX_2_DAY_SATURDAY_DELIVERY", "PRIORITY_OVERNIGHT_SATURDAY_DELIVERY"]
44
+ FREIGHT_SERVICE_TYPES = ["FEDEX_3_DAY_FREIGHT", "FEDEX_2_DAY_FREIGHT", "FEDEX_1_DAY_FREIGHT"]
45
+ FREIGHT_SATURDAY_SERVICE_TYPES = [
46
+ "FEDEX_3_DAY_FREIGHT_SATURDAY_DELIVERY", "FEDEX_2_DAY_FREIGHT_SATURDAY_DELIVERY",
47
+ "FEDEX_1_DAY_FREIGHT_SATURDAY_DELIVERY"
48
+ ]
49
+ INTERNATIONAL_SERVICE_TYPES = ["INTERNATIONAL_GROUND", "INTERNATIONAL_ECONOMY", "INTERNATIONAL_PRIORITY", "INTERNATIONAL_FIRST"]
50
+ INTERNATIONAL_SATURDAY_TYPES = ["INTERNATIONAL_PRIORITY_SATURDAY_DELIVERY"]
51
+ INTERNATIONA_FREIGHT_SERVICE_TYPES = ["INTERNATIONAL_ECONOMY_FREIGHT", "INTERNATIONAL_PRIORITY_FREIGHT"]
52
+ SERVICE_TYPES = REGULAR_SERVICE_TYPES + REGULAR_SATURDAY_SERVICE_TYPES + FREIGHT_SERVICE_TYPES + FREIGHT_SATURDAY_SERVICE_TYPES +
53
+ INTERNATIONAL_SERVICE_TYPES + INTERNATIONAL_SATURDAY_TYPES + INTERNATIONA_FREIGHT_SERVICE_TYPES
54
+
55
+ # delivery options
56
+ SIGNATURE_OPTION_TYPES = ["ADULT", "DIRECT", "INDIRECT", "NO_SIGNATURE_REQUIRED", "SERVICE_DEFAULT"]
57
+ SIGNATURE_IMAGE_TYPES = ["LETTER", "FAX"]
58
+ SPECIAL_SERVICES = [
59
+ "APPOINTMENT_DELIVERY", "DANGEROUS_GOODS", "DRY_ICE", "NON_STANDARD_CONTAINER", "PRIORITY_ALERT", "SIGNATURE_OPTION",
60
+ "FEDEX_FREIGHT", "FEDEX_NATIONAL_FREIGHT", "INSIDE_PICKUP", "INSIDE_DELIVERY", "EXHIBITION", "EXTREME_LENGTH", "FLATBED_TRAILER",
61
+ "FREIGHT_GUARANTEE", "LIFTGATE_DELIVERY", "LIFTGATE_PICKUP", "LIMITED_ACCESS_DELIVERY", "LIMITED_ACCESS_PICKUP", "PRE_DELIVERY_NOTIFICATION",
62
+ "PROTECTION_FROM_FREEZING", "REGIONAL_MALL_DELIVERY", "REGIONAL_MALL_PICKUP"
63
+ ]
64
+
65
+ # misc options
66
+ DELETION_CONTROL = ["DELETE_ALL_PACKAGES", "DELETE_ONE_PACKAGE", "LEGACY"]
67
+ EMAIL_TYPES = ["HTML", "TEXT", "WIRELESS"]
68
+ PAYMENT_TYPES = ["SENDER", "CASH", "CREDIT_CARD"]
69
+ REFERENCE_TYPES = [
70
+ "BILL_OF_LADING", "CUSTOMER_REFERENCE", "DEPARTMENT_NUMBER", "INVOICE_NUMER", "P_O_NUMBER",
71
+ "SHIPMENT_INTEGRITY", "STORE_NUMBER"
72
+ ]
73
+ PACKAGE_TYPES = ["FEDEX_ENVELOPE", "FEDEX_PAK", "FEDEX_BOX", "FEDEX_TUBE", "FEDEX_10KG_BOX", "FEDEX_25KG_BOX", "YOUR_PACKAGING"]
74
+ DROP_OFF_TYPES = ["REGULAR_PICKUP", "REQUEST_COURIER", "DROP_BOX", "BUSINESS_SERVICE_CENTER", "STATION"]
75
+ RATE_REQUEST_TYPES = ["ACCOUNT", "LIST", "MULTIWEIGHT"]
76
+
17
77
  attr_accessor :base
18
78
 
19
79
  # Accepts the base service object as a single parameter so that we can access
@@ -31,7 +91,8 @@ module Shippinglogic
31
91
  end
32
92
 
33
93
  # For each service you need to overwrite this method. This is where you make the call to fedex
34
- # and do your magic.
94
+ # and do your magic. See the child classes for examples on how to define this method. It is very
95
+ # important that you cache the result into a variable to avoid uneccessary requests.
35
96
  def target
36
97
  raise ImplementationError.new("You need to implement a target method that the proxy class can delegate method calls to")
37
98
  end
@@ -0,0 +1,227 @@
1
+ module Shippinglogic
2
+ class FedEx
3
+ # An interface to the shipe services provided by FedEx. Allows you to create shipments and get various information on the shipment
4
+ # created. Such as the tracking number, the label image, barcode image, delivery date, etc.
5
+ #
6
+ # == Options
7
+ # === Shipper options
8
+ #
9
+ # * <tt>shipper_streets</tt> - street part of the address, separate multiple streets with a new line, dont include blank lines.
10
+ # * <tt>shipper_city</tt> - city part of the address.
11
+ # * <tt>shipper_state_</tt> - state part of the address, use state abreviations.
12
+ # * <tt>shipper_postal_code</tt> - postal code part of the address. Ex: zip for the US.
13
+ # * <tt>shipper_country</tt> - country code part of the address, use abbreviations, ex: 'US'
14
+ # * <tt>shipper_residential</tt> - a boolean value representing if the address is redential or not (default: false)
15
+ #
16
+ # === Recipient options
17
+ #
18
+ # * <tt>recipient_streets</tt> - street part of the address, separate multiple streets with a new line, dont include blank lines.
19
+ # * <tt>recipient_city</tt> - city part of the address.
20
+ # * <tt>recipient_state</tt> - state part of the address, use state abreviations.
21
+ # * <tt>recipient_postal_code</tt> - postal code part of the address. Ex: zip for the US.
22
+ # * <tt>recipient_country</tt> - country code part of the address, use abbreviations, ex: 'US'
23
+ # * <tt>recipient_residential</tt> - a boolean value representing if the address is redential or not (default: false)
24
+ #
25
+ # === Label options
26
+ #
27
+ # * <tt>label_format</tt> - one of LABEL_FORMATS. (default: COMMON2D)
28
+ # * <tt>label_file_type</tt> - one of LABEL_FILE_TYPES. (default: PDF)
29
+ # * <tt>label_stock_type</tt> - one of LABEL_STOCK_TYPES. (default: PAPER_8.5X11_TOP_HALF_LABEL)
30
+ #
31
+ # === Packaging options
32
+ #
33
+ # One thing to note is that FedEx does support multiple package shipments. The problem is that all of the packages must be identical.
34
+ # FedEx specifically notes in their documentation that mutiple package specifications are not allowed. So your only option for a
35
+ # multi package shipment is to increase the package_count option and keep the dimensions and weight the same for all packages. Then again,
36
+ # the documentation for the FedEx web services is terrible, so I could be wrong. Any tests I tried resulted in an error though.
37
+ #
38
+ # * <tt>packaging_type</tt> - one of PACKAGE_TYPES. (default: YOUR_PACKAGING)
39
+ # * <tt>package_count</tt> - the number of packages in your shipment. (default: 1)
40
+ # * <tt>package_weight</tt> - a single packages weight.
41
+ # * <tt>package_weight_units</tt> - either LB or KG. (default: LB)
42
+ # * <tt>package_length</tt> - a single packages length.
43
+ # * <tt>package_width</tt> - a single packages width.
44
+ # * <tt>package_height</tt> - a single packages height.
45
+ # * <tt>package_dimension_units</tt> - either IN or CM. (default: IN)
46
+ #
47
+ # === Monetary options
48
+ #
49
+ # * <tt>currency_type</tt> - the type of currency. (default: nil, because FedEx will default to your account preferences)
50
+ # * <tt>insured_value</tt> - the value you want to insure, if any. (default: nil)
51
+ # * <tt>payment_type</tt> - one of PAYMENT_TYPES. (default: SENDER)
52
+ # * <tt>payor_account_number</tt> - if the account paying for this ship is different than the account you specified then
53
+ # you can specify that here. (default: your account number)
54
+ # * <tt>payor_country</tt> - the country code for the account number. (default: US)
55
+ #
56
+ # === Delivery options
57
+ #
58
+ # * <tt>ship_time</tt> - a Time object representing when you want to ship the package. (default: Time.now)
59
+ # * <tt>service_type</tt> - one of SERVICE_TYPES, this is optional, leave this blank if you want a list of all
60
+ # available services. (default: nil)
61
+ # * <tt>dropoff_type</tt> - one of DROP_OFF_TYPES. (default: REGULAR_PICKUP)
62
+ # * <tt>special_services_requested</tt> - any exceptions or special services FedEx needs to be aware of, this should be
63
+ # one or more of SPECIAL_SERVICES. (default: nil)
64
+ # * <tt>signature</tt> - one of SIGNATURE_OPTION_TYPES. (default: nil, which defaults to the service default)
65
+ #
66
+ # === Misc options
67
+ #
68
+ # * <tt>rate_request_types</tt> - one or more of RATE_REQUEST_TYPES. (default: ACCOUNT)
69
+ #
70
+ # == Simple Example
71
+ #
72
+ # Here is a very simple example. Mix and match the options above to get more accurate rates:
73
+ #
74
+ # fedex = Shippinglogic::FedEx.new(key, password, account, meter)
75
+ # shipment = fedex.ship(
76
+ # :shipper_postal_code => "10007",
77
+ # :shipper_country => "US",
78
+ # :recipient_postal_code => "75201",
79
+ # :recipient_country_code => "US",
80
+ # :package_weight => 24,
81
+ # :package_length => 12,
82
+ # :package_width => 12,
83
+ # :package_height => 12
84
+ # )
85
+ #
86
+ # shipment.inspect
87
+ # #<Shippinglogic::FedEx::Ship::Shipment rate:big_decimal, currency:string, delivery_date:date, tracking_number:string,
88
+ # label:string(base64 decoded), barcode:string(base64 decoded) >
89
+ #
90
+ # # to show accessor methods
91
+ # shipment.tracking_number
92
+ # # => "XXXXXXXXXXXXXX"
93
+ class Ship < Service
94
+ # The shipment result is an object of this class
95
+ class Shipment; attr_accessor :rate, :currency, :delivery_date, :tracking_number, :label, :barcode; end
96
+
97
+ VERSION = {:major => 6, :intermediate => 0, :minor => 0}
98
+
99
+ # shipper options
100
+ attribute :shipper_name, :string
101
+ attribute :shipper_company_name, :string
102
+ attribute :shipper_phone_number, :string
103
+ attribute :shipper_streets, :string
104
+ attribute :shipper_city, :string
105
+ attribute :shipper_state, :string
106
+ attribute :shipper_postal_code, :string
107
+ attribute :shipper_country, :string
108
+ attribute :shipper_residential, :boolean, :default => false
109
+
110
+ # recipient options
111
+ attribute :recipient_name, :string
112
+ attribute :recipient_company_name, :string
113
+ attribute :recipient_phone_number, :string
114
+ attribute :recipient_streets, :string
115
+ attribute :recipient_city, :string
116
+ attribute :recipient_state, :string
117
+ attribute :recipient_postal_code, :string
118
+ attribute :recipient_country, :string
119
+ attribute :recipient_residential, :boolean, :default => false
120
+
121
+ # label options
122
+ attribute :label_format, :string, :default => "COMMON2D"
123
+ attribute :label_file_type, :string, :default => "PDF"
124
+ attribute :label_stock_type, :string, :default => "PAPER_8.5X11_TOP_HALF_LABEL"
125
+
126
+ # packaging options
127
+ attribute :packaging_type, :string, :default => "YOUR_PACKAGING"
128
+ attribute :packaging_type, :string, :default => "YOUR_PACKAGING"
129
+ attribute :package_count, :integer, :default => 1
130
+ attribute :package_weight, :integer
131
+ attribute :package_weight_units, :string, :default => "LB"
132
+ attribute :package_length, :integer
133
+ attribute :package_width, :integer
134
+ attribute :package_height, :integer
135
+ attribute :package_dimension_units, :string, :default => "IN"
136
+
137
+ # monetary options
138
+ attribute :currency_type, :string
139
+ attribute :insured_value, :big_decimal
140
+ attribute :payment_type, :string, :default => "SENDER"
141
+ attribute :payor_account_number, :string, :default => lambda { |shipment| shipment.base.account }
142
+ attribute :payor_country, :string
143
+
144
+ # delivery options
145
+ attribute :ship_time, :datetime, :default => lambda { |shipment| Time.now }
146
+ attribute :service_type, :string
147
+ attribute :dropoff_type, :string, :default => "REGULAR_PICKUP"
148
+ attribute :special_services_requested, :array
149
+ attribute :signature, :string
150
+
151
+ # misc options
152
+ attribute :rate_request_types, :array, :default => ["ACCOUNT"]
153
+
154
+ private
155
+ def target
156
+ @target ||= parse_response(request(build_request))
157
+ end
158
+
159
+ # Just building some XML to send off to FedEx using our various options
160
+ def build_request
161
+ b = builder
162
+ xml = b.ProcessShipmentRequest(:xmlns => "http://fedex.com/ws/ship/v#{VERSION[:major]}") do
163
+ build_authentication(b)
164
+ build_version(b, "ship", VERSION[:major], VERSION[:intermediate], VERSION[:minor])
165
+ b.SpecialServicesRequested special_services_requested.join(",") if special_services_requested.any?
166
+
167
+ b.RequestedShipment do
168
+ b.ShipTimestamp ship_time.xmlschema if ship_time
169
+ b.DropoffType dropoff_type if dropoff_type
170
+ b.ServiceType service_type if service_type
171
+ b.PackagingType packaging_type if packaging_type
172
+ b.TotalInsuredValue insured_value if insured_value
173
+
174
+ b.Shipper do
175
+ build_contact(b, :shipper)
176
+ build_address(b, :shipper)
177
+ end
178
+
179
+ b.Recipient do
180
+ build_contact(b, :recipient)
181
+ build_address(b, :recipient)
182
+ end
183
+
184
+ b.ShippingChargesPayment do
185
+ b.PaymentType payment_type if payment_type
186
+ b.Payor do
187
+ b.AccountNumber payor_account_number if payor_account_number
188
+ b.CountryCode payor_country if payor_country
189
+ end
190
+ end
191
+
192
+ b.LabelSpecification do
193
+ b.LabelFormatType label_format if label_format
194
+ b.ImageType label_file_type if label_file_type
195
+ b.LabelStockType label_stock_type if label_stock_type
196
+ end
197
+
198
+ if signature
199
+ b.SignatureOptionDetail do
200
+ b.OptionType signature
201
+ end
202
+ end
203
+
204
+ b.RateRequestTypes rate_request_types.join(",")
205
+ build_package(b)
206
+ end
207
+ end
208
+ end
209
+
210
+ # Making sense of the reponse and grabbing the information we need.
211
+ def parse_response(response)
212
+ details = response[:completed_shipment_detail]
213
+ rate = details[:shipment_rating][:shipment_rate_details].first[:total_net_charge]
214
+ package_details = details[:completed_package_details]
215
+
216
+ shipment = Shipment.new
217
+ shipment.rate = BigDecimal.new(rate[:amount])
218
+ shipment.currency = rate[:currency]
219
+ shipment.delivery_date = Date.parse(details[:routing_detail][:delivery_date])
220
+ shipment.tracking_number = package_details[:tracking_id][:tracking_number]
221
+ shipment.label = Base64.decode64(package_details[:label][:parts][:image])
222
+ shipment.barcode = Base64.decode64(package_details[:barcodes][:common2_d_barcode])
223
+ shipment
224
+ end
225
+ end
226
+ end
227
+ end
@@ -0,0 +1,66 @@
1
+ module Shippinglogic
2
+ class FedEx
3
+ # An interface to the signature proof of delivery services provided by FedEx. Allows you to get an image
4
+ # of the signature, or you can tell fedex to fax it to a fax number.
5
+ #
6
+ # == Accessor methods / options
7
+ #
8
+ # * <tt>tracking_number</tt> - the tracking number
9
+ # * <tt>image_type</tt> - one of SIGNATURE_IMAGE_TYPES. (default: LETTER)
10
+ # * <tt>image_file_type</tt> - one of LABEL_FILE_TYPES. (default: PDF)
11
+ # * <tt>fax_number</tt> - if image_type is set to FAX you must provide a fax number here. (default: nil)
12
+ #
13
+ # === Simple Example
14
+ #
15
+ # Here is a very simple example:
16
+ #
17
+ # fedex = Shippinglogic::FedEx.new(key, password, account, meter)
18
+ # signature = fedex.signature(:tracking_number => "my number")
19
+ #
20
+ # signature.inspect
21
+ # # => #<Shippinglogic::FedEx::Signature::Signature image:string(base64 decoded) >
22
+ #
23
+ # signature.image
24
+ # # => "a bunch of garble (write this to a file and save it)"
25
+ class Signature < Service
26
+ # Each tracking result is an object of this class
27
+ class Signature; attr_accessor :image; end
28
+
29
+ VERSION = {:major => 3, :intermediate => 0, :minor => 0}
30
+
31
+ attribute :image_type, :string, :default => "LETTER"
32
+ attribute :image_file_type, :string, :default => "PDF"
33
+ attribute :tracking_number, :string
34
+ attribute :fax_number, :string
35
+
36
+ private
37
+ # The parent class Service requires that we define this method. This is our kicker. This method is only
38
+ # called when we need to deal with information from FedEx. Notice the caching into the @target variable.
39
+ def target
40
+ @target ||= parse_response(request(build_request))
41
+ end
42
+
43
+ # Just building some XML to send off to FedEx. FedEx require this particualr format.
44
+ def build_request
45
+ b = builder
46
+ xml = b.SignatureProofOfDeliveryRequest(:xmlns => "http://fedex.com/ws/track/v#{VERSION[:major]}") do
47
+ build_authentication(b)
48
+ build_version(b, "trck", VERSION[:major], VERSION[:intermediate], VERSION[:minor])
49
+
50
+ b.Type image_type
51
+ b.TrackingNumber tracking_number
52
+ b.FaxDetail fax_number if fax_number
53
+ b.LetterFormat image_file_type
54
+ end
55
+ end
56
+
57
+ # Grabbing the response from FedEx and making sense of it. There is a lot of unneeded information
58
+ # in the response.
59
+ def parse_response(response)
60
+ signature = Signature.new
61
+ signature.image = Base64.decode64(response[:letter])
62
+ signature
63
+ end
64
+ end
65
+ end
66
+ end
@@ -12,9 +12,16 @@ module Shippinglogic
12
12
  # Here is a very simple example:
13
13
  #
14
14
  # fedex = Shippinglogic::FedEx.new(key, password, account, meter)
15
- # fedex.track(:tracking_number => "my number")
15
+ # tracking = fedex.track(:tracking_number => "my number")
16
+ # tracking.first
17
+ # # => #<Shippinglogic::FedEx::Track::Event @postal_code="95817", @name="Delivered", @state="CA", @residential=false,
18
+ # # @city="Sacramento", @type="DL", @country="US", @occured_at=Mon Dec 08 10:43:37 -0500 2008>
19
+ #
20
+ # tracking.first.name
21
+ # # => "Delivered"
16
22
  #
17
23
  # === Note
24
+ #
18
25
  # FedEx does support locating packages through means other than a tracking number.
19
26
  # These are not supported and probably won't be until someone needs them. It should
20
27
  # be fairly simple to add, but I could not think of a reason why anyone would want to track
@@ -28,11 +35,14 @@ module Shippinglogic
28
35
  attribute :tracking_number, :string
29
36
 
30
37
  private
38
+ # The parent class Service requires that we define this method. This is our kicker. This method is only
39
+ # called when we need to deal with information from FedEx. Notice the caching into the @target variable.
31
40
  def target
32
- @target ||= parse_track_response(request(build_track_request))
41
+ @target ||= parse_response(request(build_request))
33
42
  end
34
43
 
35
- def build_track_request
44
+ # Just building some XML to send off to FedEx. FedEx require this particualr format.
45
+ def build_request
36
46
  b = builder
37
47
  xml = b.TrackRequest(:xmlns => "http://fedex.com/ws/track/v#{VERSION[:major]}") do
38
48
  build_authentication(b)
@@ -47,7 +57,9 @@ module Shippinglogic
47
57
  end
48
58
  end
49
59
 
50
- def parse_track_response(response)
60
+ # Grabbing the response from FedEx and making sense of it. There is a lot of unneeded information
61
+ # in the response.
62
+ def parse_response(response)
51
63
  response[:track_details][:events].collect do |details|
52
64
  event = Event.new
53
65
  event.name = details[:event_description]