diff --git a/lib/active_merchant/billing/gateways/eway_managed.rb b/lib/active_merchant/billing/gateways/eway_managed.rb index a3b01cfd3ad..f89e5bb075b 100644 --- a/lib/active_merchant/billing/gateways/eway_managed.rb +++ b/lib/active_merchant/billing/gateways/eway_managed.rb @@ -45,7 +45,7 @@ def store(creditcard, options = {}) add_creditcard(post, creditcard) add_address(post, billing_address) - add_misc_fields(post, billing_address) + add_misc_fields(post, options) commit("CreateCustomer", post) end @@ -63,17 +63,30 @@ def update(billing_id, creditcard, options={}) post[:managedCustomerID]=billing_id add_creditcard(post, creditcard) add_address(post, billing_address) - add_misc_fields(post, billing_address) + add_misc_fields(post, options) commit("UpdateCustomer", post) end - #process payment for given amount from stored CC "ManagedCustomerID = billing_id" + # Process a payment in the given amount against the stored credit card given by billing_id + # + # ==== Parameters + # + # * money -- The amount to be purchased as an Integer value in cents. + # * billing_id -- The eWay provided card/customer token to charge (managedCustomerID) + # * options -- A hash of optional parameters. + # + # ==== Options + # + # * :order_id -- The order number, passed to eWay as the "Invoice Reference" + # * :invoice -- The invoice number, passed to eWay as the "Invoice Reference" unless :order_id is also given + # * :description -- A description of the payment, passed to eWay as the "Invoice Description" def purchase(money, billing_id, options={}) post = {} post[:managedCustomerID] = billing_id.to_s post[:amount]=money - + add_invoice(post, options) + commit("ProcessPayment", post) end @@ -102,14 +115,21 @@ def add_address(post, address) end def add_misc_fields(post, options) - post[:CustomerRef]=options[:customer_ref].to_s - post[:Title]=options[:title] - post[:Company]=options[:company] - post[:JobDesc]=options[:job_desc] - post[:Email]=options[:email] - post[:URL]=options[:url] + post[:CustomerRef]=options[:billing_address][:customer_ref] || options[:customer] + post[:Title]=options[:billing_address][:title] + post[:Company]=options[:billing_address][:company] + post[:JobDesc]=options[:billing_address][:job_desc] + post[:Email]=options[:billing_address][:email] || options[:email] + post[:URL]=options[:billing_address][:url] + post[:Comments]=options[:description] + end + + def add_invoice(post, options) + post[:invoiceReference] = options[:order_id] || options[:invoice] + post[:invoiceDescription] = options[:description] end + # add credit card details to be stored by eway. NOTE eway requires "title" field def add_creditcard(post, creditcard) post[:CCNumber] = creditcard.number @@ -188,7 +208,12 @@ def commit(action, post) # Where we build the full SOAP 1.2 request using builder def soap_request(arguments, action) # eWay demands all fields be sent, but contain an empty string if blank - post=default_fields.merge(arguments) + post = case action + when 'ProcessPayment' + default_payment_fields.merge(arguments) + else + default_customer_fields.merge(arguments) + end xml = Builder::XmlMarkup.new :indent => 2 xml.instruct! @@ -211,7 +236,7 @@ def soap_request(arguments, action) xml.target! end - def default_fields + def default_customer_fields hash={} %w( CustomerRef Title FirstName LastName Company JobDesc Email Address Suburb State PostCode Country Phone Mobile Fax URL Comments CCNumber CCNameOnCard CCExpiryMonth CCExpiryYear ).each do |field| hash[field.to_sym]='' @@ -219,6 +244,14 @@ def default_fields return hash end + def default_payment_fields + hash={} + %w( managedCustomerID amount invoiceReference invoiceDescription ).each do |field| + hash[field.to_sym]='' + end + return hash + end + class EwayResponse < Response # add a method to response so we can easily get the eway token "ManagedCustomerID" def token diff --git a/test/remote/gateways/remote_eway_managed_test.rb b/test/remote/gateways/remote_eway_managed_test.rb index dc5f2c3bd93..e8cf6e26691 100644 --- a/test/remote/gateways/remote_eway_managed_test.rb +++ b/test/remote/gateways/remote_eway_managed_test.rb @@ -35,7 +35,7 @@ def test_invalid_login :username => '' ) assert response = gateway.purchase(@amount, @valid_customer_id, @options) - assert_equal 'Login failed', response.message + assert_equal 'Login failed. ', response.message assert_failure response end diff --git a/test/unit/gateways/eway_managed_test.rb b/test/unit/gateways/eway_managed_test.rb index b3cdaaeeb6b..c49469c0818 100644 --- a/test/unit/gateways/eway_managed_test.rb +++ b/test/unit/gateways/eway_managed_test.rb @@ -26,7 +26,10 @@ def setup :phone => '(555)555-5555' }, :email => 'someguy1232@fakeemail.net', - :order_id => '1000' + :order_id => '1000', + :customer => 'mycustomerref', + :description => 'My Description', + :invoice => 'invoice-4567' } end @@ -78,6 +81,51 @@ def test_successful_purchase assert_equal "123456", response.authorization assert response.test? end + + def test_expected_request_on_purchase + @gateway.expects(:ssl_post).with { |endpoint, data, headers| + # Compare the actual and expected XML documents, by converting them to Hashes first + expected = Hash.from_xml(expected_purchase_request) + actual = Hash.from_xml(data) + expected == actual + }.returns(successful_purchase_response) + @gateway.purchase(@amount, @valid_customer_id, @options) + end + + def test_purchase_invoice_reference_comes_from_order_id_or_invoice + options = @options.dup + + # invoiceReference == options[:order_id] + options[:order_id] = 'order_id' + options.delete(:invoice) + + @gateway.expects(:ssl_post).with { |endpoint, data, headers| + request_hash = Hash.from_xml(data) + request_hash['Envelope']['Body']['ProcessPayment']['invoiceReference'] == 'order_id' + }.returns(successful_purchase_response) + @gateway.purchase(@amount, @valid_customer_id, options) + + # invoiceReference == options[:invoice] + options[:invoice] = 'invoice' + options.delete(:order_id) + + @gateway.expects(:ssl_post).with { |endpoint, data, headers| + request_hash = Hash.from_xml(data) + request_hash['Envelope']['Body']['ProcessPayment']['invoiceReference'] == 'invoice' + }.returns(successful_purchase_response) + @gateway.purchase(@amount, @valid_customer_id, options) + + # invoiceReference == options[:order_id] || options[:invoice] + options[:order_id] = 'order_id' + options[:invoice] = 'invoice' + + @gateway.expects(:ssl_post).with { |endpoint, data, headers| + request_hash = Hash.from_xml(data) + request_hash['Envelope']['Body']['ProcessPayment']['invoiceReference'] == 'order_id' + }.returns(successful_purchase_response) + @gateway.purchase(@amount, @valid_customer_id, options) + + end def test_invalid_customer_id @gateway.expects(:ssl_post).returns(unsuccessful_authorization_response) @@ -97,6 +145,84 @@ def test_successful_store assert_equal "1234567", response.token assert response.test? end + + def test_expected_request_on_store + @gateway.expects(:ssl_post).with { |endpoint, data, headers| + # Compare the actual and expected XML documents, by converting them to Hashes first + expected = Hash.from_xml(expected_store_request) + actual = Hash.from_xml(data) + expected == actual + }.returns(successful_store_response) + @gateway.store(@credit_card, @options) + end + + def test_email_on_store_may_come_from_options_root_or_billing_address + options = @options.dup + + # Legacy Behavior + options.delete(:email) + options[:billing_address][:email] = 'email+billing@example.com' + + @gateway.expects(:ssl_post).with { |endpoint, data, headers| + request_hash = Hash.from_xml(data) + request_hash['Envelope']['Body']['CreateCustomer']['Email'] == 'email+billing@example.com' + }.returns(successful_store_response) + @gateway.store(@credit_card, options) + + # Desired Behavior + options[:billing_address].delete(:email) + options[:email] = 'email+root@example.com' + + @gateway.expects(:ssl_post).with { |endpoint, data, headers| + request_hash = Hash.from_xml(data) + request_hash['Envelope']['Body']['CreateCustomer']['Email'] == 'email+root@example.com' + }.returns(successful_store_response) + @gateway.store(@credit_card, options) + + # Precedence given to billing address when email is in both hashes (to support legacy behavior) + options[:billing_address][:email] = 'email+billing@example.com' + options[:email] = 'email+root@example.com' + + @gateway.expects(:ssl_post).with { |endpoint, data, headers| + request_hash = Hash.from_xml(data) + request_hash['Envelope']['Body']['CreateCustomer']['Email'] == 'email+billing@example.com' + }.returns(successful_store_response) + @gateway.store(@credit_card, options) + end + + def test_customer_ref_on_store_may_come_from_options_root_or_billing_address + options = @options.dup + + # Legacy Behavior + options.delete(:customer) + options[:billing_address][:customer_ref] = 'customer_ref+billing' + + @gateway.expects(:ssl_post).with { |endpoint, data, headers| + request_hash = Hash.from_xml(data) + request_hash['Envelope']['Body']['CreateCustomer']['CustomerRef'] == 'customer_ref+billing' + }.returns(successful_store_response) + @gateway.store(@credit_card, options) + + # Desired Behavior + options[:billing_address].delete(:customer_ref) + options[:customer] = 'customer_ref+root' + + @gateway.expects(:ssl_post).with { |endpoint, data, headers| + request_hash = Hash.from_xml(data) + request_hash['Envelope']['Body']['CreateCustomer']['CustomerRef'] == 'customer_ref+root' + }.returns(successful_store_response) + @gateway.store(@credit_card, options) + + # Precedence given to billing address when customer_ref is in both hashes (to support legacy behavior) + options[:billing_address][:customer_ref] = 'customer_ref+billing' + options[:customer] = 'customer_ref+root' + + @gateway.expects(:ssl_post).with { |endpoint, data, headers| + request_hash = Hash.from_xml(data) + request_hash['Envelope']['Body']['CreateCustomer']['CustomerRef'] == 'customer_ref+billing' + }.returns(successful_store_response) + @gateway.store(@credit_card, options) + end def test_sucessful_update @gateway.expects(:ssl_post).returns(successful_update_response) @@ -164,5 +290,70 @@ def successful_update_response XML end + + # Documented here: https://www.eway.com.au/gateway/ManagedPaymentService/managedCreditCardPayment.asmx?op=CreateCustomer + def expected_store_request + <<-XML + + + + + login + username + password + + + + + Mr. + #{@credit_card.first_name} + #{@credit_card.last_name} +
#{@options[:billing_address][:address1]}
+ #{@options[:billing_address][:city]} + #{@options[:billing_address][:state]} + #{@options[:billing_address][:company]} + #{@options[:billing_address][:zip]} + #{@options[:billing_address][:country]} + #{@options[:email]} + + #{@options[:billing_address][:phone]} + + #{@options[:customer]} + + #{@options[:description]} + + #{@credit_card.number} + #{@credit_card.first_name} #{@credit_card.last_name} + #{sprintf("%.2i", @credit_card.month)} + #{sprintf("%.4i", @credit_card.year)[-2..-1]} +
+
+
+ XML + end + + # Documented here: https://www.eway.com.au/gateway/ManagedPaymentService/managedCreditCardPayment.asmx?op=CreateCustomer + def expected_purchase_request + <<-XML + + + + + login + username + password + + + + + #{@valid_customer_id} + #{@amount} + #{@options[:order_id] || @options[:invoice]} + #{@options[:description]} + + + + XML + end end