solidus_core 1.3.0.beta1 → 1.3.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
|
|