diff --git a/app/controllers/spree/paypal_controller.rb b/app/controllers/spree/paypal_controller.rb index ac6fdddd..c78e3608 100644 --- a/app/controllers/spree/paypal_controller.rb +++ b/app/controllers/spree/paypal_controller.rb @@ -7,11 +7,14 @@ def express items = order.line_items.map(&method(:line_item)) additional_adjustments = order.all_adjustments.additional - tax_adjustments = additional_adjustments.tax shipping_adjustments = additional_adjustments.shipping + # we remove taxes refunds (negative amounts) from taxes + # because paypal doesn't accept negative taxes + @tax_adjustments, @negative_tax_adjustments = additional_adjustments.tax.partition { |a| a.amount >= 0 } + additional_adjustments.eligible.each do |adjustment| - next if (tax_adjustments + shipping_adjustments).include?(adjustment) + next if (@tax_adjustments + shipping_adjustments).include?(adjustment) items << { :Name => adjustment.label, :Quantity => 1, @@ -87,8 +90,9 @@ def line_item(item) } end - def express_checkout_request_details order, items - { :SetExpressCheckoutRequestDetails => { + def express_checkout_request_details(order, items) + { + :SetExpressCheckoutRequestDetails => { :InvoiceID => order.number, :ReturnURL => confirm_paypal_url(:payment_method_id => params[:payment_method_id], :utm_nooverride => 1), :CancelURL => cancel_paypal_url, @@ -97,7 +101,8 @@ def express_checkout_request_details order, items :cppheaderimage => payment_method.preferred_logourl.present? ? payment_method.preferred_logourl : "", :NoShipping => 1, :PaymentDetails => [payment_details(items)] - }} + } + } end def payment_method @@ -108,15 +113,17 @@ def provider payment_method.provider end - def payment_details items + def payment_details(items) # This retrieves the cost of shipping after promotions are applied # For example, if shippng costs $10, and is free with a promotion, shipment_sum is now $10 shipment_sum = current_order.shipments.map(&:discounted_cost).sum + negative_tax_adjustments_sum = @negative_tax_adjustments.map(&:amount).sum + tax_adjustments_sum = @tax_adjustments.map(&:amount).sum # This calculates the item sum based upon what is in the order total, but not for shipping # or tax. This is the easiest way to determine what the items should cost, as that # functionality doesn't currently exist in Spree core - item_sum = current_order.total - shipment_sum - current_order.additional_tax_total + item_sum = current_order.total - shipment_sum - current_order.additional_tax_total + negative_tax_adjustments_sum if item_sum.zero? # Paypal does not support no items or a zero dollar ItemTotal @@ -143,7 +150,7 @@ def payment_details items }, :TaxTotal => { :currencyID => current_order.currency, - :value => current_order.additional_tax_total + :value => tax_adjustments_sum }, :ShipToAddress => address_options, :PaymentDetailsItem => items, diff --git a/spec/features/paypal_spec.rb b/spec/features/paypal_spec.rb index 4af75250..acedd5b2 100644 --- a/spec/features/paypal_spec.rb +++ b/spec/features/paypal_spec.rb @@ -275,18 +275,18 @@ def fill_in_guest end end - context "can process an order with Tax included prices" do + context "can process an order with VAT included prices" do let(:tax_rate) { create(:tax_rate, name: 'VAT Tax', amount: 0.1, - zone: Spree::Zone.first, included_in_price: true) } + zone: Spree::Zone.last, included_in_price: true) } let(:tax_category) { create(:tax_category, tax_rates: [tax_rate]) } let(:product3) { FactoryGirl.create(:product, name: 'EU Charger', tax_category: tax_category) } - let(:tax_string) { "VAT Tax 10.0%" } + let(:tax_string) { "VAT Tax 10.0% (Included in Price)" } # Regression test for #129 - context "on countries where the Tax is applied" do + context "from countries where VAT is applied" do before do - Spree::Zone.first.update_attribute(:default_tax, true) + Spree::Zone.last.update_attribute(:default_tax, true) end specify do @@ -294,7 +294,7 @@ def fill_in_guest visit '/cart' within("#cart_adjustments") do - page.should have_content("#{tax_string} (Included in Price)") + page.should have_content(tax_string) end click_button 'Checkout' @@ -311,10 +311,41 @@ def fill_in_guest login_to_paypal click_button "Pay Now" + page.should have_content("Your order has been processed successfully") end end + # Regression test for #17 + context "from countries where VAT is refunded" do + # this is required, but we will not use this zone on this checkout + let!(:default_tax_zone) { create(:zone, default_tax: true) } + + specify do + add_to_cart(product3) + click_button 'Checkout' + fill_in_guest + fill_in_billing + click_button "Save and Continue" + + within("#checkout-summary") do + page.should have_content("Refund #{tax_string}") + end + + click_button "Save and Continue" + find("#paypal_button").click + + within_transaction_cart do + # included taxes should not reach paypal + page.should have_content(tax_string) + end + + login_to_paypal + click_button "Pay Now" + + page.should have_content("Your order has been processed successfully") + end + end end context "as an admin" do