active_shipping 0.9.13 → 0.9.14

Sign up to get free protection for your applications and to get access to all the features.
@@ -37,7 +37,7 @@ module ActiveMerchant
37
37
  :items => [ { :sku => '', :quantity => 1 } ]
38
38
  )
39
39
  rescue ActiveMerchant::Shipping::ResponseError => e
40
- e.message != "Could not verify e-mail/password combination"
40
+ e.message != "Could not verify Username/EmailAddress and Password combination"
41
41
  end
42
42
 
43
43
  private
@@ -113,9 +113,11 @@ module ActiveMerchant
113
113
  def build_rate_estimates(response, origin, destination)
114
114
  response["rates"].collect do |quote|
115
115
  RateEstimate.new(origin, destination, carrier_for(quote["service"]), quote["service"],
116
- :service_code => quote["method"],
117
- :total_price => quote["cost"],
118
- :currency => quote["currency"]
116
+ :service_code => quote["method"],
117
+ :total_price => quote["cost"],
118
+ :currency => quote["currency"],
119
+ :delivery_range => [ timestamp_from_business_day(quote["delivery_min"]),
120
+ timestamp_from_business_day(quote["delivery_max"]) ]
119
121
  )
120
122
  end
121
123
  end
@@ -139,6 +141,10 @@ module ActiveMerchant
139
141
  rate["service"] = parse_child_text(e, "Service")
140
142
  rate["cost"] = parse_child_text(e, "Cost")
141
143
  rate["currency"] = parse_child_attribute(e, "Cost", "currency")
144
+ if delivery_estimate = e.elements["DeliveryEstimate"]
145
+ rate["delivery_min"] = parse_child_text(delivery_estimate, "Minimum").to_i
146
+ rate["delivery_max"] = parse_child_text(delivery_estimate, "Maximum").to_i
147
+ end
142
148
  response["rates"] << rate
143
149
  end
144
150
 
@@ -166,7 +172,18 @@ module ActiveMerchant
166
172
  if element = parent.elements[name]
167
173
  element.attributes[attribute]
168
174
  end
169
- end
175
+ end
176
+
177
+ def timestamp_from_business_day(days)
178
+ return unless days
179
+ date = DateTime.now
180
+ days.times do
181
+ begin
182
+ date = date + 1
183
+ end until ![0,6].include?(date.wday)
184
+ end
185
+ date
186
+ end
170
187
  end
171
188
  end
172
- end
189
+ end
@@ -10,7 +10,7 @@ module ActiveMerchant
10
10
  @@name = "UPS"
11
11
 
12
12
  TEST_URL = 'https://wwwcie.ups.com'
13
- LIVE_URL = 'https://www.ups.com'
13
+ LIVE_URL = 'https://onlinetools.ups.com'
14
14
 
15
15
  RESOURCES = {
16
16
  :rates => 'ups.app/xml/Rate',
@@ -275,12 +275,16 @@ module ActiveMerchant
275
275
 
276
276
  xml.elements.each('/*/RatedShipment') do |rated_shipment|
277
277
  service_code = rated_shipment.get_text('Service/Code').to_s
278
+ days_to_delivery = rated_shipment.get_text('GuaranteedDaysToDelivery').to_s.to_i
279
+ delivery_date = days_to_delivery >= 1 ? days_to_delivery.days.from_now.strftime("%Y-%m-%d") : nil
280
+
278
281
  rate_estimates << RateEstimate.new(origin, destination, @@name,
279
282
  service_name_for(origin, service_code),
280
283
  :total_price => rated_shipment.get_text('TotalCharges/MonetaryValue').to_s.to_f,
281
284
  :currency => rated_shipment.get_text('TotalCharges/CurrencyCode').to_s,
282
285
  :service_code => service_code,
283
- :packages => packages)
286
+ :packages => packages,
287
+ :delivery_range => [delivery_date])
284
288
  end
285
289
  end
286
290
  RateResponse.new(success, message, Hash.from_xml(response).values.first, :rates => rate_estimates, :xml => response, :request => last_request)
@@ -387,4 +391,4 @@ module ActiveMerchant
387
391
 
388
392
  end
389
393
  end
390
- end
394
+ end
@@ -14,13 +14,15 @@ module ActiveMerchant #:nodoc:
14
14
  :address3,
15
15
  :phone,
16
16
  :fax,
17
- :address_type
17
+ :address_type,
18
+ :company_name
18
19
 
19
20
  alias_method :zip, :postal_code
20
21
  alias_method :postal, :postal_code
21
22
  alias_method :state, :province
22
23
  alias_method :territory, :province
23
24
  alias_method :region, :province
25
+ alias_method :company, :company_name
24
26
 
25
27
  def initialize(options = {})
