active_shipping 0.0.2 → 0.1.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/.gitignore CHANGED
@@ -1,5 +1,6 @@
1
1
  .DS_Store
2
2
  test.xml
3
+ test/fixtures.yml
3
4
  sample.rb
4
5
  *.orig
5
6
  *.swp
data/CHANGELOG CHANGED
@@ -1,3 +1,4 @@
1
+ * Require active_support instead of activesupport to avoid deprecation warning in Rails 2.3.5 [cody]
1
2
  * Remove ftools for Rails 1.9 compatibility and remove xml logging, as logging is now included in the connection [cody]
2
3
  * Update connection code from ActiveMerchant [cody]
3
4
  * Fix space-ridden USPS usernames when validating credentials [james]
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.2
1
+ 0.1.0
@@ -1,15 +1,15 @@
1
1
  # Generated by jeweler
2
- # DO NOT EDIT THIS FILE
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{active_shipping}
8
- s.version = "0.0.2"
8
+ s.version = "0.1.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["James MacAulay", "Tobias Luetke", "Cody Fauser", "Jimmy Baker"]
12
- s.date = %q{2009-11-11}
12
+ s.date = %q{2010-01-21}
13
13
  s.description = %q{Shipping API extension for Active Merchant.}
14
14
  s.email = %q{jmacaulay@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -41,11 +41,16 @@ Gem::Specification.new do |s|
41
41
  "lib/active_shipping/shipping/carriers/shipwire.rb",
42
42
  "lib/active_shipping/shipping/carriers/ups.rb",
43
43
  "lib/active_shipping/shipping/carriers/usps.rb",
44
+ "lib/active_shipping/shipping/contact.rb",
45
+ "lib/active_shipping/shipping/label.rb",
44
46
  "lib/active_shipping/shipping/location.rb",
45
47
  "lib/active_shipping/shipping/package.rb",
48
+ "lib/active_shipping/shipping/party.rb",
46
49
  "lib/active_shipping/shipping/rate_estimate.rb",
47
50
  "lib/active_shipping/shipping/rate_response.rb",
48
51
  "lib/active_shipping/shipping/response.rb",
52
+ "lib/active_shipping/shipping/return_shipment.rb",
53
+ "lib/active_shipping/shipping/shipment.rb",
49
54
  "lib/active_shipping/shipping/shipment_event.rb",
50
55
  "lib/active_shipping/shipping/tracking_response.rb",
51
56
  "lib/certs/cacert.pem",
@@ -68,7 +73,7 @@ Gem::Specification.new do |s|
68
73
  "lib/vendor/xml_node/lib/xml_node.rb",
69
74
  "lib/vendor/xml_node/test/test_generating.rb",
70
75
  "lib/vendor/xml_node/test/test_parsing.rb",
71
- "test/fixtures.yml",
76
+ "test/fixtures.example.yml",
72
77
  "test/fixtures/xml/fedex/ottawa_to_beverly_hills_rate_request.xml",
73
78
  "test/fixtures/xml/fedex/ottawa_to_beverly_hills_rate_response.xml",
74
79
  "test/fixtures/xml/fedex/tracking_request.xml",
@@ -86,10 +91,12 @@ Gem::Specification.new do |s|
86
91
  "test/fixtures/xml/usps/beverly_hills_to_ottawa_wii_rate_response.xml",
87
92
  "test/fixtures/xml/usps/example_tracking_response.xml",
88
93
  "test/fixtures/xml/usps/multi_tracking_example.xml",
94
+ "test/party_factory.rb",
89
95
  "test/remote/fedex_test.rb",
90
96
  "test/remote/shipwire_test.rb",
91
97
  "test/remote/ups_test.rb",
92
98
  "test/remote/usps_test.rb",
99
+ "test/shipment_factory.rb",
93
100
  "test/test_helper.rb",
94
101
  "test/unit/base_test.rb",
95
102
  "test/unit/carriers/fedex_test.rb",
@@ -98,7 +105,9 @@ Gem::Specification.new do |s|
98
105
  "test/unit/carriers/usps_test.rb",
99
106
  "test/unit/location_test.rb",
100
107
  "test/unit/package_test.rb",
101
- "test/unit/response_test.rb"
108
+ "test/unit/party_test.rb",
109
+ "test/unit/response_test.rb",
110
+ "test/unit/shipment_test.rb"
102
111
  ]
