From 0e0830165e5960b59cc2aced4cfc8116c064c60f Mon Sep 17 00:00:00 2001 From: Eric Saupe Date: Wed, 10 Oct 2018 09:28:17 -0700 Subject: [PATCH] Round calculator values based on order currency Fixes #1957 by getting the exponent of the desired currency from Money::Currency --- .../spree/calculator/flat_percent_item_total.rb | 5 ++++- .../calculator/shipping/flat_percent_item_total.rb | 8 +++++--- core/app/models/spree/calculator/tiered_percent.rb | 3 ++- .../spree/calculator/flat_percent_item_total_spec.rb | 11 ++++++++++- .../shipping/flat_percent_item_total_spec.rb | 5 +++++ .../models/spree/calculator/tiered_percent_spec.rb | 8 +++++++- 6 files changed, 33 insertions(+), 7 deletions(-) diff --git a/core/app/models/spree/calculator/flat_percent_item_total.rb b/core/app/models/spree/calculator/flat_percent_item_total.rb index 3f7200de258..f7d187d64b7 100644 --- a/core/app/models/spree/calculator/flat_percent_item_total.rb +++ b/core/app/models/spree/calculator/flat_percent_item_total.rb @@ -7,7 +7,10 @@ class Calculator::FlatPercentItemTotal < Calculator preference :flat_percent, :decimal, default: 0 def compute(object) - computed_amount = (object.amount * preferred_flat_percent / 100).round(2) + order = object.is_a?(Order) ? object : object.order + preferred_currency = order.currency + currency_exponent = ::Money::Currency.find(preferred_currency).exponent + computed_amount = (object.amount * preferred_flat_percent / 100).round(currency_exponent) # We don't want to cause the promotion adjustments to push the order into a negative total. if computed_amount > object.amount diff --git a/core/app/models/spree/calculator/shipping/flat_percent_item_total.rb b/core/app/models/spree/calculator/shipping/flat_percent_item_total.rb index f78f0d3ea28..767d1eec1d4 100644 --- a/core/app/models/spree/calculator/shipping/flat_percent_item_total.rb +++ b/core/app/models/spree/calculator/shipping/flat_percent_item_total.rb @@ -9,12 +9,14 @@ class FlatPercentItemTotal < ShippingCalculator preference :flat_percent, :decimal, default: 0 def compute_package(package) - compute_from_price(total(package.contents)) + value = compute_from_price(total(package.contents)) + preferred_currency = package.order.currency + currency_exponent = ::Money::Currency.find(preferred_currency).exponent + value.round(currency_exponent) end def compute_from_price(price) - value = price * BigDecimal(preferred_flat_percent.to_s) / 100.0 - value.round(2) + price * BigDecimal(preferred_flat_percent.to_s) / 100.0 end end end diff --git a/core/app/models/spree/calculator/tiered_percent.rb b/core/app/models/spree/calculator/tiered_percent.rb index 12081e3a899..74bdbcd4ddb 100644 --- a/core/app/models/spree/calculator/tiered_percent.rb +++ b/core/app/models/spree/calculator/tiered_percent.rb @@ -31,7 +31,8 @@ def compute(object) end if preferred_currency.casecmp(order.currency).zero? - (object.amount * (percent || preferred_base_percent) / 100).round(2) + currency_exponent = ::Money::Currency.find(preferred_currency).exponent + (object.amount * (percent || preferred_base_percent) / 100).round(currency_exponent) else 0 end diff --git a/core/spec/models/spree/calculator/flat_percent_item_total_spec.rb b/core/spec/models/spree/calculator/flat_percent_item_total_spec.rb index 2128fdfcdd4..3c4565a5714 100644 --- a/core/spec/models/spree/calculator/flat_percent_item_total_spec.rb +++ b/core/spec/models/spree/calculator/flat_percent_item_total_spec.rb @@ -5,7 +5,7 @@ RSpec.describe Spree::Calculator::FlatPercentItemTotal, type: :model do let(:calculator) { Spree::Calculator::FlatPercentItemTotal.new } - let(:line_item) { mock_model Spree::LineItem } + let(:line_item) { create(:line_item) } it_behaves_like 'a calculator with a description' @@ -20,6 +20,15 @@ expect(calculator.compute(line_item)).to eq 3.10 end + it "should round result based on order currency" do + line_item.order.currency = 'JPY' + allow(line_item).to receive_messages amount: 31.08 + expect(calculator.compute(line_item)).to eq 3 + + allow(line_item).to receive_messages amount: 31.00 + expect(calculator.compute(line_item)).to eq 3 + end + it 'returns object.amount if computed amount is greater' do allow(calculator).to receive_messages preferred_flat_percent: 110 allow(line_item).to receive_messages amount: 30.00 diff --git a/core/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb b/core/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb index 122d4074efb..e1db9656a29 100644 --- a/core/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb +++ b/core/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb @@ -31,6 +31,11 @@ module Calculator::Shipping expect(subject.compute(package)).to eq(4.04) end + it "should round result based on order currency" do + package.order.currency = 'JPY' + expect(subject.compute(package)).to eq(4) + end + it "should return a bigdecimal" do expect(subject.compute(package)).to be_a(BigDecimal) end diff --git a/core/spec/models/spree/calculator/tiered_percent_spec.rb b/core/spec/models/spree/calculator/tiered_percent_spec.rb index 18ed4d06813..410c7c1b29a 100644 --- a/core/spec/models/spree/calculator/tiered_percent_spec.rb +++ b/core/spec/models/spree/calculator/tiered_percent_spec.rb @@ -135,9 +135,15 @@ end context "when the order's currency does not match the calculator" do - let(:preferred_currency) { "CAD" } + let(:preferred_currency) { "JPY" } let(:line_item_count) { 1 } + let(:price) { 15 } it { is_expected.to eq 0 } + + it "rounds based on currency" do + allow(order).to receive_messages currency: "JPY" + expect(subject).to eq(2) + end end end