26
28
  @country = (options[:country].nil? or options[:country].is_a?(ActiveMerchant::Country)) ?
@@ -35,12 +37,9 @@ module ActiveMerchant #:nodoc:
35
37
  @address3 = options[:address3]
36
38
  @phone = options[:phone]
37
39
  @fax = options[:fax]
38
- if options[:address_type].present?
39
- @address_type = options[:address_type].to_s
40
- unless ADDRESS_TYPES.include?(@address_type)
41
- raise ArgumentError.new("address_type must be one of #{ADDRESS_TYPES.map(&:inspect).join(', ')}")
42
- end
43
- end
40
+ @company_name = options[:company_name] || options[:company]
41
+
42
+ self.address_type = options[:address_type]
44
43
  end
45
44
 
46
45
  def self.from(object, options={})
@@ -56,7 +55,8 @@ module ActiveMerchant #:nodoc:
56
55
  :address3 => [:address3],
57
56
  :phone => [:phone, :phone_number],
58
57
  :fax => [:fax, :fax_number],
59
- :address_type => [:address_type]
58
+ :address_type => [:address_type],
59
+ :company_name => [:company, :company_name]
60
60
  }
61
61
  attributes = {}
62
62
  hash_access = begin
@@ -84,7 +84,35 @@ module ActiveMerchant #:nodoc:
84
84
  def residential?; @address_type == 'residential' end
85
85
  def commercial?; @address_type == 'commercial' end
86
86
  def po_box?; @address_type == 'po_box' end
87
-
87
+
88
+ def address_type=(value)
89
+ return unless value.present?
90
+ raise ArgumentError.new("address_type must be one of #{ADDRESS_TYPES.join(', ')}") unless ADDRESS_TYPES.include?(value.to_s)
91
+ @address_type = value.to_s
92
+ end
93
+
94
+ def to_hash
95
+ {
96
+ :country => country_code,
97
+ :postal_code => postal_code,
98
+ :province => province,
99
+ :city => city,
100
+ :name => name,
101
+ :address1 => address1,
102
+ :address2 => address2,
103
+ :address3 => address3,
104
+ :phone => phone,
105
+ :fax => fax,
106
+ :address_type => address_type,
107
+ :company_name => company_name
108
+ }
109
+ end
110
+
111
+ def to_xml(options={})
112
+ options[:root] ||= "location"
113
+ to_hash.to_xml(options)
114
+ end
115
+
88
116
  def to_s
89
117
  prettyprint.gsub(/\n/, ' ')
90
118
  end
@@ -106,4 +134,4 @@ module ActiveMerchant #:nodoc:
106
134
  end
107
135
 
108
136
  end
109
- end
137
+ end
@@ -98,9 +98,9 @@ module ActiveMerchant #:nodoc:
98
98
  else
99
99
  case money
100
100
  when Float
101
- (money * 100).to_i
101
+ (money * 100).round
102
102
  when String
103
- money =~ /\./ ? (money.to_f * 100).to_i : money.to_i
103
+ money =~ /\./ ? (money.to_f * 100).round : money.to_i
104
104
  else
105
105
  money.to_i
106
106
  end
@@ -144,4 +144,4 @@ module ActiveMerchant #:nodoc:
144
144
 
145
145
  end
146
146
  end
147
- end
147
+ end
@@ -11,6 +11,7 @@ module ActiveMerchant #:nodoc:
11
11
  attr_reader :currency # 'USD', 'CAD', etc.
12
12
  # http://en.wikipedia.org/wiki/ISO_4217
13
13
  attr_reader :delivery_date # Usually only available for express shipments
14
+ attr_reader :delivery_range # Min and max delivery estimate in days
14
15
 
15
16
  def initialize(origin, destination, carrier, service_name, options={})
16
17
  @origin, @destination, @carrier, @service_name = origin, destination, carrier, service_name
@@ -22,9 +23,10 @@ module ActiveMerchant #:nodoc:
22
23
  end
23
24
  @total_price = Package.cents_from(options[:total_price])
24
25
  @currency = options[:currency]
25
- @delivery_date = options[:delivery_date]
26
+ @delivery_range = options[:delivery_range] ? options[:delivery_range].map { |date| date_for(date) }.compact : []
27
+ @delivery_date = @delivery_range.last
26
28
  end
27
-
29
+
28
30
  def total_price
29
31
  begin
30
32
  @total_price || @package_rates.sum {|p| p[:rate]}
@@ -48,7 +50,13 @@ module ActiveMerchant #:nodoc:
48
50
  def package_count
49
51
  package_rates.length
50
52
  end
51
-
53
+
54
+ private
55
+ def date_for(date)
56
+ date && DateTime.strptime(date.to_s, "%Y-%m-%d")
57
+ rescue ArgumentError
58
+ nil
59
+ end
52
60
  end