103
112
  s.homepage = %q{http://github.com/Shopify/active_shipping}
104
113
  s.rdoc_options = ["--charset=UTF-8"]
@@ -106,10 +115,12 @@ Gem::Specification.new do |s|
106
115
  s.rubygems_version = %q{1.3.5}
107
116
  s.summary = %q{Shipping API extension for Active Merchant.}
108
117
  s.test_files = [
109
- "test/remote/fedex_test.rb",
118
+ "test/party_factory.rb",
119
+ "test/remote/fedex_test.rb",
110
120
  "test/remote/shipwire_test.rb",
111
121
  "test/remote/ups_test.rb",
112
122
  "test/remote/usps_test.rb",
123
+ "test/shipment_factory.rb",
113
124
  "test/test_helper.rb",
114
125
  "test/unit/base_test.rb",
115
126
  "test/unit/carriers/fedex_test.rb",
@@ -118,7 +129,9 @@ Gem::Specification.new do |s|
118
129
  "test/unit/carriers/usps_test.rb",
119
130
  "test/unit/location_test.rb",
120
131
  "test/unit/package_test.rb",
121
- "test/unit/response_test.rb"
132
+ "test/unit/party_test.rb",
133
+ "test/unit/response_test.rb",
134
+ "test/unit/shipment_test.rb"
122
135
  ]
123
136
 
124
137
  if s.respond_to? :specification_version then
@@ -134,3 +147,4 @@ Gem::Specification.new do |s|
134
147
  s.add_dependency(%q<activesupport>, [">= 0"])
135
148
  end
136
149
  end
150
+
@@ -45,6 +45,15 @@ require 'active_shipping/shipping/tracking_response'
45
45
  require 'active_shipping/shipping/package'
46
46
  require 'active_shipping/shipping/location'
47
47
  require 'active_shipping/shipping/rate_estimate'
48
+
49
+ require 'active_shipping/shipping/contact'
50
+ require 'active_shipping/shipping/party'
51
+ require 'active_shipping/shipping/label'
52
+
53
+ require 'active_shipping/shipping/shipment'
54
+ require 'active_shipping/shipping/return_shipment'
55
+
48
56
  require 'active_shipping/shipping/shipment_event'
49
57
  require 'active_shipping/shipping/carrier'
50
58
  require 'active_shipping/shipping/carriers'
59
+
@@ -4,11 +4,8 @@ module ActiveMerchant
4
4
  mattr_accessor :mode
5
5
  self.mode = :production
6
6
 
7
- ALLCAPS_NAMES = ['ups','usps','dhl'] # is the class name allcaps like USPS or camelcase like FedEx?
8
-
9
7
  def self.carrier(name)
10
- name = name.to_s.downcase
11
- ActiveMerchant::Shipping.const_get(ALLCAPS_NAMES.include?(name) ? name.upcase : name.camelize)
8
+ ActiveMerchant::Shipping::Carriers.all.find {|c| c.name.downcase == name}
12
9
  end
13
10
  end
14
11
  end
@@ -32,7 +32,7 @@ module ActiveMerchant
32
32
  # alternate functionality, such as checking for test_mode to use test servers, etc.
33
33
  def valid_credentials?
34
34
  location = self.class.default_location
35
- find_rates(location,location,Package.new(100, [5,15,30]))
35
+ find_rates(location,location,Package.new(100, [5,15,30]), :test => test_mode)
36
36
  rescue ActiveMerchant::Shipping::ResponseError
37
37
  false
38
38
  else
@@ -9,7 +9,7 @@ module ActiveMerchant
9
9
  module Carriers
10
10
  class <<self
11
11
  def all
12
- [BogusCarrier, UPS, USPS, FedEx]
12
+ [BogusCarrier, UPS, USPS, FedEx, Shipwire]
13
13
  end
14
14
  end
15
15
  end
@@ -106,8 +106,145 @@ module ActiveMerchant
106
106
  response = commit(save_request(tracking_request), (options[:test] || false)).gsub(/<(\/)?.*?\:(.*?)>/, '<\1\2>')
107
107
  parse_tracking_response(response, options)
108
108
  end
109
-
109
+
110
+ def get_return_label(shipment, options = {})
111
+ req = build_return_label_request(shipment)
112
+ response = commit(save_request(req), (options[:test] || false)).gsub(/<(\/)?.*?\:(.*?)>/, '<\1\2>')
113
+
114
+ parse_return_label_response(response, shipment)
115
+ end
116
+
117
+ def validate_location(location, options = {})
118
+ req = build_location_validation_request(location)
119
+ response = commit(save_request(req), (options[:test] || false)).gsub(/<(\/)?.*?\:(.*?)>/, '<\1\2>')
120
+
121
+ parse_location_validation_request(response, location)
122
+ response
123
+ end
124
+
110
125
  protected
126
+ def build_location_validation_request(location)
127
+ xml_request = XmlNode.new('AddressValidationRequest',
128
+ 'xmlns' => 'http://fedex.com/ws/addressvalidation/v2') do |root_node|
129
+
130
+ root_node << build_request_header
131
+ root_node << XmlNode.new('Version') do |version_node|
132
+ version_node << XmlNode.new('ServiceId', 'aval')
133
+ version_node << XmlNode.new('Major', '2')
134
+ version_node << XmlNode.new('Intermediate', '0')
135
+ version_node << XmlNode.new('Minor', '0')
136
+ end
137
+
138
+ root_node << XmlNode.new('RequestTimestamp', Time.now)
139
+ root_node << XmlNode.new('Options', '')
140
+ root_node << XmlNode.new('AddressesToValidate') do |v|
141
+ v << build_party_location_node('Address', location)
142
+ end
143
+ end
144
+
145
+ xml_request.to_s
146
+ end
147
+
148
+ def parse_location_validation_request(response, location)
149
+ xml = REXML::Document.new(response)
150
+ success = response_success?(xml)
151
+ message = response_message(xml)
152
+
153
+ if success
154
+ parent = xml.elements.first
155
+ location.valid = parent.elements['//DeliveryPointValidation'][0] == 'CONFIRMED'
156
+ location.score = parent.elements['//Score'][0].to_s.to_i
157
+ else
158
+ location.valid = false
159
+ location.score = 0
160
+ message
161
+ end
162
+ end
163
+
164
+ def parse_return_label_response(response, shipment)
165
+ xml = REXML::Document.new(response)
166
+ success = response_success?(xml)
167
+ message = response_message(xml)
168
+
169
+ if success
170
+ parent = xml.elements.first
171
+ shipment.label.image = Base64.decode64(parent.elements['//Image'][0].to_s)
172
+ shipment.tracking_number = parent.elements['//TrackingNumber'][0].to_s
173
+ shipment.transit_time = parent.elements['//TransitTime'][0].to_s
174
+
175
+ shipment
176
+ else
177
+ message
178
+ end
179
+ end
180
+
181
+ def build_return_label_request(shipment)
182
+ xml_request = XmlNode.new('ProcessShipmentRequest',
183
+ 'xmlns' => 'http://fedex.com/ws/ship/v7') do |root_node|
184
+ root_node << build_request_header
185
+ root_node << XmlNode.new('Version') do |version_node|
186
+ version_node << XmlNode.new('ServiceId', 'ship')
187
+ version_node << XmlNode.new('Major', '7')
188
+ version_node << XmlNode.new('Intermediate', '0')
189
+ version_node << XmlNode.new('Minor', '0')
190
+ end
191
+
192
+ root_node << XmlNode.new('RequestedShipment') do |rs|
193
+ rs << XmlNode.new('ShipTimestamp', shipment.ship_at || Time.now)
194
+ rs << XmlNode.new('DropoffType', shipment.dropoff_type)
195
+ rs << XmlNode.new('ServiceType', shipment.service)
196
+ rs << XmlNode.new('PackagingType', shipment.packaging_type)
197
+ rs << XmlNode.new('TotalWeight') do |t|
198
+ t << XmlNode.new('Units', shipment.total_weight_units)
199
+ t << XmlNode.new('Value', shipment.total_weight_value)
200
+ end
201
+ if shipment.total_insured_amount
202
+ rs << XmlNode.new('TotalInsuredValue') do |ins|
203
+ ins << XmlNode.new('Currency', shipment.total_insured_currency)
204
+ ins << XmlNode.new('Amount', shipment.total_insured_amount)
205
+ end
206
+ end
207
+ rs << build_party_node('Shipper', shipment.shipper)
208
+ rs << build_party_node('Recipient', shipment.recipient)
209
+ rs << XmlNode.new('ShippingChargesPayment') do |payment|
210
+ payment << XmlNode.new('PaymentType', shipment.payment_type)
211
+ payment << XmlNode.new('Payor') do |payor|
212
+ payor << XmlNode.new('AccountNumber', shipment.payor_account_number)
213
+ payor << XmlNode.new('CountryCode', shipment.payor_account_country.code(:alpha2))
214
+ end
215
+ end
216
+
217
+ rs << XmlNode.new('SpecialServicesRequested') do |s|
218
+ s << XmlNode.new('SpecialServiceTypes', 'RETURN_SHIPMENT')
219
+ s << XmlNode.new('ReturnShipmentDetail') do |d|
220
+ d << XmlNode.new('ReturnType', shipment.return_type)
221
+ d << XmlNode.new('Rma') do |rma|
222
+ rma << XmlNode.new('Number', shipment.rma_number)
223
+ end
224
+ end
225
+ end
226
+
227
+ rs << XmlNode.new('LabelSpecification') do |spec|
228
+ spec << XmlNode.new('LabelFormatType',
229
+ shipment.label.format_type || 'COMMON2D')
230
+ spec << XmlNode.new('ImageType', shipment.label.image_type)
231
+ spec << XmlNode.new('LabelStockType', 'PAPER_4X6')
232
+ end
233
+ rs << XmlNode.new('RateRequestTypes', shipment.rate_request_type)
234
+ rs << XmlNode.new('PackageCount', shipment.package_count)
235
+ rs << XmlNode.new('PackageDetail', 'PACKAGE_SUMMARY')
236
+ (1..shipment.package_count).each do |package_index|
237
+ rs << XmlNode.new('RequestedPackageLineItems') do |p|
238
+ p << XmlNode.new('SequenceNumber', package_index)
239
+ end
240
+ end
241
+ end
242
+ end
243
+
244
+ xml_request.to_s
245
+ end
246
+
247
+
111
248
  def build_rate_request(origin, destination, packages, options={})
112
249
  imperial = ['US','LR','MM'].include?(origin.country_code(:alpha2))
113
250
 
@@ -205,6 +342,47 @@ module ActiveMerchant
205
342
  [web_authentication_detail, client_detail, trasaction_detail]
206
343
  end
207
344
 
345
+ def build_party_node(name, party)
346
+ XmlNode.new(name) do |xml_node|
347
+ if party.account_number
348
+ xml_node << XmlNode.new('AccountNumber', party.account_number)
349
+ end
350
+
351
+ if party.contact
352
+ xml_node << XmlNode.new('Contact') do |c|
353
+ c << XmlNode.new('PersonName', party.contact.name)
354
+ c << XmlNode.new('Title', party.contact.title)
355
+ c << XmlNode.new('CompanyName', party.contact.company_name)
356
+ c << XmlNode.new('PhoneNumber', party.contact.phone_number)
357
+ c << XmlNode.new('FaxNumber', party.contact.fax_number)
358
+ c << XmlNode.new('EMailAddress', party.contact.email_address)
359
+ end
360
+ end
361
+
362
+
363
+ if party.location
364
+ xml_node << build_party_location_node('Address', party.location)
365
+ end
366
+ end
367
+ end
368
+
369
+ def build_party_location_node(name, location)
370
+ XmlNode.new(name) do |a|
371
+ if location.address1
372
+ a << XmlNode.new('StreetLines', location.address1)
373
+ end
374
+
375
+ if location.address2
376
+ a << XmlNode.new('StreetLines', location.address2)
377
+ end
378
+
379
+ a << XmlNode.new('City', location.city)
380
+ a << XmlNode.new('StateOrProvinceCode', location.state)
381
+ a << XmlNode.new('PostalCode', location.zip)
382
+ a << XmlNode.new('CountryCode', location.country.code(:alpha2))
383
+ end
384
+ end
385
+
208
386
  def build_location_node(name, location)
209
387
  location_node = XmlNode.new(name) do |xml_node|
210
388
  xml_node << XmlNode.new('Address') do |address_node|
@@ -17,7 +17,7 @@ module ActiveMerchant
17
17
  :track => 'ups.app/xml/Track'
18
18
  }
