spree_core 3.0.5 → 3.0.6

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.
Files changed (194) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/Gemfile +3 -0
  4. data/Rakefile +30 -0
  5. data/app/assets/javascripts/spree.js.coffee.erb +1 -1
  6. data/app/models/spree/ability.rb +1 -1
  7. data/app/models/spree/base.rb +3 -1
  8. data/app/models/spree/order_updater.rb +2 -1
  9. data/app/models/spree/price.rb +7 -12
  10. data/app/models/spree/product.rb +3 -2
  11. data/app/models/spree/reimbursement.rb +1 -1
  12. data/app/models/spree/state.rb +2 -0
  13. data/app/models/spree/zone.rb +1 -1
  14. data/lib/spree/core/version.rb +1 -1
  15. data/lib/spree/testing_support/shoulda_matcher_configuration.rb +6 -0
  16. data/script/rails +9 -0
  17. data/spec/fixtures/thinking-cat.jpg +0 -0
  18. data/spec/helpers/base_helper_spec.rb +137 -0
  19. data/spec/helpers/products_helper_spec.rb +224 -0
  20. data/spec/lib/calculated_adjustments_spec.rb +7 -0
  21. data/spec/lib/i18n_spec.rb +123 -0
  22. data/spec/lib/search/base_spec.rb +86 -0
  23. data/spec/lib/spree/core/controller_helpers/auth_spec.rb +101 -0
  24. data/spec/lib/spree/core/controller_helpers/order_spec.rb +95 -0
  25. data/spec/lib/spree/core/controller_helpers/search_spec.rb +17 -0
  26. data/spec/lib/spree/core/controller_helpers/store_spec.rb +16 -0
  27. data/spec/lib/spree/core/controller_helpers/strong_parameters_spec.rb +39 -0
  28. data/spec/lib/spree/core/delegate_belongs_to_spec.rb +22 -0
  29. data/spec/lib/spree/core/importer/order_spec.rb +502 -0
  30. data/spec/lib/spree/core/validators/email_spec.rb +53 -0
  31. data/spec/lib/spree/localized_number_spec.rb +38 -0
  32. data/spec/lib/spree/migrations_spec.rb +34 -0
  33. data/spec/lib/spree/money_spec.rb +122 -0
  34. data/spec/lib/tasks/exchanges_spec.rb +136 -0
  35. data/spec/mailers/order_mailer_spec.rb +124 -0
  36. data/spec/mailers/reimbursement_mailer_spec.rb +47 -0
  37. data/spec/mailers/shipment_mailer_spec.rb +63 -0
  38. data/spec/mailers/test_mailer_spec.rb +24 -0
  39. data/spec/models/spree/ability_spec.rb +246 -0
  40. data/spec/models/spree/address_spec.rb +291 -0
  41. data/spec/models/spree/adjustable/adjustments_updater_spec.rb +286 -0
  42. data/spec/models/spree/adjustment_spec.rb +163 -0
  43. data/spec/models/spree/app_configuration_spec.rb +23 -0
  44. data/spec/models/spree/asset_spec.rb +25 -0
  45. data/spec/models/spree/calculator/default_tax_spec.rb +127 -0
  46. data/spec/models/spree/calculator/flat_percent_item_total_spec.rb +25 -0
  47. data/spec/models/spree/calculator/flat_rate_spec.rb +47 -0
  48. data/spec/models/spree/calculator/flexi_rate_spec.rb +41 -0
  49. data/spec/models/spree/calculator/percent_on_line_item_spec.rb +15 -0
  50. data/spec/models/spree/calculator/price_sack_spec.rb +30 -0
  51. data/spec/models/spree/calculator/refunds/default_refund_amount_spec.rb +51 -0
  52. data/spec/models/spree/calculator/shipping.rb +8 -0
  53. data/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb +23 -0
  54. data/spec/models/spree/calculator/shipping/flat_rate_spec.rb +13 -0
  55. data/spec/models/spree/calculator/shipping/flexi_rate_spec.rb +52 -0
  56. data/spec/models/spree/calculator/shipping/per_item_spec.rb +20 -0
  57. data/spec/models/spree/calculator/shipping/price_sack_spec.rb +29 -0
  58. data/spec/models/spree/calculator/tiered_flat_rate_spec.rb +40 -0
  59. data/spec/models/spree/calculator/tiered_percent_spec.rb +51 -0
  60. data/spec/models/spree/calculator_spec.rb +69 -0
  61. data/spec/models/spree/classification_spec.rb +93 -0
  62. data/spec/models/spree/concerns/display_money_spec.rb +43 -0
  63. data/spec/models/spree/country_spec.rb +18 -0
  64. data/spec/models/spree/credit_card_spec.rb +324 -0
  65. data/spec/models/spree/customer_return_spec.rb +262 -0
  66. data/spec/models/spree/exchange_spec.rb +75 -0
  67. data/spec/models/spree/gateway/bogus_simple.rb +20 -0
  68. data/spec/models/spree/gateway/bogus_spec.rb +13 -0
  69. data/spec/models/spree/gateway_spec.rb +54 -0
  70. data/spec/models/spree/image_spec.rb +5 -0
  71. data/spec/models/spree/inventory_unit_spec.rb +242 -0
  72. data/spec/models/spree/line_item_spec.rb +267 -0
  73. data/spec/models/spree/option_type_spec.rb +14 -0
  74. data/spec/models/spree/option_value_spec.rb +13 -0
  75. data/spec/models/spree/order/address_spec.rb +50 -0
  76. data/spec/models/spree/order/adjustments_spec.rb +29 -0
  77. data/spec/models/spree/order/callbacks_spec.rb +42 -0
  78. data/spec/models/spree/order/checkout_spec.rb +764 -0
  79. data/spec/models/spree/order/currency_updater_spec.rb +32 -0
  80. data/spec/models/spree/order/finalizing_spec.rb +117 -0
  81. data/spec/models/spree/order/helpers_spec.rb +5 -0
  82. data/spec/models/spree/order/payment_spec.rb +214 -0
  83. data/spec/models/spree/order/risk_assessment_spec.rb +84 -0
  84. data/spec/models/spree/order/shipments_spec.rb +43 -0
  85. data/spec/models/spree/order/state_machine_spec.rb +216 -0
  86. data/spec/models/spree/order/tax_spec.rb +84 -0
  87. data/spec/models/spree/order/totals_spec.rb +24 -0
  88. data/spec/models/spree/order/updating_spec.rb +18 -0
  89. data/spec/models/spree/order/validations_spec.rb +15 -0
  90. data/spec/models/spree/order_contents_spec.rb +256 -0
  91. data/spec/models/spree/order_inventory_spec.rb +228 -0
  92. data/spec/models/spree/order_merger_spec.rb +133 -0
  93. data/spec/models/spree/order_spec.rb +954 -0
  94. data/spec/models/spree/order_updater_spec.rb +283 -0
  95. data/spec/models/spree/payment/gateway_options_spec.rb +119 -0
  96. data/spec/models/spree/payment_method_spec.rb +95 -0
  97. data/spec/models/spree/payment_spec.rb +926 -0
  98. data/spec/models/spree/preference_spec.rb +80 -0
  99. data/spec/models/spree/preferences/configuration_spec.rb +30 -0
  100. data/spec/models/spree/preferences/preferable_spec.rb +348 -0
  101. data/spec/models/spree/preferences/scoped_store_spec.rb +58 -0
  102. data/spec/models/spree/preferences/store_spec.rb +46 -0
  103. data/spec/models/spree/price_spec.rb +42 -0
  104. data/spec/models/spree/product/scopes_spec.rb +148 -0
  105. data/spec/models/spree/product_duplicator_spec.rb +103 -0
  106. data/spec/models/spree/product_filter_spec.rb +26 -0
  107. data/spec/models/spree/product_option_type_spec.rb +5 -0
  108. data/spec/models/spree/product_property_spec.rb +11 -0
  109. data/spec/models/spree/product_spec.rb +474 -0
  110. data/spec/models/spree/promotion/actions/create_adjustment_spec.rb +50 -0
  111. data/spec/models/spree/promotion/actions/create_item_adjustments_spec.rb +148 -0
  112. data/spec/models/spree/promotion/actions/create_line_items_spec.rb +86 -0
  113. data/spec/models/spree/promotion/actions/free_shipping_spec.rb +36 -0
  114. data/spec/models/spree/promotion/rules/first_order_spec.rb +75 -0
  115. data/spec/models/spree/promotion/rules/item_total_spec.rb +282 -0
  116. data/spec/models/spree/promotion/rules/one_use_per_user_spec.rb +42 -0
  117. data/spec/models/spree/promotion/rules/option_value_spec.rb +90 -0
  118. data/spec/models/spree/promotion/rules/product_spec.rb +143 -0
  119. data/spec/models/spree/promotion/rules/taxon_spec.rb +102 -0
  120. data/spec/models/spree/promotion/rules/user_logged_in_spec.rb +27 -0
  121. data/spec/models/spree/promotion/rules/user_spec.rb +37 -0
  122. data/spec/models/spree/promotion_action_spec.rb +10 -0
  123. data/spec/models/spree/promotion_category_spec.rb +17 -0
  124. data/spec/models/spree/promotion_handler/cart_spec.rb +102 -0
  125. data/spec/models/spree/promotion_handler/coupon_spec.rb +323 -0
  126. data/spec/models/spree/promotion_handler/free_shipping_spec.rb +48 -0
  127. data/spec/models/spree/promotion_handler/page_spec.rb +44 -0
  128. data/spec/models/spree/promotion_rule_spec.rb +29 -0
  129. data/spec/models/spree/promotion_spec.rb +603 -0
  130. data/spec/models/spree/property_spec.rb +5 -0
  131. data/spec/models/spree/prototype_spec.rb +5 -0
  132. data/spec/models/spree/refund_spec.rb +195 -0
  133. data/spec/models/spree/reimbursement/credit_spec.rb +36 -0
  134. data/spec/models/spree/reimbursement/reimbursement_type_engine_spec.rb +140 -0
  135. data/spec/models/spree/reimbursement/reimbursement_type_validator_spec.rb +83 -0
  136. data/spec/models/spree/reimbursement_performer_spec.rb +30 -0
  137. data/spec/models/spree/reimbursement_spec.rb +215 -0
  138. data/spec/models/spree/reimbursement_tax_calculator_spec.rb +51 -0
  139. data/spec/models/spree/reimbursement_type/credit_spec.rb +53 -0
  140. data/spec/models/spree/reimbursement_type/exchange_spec.rb +46 -0
  141. data/spec/models/spree/reimbursement_type/original_payment_spec.rb +55 -0
  142. data/spec/models/spree/return_authorization_spec.rb +250 -0
  143. data/spec/models/spree/return_item/eligibility_validator/default_spec.rb +77 -0
  144. data/spec/models/spree/return_item/eligibility_validator/inventory_shipped_spec.rb +58 -0
  145. data/spec/models/spree/return_item/eligibility_validator/no_reimbursements_spec.rb +61 -0
  146. data/spec/models/spree/return_item/eligibility_validator/order_completed_spec.rb +32 -0
  147. data/spec/models/spree/return_item/eligibility_validator/rma_required_spec.rb +29 -0
  148. data/spec/models/spree/return_item/eligibility_validator/time_since_purchase_spec.rb +35 -0
  149. data/spec/models/spree/return_item/exchange_variant_eligibility/same_option_value_spec.rb +65 -0
  150. data/spec/models/spree/return_item/exchange_variant_eligibility/same_product_spec.rb +43 -0
  151. data/spec/models/spree/return_item_spec.rb +682 -0
  152. data/spec/models/spree/returns_calculator_spec.rb +14 -0
  153. data/spec/models/spree/shipment_spec.rb +740 -0
  154. data/spec/models/spree/shipping_calculator_spec.rb +45 -0
  155. data/spec/models/spree/shipping_category_spec.rb +5 -0
  156. data/spec/models/spree/shipping_method_spec.rb +88 -0
  157. data/spec/models/spree/shipping_rate_spec.rb +141 -0
  158. data/spec/models/spree/state_spec.rb +18 -0
  159. data/spec/models/spree/stock/availability_validator_spec.rb +36 -0
  160. data/spec/models/spree/stock/content_item_spec.rb +22 -0
  161. data/spec/models/spree/stock/coordinator_spec.rb +51 -0
  162. data/spec/models/spree/stock/differentiator_spec.rb +39 -0
  163. data/spec/models/spree/stock/estimator_spec.rb +154 -0
  164. data/spec/models/spree/stock/inventory_unit_builder_spec.rb +38 -0
  165. data/spec/models/spree/stock/package_spec.rb +194 -0
  166. data/spec/models/spree/stock/packer_spec.rb +70 -0
  167. data/spec/models/spree/stock/prioritizer_spec.rb +125 -0
  168. data/spec/models/spree/stock/quantifier_spec.rb +97 -0
  169. data/spec/models/spree/stock/splitter/backordered_spec.rb +29 -0
  170. data/spec/models/spree/stock/splitter/base_spec.rb +21 -0
  171. data/spec/models/spree/stock/splitter/shipping_category_spec.rb +47 -0
  172. data/spec/models/spree/stock/splitter/weight_spec.rb +32 -0
  173. data/spec/models/spree/stock_item_spec.rb +410 -0
  174. data/spec/models/spree/stock_location_spec.rb +243 -0
  175. data/spec/models/spree/stock_movement_spec.rb +56 -0
  176. data/spec/models/spree/stock_transfer_spec.rb +50 -0
  177. data/spec/models/spree/store_spec.rb +50 -0
  178. data/spec/models/spree/tax_category_spec.rb +27 -0
  179. data/spec/models/spree/tax_rate_spec.rb +382 -0
  180. data/spec/models/spree/taxon_spec.rb +74 -0
  181. data/spec/models/spree/taxonomy_spec.rb +18 -0
  182. data/spec/models/spree/tracker_spec.rb +21 -0
  183. data/spec/models/spree/user_spec.rb +130 -0
  184. data/spec/models/spree/validations/db_maximum_length_validator_spec.rb +24 -0
  185. data/spec/models/spree/variant_spec.rb +523 -0
  186. data/spec/models/spree/zone_spec.rb +444 -0
  187. data/spec/spec_helper.rb +74 -0
  188. data/spec/support/big_decimal.rb +5 -0
  189. data/spec/support/concerns/adjustment_source_spec.rb +23 -0
  190. data/spec/support/concerns/default_price_spec.rb +28 -0
  191. data/spec/support/rake.rb +13 -0
  192. data/spec/support/test_gateway.rb +2 -0
  193. data/spree_core.gemspec +48 -0
  194. metadata +185 -4
