diff --git a/README.md b/README.md index 209cc5126..7426fda9b 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Active Shipping is currently being used and improved in a production environment * [Shipwire](http://www.shipwire.com) * [Stamps](http://www.stamps.com) * [Kunaki](http://www.kunaki.com) +* [Australia Post](http://auspost.com.au/) ## Installation diff --git a/lib/active_shipping/carriers.rb b/lib/active_shipping/carriers.rb index 0f43596a6..b6d8e2f44 100644 --- a/lib/active_shipping/carriers.rb +++ b/lib/active_shipping/carriers.rb @@ -33,3 +33,4 @@ def find(name) ActiveShipping::Carriers.register :CanadaPostPWS, 'active_shipping/carriers/canada_post_pws' ActiveShipping::Carriers.register :Stamps, 'active_shipping/carriers/stamps' ActiveShipping::Carriers.register :Correios, 'active_shipping/carriers/correios' +ActiveShipping::Carriers.register :AustraliaPost, 'active_shipping/carriers/australia_post' diff --git a/lib/active_shipping/carriers/australia_post.rb b/lib/active_shipping/carriers/australia_post.rb new file mode 100644 index 000000000..48d057fd1 --- /dev/null +++ b/lib/active_shipping/carriers/australia_post.rb @@ -0,0 +1,249 @@ +require 'active_support/core_ext/object/to_query' + +module ActiveShipping + class AustraliaPost < Carrier + cattr_reader :name + @@name = 'Australia Post' + + URL = 'https://digitalapi.auspost.com.au/' + + PARCEL_ENDPOINTS = { + service: { + domestic: 'postage/parcel/domestic/service', + international: 'postage/parcel/international/service' + }, + calculate: { + domestic: 'postage/parcel/domestic/calculate', + international: 'postage/parcel/international/calculate' + } + }.freeze + + def requirements + [:api_key] + end + + def find_rates(origin, destination, packages, options = {}) + packages = Array(packages) + + service_requests = packages.map do |package| + service_request = ServiceRequest.new(origin, destination, package, options) + + service_request.parse(commit(service_request.url)) + service_request + end + + combined_request = CombinedRequest.new(origin, destination, packages, service_requests) + + RateResponse.new(true, 'success', combined_request.response_params, combined_request.response_options) + end + + def calculate_rates(origin, destination, packages, service_code, options = {}) + packages = Array(packages) + + calculate_requests = packages.map do |package| + calculate_request = CalculateRequest.new(origin, destination, package, service_code, options) + + calculate_request.parse(commit(calculate_request.url)) + calculate_request + end + + combined_request = CombinedRequest.new(origin, destination, packages, calculate_requests) + + RateResponse.new(true, 'success', combined_request.response_params, combined_request.response_options) + end + + private + + def commit(request_url) + ssl_get(request_url, headers) + + rescue ActiveUtils::ResponseError, ActiveShipping::ResponseError => e + data = JSON.parse(e.response.body) + + RateResponse.new(false, data['error']['errorMessage'], data) + end + + def headers + { + 'Content-type' => 'application/json', + 'auth-key' => @options[:api_key] + } + end + + class CombinedRequest + + def initialize(origin, destination, packages, requests) + @requests = requests + @origin = origin + @destination = destination + @packages = packages + end + + def response_options + { + rates: rates, + raw_responses: @requests.map(&:raw_response), + request: @requests.map(&:url) + } + end + + def response_params + { + responses: @requests.map(&:response) + } + end + + private + + def rate_options(rates) + { + service_name: rates.first[:service_name], + service_code: rates.first[:service_code], + total_price: rates.sum { |rate| rate[:total_price] }, + currency: 'AUD', + delivery_time_text: rates.first[:delivery_time_text] + } + end + + def rates + rates = @requests.map(&:rates).flatten + + rates.group_by { |rate| rate[:service_name] }.map do |service_name, service_rates| + next unless service_rates.size == @packages.size + + AustraliaPostRateEstimate.new(@origin, @destination, AustraliaPost.name, service_name, rate_options(service_rates)) + end.compact + end + + end + + class AustraliaPostRequest + attr_reader :raw_response + attr_reader :response + attr_reader :rates + + def initialize(origin, destination, package, options) + @origin = Location.from(origin) + @destination = Location.from(destination) + @package = package + @rates = [] + @options = options + end + + def url + endpoint = domestic_destination? ? @endpoints[:domestic] : @endpoints[:international] + params = domestic_destination? ? domestic_params : international_params + + "#{URL}#{endpoint}.json?#{params.to_query}" + end + + def parse(data) + @raw_response = data + @response = JSON.parse(data) + end + + protected + + def domestic_destination? + @destination.country_code == 'AU' + end + + def domestic_params + { + length: @package.cm(:length), + width: @package.cm(:width), + height: @package.cm(:height), + weight: @package.weight.in_kg.to_f.round(2), + from_postcode: @origin.postal_code, + to_postcode: @destination.postal_code + } + end + + def international_params + { + weight: @package.weight.in_kg.to_f.round(2), + country_code: @destination.country_code + } + end + + end + + class ServiceRequest < AustraliaPostRequest + + def initialize(origin, destination, package, options) + super + @endpoints = PARCEL_ENDPOINTS[:service] + end + + def parse(data) + super + + @rates = response['services']['service'].map do |service| + { + service_name: service['name'], + service_code: service['code'], + total_price: service['price'].to_f, + currency: 'AUD' + } + end + end + + end + + class CalculateRequest < AustraliaPostRequest + attr_reader :service_code + + def initialize(origin, destination, package, service_code, options) + super(origin, destination, package, options) + + @service_code = service_code + @endpoints = PARCEL_ENDPOINTS[:calculate] + end + + def parse(data) + super + postage_result = response['postage_result'] + + @rates = [{ + service_name: postage_result['service'], + service_code: service_code, + total_price: postage_result['total_cost'].to_f, + currency: 'AUD', + delivery_time_text: postage_result['delivery_time'] + }] + end + + private + + def calculate_params + { + service_code: @service_code, + option_code: @options[:option_code], + suboption_code: @options[:suboption_code], + extra_cover: @options[:extra_cover] + }. + # INFO: equivalent of .compact + select { |_, value| !value.nil? } + end + + def domestic_params + super.merge(calculate_params) + end + + def international_params + super.merge(calculate_params) + end + + end + + class AustraliaPostRateEstimate < RateEstimate + attr_reader :delivery_time_text + + def initialize(origin, destination, carrier, service_name, options = {}) + super + @delivery_time_text = options[:delivery_time_text] + end + + end + end +end diff --git a/test/credentials.yml b/test/credentials.yml index 3d655499f..a41462e14 100644 --- a/test/credentials.yml +++ b/test/credentials.yml @@ -65,6 +65,9 @@ stamps: username: <%= ENV['ACTIVESHIPPING_STAMPS_USERNAME'] %> password: <%= ENV['ACTIVESHIPPING_STAMPS_PASSWORD'] %> +australia_post: + api_key: <%= ENV['ACTIVESHIPPING_AUSTRALIA_POST_API_KEY'] %> + # fedex_freight: # account: FedExFreightAccountNumber # shipping_address1: FedExShippingAddress1 diff --git a/test/fixtures/json/australia_post/calculate_domestic.json b/test/fixtures/json/australia_post/calculate_domestic.json new file mode 100644 index 000000000..a1747a7cf --- /dev/null +++ b/test/fixtures/json/australia_post/calculate_domestic.json @@ -0,0 +1,13 @@ +{ + "postage_result": { + "service": "Express Post", + "delivery_time": "Guaranteed Next Business Day within the Express Post network (If posted on any business day Monday to Friday in accordance with the conditions set out on the item).", + "total_cost": "10.20", + "costs": { + "cost": { + "item": "Express Post", + "cost": "10.20" + } + } + } +} diff --git a/test/fixtures/json/australia_post/calculate_domestic_2.json b/test/fixtures/json/australia_post/calculate_domestic_2.json new file mode 100644 index 000000000..a587f1fb8 --- /dev/null +++ b/test/fixtures/json/australia_post/calculate_domestic_2.json @@ -0,0 +1,19 @@ +{ + "postage_result": { + "service": "Express Post", + "delivery_time": "Guaranteed Next Business Day within the Express Post network (If posted on any business day Monday to Friday in accordance with the conditions set out on the item).", + "total_cost": "14.70", + "costs": { + "cost": [{ + "item": "Express Post", + "cost": "10.20" + }, { + "item": "Standard Service", + "cost": "0.00" + }, { + "item": "Extra Cover", + "cost": "4.50" + }] + } + } +} diff --git a/test/fixtures/json/australia_post/calculate_international.json b/test/fixtures/json/australia_post/calculate_international.json new file mode 100644 index 000000000..26d362a3c --- /dev/null +++ b/test/fixtures/json/australia_post/calculate_international.json @@ -0,0 +1,12 @@ +{ + "postage_result": { + "service": "Courier", + "total_cost": "87.36", + "costs": { + "cost": { + "item": "Courier", + "cost": "87.36" + } + } + } +} diff --git a/test/fixtures/json/australia_post/calculate_international_2.json b/test/fixtures/json/australia_post/calculate_international_2.json new file mode 100644 index 000000000..52c357a18 --- /dev/null +++ b/test/fixtures/json/australia_post/calculate_international_2.json @@ -0,0 +1,15 @@ +{ + "postage_result": { + "service": "Courier", + "total_cost": "87.36", + "costs": { + "cost": [{ + "item": "Courier", + "cost": "87.36" + }, { + "item": "SMS track advice", + "cost": "0.00" + }] + } + } +} diff --git a/test/fixtures/json/australia_post/error_message.json b/test/fixtures/json/australia_post/error_message.json new file mode 100644 index 000000000..73241b323 --- /dev/null +++ b/test/fixtures/json/australia_post/error_message.json @@ -0,0 +1,5 @@ +{ + "error": { + "errorMessage": "Please enter From postcode." + } +} diff --git a/test/fixtures/json/australia_post/service_domestic.json b/test/fixtures/json/australia_post/service_domestic.json new file mode 100644 index 000000000..063fe0d7a --- /dev/null +++ b/test/fixtures/json/australia_post/service_domestic.json @@ -0,0 +1,117 @@ +{ + "services": { + "service": [{ + "code": "AUS_PARCEL_EXPRESS", + "name": "Express Post", + "price": "28.55", + "max_extra_cover": 300, + "options": { + "option": [{ + "code": "AUS_SERVICE_OPTION_STANDARD", + "name": "Standard Service", + "suboptions": { + "option": { + "code": "AUS_SERVICE_OPTION_EXTRA_COVER", + "name": "Extra Cover", + "max_extra_cover": 300 + } + } + }, { + "code": "AUS_SERVICE_OPTION_SIGNATURE_ON_DELIVERY", + "name": "Signature on Delivery", + "suboptions": { + "option": { + "code": "AUS_SERVICE_OPTION_EXTRA_COVER", + "name": "Extra Cover", + "max_extra_cover": 5000 + } + } + }] + } + }, { + "code": "AUS_PARCEL_EXPRESS_SATCHEL_3KG", + "name": "Express Post Medium (3Kg) Satchel", + "price": "14.80", + "max_extra_cover": 300, + "options": { + "option": [{ + "code": "AUS_SERVICE_OPTION_STANDARD", + "name": "Standard Service", + "suboptions": { + "option": { + "code": "AUS_SERVICE_OPTION_EXTRA_COVER", + "name": "Extra Cover", + "max_extra_cover": 300 + } + } + }, { + "code": "AUS_SERVICE_OPTION_SIGNATURE_ON_DELIVERY", + "name": "Signature on Delivery", + "suboptions": { + "option": { + "code": "AUS_SERVICE_OPTION_EXTRA_COVER", + "name": "Extra Cover", + "max_extra_cover": 5000 + } + } + }] + } + }, { + "code": "AUS_PARCEL_REGULAR", + "name": "Parcel Post", + "price": "16.15", + "max_extra_cover": 300, + "options": { + "option": [{ + "code": "AUS_SERVICE_OPTION_STANDARD", + "name": "Standard Service", + "suboptions": { + "option": { + "code": "AUS_SERVICE_OPTION_EXTRA_COVER", + "name": "Extra Cover", + "max_extra_cover": 300 + } + } + }, { + "code": "AUS_SERVICE_OPTION_SIGNATURE_ON_DELIVERY", + "name": "Signature on Delivery", + "suboptions": { + "option": { + "code": "AUS_SERVICE_OPTION_EXTRA_COVER", + "name": "Extra Cover", + "max_extra_cover": 5000 + } + } + }] + } + }, { + "code": "AUS_PARCEL_REGULAR_SATCHEL_3KG", + "name": "Parcel Post Medium Satchel", + "price": "13.40", + "max_extra_cover": 300, + "options": { + "option": [{ + "code": "AUS_SERVICE_OPTION_STANDARD", + "name": "Standard Service", + "suboptions": { + "option": { + "code": "AUS_SERVICE_OPTION_EXTRA_COVER", + "name": "Extra Cover", + "max_extra_cover": 300 + } + } + }, { + "code": "AUS_SERVICE_OPTION_SIGNATURE_ON_DELIVERY", + "name": "Signature on Delivery", + "suboptions": { + "option": { + "code": "AUS_SERVICE_OPTION_EXTRA_COVER", + "name": "Extra Cover", + "max_extra_cover": 5000 + } + } + }] + } + }] + } +} diff --git a/test/fixtures/json/australia_post/service_domestic_2.json b/test/fixtures/json/australia_post/service_domestic_2.json new file mode 100644 index 000000000..9235b30d2 --- /dev/null +++ b/test/fixtures/json/australia_post/service_domestic_2.json @@ -0,0 +1,117 @@ +{ + "services": { + "service": [{ + "code": "AUS_PARCEL_EXPRESS", + "name": "Express Post", + "price": "10.20", + "max_extra_cover": 300, + "options": { + "option": [{ + "code": "AUS_SERVICE_OPTION_STANDARD", + "name": "Standard Service", + "suboptions": { + "option": { + "code": "AUS_SERVICE_OPTION_EXTRA_COVER", + "name": "Extra Cover", + "max_extra_cover": 300 + } + } + }, { + "code": "AUS_SERVICE_OPTION_SIGNATURE_ON_DELIVERY", + "name": "Signature on Delivery", + "suboptions": { + "option": { + "code": "AUS_SERVICE_OPTION_EXTRA_COVER", + "name": "Extra Cover", + "max_extra_cover": 5000 + } + } + }] + } + }, { + "code": "AUS_PARCEL_EXPRESS_SATCHEL_500G", + "name": "Express Post Small Satchel", + "price": "10.55", + "max_extra_cover": 300, + "options": { + "option": [{ + "code": "AUS_SERVICE_OPTION_STANDARD", + "name": "Standard Service", + "suboptions": { + "option": { + "code": "AUS_SERVICE_OPTION_EXTRA_COVER", + "name": "Extra Cover", + "max_extra_cover": 300 + } + } + }, { + "code": "AUS_SERVICE_OPTION_SIGNATURE_ON_DELIVERY", + "name": "Signature on Delivery", + "suboptions": { + "option": { + "code": "AUS_SERVICE_OPTION_EXTRA_COVER", + "name": "Extra Cover", + "max_extra_cover": 5000 + } + } + }] + } + }, { + "code": "AUS_PARCEL_REGULAR", + "name": "Parcel Post", + "price": "7.45", + "max_extra_cover": 300, + "options": { + "option": [{ + "code": "AUS_SERVICE_OPTION_STANDARD", + "name": "Standard Service", + "suboptions": { + "option": { + "code": "AUS_SERVICE_OPTION_EXTRA_COVER", + "name": "Extra Cover", + "max_extra_cover": 300 + } + } + }, { + "code": "AUS_SERVICE_OPTION_SIGNATURE_ON_DELIVERY", + "name": "Signature on Delivery", + "suboptions": { + "option": { + "code": "AUS_SERVICE_OPTION_EXTRA_COVER", + "name": "Extra Cover", + "max_extra_cover": 5000 + } + } + }] + } + }, { + "code": "AUS_PARCEL_REGULAR_SATCHEL_500G", + "name": "Parcel Post Small Satchel", + "price": "8.25", + "max_extra_cover": 300, + "options": { + "option": [{ + "code": "AUS_SERVICE_OPTION_STANDARD", + "name": "Standard Service", + "suboptions": { + "option": { + "code": "AUS_SERVICE_OPTION_EXTRA_COVER", + "name": "Extra Cover", + "max_extra_cover": 300 + } + } + }, { + "code": "AUS_SERVICE_OPTION_SIGNATURE_ON_DELIVERY", + "name": "Signature on Delivery", + "suboptions": { + "option": { + "code": "AUS_SERVICE_OPTION_EXTRA_COVER", + "name": "Extra Cover", + "max_extra_cover": 5000 + } + } + }] + } + }] + } +} diff --git a/test/fixtures/json/australia_post/service_international.json b/test/fixtures/json/australia_post/service_international.json new file mode 100644 index 000000000..862328455 --- /dev/null +++ b/test/fixtures/json/australia_post/service_international.json @@ -0,0 +1,76 @@ +{ + "services": { + "service": [{ + "code": "INT_PARCEL_COR_OWN_PACKAGING", + "name": "Courier", + "price": "154.17", + "max_extra_cover": 5000, + "options": { + "option": [{ + "code": "INT_TRACKING", + "name": "Tracking" + }, { + "code": "INT_SMS_TRACK_ADVICE", + "name": "SMS track advice" + }, { + "code": "INT_EXTRA_COVER", + "name": "Extra Cover" + }] + } + }, { + "code": "INT_PARCEL_EXP_OWN_PACKAGING", + "name": "Express", + "price": "89.17", + "max_extra_cover": 5000, + "options": { + "option": [{ + "code": "INT_TRACKING", + "name": "Tracking" + }, { + "code": "INT_SIGNATURE_ON_DELIVERY", + "name": "Signature on delivery" + }, { + "code": "INT_SMS_TRACK_ADVICE", + "name": "SMS track advice" + }, { + "code": "INT_EXTRA_COVER", + "name": "Extra Cover" + }] + } + }, { + "code": "INT_PARCEL_STD_OWN_PACKAGING", + "name": "Standard", + "price": "84.17", + "max_extra_cover": 5000, + "options": { + "option": [{ + "code": "INT_TRACKING", + "name": "Tracking" + }, { + "code": "INT_EXTRA_COVER", + "name": "Extra Cover" + }, { + "code": "INT_SIGNATURE_ON_DELIVERY", + "name": "Signature on delivery" + }, { + "code": "INT_SMS_TRACK_ADVICE", + "name": "SMS track advice" + }] + } + }, { + "code": "INT_PARCEL_SEA_OWN_PACKAGING", + "name": "Economy Sea", + "price": "46.80", + "max_extra_cover": 5000, + "options": { + "option": [{ + "code": "INT_EXTRA_COVER", + "name": "Extra Cover" + }, { + "code": "INT_SIGNATURE_ON_DELIVERY", + "name": "Signature on delivery" + }] + } + }] + } +} diff --git a/test/fixtures/json/australia_post/service_international_2.json b/test/fixtures/json/australia_post/service_international_2.json new file mode 100644 index 000000000..88279db8e --- /dev/null +++ b/test/fixtures/json/australia_post/service_international_2.json @@ -0,0 +1,59 @@ +{ + "services": { + "service": [{ + "code": "INT_PARCEL_EXP_OWN_PACKAGING", + "name": "Express", + "price": "82.87", + "max_extra_cover": 5000, + "options": { + "option": [{ + "code": "INT_TRACKING", + "name": "Tracking" + }, { + "code": "INT_SIGNATURE_ON_DELIVERY", + "name": "Signature on delivery" + }, { + "code": "INT_SMS_TRACK_ADVICE", + "name": "SMS track advice" + }, { + "code": "INT_EXTRA_COVER", + "name": "Extra Cover" + }] + } + }, { + "code": "INT_PARCEL_STD_OWN_PACKAGING", + "name": "Standard", + "price": "71.20", + "max_extra_cover": 5000, + "options": { + "option": [{ + "code": "INT_TRACKING", + "name": "Tracking" + }, { + "code": "INT_EXTRA_COVER", + "name": "Extra Cover" + }, { + "code": "INT_SIGNATURE_ON_DELIVERY", + "name": "Signature on delivery" + }, { + "code": "INT_SMS_TRACK_ADVICE", + "name": "SMS track advice" + }] + } + }, { + "code": "INT_PARCEL_SEA_OWN_PACKAGING", + "name": "Economy Sea", + "price": "41.54", + "max_extra_cover": 5000, + "options": { + "option": [{ + "code": "INT_EXTRA_COVER", + "name": "Extra Cover" + }, { + "code": "INT_SIGNATURE_ON_DELIVERY", + "name": "Signature on delivery" + }] + } + }] + } +} diff --git a/test/remote/australia_post_test.rb b/test/remote/australia_post_test.rb new file mode 100644 index 000000000..1205a6594 --- /dev/null +++ b/test/remote/australia_post_test.rb @@ -0,0 +1,140 @@ +require 'test_helper' + +class RemoteAustraliaPostTest < Minitest::Test + include ActiveShipping::Test::Credentials + include ActiveShipping::Test::Fixtures + + def setup + @carrier = AustraliaPost.new(credentials(:australia_post)) + @sydney = location_fixtures[:sydney] + @melbourne = location_fixtures[:melbourne] + @ottawa = location_fixtures[:ottawa] + rescue NoCredentialsFound => e + skip(e.message) + end + + def test_valid_credentials + assert @carrier.valid_credentials? + end + + def test_service_domestic_simple_request + response = @carrier.find_rates(@sydney, @melbourne, package_fixtures[:wii]) + + assert response.is_a?(RateResponse) + assert response.success? + assert response.rates.any? + assert response.rates.first.is_a?(RateEstimate) + assert_equal 1, response.params["responses"].size + assert_equal 1, response.request.size + end + + def test_service_domestic_combined_request + response = @carrier.find_rates(@sydney, @melbourne, package_fixtures.values_at(:book, :small_half_pound)) + + assert response.is_a?(RateResponse) + assert response.success? + assert response.rates.any? + assert response.rates.first.is_a?(RateEstimate) + assert_equal 2, response.params["responses"].size + assert_equal 2, response.request.size + end + + def test_service_international_simple_request + response = @carrier.find_rates(@sydney, @ottawa, package_fixtures[:wii]) + + assert response.is_a?(RateResponse) + assert response.success? + assert response.rates.any? + assert response.rates.first.is_a?(RateEstimate) + assert_equal 1, response.params["responses"].size + assert_equal 1, response.request.size + end + + def test_service_domestic_combined_request + response = @carrier.find_rates(@sydney, @ottawa, package_fixtures.values_at(:book, :small_half_pound)) + + assert response.is_a?(RateResponse) + assert response.success? + assert response.rates.any? + assert response.rates.first.is_a?(RateEstimate) + assert_equal 2, response.params["responses"].size + assert_equal 2, response.request.size + end + + def test_service_domestic_response_error + error = assert_raises(ActiveShipping::ResponseError) do + @carrier.find_rates(@sydney, @melbourne, package_fixtures[:largest_gold_bar]) + end + + assert_equal 'The maximum weight of a parcel is 22 kg.', error.message + end + + def test_service_international_response_error + error = assert_raises(ActiveShipping::ResponseError) do + @carrier.find_rates(@sydney, @ottawa, package_fixtures[:largest_gold_bar]) + end + + assert_equal 'The maximum weight of a parcel is 20 kg.', error.message + end + + def test_calculate_domestic_simple_request + response = @carrier.calculate_rates(@sydney, @melbourne, package_fixtures[:wii], 'AUS_PARCEL_EXPRESS') + + assert response.is_a?(RateResponse) + assert response.success? + assert response.rates.any? + assert response.rates.first.is_a?(RateEstimate) + assert_equal 1, response.params["responses"].size + assert_equal 1, response.request.size + end + + def test_calculate_domestic_combined_request + response = @carrier.calculate_rates(@sydney, @melbourne, package_fixtures.values_at(:book, :small_half_pound), 'AUS_PARCEL_EXPRESS') + + assert response.is_a?(RateResponse) + assert response.success? + assert response.rates.any? + assert response.rates.first.is_a?(RateEstimate) + assert_equal 2, response.params["responses"].size + assert_equal 2, response.request.size + end + + def test_calculate_international_simple_request + response = @carrier.calculate_rates(@sydney, @ottawa, package_fixtures[:wii], 'INT_PARCEL_COR_OWN_PACKAGING') + + assert response.is_a?(RateResponse) + assert response.success? + assert response.rates.any? + assert response.rates.first.is_a?(RateEstimate) + assert_equal 1, response.params["responses"].size + assert_equal 1, response.request.size + end + + def test_calculate_domestic_combined_request + response = @carrier.calculate_rates(@sydney, @ottawa, package_fixtures.values_at(:book, :small_half_pound), 'INT_PARCEL_COR_OWN_PACKAGING') + + assert response.is_a?(RateResponse) + assert response.success? + assert response.rates.any? + assert response.rates.first.is_a?(RateEstimate) + assert_equal 2, response.params["responses"].size + assert_equal 2, response.request.size + end + + def test_calculate_domestic_response_error + error = assert_raises(ActiveShipping::ResponseError) do + @carrier.calculate_rates(@sydney, @melbourne, package_fixtures[:wii], 'INT_PARCEL_COR_OWN_PACKAGING') + end + + assert_equal 'Please enter a valid Service code.', error.message + end + + def test_calculate_international_response_error + error = assert_raises(ActiveShipping::ResponseError) do + @carrier.calculate_rates(@sydney, @ottawa, package_fixtures[:wii], 'AUS_PARCEL_EXPRESS') + end + + assert_equal 'Please enter a valid Service code.', error.message + end + +end diff --git a/test/test_helper.rb b/test/test_helper.rb index 515cc8233..e4afea3f2 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -245,7 +245,19 @@ def location_fixtures :city => 'Groningen', :address1 => 'Aquamarijnstraat 349', :postal_code => '9743 PJ', - :state => 'Groningen') + :state => 'Groningen'), + :sydney => Location.new( + :country => 'AUS', + :city => 'Sydney', + :state => 'NSW', + :address1 => '192 George Street', + :postal_code => '2000'), + :melbourne => Location.new( + :country => 'AUS', + :city => 'Melbourne', + :state => 'VIC', + :address1 => '192 George Street', + :postal_code => '3108') } end diff --git a/test/unit/carriers/australia_post_test.rb b/test/unit/carriers/australia_post_test.rb new file mode 100644 index 000000000..235d8889a --- /dev/null +++ b/test/unit/carriers/australia_post_test.rb @@ -0,0 +1,181 @@ +require 'test_helper' + +class AustraliaPostTest < Minitest::Test + include ActiveShipping::Test::Fixtures + + def setup + @carrier = AustraliaPost.new(api_key: '4d9dc0f0-dda0-012e-066f-000c29b44ac0') + @sydney = location_fixtures[:sydney] + @melbourne = location_fixtures[:melbourne] + @ottawa = location_fixtures[:ottawa] + end + + def test_service_domestic_simple_request + url = 'https://digitalapi.auspost.com.au/postage/parcel/domestic/service.json?from_postcode=2000&height=2&length=19&to_postcode=3108&weight=0.25&width=14' + @carrier.expects(:commit).with(url).returns(json_fixture('australia_post/service_domestic')) + @carrier.find_rates(@sydney, @melbourne, package_fixtures[:book]) + end + + def test_service_domestic_combined_request + url_1 = 'https://digitalapi.auspost.com.au/postage/parcel/domestic/service.json?from_postcode=2000&height=2&length=19&to_postcode=3108&weight=0.25&width=14' + url_2 = 'https://digitalapi.auspost.com.au/postage/parcel/domestic/service.json?from_postcode=2000&height=2.54&length=2.54&to_postcode=3108&weight=0.23&width=2.54' + @carrier.expects(:commit).with(url_1).returns(json_fixture('australia_post/service_domestic')) + @carrier.expects(:commit).with(url_2).returns(json_fixture('australia_post/service_domestic_2')) + @carrier.find_rates(@sydney, @melbourne, package_fixtures.values_at(:book, :small_half_pound)) + end + + def test_service_domestic_simple_response + @carrier.expects(:commit).returns(json_fixture('australia_post/service_domestic')) + response = @carrier.find_rates(@sydney, @melbourne, package_fixtures[:book]) + prices = [2855, 1480, 1615, 1340] + assert_equal prices, response.rates.map(&:price) + service_codes = ['AUS_PARCEL_EXPRESS', 'AUS_PARCEL_EXPRESS_SATCHEL_3KG', 'AUS_PARCEL_REGULAR', 'AUS_PARCEL_REGULAR_SATCHEL_3KG'] + assert_equal service_codes, response.rates.map(&:service_code) + service_names = ['Express Post', 'Express Post Medium (3Kg) Satchel', 'Parcel Post', 'Parcel Post Medium Satchel'] + assert_equal service_names, response.rates.map(&:service_name) + end + + def test_service_domestic_combined_response + @carrier.expects(:commit).returns(json_fixture('australia_post/service_domestic')) + @carrier.expects(:commit).returns(json_fixture('australia_post/service_domestic_2')) + response = @carrier.find_rates(@sydney, @melbourne, package_fixtures.values_at(:book, :small_half_pound)) + prices = [3875, 2360] + assert_equal prices, response.rates.map(&:price) + service_codes = ['AUS_PARCEL_EXPRESS', 'AUS_PARCEL_REGULAR'] + assert_equal service_codes, response.rates.map(&:service_code) + service_names = ['Express Post', 'Parcel Post'] + assert_equal service_names, response.rates.map(&:service_name) + end + + def test_service_international_simple_request + url = 'https://digitalapi.auspost.com.au/postage/parcel/international/service.json?country_code=CA&weight=0.25' + @carrier.expects(:commit).with(url).returns(json_fixture('australia_post/service_international')) + @carrier.find_rates(@sydney, @ottawa, package_fixtures[:book]) + end + + def test_service_international_combined_request + url_1 = 'https://digitalapi.auspost.com.au/postage/parcel/international/service.json?country_code=CA&weight=0.25' + url_2 = 'https://digitalapi.auspost.com.au/postage/parcel/international/service.json?country_code=CA&weight=0.23' + @carrier.expects(:commit).with(url_1).returns(json_fixture('australia_post/service_international')) + @carrier.expects(:commit).with(url_2).returns(json_fixture('australia_post/service_international_2')) + @carrier.find_rates(@sydney, @ottawa, package_fixtures.values_at(:book, :small_half_pound)) + end + + def test_service_international_simple_response + @carrier.expects(:commit).returns(json_fixture('australia_post/service_international')) + response = @carrier.find_rates(@sydney, @ottawa, package_fixtures[:book]) + prices = [15417, 8917, 8417, 4680] + assert_equal prices, response.rates.map(&:price) + service_codes = ['INT_PARCEL_COR_OWN_PACKAGING', 'INT_PARCEL_EXP_OWN_PACKAGING', 'INT_PARCEL_STD_OWN_PACKAGING', 'INT_PARCEL_SEA_OWN_PACKAGING'] + assert_equal service_codes, response.rates.map(&:service_code) + service_names = ['Courier', 'Express', 'Standard', 'Economy Sea'] + assert_equal service_names, response.rates.map(&:service_name) + end + + def test_service_international_combined_response + @carrier.expects(:commit).returns(json_fixture('australia_post/service_international')) + @carrier.expects(:commit).returns(json_fixture('australia_post/service_international_2')) + response = @carrier.find_rates(@sydney, @melbourne, package_fixtures.values_at(:book, :small_half_pound)) + prices = [17204, 15537, 8834] + assert_equal prices, response.rates.map(&:price) + service_codes = ['INT_PARCEL_EXP_OWN_PACKAGING', 'INT_PARCEL_STD_OWN_PACKAGING', 'INT_PARCEL_SEA_OWN_PACKAGING'] + assert_equal service_codes, response.rates.map(&:service_code) + service_names = ['Express', 'Standard', 'Economy Sea'] + assert_equal service_names, response.rates.map(&:service_name) + end + + def test_service_response_error + error = assert_raises(ActiveShipping::ResponseError) do + raise_error = ActiveShipping::ResponseError.new + raise_error.expects(:response).returns(OpenStruct.new(body: json_fixture('australia_post/error_message'))) + @carrier.expects(:ssl_get).raises raise_error + @carrier.find_rates(@sydney, @melbourne, package_fixtures[:book]) + end + assert_equal 'Please enter From postcode.', error.response.message + end + + def test_calculate_domestic_simple_request + url = 'https://digitalapi.auspost.com.au/postage/parcel/domestic/calculate.json?from_postcode=2000&height=2&length=19&service_code=AUS_PARCEL_EXPRESS&to_postcode=3108&weight=0.25&width=14' + @carrier.expects(:commit).with(url).returns(json_fixture('australia_post/calculate_domestic')) + @carrier.calculate_rates(@sydney, @melbourne, package_fixtures[:book], 'AUS_PARCEL_EXPRESS') + end + + def test_calculate_domestic_combined_request + url_1 = 'https://digitalapi.auspost.com.au/postage/parcel/domestic/calculate.json?from_postcode=2000&height=2&length=19&service_code=AUS_PARCEL_EXPRESS&to_postcode=3108&weight=0.25&width=14' + url_2 = 'https://digitalapi.auspost.com.au/postage/parcel/domestic/calculate.json?from_postcode=2000&height=2.54&length=2.54&service_code=AUS_PARCEL_EXPRESS&to_postcode=3108&weight=0.23&width=2.54' + @carrier.expects(:commit).with(url_1).returns(json_fixture('australia_post/calculate_domestic')) + @carrier.expects(:commit).with(url_2).returns(json_fixture('australia_post/calculate_domestic_2')) + @carrier.calculate_rates(@sydney, @melbourne, package_fixtures.values_at(:book, :small_half_pound), 'AUS_PARCEL_EXPRESS') + end + + def test_calculate_domestic_simple_response + @carrier.expects(:commit).returns(json_fixture('australia_post/calculate_domestic')) + response = @carrier.calculate_rates(@sydney, @melbourne, package_fixtures[:book], 'AUS_PARCEL_EXPRESS') + prices = [1020] + assert_equal prices, response.rates.map(&:price) + service_codes = ['AUS_PARCEL_EXPRESS'] + assert_equal service_codes, response.rates.map(&:service_code) + service_names = ['Express Post'] + assert_equal service_names, response.rates.map(&:service_name) + end + + def test_calculate_domestic_combined_response + @carrier.expects(:commit).returns(json_fixture('australia_post/calculate_domestic')) + @carrier.expects(:commit).returns(json_fixture('australia_post/calculate_domestic_2')) + response = @carrier.calculate_rates(@sydney, @melbourne, package_fixtures.values_at(:book, :small_half_pound), 'AUS_PARCEL_EXPRESS') + prices = [2490] + assert_equal prices, response.rates.map(&:price) + service_codes = ['AUS_PARCEL_EXPRESS'] + assert_equal service_codes, response.rates.map(&:service_code) + service_names = ['Express Post'] + assert_equal service_names, response.rates.map(&:service_name) + end + + def test_calculate_international_simple_request + url = 'https://digitalapi.auspost.com.au/postage/parcel/international/calculate.json?country_code=CA&service_code=INT_PARCEL_COR_OWN_PACKAGING&weight=0.25' + @carrier.expects(:commit).with(url).returns(json_fixture('australia_post/calculate_international')) + @carrier.calculate_rates(@sydney, @ottawa, package_fixtures[:book], 'INT_PARCEL_COR_OWN_PACKAGING') + end + + def test_calculate_international_combined_request + url_1 = 'https://digitalapi.auspost.com.au/postage/parcel/international/calculate.json?country_code=CA&service_code=INT_PARCEL_COR_OWN_PACKAGING&weight=0.25' + url_2 = 'https://digitalapi.auspost.com.au/postage/parcel/international/calculate.json?country_code=CA&service_code=INT_PARCEL_COR_OWN_PACKAGING&weight=0.23' + @carrier.expects(:commit).with(url_1).returns(json_fixture('australia_post/calculate_international')) + @carrier.expects(:commit).with(url_2).returns(json_fixture('australia_post/calculate_international_2')) + @carrier.calculate_rates(@sydney, @ottawa, package_fixtures.values_at(:book, :small_half_pound), 'INT_PARCEL_COR_OWN_PACKAGING') + end + + def test_calculate_international_simple_response + @carrier.expects(:commit).returns(json_fixture('australia_post/calculate_international')) + response = @carrier.calculate_rates(@sydney, @ottawa, package_fixtures[:book], 'INT_PARCEL_COR_OWN_PACKAGING') + prices = [8736] + assert_equal prices, response.rates.map(&:price) + service_codes = ['INT_PARCEL_COR_OWN_PACKAGING'] + assert_equal service_codes, response.rates.map(&:service_code) + service_names = ['Courier'] + assert_equal service_names, response.rates.map(&:service_name) + end + + def test_calculate_international_combined_response + @carrier.expects(:commit).returns(json_fixture('australia_post/calculate_international')) + @carrier.expects(:commit).returns(json_fixture('australia_post/calculate_international_2')) + response = @carrier.calculate_rates(@sydney, @melbourne, package_fixtures.values_at(:book, :small_half_pound), 'INT_PARCEL_COR_OWN_PACKAGING') + prices = [17472] + assert_equal prices, response.rates.map(&:price) + service_codes = ['INT_PARCEL_COR_OWN_PACKAGING'] + assert_equal service_codes, response.rates.map(&:service_code) + service_names = ['Courier'] + assert_equal service_names, response.rates.map(&:service_name) + end + + def test_calculate_response_error + error = assert_raises(ActiveShipping::ResponseError) do + raise_error = ActiveShipping::ResponseError.new + raise_error.expects(:response).returns(OpenStruct.new(body: json_fixture('australia_post/error_message'))) + @carrier.expects(:ssl_get).raises raise_error + @carrier.calculate_rates(@sydney, @melbourne, package_fixtures[:book], 'AUS_PARCEL_EXPRESS') + end + assert_equal 'Please enter From postcode.', error.response.message + end + +end