solidus_core 1.3.0.beta1 → 1.3.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of solidus_core might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/app/assets/images/noimage/large.png +0 -0
- data/app/assets/images/noimage/mini.png +0 -0
- data/app/assets/images/noimage/product.png +0 -0
- data/app/assets/images/noimage/small.png +0 -0
- data/app/models/spree/app_configuration.rb +9 -9
- data/app/models/spree/country.rb +1 -0
- data/app/models/spree/line_item.rb +7 -1
- data/app/models/spree/payment_method.rb +1 -1
- data/app/models/spree/preferences/preferable.rb +1 -0
- data/app/models/spree/preferences/statically_configurable.rb +2 -2
- data/app/models/spree/price.rb +30 -2
- data/app/models/spree/product.rb +4 -1
- data/app/models/spree/stock/inventory_unit_builder.rb +2 -2
- data/app/models/spree/tax/tax_location.rb +4 -0
- data/app/models/spree/tax_rate.rb +2 -11
- data/app/models/spree/variant/price_selector.rb +35 -0
- data/app/models/spree/variant/pricing_options.rb +69 -4
- data/app/models/spree/variant/vat_price_generator.rb +58 -0
- data/app/models/spree/variant.rb +38 -16
- data/config/locales/en.yml +22 -1
- data/db/migrate/20140410141842_add_many_missing_indexes.rb +15 -13
- data/db/migrate/20140410150358_correct_some_polymorphic_index_and_add_more_missing.rb +40 -38
- data/db/migrate/20141217215630_update_product_slug_index.rb +4 -2
- data/db/migrate/20150723224133_remove_unnecessary_indexes.rb +2 -10
- data/db/migrate/20151219020209_add_stock_item_unique_index.rb +2 -2
- data/db/migrate/20160509181311_add_country_iso_to_prices.rb +8 -0
- data/lib/spree/core/class_constantizer.rb +31 -0
- data/lib/spree/core/engine.rb +55 -59
- data/lib/spree/core/environment/calculators.rb +6 -1
- data/lib/spree/core/environment.rb +5 -2
- data/lib/spree/core/environment_extension.rb +16 -12
- data/lib/spree/core/price_migrator.rb +32 -0
- data/lib/spree/core/search/base.rb +2 -2
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +4 -0
- data/lib/spree/migration_helpers.rb +19 -0
- data/lib/spree/money.rb +41 -15
- data/lib/spree/promo/environment.rb +2 -1
- data/lib/spree/testing_support/controller_requests.rb +22 -7
- data/lib/spree/testing_support/factories/state_factory.rb +7 -0
- data/lib/spree/testing_support/factories/stock_location_factory.rb +4 -1
- data/lib/tasks/migrations/create_vat_prices.rake +11 -0
- data/lib/tasks/upgrade.rake +2 -1
- data/spec/lib/spree/core/class_constantizer_spec.rb +68 -0
- data/spec/lib/spree/core/environment_extension_spec.rb +33 -0
- data/spec/lib/spree/core/price_migrator_spec.rb +356 -0
- data/spec/lib/spree/core/testing_support/factories/state_factory_spec.rb +9 -0
- data/spec/lib/spree/core/testing_support/factories/stock_location_factory_spec.rb +9 -0
- data/spec/lib/spree/money_spec.rb +75 -0
- data/spec/models/spree/app_configuration_spec.rb +5 -5
- data/spec/models/spree/country_spec.rb +16 -0
- data/spec/models/spree/line_item_spec.rb +6 -2
- data/spec/models/spree/preferences/preferable_spec.rb +5 -0
- data/spec/models/spree/preferences/statically_configurable_spec.rb +4 -0
- data/spec/models/spree/price_spec.rb +89 -0
- data/spec/models/spree/stock/coordinator_spec.rb +9 -0
- data/spec/models/spree/stock/splitter/shipping_category_spec.rb +30 -32
- data/spec/models/spree/tax/tax_location_spec.rb +14 -5
- data/spec/models/spree/tax/taxation_integration_spec.rb +15 -42
- data/spec/models/spree/variant/{pricer_spec.rb → price_selector_spec.rb} +41 -1
- data/spec/models/spree/variant/pricing_options_spec.rb +87 -4
- data/spec/models/spree/variant/vat_price_generator_spec.rb +69 -0
- data/spec/models/spree/variant_spec.rb +57 -8
- metadata +14 -5
- data/app/models/spree/product_scope/scopes.rb +0 -47
- data/app/models/spree/variant/pricer.rb +0 -19
@@ -1,21 +1,36 @@
|
|
1
1
|
module Spree
|
2
2
|
module TestingSupport
|
3
|
-
#
|
4
|
-
#
|
3
|
+
# A module providing convenience methods to test Solidus controllers
|
4
|
+
# in Rails controller/functional tests. Possibly from inside an
|
5
|
+
# application with a mounted Solidus engine.
|
5
6
|
#
|
6
|
-
#
|
7
|
-
#
|
7
|
+
# *There is generaly no need* to use this module. Instead, in
|
8
|
+
# a functional/controller test against a Spree controller, just
|
9
|
+
# use standard Rails functionality by including:
|
10
|
+
#
|
11
|
+
# routes { Spree::Core::Engine.routes }
|
12
|
+
#
|
13
|
+
# And then use standard Rails test `get`, `post` etc methods.
|
14
|
+
#
|
15
|
+
# But some legacy code uses this ControllerRequests helper. It must
|
16
|
+
# be included only in tests against Spree controllers, it will interfere
|
17
|
+
# with tests against local app or other engine controllers, resulting
|
18
|
+
# in ActionController::UrlGenerationError.
|
19
|
+
#
|
20
|
+
# To use this module, inside your spec_helper.rb, include this module inside
|
21
|
+
# the RSpec.configure block by:
|
8
22
|
#
|
9
23
|
# require 'spree/testing_support/controller_requests'
|
10
24
|
# RSpec.configure do |c|
|
11
|
-
# c.include Spree::TestingSupport::ControllerRequests, :
|
25
|
+
# c.include Spree::TestingSupport::ControllerRequests, spree_controller: true
|
12
26
|
# end
|
13
27
|
#
|
14
|
-
# Then, in your controller tests, you can access
|
28
|
+
# Then, in your controller tests against spree controllers, you can access
|
29
|
+
# tag to use this module, and access spree routes like this:
|
15
30
|
#
|
16
31
|
# require 'spec_helper'
|
17
32
|
#
|
18
|
-
# describe Spree::ProductsController do
|
33
|
+
# describe Spree::ProductsController, :spree_controller do
|
19
34
|
# it "can see all the products" do
|
20
35
|
# spree_get :index
|
21
36
|
# end
|
@@ -8,6 +8,13 @@ FactoryGirl.define do
|
|
8
8
|
|
9
9
|
carmen_subregion do
|
10
10
|
carmen_country = Carmen::Country.coded(country.iso)
|
11
|
+
|
12
|
+
# TODO: This condition can be removed after this carmen update is
|
13
|
+
# available: https://github.com/jim/carmen/pull/177
|
14
|
+
if !carmen_country.subregions?
|
15
|
+
fail("Country #{country.iso} has no subregions")
|
16
|
+
end
|
17
|
+
|
11
18
|
carmen_country.subregions.coded(state_code) ||
|
12
19
|
carmen_country.subregions.sort_by(&:name).first ||
|
13
20
|
fail("Country #{country.iso} has no subregions")
|
@@ -14,7 +14,10 @@ FactoryGirl.define do
|
|
14
14
|
|
15
15
|
country { |stock_location| Spree::Country.first || stock_location.association(:country) }
|
16
16
|
state do |stock_location|
|
17
|
-
|
17
|
+
carmen_country = Carmen::Country.coded(stock_location.country.iso)
|
18
|
+
if carmen_country.subregions?
|
19
|
+
stock_location.country.states.first || stock_location.association(:state, country: stock_location.country)
|
20
|
+
end
|
18
21
|
end
|
19
22
|
|
20
23
|
factory :stock_location_without_variant_propagation do
|
@@ -0,0 +1,11 @@
|
|
1
|
+
namespace :solidus do
|
2
|
+
namespace :migrations do
|
3
|
+
namespace :create_vat_prices do
|
4
|
+
task up: :environment do
|
5
|
+
print "Creating differentiated prices for VAT countries ... "
|
6
|
+
Spree::PriceMigrator.migrate_default_vat_prices
|
7
|
+
puts "Success."
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/tasks/upgrade.rake
CHANGED
@@ -3,7 +3,8 @@ namespace :solidus do
|
|
3
3
|
desc "Upgrade Solidus to version 1.3"
|
4
4
|
task one_point_three: [
|
5
5
|
'solidus:migrations:assure_store_on_orders:up',
|
6
|
-
'solidus:migrations:migrate_shipping_rate_taxes:up'
|
6
|
+
'solidus:migrations:migrate_shipping_rate_taxes:up',
|
7
|
+
'solidus:migrations:create_vat_prices'
|
7
8
|
] do
|
8
9
|
puts "Your Solidus install is ready for Solidus 1.3."
|
9
10
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module ClassConstantizerTest
|
4
|
+
ClassA = Class.new
|
5
|
+
ClassB = Class.new
|
6
|
+
|
7
|
+
def self.reload
|
8
|
+
[:ClassA, :ClassB].each do |klass|
|
9
|
+
remove_const(klass)
|
10
|
+
const_set(klass, Class.new)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe Spree::Core::ClassConstantizer::Set do
|
16
|
+
let(:set) { described_class.new }
|
17
|
+
|
18
|
+
describe "#concat" do
|
19
|
+
it "can add one item" do
|
20
|
+
set.concat(['ClassConstantizerTest::ClassA'])
|
21
|
+
expect(set).to include(ClassConstantizerTest::ClassA)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "can add two items" do
|
25
|
+
set.concat(['ClassConstantizerTest::ClassA', ClassConstantizerTest::ClassB])
|
26
|
+
expect(set).to include(ClassConstantizerTest::ClassA)
|
27
|
+
expect(set).to include(ClassConstantizerTest::ClassB)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "<<" do
|
32
|
+
it "can add by string" do
|
33
|
+
set << "ClassConstantizerTest::ClassA"
|
34
|
+
expect(set).to include(ClassConstantizerTest::ClassA)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "can add by class" do
|
38
|
+
set << ClassConstantizerTest::ClassA
|
39
|
+
expect(set).to include(ClassConstantizerTest::ClassA)
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "class redefinition" do
|
43
|
+
shared_examples "working code reloading" do
|
44
|
+
it "works with a class" do
|
45
|
+
original = ClassConstantizerTest::ClassA
|
46
|
+
|
47
|
+
ClassConstantizerTest.reload
|
48
|
+
|
49
|
+
# Sanity check
|
50
|
+
expect(original).not_to eq(ClassConstantizerTest::ClassA)
|
51
|
+
|
52
|
+
expect(set).to include(ClassConstantizerTest::ClassA)
|
53
|
+
expect(set).to_not include(original)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "with a class" do
|
58
|
+
before { set << ClassConstantizerTest::ClassA }
|
59
|
+
it_should_behave_like "working code reloading"
|
60
|
+
end
|
61
|
+
|
62
|
+
context "with a string" do
|
63
|
+
before { set << "ClassConstantizerTest::ClassA" }
|
64
|
+
it_should_behave_like "working code reloading"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class DummyClass
|
4
|
+
include Spree::Core::EnvironmentExtension
|
5
|
+
end
|
6
|
+
|
7
|
+
class C1; end
|
8
|
+
class C2; end
|
9
|
+
class C3; end
|
10
|
+
|
11
|
+
describe Spree::Core::EnvironmentExtension do
|
12
|
+
subject { DummyClass.new }
|
13
|
+
|
14
|
+
before { subject.add_class('random_name') }
|
15
|
+
|
16
|
+
describe 'Basis' do
|
17
|
+
it { respond_to?(:random_name) }
|
18
|
+
it { respond_to?(:random_name=) }
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#getter' do
|
22
|
+
it { expect(subject.random_name).to be_empty }
|
23
|
+
it { expect(subject.random_name).to be_kind_of Spree::Core::ClassConstantizer::Set }
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#setter' do
|
27
|
+
before { subject.random_name = [C1, C2]; @set = subject.random_name.to_a }
|
28
|
+
|
29
|
+
it { expect(@set).to include(C1) }
|
30
|
+
it { expect(@set).to include(C2) }
|
31
|
+
it { expect(@set).not_to include(C3) }
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,356 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spree::PriceMigrator do
|
4
|
+
let(:order) { create :order, ship_address: shipping_address, state: "delivery" }
|
5
|
+
let(:book_product) do
|
6
|
+
create :product,
|
7
|
+
price: 20,
|
8
|
+
name: "Book",
|
9
|
+
tax_category: books_category,
|
10
|
+
shipping_category: books_shipping_category
|
11
|
+
end
|
12
|
+
let(:download_product) do
|
13
|
+
create :product,
|
14
|
+
price: 10,
|
15
|
+
name: "Download",
|
16
|
+
tax_category: digital_category,
|
17
|
+
shipping_category: digital_shipping_category
|
18
|
+
end
|
19
|
+
let(:sweater_product) do
|
20
|
+
create :product,
|
21
|
+
price: 30,
|
22
|
+
name: "Download",
|
23
|
+
tax_category: normal_category,
|
24
|
+
shipping_category: normal_shipping_category
|
25
|
+
end
|
26
|
+
|
27
|
+
let!(:book) { book_product.master }
|
28
|
+
let!(:download) { download_product.master }
|
29
|
+
let!(:sweater) { sweater_product.master }
|
30
|
+
|
31
|
+
let(:books_category) { create :tax_category, name: "Books" }
|
32
|
+
let(:normal_category) { create :tax_category, name: "Normal" }
|
33
|
+
let(:digital_category) { create :tax_category, name: "Digital Goods" }
|
34
|
+
|
35
|
+
let(:books_shipping_category) { create :shipping_category, name: "Book Shipping" }
|
36
|
+
let(:normal_shipping_category) { create :shipping_category, name: "Normal Shipping" }
|
37
|
+
let(:digital_shipping_category) { create :shipping_category, name: "Digital Premium Download" }
|
38
|
+
|
39
|
+
let(:line_item) { order.line_items.first }
|
40
|
+
let(:shipment) { order.shipments.first }
|
41
|
+
let(:shipping_rate) { shipment.shipping_rates.first }
|
42
|
+
|
43
|
+
context 'selling from germany' do
|
44
|
+
let(:germany) { create :country, iso: "DE" }
|
45
|
+
# The weird default_tax boolean is what makes this context one with default included taxes
|
46
|
+
let!(:germany_zone) { create :zone, countries: [germany], default_tax: true }
|
47
|
+
let(:romania) { create(:country, iso: "RO") }
|
48
|
+
let(:romania_zone) { create(:zone, countries: [romania] ) }
|
49
|
+
let(:eu_zone) { create(:zone, countries: [romania, germany]) }
|
50
|
+
let(:world_zone) { create(:zone, :with_country) }
|
51
|
+
|
52
|
+
let!(:german_book_vat) do
|
53
|
+
create(
|
54
|
+
:tax_rate,
|
55
|
+
name: "German reduced VAT",
|
56
|
+
included_in_price: true,
|
57
|
+
amount: 0.07,
|
58
|
+
tax_category: books_category,
|
59
|
+
zone: eu_zone
|
60
|
+
)
|
61
|
+
end
|
62
|
+
let!(:german_normal_vat) do
|
63
|
+
create(
|
64
|
+
:tax_rate,
|
65
|
+
name: "German VAT",
|
66
|
+
included_in_price: true,
|
67
|
+
amount: 0.19,
|
68
|
+
tax_category: normal_category,
|
69
|
+
zone: eu_zone
|
70
|
+
)
|
71
|
+
end
|
72
|
+
let!(:german_digital_vat) do
|
73
|
+
create(
|
74
|
+
:tax_rate,
|
75
|
+
name: "German VAT",
|
76
|
+
included_in_price: true,
|
77
|
+
amount: 0.19,
|
78
|
+
tax_category: digital_category,
|
79
|
+
zone: germany_zone
|
80
|
+
)
|
81
|
+
end
|
82
|
+
let!(:romanian_digital_vat) do
|
83
|
+
create(
|
84
|
+
:tax_rate,
|
85
|
+
name: "Romanian VAT",
|
86
|
+
included_in_price: true,
|
87
|
+
amount: 0.24,
|
88
|
+
tax_category: digital_category,
|
89
|
+
zone: romania_zone
|
90
|
+
)
|
91
|
+
end
|
92
|
+
let!(:book_shipping_method) do
|
93
|
+
create :shipping_method,
|
94
|
+
cost: 8.00,
|
95
|
+
shipping_categories: [books_shipping_category],
|
96
|
+
tax_category: books_category,
|
97
|
+
zones: [eu_zone, world_zone]
|
98
|
+
end
|
99
|
+
|
100
|
+
let!(:sweater_shipping_method) do
|
101
|
+
create :shipping_method,
|
102
|
+
cost: 16.00,
|
103
|
+
shipping_categories: [normal_shipping_category],
|
104
|
+
tax_category: normal_category,
|
105
|
+
zones: [eu_zone, world_zone]
|
106
|
+
end
|
107
|
+
|
108
|
+
let!(:premium_download_shipping_method) do
|
109
|
+
create :shipping_method,
|
110
|
+
cost: 2.00,
|
111
|
+
shipping_categories: [digital_shipping_category],
|
112
|
+
tax_category: digital_category,
|
113
|
+
zones: [eu_zone, world_zone]
|
114
|
+
end
|
115
|
+
|
116
|
+
before do
|
117
|
+
Spree::PriceMigrator.migrate_default_vat_prices
|
118
|
+
order.contents.add(variant)
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'to germany' do
|
122
|
+
let(:shipping_address) { create :address, country_iso_code: "DE" }
|
123
|
+
|
124
|
+
context 'an order with a book' do
|
125
|
+
let(:variant) { book }
|
126
|
+
|
127
|
+
it 'still has the original price' do
|
128
|
+
expect(line_item.price).to eq(20)
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'has one tax adjustment' do
|
132
|
+
expect(line_item.adjustments.tax.count).to eq(1)
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'has 1.13 cents of included tax' do
|
136
|
+
expect(line_item.included_tax_total).to eq(1.31)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'an order with a sweater' do
|
141
|
+
let(:variant) { sweater }
|
142
|
+
|
143
|
+
it 'still has the original price' do
|
144
|
+
expect(line_item.price).to eq(30)
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'has one tax adjustment' do
|
148
|
+
expect(line_item.adjustments.tax.count).to eq(1)
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'has 4,78 of included tax' do
|
152
|
+
expect(line_item.included_tax_total).to eq(4.79)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
context 'an order with a download' do
|
157
|
+
let(:variant) { download }
|
158
|
+
|
159
|
+
it 'still has the original price' do
|
160
|
+
expect(line_item.price).to eq(10)
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'has one tax adjustment' do
|
164
|
+
expect(line_item.adjustments.tax.count).to eq(1)
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'has 1.60 of included tax' do
|
168
|
+
expect(line_item.included_tax_total).to eq(1.60)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
context 'to romania' do
|
174
|
+
let(:shipping_address) { create :address, country_iso_code: "RO" }
|
175
|
+
|
176
|
+
context 'an order with a book' do
|
177
|
+
let(:variant) { book }
|
178
|
+
|
179
|
+
it 'still has the original price' do
|
180
|
+
expect(line_item.price).to eq(20)
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'is adjusted to the original price' do
|
184
|
+
expect(line_item.total).to eq(20)
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'has one tax adjustment' do
|
188
|
+
expect(line_item.adjustments.tax.count).to eq(1)
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'has 1.13 cents of included tax' do
|
192
|
+
expect(line_item.included_tax_total).to eq(1.31)
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'has a constant amount pre tax' do
|
196
|
+
expect(line_item.discounted_amount - line_item.included_tax_total).to eq(18.69)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
context 'an order with a sweater' do
|
201
|
+
let(:variant) { sweater }
|
202
|
+
|
203
|
+
it 'still has the original price' do
|
204
|
+
expect(line_item.price).to eq(30)
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'has one tax adjustment' do
|
208
|
+
expect(line_item.adjustments.tax.count).to eq(1)
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'has 4.79 of included tax' do
|
212
|
+
expect(line_item.included_tax_total).to eq(4.79)
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'has a constant amount pre tax' do
|
216
|
+
expect(line_item.discounted_amount - line_item.included_tax_total).to eq(25.21)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
context 'an order with a download' do
|
221
|
+
let(:variant) { download }
|
222
|
+
|
223
|
+
it 'still has an adjusted price for romania' do
|
224
|
+
expect(line_item.price).to eq(10.42)
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'has one tax adjustment' do
|
228
|
+
expect(line_item.adjustments.tax.count).to eq(1)
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'has 2.02 of included tax' do
|
232
|
+
expect(line_item.included_tax_total).to eq(2.02)
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'has a constant amount pre tax' do
|
236
|
+
expect(line_item.discounted_amount - line_item.included_tax_total).to eq(8.40)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
# Technically, this can't be the case yet as the order won't pass the shipment stage,
|
242
|
+
# but the taxation code shouldn't implicitly depend on the shipping code.
|
243
|
+
context 'to an address that does not have a zone associated' do
|
244
|
+
let(:shipping_address) { create :address, country_iso_code: "IT" }
|
245
|
+
|
246
|
+
context 'an order with a book' do
|
247
|
+
let(:variant) { book }
|
248
|
+
|
249
|
+
it 'should sell at the net price' do
|
250
|
+
expect(line_item.price).to eq(18.69)
|
251
|
+
end
|
252
|
+
|
253
|
+
it 'is adjusted to the net price' do
|
254
|
+
expect(line_item.total).to eq(18.69)
|
255
|
+
end
|
256
|
+
|
257
|
+
it 'has no tax adjustments' do
|
258
|
+
expect(line_item.adjustments.tax.count).to eq(0)
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'has no included tax' do
|
262
|
+
expect(line_item.included_tax_total).to eq(0)
|
263
|
+
end
|
264
|
+
|
265
|
+
it 'has no additional tax' do
|
266
|
+
expect(line_item.additional_tax_total).to eq(0)
|
267
|
+
end
|
268
|
+
|
269
|
+
it 'has a constant amount pre tax' do
|
270
|
+
expect(line_item.discounted_amount - line_item.included_tax_total).to eq(18.69)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
# International delivery, no tax applies whatsoever
|
276
|
+
context 'to anywhere else in the world' do
|
277
|
+
let(:shipping_address) { create :address, country: world_zone.countries.first }
|
278
|
+
|
279
|
+
context 'an order with a book' do
|
280
|
+
let(:variant) { book }
|
281
|
+
|
282
|
+
it 'should sell at the net price' do
|
283
|
+
expect(line_item.price).to eq(18.69)
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'is adjusted to the net price' do
|
287
|
+
expect(line_item.total).to eq(18.69)
|
288
|
+
end
|
289
|
+
|
290
|
+
it 'has no tax adjustments' do
|
291
|
+
expect(line_item.adjustments.tax.count).to eq(0)
|
292
|
+
end
|
293
|
+
|
294
|
+
it 'has no included tax' do
|
295
|
+
expect(line_item.included_tax_total).to eq(0)
|
296
|
+
end
|
297
|
+
|
298
|
+
it 'has no additional tax' do
|
299
|
+
expect(line_item.additional_tax_total).to eq(0)
|
300
|
+
end
|
301
|
+
|
302
|
+
it 'has a constant amount pre tax' do
|
303
|
+
expect(line_item.discounted_amount - line_item.included_tax_total).to eq(18.69)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
context 'an order with a sweater' do
|
308
|
+
let(:variant) { sweater }
|
309
|
+
|
310
|
+
it 'should sell at the net price' do
|
311
|
+
expect(line_item.price).to eq(25.21)
|
312
|
+
end
|
313
|
+
|
314
|
+
it 'has no tax adjustments' do
|
315
|
+
expect(line_item.adjustments.tax.count).to eq(0)
|
316
|
+
end
|
317
|
+
|
318
|
+
it 'has no included tax' do
|
319
|
+
expect(line_item.included_tax_total).to eq(0)
|
320
|
+
end
|
321
|
+
|
322
|
+
it 'has no additional tax' do
|
323
|
+
expect(line_item.additional_tax_total).to eq(0)
|
324
|
+
end
|
325
|
+
|
326
|
+
it 'has a constant amount pre tax' do
|
327
|
+
expect(line_item.discounted_amount - line_item.included_tax_total).to eq(25.21)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
context 'an order with a download' do
|
332
|
+
let(:variant) { download }
|
333
|
+
|
334
|
+
it 'should sell at the net price' do
|
335
|
+
expect(line_item.price).to eq(8.40)
|
336
|
+
end
|
337
|
+
|
338
|
+
it 'has no tax adjustments' do
|
339
|
+
expect(line_item.adjustments.tax.count).to eq(0)
|
340
|
+
end
|
341
|
+
|
342
|
+
it 'has no included tax' do
|
343
|
+
expect(line_item.included_tax_total).to eq(0)
|
344
|
+
end
|
345
|
+
|
346
|
+
it 'has no additional tax' do
|
347
|
+
expect(line_item.additional_tax_total).to eq(0)
|
348
|
+
end
|
349
|
+
|
350
|
+
it 'has a constant amount pre tax' do
|
351
|
+
expect(line_item.discounted_amount - line_item.included_tax_total).to eq(8.40)
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
@@ -17,6 +17,7 @@ RSpec.describe 'state factory' do
|
|
17
17
|
|
18
18
|
describe 'when given a country iso code' do
|
19
19
|
let(:state) { build(:state, country_iso: "DE") }
|
20
|
+
|
20
21
|
it 'creates the first state for that country it finds in carmen' do
|
21
22
|
expect(state.abbr).to eq("BW")
|
22
23
|
expect(state.name).to eq("Baden-Württemberg")
|
@@ -45,4 +46,12 @@ RSpec.describe 'state factory' do
|
|
45
46
|
expect{ build(:state, country_iso: "ZZ") }.to raise_error(RuntimeError, 'Unknown country iso code: "ZZ"')
|
46
47
|
end
|
47
48
|
end
|
49
|
+
|
50
|
+
context 'with a country that does not have subregions' do
|
51
|
+
it 'raises an exception' do
|
52
|
+
expect {
|
53
|
+
create(:state, country_iso: 'HK')
|
54
|
+
}.to raise_error('Country HK has no subregions')
|
55
|
+
end
|
56
|
+
end
|
48
57
|
end
|
@@ -21,4 +21,13 @@ RSpec.describe 'stock location factory' do
|
|
21
21
|
|
22
22
|
it_behaves_like 'a working factory'
|
23
23
|
end
|
24
|
+
|
25
|
+
describe 'stock location for a country without subregions' do
|
26
|
+
let(:country) { create(:country, iso: 'HK') }
|
27
|
+
it 'succeeds' do
|
28
|
+
expect(
|
29
|
+
create(:stock_location, country: country)
|
30
|
+
).to be_a(Spree::StockLocation)
|
31
|
+
end
|
32
|
+
end
|
24
33
|
end
|
@@ -8,6 +8,81 @@ describe Spree::Money do
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
+
describe '#initialize' do
|
12
|
+
subject do
|
13
|
+
Spree::Deprecation.silence do
|
14
|
+
described_class.new(amount, currency: currency, with_currency: true).to_s
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'with no currency' do
|
19
|
+
let(:currency) { nil }
|
20
|
+
let(:amount){ 10 }
|
21
|
+
it { should == "$10.00 USD" }
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'with currency' do
|
25
|
+
let(:currency){ 'USD' }
|
26
|
+
|
27
|
+
context "CAD" do
|
28
|
+
let(:amount){ '10.00' }
|
29
|
+
let(:currency){ 'CAD' }
|
30
|
+
it { should == "$10.00 CAD" }
|
31
|
+
end
|
32
|
+
|
33
|
+
context "with string amount" do
|
34
|
+
let(:amount){ '10.00' }
|
35
|
+
it { should == "$10.00 USD" }
|
36
|
+
end
|
37
|
+
|
38
|
+
context "with no decimal point" do
|
39
|
+
let(:amount){ '10' }
|
40
|
+
it { should == "$10.00 USD" }
|
41
|
+
end
|
42
|
+
|
43
|
+
context "with symbol" do
|
44
|
+
let(:amount){ '$10.00' }
|
45
|
+
it { should == "$10.00 USD" }
|
46
|
+
end
|
47
|
+
|
48
|
+
context "with extra currency" do
|
49
|
+
let(:amount){ '$10.00 USD' }
|
50
|
+
it { should == "$10.00 USD" }
|
51
|
+
end
|
52
|
+
|
53
|
+
context "with different currency" do
|
54
|
+
let(:currency){ 'USD' }
|
55
|
+
let(:amount){ '$10.00 CAD' }
|
56
|
+
it { should == "$10.00 CAD" }
|
57
|
+
end
|
58
|
+
|
59
|
+
context "with commas" do
|
60
|
+
let(:amount){ '1,000.00' }
|
61
|
+
it { should == "$1,000.00 USD" }
|
62
|
+
end
|
63
|
+
|
64
|
+
context "with comma for decimal point" do
|
65
|
+
let(:amount){ '10,00' }
|
66
|
+
it { should == "$10.00 USD" }
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'with fixnum' do
|
70
|
+
let(:amount){ 10 }
|
71
|
+
it { should == "$10.00 USD" }
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'with float' do
|
75
|
+
let(:amount){ 10.00 }
|
76
|
+
it { should == "$10.00 USD" }
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'with BigDecimal' do
|
80
|
+
let(:amount){ BigDecimal.new('10.00') }
|
81
|
+
it { should == "$10.00 USD" }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
11
86
|
it "formats correctly" do
|
12
87
|
money = Spree::Money.new(10)
|
13
88
|
expect(money.to_s).to eq("$10.00")
|
@@ -20,16 +20,16 @@ describe Spree::AppConfiguration, type: :model do
|
|
20
20
|
expect(prefs.variant_search_class).to eq Spree::Core::Search::Variant
|
21
21
|
end
|
22
22
|
|
23
|
-
it "uses variant
|
24
|
-
expect(prefs.
|
23
|
+
it "uses variant price selector class by default" do
|
24
|
+
expect(prefs.variant_price_selector_class).to eq Spree::Variant::PriceSelector
|
25
25
|
end
|
26
26
|
|
27
|
-
it "has a getter for the pricing options class provided by the variant
|
28
|
-
expect(prefs.pricing_options_class).to eq Spree::Variant::
|
27
|
+
it "has a getter for the pricing options class provided by the variant price selector class" do
|
28
|
+
expect(prefs.pricing_options_class).to eq Spree::Variant::PriceSelector.pricing_options_class
|
29
29
|
end
|
30
30
|
|
31
31
|
it "has an instacached getter for the default pricing options" do
|
32
|
-
expect(prefs.default_pricing_options).to be_a Spree::Variant::
|
32
|
+
expect(prefs.default_pricing_options).to be_a Spree::Variant::PriceSelector.pricing_options_class
|
33
33
|
expect(prefs.default_pricing_options.object_id).to eq prefs.default_pricing_options.object_id
|
34
34
|
end
|
35
35
|
|