From a76b7d42a9944736cf97e9002acd07439da3be30 Mon Sep 17 00:00:00 2001 From: Bob Perkinson Date: Mon, 9 Apr 2018 15:15:31 -0500 Subject: [PATCH 1/8] added canada post contract shipping with returns --- .../carriers/canada_post_pws.rb | 116 +++++++++++++++++- test/credentials.yml | 1 + test/remote/canada_post_pws_test.rb | 60 +++++++-- .../carriers/canada_post_pws_shipping_test.rb | 25 ++++ 4 files changed, 190 insertions(+), 12 deletions(-) diff --git a/lib/active_shipping/carriers/canada_post_pws.rb b/lib/active_shipping/carriers/canada_post_pws.rb index 2718aecf7..dca29fc9e 100644 --- a/lib/active_shipping/carriers/canada_post_pws.rb +++ b/lib/active_shipping/carriers/canada_post_pws.rb @@ -33,6 +33,7 @@ class CanadaPostPWS < Carrier ENDPOINT = "https://soa-gw.canadapost.ca/" # production SHIPMENT_MIMETYPE = "application/vnd.cpc.ncshipment+xml" + CONTRACT_MIMETYPE = "application/vnd.cpc.shipment-v8+xml" RATE_MIMETYPE = "application/vnd.cpc.ship.rate+xml" TRACK_MIMETYPE = "application/vnd.cpc.track+xml" REGISTER_MIMETYPE = "application/vnd.cpc.registration+xml" @@ -107,6 +108,16 @@ def create_shipment(origin, destination, package, line_items = [], options = {}) CPPWSShippingResponse.new(false, "Missing Customer Number", {}, :carrier => @@name) end + def create_contract_shipment(origin, destination, package, line_items = [], options = {}, return_details = {}) + request_body = build_contract_shipment_request(origin, destination, package, line_items, options, return_details) + response = ssl_post(create_contract_shipment_url(options), request_body, headers(options, CONTRACT_MIMETYPE, CONTRACT_MIMETYPE)) + parse_contract_shipment_response(response) + rescue ActiveUtils::ResponseError, ActiveShipping::ResponseError => e + error_response(e.response.body, CPPWSShippingResponse) + rescue MissingCustomerNumberError + CPPWSShippingResponse.new(false, "Missing Customer Number", {}, :carrier => @@name) + end + def retrieve_shipment(shipping_id, options = {}) response = ssl_post(shipment_url(shipping_id, options), nil, headers(options, SHIPMENT_MIMETYPE, SHIPMENT_MIMETYPE)) parse_shipment_response(response) @@ -358,6 +369,7 @@ def build_tracking_events(events) # :show_postage_rate # :cod, :cod_amount, :insurance, :insurance_amount, :signature_required, :pa18, :pa19, :hfp, :dns, :lad # + # def build_shipment_request(origin, destination, package, line_items = [], options = {}) builder = Nokogiri::XML::Builder.new do |xml| xml.public_send('non-contract-shipment', :xmlns => "http://www.canadapost.ca/ws/ncshipment") do @@ -378,10 +390,48 @@ def build_shipment_request(origin, destination, package, line_items = [], option builder.to_xml end + # return_details + # :service_code, :return_recipient {:name, :company, :address_details {:address_line_1...}} + + def build_contract_shipment_request(origin, destination, package, line_items = [], options = {}, return_details = {}) + builder = Nokogiri::XML::Builder.new do |xml| + xml.public_send('shipment', :xmlns => "http://www.canadapost.ca/ws/shipment-v8") do + shipment_node(xml, options) + xml.public_send('delivery-spec') do + shipment_service_code_node(xml, options) + shipment_sender_node(xml, origin, options) + shipment_destination_node(xml, destination, options) + shipment_options_node(xml, options) + shipment_parcel_node(xml, package) + shipment_notification_node(xml, options) + shipment_preferences_node(xml, options) + references_node(xml, options) # optional > user defined custom notes + shipment_customs_node(xml, destination, line_items, options) + settlement_node(xml, options) + # COD Remittance defaults to sender + end + shipment_return_node(xml, return_details, options) + end + end + builder.to_xml + end + + def shipment_node(xml, options) + xml.public_send('transmit-shipment', options[:transmit] || true) + xml.public_send('requested-shipping-point', options[:shipping_point]) + end + def shipment_service_code_node(xml, options) xml.public_send('service-code', options[:service]) end + def settlement_node(xml, options) + xml.public_send('settlement-info') do + xml.public_send('contract-id', options[:contract_number]) + xml.public_send('intended-method-of-payment', options[:payment_type] || 'Account' ) + end + end + def shipment_sender_node(xml, sender, options) location = location_from_hash(sender) xml.public_send('sender') do @@ -393,7 +443,7 @@ def shipment_sender_node(xml, sender, options) xml.public_send('address-line-2', location.address2_and_3) unless location.address2_and_3.blank? xml.public_send('city', location.city) xml.public_send('prov-state', location.province) - # xml.public_send('country-code', location.country_code) + xml.public_send('country-code', location.country_code) unless location.country_code.blank? xml.public_send('postal-zip-code', get_sanitized_postal_code(location)) end end @@ -473,6 +523,28 @@ def shipment_customs_node(xml, destination, line_items, options) end end + # return_details + # :service_code, :return_recipient {:name, :company, :address_details {:address_line_1...}} + + def shipment_return_node(xml, return_details, options) + return if return_details.blank? + location = location_from_hash(return_details[:return_recipient][:address_details]) + xml.public_send('return-spec') do + xml.public_send('service-code', return_details[:service_code] ) + xml.public_send('return-recipient') do + xml.public_send('name', return_details[:name]) if return_details[:name] + xml.public_send('company', return_details[:company]) if return_details[:company] + xml.public_send('address-details') do + xml.public_send('address-line-1', location.address1) + xml.public_send('address-line-2', location.address2_and_3) unless location.address2_and_3.blank? + xml.public_send('city', location.city) + xml.public_send('prov-state', location.province) unless location.province.blank? + xml.public_send('postal-zip-code', get_sanitized_postal_code(location)) + end + end + end + end + def shipment_parcel_node(xml, package, options = {}) weight = sanitize_weight_kg(package.kilograms.to_f) xml.public_send('parcel-characteristics') do @@ -484,7 +556,7 @@ def shipment_parcel_node(xml, package, options = {}) xml.public_send('width', '%.1f' % ((pkg_dim[1] * 10).round / 10.0)) if pkg_dim.size >= 2 xml.public_send('height', '%.1f' % ((pkg_dim[0] * 10).round / 10.0)) if pkg_dim.size >= 1 end - xml.public_send('document', false) + #xml.public_send('document', false) else xml.public_send('document', true) end @@ -494,6 +566,23 @@ def shipment_parcel_node(xml, package, options = {}) end end + def parse_contract_shipment_response(response) + doc = Nokogiri.XML(response) + doc.remove_namespaces! + raise ActiveShipping::ResponseError, "No Shipping" unless doc.at('shipment-info') + receipt_url = doc.root.at_xpath("links/link[@rel='receipt']")['href'] unless doc.root.at_xpath("links/link[@rel='receipt']").blank? + return_label_url = doc.root.at_xpath("links/link[@rel='returnLabel']")['href'] unless doc.root.at_xpath("links/link[@rel='returnLabel']").blank? + options = { + :shipping_id => doc.root.at('shipment-id').text, + :details_url => doc.root.at_xpath("links/link[@rel='details']")['href'], + :label_url => doc.root.at_xpath("links/link[@rel='label']")['href'], + :receipt_url => receipt_url, + :return_label_url => return_label_url + } + options[:tracking_number] = doc.root.at('tracking-pin').text if doc.root.at('tracking-pin') + CPPWSContractShippingResponse.new(true, "", {}, options) + end + def parse_shipment_response(response) doc = Nokogiri.XML(response) doc.remove_namespaces! @@ -505,7 +594,6 @@ def parse_shipment_response(response) :receipt_url => doc.root.at_xpath("links/link[@rel='receipt']")['href'], } options[:tracking_number] = doc.root.at('tracking-pin').text if doc.root.at('tracking-pin') - CPPWSShippingResponse.new(true, "", {}, options) end @@ -604,6 +692,15 @@ def create_shipment_url(options) end end + def create_contract_shipment_url(options) + raise MissingCustomerNumberError unless customer_number = options[:customer_number] + if @platform_id.present? + endpoint + "rs/#{customer_number}-#{@platform_id}/shipment" + else + endpoint + "rs/#{customer_number}/#{customer_number}/shipment" + end + end + def shipment_url(shipping_id, options = {}) raise MissingCustomerNumberError unless customer_number = options[:customer_number] if @platform_id.present? @@ -873,6 +970,19 @@ def initialize(success, message, params = {}, options = {}) end end + class CPPWSContractShippingResponse < ShippingResponse + include CPPWSErrorResponse + attr_reader :label_url, :details_url, :receipt_url, :return_label_url + def initialize(success, message, params = {}, options = {}) + handle_error(message, options) + super + @label_url = options[:label_url] + @details_url = options[:details_url] + @receipt_url = options[:receipt_url] + @return_label_url = options[:return_label_url] + end + end + class CPPWSRegisterResponse < Response include CPPWSErrorResponse attr_reader :token_id diff --git a/test/credentials.yml b/test/credentials.yml index 861689b83..dc706aecf 100644 --- a/test/credentials.yml +++ b/test/credentials.yml @@ -34,6 +34,7 @@ canada_post_pws: customer_number: <%= ENV['ACTIVESHIPPING_CANADA_POST_PWS_CUSTOMER_NUMBER'] %> api_key: <%= ENV['ACTIVESHIPPING_CANADA_POST_PWS_API_KEY'] %> secret: <%= ENV['ACTIVESHIPPING_CANADA_POST_PWS_SECRET'] %> + contract_number: <%= ENV['ACTIVESHIPPING_CANADA_POST_PWS_CONTRACT'] %> canada_post_pws_platform: platform_id: <%= ENV['ACTIVESHIPPING_CANADA_POST_PWS_PLATFORM_PLATFORM_ID'] %> diff --git a/test/remote/canada_post_pws_test.rb b/test/remote/canada_post_pws_test.rb index ac2d1fa72..c29b60d7d 100644 --- a/test/remote/canada_post_pws_test.rb +++ b/test/remote/canada_post_pws_test.rb @@ -2,6 +2,8 @@ class RemoteCanadaPostPWSTest < ActiveSupport::TestCase # All remote tests require Canada Post development environment credentials + # When using an account with a contract number you should add it to the opts hash + include ActiveShipping::Test::Credentials include ActiveShipping::Test::Fixtures @@ -14,7 +16,9 @@ def setup @line_item1 = line_item_fixture - @shipping_opts1 = { :dc => true, :cov => true, :cov_amount => 100.00, :aban => true } + @shipping_opts1 = {:cod => true, :dc => true, :cov => true, :cov_amount => 100.00, :aban => true } + + @shipping_opts2 = {so: true, cov: true, cov_amount: 999.99, transmit: true, shipping_point: 'R3W1S1'} @home_params = { :name => "John Smith", @@ -23,11 +27,22 @@ def setup :address1 => "123 Elm St.", :city => 'Ottawa', :province => 'ON', - :country => 'CA', :postal_code => 'K1P 1J1' } @home = Location.new(@home_params) + @contract_home_params = { + :name => "John Smith", + :company => "test", + :phone => "613-555-1212", + :address1 => "123 Elm St.", + :city => 'Ottawa', + :province => 'ON', + :country => 'CA', + :postal_code => 'K1P 1J1' + } + @contract_home = Location.new(@contract_home_params) + @dom_params = { :name => "John Smith Sr.", :company => "", @@ -77,6 +92,7 @@ def setup @cp.logger = Logger.new(StringIO.new) @customer_number = @login[:customer_number] + @contract_number = @login[:contract_number] @DEFAULT_RESPONSE = { :shipping_id => "406951321983787352", @@ -121,25 +137,51 @@ def test_tracking_when_no_tracking_info_raises_exception end def test_create_shipment - skip "Failing with 'Contract Number is a required field' after API change, skipping because no clue how to fix, might need different creds" + skip "contract number in credentials" if @contract_number opts = {:customer_number => @customer_number, :service => "DOM.XP"} response = @cp.create_shipment(@home_params, @dom_params, @pkg1, @line_item1, opts) assert_kind_of CPPWSShippingResponse, response - assert_match /\A\d{17}\z/, response.shipping_id + assert_match /\A\d{18}\z/, response.shipping_id assert_equal "123456789012", response.tracking_number - assert_match "https://ct.soa-gw.canadapost.ca/ers/artifact/", response.label_url + assert_match "https://ct.soa-gw.canadapost.ca/rs/artifact/", response.label_url assert_match @login[:api_key], response.label_url end def test_create_shipment_with_options - skip "Failing with 'Contract Number is a required field' after API change, skipping because no clue how to fix, might need different creds" + skip "contract number in credentials" if @contract_number opts = {:customer_number => @customer_number, :service => "USA.EP"}.merge(@shipping_opts1) response = @cp.create_shipment(@home_params, @dest_params, @pkg1, @line_item1, opts) - assert_kind_of CPPWSShippingResponse, response - assert_match /\A\d{17}\z/, response.shipping_id + assert_match /\A\d{18}\z/, response.shipping_id + assert_equal "123456789012", response.tracking_number + assert_match "https://ct.soa-gw.canadapost.ca/rs/artifact/", response.label_url + assert_match @login[:api_key], response.label_url + end + + def test_create_contract_shipment_with_options + skip "no contract number in credentials" unless @contract_number + opts = {:customer_number => @customer_number, :service => "DOM.XP", contract_number: @contract_number}.merge(@shipping_opts2) + response = @cp.create_contract_shipment(@contract_home_params, @dom_params, @pkg1, @line_item1, opts) + assert_kind_of CPPWSContractShippingResponse, response + assert_match /\A\d{18}\z/, response.shipping_id + assert_equal "123456789012", response.tracking_number + assert_match "https://ct.soa-gw.canadapost.ca/rs/artifact/", response.label_url + assert_match @login[:api_key], response.label_url + end + + def test_create_contract_shipment_with_return_label_and_options + skip "no contract number in credentials" unless @contract_number + + opts = {:customer_number => @customer_number, :service => "DOM.XP", contract_number: @contract_number}.merge(@shipping_opts2) + + return_details = {service_code: 'DOM.RP', return_recipient: { address_details: @contract_home_params } } + + response = @cp.create_contract_shipment(@contract_home_params, @dom_params, @pkg1, @line_item1, opts, return_details) + assert_kind_of CPPWSContractShippingResponse, response + assert_match /\A\d{18}\z/, response.shipping_id assert_equal "123456789012", response.tracking_number - assert_match "https://ct.soa-gw.canadapost.ca/ers/artifact/", response.label_url + assert_match "https://ct.soa-gw.canadapost.ca/rs/artifact/", response.label_url + assert_match "https://ct.soa-gw.canadapost.ca/rs/artifact/", response.return_label_url assert_match @login[:api_key], response.label_url end diff --git a/test/unit/carriers/canada_post_pws_shipping_test.rb b/test/unit/carriers/canada_post_pws_shipping_test.rb index 20db669f8..fd95a5d27 100644 --- a/test/unit/carriers/canada_post_pws_shipping_test.rb +++ b/test/unit/carriers/canada_post_pws_shipping_test.rb @@ -63,6 +63,7 @@ def setup :so => true, :pa18 => true} @default_options = {:customer_number => '123456'} + @default_contract_options = {:customer_number => '123456', :contract_number => '42708517'} @DEFAULT_RESPONSE = { :shipping_id => "406951321983787352", @@ -93,6 +94,30 @@ def test_build_shipment_request_for_domestic refute request.blank? end + def test_build_contract_shipment_request_for_domestic + options = @default_contract_options.dup + request = @cp.build_contract_shipment_request(@home_params, @dom_params, @pkg1, @line_item1, options) + refute request.blank? + end + + def test_build_contract_shipment_with_return_request_for_domestic + options = @default_contract_options.dup + return_details = {service_code: 'DOM.RP', return_recipient: { address_details: @home_params } } + + request = @cp.build_contract_shipment_request(@home_params, @dom_params, @pkg1, @line_item1, options, return_details) + refute request.blank? + + doc = Nokogiri.XML(request) + doc.remove_namespaces! + + assert root_node = doc.at('shipment') + assert delivery_spec = root_node.at('delivery-spec') + assert destination = delivery_spec.at('destination') + assert address_details = destination.at('address-details') + assert_equal 'CA', address_details.at('country-code').text + assert return_spec = root_node.at('return-spec') + end + def test_build_shipment_request_for_US options = @default_options.dup request = @cp.build_shipment_request(@home_params, @us_params, @pkg1, @line_item1, options) From 4b3ec44fa2a9c3327b94025e551b4241b17666b0 Mon Sep 17 00:00:00 2001 From: Bob Perkinson Date: Mon, 3 Jun 2019 11:20:32 -0500 Subject: [PATCH 2/8] add return shipping capabilities update to ruby 2.5 and support for rails < 6.0 --- .travis.yml | 1 + active_shipping.gemspec | 2 +- dev.yml | 2 +- .../carriers/canada_post_pws.rb | 124 +++++++++++++++++- test/credentials.yml | 1 + test/remote/canada_post_pws_test.rb | 60 +++++++-- .../carriers/canada_post_pws_shipping_test.rb | 25 ++++ 7 files changed, 201 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index cc038d895..2aee8f0d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,4 +24,5 @@ env: - ACTIVESHIPPING_CANADA_POST_PWS_CUSTOMER_NUMBER=2004381 - ACTIVESHIPPING_CANADA_POST_PWS_API_KEY=6e93d53968881714 - ACTIVESHIPPING_CANADA_POST_PWS_SECRET=0bfa9fcb9853d1f51ee57a + - ACTIVESHIPPING_CANADA_POST_PWS_CONTRACT=42708517 - ACTIVESHIPPING_USPS_LOGIN=677JADED7283 diff --git a/active_shipping.gemspec b/active_shipping.gemspec index f3d9dc841..4b2e5bd3a 100644 --- a/active_shipping.gemspec +++ b/active_shipping.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |s| s.add_dependency("measured", ">= 2.0") - s.add_dependency("activesupport", ">= 4.2", "< 5.2.0") + s.add_dependency("activesupport", ">= 4.2", "< 6.0.0") s.add_dependency("active_utils", "~> 3.3.1") s.add_dependency("nokogiri", ">= 1.6") diff --git a/dev.yml b/dev.yml index 50cf934ad..f93543708 100644 --- a/dev.yml +++ b/dev.yml @@ -1,7 +1,7 @@ name: active-shipping up: - - ruby: 2.3.1 + - ruby: 2.5.3 - bundler commands: diff --git a/lib/active_shipping/carriers/canada_post_pws.rb b/lib/active_shipping/carriers/canada_post_pws.rb index 2718aecf7..c8518a85d 100644 --- a/lib/active_shipping/carriers/canada_post_pws.rb +++ b/lib/active_shipping/carriers/canada_post_pws.rb @@ -33,6 +33,7 @@ class CanadaPostPWS < Carrier ENDPOINT = "https://soa-gw.canadapost.ca/" # production SHIPMENT_MIMETYPE = "application/vnd.cpc.ncshipment+xml" + CONTRACT_MIMETYPE = "application/vnd.cpc.shipment-v8+xml" RATE_MIMETYPE = "application/vnd.cpc.ship.rate+xml" TRACK_MIMETYPE = "application/vnd.cpc.track+xml" REGISTER_MIMETYPE = "application/vnd.cpc.registration+xml" @@ -107,6 +108,16 @@ def create_shipment(origin, destination, package, line_items = [], options = {}) CPPWSShippingResponse.new(false, "Missing Customer Number", {}, :carrier => @@name) end + def create_contract_shipment(origin, destination, package, line_items = [], options = {}, return_details = {}) + request_body = build_contract_shipment_request(origin, destination, package, line_items, options, return_details) + response = ssl_post(create_contract_shipment_url(options), request_body, headers(options, CONTRACT_MIMETYPE, CONTRACT_MIMETYPE)) + parse_contract_shipment_response(response) + rescue ActiveUtils::ResponseError, ActiveShipping::ResponseError => e + error_response(e.response.body, CPPWSShippingResponse) + rescue MissingCustomerNumberError + CPPWSShippingResponse.new(false, "Missing Customer Number", {}, :carrier => @@name) + end + def retrieve_shipment(shipping_id, options = {}) response = ssl_post(shipment_url(shipping_id, options), nil, headers(options, SHIPMENT_MIMETYPE, SHIPMENT_MIMETYPE)) parse_shipment_response(response) @@ -122,6 +133,11 @@ def retrieve_shipping_label(shipping_response, options = {}) ssl_get(shipping_response.label_url, headers(options, "application/pdf")) end + def retrieve_return_label(shipping_response, options = {}) + raise MissingShippingNumberError unless shipping_response && shipping_response.shipping_id + ssl_get(shipping_response.return_label_url, headers(options, "application/pdf")) + end + def register_merchant(options = {}) url = endpoint + "ot/token" response = ssl_post(url, nil, headers({}, REGISTER_MIMETYPE, REGISTER_MIMETYPE).merge("Content-Length" => "0")) @@ -358,6 +374,7 @@ def build_tracking_events(events) # :show_postage_rate # :cod, :cod_amount, :insurance, :insurance_amount, :signature_required, :pa18, :pa19, :hfp, :dns, :lad # + # def build_shipment_request(origin, destination, package, line_items = [], options = {}) builder = Nokogiri::XML::Builder.new do |xml| xml.public_send('non-contract-shipment', :xmlns => "http://www.canadapost.ca/ws/ncshipment") do @@ -378,10 +395,48 @@ def build_shipment_request(origin, destination, package, line_items = [], option builder.to_xml end + # return_details + # :service_code, :return_recipient {:name, :company, :address_details {:address_line_1...}} + + def build_contract_shipment_request(origin, destination, package, line_items = [], options = {}, return_details = {}) + builder = Nokogiri::XML::Builder.new do |xml| + xml.public_send('shipment', :xmlns => "http://www.canadapost.ca/ws/shipment-v8") do + shipment_node(xml, options) + xml.public_send('delivery-spec') do + shipment_service_code_node(xml, options) + shipment_sender_node(xml, origin, options) + shipment_destination_node(xml, destination, options) + shipment_options_node(xml, options) + shipment_parcel_node(xml, package) + shipment_notification_node(xml, options) + shipment_preferences_node(xml, options) + references_node(xml, options) # optional > user defined custom notes + shipment_customs_node(xml, destination, line_items, options) + settlement_node(xml, options) + # COD Remittance defaults to sender + end + shipment_return_node(xml, return_details, options) + end + end + builder.to_xml + end + + def shipment_node(xml, options) + xml.public_send('transmit-shipment', options[:transmit] || true) + xml.public_send('requested-shipping-point', options[:shipping_point]) + end + def shipment_service_code_node(xml, options) xml.public_send('service-code', options[:service]) end + def settlement_node(xml, options) + xml.public_send('settlement-info') do + xml.public_send('contract-id', options[:contract_number]) + xml.public_send('intended-method-of-payment', options[:payment_type] || 'Account' ) + end + end + def shipment_sender_node(xml, sender, options) location = location_from_hash(sender) xml.public_send('sender') do @@ -393,7 +448,7 @@ def shipment_sender_node(xml, sender, options) xml.public_send('address-line-2', location.address2_and_3) unless location.address2_and_3.blank? xml.public_send('city', location.city) xml.public_send('prov-state', location.province) - # xml.public_send('country-code', location.country_code) + xml.public_send('country-code', location.country_code) unless location.country_code.blank? xml.public_send('postal-zip-code', get_sanitized_postal_code(location)) end end @@ -473,6 +528,28 @@ def shipment_customs_node(xml, destination, line_items, options) end end + # return_details + # :service_code, :return_recipient {:name, :company, :address_details {:address_line_1...}} + + def shipment_return_node(xml, return_details, options) + return if return_details.blank? + location = location_from_hash(return_details[:return_recipient][:address_details]) + xml.public_send('return-spec') do + xml.public_send('service-code', return_details[:service_code] ) + xml.public_send('return-recipient') do + xml.public_send('name', return_details[:name]) if return_details[:name] + xml.public_send('company', return_details[:company]) if return_details[:company] + xml.public_send('address-details') do + xml.public_send('address-line-1', location.address1) + xml.public_send('address-line-2', location.address2_and_3) unless location.address2_and_3.blank? + xml.public_send('city', location.city) + xml.public_send('prov-state', location.province) unless location.province.blank? + xml.public_send('postal-zip-code', get_sanitized_postal_code(location)) + end + end + end + end + def shipment_parcel_node(xml, package, options = {}) weight = sanitize_weight_kg(package.kilograms.to_f) xml.public_send('parcel-characteristics') do @@ -484,7 +561,7 @@ def shipment_parcel_node(xml, package, options = {}) xml.public_send('width', '%.1f' % ((pkg_dim[1] * 10).round / 10.0)) if pkg_dim.size >= 2 xml.public_send('height', '%.1f' % ((pkg_dim[0] * 10).round / 10.0)) if pkg_dim.size >= 1 end - xml.public_send('document', false) + #xml.public_send('document', false) else xml.public_send('document', true) end @@ -494,6 +571,25 @@ def shipment_parcel_node(xml, package, options = {}) end end + def parse_contract_shipment_response(response) + doc = Nokogiri.XML(response) + doc.remove_namespaces! + raise ActiveShipping::ResponseError, "No Shipping" unless doc.at('shipment-info') + receipt_url = doc.root.at_xpath("links/link[@rel='receipt']")['href'] unless doc.root.at_xpath("links/link[@rel='receipt']").blank? + return_label_url = doc.root.at_xpath("links/link[@rel='returnLabel']")['href'] unless doc.root.at_xpath("links/link[@rel='returnLabel']").blank? + options = { + :shipping_id => doc.root.at('shipment-id').text, + :details_url => doc.root.at_xpath("links/link[@rel='details']")['href'], + :label_url => doc.root.at_xpath("links/link[@rel='label']")['href'], + :receipt_url => receipt_url, + :return_label_url => return_label_url + } + options[:tracking_number] = doc.root.at('tracking-pin').text if doc.root.at('tracking-pin') + options[:return_tracking_number] = doc.root.at('return-tracking-pin').text if doc.root.at('return-tracking-pin') + puts "OPTIONS: #{options}" + CPPWSContractShippingResponse.new(true, "", {}, options) + end + def parse_shipment_response(response) doc = Nokogiri.XML(response) doc.remove_namespaces! @@ -505,7 +601,6 @@ def parse_shipment_response(response) :receipt_url => doc.root.at_xpath("links/link[@rel='receipt']")['href'], } options[:tracking_number] = doc.root.at('tracking-pin').text if doc.root.at('tracking-pin') - CPPWSShippingResponse.new(true, "", {}, options) end @@ -604,6 +699,15 @@ def create_shipment_url(options) end end + def create_contract_shipment_url(options) + raise MissingCustomerNumberError unless customer_number = options[:customer_number] + if @platform_id.present? + endpoint + "rs/#{customer_number}-#{@platform_id}/shipment" + else + endpoint + "rs/#{customer_number}/#{customer_number}/shipment" + end + end + def shipment_url(shipping_id, options = {}) raise MissingCustomerNumberError unless customer_number = options[:customer_number] if @platform_id.present? @@ -873,6 +977,20 @@ def initialize(success, message, params = {}, options = {}) end end + class CPPWSContractShippingResponse < ShippingResponse + include CPPWSErrorResponse + attr_reader :label_url, :details_url, :receipt_url, :return_label_url, :return_tracking_number + def initialize(success, message, params = {}, options = {}) + handle_error(message, options) + super + @label_url = options[:label_url] + @details_url = options[:details_url] + @receipt_url = options[:receipt_url] + @return_label_url = options[:return_label_url] + @return_tracking_number = options[:return_tracking_number] + end + end + class CPPWSRegisterResponse < Response include CPPWSErrorResponse attr_reader :token_id diff --git a/test/credentials.yml b/test/credentials.yml index 861689b83..dc706aecf 100644 --- a/test/credentials.yml +++ b/test/credentials.yml @@ -34,6 +34,7 @@ canada_post_pws: customer_number: <%= ENV['ACTIVESHIPPING_CANADA_POST_PWS_CUSTOMER_NUMBER'] %> api_key: <%= ENV['ACTIVESHIPPING_CANADA_POST_PWS_API_KEY'] %> secret: <%= ENV['ACTIVESHIPPING_CANADA_POST_PWS_SECRET'] %> + contract_number: <%= ENV['ACTIVESHIPPING_CANADA_POST_PWS_CONTRACT'] %> canada_post_pws_platform: platform_id: <%= ENV['ACTIVESHIPPING_CANADA_POST_PWS_PLATFORM_PLATFORM_ID'] %> diff --git a/test/remote/canada_post_pws_test.rb b/test/remote/canada_post_pws_test.rb index ac2d1fa72..c29b60d7d 100644 --- a/test/remote/canada_post_pws_test.rb +++ b/test/remote/canada_post_pws_test.rb @@ -2,6 +2,8 @@ class RemoteCanadaPostPWSTest < ActiveSupport::TestCase # All remote tests require Canada Post development environment credentials + # When using an account with a contract number you should add it to the opts hash + include ActiveShipping::Test::Credentials include ActiveShipping::Test::Fixtures @@ -14,7 +16,9 @@ def setup @line_item1 = line_item_fixture - @shipping_opts1 = { :dc => true, :cov => true, :cov_amount => 100.00, :aban => true } + @shipping_opts1 = {:cod => true, :dc => true, :cov => true, :cov_amount => 100.00, :aban => true } + + @shipping_opts2 = {so: true, cov: true, cov_amount: 999.99, transmit: true, shipping_point: 'R3W1S1'} @home_params = { :name => "John Smith", @@ -23,11 +27,22 @@ def setup :address1 => "123 Elm St.", :city => 'Ottawa', :province => 'ON', - :country => 'CA', :postal_code => 'K1P 1J1' } @home = Location.new(@home_params) + @contract_home_params = { + :name => "John Smith", + :company => "test", + :phone => "613-555-1212", + :address1 => "123 Elm St.", + :city => 'Ottawa', + :province => 'ON', + :country => 'CA', + :postal_code => 'K1P 1J1' + } + @contract_home = Location.new(@contract_home_params) + @dom_params = { :name => "John Smith Sr.", :company => "", @@ -77,6 +92,7 @@ def setup @cp.logger = Logger.new(StringIO.new) @customer_number = @login[:customer_number] + @contract_number = @login[:contract_number] @DEFAULT_RESPONSE = { :shipping_id => "406951321983787352", @@ -121,25 +137,51 @@ def test_tracking_when_no_tracking_info_raises_exception end def test_create_shipment - skip "Failing with 'Contract Number is a required field' after API change, skipping because no clue how to fix, might need different creds" + skip "contract number in credentials" if @contract_number opts = {:customer_number => @customer_number, :service => "DOM.XP"} response = @cp.create_shipment(@home_params, @dom_params, @pkg1, @line_item1, opts) assert_kind_of CPPWSShippingResponse, response - assert_match /\A\d{17}\z/, response.shipping_id + assert_match /\A\d{18}\z/, response.shipping_id assert_equal "123456789012", response.tracking_number - assert_match "https://ct.soa-gw.canadapost.ca/ers/artifact/", response.label_url + assert_match "https://ct.soa-gw.canadapost.ca/rs/artifact/", response.label_url assert_match @login[:api_key], response.label_url end def test_create_shipment_with_options - skip "Failing with 'Contract Number is a required field' after API change, skipping because no clue how to fix, might need different creds" + skip "contract number in credentials" if @contract_number opts = {:customer_number => @customer_number, :service => "USA.EP"}.merge(@shipping_opts1) response = @cp.create_shipment(@home_params, @dest_params, @pkg1, @line_item1, opts) - assert_kind_of CPPWSShippingResponse, response - assert_match /\A\d{17}\z/, response.shipping_id + assert_match /\A\d{18}\z/, response.shipping_id + assert_equal "123456789012", response.tracking_number + assert_match "https://ct.soa-gw.canadapost.ca/rs/artifact/", response.label_url + assert_match @login[:api_key], response.label_url + end + + def test_create_contract_shipment_with_options + skip "no contract number in credentials" unless @contract_number + opts = {:customer_number => @customer_number, :service => "DOM.XP", contract_number: @contract_number}.merge(@shipping_opts2) + response = @cp.create_contract_shipment(@contract_home_params, @dom_params, @pkg1, @line_item1, opts) + assert_kind_of CPPWSContractShippingResponse, response + assert_match /\A\d{18}\z/, response.shipping_id + assert_equal "123456789012", response.tracking_number + assert_match "https://ct.soa-gw.canadapost.ca/rs/artifact/", response.label_url + assert_match @login[:api_key], response.label_url + end + + def test_create_contract_shipment_with_return_label_and_options + skip "no contract number in credentials" unless @contract_number + + opts = {:customer_number => @customer_number, :service => "DOM.XP", contract_number: @contract_number}.merge(@shipping_opts2) + + return_details = {service_code: 'DOM.RP', return_recipient: { address_details: @contract_home_params } } + + response = @cp.create_contract_shipment(@contract_home_params, @dom_params, @pkg1, @line_item1, opts, return_details) + assert_kind_of CPPWSContractShippingResponse, response + assert_match /\A\d{18}\z/, response.shipping_id assert_equal "123456789012", response.tracking_number - assert_match "https://ct.soa-gw.canadapost.ca/ers/artifact/", response.label_url + assert_match "https://ct.soa-gw.canadapost.ca/rs/artifact/", response.label_url + assert_match "https://ct.soa-gw.canadapost.ca/rs/artifact/", response.return_label_url assert_match @login[:api_key], response.label_url end diff --git a/test/unit/carriers/canada_post_pws_shipping_test.rb b/test/unit/carriers/canada_post_pws_shipping_test.rb index 20db669f8..fd95a5d27 100644 --- a/test/unit/carriers/canada_post_pws_shipping_test.rb +++ b/test/unit/carriers/canada_post_pws_shipping_test.rb @@ -63,6 +63,7 @@ def setup :so => true, :pa18 => true} @default_options = {:customer_number => '123456'} + @default_contract_options = {:customer_number => '123456', :contract_number => '42708517'} @DEFAULT_RESPONSE = { :shipping_id => "406951321983787352", @@ -93,6 +94,30 @@ def test_build_shipment_request_for_domestic refute request.blank? end + def test_build_contract_shipment_request_for_domestic + options = @default_contract_options.dup + request = @cp.build_contract_shipment_request(@home_params, @dom_params, @pkg1, @line_item1, options) + refute request.blank? + end + + def test_build_contract_shipment_with_return_request_for_domestic + options = @default_contract_options.dup + return_details = {service_code: 'DOM.RP', return_recipient: { address_details: @home_params } } + + request = @cp.build_contract_shipment_request(@home_params, @dom_params, @pkg1, @line_item1, options, return_details) + refute request.blank? + + doc = Nokogiri.XML(request) + doc.remove_namespaces! + + assert root_node = doc.at('shipment') + assert delivery_spec = root_node.at('delivery-spec') + assert destination = delivery_spec.at('destination') + assert address_details = destination.at('address-details') + assert_equal 'CA', address_details.at('country-code').text + assert return_spec = root_node.at('return-spec') + end + def test_build_shipment_request_for_US options = @default_options.dup request = @cp.build_shipment_request(@home_params, @us_params, @pkg1, @line_item1, options) From c761e07abeeb2281dc4789e2142f149df4d1fcf7 Mon Sep 17 00:00:00 2001 From: Bob Perkinson Date: Mon, 3 Jun 2019 12:00:48 -0500 Subject: [PATCH 3/8] update ruby version for testing --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 2aee8f0d8..312e56cff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ rvm: - "2.2.2" - "2.3.1" - "2.4.0" +- "2.5.3" gemfile: - gemfiles/activesupport42.gemfile From f781b715f10c04a530352170da36e7e8ff6db978 Mon Sep 17 00:00:00 2001 From: Bob Perkinson Date: Tue, 4 Jun 2019 07:51:18 -0500 Subject: [PATCH 4/8] update version --- lib/active_shipping/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/active_shipping/version.rb b/lib/active_shipping/version.rb index a1365a03d..93ad7087a 100644 --- a/lib/active_shipping/version.rb +++ b/lib/active_shipping/version.rb @@ -1,3 +1,3 @@ module ActiveShipping - VERSION = "2.2.0" + VERSION = "2.2.1" end From cf1e59e891669019ee55daaccb843b9f593b88d1 Mon Sep 17 00:00:00 2001 From: Bob Perkinson Date: Tue, 4 Jun 2019 08:05:07 -0500 Subject: [PATCH 5/8] update version --- lib/active_shipping/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/active_shipping/version.rb b/lib/active_shipping/version.rb index a1365a03d..93ad7087a 100644 --- a/lib/active_shipping/version.rb +++ b/lib/active_shipping/version.rb @@ -1,3 +1,3 @@ module ActiveShipping - VERSION = "2.2.0" + VERSION = "2.2.1" end From 37b1dde05c501efab55a97961ee0946696736f65 Mon Sep 17 00:00:00 2001 From: Bob Perkinson Date: Tue, 4 Jun 2019 08:18:42 -0500 Subject: [PATCH 6/8] change of default address --- lib/active_shipping/carriers/canada_post_pws.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/active_shipping/carriers/canada_post_pws.rb b/lib/active_shipping/carriers/canada_post_pws.rb index 019fa4626..c8606adad 100644 --- a/lib/active_shipping/carriers/canada_post_pws.rb +++ b/lib/active_shipping/carriers/canada_post_pws.rb @@ -71,7 +71,7 @@ def self.default_location :province => 'ON', :city => 'Ottawa', :address1 => '61A York St', - :postal_code => 'K1N5T2' + :postal_code => 'K1N5T3' } end From 9d764a3447a6e864f85f8674942d687b92a93a32 Mon Sep 17 00:00:00 2001 From: Bob Perkinson Date: Wed, 12 Jun 2019 16:56:47 -0500 Subject: [PATCH 7/8] final additions to retrieving manifest details and downloading documents added tests for some manifest calls. --- .../carriers/canada_post_pws.rb | 197 +++++++++++++++++- lib/active_shipping/location.rb | 4 + lib/active_shipping/version.rb | 2 +- .../xml/canadapost_pws/group_ids_response.xml | 6 + .../xml/canadapost_pws/manifest_details.xml | 7 + .../xml/canadapost_pws/transmit_response.xml | 4 + .../xml/canadapost_pws/transmit_set.xml | 20 ++ .../carriers/canada_post_pws_shipping_test.rb | 15 ++ test/unit/carriers/canada_post_pws_test.rb | 6 +- 9 files changed, 256 insertions(+), 5 deletions(-) create mode 100644 test/fixtures/xml/canadapost_pws/group_ids_response.xml create mode 100644 test/fixtures/xml/canadapost_pws/manifest_details.xml create mode 100644 test/fixtures/xml/canadapost_pws/transmit_response.xml create mode 100644 test/fixtures/xml/canadapost_pws/transmit_set.xml diff --git a/lib/active_shipping/carriers/canada_post_pws.rb b/lib/active_shipping/carriers/canada_post_pws.rb index c8606adad..d810b0130 100644 --- a/lib/active_shipping/carriers/canada_post_pws.rb +++ b/lib/active_shipping/carriers/canada_post_pws.rb @@ -37,6 +37,8 @@ class CanadaPostPWS < Carrier RATE_MIMETYPE = "application/vnd.cpc.ship.rate+xml" TRACK_MIMETYPE = "application/vnd.cpc.track+xml" REGISTER_MIMETYPE = "application/vnd.cpc.registration+xml" + MANIFEST_MIMETYPE = "application/vnd.cpc.manifest-v8+xml" + LANGUAGE = { 'en' => 'en-CA', @@ -75,6 +77,31 @@ def self.default_location } end + def list_group_ids(options ={}) + url = endpoint + "rs/#{@customer_number}/#{@customer_number}/group" + response = ssl_get(url, headers(options, CONTRACT_MIMETYPE)) + parse_group_ids_response(response) + rescue ActiveUtils::ResponseError, ActiveShipping::ResponseError => e + error_response(e.response.body, CPPWSGroupResponse) + end + + def transmit_shipments(warehouse_location, options = {}) + url = endpoint + "rs/#{@customer_number}/#{@customer_number}/manifest" + request = build_transmit_request(warehouse_location, options) + response = ssl_post(url, request, headers(options, MANIFEST_MIMETYPE, MANIFEST_MIMETYPE)) + parse_transmit_response(response) + rescue ActiveUtils::ResponseError, ActiveShipping::ResponseError => e + error_response(e.response.body, CPPWSTransmitResponse) if e.response + end + + def find_manifest(manifest_url, options = {}) + url = manifest_url + response = ssl_get(url, headers(options, MANIFEST_MIMETYPE)) + parse_manifest_response(response) + rescue ActiveUtils::ResponseError, ActiveShipping::ResponseError => e + error_response(e.response.body, CPPWSManifestResponse) + end + def find_rates(origin, destination, line_items = [], options = {}, package = nil, services = []) url = endpoint + "rs/ship/price" request = build_rates_request(origin, destination, line_items, options, package, services) @@ -138,6 +165,12 @@ def retrieve_return_label(shipping_response, options = {}) ssl_get(shipping_response.return_label_url, headers(options, "application/pdf")) end + def retrieve_manifest_document(transmit_response, options = {}) + raise MissingTransmitError unless transmit_response + ssl_get(transmit_response, headers(options, "application/pdf")) + end + + def register_merchant(options = {}) url = endpoint + "ot/token" response = ssl_post(url, nil, headers({}, REGISTER_MIMETYPE, REGISTER_MIMETYPE).merge("Content-Length" => "0")) @@ -310,6 +343,46 @@ def parse_rates_response(response, origin, destination, exclude_tax) CPPWSRateResponse.new(true, "", {}, :rates => rates) end + def parse_group_ids_response(response) + doc = Nokogiri.XML(response) + doc.remove_namespaces! + raise ActiveShipping::ResponseError, "No Group ID's" unless doc.at('groups') + group_ids = [] + group_ids = doc.root.xpath('group').map do |node| + link = node.at("link")['href'] + group_id = node.at("group-id").text + group_ids << {link: link, group_id: group_id} + end + CPPWSGroupResponse.new(true, "", {}, :group_ids => group_ids) + end + + def parse_transmit_response(response) + doc = Nokogiri.XML(response) + doc.remove_namespaces! + raise ActiveShipping::ResponseError, "No manifests" unless doc.at('manifests') + manifests = [] + manifests = doc.xpath('manifests').map do |node| + link = node.at("link")['href'] + end + CPPWSTransmitResponse.new(true, "", {}, :manifests => manifests) + end + + def parse_manifest_response(response) + doc = Nokogiri.XML(response) + doc.remove_namespaces! + raise ActiveShipping::ResponseError, "No manifests" unless doc.at('manifest') + + po_number = doc.at("manifest/po-number").text + manifest_url = doc.at_xpath("manifest/links/link[@rel='self']")['href'] + artifact_url = doc.at_xpath("manifest/links/link[@rel='artifact']")['href'] + details_url = doc.at_xpath("manifest/links/link[@rel='details']")['href'] + manifest_shipments_url = doc.at_xpath("manifest/links/link[@rel='manifestShipments']")['href'] + manifest = CPPWSManifest.new(po_number, manifest_url, artifact_url, details_url, manifest_shipments_url) + + + CPPWSManifestResponse.new(true, "", {}, :manifest => manifest) + end + def price_from_node(node, exclude_tax) price = node.at('price-details/due').text return price unless exclude_tax @@ -421,8 +494,80 @@ def build_contract_shipment_request(origin, destination, package, line_items = [ builder.to_xml end + def build_transmit_request(warehouse_location, options = {}) + builder = Nokogiri::XML::Builder.new do |xml| + xml.public_send('transmit-set', :xmlns => "http://www.canadapost.ca/ws/manifest-v8") do + group_node(xml, options) + unless options[:shipping_point].nil? + options[:postal_simple] = warehouse_location.postal_simple + options[:pickup_indicator] = true + requested_shipping_point_node(xml, options) + cpc_pickup_indicator_node(xml, options) + else + shipping_point_node(xml, options) + end + method_of_payment_node(xml, options) + manifest_address_node(warehouse_location, xml, options) + detailed_manifests_node(xml, options) + end + end + builder.to_xml + end + + def detailed_manifests_node(xml, options) + xml.public_send('detailed-manifests', options[:detailed_manifest] || false) + end + + def manifest_address_node(warehouse_location, xml, options) + xml.public_send('manifest-address') do + xml.public_send('manifest-company' , warehouse_location.company) + xml.public_send('phone-number' , warehouse_location.phone) + xml.public_send('address-details') do + xml.public_send('address-line-1', warehouse_location.address1) + xml.public_send('address-line-2', warehouse_location.address2) unless warehouse_location.address2.blank? + xml.public_send('city', warehouse_location.city) + xml.public_send('prov-state', warehouse_location.province) + xml.public_send('country-code', warehouse_location.country_code) + # pc_strip = warehouse_location.postal_code.sub(/[^a-zA-Z0-9]/,'') + xml.public_send('postal-zip-code', warehouse_location.postal_simple) + end + end + end + + def method_of_payment_node(xml, options) + #CreditCard Account SupplierAccount + #default to account + pay_method = options[:payment_method] || "Account" + xml.public_send('method-of-payment', pay_method) + end + + def requested_shipping_point_node(xml, options) + xml.public_send('requested-shipping-point', options[:postal_simple]) + end + + def cpc_pickup_indicator_node(xml, options) + xml.public_send('cpc-pickup-indicator', options[:pickup_indicator]) + end + + def shipping_point_node(xml, options) + xml.public_send('shipping-point-id', options[:shipping_point_id]) + end + + def group_node(xml, options) + raise ActiveShipping::ResponseError, "No Group ID's defined in options" unless options[:group_ids].is_a?(Array) + xml.public_send('group-ids') do + options[:group_ids].each do |grp| + xml.public_send('group-id' , grp) + end + end + end + def shipment_node(xml, options) - xml.public_send('transmit-shipment', options[:transmit] || true) + if !!options[:transmit] + xml.public_send('transmit-shipment', options[:transmit] || true) + else + xml.public_send('group-id', options[:group_id]) + end xml.public_send('requested-shipping-point', options[:shipping_point]) end @@ -934,6 +1079,32 @@ def initialize(success, message, params = {}, options = {}) end end + class CPPWSGroupResponse < Response + DELIVERED_EVENT_CODES = %w(404 AA003) + include CPPWSErrorResponse + + attr_reader :group_ids + + def initialize(success, message, params = {}, options = {}) + handle_error(message, options) + super + @group_ids = options[:group_ids] + end + end + + class CPPWSManifestResponse < Response + DELIVERED_EVENT_CODES = %w(7313 7317 9118 9119 9122 9186 9187 9188 9189) + include CPPWSErrorResponse + + attr_reader :manifest + + def initialize(success, message, params = {}, options = {}) + handle_error(message, options) + super + @manifest = options[:manifest] + end + end + class CPPWSTrackingResponse < TrackingResponse DELIVERED_EVENT_CODES = %w(1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1441 1442 1496 1497 1498 1499 5300) include CPPWSErrorResponse @@ -977,6 +1148,29 @@ def initialize(success, message, params = {}, options = {}) end end + class CPPWSTransmitResponse < Response + include CPPWSErrorResponse + attr_reader :manifest_urls + def initialize(success, message, params = {}, options = {}) + handle_error(message, options) + super + @manifest_urls = options[:manifests] + + end + end + + class CPPWSManifest < Response + attr_reader :po_number, :manifest_url, :artifact_url, :details_url, :manifest_shipments_url + + def initialize(po_number, manifest_url, artifact_url, details_url, manifest_shipments_url) + @po_number = po_number + @manifest_url = manifest_url + @artifact_url = artifact_url + @details_url = details_url + @manifest_shipments_url = manifest_shipments_url + end + end + class CPPWSContractShippingResponse < ShippingResponse include CPPWSErrorResponse attr_reader :label_url, :details_url, :receipt_url, :return_label_url, :return_tracking_number @@ -1024,4 +1218,5 @@ class InvalidPinFormatError < StandardError; end class MissingCustomerNumberError < StandardError; end class MissingShippingNumberError < StandardError; end class MissingTokenIdError < StandardError; end + class MissingTransmitError < StandardError; end end diff --git a/lib/active_shipping/location.rb b/lib/active_shipping/location.rb index ebcf777b2..622db13b2 100644 --- a/lib/active_shipping/location.rb +++ b/lib/active_shipping/location.rb @@ -135,6 +135,10 @@ def to_s prettyprint.gsub(/\n/, ' ') end + def postal_simple + @postal_code.sub(/[^a-zA-Z0-9]/,'') + end + def prettyprint chunks = [@name, @address1, @address2, @address3] chunks << [@city, @province, @postal_code].reject(&:blank?).join(', ') diff --git a/lib/active_shipping/version.rb b/lib/active_shipping/version.rb index 93ad7087a..feb9fec8e 100644 --- a/lib/active_shipping/version.rb +++ b/lib/active_shipping/version.rb @@ -1,3 +1,3 @@ module ActiveShipping - VERSION = "2.2.1" + VERSION = "2.2.2" end diff --git a/test/fixtures/xml/canadapost_pws/group_ids_response.xml b/test/fixtures/xml/canadapost_pws/group_ids_response.xml new file mode 100644 index 000000000..37fc7cc45 --- /dev/null +++ b/test/fixtures/xml/canadapost_pws/group_ids_response.xml @@ -0,0 +1,6 @@ + + + + 123456 + + \ No newline at end of file diff --git a/test/fixtures/xml/canadapost_pws/manifest_details.xml b/test/fixtures/xml/canadapost_pws/manifest_details.xml new file mode 100644 index 000000000..70de00aa9 --- /dev/null +++ b/test/fixtures/xml/canadapost_pws/manifest_details.xml @@ -0,0 +1,7 @@ + + D906367941 + + + + + \ No newline at end of file diff --git a/test/fixtures/xml/canadapost_pws/transmit_response.xml b/test/fixtures/xml/canadapost_pws/transmit_response.xml new file mode 100644 index 000000000..594f533fb --- /dev/null +++ b/test/fixtures/xml/canadapost_pws/transmit_response.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/test/fixtures/xml/canadapost_pws/transmit_set.xml b/test/fixtures/xml/canadapost_pws/transmit_set.xml new file mode 100644 index 000000000..f3d69c2e8 --- /dev/null +++ b/test/fixtures/xml/canadapost_pws/transmit_set.xml @@ -0,0 +1,20 @@ + + + 1234 + + K1K4T3 + true + true + Account + + my company + MajorShop + 555 555 5555 + + 1230 Tako RD. + Ottawa + ON + K1A1A1 + + + \ No newline at end of file diff --git a/test/unit/carriers/canada_post_pws_shipping_test.rb b/test/unit/carriers/canada_post_pws_shipping_test.rb index fd95a5d27..7e92abaf6 100644 --- a/test/unit/carriers/canada_post_pws_shipping_test.rb +++ b/test/unit/carriers/canada_post_pws_shipping_test.rb @@ -280,4 +280,19 @@ def test_parse_find_shipment_receipt_doesnt_break_without_priced_options def test_maximum_address_field_length assert_equal 44, @cp.maximum_address_field_length end + + def test_manifest_group_ids + options = @default_options.dup + xml_response = xml_fixture('canadapost_pws/group_ids_response') + @cp.expects(:ssl_get).once.returns(xml_response) + response = @cp.list_group_ids(options) + assert_equal @cp.parse_group_ids_response(xml_response).group_ids, response.group_ids + end + + def test_transmit_shipments + options = @default_options.dup + xml_response = xml_fixture('canadapost_pws/transmit_response') + response = @cp.transmit_shipments(Location.new(@home_params), options) + assert response.nil? + end end diff --git a/test/unit/carriers/canada_post_pws_test.rb b/test/unit/carriers/canada_post_pws_test.rb index 8e844ba23..e8942b5fe 100644 --- a/test/unit/carriers/canada_post_pws_test.rb +++ b/test/unit/carriers/canada_post_pws_test.rb @@ -10,17 +10,17 @@ def setup def test_get_sanitized_postal_code_location_nil postal_code = @cp.send(:get_sanitized_postal_code, nil) - assert_equal nil, postal_code + assert_nil postal_code end def test_get_sanitized_postal_code_postal_code_nil location = Location.new(name: 'Test test') - assert_equal nil, location.postal_code + assert_nil location.postal_code postal_code = @cp.send(:get_sanitized_postal_code, location) - assert_equal nil, postal_code + assert_nil postal_code end def test_get_sanitized_postal_code_spaces From c562cd60fd504e70fc65497589ab70bd3771f36c Mon Sep 17 00:00:00 2001 From: Bob Perkinson Date: Tue, 17 Dec 2019 11:07:24 -0600 Subject: [PATCH 8/8] added support for activesupport 6 --- active_shipping.gemspec | 2 +- gemfiles/activesupport60.gemfile | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 gemfiles/activesupport60.gemfile diff --git a/active_shipping.gemspec b/active_shipping.gemspec index 4b2e5bd3a..095063ba9 100644 --- a/active_shipping.gemspec +++ b/active_shipping.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |s| s.add_dependency("measured", ">= 2.0") - s.add_dependency("activesupport", ">= 4.2", "< 6.0.0") + s.add_dependency("activesupport", ">= 4.2", "< 6.1.0") s.add_dependency("active_utils", "~> 3.3.1") s.add_dependency("nokogiri", ">= 1.6") diff --git a/gemfiles/activesupport60.gemfile b/gemfiles/activesupport60.gemfile new file mode 100644 index 000000000..dc3fca536 --- /dev/null +++ b/gemfiles/activesupport60.gemfile @@ -0,0 +1,6 @@ +source "https://rubygems.org" + +gemspec path: '..' + +gem 'activesupport', '~> 6.0.0' +gem 'active_utils', '~> 3.3.0'