module ActiveMerchant module Shipping class NewZealandPost < Carrier # class NewZealandPostRateResponse < RateResponse # end cattr_reader :name @@name = "New Zealand Post" URL = "http://workshop.nzpost.co.nz/api/v1/rate.xml" # Override to return required keys in options hash for initialize method. def requirements [:key] end # Override with whatever you need to get the rates def find_rates(origin, destination, packages, options = {}) packages = Array(packages) rate_responses = [] packages.each do |package| if package.tube? request_hash = build_tube_request_params(origin, destination, package, options) else request_hash = build_rectangular_request_params(origin, destination, package, options) end url = URL + '?' + request_hash.to_param response = ssl_get(url) rate_responses << parse_rate_response(origin, destination, package, response, options) end combine_rate_responses(rate_responses, packages) end def maximum_weight Mass.new(20, :kilograms) end protected # Override in subclasses for non-U.S.-based carriers. def self.default_location Location.new(:postal_code => '6011') end private def build_rectangular_request_params(origin, destination, package, options = {}) params = { :postcode_src => origin.postal_code, :postcode_dest => destination.postal_code, :api_key => @options[:key], :height => "#{package.centimetres(:height) * 10}", :thickness => "#{package.centimetres(:width) * 10}", :length => "#{package.centimetres(:length) * 10}", :weight =>"%.1f" % (package.weight.amount / 1000.0) } end def build_tube_request_params(origin, destination, package, options = {}) params = { :postcode_src => origin.postal_code, :postcode_dest => destination.postal_code, :api_key => @options[:key], :diameter => "#{package.centimetres(:width) * 10}", :length => "#{package.centimetres(:length) * 10}", :weight => "%.1f" % (package.weight.amount / 1000.0) } end def parse_rate_response(origin, destination, package, response, options={}) xml = REXML::Document.new(response) if response_success?(xml) rate_estimates = [] xml.elements.each('hash/products/product') do |prod| if( prod.get_text('packaging') == 'postage_only' ) rate_estimates << RateEstimate.new(origin, destination, @@name, prod.get_text('service-group-description').to_s, :total_price => prod.get_text('cost').to_s.to_f, :currency => 'NZD', :service_code => prod.get_text('code').to_s, :package => package) end end RateResponse.new(true, "Success", Hash.from_xml(response), :rates => rate_estimates, :xml => response) else error_message = response_message(xml) RateResponse.new(false, error_message, Hash.from_xml(response), :rates => rate_estimates, :xml => response) end end def combine_rate_responses(rate_responses, packages) #if there are any failed responses, return on that response rate_responses.each do |r| return r if !r.success? end #group rate estimates by delivery type so that we can exclude any incomplete delviery types rate_estimate_delivery_types = {} rate_responses.each do |rr| rr.rate_estimates.each do |re| (rate_estimate_delivery_types[re.service_code] ||= []) << re end end rate_estimate_delivery_types.delete_if{ |type, re| re.size != packages.size } #combine cost estimates for remaining packages combined_rate_estimates = [] rate_estimate_delivery_types.each do |type, re| total_price = re.sum(&:total_price) r = re.first combined_rate_estimates << RateEstimate.new(r.origin, r.destination, r.carrier, r.service_name, :total_price => total_price, :currency => r.currency, :service_code => r.service_code, :packages => packages) end RateResponse.new(true, "Success", {}, :rates => combined_rate_estimates) end def response_success?(xml) xml.get_text('hash/status').to_s == 'success' end def response_message(xml) if response_success?(xml) 'Success' else xml.get_text('hash/message').to_s end end end end end