solidus_core 1.0.2 → 1.0.3

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 (216) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -0
  3. data/Gemfile +3 -0
  4. data/Rakefile +16 -0
  5. data/script/rails +9 -0
  6. data/solidus_core.gemspec +48 -0
  7. data/spec/fixtures/thinking-cat.jpg +0 -0
  8. data/spec/helpers/base_helper_spec.rb +173 -0
  9. data/spec/helpers/order_helper_spec.rb +12 -0
  10. data/spec/helpers/products_helper_spec.rb +220 -0
  11. data/spec/helpers/taxons_helper_spec.rb +17 -0
  12. data/spec/lib/calculated_adjustments_spec.rb +7 -0
  13. data/spec/lib/i18n_spec.rb +123 -0
  14. data/spec/lib/search/base_spec.rb +86 -0
  15. data/spec/lib/search/variant_spec.rb +92 -0
  16. data/spec/lib/spree/core/controller_helpers/auth_spec.rb +66 -0
  17. data/spec/lib/spree/core/controller_helpers/order_spec.rb +92 -0
  18. data/spec/lib/spree/core/controller_helpers/search_spec.rb +17 -0
  19. data/spec/lib/spree/core/controller_helpers/store_spec.rb +16 -0
  20. data/spec/lib/spree/core/controller_helpers/strong_parameters_spec.rb +39 -0
  21. data/spec/lib/spree/core/current_store_spec.rb +36 -0
  22. data/spec/lib/spree/core/delegate_belongs_to_spec.rb +22 -0
  23. data/spec/lib/spree/core/importer/order_spec.rb +431 -0
  24. data/spec/lib/spree/core/role_configuration_spec.rb +138 -0
  25. data/spec/lib/spree/core/validators/email_spec.rb +48 -0
  26. data/spec/lib/spree/localized_number_spec.rb +38 -0
  27. data/spec/lib/spree/migrations_spec.rb +36 -0
  28. data/spec/lib/spree/money_spec.rb +127 -0
  29. data/spec/lib/tasks/exchanges_spec.rb +231 -0
  30. data/spec/lib/tasks/migrations/copy_shipped_shipments_to_cartons_spec.rb +115 -0
  31. data/spec/lib/tasks/order_capturing_spec.rb +56 -0
  32. data/spec/mailers/carton_mailer_spec.rb +43 -0
  33. data/spec/mailers/order_mailer_spec.rb +122 -0
  34. data/spec/mailers/reimbursement_mailer_spec.rb +40 -0
  35. data/spec/mailers/test_mailer_spec.rb +15 -0
  36. data/spec/models/spree/ability_spec.rb +276 -0
  37. data/spec/models/spree/address_spec.rb +250 -0
  38. data/spec/models/spree/adjustment_reason_spec.rb +13 -0
  39. data/spec/models/spree/adjustment_spec.rb +177 -0
  40. data/spec/models/spree/app_configuration_spec.rb +20 -0
  41. data/spec/models/spree/asset_spec.rb +24 -0
  42. data/spec/models/spree/calculator/default_tax_spec.rb +127 -0
  43. data/spec/models/spree/calculator/flat_percent_item_total_spec.rb +25 -0
  44. data/spec/models/spree/calculator/flat_rate_spec.rb +47 -0
  45. data/spec/models/spree/calculator/flexi_rate_spec.rb +41 -0
  46. data/spec/models/spree/calculator/percent_on_line_item_spec.rb +15 -0
  47. data/spec/models/spree/calculator/price_sack_spec.rb +30 -0
  48. data/spec/models/spree/calculator/refunds/default_refund_amount_spec.rb +51 -0
  49. data/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb +23 -0
  50. data/spec/models/spree/calculator/shipping/flat_rate_spec.rb +13 -0
  51. data/spec/models/spree/calculator/shipping/flexi_rate_spec.rb +52 -0
  52. data/spec/models/spree/calculator/shipping/per_item_spec.rb +20 -0
  53. data/spec/models/spree/calculator/shipping/price_sack_spec.rb +30 -0
  54. data/spec/models/spree/calculator/tiered_flat_rate_spec.rb +36 -0
  55. data/spec/models/spree/calculator/tiered_percent_spec.rb +47 -0
  56. data/spec/models/spree/calculator_spec.rb +36 -0
  57. data/spec/models/spree/carton_spec.rb +133 -0
  58. data/spec/models/spree/classification_spec.rb +15 -0
  59. data/spec/models/spree/concerns/display_money_spec.rb +43 -0
  60. data/spec/models/spree/concerns/user_methods_spec.rb +41 -0
  61. data/spec/models/spree/credit_card_spec.rb +334 -0
  62. data/spec/models/spree/customer_return_spec.rb +276 -0
  63. data/spec/models/spree/exchange_spec.rb +79 -0
  64. data/spec/models/spree/gateway/bogus_simple.rb +20 -0
  65. data/spec/models/spree/gateway/bogus_spec.rb +13 -0
  66. data/spec/models/spree/gateway_spec.rb +82 -0
  67. data/spec/models/spree/inventory_unit_spec.rb +307 -0
  68. data/spec/models/spree/item_adjustments_spec.rb +256 -0
  69. data/spec/models/spree/line_item_spec.rb +191 -0
  70. data/spec/models/spree/option_type_spec.rb +14 -0
  71. data/spec/models/spree/option_value_spec.rb +22 -0
  72. data/spec/models/spree/order/address_spec.rb +50 -0
  73. data/spec/models/spree/order/adjustments_spec.rb +39 -0
  74. data/spec/models/spree/order/callbacks_spec.rb +42 -0
  75. data/spec/models/spree/order/checkout_spec.rb +902 -0
  76. data/spec/models/spree/order/currency_updater_spec.rb +32 -0
  77. data/spec/models/spree/order/finalizing_spec.rb +111 -0
  78. data/spec/models/spree/order/payment_spec.rb +210 -0
  79. data/spec/models/spree/order/risk_assessment_spec.rb +68 -0
  80. data/spec/models/spree/order/state_machine_spec.rb +221 -0
  81. data/spec/models/spree/order/tax_spec.rb +84 -0
  82. data/spec/models/spree/order/totals_spec.rb +24 -0
  83. data/spec/models/spree/order/updating_spec.rb +18 -0
  84. data/spec/models/spree/order/validations_spec.rb +15 -0
  85. data/spec/models/spree/order_cancellations_spec.rb +120 -0
  86. data/spec/models/spree/order_capturing_spec.rb +116 -0
  87. data/spec/models/spree/order_contents_spec.rb +265 -0
  88. data/spec/models/spree/order_inventory_spec.rb +228 -0
  89. data/spec/models/spree/order_mutex_spec.rb +85 -0
  90. data/spec/models/spree/order_promotion_spec.rb +31 -0
  91. data/spec/models/spree/order_shipping_spec.rb +247 -0
  92. data/spec/models/spree/order_spec.rb +1412 -0
  93. data/spec/models/spree/order_stock_location_spec.rb +18 -0
  94. data/spec/models/spree/order_updater_spec.rb +299 -0
  95. data/spec/models/spree/payment_method/store_credit_spec.rb +294 -0
  96. data/spec/models/spree/payment_method_spec.rb +96 -0
  97. data/spec/models/spree/payment_spec.rb +1044 -0
  98. data/spec/models/spree/permission_sets/base_spec.rb +12 -0
  99. data/spec/models/spree/permission_sets/configuration_display.rb +82 -0
  100. data/spec/models/spree/permission_sets/configuration_management_spec.rb +50 -0
  101. data/spec/models/spree/permission_sets/dashboard_display_spec.rb +22 -0
  102. data/spec/models/spree/permission_sets/order_display_spec.rb +49 -0
  103. data/spec/models/spree/permission_sets/order_management_spec.rb +36 -0
  104. data/spec/models/spree/permission_sets/product_display_spec.rb +60 -0
  105. data/spec/models/spree/permission_sets/product_management_spec.rb +40 -0
  106. data/spec/models/spree/permission_sets/promotion_display_spec.rb +34 -0
  107. data/spec/models/spree/permission_sets/promotion_management_spec.rb +26 -0
  108. data/spec/models/spree/permission_sets/report_display_spec.rb +24 -0
  109. data/spec/models/spree/permission_sets/restricted_transfer_management_spec.rb +132 -0
  110. data/spec/models/spree/permission_sets/stock_display_spec.rb +26 -0
  111. data/spec/models/spree/permission_sets/stock_management_spec.rb +24 -0
  112. data/spec/models/spree/permission_sets/user_display_spec.rb +36 -0
  113. data/spec/models/spree/permission_sets/user_management_spec.rb +28 -0
  114. data/spec/models/spree/preference_spec.rb +80 -0
  115. data/spec/models/spree/preferences/configuration_spec.rb +30 -0
  116. data/spec/models/spree/preferences/preferable_spec.rb +294 -0
  117. data/spec/models/spree/preferences/scoped_store_spec.rb +58 -0
  118. data/spec/models/spree/preferences/static_model_preferences_spec.rb +78 -0
  119. data/spec/models/spree/preferences/statically_configurable_spec.rb +60 -0
  120. data/spec/models/spree/preferences/store_spec.rb +39 -0
  121. data/spec/models/spree/price_spec.rb +42 -0
  122. data/spec/models/spree/product/scopes_spec.rb +148 -0
  123. data/spec/models/spree/product_duplicator_spec.rb +103 -0
  124. data/spec/models/spree/product_filter_spec.rb +26 -0
  125. data/spec/models/spree/product_property_spec.rb +20 -0
  126. data/spec/models/spree/product_spec.rb +437 -0
  127. data/spec/models/spree/promotion/actions/create_adjustment_spec.rb +96 -0
  128. data/spec/models/spree/promotion/actions/create_item_adjustments_spec.rb +165 -0
  129. data/spec/models/spree/promotion/actions/create_quantity_adjustments_spec.rb +115 -0
  130. data/spec/models/spree/promotion/actions/free_shipping_spec.rb +40 -0
  131. data/spec/models/spree/promotion/rules/first_order_spec.rb +75 -0
  132. data/spec/models/spree/promotion/rules/item_total_spec.rb +67 -0
  133. data/spec/models/spree/promotion/rules/nth_order_spec.rb +70 -0
  134. data/spec/models/spree/promotion/rules/one_use_per_user_spec.rb +42 -0
  135. data/spec/models/spree/promotion/rules/option_value_spec.rb +94 -0
  136. data/spec/models/spree/promotion/rules/product_spec.rb +143 -0
  137. data/spec/models/spree/promotion/rules/taxon_spec.rb +102 -0
  138. data/spec/models/spree/promotion/rules/user_logged_in_spec.rb +27 -0
  139. data/spec/models/spree/promotion/rules/user_spec.rb +37 -0
  140. data/spec/models/spree/promotion_builder_spec.rb +118 -0
  141. data/spec/models/spree/promotion_category_spec.rb +17 -0
  142. data/spec/models/spree/promotion_code/code_builder_spec.rb +79 -0
  143. data/spec/models/spree/promotion_code_spec.rb +187 -0
  144. data/spec/models/spree/promotion_handler/cart_spec.rb +114 -0
  145. data/spec/models/spree/promotion_handler/coupon_spec.rb +335 -0
  146. data/spec/models/spree/promotion_handler/free_shipping_spec.rb +47 -0
  147. data/spec/models/spree/promotion_handler/page_spec.rb +44 -0
  148. data/spec/models/spree/promotion_rule_spec.rb +28 -0
  149. data/spec/models/spree/promotion_spec.rb +767 -0
  150. data/spec/models/spree/refund_spec.rb +204 -0
  151. data/spec/models/spree/reimbursement/credit_spec.rb +36 -0
  152. data/spec/models/spree/reimbursement/reimbursement_type_engine_spec.rb +140 -0
  153. data/spec/models/spree/reimbursement/reimbursement_type_validator_spec.rb +83 -0
  154. data/spec/models/spree/reimbursement_performer_spec.rb +30 -0
  155. data/spec/models/spree/reimbursement_spec.rb +231 -0
  156. data/spec/models/spree/reimbursement_tax_calculator_spec.rb +51 -0
  157. data/spec/models/spree/reimbursement_type/credit_spec.rb +53 -0
  158. data/spec/models/spree/reimbursement_type/exchange_spec.rb +46 -0
  159. data/spec/models/spree/reimbursement_type/original_payment_spec.rb +107 -0
  160. data/spec/models/spree/reimbursement_type/store_credit_spec.rb +97 -0
  161. data/spec/models/spree/return_authorization_spec.rb +290 -0
  162. data/spec/models/spree/return_item/eligibility_validator/default_spec.rb +77 -0
  163. data/spec/models/spree/return_item/eligibility_validator/inventory_shipped_spec.rb +58 -0
  164. data/spec/models/spree/return_item/eligibility_validator/no_reimbursements_spec.rb +85 -0
  165. data/spec/models/spree/return_item/eligibility_validator/order_completed_spec.rb +32 -0
  166. data/spec/models/spree/return_item/eligibility_validator/rma_required_spec.rb +29 -0
  167. data/spec/models/spree/return_item/eligibility_validator/time_since_purchase_spec.rb +35 -0
  168. data/spec/models/spree/return_item/exchange_variant_eligibility/same_option_value_spec.rb +65 -0
  169. data/spec/models/spree/return_item/exchange_variant_eligibility/same_product_spec.rb +43 -0
  170. data/spec/models/spree/return_item_spec.rb +775 -0
  171. data/spec/models/spree/returns_calculator_spec.rb +14 -0
  172. data/spec/models/spree/shipment_spec.rb +709 -0
  173. data/spec/models/spree/shipping_calculator_spec.rb +45 -0
  174. data/spec/models/spree/shipping_method_spec.rb +88 -0
  175. data/spec/models/spree/shipping_rate_spec.rb +142 -0
  176. data/spec/models/spree/state_spec.rb +14 -0
  177. data/spec/models/spree/stock/availability_validator_spec.rb +83 -0
  178. data/spec/models/spree/stock/coordinator_spec.rb +116 -0
  179. data/spec/models/spree/stock/differentiator_spec.rb +39 -0
  180. data/spec/models/spree/stock/estimator_spec.rb +146 -0
  181. data/spec/models/spree/stock/inventory_unit_builder_spec.rb +38 -0
  182. data/spec/models/spree/stock/package_spec.rb +163 -0
  183. data/spec/models/spree/stock/packer_spec.rb +91 -0
  184. data/spec/models/spree/stock/prioritizer_spec.rb +125 -0
  185. data/spec/models/spree/stock/quantifier_spec.rb +115 -0
  186. data/spec/models/spree/stock/splitter/backordered_spec.rb +29 -0
  187. data/spec/models/spree/stock/splitter/base_spec.rb +21 -0
  188. data/spec/models/spree/stock/splitter/shipping_category_spec.rb +50 -0
  189. data/spec/models/spree/stock/splitter/weight_spec.rb +29 -0
  190. data/spec/models/spree/stock_item_spec.rb +426 -0
  191. data/spec/models/spree/stock_location_spec.rb +279 -0
  192. data/spec/models/spree/stock_movement_spec.rb +56 -0
  193. data/spec/models/spree/stock_transfer_spec.rb +290 -0
  194. data/spec/models/spree/store_credit_category_spec.rb +17 -0
  195. data/spec/models/spree/store_credit_event_spec.rb +314 -0
  196. data/spec/models/spree/store_credit_spec.rb +876 -0
  197. data/spec/models/spree/store_spec.rb +55 -0
  198. data/spec/models/spree/tax_category_spec.rb +27 -0
  199. data/spec/models/spree/tax_rate_spec.rb +378 -0
  200. data/spec/models/spree/taxon_spec.rb +74 -0
  201. data/spec/models/spree/taxonomy_spec.rb +18 -0
  202. data/spec/models/spree/tracker_spec.rb +21 -0
  203. data/spec/models/spree/transfer_item_spec.rb +264 -0
  204. data/spec/models/spree/unit_cancel_spec.rb +148 -0
  205. data/spec/models/spree/user_spec.rb +223 -0
  206. data/spec/models/spree/validations/db_maximum_length_validator_spec.rb +23 -0
  207. data/spec/models/spree/variant/scopes_spec.rb +55 -0
  208. data/spec/models/spree/variant_spec.rb +546 -0
  209. data/spec/models/spree/zone_spec.rb +305 -0
  210. data/spec/spec_helper.rb +78 -0
  211. data/spec/support/big_decimal.rb +5 -0
  212. data/spec/support/concerns/default_price.rb +34 -0
  213. data/spec/support/dummy_ability.rb +4 -0
  214. data/spec/support/test_gateway.rb +2 -0
  215. metadata +229 -3
  216. data/lib/spree/testing_support/rspec-activemodel-mocks_patch.rb +0 -8
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ describe Spree::Order, :type => :model do
5
+ let(:order) { stub_model(Spree::Order) }
6
+
7
+ context "#tax_zone" do
8
+ let(:bill_address) { create :address }
9
+ let(:ship_address) { create :address }
10
+ let(:order) { Spree::Order.create(:ship_address => ship_address, :bill_address => bill_address) }
11
+ let(:zone) { create :zone }
12
+
13
+ context "when no zones exist" do
14
+ it "should return nil" do
15
+ expect(order.tax_zone).to be_nil
16
+ end
17
+ end
18
+
19
+ context "when :tax_using_ship_address => true" do
20
+ before { Spree::Config.set(:tax_using_ship_address => true) }
21
+
22
+ it "should calculate using ship_address" do
23
+ expect(Spree::Zone).to receive(:match).at_least(:once).with(ship_address)
24
+ expect(Spree::Zone).not_to receive(:match).with(bill_address)
25
+ order.tax_zone
26
+ end
27
+ end
28
+
29
+ context "when :tax_using_ship_address => false" do
30
+ before { Spree::Config.set(:tax_using_ship_address => false) }
31
+
32
+ it "should calculate using bill_address" do
33
+ expect(Spree::Zone).to receive(:match).at_least(:once).with(bill_address)
34
+ expect(Spree::Zone).not_to receive(:match).with(ship_address)
35
+ order.tax_zone
36
+ end
37
+ end
38
+
39
+ context "when there is a default tax zone" do
40
+ before do
41
+ @default_zone = create(:zone, :name => "foo_zone")
42
+ allow(Spree::Zone).to receive_messages :default_tax => @default_zone
43
+ end
44
+
45
+ context "when there is a matching zone" do
46
+ before { allow(Spree::Zone).to receive_messages(:match => zone) }
47
+
48
+ it "should return the matching zone" do
49
+ expect(order.tax_zone).to eq(zone)
50
+ end
51
+ end
52
+
53
+ context "when there is no matching zone" do
54
+ before { allow(Spree::Zone).to receive_messages(:match => nil) }
55
+
56
+ it "should return the default tax zone" do
57
+ expect(order.tax_zone).to eq(@default_zone)
58
+ end
59
+ end
60
+ end
61
+
62
+ context "when no default tax zone" do
63
+ before { allow(Spree::Zone).to receive_messages :default_tax => nil }
64
+
65
+ context "when there is a matching zone" do
66
+ before { allow(Spree::Zone).to receive_messages(:match => zone) }
67
+
68
+ it "should return the matching zone" do
69
+ expect(order.tax_zone).to eq(zone)
70
+ end
71
+ end
72
+
73
+ context "when there is no matching zone" do
74
+ before { allow(Spree::Zone).to receive_messages(:match => nil) }
75
+
76
+ it "should return nil" do
77
+ expect(order.tax_zone).to be_nil
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ describe Order, :type => :model do
5
+ let(:order) { Order.create }
6
+ let(:shirt) { create(:variant) }
7
+
8
+ context "adds item to cart and activates promo" do
9
+ let(:promotion) { Promotion.create name: 'Huhu' }
10
+ let(:calculator) { Calculator::FlatPercentItemTotal.new(:preferred_flat_percent => 10) }
11
+ let!(:action) { Promotion::Actions::CreateAdjustment.create(promotion: promotion, calculator: calculator) }
12
+
13
+ before { order.contents.add(shirt, 1) }
14
+
15
+ context "item quantity changes" do
16
+ it "recalculates order adjustments" do
17
+ expect {
18
+ order.contents.add(shirt, 3)
19
+ }.to change { order.adjustments.eligible.pluck(:amount) }
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::Order, :type => :model do
4
+ let(:order) { stub_model(Spree::Order) }
5
+
6
+ context "#update!" do
7
+ let(:line_items) { [mock_model(Spree::LineItem, :amount => 5) ]}
8
+
9
+ context "when there are update hooks" do
10
+ before { Spree::Order.register_update_hook :foo }
11
+ after { Spree::Order.update_hooks.clear }
12
+ it "should call each of the update hooks" do
13
+ expect(order).to receive :foo
14
+ order.update!
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ describe Spree::Order, :type => :model do
5
+ context "validations" do
6
+ # Regression test for #2214
7
+ it "does not return two error messages when email is blank" do
8
+ order = Spree::Order.new
9
+ allow(order).to receive_messages(:require_email => true)
10
+ order.valid?
11
+ expect(order.errors[:email]).to eq(["can't be blank"])
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,120 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::OrderCancellations do
4
+ describe "#short_ship" do
5
+ subject { Spree::OrderCancellations.new(order).short_ship([inventory_unit]) }
6
+
7
+ let(:order) { create(:order_ready_to_ship, line_items_count: 1) }
8
+ let(:inventory_unit) { order.inventory_units.first }
9
+ let(:shipment) { inventory_unit.shipment }
10
+
11
+ it "creates a UnitCancel record" do
12
+ expect { subject }.to change { Spree::UnitCancel.count }.by(1)
13
+
14
+ unit_cancel = Spree::UnitCancel.last
15
+ expect(unit_cancel.inventory_unit).to eq inventory_unit
16
+ expect(unit_cancel.reason).to eq Spree::UnitCancel::SHORT_SHIP
17
+ end
18
+
19
+ it "cancels the inventory unit" do
20
+ expect { subject }.to change { inventory_unit.state }.to "canceled"
21
+ end
22
+
23
+ it "updates the shipment.state" do
24
+ expect { subject }.to change { shipment.reload.state }.from('ready').to('shipped')
25
+ end
26
+
27
+ it "updates the order.shipment_state" do
28
+ expect { subject }.to change { order.shipment_state }.from('ready').to('shipped')
29
+ end
30
+
31
+ it "adjusts the order" do
32
+ expect { subject }.to change { order.total }.by(-10.0)
33
+ end
34
+
35
+ it "sends a cancellation email" do
36
+ mail_double = double
37
+ expect(Spree::OrderMailer).to receive(:inventory_cancellation_email).with(order, [inventory_unit]).and_return(mail_double)
38
+ expect(mail_double).to receive(:deliver_later)
39
+ subject
40
+ end
41
+
42
+ context "when send_cancellation_mailer is false" do
43
+ subject { Spree::OrderCancellations.new(order).short_ship([inventory_unit]) }
44
+
45
+ before do
46
+ @original_send_boolean = Spree::OrderCancellations.send_cancellation_mailer
47
+ Spree::OrderCancellations.send_cancellation_mailer = false
48
+ end
49
+
50
+ after { Spree::OrderCancellations.send_cancellation_mailer = @original_send_boolean }
51
+
52
+ it "does not send a cancellation email" do
53
+ expect(Spree::OrderMailer).not_to receive(:inventory_cancellation_email)
54
+ subject
55
+ end
56
+ end
57
+
58
+ context "with a who" do
59
+ subject { order.cancellations.short_ship([inventory_unit], whodunnit: 'some automated system') }
60
+
61
+ let(:user) { order.user }
62
+
63
+ it "sets the user on the UnitCancel" do
64
+ expect { subject }.to change { Spree::UnitCancel.count }.by(1)
65
+ expect(Spree::UnitCancel.last.created_by).to eq("some automated system")
66
+ end
67
+ end
68
+
69
+ context "when rounding is required" do
70
+ let(:order) { create(:order_ready_to_ship, line_items_count: 1, line_items_price: 0.83) }
71
+ let(:line_item) { order.line_items.first }
72
+ let(:inventory_unit_1) { line_item.inventory_units[0] }
73
+ let(:inventory_unit_2) { line_item.inventory_units[1] }
74
+
75
+ before do
76
+ order.contents.add(line_item.variant)
77
+ line_item.reload
78
+
79
+ # make the total $1.67 so it divides unevenly
80
+ Spree::Adjustment.tax.create!(
81
+ order: order,
82
+ adjustable: line_item,
83
+ amount: 0.01,
84
+ label: 'some fake tax',
85
+ state: 'closed',
86
+ )
87
+ order.update!
88
+ end
89
+
90
+ it "generates the correct total amount" do
91
+ order.cancellations.short_ship([inventory_unit_1])
92
+ order.cancellations.short_ship([inventory_unit_2])
93
+ expect(line_item.adjustments.non_tax.sum(:amount)).to eq -1.67
94
+ expect(line_item.total).to eq 0
95
+ end
96
+ end
97
+
98
+ describe 'short_ship_tax_notifier' do
99
+ context 'when present' do
100
+ let(:short_ship_tax_notifier) { double }
101
+
102
+ before do
103
+ @old_notifier = Spree::OrderCancellations.short_ship_tax_notifier
104
+ Spree::OrderCancellations.short_ship_tax_notifier = short_ship_tax_notifier
105
+ end
106
+ after do
107
+ Spree::OrderCancellations.short_ship_tax_notifier = @old_notifier
108
+ end
109
+
110
+ it 'calls the short_ship_tax_notifier' do
111
+ expect(short_ship_tax_notifier).to receive(:call) do |unit_cancels|
112
+ expect(unit_cancels.map(&:inventory_unit)).to match_array([inventory_unit])
113
+ end
114
+
115
+ order.cancellations.short_ship([inventory_unit])
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,116 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::OrderCapturing do
4
+ describe '#capture_payments' do
5
+ subject { Spree::OrderCapturing.new(order, payment_methods).capture_payments }
6
+
7
+ context "payment methods specified" do
8
+ let!(:order) { create(:order, ship_address: create(:address)) }
9
+
10
+ let!(:product) { create(:product, price: 10.00) }
11
+ let!(:variant) do
12
+ create(:variant, price: 10, product: product, track_inventory: false, tax_category: tax_rate.tax_category)
13
+ end
14
+ let!(:shipping_method) { create(:free_shipping_method) }
15
+ let(:tax_rate) { create(:tax_rate, amount: 0.1, zone: create(:global_zone, name: "Some Tax Zone")) }
16
+ let(:secondary_total) { 10.0 }
17
+ let(:bogus_total) { order.total }
18
+
19
+ before do
20
+ order.contents.add(variant, 3)
21
+ order.update!
22
+ @secondary_bogus_payment = create(:payment, order: order, amount: secondary_total, payment_method: secondary_payment_method.create!(name: 'So bogus', environment: 'test'))
23
+ @bogus_payment = create(:payment, order: order, amount: bogus_total)
24
+ order.contents.advance
25
+ order.complete!
26
+ order.reload
27
+ end
28
+
29
+ context "payment method ordering" do
30
+ let(:secondary_payment_method) { SecondaryBogusPaymentMethod }
31
+
32
+ class SecondaryBogusPaymentMethod < Spree::Gateway::Bogus; end
33
+
34
+ context "SecondaryBogusPaymentMethod payments are prioritized" do
35
+ let(:payment_methods) { [SecondaryBogusPaymentMethod, Spree::Gateway::Bogus] }
36
+
37
+ it "captures SecondaryBogusPaymentMethod payments first" do
38
+ subject
39
+ expect(@secondary_bogus_payment.reload.capture_events.sum(:amount)).to eq(10.0)
40
+ expect(@bogus_payment.reload.capture_events.sum(:amount)).to eq(order.total - 10.0)
41
+ end
42
+ end
43
+
44
+ context "Bogus payments are prioritized" do
45
+ let(:payment_methods) { [Spree::Gateway::Bogus, SecondaryBogusPaymentMethod] }
46
+
47
+ it "captures Bogus payments first" do
48
+ subject
49
+ expect(@secondary_bogus_payment.reload.capture_events.sum(:amount)).to eq(0.0)
50
+ expect(@bogus_payment.reload.capture_events.sum(:amount)).to eq(order.total)
51
+ end
52
+ end
53
+
54
+ context "when the payment method ordering is configured" do
55
+ subject { Spree::OrderCapturing.new(order, payment_methods).capture_payments }
56
+
57
+ let(:payment_methods) { nil }
58
+
59
+ before do
60
+ allow(Spree::OrderCapturing).to receive(:sorted_payment_method_classes).and_return(
61
+ [SecondaryBogusPaymentMethod, Spree::Gateway::Bogus]
62
+ )
63
+ end
64
+
65
+ it "captures in the order specified" do
66
+ subject
67
+ expect(@secondary_bogus_payment.reload.capture_events.sum(:amount)).to eq(10.0)
68
+ expect(@bogus_payment.reload.capture_events.sum(:amount)).to eq(order.total - 10.0)
69
+ end
70
+ end
71
+ end
72
+
73
+ context "when a payment is not needed to capture the entire order" do
74
+ let(:bogus_total) { order.total }
75
+ let(:secondary_payment_method) { SecondaryBogusPaymentMethod }
76
+ let(:payment_methods) { [Spree::Gateway::Bogus, SecondaryBogusPaymentMethod] }
77
+
78
+ context "when void_unused_payments is true" do
79
+ before { allow(Spree::OrderCapturing).to receive(:void_unused_payments).and_return(true) }
80
+
81
+ it "captures for the order and voids the unused payment" do
82
+ subject
83
+ expect(order.reload.payment_state).to eq 'paid'
84
+ expect(@secondary_bogus_payment.reload.state).to eq 'void'
85
+ end
86
+ end
87
+
88
+ context "when void_unused_payments is false" do
89
+ it "captures for the order and leaves the unused payment in a pending state" do
90
+ subject
91
+ expect(order.reload.payment_state).to eq 'paid'
92
+ expect(@secondary_bogus_payment.reload.state).to eq 'pending'
93
+ end
94
+ end
95
+ end
96
+
97
+ context "when there is an error processing a payment" do
98
+ let(:secondary_payment_method) { ExceptionallyBogusPaymentMethod }
99
+ let(:bogus_total) { order.total - 1 }
100
+ let(:secondary_total) { 1 }
101
+ let(:payment_methods) { [Spree::Gateway::Bogus, ExceptionallyBogusPaymentMethod] }
102
+
103
+ class ExceptionallyBogusPaymentMethod < Spree::Gateway::Bogus
104
+ def capture(*args)
105
+ raise ActiveMerchant::ConnectionError.new("foo", nil)
106
+ end
107
+ end
108
+
109
+ it "raises an error and leaves the order in a reasonable state" do
110
+ expect { subject }.to raise_error(Spree::Core::GatewayError)
111
+ expect(order.payments.to_a.sum(&:uncaptured_amount)).to eq 1.0
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,265 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::OrderContents, :type => :model do
4
+ let(:order) { Spree::Order.create }
5
+ let(:variant) { create(:variant) }
6
+ let!(:stock_location) { variant.stock_locations.first }
7
+ let(:stock_location_2) { create(:stock_location) }
8
+
9
+ subject { described_class.new(order) }
10
+
11
+ context "#add" do
12
+ context 'given quantity is not explicitly provided' do
13
+ it 'should add one line item' do
14
+ line_item = subject.add(variant)
15
+ expect(line_item.quantity).to eq(1)
16
+ expect(order.line_items.size).to eq(1)
17
+ end
18
+ end
19
+
20
+ context 'given a shipment' do
21
+ it "ensure shipment calls update_amounts instead of order calling ensure_updated_shipments" do
22
+ shipment = create(:shipment)
23
+ expect(subject.order).to_not receive(:ensure_updated_shipments)
24
+ expect(shipment).to receive(:update_amounts)
25
+ subject.add(variant, 1, shipment: shipment)
26
+ end
27
+ end
28
+
29
+ context 'not given a shipment' do
30
+ it "ensures updated shipments" do
31
+ expect(subject.order).to receive(:ensure_updated_shipments)
32
+ subject.add(variant)
33
+ end
34
+ end
35
+
36
+ it 'should add line item if one does not exist' do
37
+ line_item = subject.add(variant, 1)
38
+ expect(line_item.quantity).to eq(1)
39
+ expect(order.line_items.size).to eq(1)
40
+ end
41
+
42
+ it 'should update line item if one exists' do
43
+ subject.add(variant, 1)
44
+ line_item = subject.add(variant, 1)
45
+ expect(line_item.quantity).to eq(2)
46
+ expect(order.line_items.size).to eq(1)
47
+ end
48
+
49
+ it "should update order totals" do
50
+ expect(order.item_total.to_f).to eq(0.00)
51
+ expect(order.total.to_f).to eq(0.00)
52
+
53
+ subject.add(variant, 1)
54
+
55
+ expect(order.item_total.to_f).to eq(19.99)
56
+ expect(order.total.to_f).to eq(19.99)
57
+ end
58
+
59
+ it "should create stock location associations if provided" do
60
+ line_item = subject.add(variant, 3, stock_location_quantities: {stock_location.id => 1, stock_location_2.id => 2})
61
+ order_stock_locations = line_item.order.order_stock_locations
62
+ expect(order_stock_locations.count).to eq(2)
63
+ expect(order_stock_locations.map(&:quantity)).to eq([1, 2])
64
+ expect(order_stock_locations.map(&:stock_location_id)).to eq([stock_location.id, stock_location_2.id])
65
+ end
66
+
67
+ context "running promotions" do
68
+ let(:promotion) { create(:promotion) }
69
+ let(:calculator) { Spree::Calculator::FlatRate.new(:preferred_amount => 10) }
70
+
71
+ shared_context "discount changes order total" do
72
+ before { subject.add(variant, 1) }
73
+ it { expect(subject.order.total).not_to eq variant.price }
74
+ end
75
+
76
+ context "one active order promotion" do
77
+ let!(:action) { Spree::Promotion::Actions::CreateAdjustment.create(promotion: promotion, calculator: calculator) }
78
+
79
+ it "creates valid discount on order" do
80
+ subject.add(variant, 1)
81
+ expect(subject.order.adjustments.to_a.sum(&:amount)).not_to eq 0
82
+ end
83
+
84
+ include_context "discount changes order total"
85
+ end
86
+
87
+ context "one active line item promotion" do
88
+ let!(:action) { Spree::Promotion::Actions::CreateItemAdjustments.create(promotion: promotion, calculator: calculator) }
89
+
90
+ it "creates valid discount on order" do
91
+ subject.add(variant, 1)
92
+ expect(subject.order.line_item_adjustments.to_a.sum(&:amount)).not_to eq 0
93
+ end
94
+
95
+ include_context "discount changes order total"
96
+ end
97
+ end
98
+ end
99
+
100
+ context "#remove" do
101
+ context "given an invalid variant" do
102
+ it "raises an exception" do
103
+ expect {
104
+ subject.remove(variant, 1)
105
+ }.to raise_error(ActiveRecord::RecordNotFound)
106
+ end
107
+ end
108
+
109
+ context 'given quantity is not explicitly provided' do
110
+ it 'should remove one line item' do
111
+ line_item = subject.add(variant, 3)
112
+ subject.remove(variant)
113
+
114
+ expect(line_item.reload.quantity).to eq(2)
115
+ end
116
+ end
117
+
118
+ context 'given a shipment' do
119
+ it "ensure shipment calls update_amounts instead of order calling ensure_updated_shipments" do
120
+ line_item = subject.add(variant, 1)
121
+ shipment = create(:shipment)
122
+ expect(subject.order).to_not receive(:ensure_updated_shipments)
123
+ expect(shipment).to receive(:update_amounts)
124
+ subject.remove(variant, 1, shipment: shipment)
125
+ end
126
+ end
127
+
128
+ context 'not given a shipment' do
129
+ it "ensures updated shipments" do
130
+ line_item = subject.add(variant, 1)
131
+ expect(subject.order).to receive(:ensure_updated_shipments)
132
+ subject.remove(variant)
133
+ end
134
+ end
135
+
136
+ it 'should reduce line_item quantity if quantity is less the line_item quantity' do
137
+ line_item = subject.add(variant, 3)
138
+ subject.remove(variant, 1)
139
+
140
+ expect(line_item.reload.quantity).to eq(2)
141
+ end
142
+
143
+ it 'should remove line_item if quantity matches line_item quantity' do
144
+ subject.add(variant, 1)
145
+ subject.remove(variant, 1)
146
+
147
+ expect(order.reload.find_line_item_by_variant(variant)).to be_nil
148
+ end
149
+
150
+ it "should update order totals" do
151
+ expect(order.item_total.to_f).to eq(0.00)
152
+ expect(order.total.to_f).to eq(0.00)
153
+
154
+ subject.add(variant,2)
155
+
156
+ expect(order.item_total.to_f).to eq(39.98)
157
+ expect(order.total.to_f).to eq(39.98)
158
+
159
+ subject.remove(variant,1)
160
+ expect(order.item_total.to_f).to eq(19.99)
161
+ expect(order.total.to_f).to eq(19.99)
162
+ end
163
+ end
164
+
165
+ context "update cart" do
166
+ let!(:shirt) { subject.add variant, 1 }
167
+
168
+ let(:params) do
169
+ { line_items_attributes: {
170
+ "0" => { id: shirt.id, quantity: 3 }
171
+ } }
172
+ end
173
+
174
+ it "changes item quantity" do
175
+ subject.update_cart params
176
+ expect(shirt.reload.quantity).to eq 3
177
+ end
178
+
179
+ it "updates order totals" do
180
+ expect {
181
+ subject.update_cart params
182
+ }.to change { subject.order.total }
183
+ end
184
+
185
+ context "submits item quantity 0" do
186
+ let(:params) do
187
+ { line_items_attributes: {
188
+ "0" => { id: shirt.id, quantity: 0 },
189
+ } }
190
+ end
191
+
192
+ it "removes item from order" do
193
+ expect {
194
+ subject.update_cart params
195
+ }.to change { subject.order.line_items.count }
196
+ end
197
+ end
198
+
199
+ it "ensures updated shipments" do
200
+ expect(subject.order).to receive(:ensure_updated_shipments)
201
+ subject.update_cart params
202
+ end
203
+ end
204
+
205
+ context "completed order" do
206
+ let(:order) { Spree::Order.create! state: 'complete', completed_at: Time.now }
207
+
208
+ before { order.shipments.create! stock_location_id: variant.stock_location_ids.first }
209
+
210
+ it "updates order payment state" do
211
+ expect {
212
+ subject.add variant
213
+ }.to change { order.payment_state }
214
+
215
+ expect {
216
+ subject.remove variant
217
+ }.to change { order.payment_state }
218
+ end
219
+ end
220
+
221
+ describe "#approve" do
222
+ context 'when a name is supplied' do
223
+ it 'approves the order' do
224
+ order.contents.approve(name: 'Jordan')
225
+ expect(order.approver).to be_nil
226
+ expect(order.approver_name).to eq('Jordan')
227
+ expect(order.approved_at).to be_present
228
+ expect(order.approved?).to be_truthy
229
+ end
230
+ end
231
+
232
+ context 'when a user is supplied' do
233
+ let(:user) { create(:user) }
234
+
235
+ it 'approves the order' do
236
+ order.contents.approve(user: user)
237
+ expect(order.approver).to eq(user)
238
+ expect(order.approver_name).to be_nil
239
+ expect(order.approved_at).to be_present
240
+ expect(order.approved?).to be_truthy
241
+ end
242
+ end
243
+
244
+ context 'when a user and a name are supplied' do
245
+ let(:user) { create(:user) }
246
+
247
+ it 'approves the order' do
248
+ order.contents.approve(user: user, name: 'Jordan')
249
+ expect(order.approver).to eq(user)
250
+ expect(order.approver_name).to eq('Jordan')
251
+ expect(order.approved_at).to be_present
252
+ expect(order.approved?).to be_truthy
253
+ end
254
+ end
255
+
256
+ context 'when neither a user nor a name are supplied' do
257
+ it 'raises' do
258
+ expect {
259
+ order.contents.approve
260
+ }.to raise_error(ArgumentError, 'user or name must be specified')
261
+ end
262
+ end
263
+ end
264
+
265
+ end