active_shipping 0.10.0 → 0.10.1

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/CHANGELOG CHANGED
@@ -1,3 +1,11 @@
1
+ ### v0.10.1
2
+ - Canada Post PWS: Makes wrapper act more consistently with the rest of the API [jnormore]
3
+ - UPS: Adds insurance charge to package object declarations [pbonnell]
4
+ - USPS: Improves how unavailable delivery information is handled [cyu]
5
+ - Shipment Packer: Prevents packing errors and consistently return an array when packing [christianblais]
6
+ - General: Improves tests such that they work with ruby 2.0 [Sirupsen]
7
+
8
+
1
9
  2011/04/21:
2
10
  * USPS updated to use new APIs [james]
3
11
  * new :gift boolean option for Package [james]
data/README.markdown CHANGED
@@ -122,6 +122,16 @@ After you've pushed your well-tested changes to your github fork, make a pull re
122
122
  * Cody Fauser (<http://codyfauser.com>)
123
123
  * Jimmy Baker (<http://jimmyville.com/>)
124
124
  * William Lang (<http://williamlang.net/>)
125
+ * Cameron Fowler
126
+ * Christopher Saunders (<http://christophersaunders.ca>)
127
+ * Denis Odorcic
128
+ * Dennis O'Connor
129
+ * Dennis Theisen
130
+ * Edward Ocampo-Gooding
131
+ * Isaac Kearse
132
+ * John Duff
133
+ * Nigel Ramsay
134
+ * Philip Arndt
125
135
 
126
136
  ## Legal Mumbo Jumbo
127
137
 
@@ -49,3 +49,4 @@ require 'active_shipping/shipping/shipment_event'
49
49
  require 'active_shipping/shipping/shipment_packer'
50
50
  require 'active_shipping/shipping/carrier'
51
51
  require 'active_shipping/shipping/carriers'
52
+ require 'active_shipping/shipping/errors'
@@ -237,6 +237,7 @@ module ActiveMerchant
237
237
  # rating
238
238
 
239
239
  def build_rates_request(origin, destination, line_items = [], options = {}, package = nil, services = [])
240
+ line_items = Array(line_items)
240
241
  xml = XmlNode.new('mailing-scenario', :xmlns => "http://www.canadapost.ca/ws/ship/rate") do |node|
241
242
  node << customer_number_node(options)
242
243
  node << contract_id_node(options)
@@ -329,9 +330,9 @@ module ActiveMerchant
329
330
  # :show_postage_rate
330
331
  # :cod, :cod_amount, :insurance, :insurance_amount, :signature_required, :pa18, :pa19, :hfp, :dns, :lad
331
332
  #
332
- def build_shipment_request(origin_hash, destination_hash, package, line_items = [], options = {})
333
- origin = Location.new(sanitize_zip(origin_hash))
334
- destination = Location.new(sanitize_zip(destination_hash))
333
+ def build_shipment_request(origin, destination, package, line_items = [], options = {})
334
+ origin = sanitize_location(origin)
335
+ destination = sanitize_location(destination)
335
336
 
336
337
  xml = XmlNode.new('non-contract-shipment', :xmlns => "http://www.canadapost.ca/ws/ncshipment") do |root_node|
337
338
  root_node << XmlNode.new('delivery-spec') do |node|
@@ -652,13 +653,13 @@ module ActiveMerchant
652
653
  end
653
654
  end
654
655
 
655
- def origin_node(location_hash)
656
- origin = Location.new(sanitize_zip(location_hash))
656
+ def origin_node(location)
657
+ origin = sanitize_location(location)
657
658
  XmlNode.new("origin-postal-code", origin.zip)
658
659
  end
659
660
 
660
- def destination_node(location_hash)
661
- destination = Location.new(sanitize_zip(location_hash))
661
+ def destination_node(location)
662
+ destination = sanitize_location(location)
662
663
  case destination.country_code
663
664
  when 'CA'
664
665
  XmlNode.new('destination') do |node|
@@ -739,6 +740,12 @@ module ActiveMerchant
739
740
  DateTime.strptime((options[:shipping_date] || Time.now).to_s, "%Y-%m-%d")
740
741
  end
741
742
 
743
+ def sanitize_location(location)
744
+ location_hash = location.is_a?(Location) ? location.to_hash : location
745
+ location_hash = sanitize_zip(location_hash)
746
+ Location.new(location_hash)
747
+ end
748
+
742
749
  def sanitize_zip(hash)
743
750
  [:postal_code, :zip].each do |attr|
744
751
  hash[attr].gsub!(/\s+/,'') if hash[attr]
@@ -265,7 +265,7 @@ module ActiveMerchant
265
265
  rate_estimates = []
266
266
  success, message = nil
267
267
 
268
- xml = REXML::Document.new(response)
268
+ xml = build_document(response)
269
269
  root_node = xml.elements['RateReply']
270
270
 
271
271
  success = response_success?(xml)
@@ -330,7 +330,7 @@ module ActiveMerchant
330
330
  end
331
331
 
332
332
  def parse_tracking_response(response, options)
333
- xml = REXML::Document.new(response)
333
+ xml = build_document(response)
334
334
  root_node = xml.elements['TrackReply']
335
335
 
336
336
  success = response_success?(xml)
@@ -462,6 +462,12 @@ module ActiveMerchant
462
462
 
463
463
  Location.new(args)
464
464
  end
465
+
466
+ def build_document(xml)
467
+ REXML::Document.new(xml)
468
+ rescue REXML::ParseException => e
469
+ raise ActiveMerchant::Shipping::ResponseContentError.new(e, xml)
470
+ end
465
471
  end
466
472
  end
467
473
  end
@@ -208,6 +208,9 @@ module ActiveMerchant
208
208
  package_weight << XmlNode.new("UnitOfMeasurement") do |units|
209
209
  units << XmlNode.new("Code", imperial ? 'LBS' : 'KGS')
210
210
  end
211
+ if package.value.present? && package.currency.present?
212
+ add_insured_node( package_node, currency:package.currency, value:(package.value.to_i/100) )
213
+ end
211
214
 
212
215
  value = ((imperial ? package.lbs : package.kgs).to_f*1000).round/1000.0 # 3 decimals
213
216
  package_weight << XmlNode.new("Weight", [value,0.1].max)
@@ -273,6 +276,21 @@ module ActiveMerchant
273
276
  end
274
277
  end
275
278
 
279
+ def add_insured_node(*args)
280
+ params, package_node = args.extract_options!, args[0]
281
+ currency, value = params[:currency], params[:value].to_i
282
+ package_node << XmlNode.new("PackageServiceOptions") do |package_service_options|
283
+ package_service_options << XmlNode.new("DeclaredValue") do |declared_value|
284
+ declared_value << XmlNode.new("CurrencyCode", currency)
285
+ declared_value << XmlNode.new("MonetaryValue", (value.to_i))
286
+ end
287
+ package_service_options << XmlNode.new("InsuredValue") do |declared_value|
288
+ declared_value << XmlNode.new("CurrencyCode", currency)
289
+ declared_value << XmlNode.new("MonetaryValue", (value.to_i))
290
+ end
291
+ end
292
+ end
293
+
276
294
  def parse_rate_response(origin, destination, packages, response, options={})
277
295
  rates = []
278
296
 
@@ -287,10 +305,10 @@ module ActiveMerchant
287
305
  service_code = rated_shipment.get_text('Service/Code').to_s
288
306
  days_to_delivery = rated_shipment.get_text('GuaranteedDaysToDelivery').to_s.to_i
289
307
  days_to_delivery = nil if days_to_delivery == 0
290
-
291
308
  rate_estimates << RateEstimate.new(origin, destination, @@name,
292
309
  service_name_for(origin, service_code),
293
310
  :total_price => rated_shipment.get_text('TotalCharges/MonetaryValue').to_s.to_f,
311
+ :insurance_price => rated_shipment.get_text('ServiceOptionsCharges/MonetaryValue').to_s.to_f,
294
312
  :currency => rated_shipment.get_text('TotalCharges/CurrencyCode').to_s,
295
313
  :service_code => service_code,
296
314
  :packages => packages,
@@ -125,6 +125,18 @@ module ActiveMerchant
125
125
  "WS" => "Western Samoa"
126
126
  }
127
127
 
128
+ STATUS_NODE_PATTERNS = %w(
129
+ */*/TrackSummary
130
+ Error/Description
131
+ */TrackInfo/Error/Description
132
+ )
133
+
134
+ RESPONSE_ERROR_MESSAGES = [
135
+ /There is no record of that mail item/,
136
+ /This Information has not been included in this Test Server\./,
137
+ /Delivery status information is not available/
138
+ ]
139
+
128
140
  def find_tracking_info(tracking_number, options={})
129
141
  options = @options.update(options)
130
142
  tracking_request = build_tracking_request(tracking_number, options)
@@ -584,12 +596,16 @@ module ActiveMerchant
584
596
  end
585
597
 
586
598
  def response_status_node(document)
587
- document.elements['*/*/TrackSummary'] || document.elements['Error/Description']
599
+ STATUS_NODE_PATTERNS.each do |pattern|
600
+ if node = document.elements[pattern]
601
+ return node
602
+ end
603
+ end
588
604
  end
589
605
 
590
606
  def response_success?(document)
591
607
  summary = response_status_node(document).get_text.to_s
592
- !(summary =~ /There is no record of that mail item/ || summary =~ /This Information has not been included in this Test Server\./)
608
+ !RESPONSE_ERROR_MESSAGES.detect { |re| summary =~ re }
593
609
  end
594
610
 
595
611
  def response_message(document)
@@ -0,0 +1,9 @@
1
+ module ActiveMerchant
2
+ module Shipping
3
+ class ResponseContentError < StandardError
4
+ def initialize(exception, content_body)
5
+ super("#{exception.message} \n\n#{content_body}")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -14,6 +14,7 @@ module ActiveMerchant #:nodoc:
14
14
  attr_reader :delivery_date # Usually only available for express shipments
15
15
  attr_reader :delivery_range # Min and max delivery estimate in days
16
16
  attr_reader :negotiated_rate
17
+ attr_reader :insurance_price
17
18
 
18
19
  def initialize(origin, destination, carrier, service_name, options={})
19
20
  @origin, @destination, @carrier, @service_name = origin, destination, carrier, service_name
@@ -29,6 +30,7 @@ module ActiveMerchant #:nodoc:
29
30
  @delivery_range = options[:delivery_range] ? options[:delivery_range].map { |date| date_for(date) }.compact : []
30
31
  @shipping_date = date_for(options[:shipping_date])
31
32
  @delivery_date = @delivery_range.last
33
+ @insurance_price = Package.cents_from(options[:insurance_price])
32
34
  end
33
35
 
34
36
  def total_price
@@ -10,8 +10,11 @@ module ActiveMerchant
10
10
  # maximum_weight - maximum weight in grams
11
11
  # currency - ISO currency code
12
12
  def self.pack(items, dimensions, maximum_weight, currency)
13
- items = items.map(&:symbolize_keys).map { |item| [item] * item[:quantity].to_i }.flatten
14
13
  packages = []
14
+
15
+ return packages if items.empty?
16
+
17
+ items = items.map(&:symbolize_keys).map { |item| [item] * item[:quantity].to_i }.flatten
15
18
  state = :package_empty
16
19
 
17
20
  while state != :packing_finished
@@ -1,3 +1,3 @@
1
1
  module ActiveShipping
2
- VERSION = "0.10.0"
2
+ VERSION = "0.10.1"
3
3
  end
@@ -1,6 +1,5 @@
1
1
  require 'rake'
2
2
  require 'rake/testtask'
3
- require 'rake/rdoctask'
4
3
 
5
4
  desc 'Default: run unit tests.'
6
5
  task :default => :test
@@ -8,14 +7,7 @@ task :default => :test
8
7
  desc 'Test the plugin.'
9
8
  Rake::TestTask.new(:test) do |t|
10
9
  t.libs << 'lib'
10
+ t.libs << 'test'
11
11
  t.pattern = 'test/**/*_test.rb'
12
12
  t.verbose = true
13
13
  end
14
-
15
- desc 'Generate documentation for the calculations plugin.'
16
- Rake::RDocTask.new(:rdoc) do |rdoc|
17
- rdoc.rdoc_dir = 'rdoc'
18
- rdoc.title = 'Quantified'
19
- rdoc.options << '--line-numbers --inline-source'
20
- rdoc.rdoc_files.include('lib/**/*.rb')
21
- end
@@ -38,6 +38,10 @@ module Quantified
38
38
  def system
39
39
  self.class.units_to_systems[unit]
40
40
  end
41
+
42
+ def coerce(other)
43
+ [other, self.amount]
44
+ end
41
45
 
42
46
  def method_missing(meth, *args)
43
47
  if args.size == 1 && self.class == (other = args.first).class
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/test_helper'
1
+ require 'test_helper'
2
2
  require 'quantified/length'
3
3
 
4
4
  class LengthTest < Test::Unit::TestCase
@@ -40,17 +40,15 @@ class LengthTest < Test::Unit::TestCase
40
40
  end
41
41
 
42
42
  def test_convert_yards_to_millimetres
43
- assert Length.new(914.4, :millimetres).eql?(Length.new(1, :yards).to_millimetres)
43
+ assert_in_epsilon Length.new(914.4, :millimetres).to_f, Length.new(1, :yards).to_millimetres.to_f
44
44
  end
45
45
 
46
46
  def test_convert_millimetres_to_yards
47
- assert Length.new(1, :yards).eql?(Length.new(914.4, :millimetres).to_yards)
47
+ assert_in_epsilon Length.new(1, :yards).to_f, Length.new(914.4, :millimetres).to_yards.to_f
48
48
  end
49
49
 
50
50
  def test_convert_metres_to_inches
51
- assert_equal 1.inches, (0.0254).metres.to_inches
52
- assert 1.inches.eql?((0.0254).metres.to_inches)
53
- assert 1.inches.eql?((0.0254).metres.in_inches)
51
+ assert_in_epsilon 1.inches.to_f, (0.0254).metres.to_inches.to_f
54
52
  end
55
53
 
56
54
  def test_comparison_with_numeric
@@ -89,4 +87,4 @@ class LengthTest < Test::Unit::TestCase
89
87
  assert_equal :metric, 2.centimetres.system
90
88
  assert_equal :imperial, 2.feet.system
91
89
  end
92
- end
90
+ end
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/test_helper'
1
+ require 'test_helper'
2
2
  require 'quantified/mass'
3
3
 
4
4
  class MassTest < Test::Unit::TestCase
@@ -85,4 +85,12 @@ class MassTest < Test::Unit::TestCase
85
85
  assert_equal [:grams, :milligrams, :kilograms], Mass.units(:metric)
86
86
  assert_equal [:ounces, :pounds, :stones, :short_tons], Mass.units(:imperial)
87
87
  end
88
- end
88
+
89
+ def test_right_side_comparison_with_fixnum
90
+ assert Mass.new(14, :grams) < 20
91
+ end
92
+
93
+ def test_left_side_comparison_with_fixnum
94
+ assert 20 > Mass.new(14, :grams)
95
+ end
96
+ end
@@ -1,4 +1,5 @@
1
1
  require 'test/unit'
2
+
2
3
  begin
3
4
  require 'active_support/inflector'
4
5
  rescue LoadError => e
@@ -8,3 +9,12 @@ rescue LoadError => e
8
9
  end
9
10
 
10
11
  require File.dirname(__FILE__) + '/../lib/quantified'
12
+
13
+
14
+ class Test::Unit::TestCase
15
+ EPSILON = 0.00001
16
+
17
+ def assert_in_epsilon(expected, actual, msg = nil)
18
+ assert_in_delta expected, actual, EPSILON, msg
19
+ end
20
+ end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: active_shipping
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.10.0
5
+ version: 0.10.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - James MacAulay
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2013-07-23 00:00:00.000000000 Z
15
+ date: 2013-08-23 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  prerelease: false
@@ -94,6 +94,22 @@ dependencies:
94
94
  - !ruby/object:Gem::Version
95
95
  version: 1.5.1
96
96
  none: false
97
+ - !ruby/object:Gem::Dependency
98
+ prerelease: false
99
+ name: minitest
100
+ type: :development
101
+ version_requirements: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ~>
104
+ - !ruby/object:Gem::Version
105
+ version: 4.7.5
106
+ none: false
107
+ requirement: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ~>
110
+ - !ruby/object:Gem::Version
111
+ version: 4.7.5
112
+ none: false
97
113
  - !ruby/object:Gem::Dependency
98
114
  prerelease: false
99
115
  name: rake
@@ -116,15 +132,15 @@ dependencies:
116
132
  type: :development
117
133
  version_requirements: !ruby/object:Gem::Requirement
118
134
  requirements:
119
- - - ! '>='
135
+ - - ~>
120
136
  - !ruby/object:Gem::Version
121
- version: '0'
137
+ version: 0.14.0
122
138
  none: false
123
139
  requirement: !ruby/object:Gem::Requirement
124
140
  requirements:
125
- - - ! '>='
141
+ - - ~>
126
142
  - !ruby/object:Gem::Version
127
- version: '0'
143
+ version: 0.14.0
128
144
  none: false
129
145
  - !ruby/object:Gem::Dependency
130
146
  prerelease: false
@@ -179,6 +195,7 @@ files:
179
195
  - lib/active_shipping/shipping/carriers/usps.rb
180
196
  - lib/active_shipping/shipping/carriers/usps.rb.orig
181
197
  - lib/active_shipping/shipping/carriers.rb
198
+ - lib/active_shipping/shipping/errors.rb
182
199
  - lib/active_shipping/shipping/location.rb
183
200
  - lib/active_shipping/shipping/package.rb
184
201
  - lib/active_shipping/shipping/rate_estimate.rb
@@ -225,7 +242,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
225
242
  - !ruby/object:Gem::Version
226
243
  segments:
227
244
  - 0
228
- hash: -3915278247980377542
245
+ hash: 4495588430750097686
229
246
  version: '0'
230
247
  none: false
231
248
  required_rubygems_version: !ruby/object:Gem::Requirement