binarylogic-shippinglogic 0.9.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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]