Skip to content

Commit

Permalink
The PaymentDetails & PaymentDetailsItem objects are common between pr…
Browse files Browse the repository at this point in the history
…o & express

Also removed a bunch of duplication
  • Loading branch information
Diego Scataglini committed Mar 21, 2012
1 parent 67203a4 commit 0b25ede
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 76 deletions.
19 changes: 1 addition & 18 deletions lib/active_merchant/billing/gateways/paypal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,24 +51,7 @@ def build_sale_or_authorization_request(action, money, credit_card_or_referenced
xml.tag! 'n2:' + transaction_type + 'RequestDetails' do
xml.tag! 'n2:ReferenceID', reference_id if transaction_type == 'DoReferenceTransaction'
xml.tag! 'n2:PaymentAction', action
xml.tag! 'n2:PaymentDetails' do
xml.tag! 'n2:OrderTotal', localized_amount(money, currency_code), 'currencyID' => currency_code

# All of the values must be included together and add up to the order total
if [:subtotal, :shipping, :handling, :tax].all?{ |o| options.has_key?(o) }
xml.tag! 'n2:ItemTotal', localized_amount(options[:subtotal], currency_code), 'currencyID' => currency_code
xml.tag! 'n2:ShippingTotal', localized_amount(options[:shipping], currency_code),'currencyID' => currency_code
xml.tag! 'n2:HandlingTotal', localized_amount(options[:handling], currency_code),'currencyID' => currency_code
xml.tag! 'n2:TaxTotal', localized_amount(options[:tax], currency_code), 'currencyID' => currency_code
end

xml.tag! 'n2:NotifyURL', options[:notify_url]
xml.tag! 'n2:OrderDescription', options[:description]
xml.tag! 'n2:InvoiceID', options[:order_id]
xml.tag! 'n2:ButtonSource', application_id.to_s.slice(0,32) unless application_id.blank?

add_address(xml, 'n2:ShipToAddress', options[:shipping_address]) if options[:shipping_address]
end
add_payment_details(xml, money, currency_code, options)
add_credit_card(xml, credit_card_or_referenced_id, billing_address, options) unless transaction_type == 'DoReferenceTransaction'
xml.tag! 'n2:IPAddress', options[:ip]
end
Expand Down
78 changes: 78 additions & 0 deletions lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,17 @@ def credit(money, identification, options = {})
end

private
def build_request_wrapper(action)
xml = Builder::XmlMarkup.new :indent => 2
xml.tag! action + 'Req', 'xmlns' => PAYPAL_NAMESPACE do
xml.tag! action + 'Request', 'xmlns:n2' => EBAY_NAMESPACE do
xml.tag! 'n2:Version', API_VERSION
yield(xml)
end
end
xml.target!
end

def build_reauthorize_request(money, authorization, options)
xml = Builder::XmlMarkup.new

Expand Down Expand Up @@ -318,6 +329,73 @@ def add_address(xml, element, address)
end
end

def add_payment_details_items_xml(xml, options, currency_code)
options[:items].each do |item|
xml.tag! 'n2:PaymentDetailsItem' do
xml.tag! 'n2:Name', item[:name]
xml.tag! 'n2:Number', item[:number]
xml.tag! 'n2:Quantity', item[:quantity]
if item[:amount]
xml.tag! 'n2:Amount', localized_amount(item[:amount], currency_code), 'currencyID' => currency_code
end
xml.tag! 'n2:Description', item[:description]
xml.tag! 'n2:ItemURL', item[:url]
xml.tag! 'n2:ItemCategory', item[:category] if item[:category]
end
end
end

def add_payment_details(xml, money, currency_code, options = {})
xml.tag! 'n2:PaymentDetails' do
xml.tag! 'n2:OrderTotal', localized_amount(money, currency_code), 'currencyID' => currency_code

# All of the values must be included together and add up to the order total
if [:subtotal, :shipping, :handling, :tax].all?{ |o| options.has_key?(o) }
xml.tag! 'n2:ItemTotal', localized_amount(options[:subtotal], currency_code), 'currencyID' => currency_code
xml.tag! 'n2:ShippingTotal', localized_amount(options[:shipping], currency_code),'currencyID' => currency_code
xml.tag! 'n2:HandlingTotal', localized_amount(options[:handling], currency_code),'currencyID' => currency_code
xml.tag! 'n2:TaxTotal', localized_amount(options[:tax], currency_code), 'currencyID' => currency_code
end

xml.tag! 'n2:InsuranceTotal', localized_amount(options[:insurance_total], currency_code),'currencyID' => currency_code unless options[:insurance_total].blank?
xml.tag! 'n2:ShippingDiscount', localized_amount(options[:shipping_discount], currency_code),'currencyID' => currency_code unless options[:shipping_discount].blank?
xml.tag! 'n2:InsuranceOptionOffered', options[:insurance_option_offered] if options.has_key?(:insurance_option_offered)

xml.tag! 'n2:OrderDescription', options[:description] unless options[:description].blank?

# Custom field Character length and limitations: 256 single-byte alphanumeric characters
xml.tag! 'n2:Custom', options[:custom] unless options[:custom].blank?

xml.tag! 'n2:InvoiceID', options[:order_id] unless options[:order_id].blank?
xml.tag! 'n2:ButtonSource', application_id.to_s.slice(0,32) unless application_id.blank?

# The notify URL applies only to DoExpressCheckoutPayment.
# This value is ignored when set in SetExpressCheckout or GetExpressCheckoutDetails
xml.tag! 'n2:NotifyURL', options[:notify_url] unless options[:notify_url].blank?

add_address(xml, 'n2:ShipToAddress', options[:shipping_address]) unless options[:shipping_address].blank?

add_payment_details_items_xml(xml, options, currency_code) unless options[:items].blank?

add_express_only_payment_details(xml, options) if options[:express_request]

# Any value other than Y – This is not a recurring transaction
# To pass Y in this field, you must have established a billing agreement with
# the buyer specifying the amount, frequency, and duration of the recurring payment.
# requires version 80.0 of the API
xml.tag! 'n2:Recurring', options[:recurring] unless options[:recurring].blank?
end
end

def add_express_only_payment_details(xml, options = {})
%w{NoteText SoftDescriptor TransactionId AllowedPaymentMethodType
PaymentRequestID PaymentAction}.each do |optional_text_field|
field_as_symbol = optional_text_field.underscore.to_sym
xml.tag! 'n2:' + optional_text_field, options[field_as_symbol] unless options[field_as_symbol].blank?
end
xml
end

def endpoint_url
URLS[test? ? :test : :live][@options[:signature].blank? ? :certificate : :signature]
end
Expand Down
65 changes: 7 additions & 58 deletions lib/active_merchant/billing/gateways/paypal_express.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,24 +71,7 @@ def build_sale_or_authorization_request(action, money, options)
xml.tag! 'n2:PaymentAction', action
xml.tag! 'n2:Token', options[:token]
xml.tag! 'n2:PayerID', options[:payer_id]
xml.tag! 'n2:PaymentDetails' do
xml.tag! 'n2:OrderTotal', localized_amount(money, currency_code), 'currencyID' => currency_code

# All of the values must be included together and add up to the order total
if [:subtotal, :shipping, :handling, :tax].all?{ |o| options.has_key?(o) }
xml.tag! 'n2:ItemTotal', localized_amount(options[:subtotal], currency_code), 'currencyID' => currency_code
xml.tag! 'n2:ShippingTotal', localized_amount(options[:shipping], currency_code),'currencyID' => currency_code
xml.tag! 'n2:HandlingTotal', localized_amount(options[:handling], currency_code),'currencyID' => currency_code
xml.tag! 'n2:TaxTotal', localized_amount(options[:tax], currency_code), 'currencyID' => currency_code
end

xml.tag! 'n2:NotifyURL', options[:notify_url]
xml.tag! 'n2:ButtonSource', application_id.to_s.slice(0,32) unless application_id.blank?
xml.tag! 'n2:InvoiceID', options[:order_id]
xml.tag! 'n2:OrderDescription', options[:description]

add_items_xml(xml, options, currency_code) if options[:items]
end
add_payment_details(xml, money, currency_code, options)
end
end
end
Expand All @@ -98,6 +81,10 @@ def build_sale_or_authorization_request(action, money, options)

def build_setup_request(action, money, options)
currency_code = options[:currency] || currency(money)
options[:payment_action] = action
options[:express_request] = true
options[:shipping_address] ||= options[:address]
money = 100 if amount(money).to_f.zero?

xml = Builder::XmlMarkup.new :indent => 2
xml.tag! 'SetExpressCheckoutReq', 'xmlns' => PAYPAL_NAMESPACE do
Expand Down Expand Up @@ -137,28 +124,8 @@ def build_setup_request(action, money, options)
xml.tag! 'n2:AllowNote', options[:allow_note] ? '1' : '0'
end
xml.tag! 'n2:CallbackURL', options[:callback_url] unless options[:callback_url].blank?

xml.tag! 'n2:PaymentDetails' do
xml.tag! 'n2:OrderTotal', amount(money).to_f.zero? ? localized_amount(100, currency_code) : localized_amount(money, currency_code), 'currencyID' => currency_code
# All of the values must be included together and add up to the order total
if [:subtotal, :shipping, :handling, :tax].all? { |o| options.has_key?(o) }
xml.tag! 'n2:ItemTotal', localized_amount(options[:subtotal], currency_code), 'currencyID' => currency_code
xml.tag! 'n2:ShippingTotal', localized_amount(options[:shipping], currency_code), 'currencyID' => currency_code
xml.tag! 'n2:HandlingTotal', localized_amount(options[:handling], currency_code), 'currencyID' => currency_code
xml.tag! 'n2:TaxTotal', localized_amount(options[:tax], currency_code), 'currencyID' => currency_code
end

xml.tag! 'n2:OrderDescription', options[:description]
xml.tag! 'n2:InvoiceID', options[:order_id]

add_address(xml, 'n2:ShipToAddress', options[:shipping_address] || options[:address])

add_items_xml(xml, options, currency_code) if options[:items]

xml.tag! 'n2:PaymentAction', action
xml.tag! 'n2:Custom', options[:custom] unless options[:custom].blank?
end


add_payment_details(xml, money, currency_code, options)
if options[:shipping_options]
options[:shipping_options].each do |shipping_option|
xml.tag! 'n2:FlatRateShippingOptions' do
Expand Down Expand Up @@ -207,24 +174,6 @@ def build_reference_transaction_request(action, money, options)
def build_response(success, message, response, options = {})
PaypalExpressResponse.new(success, message, response, options)
end

private

def add_items_xml(xml, options, currency_code)
options[:items].each do |item|
xml.tag! 'n2:PaymentDetailsItem' do
xml.tag! 'n2:Name', item[:name]
xml.tag! 'n2:Number', item[:number]
xml.tag! 'n2:Quantity', item[:quantity]
if item[:amount]
xml.tag! 'n2:Amount', localized_amount(item[:amount], currency_code), 'currencyID' => currency_code
end
xml.tag! 'n2:Description', item[:description]
xml.tag! 'n2:ItemURL', item[:url]
xml.tag! 'n2:ItemCategory', item[:category] if item[:category]
end
end
end
end
end
end
60 changes: 60 additions & 0 deletions test/unit/gateways/paypal/paypal_common_api_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
require 'test_helper'
require 'nokogiri'

class PaypalExpressTest < Test::Unit::TestCase
def setup
@gateway = Class.new{ include PaypalCommonApi }

@address = { :address1 => '1234 My Street',
:address2 => 'Apt 1',
:company => 'Widgets Inc',
:city => 'Ottawa',
:state => 'ON',
:zip => 'K1C2N6',
:country => 'Canada',
:phone => '(555)555-5555'
}
end

def xml_builder
Builder::XmlMarkup.new
end

def wrap_xml(&block)
REXML::Document.new(@gateway.send(:build_request_wrapper, 'Action', &block))
end

def test_add_payment_details_adds_express_only_payment_details_when_necessary
options = {:express_request => true}
@gateway.expects(:add_express_only_payment_details)
@gateway.send(:add_payment_details, xml_builder, 100, 'USD', options)
end

def test_add_payment_details_adds_items_details
options = {:items => [1]}
@gateway.expects(:add_payment_details_items_xml)
@gateway.send(:add_payment_details, xml_builder, 100, 'USD', options)
end

def test_add_payment_details_adds_address
options = {:shipping_address => @address}
@gateway.expects(:add_address)
@gateway.send(:add_payment_details, xml_builder, 100, 'USD', options)
end

def test_add_payment_details_adds_items_details_elements
options = {:items => [{:name => 'foo'}]}
request = wrap_xml do |xml|
@gateway.send(:add_payment_details, xml, 100, 'USD', options)
end
assert_equal 'foo', REXML::XPath.first(request, '//n2:PaymentDetails/n2:PaymentDetailsItem/n2:Name').text
end

def test_add_express_only_payment_details_adds_non_blank_fields
request = wrap_xml do |xml|
@gateway.send(:add_express_only_payment_details, xml, {:payment_action => 'Sale', :payment_request_id => ''})
end
assert_equal 'Sale', REXML::XPath.first(request, '//n2:PaymentAction').text
assert_nil REXML::XPath.first(request, '//n2:PaymentRequestID')
end
end

0 comments on commit 0b25ede

Please sign in to comment.