@@ -0,0 +1,243 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ describe StockLocation, :type => :model do
5
+ subject { create(:stock_location_with_items, backorderable_default: true) }
6
+ let(:stock_item) { subject.stock_items.order(:id).first }
7
+ let(:variant) { stock_item.variant }
8
+
9
+ it 'creates stock_items for all variants' do
10
+ expect(subject.stock_items.count).to eq Variant.count
11
+ end
12
+
13
+ context "handling stock items" do
14
+ let!(:variant) { create(:variant) }
15
+
16
+ context "given a variant" do
17
+ subject { StockLocation.create(name: "testing", propagate_all_variants: false) }
18
+
19
+ context "set up" do
20
+ it "creates stock item" do
21
+ expect(subject).to receive(:propagate_variant)
22
+ subject.set_up_stock_item(variant)
23
+ end
24
+
25
+ context "stock item exists" do
26
+ let!(:stock_item) { subject.propagate_variant(variant) }
27
+
28
+ it "returns existing stock item" do
29
+ expect(subject.set_up_stock_item(variant)).to eq(stock_item)
30
+ end
31
+ end
32
+ end
33
+
34
+ context "propagate variants" do
35
+ let(:stock_item) { subject.propagate_variant(variant) }
36
+
37
+ it "creates a new stock item" do
38
+ expect {
39
+ subject.propagate_variant(variant)
40
+ }.to change{ StockItem.count }.by(1)
41
+ end
42
+
43
+ context "passes backorderable default config" do
44
+ context "true" do
45
+ before { subject.backorderable_default = true }
46
+ it { expect(stock_item.backorderable).to be true }
47
+ end
48
+
49
+ context "false" do
50
+ before { subject.backorderable_default = false }
51
+ it { expect(stock_item.backorderable).to be false }
52
+ end
53
+ end
54
+ end
55
+
56
+ context "propagate all variants" do
57
+ subject { StockLocation.new(name: "testing") }
58
+
59
+ context "true" do
60
+ before { subject.propagate_all_variants = true }
61
+
62
+ specify do
63
+ expect(subject).to receive(:propagate_variant).at_least(:once)
64
+ subject.save!
65
+ end
66
+ end
67
+
68
+ context "false" do
69
+ before { subject.propagate_all_variants = false }
70
+
71
+ specify do
72
+ expect(subject).not_to receive(:propagate_variant)
73
+ subject.save!
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ it 'finds a stock_item for a variant' do
81
+ stock_item = subject.stock_item(variant)
82
+ expect(stock_item.count_on_hand).to eq 10
83
+ end
84
+
85
+ it 'finds a stock_item for a variant by id' do
86
+ stock_item = subject.stock_item(variant.id)
87
+ expect(stock_item.variant).to eq variant
88
+ end
89
+
90
+ it 'returns nil when stock_item is not found for variant' do
91
+ stock_item = subject.stock_item(100)
92
+ expect(stock_item).to be_nil
93
+ end
94
+
95
+ describe '#stock_item_or_create' do
96
+ before do
97
+ variant = create(:variant)
98
+ variant.stock_items.destroy_all
99
+ variant.save
100
+ end
101
+
102
+ it 'creates a stock_item if not found for a variant' do
103
+ stock_item = subject.stock_item_or_create(variant)
104
+ expect(stock_item.variant).to eq variant
105
+ end
106
+ end
107
+
108
+ it 'finds a count_on_hand for a variant' do
109
+ expect(subject.count_on_hand(variant)).to eq 10
110
+ end
111
+
112
+ it 'finds determines if you a variant is backorderable' do
113
+ expect(subject.backorderable?(variant)).to be true
114
+ end
115
+
116
+ it 'restocks a variant with a positive stock movement' do
117
+ originator = double
118
+ expect(subject).to receive(:move).with(variant, 5, originator)
119
+ subject.restock(variant, 5, originator)
120
+ end
121
+
122
+ it 'unstocks a variant with a negative stock movement' do
123
+ originator = double
124
+ expect(subject).to receive(:move).with(variant, -5, originator)
125
+ subject.unstock(variant, 5, originator)
126
+ end
127
+
128
+ it 'it creates a stock_movement' do
129
+ expect {
130
+ subject.move variant, 5
131
+ }.to change { subject.stock_movements.where(stock_item_id: stock_item).count }.by(1)
132
+ end
133
+
134
+ it 'can be deactivated' do
135
+ create(:stock_location, :active => true)
136
+ create(:stock_location, :active => false)
137
+ expect(Spree::StockLocation.active.count).to eq 1
138
+ end
139
+
140
+ it 'ensures only one stock location is default at a time' do
141
+ first = create(:stock_location, :active => true, :default => true)
142
+ second = create(:stock_location, :active => true, :default => true)
143
+
144
+ expect(first.reload.default).to eq false
145
+ expect(second.reload.default).to eq true
146
+
147
+ first.default = true
148
+ first.save!
149
+
150
+ expect(first.reload.default).to eq true
151
+ expect(second.reload.default).to eq false
152
+ end
153
+
154
+ context 'fill_status' do
155
+ it 'all on_hand with no backordered' do
156
+ on_hand, backordered = subject.fill_status(variant, 5)
157
+ expect(on_hand).to eq 5
158
+ expect(backordered).to eq 0
159
+ end
160
+
161
+ it 'some on_hand with some backordered' do
162
+ on_hand, backordered = subject.fill_status(variant, 20)
163
+ expect(on_hand).to eq 10
164
+ expect(backordered).to eq 10
165
+ end
166
+
167
+ it 'zero on_hand with all backordered' do
168
+ zero_stock_item = mock_model(StockItem,
169
+ count_on_hand: 0,
170
+ backorderable?: true)
171
+ expect(subject).to receive(:stock_item).with(variant).and_return(zero_stock_item)
172
+
173
+ on_hand, backordered = subject.fill_status(variant, 20)
174
+ expect(on_hand).to eq 0
175
+ expect(backordered).to eq 20
176
+ end
177
+
178
+ context 'when backordering is not allowed' do
179
+ before do
180
+ @stock_item = mock_model(StockItem, backorderable?: false)
181
+ expect(subject).to receive(:stock_item).with(variant).and_return(@stock_item)
182
+ end
183
+
184
+ it 'all on_hand' do
185
+ allow(@stock_item).to receive_messages(count_on_hand: 10)
186
+
187
+ on_hand, backordered = subject.fill_status(variant, 5)
188
+ expect(on_hand).to eq 5
189
+ expect(backordered).to eq 0
190
+ end
191
+
192
+ it 'some on_hand' do
193
+ allow(@stock_item).to receive_messages(count_on_hand: 10)
194
+
195
+ on_hand, backordered = subject.fill_status(variant, 20)
196
+ expect(on_hand).to eq 10
197
+ expect(backordered).to eq 0
198
+ end
199
+
200
+ it 'zero on_hand' do
201
+ allow(@stock_item).to receive_messages(count_on_hand: 0)
202
+
203
+ on_hand, backordered = subject.fill_status(variant, 20)
204
+ expect(on_hand).to eq 0
205
+ expect(backordered).to eq 0
206
+ end
207
+ end
208
+
209
+ context 'without stock_items' do
210
+ subject { create(:stock_location) }
211
+ let(:variant) { create(:base_variant) }
212
+
213
+ it 'zero on_hand and backordered' do
214
+ subject
215
+ variant.stock_items.destroy_all
216
+ on_hand, backordered = subject.fill_status(variant, 1)
217
+ expect(on_hand).to eq 0
218
+ expect(backordered).to eq 0
219
+ end
220
+ end
221
+ end
222
+
223
+ context '#state_text' do
224
+ context 'state is blank' do
225
+ subject { StockLocation.create(name: "testing", state: nil, state_name: 'virginia') }
226
+ specify { expect(subject.state_text).to eq('virginia') }
227
+ end
228
+
229
+ context 'both name and abbr is present' do
230
+ let(:state) { stub_model(Spree::State, name: 'virginia', abbr: 'va') }
231
+ subject { StockLocation.create(name: "testing", state: state, state_name: nil) }
232
+ specify { expect(subject.state_text).to eq('va') }
233
+ end
234
+
235
+ context 'only name is present' do
236
+ let(:state) { stub_model(Spree::State, name: 'virginia', abbr: nil) }
237
+ subject { StockLocation.create(name: "testing", state: state, state_name: nil) }
238
+ specify { expect(subject.state_text).to eq('virginia') }
239
+ end
240
+ end
241
+
242
+ end
243
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::StockMovement, :type => :model do
4
+ let(:stock_location) { create(:stock_location_with_items) }
5
+ let(:stock_item) { stock_location.stock_items.order(:id).first }
6
+ subject { build(:stock_movement, stock_item: stock_item) }
7
+
8
+ it 'should belong to a stock item' do
9
+ expect(subject).to respond_to(:stock_item)
10
+ end
11
+
12
+ it 'is readonly unless new' do
13
+ subject.save
14
+ expect {
15
+ subject.save
16
+ }.to raise_error(ActiveRecord::ReadOnlyRecord)
17
+ end
18
+
19
+ it 'does not update count on hand when track inventory levels is false' do
20
+ Spree::Config[:track_inventory_levels] = false
21
+ subject.quantity = 1
22
+ subject.save
23
+ stock_item.reload
24
+ expect(stock_item.count_on_hand).to eq(10)
25
+ end
26
+
27
+ it 'does not update count on hand when variant inventory tracking is off' do
28
+ stock_item.variant.track_inventory = false
29
+ subject.quantity = 1
30
+ subject.save
31
+ stock_item.reload
32
+ expect(stock_item.count_on_hand).to eq(10)
33
+ end
34
+
35
+ context "when quantity is negative" do
36
+ context "after save" do
37
+ it "should decrement the stock item count on hand" do
38
+ subject.quantity = -1
39
+ subject.save
40
+ stock_item.reload
41
+ expect(stock_item.count_on_hand).to eq(9)
42
+ end
43
+ end
44
+ end
45
+
46
+ context "when quantity is positive" do
47
+ context "after save" do
48
+ it "should increment the stock item count on hand" do
49
+ subject.quantity = 1
50
+ subject.save
51
+ stock_item.reload
52
+ expect(stock_item.count_on_hand).to eq(11)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ describe StockTransfer, :type => :model do
5
+ let(:destination_location) { create(:stock_location_with_items) }
6
+ let(:source_location) { create(:stock_location_with_items) }
7
+ let(:stock_item) { source_location.stock_items.order(:id).first }
8
+ let(:variant) { stock_item.variant }
9
+
10
+ subject { StockTransfer.create(reference: 'PO123') }
11
+
12
+ describe '#reference' do
13
+ subject { super().reference }
14
+ it { is_expected.to eq 'PO123' }
15
+ end
16
+
17
+ describe '#to_param' do
18
+ subject { super().to_param }
19
+ it { is_expected.to match /T\d+/ }
20
+ end
21
+
22
+ it 'transfers variants between 2 locations' do
23
+ variants = { variant => 5 }
24
+
25
+ subject.transfer(source_location,
26
+ destination_location,
27
+ variants)
28
+
29
+ expect(source_location.count_on_hand(variant)).to eq 5
30
+ expect(destination_location.count_on_hand(variant)).to eq 5
31
+
32
+ expect(subject.source_location).to eq source_location
33
+ expect(subject.destination_location).to eq destination_location
34
+
35
+ expect(subject.source_movements.first.quantity).to eq -5
36
+ expect(subject.destination_movements.first.quantity).to eq 5
37
+ end
38
+
39
+ it 'receive new inventory (from a vendor)' do
40
+ variants = { variant => 5 }
41
+
42
+ subject.receive(destination_location, variants)
43
+
44
+ expect(destination_location.count_on_hand(variant)).to eq 5
45
+
46
+ expect(subject.source_location).to be_nil
47
+ expect(subject.destination_location).to eq destination_location
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::Store, :type => :model do
4
+
5
+ describe ".by_url" do
6
+ let!(:store) { create(:store, url: "website1.com\nwww.subdomain.com") }
7
+ let!(:store_2) { create(:store, url: 'freethewhales.com') }
8
+
9
+ it "should find stores by url" do
10
+ by_domain = Spree::Store.by_url('www.subdomain.com')
11
+
12
+ expect(by_domain).to include(store)
13
+ expect(by_domain).not_to include(store_2)
14
+ end
15
+ end
16
+
17
+ describe '.current' do
18
+ # there is a default store created with the test_app rake task.
19
+ let!(:store_1) { Spree::Store.first || create(:store) }
20
+
21
+ let!(:store_2) { create(:store, default: false, url: 'www.subdomain.com') }
22
+
23
+ it 'should return default when no domain' do
24
+ expect(subject.class.current).to eql(store_1)
25
+ end
26
+
27
+ it 'should return store for domain' do
28
+ expect(subject.class.current('spreecommerce.com')).to eql(store_1)
29
+ expect(subject.class.current('www.subdomain.com')).to eql(store_2)
30
+ end
31
+ end
32
+
33
+ describe ".default" do
34
+ let!(:store) { create(:store) }
35
+ let!(:store_2) { create(:store, default: true) }
36
+
37
+ it "should ensure there is a default if one doesn't exist yet" do
38
+ expect(store_2.default).to be true
39
+ end
40
+
41
+ it "should ensure there is only one default" do
42
+ [store, store_2].each(&:reload)
43
+
44
+ expect(Spree::Store.where(default: true).count).to eq(1)
45
+ expect(store_2.default).to be true
46
+ expect(store.default).not_to be true
47
+ end
48
+ end
49
+
50
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::TaxCategory, :type => :model do
4
+ context 'default tax category' do
5
+ let(:tax_category) { create(:tax_category) }
6
+ let(:new_tax_category) { create(:tax_category) }
7
+
8
+ before do
9
+ tax_category.update_column(:is_default, true)
10
+ end
11
+
12
+ it "should undefault the previous default tax category" do
13
+ new_tax_category.update_attributes({:is_default => true})
14
+ expect(new_tax_category.is_default).to be true
15
+
16
+ tax_category.reload
17
+ expect(tax_category.is_default).to be false
18
+ end
19
+
20
+ it "should undefault the previous default tax category except when updating the existing default tax category" do
21
+ tax_category.update_column(:description, "Updated description")
22
+
23
+ tax_category.reload
24
+ expect(tax_category.is_default).to be true
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,382 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::TaxRate, :type => :model do
4
+ context "match" do
5
+ let(:order) { create(:order) }
6
+ let(:country) { create(:country) }
7
+ let(:tax_category) { create(:tax_category) }
8
+ let(:calculator) { Spree::Calculator::FlatRate.new }
9
+
10
+ it "should return an empty array when tax_zone is nil" do
11
+ allow(order).to receive_messages :tax_zone => nil
12
+ expect(Spree::TaxRate.match(order.tax_zone)).to eq([])
13
+ end
14
+
15
+ context "when no rate zones match the tax zone" do
16
+ before do
17
+ Spree::TaxRate.create(:amount => 1, :zone => create(:zone))
18
+ end
19
+
20
+ context "when there is no default tax zone" do
21
+ before do
22
+ @zone = create(:zone, :name => "Country Zone", :default_tax => false, :zone_members => [])
23
+ @zone.zone_members.create(:zoneable => country)
24
+ end
25
+
26
+ it "should return an empty array" do
27
+ allow(order).to receive_messages :tax_zone => @zone
28
+ expect(Spree::TaxRate.match(order.tax_zone)).to eq([])
29
+ end
30
+
31
+ it "should return the rate that matches the rate zone" do
32
+ rate = Spree::TaxRate.create(
33
+ :amount => 1,
34
+ :zone => @zone,
35
+ :tax_category => tax_category,
36
+ :calculator => calculator
37
+ )
38
+
39
+ allow(order).to receive_messages :tax_zone => @zone
40
+ expect(Spree::TaxRate.match(order.tax_zone)).to eq([rate])
41
+ end
42
+
43
+ it "should return all rates that match the rate zone" do
44
+ rate1 = Spree::TaxRate.create(
45
+ :amount => 1,
46
+ :zone => @zone,
47
+ :tax_category => tax_category,
48
+ :calculator => calculator
49
+ )
50
+
51
+ rate2 = Spree::TaxRate.create(
52
+ :amount => 2,
53
+ :zone => @zone,
54
+ :tax_category => tax_category,
55
+ :calculator => Spree::Calculator::FlatRate.new
56
+ )
57
+
58
+ allow(order).to receive_messages :tax_zone => @zone
59
+ expect(Spree::TaxRate.match(order.tax_zone)).to match_array([rate1, rate2])
60
+ end
61
+
62
+ context "when the tax_zone is contained within a rate zone" do
63
+ before do
64
+ sub_zone = create(:zone, :name => "State Zone", :zone_members => [])
65
+ sub_zone.zone_members.create(:zoneable => create(:state, :country => country))
66
+ allow(order).to receive_messages :tax_zone => sub_zone
67
+ @rate = Spree::TaxRate.create(
68
+ :amount => 1,
69
+ :zone => @zone,
70
+ :tax_category => tax_category,
71
+ :calculator => calculator
72
+ )
73
+ end
74
+
75
+ it "should return the rate zone" do
76
+ expect(Spree::TaxRate.match(order.tax_zone)).to eq([@rate])
77
+ end
78
+ end
79
+ end
80
+
81
+ context "when there is a default tax zone" do
82
+ before do
83
+ @zone = create(:zone, :name => "Country Zone", :default_tax => true, :zone_members => [])
84
+ @zone.zone_members.create(:zoneable => country)
85
+ end
86
+
87
+ let(:included_in_price) { false }
88
+ let!(:rate) do
89
+ Spree::TaxRate.create(:amount => 1,
90
+ :zone => @zone,
91
+ :tax_category => tax_category,
92
+ :calculator => calculator,
93
+ :included_in_price => included_in_price)
94
+ end
95
+
96
+ subject { Spree::TaxRate.match(order.tax_zone) }
97
+
98
+ context "when the order has the same tax zone" do
99
+ before do
100
+ allow(order).to receive_messages :tax_zone => @zone
101
+ allow(order).to receive_messages :tax_address => tax_address
102
+ end
103
+
104
+ let(:tax_address) { stub_model(Spree::Address) }
105
+
106
+ context "when the tax is not a VAT" do
107
+ it { is_expected.to eq([rate]) }
108
+ end
109
+
110
+ context "when the tax is a VAT" do
111
+ let(:included_in_price) { true }
112
+ it { is_expected.to eq([rate]) }
113
+ end
114
+ end
115
+
116
+ context "when the order has a different tax zone" do
117
+ before do
118
+ allow(order).to receive_messages :tax_zone => create(:zone, :name => "Other Zone")
119
+ allow(order).to receive_messages :tax_address => tax_address
120
+ end
121
+
122
+ context "when the order has a tax_address" do
123
+ let(:tax_address) { stub_model(Spree::Address) }
124
+
125
+ context "when the tax is a VAT" do
126
+ let(:included_in_price) { true }
127
+ # The rate should match in this instance because:
128
+ # 1) It's the default rate (and as such, a negative adjustment should apply)
129
+ it { is_expected.to eq([rate]) }
130
+ end
131
+
132
+ context "when the tax is not VAT" do
133
+ it "returns no tax rate" do
134
+ expect(subject).to be_empty
135
+ end
136
+ end
137
+ end
138
+
139
+ context "when the order does not have a tax_address" do
140
+ let(:tax_address) { nil}
141
+
142
+ context "when the tax is a VAT" do
143
+ let(:included_in_price) { true }
144
+ # The rate should match in this instance because:
145
+ # 1) The order has no tax address by this stage
146
+ # 2) With no tax address, it has no tax zone
147
+ # 3) Therefore, we assume the default tax zone
148
+ # 4) This default zone has a default tax rate.
149
+ it { is_expected.to eq([rate]) }
150
+ end
151
+
152
+ context "when the tax is not a VAT" do
153
+ it { is_expected.to be_empty }
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
160
+
161
+ context ".adjust" do
162
+ let(:order) { stub_model(Spree::Order) }
163
+ let(:tax_category_1) { stub_model(Spree::TaxCategory) }
164
+ let(:tax_category_2) { stub_model(Spree::TaxCategory) }
165
+ let(:rate_1) { stub_model(Spree::TaxRate, :tax_category => tax_category_1) }
166
+ let(:rate_2) { stub_model(Spree::TaxRate, :tax_category => tax_category_2) }
167
+
168
+ context "with line items" do
169
+ let(:line_item) do
170
+ stub_model(Spree::LineItem,
171
+ :price => 10.0,
172
+ :quantity => 1,
173
+ :tax_category => tax_category_1,
174
+ :variant => stub_model(Spree::Variant)
175
+ )
176
+ end
177
+
178
+ let(:line_items) { [line_item] }
179
+
180
+ before do
181
+ allow(Spree::TaxRate).to receive_messages :match => [rate_1, rate_2]
182
+ end
183
+
184
+ it "should apply adjustments for two tax rates to the order" do
185
+ expect(rate_1).to receive(:adjust)
186
+ expect(rate_2).not_to receive(:adjust)
187
+ Spree::TaxRate.adjust(order, line_items)
188
+ end
189
+ end
190
+
191
+ context "with shipments" do
192
+ let(:shipments) { [stub_model(Spree::Shipment, :cost => 10.0, :tax_category => tax_category_1)] }
193
+
194
+ before do
195
+ allow(Spree::TaxRate).to receive_messages :match => [rate_1, rate_2]
196
+ end
197
+
198
+ it "should apply adjustments for two tax rates to the order" do
199
+ expect(rate_1).to receive(:adjust)
200
+ expect(rate_2).not_to receive(:adjust)
201
+ Spree::TaxRate.adjust(order, shipments)
202
+ end
203
+ end
204
+ end
205
+
206
+ context "#adjust" do
207
+ before do
208
+ @country = create(:country)
209
+ @zone = create(:zone, :name => "Country Zone", :default_tax => true, :zone_members => [])
210
+ @zone.zone_members.create(:zoneable => @country)
211
+ @category = Spree::TaxCategory.create :name => "Taxable Foo"
212
+ @category2 = Spree::TaxCategory.create(:name => "Non Taxable")
213
+ @rate1 = Spree::TaxRate.create(
214
+ :amount => 0.10,
215
+ :calculator => Spree::Calculator::DefaultTax.create,
216
+ :tax_category => @category,
217
+ :zone => @zone
218
+ )
219
+ @rate2 = Spree::TaxRate.create(
220
+ :amount => 0.05,
221
+ :calculator => Spree::Calculator::DefaultTax.create,
222
+ :tax_category => @category,
223
+ :zone => @zone
224
+ )
225
+ @order = Spree::Order.create!
226
+ @taxable = create(:product, :tax_category => @category)
227
+ @nontaxable = create(:product, :tax_category => @category2)
228
+ end
229
+
230
+ context "not taxable line item " do
231
+ let!(:line_item) { @order.contents.add(@nontaxable.master, 1) }
232
+
233
+ it "should not create a tax adjustment" do
234
+ Spree::TaxRate.adjust(@order, @order.line_items)
235
+ expect(line_item.adjustments.tax.charge.count).to eq(0)
236
+ end
237
+
238
+ it "should not create a refund" do
239
+ Spree::TaxRate.adjust(@order, @order.line_items)
240
+ expect(line_item.adjustments.credit.count).to eq(0)
241
+ end
242
+ end
243
+
244
+ context "taxable line item" do
245
+ let!(:line_item) { @order.contents.add(@taxable.master, 1) }
246
+
247
+ context "when price includes tax" do
248
+ before do
249
+ @rate1.update_column(:included_in_price, true)
250
+ @rate2.update_column(:included_in_price, true)
251
+ Spree::TaxRate.store_pre_tax_amount(line_item, [@rate1, @rate2])
252
+ end
253
+
254
+ context "when zone is contained by default tax zone" do
255
+ it "should create two adjustments, one for each tax rate" do
256
+ Spree::TaxRate.adjust(@order, @order.line_items)
257
+ expect(line_item.adjustments.count).to eq(1)
258
+ end
259
+
260
+ it "should not create a tax refund" do
261
+ Spree::TaxRate.adjust(@order, @order.line_items)
262
+ expect(line_item.adjustments.credit.count).to eq(0)
263
+ end
264
+ end
265
+
266
+ context "when order's zone is neither the default zone, or included in the default zone, but matches the rate's zone" do
267
+ before do
268
+ # With no zone members, this zone will not contain anything
269
+ # Previously:
270
+ # Zone.stub_chain :default_tax, :contains? => false
271
+ @zone.zone_members.delete_all
272
+ end
273
+ it "should create an adjustment" do
274
+ Spree::TaxRate.adjust(@order, @order.line_items)
275
+ expect(line_item.adjustments.charge.count).to eq(1)
276
+ end
277
+
278
+ it "should not create a tax refund for each tax rate" do
279
+ Spree::TaxRate.adjust(@order, @order.line_items)
280
+ expect(line_item.adjustments.credit.count).to eq(0)
281
+ end
282
+ end
283
+
284
+ context "when order's zone does not match default zone, is not included in the default zone, AND does not match the rate's zone" do
285
+ before do
286
+ @new_zone = create(:zone, :name => "New Zone", :default_tax => false)
287
+ @new_country = create(:country, :name => "New Country")
288
+ @new_zone.zone_members.create(:zoneable => @new_country)
289
+ @order.ship_address = create(:address, :country => @new_country)
290
+ @order.save
291
+ @order.reload
292
+ end
293
+
294
+ it "should not create positive adjustments" do
295
+ Spree::TaxRate.adjust(@order, @order.line_items)
296
+ expect(line_item.adjustments.charge.count).to eq(0)
297
+ end
298
+
299
+ it "should create a tax refund for each tax rate" do
300
+ Spree::TaxRate.adjust(@order, @order.line_items)
301
+ expect(line_item.adjustments.credit.count).to eq(1)
302
+ end
303
+ end
304
+
305
+ context "when price does not include tax" do
306
+ before do
307
+ allow(@order).to receive_messages :tax_zone => @zone
308
+ [@rate1, @rate2].each do |rate|
309
+ rate.included_in_price = false
310
+ rate.zone = @zone
311
+ rate.save
312
+ end
313
+ Spree::TaxRate.adjust(@order, @order.line_items)
314
+ end
315
+
316
+ it "should delete adjustments for open order when taxrate is deleted" do
317
+ @rate1.destroy!
318
+ @rate2.destroy!
319
+ expect(line_item.adjustments.count).to eq(0)
320
+ end
321
+
322
+ it "should not delete adjustments for complete order when taxrate is deleted" do
323
+ @order.update_column :completed_at, Time.now
324
+ @rate1.destroy!
325
+ @rate2.destroy!
326
+ expect(line_item.adjustments.count).to eq(2)
327
+ end
328
+
329
+ it "should create an adjustment" do
330
+ expect(line_item.adjustments.count).to eq(2)
331
+ end
332
+
333
+ it "should not create a tax refund" do
334
+ expect(line_item.adjustments.credit.count).to eq(0)
335
+ end
336
+
337
+ describe 'tax adjustments' do
338
+ before { Spree::TaxRate.adjust(@order, @order.line_items) }
339
+
340
+ it "should apply adjustments when a tax zone is present" do
341
+ expect(line_item.adjustments.count).to eq(2)
342
+ line_item.adjustments.each do |adjustment|
343
+ expect(adjustment.label).to eq("#{adjustment.source.tax_category.name} #{adjustment.source.amount * 100}%")
344
+ end
345
+ end
346
+
347
+ describe 'when the tax zone is removed' do
348
+ before { allow(@order).to receive_messages :tax_zone => nil }
349
+
350
+ it 'does not apply any adjustments' do
351
+ Spree::TaxRate.adjust(@order, @order.line_items)
352
+ expect(line_item.adjustments.count).to eq(0)
353
+ end
354
+ end
355
+ end
356
+ end
357
+
358
+ context "when two rates apply" do
359
+ before do
360
+ @price_before_taxes = line_item.price / (1 + @rate1.amount + @rate2.amount)
361
+ # Use the same rounding method as in DefaultTax calculator
362
+ @price_before_taxes = BigDecimal.new(@price_before_taxes).round(2, BigDecimal::ROUND_HALF_UP)
363
+ line_item.update_column(:pre_tax_amount, @price_before_taxes)
364
+ # Clear out any previously automatically-applied adjustments
365
+ @order.all_adjustments.delete_all
366
+ @rate1.adjust(@order, line_item)
367
+ @rate2.adjust(@order, line_item)
368
+ end
369
+
370
+ it "should create two price adjustments" do
371
+ expect(@order.line_item_adjustments.count).to eq(2)
372
+ end
373
+
374
+ it "price adjustments should be accurate" do
375
+ included_tax = @order.line_item_adjustments.sum(:amount)
376
+ expect(@price_before_taxes + included_tax).to eq(line_item.price)
377
+ end
378
+ end
379
+ end
380
+ end
381
+ end
382
+ end