solidus_core 1.1.0 → 1.1.1

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 (228) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -0
  3. data/Rakefile +16 -0
  4. data/script/rails +9 -0
  5. data/solidus_core.gemspec +48 -0
  6. data/spec/fixtures/thinking-cat.jpg +0 -0
  7. data/spec/helpers/base_helper_spec.rb +173 -0
  8. data/spec/helpers/order_helper_spec.rb +12 -0
  9. data/spec/helpers/products_helper_spec.rb +208 -0
  10. data/spec/helpers/taxons_helper_spec.rb +17 -0
  11. data/spec/lib/calculated_adjustments_spec.rb +7 -0
  12. data/spec/lib/i18n_spec.rb +106 -0
  13. data/spec/lib/search/base_spec.rb +86 -0
  14. data/spec/lib/search/variant_spec.rb +112 -0
  15. data/spec/lib/spree/core/controller_helpers/auth_spec.rb +66 -0
  16. data/spec/lib/spree/core/controller_helpers/order_spec.rb +92 -0
  17. data/spec/lib/spree/core/controller_helpers/payment_parameters_spec.rb +80 -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 +24 -0
  23. data/spec/lib/spree/core/importer/order_spec.rb +431 -0
  24. data/spec/lib/spree/core/role_configuration_spec.rb +156 -0
  25. data/spec/lib/spree/core/unreturned_item_charger_spec.rb +130 -0
  26. data/spec/lib/spree/core/validators/email_spec.rb +48 -0
  27. data/spec/lib/spree/localized_number_spec.rb +38 -0
  28. data/spec/lib/spree/migrations_spec.rb +36 -0
  29. data/spec/lib/spree/money_spec.rb +127 -0
  30. data/spec/lib/tasks/exchanges_spec.rb +231 -0
  31. data/spec/lib/tasks/migrations/copy_shipped_shipments_to_cartons_spec.rb +115 -0
  32. data/spec/lib/tasks/order_capturing_spec.rb +56 -0
  33. data/spec/mailers/carton_mailer_spec.rb +55 -0
  34. data/spec/mailers/order_mailer_spec.rb +135 -0
  35. data/spec/mailers/reimbursement_mailer_spec.rb +40 -0
  36. data/spec/mailers/test_mailer_spec.rb +15 -0
  37. data/spec/models/spree/ability_spec.rb +276 -0
  38. data/spec/models/spree/address_spec.rb +376 -0
  39. data/spec/models/spree/adjustment_reason_spec.rb +13 -0
  40. data/spec/models/spree/adjustment_spec.rb +169 -0
  41. data/spec/models/spree/app_configuration_spec.rb +24 -0
  42. data/spec/models/spree/asset_spec.rb +24 -0
  43. data/spec/models/spree/calculator/default_tax_spec.rb +127 -0
  44. data/spec/models/spree/calculator/flat_percent_item_total_spec.rb +25 -0
  45. data/spec/models/spree/calculator/flat_rate_spec.rb +47 -0
  46. data/spec/models/spree/calculator/flexi_rate_spec.rb +41 -0
  47. data/spec/models/spree/calculator/percent_on_line_item_spec.rb +15 -0
  48. data/spec/models/spree/calculator/price_sack_spec.rb +30 -0
  49. data/spec/models/spree/calculator/refunds/default_refund_amount_spec.rb +60 -0
  50. data/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb +23 -0
  51. data/spec/models/spree/calculator/shipping/flat_rate_spec.rb +13 -0
  52. data/spec/models/spree/calculator/shipping/flexi_rate_spec.rb +52 -0
  53. data/spec/models/spree/calculator/shipping/per_item_spec.rb +20 -0
  54. data/spec/models/spree/calculator/shipping/price_sack_spec.rb +30 -0
  55. data/spec/models/spree/calculator/tiered_flat_rate_spec.rb +36 -0
  56. data/spec/models/spree/calculator/tiered_percent_spec.rb +47 -0
  57. data/spec/models/spree/calculator_spec.rb +36 -0
  58. data/spec/models/spree/carton_spec.rb +133 -0
  59. data/spec/models/spree/classification_spec.rb +93 -0
  60. data/spec/models/spree/concerns/display_money_spec.rb +43 -0
  61. data/spec/models/spree/concerns/ordered_property_value_list_spec.rb +25 -0
  62. data/spec/models/spree/concerns/user_address_book_spec.rb +332 -0
  63. data/spec/models/spree/concerns/user_methods_spec.rb +41 -0
  64. data/spec/models/spree/credit_card_spec.rb +341 -0
  65. data/spec/models/spree/customer_return_spec.rb +276 -0
  66. data/spec/models/spree/exchange_spec.rb +79 -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 +104 -0
  70. data/spec/models/spree/inventory_unit_spec.rb +307 -0
  71. data/spec/models/spree/item_adjustments_spec.rb +275 -0
  72. data/spec/models/spree/line_item_spec.rb +199 -0
  73. data/spec/models/spree/option_type_spec.rb +14 -0
  74. data/spec/models/spree/option_value_spec.rb +45 -0
  75. data/spec/models/spree/order/address_spec.rb +50 -0
  76. data/spec/models/spree/order/adjustments_spec.rb +27 -0
  77. data/spec/models/spree/order/callbacks_spec.rb +42 -0
  78. data/spec/models/spree/order/checkout_spec.rb +884 -0
  79. data/spec/models/spree/order/currency_updater_spec.rb +32 -0
  80. data/spec/models/spree/order/finalizing_spec.rb +110 -0
  81. data/spec/models/spree/order/payment_spec.rb +243 -0
  82. data/spec/models/spree/order/risk_assessment_spec.rb +68 -0
  83. data/spec/models/spree/order/state_machine_spec.rb +209 -0
  84. data/spec/models/spree/order/tax_spec.rb +84 -0
  85. data/spec/models/spree/order/totals_spec.rb +24 -0
  86. data/spec/models/spree/order/updating_spec.rb +18 -0
  87. data/spec/models/spree/order/validations_spec.rb +15 -0
  88. data/spec/models/spree/order_cancellations_spec.rb +120 -0
  89. data/spec/models/spree/order_capturing_spec.rb +150 -0
  90. data/spec/models/spree/order_contents_spec.rb +307 -0
  91. data/spec/models/spree/order_inventory_spec.rb +228 -0
  92. data/spec/models/spree/order_mutex_spec.rb +85 -0
  93. data/spec/models/spree/order_promotion_spec.rb +31 -0
  94. data/spec/models/spree/order_shipping_spec.rb +241 -0
  95. data/spec/models/spree/order_spec.rb +1482 -0
  96. data/spec/models/spree/order_stock_location_spec.rb +18 -0
  97. data/spec/models/spree/order_updater_spec.rb +283 -0
  98. data/spec/models/spree/payment_method/store_credit_spec.rb +294 -0
  99. data/spec/models/spree/payment_method_spec.rb +147 -0
  100. data/spec/models/spree/payment_spec.rb +1087 -0
  101. data/spec/models/spree/permission_sets/base_spec.rb +12 -0
  102. data/spec/models/spree/permission_sets/configuration_display.rb +82 -0
  103. data/spec/models/spree/permission_sets/configuration_management_spec.rb +50 -0
  104. data/spec/models/spree/permission_sets/dashboard_display_spec.rb +22 -0
  105. data/spec/models/spree/permission_sets/order_display_spec.rb +55 -0
  106. data/spec/models/spree/permission_sets/order_management_spec.rb +42 -0
  107. data/spec/models/spree/permission_sets/product_display_spec.rb +60 -0
  108. data/spec/models/spree/permission_sets/product_management_spec.rb +40 -0
  109. data/spec/models/spree/permission_sets/promotion_display_spec.rb +40 -0
  110. data/spec/models/spree/permission_sets/promotion_management_spec.rb +26 -0
  111. data/spec/models/spree/permission_sets/report_display_spec.rb +24 -0
  112. data/spec/models/spree/permission_sets/restricted_stock_display_spec.rb +41 -0
  113. data/spec/models/spree/permission_sets/restricted_stock_management_spec.rb +41 -0
  114. data/spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb +50 -0
  115. data/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb +160 -0
  116. data/spec/models/spree/permission_sets/stock_display_spec.rb +24 -0
  117. data/spec/models/spree/permission_sets/stock_management_spec.rb +22 -0
  118. data/spec/models/spree/permission_sets/stock_transfer_display_spec.rb +24 -0
  119. data/spec/models/spree/permission_sets/stock_transfer_management_spec.rb +25 -0
  120. data/spec/models/spree/permission_sets/user_display_spec.rb +38 -0
  121. data/spec/models/spree/permission_sets/user_management_spec.rb +48 -0
  122. data/spec/models/spree/preference_spec.rb +80 -0
  123. data/spec/models/spree/preferences/configuration_spec.rb +30 -0
  124. data/spec/models/spree/preferences/preferable_spec.rb +294 -0
  125. data/spec/models/spree/preferences/scoped_store_spec.rb +60 -0
  126. data/spec/models/spree/preferences/static_model_preferences_spec.rb +78 -0
  127. data/spec/models/spree/preferences/statically_configurable_spec.rb +60 -0
  128. data/spec/models/spree/preferences/store_spec.rb +39 -0
  129. data/spec/models/spree/price_spec.rb +42 -0
  130. data/spec/models/spree/product/scopes_spec.rb +116 -0
  131. data/spec/models/spree/product_duplicator_spec.rb +103 -0
  132. data/spec/models/spree/product_filter_spec.rb +26 -0
  133. data/spec/models/spree/product_property_spec.rb +18 -0
  134. data/spec/models/spree/product_spec.rb +504 -0
  135. data/spec/models/spree/promotion/actions/create_adjustment_spec.rb +96 -0
  136. data/spec/models/spree/promotion/actions/create_item_adjustments_spec.rb +165 -0
  137. data/spec/models/spree/promotion/actions/create_quantity_adjustments_spec.rb +115 -0
  138. data/spec/models/spree/promotion/actions/free_shipping_spec.rb +40 -0
  139. data/spec/models/spree/promotion/rules/first_order_spec.rb +75 -0
  140. data/spec/models/spree/promotion/rules/first_repeat_purchase_since_spec.rb +69 -0
  141. data/spec/models/spree/promotion/rules/item_total_spec.rb +67 -0
  142. data/spec/models/spree/promotion/rules/nth_order_spec.rb +70 -0
  143. data/spec/models/spree/promotion/rules/one_use_per_user_spec.rb +42 -0
  144. data/spec/models/spree/promotion/rules/option_value_spec.rb +94 -0
  145. data/spec/models/spree/promotion/rules/product_spec.rb +143 -0
  146. data/spec/models/spree/promotion/rules/taxon_spec.rb +102 -0
  147. data/spec/models/spree/promotion/rules/user_logged_in_spec.rb +27 -0
  148. data/spec/models/spree/promotion/rules/user_spec.rb +37 -0
  149. data/spec/models/spree/promotion_builder_spec.rb +118 -0
  150. data/spec/models/spree/promotion_category_spec.rb +17 -0
  151. data/spec/models/spree/promotion_code/code_builder_spec.rb +79 -0
  152. data/spec/models/spree/promotion_code_spec.rb +187 -0
  153. data/spec/models/spree/promotion_handler/cart_spec.rb +130 -0
  154. data/spec/models/spree/promotion_handler/coupon_spec.rb +335 -0
  155. data/spec/models/spree/promotion_handler/free_shipping_spec.rb +47 -0
  156. data/spec/models/spree/promotion_handler/page_spec.rb +44 -0
  157. data/spec/models/spree/promotion_rule_spec.rb +28 -0
  158. data/spec/models/spree/promotion_spec.rb +776 -0
  159. data/spec/models/spree/refund_spec.rb +192 -0
  160. data/spec/models/spree/reimbursement/credit_spec.rb +36 -0
  161. data/spec/models/spree/reimbursement/reimbursement_type_engine_spec.rb +140 -0
  162. data/spec/models/spree/reimbursement/reimbursement_type_validator_spec.rb +83 -0
  163. data/spec/models/spree/reimbursement_performer_spec.rb +30 -0
  164. data/spec/models/spree/reimbursement_spec.rb +231 -0
  165. data/spec/models/spree/reimbursement_tax_calculator_spec.rb +51 -0
  166. data/spec/models/spree/reimbursement_type/credit_spec.rb +53 -0
  167. data/spec/models/spree/reimbursement_type/exchange_spec.rb +46 -0
  168. data/spec/models/spree/reimbursement_type/original_payment_spec.rb +107 -0
  169. data/spec/models/spree/reimbursement_type/store_credit_spec.rb +97 -0
  170. data/spec/models/spree/return_authorization_spec.rb +290 -0
  171. data/spec/models/spree/return_item/eligibility_validator/default_spec.rb +77 -0
  172. data/spec/models/spree/return_item/eligibility_validator/inventory_shipped_spec.rb +58 -0
  173. data/spec/models/spree/return_item/eligibility_validator/no_reimbursements_spec.rb +85 -0
  174. data/spec/models/spree/return_item/eligibility_validator/order_completed_spec.rb +32 -0
  175. data/spec/models/spree/return_item/eligibility_validator/rma_required_spec.rb +29 -0
  176. data/spec/models/spree/return_item/eligibility_validator/time_since_purchase_spec.rb +35 -0
  177. data/spec/models/spree/return_item/exchange_variant_eligibility/same_option_value_spec.rb +65 -0
  178. data/spec/models/spree/return_item/exchange_variant_eligibility/same_product_spec.rb +43 -0
  179. data/spec/models/spree/return_item_spec.rb +776 -0
  180. data/spec/models/spree/returns_calculator_spec.rb +14 -0
  181. data/spec/models/spree/shipment_spec.rb +753 -0
  182. data/spec/models/spree/shipping_calculator_spec.rb +45 -0
  183. data/spec/models/spree/shipping_manifest_spec.rb +94 -0
  184. data/spec/models/spree/shipping_method_spec.rb +88 -0
  185. data/spec/models/spree/shipping_rate_spec.rb +142 -0
  186. data/spec/models/spree/state_spec.rb +14 -0
  187. data/spec/models/spree/stock/availability_validator_spec.rb +83 -0
  188. data/spec/models/spree/stock/coordinator_spec.rb +116 -0
  189. data/spec/models/spree/stock/differentiator_spec.rb +39 -0
  190. data/spec/models/spree/stock/estimator_spec.rb +146 -0
  191. data/spec/models/spree/stock/inventory_unit_builder_spec.rb +38 -0
  192. data/spec/models/spree/stock/package_spec.rb +163 -0
  193. data/spec/models/spree/stock/packer_spec.rb +91 -0
  194. data/spec/models/spree/stock/prioritizer_spec.rb +125 -0
  195. data/spec/models/spree/stock/quantifier_spec.rb +115 -0
  196. data/spec/models/spree/stock/splitter/backordered_spec.rb +29 -0
  197. data/spec/models/spree/stock/splitter/base_spec.rb +21 -0
  198. data/spec/models/spree/stock/splitter/shipping_category_spec.rb +50 -0
  199. data/spec/models/spree/stock/splitter/weight_spec.rb +29 -0
  200. data/spec/models/spree/stock_item_spec.rb +444 -0
  201. data/spec/models/spree/stock_location_spec.rb +279 -0
  202. data/spec/models/spree/stock_movement_spec.rb +56 -0
  203. data/spec/models/spree/stock_transfer_spec.rb +290 -0
  204. data/spec/models/spree/store_credit_category_spec.rb +17 -0
  205. data/spec/models/spree/store_credit_event_spec.rb +314 -0
  206. data/spec/models/spree/store_credit_spec.rb +876 -0
  207. data/spec/models/spree/store_spec.rb +55 -0
  208. data/spec/models/spree/tax_category_spec.rb +27 -0
  209. data/spec/models/spree/tax_rate_spec.rb +378 -0
  210. data/spec/models/spree/taxon_spec.rb +74 -0
  211. data/spec/models/spree/taxonomy_spec.rb +18 -0
  212. data/spec/models/spree/tracker_spec.rb +21 -0
  213. data/spec/models/spree/transfer_item_spec.rb +264 -0
  214. data/spec/models/spree/unit_cancel_spec.rb +149 -0
  215. data/spec/models/spree/user_spec.rb +246 -0
  216. data/spec/models/spree/validations/db_maximum_length_validator_spec.rb +23 -0
  217. data/spec/models/spree/variant/scopes_spec.rb +55 -0
  218. data/spec/models/spree/variant_property_rule_condition_spec.rb +15 -0
  219. data/spec/models/spree/variant_property_rule_spec.rb +83 -0
  220. data/spec/models/spree/variant_property_rule_value_spec.rb +18 -0
  221. data/spec/models/spree/variant_spec.rb +601 -0
  222. data/spec/models/spree/zone_spec.rb +305 -0
  223. data/spec/spec_helper.rb +80 -0
  224. data/spec/support/big_decimal.rb +5 -0
  225. data/spec/support/concerns/default_price.rb +34 -0
  226. data/spec/support/dummy_ability.rb +4 -0
  227. data/spec/support/test_gateway.rb +2 -0
  228. metadata +242 -2
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::ReturnItem::EligibilityValidator::InventoryShipped do
4
+ let(:return_item) { create(:return_item) }
5
+ let(:validator) { Spree::ReturnItem::EligibilityValidator::InventoryShipped.new(return_item) }
6
+
7
+ describe "#eligible_for_return?" do
8
+ before { allow(return_item.inventory_unit).to receive(:shipped?).and_return(true) }
9
+
10
+ subject { validator.eligible_for_return? }
11
+
12
+ context "the associated inventory unit is shipped" do
13
+ it "returns true" do
14
+ expect(subject).to eq true
15
+ end
16
+ end
17
+
18
+ context "the associated inventory unit is not shipped" do
19
+ before { allow(return_item.inventory_unit).to receive(:shipped?).and_return(false) }
20
+
21
+ it "returns false" do
22
+ expect(subject).to eq false
23
+ end
24
+
25
+ it "sets an error" do
26
+ subject
27
+ expect(validator.errors[:inventory_unit_shipped]).to eq Spree.t('return_item_inventory_unit_ineligible')
28
+ end
29
+ end
30
+ end
31
+
32
+ describe "#requires_manual_intervention?" do
33
+ subject { validator.requires_manual_intervention? }
34
+
35
+ context "not eligible for return" do
36
+ before do
37
+ allow(return_item.inventory_unit).to receive(:shipped?).and_return(false)
38
+ validator.eligible_for_return?
39
+ end
40
+
41
+ it 'returns true if errors were added' do
42
+ expect(subject).to eq true
43
+ end
44
+ end
45
+
46
+ context "eligible for return" do
47
+ before do
48
+ allow(return_item.inventory_unit).to receive(:shipped?).and_return(true)
49
+ validator.eligible_for_return?
50
+ end
51
+
52
+ it 'returns false if no errors were added' do
53
+ expect(subject).to eq false
54
+ end
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::ReturnItem::EligibilityValidator::NoReimbursements do
4
+ let(:validator) { Spree::ReturnItem::EligibilityValidator::NoReimbursements.new(return_item) }
5
+
6
+ describe "#eligible_for_return?" do
7
+
8
+ subject { validator.eligible_for_return? }
9
+
10
+ context "inventory unit has already been reimbursed" do
11
+ let(:reimbursement) { create(:reimbursement) }
12
+ let(:return_item) { reimbursement.return_items.last }
13
+
14
+ it "returns false" do
15
+ expect(subject).to eq false
16
+ end
17
+
18
+ it "sets an error" do
19
+ subject
20
+ expect(validator.errors[:inventory_unit_reimbursed]).to eq Spree.t('return_item_inventory_unit_reimbursed')
21
+ end
22
+
23
+ context "but the return item has been expired" do
24
+ before { return_item.expired }
25
+
26
+ it "returns true" do
27
+ expect(subject).to eq true
28
+ end
29
+ end
30
+
31
+ context "but the return item has been canceled" do
32
+ before { return_item.cancel }
33
+
34
+ it "returns true" do
35
+ expect(subject).to eq true
36
+ end
37
+ end
38
+
39
+ context "but the return item has been unexchanged" do
40
+ before { return_item.unexchange }
41
+
42
+ it "returns true" do
43
+ expect(subject).to eq true
44
+ end
45
+ end
46
+ end
47
+
48
+ context "inventory unit has not been reimbursed" do
49
+ let(:return_item) { create(:return_item) }
50
+
51
+ it "returns true" do
52
+ expect(subject).to eq true
53
+ end
54
+ end
55
+ end
56
+
57
+ describe "#requires_manual_intervention?" do
58
+ subject { validator.requires_manual_intervention? }
59
+
60
+ context "not eligible for return" do
61
+ let(:reimbursement) { create(:reimbursement) }
62
+ let(:return_item) { reimbursement.return_items.last }
63
+
64
+ before do
65
+ validator.eligible_for_return?
66
+ end
67
+
68
+ it 'returns true if errors were added' do
69
+ expect(subject).to eq true
70
+ end
71
+ end
72
+
73
+ context "eligible for return" do
74
+ let(:return_item) { create(:return_item) }
75
+
76
+ before do
77
+ validator.eligible_for_return?
78
+ end
79
+
80
+ it 'returns false if no errors were added' do
81
+ expect(subject).to eq false
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::ReturnItem::EligibilityValidator::OrderCompleted do
4
+ let(:inventory_unit) { create(:inventory_unit, order: order) }
5
+ let(:return_item) { create(:return_item, inventory_unit: inventory_unit) }
6
+ let(:validator) { Spree::ReturnItem::EligibilityValidator::OrderCompleted.new(return_item) }
7
+
8
+ describe "#eligible_for_return?" do
9
+ subject { validator.eligible_for_return? }
10
+
11
+ context "the order was completed" do
12
+ let(:order) { create(:completed_order_with_totals) }
13
+
14
+ it "returns true" do
15
+ expect(subject).to be true
16
+ end
17
+ end
18
+
19
+ context "the order is not completed" do
20
+ let(:order) { create(:order) }
21
+
22
+ it "returns false" do
23
+ expect(subject).to be false
24
+ end
25
+
26
+ it "sets an error" do
27
+ subject
28
+ expect(validator.errors[:order_not_completed]).to eq Spree.t('return_item_order_not_completed')
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::ReturnItem::EligibilityValidator::RMARequired, :type => :model do
4
+ let(:return_item) { create(:return_item) }
5
+ let(:validator) { Spree::ReturnItem::EligibilityValidator::RMARequired.new(return_item) }
6
+
7
+ describe "#eligible_for_return?" do
8
+ subject { validator.eligible_for_return? }
9
+
10
+ context "there is an rma on the return item" do
11
+ it "returns true" do
12
+ expect(subject).to be true
13
+ end
14
+ end
15
+
16
+ context "there is no rma on the return item" do
17
+ before { allow(return_item).to receive(:return_authorization).and_return(nil) }
18
+
19
+ it "returns false" do
20
+ expect(subject).to be false
21
+ end
22
+
23
+ it "sets an error" do
24
+ subject
25
+ expect(validator.errors[:rma_required]).to eq Spree.t('return_item_rma_ineligible')
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::ReturnItem::EligibilityValidator::TimeSincePurchase, :type => :model do
4
+ let(:inventory_unit) { create(:inventory_unit, order: create(:shipped_order)) }
5
+ let(:return_item) { create(:return_item, inventory_unit: inventory_unit) }
6
+ let(:validator) { Spree::ReturnItem::EligibilityValidator::TimeSincePurchase.new(return_item) }
7
+
8
+ describe "#eligible_for_return?" do
9
+ subject { validator.eligible_for_return? }
10
+
11
+ context "it is within the return timeframe" do
12
+ it "returns true" do
13
+ completed_at = return_item.inventory_unit.order.completed_at - (Spree::Config[:return_eligibility_number_of_days].days / 2)
14
+ return_item.inventory_unit.order.update_attributes(completed_at: completed_at)
15
+ expect(subject).to be true
16
+ end
17
+ end
18
+
19
+ context "it is past the return timeframe" do
20
+ before do
21
+ completed_at = return_item.inventory_unit.order.completed_at - Spree::Config[:return_eligibility_number_of_days].days - 1.day
22
+ return_item.inventory_unit.order.update_attributes(completed_at: completed_at)
23
+ end
24
+
25
+ it "returns false" do
26
+ expect(subject).to be false
27
+ end
28
+
29
+ it "sets an error" do
30
+ subject
31
+ expect(validator.errors[:number_of_days]).to eq Spree.t('return_item_time_period_ineligible')
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ module ReturnItem::ExchangeVariantEligibility
5
+ describe SameOptionValue, :type => :model do
6
+ describe ".eligible_variants" do
7
+ let(:color_option_type) { create(:option_type, name: "color") }
8
+ let(:waist_option_type) { create(:option_type, name: "waist") }
9
+ let(:inseam_option_type) { create(:option_type, name: "inseam") }
10
+
11
+ let(:blue_option_value) { create(:option_value, name: "blue", option_type: color_option_type) }
12
+ let(:red_option_value) { create(:option_value, name: "red", option_type: color_option_type) }
13
+
14
+ let(:three_two_waist_option_value) { create(:option_value, name: 32, option_type: waist_option_type) }
15
+ let(:three_four_waist_option_value) { create(:option_value, name: 34, option_type: waist_option_type) }
16
+
17
+ let(:three_zero_inseam_option_value) { create(:option_value, name: 30, option_type: inseam_option_type) }
18
+ let(:three_one_inseam_option_value) { create(:option_value, name: 31, option_type: inseam_option_type) }
19
+
20
+ let(:product) { create(:product, option_types: [color_option_type, waist_option_type, inseam_option_type]) }
21
+
22
+ let!(:variant) { create(:variant, product: product, option_values: [blue_option_value, three_two_waist_option_value, three_zero_inseam_option_value]) }
23
+ let!(:same_option_values_variant) { create(:variant, product: product, option_values: [blue_option_value, three_two_waist_option_value, three_one_inseam_option_value]) }
24
+ let!(:different_color_option_value_variant) { create(:variant, product: product, option_values: [red_option_value, three_two_waist_option_value, three_one_inseam_option_value]) }
25
+ let!(:different_waist_option_value_variant) { create(:variant, product: product, option_values: [blue_option_value, three_four_waist_option_value, three_one_inseam_option_value]) }
26
+
27
+ before do
28
+ @original_option_type_restrictions = SameOptionValue.option_type_restrictions
29
+ SameOptionValue.option_type_restrictions = ["color", "waist"]
30
+ end
31
+
32
+ after { SameOptionValue.option_type_restrictions = @original_option_type_restrictions }
33
+
34
+ subject { SameOptionValue.eligible_variants(variant.reload) }
35
+
36
+ it "returns all other variants for the same product with the same option value for the specified option type" do
37
+ Spree::StockItem.update_all(count_on_hand: 10)
38
+
39
+ expect(subject.sort).to eq [variant, same_option_values_variant].sort
40
+ end
41
+
42
+ it "does not return variants for another product" do
43
+ other_product_variant = create(:variant)
44
+ expect(subject).not_to include other_product_variant
45
+ end
46
+
47
+ context "no option value restrictions are specified" do
48
+ before do
49
+ @original_option_type_restrictions = SameOptionValue.option_type_restrictions
50
+ SameOptionValue.option_type_restrictions = []
51
+ end
52
+
53
+ after { SameOptionValue.option_type_restrictions = @original_option_type_restrictions }
54
+
55
+ it "returns all variants for the product" do
56
+ Spree::StockItem.update_all(count_on_hand: 10)
57
+
58
+ expect(subject.sort).to eq [variant, same_option_values_variant, different_waist_option_value_variant, different_color_option_value_variant].sort
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ module ReturnItem::ExchangeVariantEligibility
5
+ describe SameProduct, :type => :model do
6
+ describe ".eligible_variants" do
7
+
8
+ context "product has no variants" do
9
+ it "returns the master variant for the same product" do
10
+ product = create(:product)
11
+ product.master.stock_items.first.update_column(:count_on_hand, 10)
12
+
13
+ expect(SameProduct.eligible_variants(product.master)).to eq [product.master]
14
+ end
15
+ end
16
+
17
+ context "product has variants" do
18
+ it "returns all variants for the same product" do
19
+ product = create(:product, variants: 3.times.map { create(:variant) })
20
+ product.variants.map { |v| v.stock_items.first.update_column(:count_on_hand, 10) }
21
+
22
+ expect(SameProduct.eligible_variants(product.variants.first).sort).to eq product.variants.sort
23
+ end
24
+ end
25
+
26
+ it "does not return variants for another product" do
27
+ variant = create(:variant)
28
+ other_product_variant = create(:variant)
29
+ expect(SameProduct.eligible_variants(variant)).not_to include other_product_variant
30
+ end
31
+
32
+ it "only returns variants that are on hand" do
33
+ product = create(:product, variants: 2.times.map { create(:variant) })
34
+ in_stock_variant = product.variants.first
35
+
36
+ in_stock_variant.stock_items.first.update_column(:count_on_hand, 10)
37
+ expect(SameProduct.eligible_variants(in_stock_variant)).to eq [in_stock_variant]
38
+ end
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,776 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples "an invalid state transition" do |status, expected_status|
4
+ let(:status) { status }
5
+
6
+ it "cannot transition to #{expected_status}" do
7
+ expect { subject }.to raise_error(StateMachines::InvalidTransition)
8
+ end
9
+ end
10
+
11
+ describe Spree::ReturnItem, :type => :model do
12
+
13
+ all_reception_statuses = Spree::ReturnItem.state_machines[:reception_status].states.map(&:name).map(&:to_s)
14
+ all_acceptance_statuses = Spree::ReturnItem.state_machines[:acceptance_status].states.map(&:name).map(&:to_s)
15
+
16
+ before do
17
+ allow_any_instance_of(Spree::Order).to receive(:return!).and_return(true)
18
+ end
19
+
20
+ describe '#receive!' do
21
+ let(:now) { Time.now }
22
+ let(:order) { create(:shipped_order)}
23
+ let(:inventory_unit) { create(:inventory_unit, order: order,state: 'shipped') }
24
+ let!(:customer_return) { create(:customer_return_without_return_items, return_items: [return_item], stock_location_id: inventory_unit.shipment.stock_location_id) }
25
+ let(:return_item) { create(:return_item, inventory_unit: inventory_unit) }
26
+
27
+ before do
28
+ inventory_unit.update_attributes!(state: 'shipped')
29
+ return_item.update_attributes!(reception_status: 'awaiting')
30
+ allow(return_item).to receive(:eligible_for_return?).and_return(true)
31
+ end
32
+
33
+ subject { return_item.receive! }
34
+
35
+ it 'returns the inventory unit' do
36
+ subject
37
+ expect(inventory_unit.reload.state).to eq 'returned'
38
+ end
39
+
40
+ it 'attempts to accept the return item' do
41
+ expect(return_item).to receive(:attempt_accept)
42
+ subject
43
+ end
44
+
45
+ context 'when there is a received return item with the same inventory unit' do
46
+ let!(:return_item_with_dupe_inventory_unit) { create(:return_item, inventory_unit: inventory_unit, reception_status: 'received') }
47
+
48
+ before do
49
+ assert_raises(StateMachines::InvalidTransition) { subject }
50
+ end
51
+
52
+ it 'does not receive the return item' do
53
+ expect(return_item.reception_status).to eq 'awaiting'
54
+ end
55
+
56
+ it 'adds an error to the return item' do
57
+ expect(return_item.errors[:inventory_unit]).to include "#{return_item.inventory_unit_id} has already been taken by return item #{return_item_with_dupe_inventory_unit.id}"
58
+ end
59
+ end
60
+
61
+ context 'when the received item is actually the exchange (aka customer changed mind about exchange)' do
62
+ let(:exchange_inventory_unit) { create(:inventory_unit, order: order,state: 'shipped') }
63
+ let!(:return_item_with_exchange) { create(:return_item, inventory_unit: inventory_unit, exchange_inventory_unit: exchange_inventory_unit) }
64
+ let!(:return_item_in_lieu) { create(:return_item, inventory_unit: exchange_inventory_unit)}
65
+
66
+ it 'unexchanges original return item' do
67
+ return_item_in_lieu.receive!
68
+
69
+ return_item_with_exchange.reload
70
+ return_item_in_lieu.reload
71
+ expect(return_item_with_exchange.reception_status).to eq 'unexchanged'
72
+ expect(return_item_in_lieu.reception_status).to eq 'received'
73
+ expect(return_item_in_lieu.pre_tax_amount).to eq 0
74
+ expect(inventory_unit.reload.state).to eq 'shipped'
75
+ expect(exchange_inventory_unit.reload.state).to eq 'returned'
76
+ end
77
+ end
78
+
79
+ context 'with a stock location' do
80
+ let(:stock_location) { customer_return.stock_location }
81
+ let(:stock_item) { stock_location.stock_item(inventory_unit.variant) }
82
+
83
+ before do
84
+ inventory_unit.update_attributes!(state: 'shipped')
85
+ return_item.update_attributes!(reception_status: 'awaiting')
86
+ stock_location.update_attributes!(restock_inventory: true)
87
+ end
88
+
89
+ it 'increases the count on hand' do
90
+ expect { subject }.to change { stock_item.reload.count_on_hand }.by(1)
91
+ end
92
+
93
+ context 'when variant does not track inventory' do
94
+ before do
95
+ inventory_unit.update_attributes!(state: 'shipped')
96
+ inventory_unit.variant.update_attributes!(track_inventory: false)
97
+ return_item.update_attributes!(reception_status: 'awaiting')
98
+ end
99
+
100
+ it 'does not increase the count on hand' do
101
+ expect { subject }.to_not change { stock_item.reload.count_on_hand }
102
+ end
103
+ end
104
+
105
+ context "when the stock location's restock_inventory is false" do
106
+ before do
107
+ stock_location.update_attributes!(restock_inventory: false)
108
+ end
109
+
110
+ it 'does not increase the count on hand' do
111
+ expect { subject }.to_not change { stock_item.reload.count_on_hand }
112
+ end
113
+ end
114
+
115
+ context "when the inventory unit's variant does not yet have a stock item for the stock location it was returned to" do
116
+ before { inventory_unit.variant.stock_items.destroy_all }
117
+
118
+ it "creates a new stock item for the inventory unit with a count of 1" do
119
+ expect { subject }.to change(Spree::StockItem, :count).by(1)
120
+ stock_item = Spree::StockItem.last
121
+ expect(stock_item.variant).to eq inventory_unit.variant
122
+ expect(stock_item.count_on_hand).to eq 1
123
+ end
124
+
125
+ end
126
+
127
+ Spree::ReturnItem::INTERMEDIATE_RECEPTION_STATUSES.each do |status|
128
+ context "when the item was #{status}" do
129
+ before { return_item.update_attributes!(reception_status: status) }
130
+
131
+ it 'processes the inventory unit' do
132
+ subject
133
+ expect(return_item.inventory_unit.reload.state).to eq('returned')
134
+ end
135
+
136
+ it 'return remains accepted' do
137
+ subject
138
+ expect(return_item.acceptance_status).to eq('accepted')
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
144
+
145
+
146
+ describe "#display_pre_tax_amount" do
147
+ let(:pre_tax_amount) { 21.22 }
148
+ let(:return_item) { build(:return_item, pre_tax_amount: pre_tax_amount) }
149
+
150
+ it "returns a Spree::Money" do
151
+ expect(return_item.display_pre_tax_amount).to eq Spree::Money.new(pre_tax_amount)
152
+ end
153
+ end
154
+
155
+ describe ".default_refund_amount_calculator" do
156
+ it "defaults to the default refund amount calculator" do
157
+ expect(Spree::ReturnItem.refund_amount_calculator).to eq Spree::Calculator::Returns::DefaultRefundAmount
158
+ end
159
+ end
160
+
161
+ describe "pre_tax_amount calculations on create" do
162
+ let(:inventory_unit) { build(:inventory_unit) }
163
+ before { subject.save! }
164
+
165
+ context "pre tax amount is not specified" do
166
+ subject { build(:return_item, inventory_unit: inventory_unit) }
167
+
168
+ context "not an exchange" do
169
+ it { expect(subject.pre_tax_amount).to eq Spree::Calculator::Returns::DefaultRefundAmount.new.compute(subject) }
170
+ end
171
+
172
+ context "an exchange" do
173
+ subject { build(:exchange_return_item) }
174
+
175
+ it { expect(subject.pre_tax_amount).to eq 0.0 }
176
+ end
177
+ end
178
+
179
+ context "pre tax amount is specified" do
180
+ subject { build(:return_item, inventory_unit: inventory_unit, pre_tax_amount: 100) }
181
+
182
+ it { expect(subject.pre_tax_amount).to eq 100 }
183
+ end
184
+ end
185
+
186
+ describe ".from_inventory_unit" do
187
+ let(:inventory_unit) { build(:inventory_unit) }
188
+
189
+ subject { Spree::ReturnItem.from_inventory_unit(inventory_unit) }
190
+
191
+ context "with a cancelled return item" do
192
+ let!(:return_item) { create(:return_item, inventory_unit: inventory_unit, reception_status: 'cancelled') }
193
+
194
+ it { is_expected.not_to be_persisted }
195
+ end
196
+
197
+ context 'with a expired item' do
198
+ let!(:return_item) { create(:return_item, inventory_unit: inventory_unit, reception_status: 'expired') }
199
+
200
+ it { is_expected.not_to be_persisted }
201
+ end
202
+
203
+ context "with a non-cancelled return item" do
204
+ let!(:return_item) { create(:return_item, inventory_unit: inventory_unit) }
205
+
206
+ it { is_expected.to be_persisted }
207
+ end
208
+ end
209
+
210
+ describe "reception_status state_machine" do
211
+ subject(:return_item) { create(:return_item) }
212
+
213
+ it "starts off in the awaiting state" do
214
+ expect(return_item).to be_awaiting
215
+ end
216
+ end
217
+
218
+ describe "acceptance_status state_machine" do
219
+ subject(:return_item) { create(:return_item) }
220
+
221
+ it "starts off in the pending state" do
222
+ expect(return_item).to be_pending
223
+ end
224
+ end
225
+
226
+ describe "#receive" do
227
+ let(:inventory_unit) { create(:inventory_unit, order: create(:shipped_order)) }
228
+ let(:return_item) { create(:return_item, reception_status: status, inventory_unit: inventory_unit) }
229
+
230
+ subject { return_item.receive! }
231
+
232
+ context "awaiting status" do
233
+ let(:status) { 'awaiting' }
234
+
235
+ before do
236
+ expect(return_item.inventory_unit).to receive(:return!)
237
+ end
238
+
239
+ before { subject }
240
+
241
+ it "transitions successfully" do
242
+ expect(return_item).to be_received
243
+ end
244
+ end
245
+
246
+ context "return_item has a reception status of cancelled" do
247
+ it_behaves_like "an invalid state transition", 'cancelled', 'received'
248
+ end
249
+ end
250
+
251
+ describe "#cancel" do
252
+ let(:return_item) { create(:return_item, reception_status: status) }
253
+
254
+ subject { return_item.cancel! }
255
+
256
+ context "awaiting status" do
257
+ let(:status) { 'awaiting' }
258
+
259
+ before { subject }
260
+
261
+ it "transitions successfully" do
262
+ expect(return_item).to be_cancelled
263
+ end
264
+ end
265
+
266
+ (all_reception_statuses - ['awaiting']).each do |invalid_transition_status|
267
+ context "return_item has a reception status of #{invalid_transition_status}" do
268
+ it_behaves_like "an invalid state transition", invalid_transition_status, 'cancelled'
269
+ end
270
+ end
271
+ end
272
+
273
+ {
274
+ give: 'given_to_customer',
275
+ lost: 'lost_in_transit',
276
+ wrong_item_shipped: 'shipped_wrong_item',
277
+ in_transit: 'in_transit',
278
+ short_shipped: 'short_shipped'
279
+ }.each do |transition, status|
280
+ describe "##{transition}" do
281
+ let(:return_item) { create(:return_item, reception_status: status, inventory_unit: inventory_unit) }
282
+ let(:inventory_unit) { create(:inventory_unit, state: 'shipped') }
283
+ subject { return_item.public_send("#{transition}!") }
284
+ context "awaiting status" do
285
+ before do
286
+ return_item.update_attributes!(reception_status: 'awaiting')
287
+ allow(return_item).to receive(:eligible_for_return?).and_return(true)
288
+ end
289
+
290
+ it 'accepts the return' do
291
+ subject
292
+ expect(return_item.acceptance_status).to eq('accepted')
293
+ end
294
+
295
+ it 'does not decrease inventory' do
296
+ expect(return_item).to_not receive(:process_inventory_unit)
297
+ subject
298
+ end
299
+
300
+ it "transitions successfully" do
301
+ subject
302
+ expect(return_item.reception_status).to eq status
303
+ end
304
+ end
305
+
306
+ it_behaves_like "an invalid state transition", 'cancelled', status
307
+ end
308
+ end
309
+
310
+ describe "#attempt_accept" do
311
+ let(:return_item) { create(:return_item, acceptance_status: status) }
312
+ let(:validator_errors) { {} }
313
+ let(:validator_double) { double(errors: validator_errors) }
314
+
315
+ subject { return_item.attempt_accept! }
316
+
317
+ before do
318
+ allow(return_item).to receive(:validator).and_return(validator_double)
319
+ end
320
+
321
+ context "pending status" do
322
+ let(:status) { 'pending' }
323
+
324
+ before do
325
+ allow(return_item).to receive(:eligible_for_return?).and_return(true)
326
+ subject
327
+ end
328
+
329
+ it "transitions successfully" do
330
+ expect(return_item).to be_accepted
331
+ end
332
+
333
+ it "has no acceptance status errors" do
334
+ expect(return_item.acceptance_status_errors).to be_empty
335
+ end
336
+ end
337
+
338
+ (all_acceptance_statuses - ['accepted', 'pending']).each do |invalid_transition_status|
339
+ context "return_item has an acceptance status of #{invalid_transition_status}" do
340
+ it_behaves_like "an invalid state transition", invalid_transition_status, 'accepted'
341
+ end
342
+ end
343
+
344
+ context "not eligible for return" do
345
+ let(:status) { 'pending' }
346
+ let(:validator_errors) { { number_of_days: "Return Item is outside the eligible time period" } }
347
+
348
+ before do
349
+ allow(return_item).to receive(:eligible_for_return?).and_return(false)
350
+ end
351
+
352
+ context "manual intervention required" do
353
+ before do
354
+ allow(return_item).to receive(:requires_manual_intervention?).and_return(true)
355
+ subject
356
+ end
357
+
358
+ it "transitions to manual intervention required" do
359
+ expect(return_item).to be_manual_intervention_required
360
+ end
361
+
362
+ it "sets the acceptance status errors" do
363
+ expect(return_item.acceptance_status_errors).to eq validator_errors
364
+ end
365
+ end
366
+
367
+ context "manual intervention not required" do
368
+ before do
369
+ allow(return_item).to receive(:requires_manual_intervention?).and_return(false)
370
+ subject
371
+ end
372
+
373
+ it "transitions to rejected" do
374
+ expect(return_item).to be_rejected
375
+ end
376
+
377
+ it "sets the acceptance status errors" do
378
+ expect(return_item.acceptance_status_errors).to eq validator_errors
379
+ end
380
+ end
381
+ end
382
+ end
383
+
384
+ describe "#reject" do
385
+ let(:return_item) { create(:return_item, acceptance_status: status) }
386
+
387
+ subject { return_item.reject! }
388
+
389
+ context "pending status" do
390
+ let(:status) { 'pending' }
391
+
392
+ before { subject }
393
+
394
+ it "transitions successfully" do
395
+ expect(return_item).to be_rejected
396
+ end
397
+
398
+ it "has no acceptance status errors" do
399
+ expect(return_item.acceptance_status_errors).to be_empty
400
+ end
401
+ end
402
+
403
+ (all_acceptance_statuses - ['accepted', 'pending', 'manual_intervention_required']).each do |invalid_transition_status|
404
+ context "return_item has an acceptance status of #{invalid_transition_status}" do
405
+ it_behaves_like "an invalid state transition", invalid_transition_status, 'rejected'
406
+ end
407
+ end
408
+ end
409
+
410
+ describe "#accept" do
411
+ let(:return_item) { create(:return_item, acceptance_status: status) }
412
+
413
+ subject { return_item.accept! }
414
+
415
+ context "pending status" do
416
+ let(:status) { 'pending' }
417
+
418
+ before { subject }
419
+
420
+ it "transitions successfully" do
421
+ expect(return_item).to be_accepted
422
+ end
423
+
424
+ it "has no acceptance status errors" do
425
+ expect(return_item.acceptance_status_errors).to be_empty
426
+ end
427
+ end
428
+
429
+ (all_acceptance_statuses - ['accepted', 'pending', 'manual_intervention_required']).each do |invalid_transition_status|
430
+ context "return_item has an acceptance status of #{invalid_transition_status}" do
431
+ it_behaves_like "an invalid state transition", invalid_transition_status, 'accepted'
432
+ end
433
+ end
434
+ end
435
+
436
+ describe "#require_manual_intervention" do
437
+ let(:return_item) { create(:return_item, acceptance_status: status) }
438
+
439
+ subject { return_item.require_manual_intervention! }
440
+
441
+ context "pending status" do
442
+ let(:status) { 'pending' }
443
+
444
+ before { subject }
445
+
446
+ it "transitions successfully" do
447
+ expect(return_item).to be_manual_intervention_required
448
+ end
449
+
450
+ it "has no acceptance status errors" do
451
+ expect(return_item.acceptance_status_errors).to be_empty
452
+ end
453
+ end
454
+
455
+ (all_acceptance_statuses - ['accepted', 'pending', 'manual_intervention_required']).each do |invalid_transition_status|
456
+ context "return_item has an acceptance status of #{invalid_transition_status}" do
457
+ it_behaves_like "an invalid state transition", invalid_transition_status, 'manual_intervention_required'
458
+ end
459
+ end
460
+ end
461
+
462
+ describe 'validity for reimbursements' do
463
+ let(:return_item) { create(:return_item, acceptance_status: acceptance_status) }
464
+ let(:acceptance_status) { 'pending' }
465
+
466
+ before { return_item.reimbursement = build(:reimbursement) }
467
+
468
+ subject { return_item }
469
+
470
+ context 'when acceptance_status is accepted' do
471
+ let(:acceptance_status) { 'accepted' }
472
+
473
+ it 'is valid' do
474
+ expect(subject).to be_valid
475
+ end
476
+ end
477
+
478
+ context 'when acceptance_status is accepted' do
479
+ let(:acceptance_status) { 'pending' }
480
+
481
+ it 'is valid' do
482
+ expect(subject).to_not be_valid
483
+ expect(subject.errors.messages).to eq({reimbursement: [I18n.t(:cannot_be_associated_unless_accepted, scope: 'activerecord.errors.models.spree/return_item.attributes.reimbursement')]})
484
+ end
485
+ end
486
+ end
487
+
488
+ describe "#part_of_exchange?" do
489
+ context "exchange variant exists, unexchanged sibling does not" do
490
+ before { allow(subject).to receive(:exchange_variant).and_return(mock_model(Spree::Variant)) }
491
+ it { expect(subject.part_of_exchange?).to eq true }
492
+ end
493
+ context "exchange variant does not exist, but unexchagned sibling does" do
494
+ before { expect(subject).to receive(:sibling_intended_for_exchange).with('unexchanged').and_return(true) }
495
+ it { expect(subject.part_of_exchange?).to eq true }
496
+ end
497
+ context "neither exchange variant nor unexchanged sibling exist" do
498
+ before { expect(subject).to receive(:sibling_intended_for_exchange).with('unexchanged').and_return(false) }
499
+ it { expect(subject.part_of_exchange?).to eq false }
500
+ end
501
+ end
502
+
503
+ describe "#exchange_requested?" do
504
+ context "exchange variant exists" do
505
+ before { allow(subject).to receive(:exchange_variant).and_return(mock_model(Spree::Variant)) }
506
+ it { expect(subject.exchange_requested?).to eq true }
507
+ end
508
+ context "exchange variant does not exist" do
509
+ before { allow(subject).to receive(:exchange_variant).and_return(nil) }
510
+ it { expect(subject.exchange_requested?).to eq false }
511
+ end
512
+ end
513
+
514
+ describe "#exchange_processed?" do
515
+ context "exchange inventory unit exists" do
516
+ before { allow(subject).to receive(:exchange_inventory_unit).and_return(mock_model(Spree::InventoryUnit)) }
517
+ it { expect(subject.exchange_processed?).to eq true }
518
+ end
519
+ context "exchange inventory unit does not exist" do
520
+ before { allow(subject).to receive(:exchange_inventory_unit).and_return(nil) }
521
+ it { expect(subject.exchange_processed?).to eq false }
522
+ end
523
+ end
524
+
525
+ describe "#exchange_required?" do
526
+ context "exchange has been requested and not yet processed" do
527
+ before do
528
+ allow(subject).to receive(:exchange_requested?).and_return(true)
529
+ allow(subject).to receive(:exchange_processed?).and_return(false)
530
+ end
531
+
532
+ it { expect(subject.exchange_required?).to be true }
533
+ end
534
+
535
+ context "exchange has not been requested" do
536
+ before { allow(subject).to receive(:exchange_requested?).and_return(false) }
537
+ it { expect(subject.exchange_required?).to be false }
538
+ end
539
+
540
+ context "exchange has been requested and processed" do
541
+ before do
542
+ allow(subject).to receive(:exchange_requested?).and_return(true)
543
+ allow(subject).to receive(:exchange_processed?).and_return(true)
544
+ end
545
+ it { expect(subject.exchange_required?).to be false }
546
+ end
547
+ end
548
+
549
+ describe "#eligible_exchange_variants" do
550
+ it "uses the exchange variant calculator to compute possible variants to exchange for" do
551
+ return_item = build(:return_item)
552
+ expect(Spree::ReturnItem.exchange_variant_engine).to receive(:eligible_variants).with(return_item.variant, stock_locations: nil)
553
+ return_item.eligible_exchange_variants
554
+ end
555
+ end
556
+
557
+ describe ".exchange_variant_engine" do
558
+ it "defaults to the same product calculator" do
559
+ expect(Spree::ReturnItem.exchange_variant_engine).to eq Spree::ReturnItem::ExchangeVariantEligibility::SameProduct
560
+ end
561
+ end
562
+
563
+ describe "exchange pre_tax_amount" do
564
+ let(:return_item) { build(:return_item) }
565
+
566
+ context "the return item is intended to be exchanged" do
567
+ before do
568
+ return_item.inventory_unit.variant.update_column(:track_inventory, false)
569
+ return_item.exchange_variant = return_item.inventory_unit.variant
570
+ end
571
+
572
+ it do
573
+ return_item.pre_tax_amount = 5.0
574
+ return_item.save!
575
+ expect(return_item.reload.pre_tax_amount).to eq 0.0
576
+ end
577
+ end
578
+
579
+ context "the return item is not intended to be exchanged" do
580
+ it do
581
+ return_item.pre_tax_amount = 5.0
582
+ return_item.save!
583
+ expect(return_item.reload.pre_tax_amount).to eq 5.0
584
+ end
585
+ end
586
+ end
587
+
588
+ describe "#build_exchange_inventory_unit" do
589
+ let(:return_item) { build(:return_item) }
590
+ subject { return_item.build_exchange_inventory_unit }
591
+
592
+ context "the return item is intended to be exchanged" do
593
+ before { allow(return_item).to receive(:exchange_variant).and_return(mock_model(Spree::Variant)) }
594
+
595
+ context "an exchange inventory unit already exists" do
596
+ before { allow(return_item).to receive(:exchange_inventory_unit).and_return(mock_model(Spree::InventoryUnit)) }
597
+ it { expect(subject).to be_nil }
598
+ end
599
+
600
+ context "no exchange inventory unit exists" do
601
+ it "builds a pending inventory unit with references to the return item, variant, and previous inventory unit" do
602
+ expect(subject.variant).to eq return_item.exchange_variant
603
+ expect(subject.pending).to eq true
604
+ expect(subject).not_to be_persisted
605
+ expect(subject.original_return_item).to eq return_item
606
+ expect(subject.line_item).to eq return_item.inventory_unit.line_item
607
+ expect(subject.order).to eq return_item.inventory_unit.order
608
+ end
609
+ end
610
+ end
611
+
612
+ context "the return item is not intended to be exchanged" do
613
+ it { expect(subject).to be_nil }
614
+ end
615
+ end
616
+
617
+ describe "#exchange_shipment" do
618
+ it "returns the exchange inventory unit's shipment" do
619
+ inventory_unit = build(:inventory_unit)
620
+ subject.exchange_inventory_unit = inventory_unit
621
+ expect(subject.exchange_shipment).to eq inventory_unit.shipment
622
+ end
623
+ end
624
+
625
+ describe "#shipment" do
626
+ it "returns the inventory unit's shipment" do
627
+ inventory_unit = build(:inventory_unit)
628
+ subject.inventory_unit = inventory_unit
629
+ expect(subject.shipment).to eq inventory_unit.shipment
630
+ end
631
+ end
632
+
633
+ describe 'inventory_unit uniqueness' do
634
+ let!(:old_return_item) { create(:return_item, reception_status: old_reception_status) }
635
+ let(:old_reception_status) { 'awaiting' }
636
+
637
+ subject do
638
+ build(:return_item, {
639
+ return_authorization: old_return_item.return_authorization,
640
+ inventory_unit: old_return_item.inventory_unit,
641
+ })
642
+ end
643
+
644
+ context 'with other awaiting return items exist for the same inventory unit' do
645
+ let(:old_reception_status) { 'awaiting' }
646
+
647
+ it 'cancels the others' do
648
+ expect {
649
+ subject.save!
650
+ }.to change { old_return_item.reload.reception_status }.from('awaiting').to('cancelled')
651
+ end
652
+
653
+ it 'does not cancel itself' do
654
+ subject.save!
655
+ expect(subject).to be_awaiting
656
+ end
657
+ end
658
+
659
+ context 'with other cancelled return items exist for the same inventory unit' do
660
+ let(:old_reception_status) { 'cancelled' }
661
+
662
+ it 'succeeds' do
663
+ expect { subject.save! }.to_not raise_error
664
+ end
665
+ end
666
+
667
+ context 'with other received return items exist for the same inventory unit' do
668
+ let(:old_reception_status) { 'received' }
669
+
670
+ it 'is invalid' do
671
+ expect(subject).to_not be_valid
672
+ expect(subject.errors.to_a).to eq ["Inventory unit #{subject.inventory_unit_id} has already been taken by return item #{old_return_item.id}"]
673
+ end
674
+ end
675
+
676
+ context 'with other given_to_customer return items exist for the same inventory unit' do
677
+ let(:old_reception_status) { 'given_to_customer' }
678
+
679
+ it 'is invalid' do
680
+ expect(subject).to_not be_valid
681
+ expect(subject.errors.to_a).to eq ["Inventory unit #{subject.inventory_unit_id} has already been taken by return item #{old_return_item.id}"]
682
+ end
683
+ end
684
+ end
685
+
686
+ describe "included tax in total" do
687
+ let(:inventory_unit) { create(:inventory_unit, state: 'shipped') }
688
+ let(:return_item) do
689
+ create(
690
+ :return_item,
691
+ inventory_unit: inventory_unit,
692
+ included_tax_total: 10
693
+ )
694
+ end
695
+
696
+ it 'includes included tax total' do
697
+ expect(return_item.pre_tax_amount).to eq 10
698
+ expect(return_item.included_tax_total).to eq 10
699
+ expect(return_item.total).to eq 20
700
+ end
701
+ end
702
+
703
+ describe "valid exchange variant" do
704
+ subject { return_item }
705
+
706
+ before { subject.save }
707
+
708
+ context "return item doesn't have an exchange variant" do
709
+ let(:return_item) { create(:return_item) }
710
+
711
+ it "is valid" do
712
+ expect(subject).to be_valid
713
+ end
714
+ end
715
+
716
+ context "return item has an exchange variant" do
717
+ let(:return_item) { create(:exchange_return_item) }
718
+ let(:exchange_variant) { create(:on_demand_variant, product: return_item.inventory_unit.variant.product) }
719
+
720
+ context "the exchange variant is eligible" do
721
+ before { return_item.exchange_variant = exchange_variant }
722
+
723
+ it "is valid" do
724
+ expect(subject).to be_valid
725
+ end
726
+ end
727
+
728
+ context "the exchange variant is not eligible" do
729
+ context "new return item" do
730
+ let(:return_item) { build(:return_item) }
731
+ let(:exchange_variant) { create(:variant, product: return_item.inventory_unit.variant.product) }
732
+
733
+ before { return_item.exchange_variant = exchange_variant }
734
+
735
+ it "is invalid" do
736
+ expect(subject).to_not be_valid
737
+ end
738
+
739
+ it "adds an error message about the invalid exchange variant" do
740
+ subject.valid?
741
+ expect(subject.errors.to_a).to eq ["Invalid exchange variant."]
742
+ end
743
+ end
744
+
745
+ context "the exchange variant has been updated" do
746
+ before do
747
+ other_variant = create(:variant)
748
+ return_item.exchange_variant_id = other_variant.id
749
+ subject.valid?
750
+ end
751
+
752
+ it "is invalid" do
753
+ expect(subject).to_not be_valid
754
+ end
755
+
756
+ it "adds an error message about the invalid exchange variant" do
757
+ expect(subject.errors.to_a).to eq ["Invalid exchange variant."]
758
+ end
759
+ end
760
+
761
+ context "the exchange variant has not been updated" do
762
+ before do
763
+ other_variant = create(:variant)
764
+ return_item.update_column(:exchange_variant_id, other_variant.id)
765
+ return_item.reload
766
+ subject.valid?
767
+ end
768
+
769
+ it "is valid" do
770
+ expect(subject).to be_valid
771
+ end
772
+ end
773
+ end
774
+ end
775
+ end
776
+ end