19
19
 
20
- PICKUP_CODES = {
20
+ PICKUP_CODES = HashWithIndifferentAccess.new({
21
21
  :daily_pickup => "01",
22
22
  :customer_counter => "03",
23
23
  :one_time_pickup => "06",
@@ -25,7 +25,25 @@ module ActiveMerchant
25
25
  :suggested_retail_rates => "11",
26
26
  :letter_center => "19",
27
27
  :air_service_center => "20"
28
- }
28
+ })
29
+
30
+ CUSTOMER_CLASSIFICATIONS = HashWithIndifferentAccess.new({
31
+ :wholesale => "01",
32
+ :occasional => "03",
33
+ :retail => "04"
34
+ })
35
+
36
+ # these are the defaults described in the UPS API docs,
37
+ # but they don't seem to apply them under all circumstances,
38
+ # so we need to take matters into our own hands
39
+ DEFAULT_CUSTOMER_CLASSIFICATIONS = Hash.new do |hash,key|
40
+ hash[key] = case key.to_sym
41
+ when :daily_pickup then :wholesale
42
+ when :customer_counter then :retail
43
+ else
44
+ :occasional
45
+ end
46
+ end
29
47
 
30
48
  DEFAULT_SERVICES = {
31
49
  "01" => "UPS Next Day Air",
@@ -127,11 +145,18 @@ module ActiveMerchant
127
145
  # not implemented: 'Rate' RequestOption to specify a single service query
128
146
  # request << XmlNode.new('RequestOption', ((options[:service].nil? or options[:service] == :all) ? 'Shop' : 'Rate'))
129
147
  end
130
- root_node << XmlNode.new('PickupType') do |pickup_type|
131
- pickup_type << XmlNode.new('Code', PICKUP_CODES[options[:pickup_type] || :daily_pickup])
148
+
149
+ pickup_type = options[:pickup_type] || :daily_pickup
150
+
151
+ root_node << XmlNode.new('PickupType') do |pickup_type_node|
152
+ pickup_type_node << XmlNode.new('Code', PICKUP_CODES[pickup_type])
132
153
  # not implemented: PickupType/PickupDetails element
133
154
  end
134
- # not implemented: CustomerClassification element
155
+ cc = options[:customer_classification] || DEFAULT_CUSTOMER_CLASSIFICATIONS[pickup_type]
156
+ root_node << XmlNode.new('CustomerClassification') do |cc_node|
157
+ cc_node << XmlNode.new('Code', CUSTOMER_CLASSIFICATIONS[cc])
158
+ end
159
+
135
160
  root_node << XmlNode.new('Shipment') do |shipment|
136
161
  # not implemented: Shipment/Description element
137
162
  shipment << build_location_node('Shipper', (options[:shipper] || origin), options)
@@ -150,7 +175,6 @@ module ActiveMerchant
150
175
  # * Shipment/DocumentsOnly element
151
176
 
152
177
  packages.each do |package|
153
- debugger if package.nil?
154
178
 
155
179
 
156
180
  imperial = ['US','LR','MM'].include?(origin.country_code(:alpha2))
@@ -342,7 +366,7 @@ module ActiveMerchant
342
366
  end
343
367
 
344
368
  def response_message(xml)
345
- xml.get_text('/*/Response/ResponseStatusDescription | /*/Response/Error/ErrorDescription').to_s
369
+ xml.get_text('/*/Response/Error/ErrorDescription | /*/Response/ResponseStatusDescription').to_s
346
370
  end
347
371
 
348
372
  def commit(action, request, test = false)
@@ -0,0 +1,18 @@
1
+ module ActiveMerchant
2
+ module Shipping
3
+ class Contact
4
+ attr_accessor :name
5
+ attr_accessor :title
6
+ attr_accessor :company_name
7
+ attr_accessor :phone_number
8
+ attr_accessor :fax_number
9
+ attr_accessor :email_address
10
+
11
+ def initialize(attrs = {})
12
+ attrs.each do |key, value|
13
+ self.send("#{key}=", value) if self.respond_to?("#{key}=")
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,31 @@
1
+ module ActiveMerchant
2
+ module Shipping
3
+ class Label
4
+ FEDEX_FORMATS = [
5
+ 'COMMON2D',
6
+ 'LABEL_DATA_ONLY'
7
+ ]
8
+
9
+ FEDEX_IMAGE_TYPES = [
10
+ 'DPL',
11
+ 'EPL2',
12
+ 'PDF',
13
+ 'PNG',
14
+ 'ZPLII'
15
+ ]
16
+
17
+ attr_accessor :format_type
18
+ attr_accessor :image_type
19
+ attr_accessor :image
20
+
21
+ def initialize(attrs = {})
22
+ attrs.each do |key, value|
23
+ self.send("#{key}=", value) if self.respond_to?("#{key}=")
24
+ end
25
+
26
+ self.image_type ||= 'PNG'
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -19,6 +19,9 @@ module ActiveMerchant #:nodoc:
19
19
  alias_method :state, :province
20
20
  alias_method :territory, :province
21
21
  alias_method :region, :province
22
+
23
+ attr_accessor :valid
24
+ attr_accessor :score
22
25
 
23
26
  def initialize(options = {})
24
27
  @country = (options[:country].nil? or options[:country].is_a?(ActiveMerchant::Country)) ?
@@ -97,4 +100,4 @@ module ActiveMerchant #:nodoc:
97
100
  end
98
101
 
99
102
  end
100
- end
103
+ end
@@ -0,0 +1,15 @@
1
+ module ActiveMerchant
2
+ module Shipping
3
+ class Party
4
+ attr_accessor :location
5
+ attr_accessor :contact
6
+ attr_accessor :account_number
7
+
8
+ def initialize(attrs = {})
9
+ attrs.each do |key, value|
10
+ self.send("#{key}=", value) if self.respond_to?("#{key}=")
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ module ActiveMerchant
2
+ module Shipping
3
+ class ReturnShipment < Shipment
4
+ attr_accessor :rma_number
5
+ attr_reader :return_type
6
+ def initialize(opts = {})
7
+ super
8
+ self.rma_number = opts[:rma_number]
9
+ self.payment_type ||= 'RECIPIENT'
10
+ @return_type = opts[:return_type] || 'PRINT_RETURN_LABEL'
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,73 @@
1
+ module ActiveMerchant
2
+ module Shipping
3
+ class Shipment
4
+ include ActiveMerchant::Shipping
5
+
6
+ FEDEX_PAYMENT_TYPES = [
7
+ 'COLLECT',
8
+ 'RECIPIENT',
9
+ 'SENDER',
10
+ 'THIRD_PARTY'
11
+ ]
12
+
13
+ FEDEX_DROPOFF_TYPES = [
14
+ "REGULAR_PICKUP",
15
+ "REQUEST_COURIER",
16
+ "DROP_BOX",
17
+ "BUSINESS_SERVICE_CENTER",
18
+ "STATION"
19
+ ]
20
+
21
+ FEDEX_RATE_REQUEST_TYPES = [
22
+ "ACCOUNT",
23
+ "LIST"
24
+ ]
25
+
26
+ attr_accessor :ship_at
27
+ attr_accessor :service
28
+ attr_accessor :packaging_type
29
+ attr_accessor :shipper
30
+ attr_accessor :total_insured_amount
31
+ attr_accessor :total_insured_currency
32
+ attr_accessor :recipient
33
+ attr_accessor :payment_type
34
+ attr_accessor :special_services
35
+ attr_accessor :label
36
+ attr_accessor :requested_packages
37
+ attr_accessor :dropoff_type
38
+ attr_accessor :rate_request_type
39
+ attr_accessor :package_count
40
+ attr_accessor :total_weight_value
41
+ attr_accessor :total_weight_units
42
+ attr_accessor :payor_account_number
43
+
44
+ attr_accessor :tracking_number
45
+ attr_accessor :transit_time
46
+
47
+ attr_reader :payor_account_country
48
+
49
+ def initialize(attrs = {})
50
+ attrs.each do |key, value|
51
+ self.send("#{key}=", value) if self.respond_to?("#{key}=")
52
+ end
53
+
54
+ self.label ||= Label.new(:format_type => 'COMMON2D')
55
+ self.requested_packages ||= 1
56
+ self.dropoff_type ||= 'REGULAR_PICKUP'
57
+ self.service ||= 'FEDEX_GROUND'
58
+ self.packaging_type ||= 'YOUR_PACKAGING'
59
+ self.ship_at ||= Time.now
60
+ self.package_count ||= 1
61
+ self.rate_request_type ||= 'ACCOUNT'
62
+ self.total_insured_currency ||= 'USD' if self.total_insured_amount
63
+ self.total_weight_units ||= 'LB' if self.total_weight_value
64
+ end
65
+ end
66
+
67
+ def payor_account_country=(c)
68
+ @payor_account_country = (c.nil? || c.is_a?(ActiveMerchant::Country)) ?
69
+ c : ActiveMerchant::Country.find(c)
70
+ @payor_account_country
71
+ end
72
+ end
73
+ end
@@ -1,6 +1,6 @@
1
1
  $: << File.dirname(__FILE__)
2
2
  require 'rubygems'
3
- require 'activesupport'
3
+ require 'active_support'
4
4
  require 'bigdecimal'
5
5
 
6
6
  require 'quantified/attribute'
@@ -5,8 +5,8 @@ ups:
5
5
  login: UPSDotComLogin
6
6
  password: UPSDotComPassword
7
7
  fedex:
8
- login: FedExAccountNumber
9
- password: FedExMeterNumber
8
+ login: FEDEXAccountNumber
9
+ password: FEDEXMeterNumber
10
10
  test: true
11
11
  shipwire:
12
12
  login: EmailAddress
@@ -0,0 +1,29 @@
1
+ class PartyFactory
2
+ include ActiveMerchant::Shipping
3
+ def self.build(carrier = :fedex, attrs = {})
4
+ default_location = Location.new(
5
+ :country => 'US',
6
+ :state => 'MA',
7
+ :address1 => '4 Yawkey Way',
8
+ :city => 'Boston',
9
+ :state => 'MA',
10
+ :zip => '02215'
11
+ )
12
+
13
+ default_contact = Contact.new(
14
+ :name => 'John Smith',
15
+ :company => 'Red Sox',
16
+ :phone_number => '1-555-867-5309',
17
+ :fax_number => '1-555-867-5310',
18
+ :email_address => 'user@example.com'
19
+ )
20
+
21
+ default_attrs = {
22
+ :location => default_location,
23
+ :contact => default_contact,
24
+ :account_number => '5555555'
25
+ }
26
+
27
+ Party.new(default_attrs.merge(attrs))
28
+ end
29
+ end
@@ -5,8 +5,12 @@ class FedExTest < Test::Unit::TestCase
5
5
  def setup
6
6
  @packages = TestFixtures.packages
7
7
  @locations = TestFixtures.locations
8
- @carrier = FedEx.new(fixtures(:fedex))
9
- FedEx.logger = Logger.new('/Users/james/.active_merchant/fedex.log')
8
+ @carrier = FedEx.new(fixtures(:fedex).merge(:test => true))
9
+ #FedEx.logger = Logger.new('/Users/james/.active_merchant/fedex.log')
10
+ end
11
+
12
+ def test_valid_credentials
13
+ assert @carrier.valid_credentials?
10
14
  end
11
15
 
12
16
  def test_us_to_canada
@@ -15,8 +19,7 @@ class FedExTest < Test::Unit::TestCase
15
19
  response = @carrier.find_rates(
16
20
  @locations[:beverly_hills],
17
21
  @locations[:ottawa],
18
- @packages.values_at(:wii),
19
- :test => true
22
+ @packages.values_at(:wii)
20
23
  )
21
24
  assert !response.rates.blank?
22
25
  response.rates.each do |rate|
@@ -31,8 +34,7 @@ class FedExTest < Test::Unit::TestCase
31
34
  @carrier.find_rates(
32
35
  Location.new(:zip => 40524),
33
36
  Location.new(:zip => 40515),
34
- @packages[:wii],
35
- :test => true
37
+ @packages[:wii]
36
38
  )
37
39
  rescue ResponseError => e
38
40
  assert_match /country\s?code/i, e.message
@@ -45,8 +47,7 @@ class FedExTest < Test::Unit::TestCase
45
47
  response = @carrier.find_rates(
46
48
  @locations[:bare_beverly_hills],
47
49
  @locations[:bare_ottawa],
48
- @packages.values_at(:wii),
49
- :test => true
50
+ @packages.values_at(:wii)
50
51
  )
51
52
 
52
53
  assert response.rates.size > 0
@@ -57,8 +58,7 @@ class FedExTest < Test::Unit::TestCase
57
58
  response = @carrier.find_rates(
58
59
  @locations[:bare_beverly_hills],
59
60
  Location.new(:country => 'CA'),
60
- @packages.values_at(:wii),
61
- :test => true
61
+ @packages.values_at(:wii)
62
62
  )
63
63
  rescue ResponseError => e
64
64
  assert_match /postal code/i, e.message
@@ -71,8 +71,7 @@ class FedExTest < Test::Unit::TestCase
71
71
  response = @carrier.find_rates(
72
72
  @locations[:bare_beverly_hills],
73
73
  Location.new(:country => 'JP', :zip => '108-8361'),
74
- @packages.values_at(:wii),
75
- :test => true
74
+ @packages.values_at(:wii)
76
75
  )
77
76
  rescue ResponseError => e
78
77
  assert_match /postal code/i, e.message
@@ -86,8 +85,7 @@ class FedExTest < Test::Unit::TestCase
86
85
  response = @carrier.find_rates(
87
86
  @locations[:ottawa],
88
87
  @locations[:beverly_hills],
89
- @packages.values_at(:book, :wii),
90
- :test => true
88
+ @packages.values_at(:book, :wii)
91
89
  )
92
90
  assert !response.rates.blank?
93
91
  response.rates.each do |rate|
@@ -103,8 +101,7 @@ class FedExTest < Test::Unit::TestCase
103
101
  response = @carrier.find_rates(
104
102
  @locations[:ottawa],
105
103
  @locations[:london],
106
- @packages.values_at(:book, :wii),
107
- :test => true
104
+ @packages.values_at(:book, :wii)
108
105
  )
109
106
  assert !response.rates.blank?
110
107
  response.rates.each do |rate|
@@ -120,8 +117,7 @@ class FedExTest < Test::Unit::TestCase
120
117
  response = @carrier.find_rates(
121
118
  @locations[:beverly_hills],
122
119
  @locations[:london],
123
- @packages.values_at(:book, :wii),
124
- :test => true
120
+ @packages.values_at(:book, :wii)
125
121
  )
126
122
  assert !response.rates.blank?
127
123
  response.rates.each do |rate|
@@ -137,4 +133,28 @@ class FedExTest < Test::Unit::TestCase
137
133
  end
138
134
  end
139
135
 
140
- end
136
+ def test_return_label
137
+ shipment = ShipmentFactory.build
138
+ shipment.shipper.account_number = fixtures(:fedex)[:account]
139
+ shipment.payor_account_number = fixtures(:fedex)[:account]
140
+ shipment.payor_account_country = 'US'
141
+ shipment.label.image_type = 'PDF'
142
+ @carrier.get_return_label(shipment, :test => true)
143
+ assert_not_nil shipment.label.image
144
+ assert_not_nil shipment.tracking_number
145
+ end
146
+
147
+ def test_address_validation
148
+ party = PartyFactory.build
149
+ @carrier.validate_location(party.location, :test => true)
150
+ assert party.location.valid
151
+ assert_equal 100, party.location.score
152
+ end
153
+
154
+ def test_address_validation_with_bunk_address
155
+ party = PartyFactory.build
156
+ party.location.stubs(:address1).returns('44 Foeawrfsadfasd Street')
157
+ @carrier.validate_location(party.location, :test => true)
158
+ assert !party.location.valid
159
+ end
160
+ end
@@ -114,6 +114,26 @@ class UPSTest < Test::Unit::TestCase
114
114
  end
115
115
  end
116
116
 
117
+ def test_us_to_uk_with_different_pickup_types
118
+ assert_nothing_raised do
119
+ daily_response = @carrier.find_rates(
120
+ @locations[:beverly_hills],
121
+ @locations[:london],
122
+ @packages.values_at(:book, :wii),
123
+ :pickup_type => :daily_pickup,
124
+ :test => true
125
+ )
126
+ one_time_response = @carrier.find_rates(
127
+ @locations[:beverly_hills],
128
+ @locations[:london],
129
+ @packages.values_at(:book, :wii),
130
+ :pickup_type => :one_time_pickup,
131
+ :test => true
132
+ )
133
+ assert_not_equal daily_response.rates.map(&:price), one_time_response.rates.map(&:price)
134
+ end
135
+ end
136
+
117
137
  def test_bare_packages
118
138
  response = nil
119
139
  p = Package.new(0,0)
@@ -0,0 +1,27 @@
1
+ class ShipmentFactory
2
+ include ActiveMerchant::Shipping
3
+
4
+ def self.build(carrier = :fedex)
5
+ shipment = ReturnShipment.new
6
+ if carrier == :fedex
7
+ shipment.ship_at = Time.now
8
+ shipment.service = 'FEDEX_GROUND'
9
+ shipment.payment_type = 'RECIPIENT'
10
+ shipment.packaging_type = FedEx::PackageTypes['your_packaging']
11
+ shipment.recipient = PartyFactory.build(:fedex)
12
+ jillians_boston = Location.new(
13
+ :address1 => '145 Ipswitch Street',
14
+ :city => 'Boston',
15
+ :state => 'MA',
16
+ :zip => '02215',
17
+ :country => 'US'
18
+ )
19
+ shipment.shipper = PartyFactory.build(:fedex, :location => jillians_boston)
20
+ shipment.total_weight_value = 10
21
+ shipment.payment_type = 'SENDER'
22
+ shipment.total_weight_units = 'LB'
23
+ end
24
+
25
+ shipment
26
+ end
27
+ end
data/test/test_helper.rb CHANGED
@@ -1,10 +1,14 @@
1
1
  #!/usr/bin/env ruby
2
2
  $:.unshift(File.dirname(__FILE__) + '/../lib')
3
+ $:.unshift(File.dirname(__FILE__))
3
4
 
4
5
  require 'test/unit'
5
6
  require 'active_shipping'
6
7
  require 'mocha'
7
8
 
9
+ require 'shipment_factory'
10
+ require 'party_factory'
11
+
8
12
  module Test
9
13
  module Unit
10
14
  class TestCase
@@ -164,4 +168,4 @@ module ActiveMerchant
164
168
 
165
169
  end
166
170
  end
167
- end
171
+ end
@@ -0,0 +1,20 @@
1
+ require 'test_helper'
2
+
3
+ class ActiveMerchant::Shipping::PartyTest < Test::Unit::TestCase
4
+ include ActiveMerchant::Shipping
5
+ def setup
6
+ @party = PartyFactory.build(:fedex)
7
+ end
8
+
9
+ def test_has_location
10
+ assert_not_nil @party.location
11
+ end
12
+
13
+ def test_has_contact
14
+ assert_not_nil @party.contact
15
+ end
16
+
17
+ def test_has_account_number
18
+ assert_not_nil @party.account_number
19
+ end
20
+ end
@@ -0,0 +1,43 @@
1
+ require 'test_helper'
2
+
3
+ class ShipmentTest < Test::Unit::TestCase
4
+ def setup
5
+ @shipment = ShipmentFactory.build(:fedex)
6
+ end
7
+
8
+ def test_should_have_ship_at
9
+ assert_not_nil @shipment.ship_at
10
+ end
11
+
12
+ def test_should_have_service
13
+ assert_not_nil @shipment.service
14
+ end
15
+
16
+ def test_should_have_valid_service
17
+ end
18
+
19
+ def test_should_have_packaging_type
20
+ assert_not_nil @shipment.packaging_type
21
+ end
22
+
23
+ def test_should_have_shipper
24
+ assert_not_nil @shipment.shipper
25
+ end
26
+
27
+ def test_should_have_recipient
28
+ assert_not_nil @shipment.recipient
29
+ end
30
+
31
+ def test_should_have_payment_type
32
+ assert_not_nil @shipment.payment_type
33
+ end
34
+
35
+ def test_should_have_label
36
+ assert_not_nil @shipment.label
37
+ end
38
+
39
+ def test_should_have_requested_packages
40
+ assert_not_nil @shipment.requested_packages
41
+ end
42
+
43
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_shipping
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James MacAulay
@@ -12,7 +12,7 @@ autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
14
 
15
- date: 2009-11-11 00:00:00 -05:00
15
+ date: 2010-01-21 00:00:00 -05:00
16
16
  default_executable:
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
@@ -59,11 +59,16 @@ files:
59
59
  - lib/active_shipping/shipping/carriers/shipwire.rb
60
60
  - lib/active_shipping/shipping/carriers/ups.rb
61
61
  - lib/active_shipping/shipping/carriers/usps.rb
62
+ - lib/active_shipping/shipping/contact.rb
63
+ - lib/active_shipping/shipping/label.rb
62
64
  - lib/active_shipping/shipping/location.rb
63
65
  - lib/active_shipping/shipping/package.rb
66
+ - lib/active_shipping/shipping/party.rb
64
67
  - lib/active_shipping/shipping/rate_estimate.rb
65
68
  - lib/active_shipping/shipping/rate_response.rb
66
69
  - lib/active_shipping/shipping/response.rb
70
+ - lib/active_shipping/shipping/return_shipment.rb
71
+ - lib/active_shipping/shipping/shipment.rb
67
72
  - lib/active_shipping/shipping/shipment_event.rb
68
73
  - lib/active_shipping/shipping/tracking_response.rb
69
74
  - lib/certs/cacert.pem
@@ -86,7 +91,7 @@ files:
86
91
  - lib/vendor/xml_node/lib/xml_node.rb
87
92
  - lib/vendor/xml_node/test/test_generating.rb
88
93
  - lib/vendor/xml_node/test/test_parsing.rb
89
- - test/fixtures.yml
94
+ - test/fixtures.example.yml
90
95
  - test/fixtures/xml/fedex/ottawa_to_beverly_hills_rate_request.xml
91
96
  - test/fixtures/xml/fedex/ottawa_to_beverly_hills_rate_response.xml
92
97
  - test/fixtures/xml/fedex/tracking_request.xml
@@ -104,10 +109,12 @@ files:
104
109
  - test/fixtures/xml/usps/beverly_hills_to_ottawa_wii_rate_response.xml
105
110
  - test/fixtures/xml/usps/example_tracking_response.xml
106
111
  - test/fixtures/xml/usps/multi_tracking_example.xml
112
+ - test/party_factory.rb
107
113
  - test/remote/fedex_test.rb
108
114
  - test/remote/shipwire_test.rb
109
115
  - test/remote/ups_test.rb
110
116
  - test/remote/usps_test.rb
117
+ - test/shipment_factory.rb
111
118
  - test/test_helper.rb
112
119
  - test/unit/base_test.rb
113
120
  - test/unit/carriers/fedex_test.rb
@@ -116,7 +123,9 @@ files:
116
123
  - test/unit/carriers/usps_test.rb
117
124
  - test/unit/location_test.rb
118
125
  - test/unit/package_test.rb
126
+ - test/unit/party_test.rb
119
127
  - test/unit/response_test.rb
128
+ - test/unit/shipment_test.rb
120
129
  has_rdoc: true
121
130
  homepage: http://github.com/Shopify/active_shipping
122
131
  licenses: []
@@ -146,10 +155,12 @@ signing_key:
146
155
  specification_version: 3
147
156
  summary: Shipping API extension for Active Merchant.
148
157
  test_files:
158
+ - test/party_factory.rb
149
159
  - test/remote/fedex_test.rb
150
160
  - test/remote/shipwire_test.rb
151
161
  - test/remote/ups_test.rb
152
162
  - test/remote/usps_test.rb
163
+ - test/shipment_factory.rb
153
164
  - test/test_helper.rb
154
165
  - test/unit/base_test.rb
155
166
  - test/unit/carriers/fedex_test.rb
@@ -158,4 +169,6 @@ test_files:
158
169
  - test/unit/carriers/usps_test.rb
159
170
  - test/unit/location_test.rb
160
171
  - test/unit/package_test.rb
172
+ - test/unit/party_test.rb
161
173
  - test/unit/response_test.rb
174
+ - test/unit/shipment_test.rb