Skip to content

Commit 7123063

Browse files
committed
fix payments with refunded VAT, fix #17
1 parent b40f213 commit 7123063

2 files changed

Lines changed: 59 additions & 13 deletions

File tree

app/controllers/spree/paypal_controller.rb

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ def express
77
items = order.line_items.map(&method(:line_item))
88

99
additional_adjustments = order.all_adjustments.additional
10-
tax_adjustments = additional_adjustments.tax
1110
shipping_adjustments = additional_adjustments.shipping
1211

12+
# we remove taxes refunds (negative amounts) from taxes
13+
# because paypal doesn't accept negative taxes
14+
tax_adjustments, negative_tax_adjustments = split_tax_adjustments(order)
15+
1316
additional_adjustments.eligible.each do |adjustment|
1417
next if (tax_adjustments + shipping_adjustments).include?(adjustment)
1518
items << {
@@ -87,8 +90,9 @@ def line_item(item)
8790
}
8891
end
8992

90-
def express_checkout_request_details order, items
91-
{ :SetExpressCheckoutRequestDetails => {
93+
def express_checkout_request_details(order, items)
94+
{
95+
:SetExpressCheckoutRequestDetails => {
9296
:InvoiceID => order.number,
9397
:ReturnURL => confirm_paypal_url(:payment_method_id => params[:payment_method_id], :utm_nooverride => 1),
9498
:CancelURL => cancel_paypal_url,
@@ -97,7 +101,8 @@ def express_checkout_request_details order, items
97101
:cppheaderimage => payment_method.preferred_logourl.present? ? payment_method.preferred_logourl : "",
98102
:NoShipping => 1,
99103
:PaymentDetails => [payment_details(items)]
100-
}}
104+
}
105+
}
101106
end
102107

103108
def payment_method
@@ -108,15 +113,19 @@ def provider
108113
payment_method.provider
109114
end
110115

111-
def payment_details items
116+
def payment_details(items)
112117
# This retrieves the cost of shipping after promotions are applied
113118
# For example, if shippng costs $10, and is free with a promotion, shipment_sum is now $10
114119
shipment_sum = current_order.shipments.map(&:discounted_cost).sum
115120

121+
tax_adjustments, negative_tax_adjustments = split_tax_adjustments(current_order)
122+
negative_tax_adjustments_sum = negative_tax_adjustments.map(&:amount).sum
123+
tax_adjustments_sum = tax_adjustments.map(&:amount).sum
124+
116125
# This calculates the item sum based upon what is in the order total, but not for shipping
117126
# or tax. This is the easiest way to determine what the items should cost, as that
118127
# functionality doesn't currently exist in Spree core
119-
item_sum = current_order.total - shipment_sum - current_order.additional_tax_total
128+
item_sum = current_order.total - shipment_sum - current_order.additional_tax_total + negative_tax_adjustments_sum
120129

121130
if item_sum.zero?
122131
# Paypal does not support no items or a zero dollar ItemTotal
@@ -143,7 +152,7 @@ def payment_details items
143152
},
144153
:TaxTotal => {
145154
:currencyID => current_order.currency,
146-
:value => current_order.additional_tax_total
155+
:value => tax_adjustments_sum
147156
},
148157
:ShipToAddress => address_options,
149158
:PaymentDetailsItem => items,
@@ -175,5 +184,11 @@ def completion_route(order)
175184
def address_required?
176185
payment_method.preferred_solution.eql?('Sole')
177186
end
187+
188+
def split_tax_adjustments(order)
189+
@split_tax_adjustments ||= order.all_adjustments.additional.tax.partition do |a|
190+
a.amount >= 0
191+
end
192+
end
178193
end
179194
end

spec/features/paypal_spec.rb

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -275,26 +275,26 @@ def fill_in_guest
275275
end
276276
end
277277

278-
context "can process an order with Tax included prices" do
278+
context "can process an order with VAT included prices" do
279279
let(:tax_rate) { create(:tax_rate, name: 'VAT Tax', amount: 0.1,
280-
zone: Spree::Zone.first, included_in_price: true) }
280+
zone: Spree::Zone.last, included_in_price: true) }
281281
let(:tax_category) { create(:tax_category, tax_rates: [tax_rate]) }
282282
let(:product3) { FactoryGirl.create(:product, name: 'EU Charger', tax_category: tax_category) }
283-
let(:tax_string) { "VAT Tax 10.0%" }
283+
let(:tax_string) { "VAT Tax 10.0% (Included in Price)" }
284284

285285
# Regression test for #129
286-
context "on countries where the Tax is applied" do
286+
context "from countries where VAT is applied" do
287287

288288
before do
289-
Spree::Zone.first.update_attribute(:default_tax, true)
289+
Spree::Zone.last.update_attribute(:default_tax, true)
290290
end
291291

292292
specify do
293293
add_to_cart(product3)
294294
visit '/cart'
295295

296296
within("#cart_adjustments") do
297-
page.should have_content("#{tax_string} (Included in Price)")
297+
page.should have_content(tax_string)
298298
end
299299

300300
click_button 'Checkout'
@@ -311,10 +311,41 @@ def fill_in_guest
311311

312312
login_to_paypal
313313
click_button "Pay Now"
314+
314315
page.should have_content("Your order has been processed successfully")
315316
end
316317
end
317318

319+
# Regression test for #17
320+
context "from countries where VAT is refunded" do
321+
# this is required, but we will not use this zone on this checkout
322+
let!(:default_tax_zone) { create(:zone, default_tax: true) }
323+
324+
specify do
325+
add_to_cart(product3)
326+
click_button 'Checkout'
327+
fill_in_guest
328+
fill_in_billing
329+
click_button "Save and Continue"
330+
331+
within("#checkout-summary") do
332+
page.should have_content("Refund #{tax_string}")
333+
end
334+
335+
click_button "Save and Continue"
336+
find("#paypal_button").click
337+
338+
within_transaction_cart do
339+
# included taxes should not reach paypal
340+
page.should have_content(tax_string)
341+
end
342+
343+
login_to_paypal
344+
click_button "Pay Now"
345+
346+
page.should have_content("Your order has been processed successfully")
347+
end
348+
end
318349
end
319350

320351
context "as an admin" do

0 commit comments

Comments
 (0)