diff --git a/README.md b/README.md index 4ea0faea..654ca49d 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ You will also need a "Personal" account to test the transactions on your site. C #### Spree Setup -In Spree, go to the admin backend, click "Configuration" and then "Payment Methods" and create a new payment method. Select "Spree::Gateway::PayPalExpress" as the provider, and click "Create". Enter the email address, password and signature from the "API Credentials" tab for the **Business** account on PayPal. +In Spree, go to the admin backend, click "Configuration" and then "Payment Methods" and create a new payment method. Select "Spree::Gateway::PayPalExpress" as the provider, and click "Create". Enter the email address, password and signature from the "API Credentials" tab for the **Business** account on PayPal. ### Production setup @@ -56,7 +56,7 @@ This Spree extension supports *some* of those. If your favourite is not here, th ### Solution Type -Determines whether or not a user needs a PayPal account to check out. +Determines whether or not a user needs a PayPal account to check out. ```ruby payment_method.preferred_solution_type = "Mark" @@ -64,7 +64,7 @@ payment_method.preferred_solution_type = "Mark" payment_method.preferred_solution_type = "Sole" ``` -"Mark" if you do want users to have a paypal account, "Sole" otherwise. +"Mark" if you do want users to have a paypal account, "Sole" otherwise. ### Landing Page @@ -88,6 +88,45 @@ payment_method.preferred_logourl = 'http://yoursite.com/images/checkout.jpg' **Must** be an absolute path to the image. +### Displaying Shipping Addresses + +You have the option of displaying the shipping address of an order on +the PayPal pages: + +```ruby +# Displays the shipping address of the order on the Paypal page +payment_method.preferred_no_shipping = '0' + +# Do not display the shipping address on the Paypal page +# This is the default configuration since this matches the pre-existing +# behavior of the gem +payment_method.preferred_no_shipping = '1' + +# Display the shipping address listed in the profile if it is not +# sent along with the order +payment_method.preferred_no_shipping = '2' +``` + +This has no effect on what shipping address is passed to the gateway. + +### Overriding the Shipping Address + +By default PayPay will use the shipping address that it has on file as +the shipping address for an order. + +You can configure the gateway to send up the shipping address associated +with the order through the following configuration: + +```ruby +# Do not override the shipping address on file (default) +payment_method.preferred_address_override = '0' + +# Override the shipping address on file +payment_method.preferred_address_override = '1' +``` + +The shipping address will be sent to the server if configured to do so. + ## Caveats *Caveat venditor* diff --git a/app/controllers/spree/paypal_controller.rb b/app/controllers/spree/paypal_controller.rb index 405d45bb..5d6caaf9 100644 --- a/app/controllers/spree/paypal_controller.rb +++ b/app/controllers/spree/paypal_controller.rb @@ -95,7 +95,8 @@ def express_checkout_request_details order, items :SolutionType => payment_method.preferred_solution.present? ? payment_method.preferred_solution : "Mark", :LandingPage => payment_method.preferred_landing_page.present? ? payment_method.preferred_landing_page : "Billing", :cppheaderimage => payment_method.preferred_logourl.present? ? payment_method.preferred_logourl : "", - :NoShipping => payment_method.preferred_no_shipping.present? ? (payment_method.preferred_no_shipping ? 1 : 0) : 1, + :NoShipping => payment_method.preferred_no_shipping.present? ? payment_method.preferred_no_shipping : '1', + :AddressOverride => payment_method.preferred_address_override.present? ? payment_method.preferred_address_override : '0', :PaymentDetails => [payment_details(items)] }} end @@ -156,15 +157,17 @@ def payment_details items def address_options return {} unless address_required? + address = current_order.use_billing ? current_order.bill_address : current_order.ship_address + { - :Name => current_order.bill_address.try(:full_name), - :Street1 => current_order.bill_address.address1, - :Street2 => current_order.bill_address.address2, - :CityName => current_order.bill_address.city, - :Phone => current_order.bill_address.phone, - :StateOrProvince => current_order.bill_address.state_text, - :Country => current_order.bill_address.country.iso, - :PostalCode => current_order.bill_address.zipcode + :Name => address.try(:full_name), + :Street1 => address.address1, + :Street2 => address.address2, + :CityName => address.city, + :Phone => address.phone, + :StateOrProvince => address.state_text, + :Country => address.country.iso, + :PostalCode => address.zipcode } end @@ -173,7 +176,8 @@ def completion_route(order) end def address_required? - payment_method.preferred_solution.eql?('Sole') + payment_method.preferred_solution.eql?('Sole') \ + || payment_method.preferred_address_override.eql?('1') end end end diff --git a/app/models/spree/gateway/pay_pal_express.rb b/app/models/spree/gateway/pay_pal_express.rb index 003436bd..4b5fe8c4 100644 --- a/app/models/spree/gateway/pay_pal_express.rb +++ b/app/models/spree/gateway/pay_pal_express.rb @@ -8,7 +8,19 @@ class Gateway::PayPalExpress < Gateway preference :solution, :string, default: 'Mark' preference :landing_page, :string, default: 'Billing' preference :logourl, :string, default: '' - preference :no_shipping, :boolean, default: true + # Indicates whether to display the shipping address on the paypal checkout + # page. + # + # 0 - Paypal displays the shipping address on the page. + # 1 - Paypal does not display the shipping address on its pages. This is + # the default due to the history of this gem. + # 2 - Paypal will obtain the shipping address from the profile. + preference :no_shipping, :string, default: '1' + + # Allow Address Override + # 0 - Do not display the address passed to Paypal + # 1 - Display the address sent to Paypal + preference :address_override, :string, default: '0' def supports?(source) true diff --git a/spec/features/paypal_spec.rb b/spec/features/paypal_spec.rb index 78540457..32c300fb 100644 --- a/spec/features/paypal_spec.rb +++ b/spec/features/paypal_spec.rb @@ -13,6 +13,7 @@ }) FactoryGirl.create(:shipping_method) end + def fill_in_billing within("#billing") do fill_in "First Name", :with => "Test" @@ -27,6 +28,21 @@ def fill_in_billing end end + def fill_in_shipping + uncheck("order[use_billing]") + within("#shipping") do + fill_in "First Name", :with => "Test" + fill_in "Last Name", :with => "User" + fill_in "Street Address", :with => "2 User Lane" + # City, State and ZIP must all match for PayPal to be happy + fill_in "City", :with => "Adamsville" + select "United States of America", :from => "order_ship_address_attributes_country_id" + select "Alabama", :from => "order_ship_address_attributes_state_id" + fill_in "Zip", :with => "35005" + fill_in "Phone", :with => "555-123-4567" + end + end + def switch_to_paypal_login # If you go through a payment once in the sandbox, it remembers your preferred setting. # It defaults to the *wrong* setting for the first time, so we need to have this method. @@ -48,10 +64,14 @@ def within_transaction_cart(&block) within(".transctionCartDetails") { block.call } end - it "pays for an order successfully" do + def add_product_to_cart(product) visit spree.root_path - click_link 'iPad' + click_link product click_button 'Add To Cart' + end + + it "pays for an order successfully" do + add_product_to_cart 'iPad' click_button 'Checkout' within("#guest_checkout") do fill_in "Email", :with => "test@example.com" @@ -76,9 +96,7 @@ def within_transaction_cart(&block) end it "passes user details to PayPal" do - visit spree.root_path - click_link 'iPad' - click_button 'Add To Cart' + add_product_to_cart('iPad') click_button 'Checkout' within("#guest_checkout") do fill_in "Email", :with => "test@example.com" @@ -102,9 +120,7 @@ def within_transaction_cart(&block) end it "includes adjustments in PayPal summary" do - visit spree.root_path - click_link 'iPad' - click_button 'Add To Cart' + add_product_to_cart('iPad') # TODO: Is there a better way to find this current order? order = Spree::Order.last order.adjustments.create!(:amount => -5, :label => "$5 off") @@ -154,10 +170,7 @@ def within_transaction_cart(&block) end it "includes line item adjustments in PayPal summary" do - - visit spree.root_path - click_link 'iPad' - click_button 'Add To Cart' + add_product_to_cart('iPad') # TODO: Is there a better way to find this current order? order = Spree::Order.last order.line_item_adjustments.count.should == 1 @@ -190,18 +203,14 @@ def within_transaction_cart(&block) end end + # Regression test for #10 context "will skip $0 items" do let!(:product2) { FactoryGirl.create(:product, :name => 'iPod') } specify do - visit spree.root_path - click_link 'iPad' - click_button 'Add To Cart' - - visit spree.root_path - click_link 'iPod' - click_button 'Add To Cart' + add_product_to_cart('iPad') + add_product_to_cart('iPod') # TODO: Is there a better way to find this current order? order = Spree::Order.last @@ -247,9 +256,7 @@ def within_transaction_cart(&block) end specify do - visit spree.root_path - click_link 'iPad' - click_button 'Add To Cart' + add_product_to_cart('iPad') # TODO: Is there a better way to find this current order? order = Spree::Order.last order.adjustments.create!(:amount => -order.line_items.last.price, :label => "FREE iPad ZOMG!") @@ -274,6 +281,127 @@ def within_transaction_cart(&block) end end + shared_examples_for :no_shipping do + it "displays the shipping address on file on the paypal page" do + add_product_to_cart('iPad') + click_button 'Checkout' + within('#guest_checkout') do + fill_in "Email", with: "test@example.com" + click_button 'Continue' + end + fill_in_billing + fill_in_shipping + + click_button "Save and Continue" + # Delivery step doesn't require any action + click_button "Save and Continue" + + find("#paypal_button").click + + login_to_paypal + + within("#shippingAddress") do + page.should have_content("Ship to") + end + end + end + + context "displays the shipping address on the paypal page" do + before do + @gateway.preferred_no_shipping = '0' + @gateway.save + end + + it_behaves_like :no_shipping + end + + context "displays the shipping address on the paypal page when none is passed" do + before do + @gateway.preferred_no_shipping = '2' + @gateway.save + end + + it_behaves_like :no_shipping + end + + context "default no shipping option" do + + it "does not show the address by default" do + add_product_to_cart('iPad') + click_button 'Checkout' + within('#guest_checkout') do + fill_in "Email", with: "test@example.com" + click_button 'Continue' + end + fill_in_billing + fill_in_shipping + + click_button "Save and Continue" + # Delivery step doesn't require any action + click_button "Save and Continue" + + find("#paypal_button").click + + login_to_paypal + + page.should have_no_content("Ship To") + end + end + + context "shipping address override" do + before do + @gateway.preferred_no_shipping = '0' + @gateway.preferred_address_override = '1' + @gateway.save + end + + it "shipping address from order" do + add_product_to_cart('iPad') + click_button 'Checkout' + within('#guest_checkout') do + fill_in "Email", with: "test@example.com" + click_button 'Continue' + end + fill_in_billing + fill_in_shipping + + click_button "Save and Continue" + # Delivery step doesn't require any action + click_button "Save and Continue" + + find("#paypal_button").click + + login_to_paypal + + within("#shippingAddress") do + page.should have_content("2 User Lane") + end + end + + it "billing address from order" do + add_product_to_cart('iPad') + click_button 'Checkout' + within('#guest_checkout') do + fill_in "Email", with: "test@example.com" + click_button 'Continue' + end + fill_in_billing + + click_button "Save and Continue" + # Delivery step doesn't require any action + click_button "Save and Continue" + + find("#paypal_button").click + + login_to_paypal + + within("#shippingAddress") do + page.should have_content("1 User Lane") + end + end + end + + context "cannot process a payment with invalid gateway details" do before do @gateway.preferred_login = nil @@ -281,9 +409,7 @@ def within_transaction_cart(&block) end specify do - visit spree.root_path - click_link 'iPad' - click_button 'Add To Cart' + add_product_to_cart('iPad') click_button 'Checkout' within("#guest_checkout") do fill_in "Email", :with => "test@example.com" @@ -303,9 +429,7 @@ def within_transaction_cart(&block) context "refunding payments" do before do - visit spree.root_path - click_link 'iPad' - click_button 'Add To Cart' + add_product_to_cart('iPad') click_button 'Checkout' within("#guest_checkout") do fill_in "Email", :with => "test@example.com"