53
61
  end
54
62
  end
@@ -0,0 +1,48 @@
1
+ module ActiveMerchant
2
+ module Shipping
3
+ class ShipmentPacker
4
+ class OverweightItem < StandardError
5
+ end
6
+
7
+ # items - array of hashes containing quantity, grams and price.
8
+ # ex. [{:quantity => 2, :price => 1.0, :grams => 50}]
9
+ # dimensions - [5.0, 15.0, 30.0]
10
+ # maximum_weight - maximum weight in grams
11
+ # currency - ISO currency code
12
+ def self.pack(items, dimensions, maximum_weight, currency)
13
+ items = items.map(&:symbolize_keys).map { |item| [item] * item[:quantity].to_i }.flatten
14
+ packages = []
15
+ state = :package_empty
16
+
17
+ while state != :packing_finished
18
+ case state
19
+ when :package_empty
20
+ package_weight, package_value = 0, 0
21
+ state = :filling_package
22
+ when :filling_package
23
+ item = items.shift
24
+ item_weight, item_price = item[:grams].to_i, Package.cents_from(item[:price])
25
+
26
+ if item_weight > maximum_weight
27
+ raise OverweightItem, "The item with weight of #{item_weight}g is heavier than the allowable package weight of #{maximum_weight}g"
28
+ end
29
+
30
+ if (package_weight + item_weight) <= maximum_weight
31
+ package_weight += item_weight
32
+ package_value += item_price
33
+ state = :package_full if items.empty?
34
+ else
35
+ items.unshift(item)
36
+ state = :package_full
37
+ end
38
+ when :package_full
39
+ packages << ActiveMerchant::Shipping::Package.new(package_weight, dimensions, :value => package_value, :currency => currency)
40
+ state = items.any? ? :package_empty : :packing_finished
41
+ end
42
+ end
43
+
44
+ packages
45
+ end
46
+ end
47
+ end
48
+ end
@@ -1,3 +1,3 @@
1
1
  module ActiveShipping
2
- VERSION = "0.9.13"
3
- end
2
+ VERSION = "0.9.14"
3
+ end
@@ -1,8 +1,6 @@
1
1
  $: << File.dirname(__FILE__)
2
-
3
- require 'active_support/all'
4
2
  require 'bigdecimal'
5
3
 
6
4
  require 'quantified/attribute'
7
5
  require 'quantified/mass'
8
- require 'quantified/length'
6
+ require 'quantified/length'
@@ -76,14 +76,10 @@ module Quantified
76
76
  if system
77
77
  self.systems_to_units[system.to_sym].dup
78
78
  else
79
- read_inheritable_attribute(:primitives) | self.conversions.keys
79
+ self.primitives | self.conversions.keys
80
80
  end
81
81
  end
82
82
 
83
- def self.primitives
84
- read_inheritable_attribute(:primitives).dup
85
- end
86
-
87
83
  def self.non_primitives
88
84
  self.conversions.keys
89
85
  end
@@ -103,14 +99,18 @@ module Quantified
103
99
  end
104
100
 
105
101
  protected
106
-
107
- class_inheritable_accessor :add_numeric_methods, :primitives, :conversions, :current_system, :systems_to_units, :units_to_systems
108
- self.add_numeric_methods = false
109
- self.primitives = []
110
- self.conversions = {}
111
- self.current_system = nil
112
- self.systems_to_units = {}
113
- self.units_to_systems = {}
102
+
103
+ class << self
104
+ def primitives; @primitives ||= []; end
105
+ def add_numeric_methods; @add_numeric_methods ||= false; end
106
+ def add_numeric_methods=(v); @add_numeric_methods = v; end
107
+ def conversions; @conversions ||= {}; end
108
+ def current_system; @current_system; end
109
+ def current_system=(v); @current_system = v; end
110
+ def systems_to_units; @systems_to_units ||= {}; end
111
+ def units_to_systems; @units_to_systems ||= {}; end
112
+ end
113
+
114
114
 
115
115
  def self.system(system_name, &block)
116
116
  old_system = self.current_system
@@ -205,4 +205,4 @@ module Quantified
205
205
  end
206
206
  end
207
207
  end
208
- end
208
+ end
@@ -1,2 +1,10 @@
1
1
  require 'test/unit'
2
- require File.dirname(__FILE__) + '/../lib/quantified'
2
+ begin
3
+ require 'active_support/inflector'
4
+ rescue LoadError => e
5
+ require 'rubygems'
6
+ gem "activesupport", ">= 2.3.5"
7
+ require 'active_support/inflector'
8
+ end
9
+
10
+ require File.dirname(__FILE__) + '/../lib/quantified'
@@ -4,10 +4,4 @@ $:.unshift(File.dirname(__FILE__) + '/../lib')
4
4
 
5
5
  require 'test/unit'
6
6
  require 'active_shipping'
7
-
8
- begin
9
- require 'mocha'
10
- rescue LoadError
11
- require 'rubygems'
12
- require 'mocha'
13
- end
7
+ require 'mocha'
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_shipping
3
3
  version: !ruby/object:Gem::Version
4
- hash: 33
4
+ hash: 39
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 9
9
- - 13
10
- version: 0.9.13
9
+ - 14
10
+ version: 0.9.14
11
11
  platform: ruby
12
12
  authors:
13
13
  - James MacAulay
@@ -18,7 +18,7 @@ autorequire:
18
18
  bindir: bin
19
19
  cert_chain: []
20
20
 
21
- date: 2011-04-27 00:00:00 -04:00
21
+ date: 2012-05-02 00:00:00 -04:00
22
22
  default_executable:
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency
@@ -38,7 +38,7 @@ dependencies:
38
38
  type: :runtime
39
39
  version_requirements: *id001
40
40
  - !ruby/object:Gem::Dependency
41
- name: mocha
41
+ name: i18n
42
42
  prerelease: false
43
43
  requirement: &id002 !ruby/object:Gem::Requirement
44
44
  none: false
@@ -49,8 +49,82 @@ dependencies:
49
49
  segments:
50
50
  - 0
51
51
  version: "0"
52
- type: :development
52
+ type: :runtime
53
53
  version_requirements: *id002
54
+ - !ruby/object:Gem::Dependency
55
+ name: active_utils
56
+ prerelease: false
57
+ requirement: &id003 !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ hash: 21
63
+ segments:
64
+ - 1
65
+ - 0
66
+ - 1
67
+ version: 1.0.1
68
+ type: :runtime
69
+ version_requirements: *id003
70
+ - !ruby/object:Gem::Dependency
71
+ name: builder
72
+ prerelease: false
73
+ requirement: &id004 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ hash: 3
79
+ segments:
80
+ - 0
81
+ version: "0"
82
+ type: :runtime
83
+ version_requirements: *id004
84
+ - !ruby/object:Gem::Dependency
85
+ name: json
86
+ prerelease: false
87
+ requirement: &id005 !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ hash: 1
93
+ segments:
94
+ - 1
95
+ - 5
96
+ - 1
97
+ version: 1.5.1
98
+ type: :runtime
99
+ version_requirements: *id005
100
+ - !ruby/object:Gem::Dependency
101
+ name: rake
102
+ prerelease: false
103
+ requirement: &id006 !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ hash: 3
109
+ segments:
110
+ - 0
111
+ version: "0"
112
+ type: :development
113
+ version_requirements: *id006
114
+ - !ruby/object:Gem::Dependency
115
+ name: mocha
116
+ prerelease: false
117
+ requirement: &id007 !ruby/object:Gem::Requirement
118
+ none: false
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ hash: 3
123
+ segments:
124
+ - 0
125
+ version: "0"
126
+ type: :development
127
+ version_requirements: *id007
54
128
  description: Get rates and tracking info from various shipping carriers.
55
129
  email:
56
130
  - james@shopify.com
@@ -61,15 +135,6 @@ extensions: []
61
135
  extra_rdoc_files: []
62
136
 
63
137
  files:
64
- - lib/active_merchant/common/connection.rb
65
- - lib/active_merchant/common/country.rb
66
- - lib/active_merchant/common/error.rb
67
- - lib/active_merchant/common/post_data.rb
68
- - lib/active_merchant/common/posts_data.rb
69
- - lib/active_merchant/common/requires_parameters.rb
70
- - lib/active_merchant/common/utils.rb
71
- - lib/active_merchant/common/validateable.rb
72
- - lib/active_merchant/common.rb
73
138
  - lib/active_shipping/shipping/base.rb
74
139
  - lib/active_shipping/shipping/carrier.rb
75
140
  - lib/active_shipping/shipping/carriers/bogus_carrier.rb
@@ -87,10 +152,10 @@ files:
87
152
  - lib/active_shipping/shipping/rate_response.rb
88
153
  - lib/active_shipping/shipping/response.rb
89
154
  - lib/active_shipping/shipping/shipment_event.rb
155
+ - lib/active_shipping/shipping/shipment_packer.rb
90
156
  - lib/active_shipping/shipping/tracking_response.rb
91
157
  - lib/active_shipping/version.rb
92
158
  - lib/active_shipping.rb
93
- - lib/certs/cacert.pem
94
159
  - lib/certs/eParcel.dtd
95
160
  - lib/vendor/quantified/init.rb
96
161
  - lib/vendor/quantified/lib/quantified/attribute.rb