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,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::ReimbursementPerformer, :type => :model do
4
+ let(:reimbursement) { create(:reimbursement, return_items_count: 1) }
5
+ let(:return_item) { reimbursement.return_items.first }
6
+ let(:reimbursement_type) { double("ReimbursementType") }
7
+ let(:reimbursement_type_hash) { { reimbursement_type => [return_item]} }
8
+
9
+ before do
10
+ expect(Spree::ReimbursementPerformer).to receive(:calculate_reimbursement_types).and_return(reimbursement_type_hash)
11
+ end
12
+
13
+ describe ".simulate" do
14
+ subject { Spree::ReimbursementPerformer.simulate(reimbursement) }
15
+
16
+ it "reimburses each calculated reimbursement types with the correct return items as a simulation" do
17
+ expect(reimbursement_type).to receive(:reimburse).with(reimbursement, [return_item], true)
18
+ subject
19
+ end
20
+ end
21
+
22
+ describe '.perform' do
23
+ subject { Spree::ReimbursementPerformer.perform(reimbursement) }
24
+
25
+ it "reimburses each calculated reimbursement types with the correct return items as a simulation" do
26
+ expect(reimbursement_type).to receive(:reimburse).with(reimbursement, [return_item], false)
27
+ subject
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,231 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::Reimbursement, type: :model do
4
+
5
+ describe ".before_create" do
6
+ describe "#generate_number" do
7
+ context "number is assigned" do
8
+ let(:number) { '123' }
9
+ let(:reimbursement) { Spree::Reimbursement.new(number: number) }
10
+
11
+ it "should return the assigned number" do
12
+ reimbursement.save
13
+ expect(reimbursement.number).to eq number
14
+ end
15
+ end
16
+
17
+ context "number is not assigned" do
18
+ let(:reimbursement) { Spree::Reimbursement.new(number: nil) }
19
+
20
+ before do
21
+ allow(reimbursement).to receive_messages(valid?: true)
22
+ end
23
+
24
+ it "should assign number with random RI number" do
25
+ reimbursement.save
26
+ expect(reimbursement.number).to be =~ /RI\d{9}/
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ describe "#display_total" do
33
+ let(:total) { 100.50 }
34
+ let(:currency) { "USD" }
35
+ let(:order) { Spree::Order.new(currency: currency) }
36
+ let(:reimbursement) { Spree::Reimbursement.new(total: total, order: order) }
37
+
38
+ subject { reimbursement.display_total }
39
+
40
+ it "returns the value as a Spree::Money instance" do
41
+ expect(subject).to eq Spree::Money.new(total)
42
+ end
43
+
44
+ it "uses the order's currency" do
45
+ expect(subject.money.currency.to_s).to eq currency
46
+ end
47
+ end
48
+
49
+ describe "#perform!" do
50
+ let!(:adjustments) { [] } # placeholder to ensure it gets run prior the "before" at this level
51
+
52
+ let!(:tax_rate) { nil }
53
+ let!(:tax_zone) { create :zone, default_tax: true }
54
+ let(:shipping_method) { create :shipping_method, zones: [tax_zone] }
55
+ let(:variant) { create :variant }
56
+ let(:order) { create(:order_with_line_items, state: 'payment', line_items_attributes: [{variant: variant, price: line_items_price}], shipment_cost: 0, shipping_method: shipping_method) }
57
+ let(:line_items_price) { BigDecimal.new(10) }
58
+ let(:line_item) { order.line_items.first }
59
+ let(:inventory_unit) { line_item.inventory_units.first }
60
+ let(:payment) { build(:payment, amount: payment_amount, order: order, state: 'checkout') }
61
+ let(:payment_amount) { order.total }
62
+ let(:customer_return) { build(:customer_return, return_items: [return_item]) }
63
+ let(:return_item) { build(:return_item, inventory_unit: inventory_unit) }
64
+
65
+ let!(:default_refund_reason) { Spree::RefundReason.find_or_create_by!(name: Spree::RefundReason::RETURN_PROCESSING_REASON, mutable: false) }
66
+
67
+ let(:reimbursement) { create(:reimbursement, customer_return: customer_return, order: order, return_items: [return_item]) }
68
+
69
+ subject { reimbursement.perform! }
70
+
71
+ before do
72
+ order.shipments.each do |shipment|
73
+ shipment.inventory_units.update_all state: 'shipped'
74
+ shipment.update_column('state', 'shipped')
75
+ end
76
+ order.reload
77
+ order.update!
78
+ if payment
79
+ payment.save!
80
+ order.next! # confirm
81
+ end
82
+ order.complete! # completed
83
+ payment.capture!
84
+ customer_return.save!
85
+ return_item.accept!
86
+ end
87
+
88
+ it "refunds the total amount" do
89
+ subject
90
+ expect(reimbursement.unpaid_amount).to eq 0
91
+ end
92
+
93
+ it "creates a refund" do
94
+ expect {
95
+ subject
96
+ }.to change{ Spree::Refund.count }.by(1)
97
+ expect(Spree::Refund.last.amount).to eq order.total
98
+ end
99
+
100
+ context 'with additional tax' do
101
+ let!(:tax_rate) { create(:tax_rate, name: "Sales Tax", amount: 0.10, included_in_price: false, zone: tax_zone) }
102
+
103
+ it 'saves the additional tax and refunds the total' do
104
+ expect {
105
+ subject
106
+ }.to change { Spree::Refund.count }.by(1)
107
+ return_item.reload
108
+ expect(return_item.additional_tax_total).to be > 0
109
+ expect(return_item.additional_tax_total).to eq line_item.additional_tax_total
110
+ expect(reimbursement.total).to eq line_item.pre_tax_amount + line_item.additional_tax_total
111
+ expect(Spree::Refund.last.amount).to eq line_item.pre_tax_amount + line_item.additional_tax_total
112
+ end
113
+ end
114
+
115
+ context 'with included tax' do
116
+ let!(:tax_rate) { create(:tax_rate, name: "VAT Tax", amount: 0.1, included_in_price: true, zone: tax_zone) }
117
+
118
+ it 'saves the included tax and refunds the total' do
119
+ expect {
120
+ subject
121
+ }.to change { Spree::Refund.count }.by(1)
122
+ return_item.reload
123
+ expect(return_item.included_tax_total).to be > 0
124
+ expect(return_item.included_tax_total).to eq line_item.included_tax_total
125
+ expect(reimbursement.total).to eq (line_item.pre_tax_amount + line_item.included_tax_total).round(2, :down)
126
+ expect(Spree::Refund.last.amount).to eq (line_item.pre_tax_amount + line_item.included_tax_total).round(2, :down)
127
+ end
128
+ end
129
+
130
+ context 'when reimbursement cannot be fully performed' do
131
+ let!(:non_return_refund) { create(:refund, amount: 1, payment: payment) }
132
+
133
+ it 'raises IncompleteReimbursement error' do
134
+ expect { subject }.to raise_error(Spree::Reimbursement::IncompleteReimbursementError)
135
+ end
136
+ end
137
+
138
+ context "when exchange is required" do
139
+ let(:exchange_variant) { create(:on_demand_variant, product: return_item.inventory_unit.variant.product) }
140
+ before { return_item.exchange_variant = exchange_variant }
141
+ it "generates an exchange shipment for the order for the exchange items" do
142
+ expect { subject }.to change { order.reload.shipments.count }.by 1
143
+ expect(order.shipments.last.inventory_units.first.variant).to eq exchange_variant
144
+ end
145
+ end
146
+
147
+ it "triggers the reimbursement mailer to be sent" do
148
+ expect(Spree::ReimbursementMailer).to receive(:reimbursement_email).with(reimbursement.id) { double(deliver_now: true) }
149
+ subject
150
+ end
151
+
152
+ end
153
+
154
+ describe "#return_items_requiring_exchange" do
155
+ it "returns only the return items that require an exchange" do
156
+ return_items = [double(exchange_required?: true), double(exchange_required?: true),double(exchange_required?: false)]
157
+ allow(subject).to receive(:return_items) { return_items }
158
+ expect(subject.return_items_requiring_exchange).to eq return_items.take(2)
159
+ end
160
+ end
161
+
162
+ describe "#all_exchanges?" do
163
+ it "returns true if all of the return items processed an exchange" do
164
+ return_items = [double(exchange_processed?: true), double(exchange_processed?: true)]
165
+ allow(subject).to receive(:return_items) { return_items }
166
+ expect(subject.all_exchanges?).to be true
167
+ end
168
+
169
+ it "returns false if any of the return items processed an exchange" do
170
+ return_items = [double(exchange_processed?: true), double(exchange_processed?: false)]
171
+ allow(subject).to receive(:return_items) { return_items }
172
+ expect(subject.all_exchanges?).to be false
173
+ end
174
+ end
175
+
176
+ describe "#any_exchanges?" do
177
+ it "returns true if any of the return items processed an exchange" do
178
+ return_items = [double(exchange_processed?: true), double(exchange_processed?: false)]
179
+ allow(subject).to receive(:return_items) { return_items }
180
+ expect(subject.any_exchanges?).to be true
181
+ end
182
+
183
+ it "returns false if none of the return items processed an exchange" do
184
+ return_items = [double(exchange_processed?: false), double(exchange_processed?: false)]
185
+ allow(subject).to receive(:return_items) { return_items }
186
+ expect(subject.any_exchanges?).to be false
187
+ end
188
+ end
189
+
190
+ describe "#calculated_total" do
191
+ context 'with return item amounts that would round up' do
192
+ let(:reimbursement) { Spree::Reimbursement.new }
193
+
194
+ subject { reimbursement.calculated_total }
195
+
196
+ before do
197
+ reimbursement.return_items << Spree::ReturnItem.new(pre_tax_amount: 10.003)
198
+ reimbursement.return_items << Spree::ReturnItem.new(pre_tax_amount: 10.003)
199
+ end
200
+
201
+ it 'rounds down' do
202
+ expect(subject).to eq 20
203
+ end
204
+ end
205
+ end
206
+
207
+ describe '.build_from_customer_return' do
208
+ let(:customer_return) { create(:customer_return, line_items_count: 5) }
209
+ before { customer_return.return_items.each(&:receive!) }
210
+ let!(:pending_return_item) { customer_return.return_items.first.tap { |ri| ri.update!(acceptance_status: 'pending') } }
211
+ let!(:accepted_return_item) { customer_return.return_items.second.tap(&:accept!) }
212
+ let!(:rejected_return_item) { customer_return.return_items.third.tap(&:reject!) }
213
+ let!(:manual_intervention_return_item) { customer_return.return_items.fourth.tap(&:require_manual_intervention!) }
214
+ let!(:already_reimbursed_return_item) { customer_return.return_items.fifth }
215
+ let!(:previous_reimbursement) { create(:reimbursement, order: customer_return.order, return_items: [already_reimbursed_return_item]) }
216
+
217
+ subject { Spree::Reimbursement.build_from_customer_return(customer_return) }
218
+
219
+ it 'connects to the accepted return items' do
220
+ expect(subject.return_items.to_a).to eq [accepted_return_item]
221
+ end
222
+
223
+ it 'connects to the order' do
224
+ expect(subject.order).to eq customer_return.order
225
+ end
226
+
227
+ it 'connects to the customer_return' do
228
+ expect(subject.customer_return).to eq customer_return
229
+ end
230
+ end
231
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::ReimbursementTaxCalculator, :type => :model do
4
+
5
+ let!(:tax_rate) { nil }
6
+
7
+ let(:reimbursement) { create(:reimbursement, return_items_count: 1) }
8
+ let(:return_item) { reimbursement.return_items.first }
9
+ let(:line_item) { return_item.inventory_unit.line_item }
10
+
11
+ subject do
12
+ Spree::ReimbursementTaxCalculator.call(reimbursement)
13
+ end
14
+
15
+ context 'without taxes' do
16
+ let!(:tax_rate) { nil }
17
+
18
+ it 'leaves the return items additional_tax_total and included_tax_total at zero' do
19
+ subject
20
+
21
+ expect(return_item.additional_tax_total).to eq 0
22
+ expect(return_item.included_tax_total).to eq 0
23
+ end
24
+ end
25
+
26
+ context 'with additional tax' do
27
+ let!(:tax_rate) { create(:tax_rate, name: "Sales Tax", amount: 0.10, included_in_price: false, zone: tax_zone) }
28
+ let(:tax_zone) { create(:zone, default_tax: true) }
29
+
30
+ it 'sets additional_tax_total on the return items' do
31
+ subject
32
+ return_item.reload
33
+
34
+ expect(return_item.additional_tax_total).to be > 0
35
+ expect(return_item.additional_tax_total).to eq line_item.additional_tax_total
36
+ end
37
+ end
38
+
39
+ context 'with included tax' do
40
+ let!(:tax_rate) { create(:tax_rate, name: "VAT Tax", amount: 0.1, included_in_price: true, zone: tax_zone) }
41
+ let(:tax_zone) { create(:zone, default_tax: true) }
42
+
43
+ it 'sets included_tax_total on the return items' do
44
+ subject
45
+ return_item.reload
46
+
47
+ expect(return_item.included_tax_total).to be < 0
48
+ expect(return_item.included_tax_total).to eq line_item.included_tax_total
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ describe ReimbursementType::Credit, :type => :model do
5
+ let(:reimbursement) { create(:reimbursement, return_items_count: 1) }
6
+ let(:return_item) { reimbursement.return_items.first }
7
+ let(:payment) { reimbursement.order.payments.first }
8
+ let(:simulate) { false }
9
+ let!(:default_refund_reason) { Spree::RefundReason.find_or_create_by!(name: Spree::RefundReason::RETURN_PROCESSING_REASON, mutable: false) }
10
+ let(:creditable) { DummyCreditable.new(amount: 99.99) }
11
+
12
+ class DummyCreditable < Spree::Base
13
+ attr_accessor :amount
14
+ self.table_name = 'spree_payments' # Your creditable class should not use this table
15
+ end
16
+
17
+ subject { Spree::ReimbursementType::Credit.reimburse(reimbursement, [return_item], simulate)}
18
+
19
+ before do
20
+ reimbursement.update!(total: reimbursement.calculated_total)
21
+ allow(Spree::ReimbursementType::Credit).to receive(:create_creditable).and_return(creditable)
22
+ end
23
+
24
+ describe '.reimburse' do
25
+ context 'simulate is true' do
26
+ let(:simulate) { true }
27
+
28
+ it 'creates one readonly lump credit for all outstanding balance payable to the customer' do
29
+ expect(subject.map(&:class)).to eq [Spree::Reimbursement::Credit]
30
+ expect(subject.map(&:readonly?)).to eq [true]
31
+ expect(subject.sum(&:amount)).to eq reimbursement.return_items.to_a.sum(&:total)
32
+ end
33
+
34
+ it 'does not save to the database' do
35
+ expect { subject }.to_not change { Spree::Reimbursement::Credit.count }
36
+ end
37
+ end
38
+
39
+ context 'simulate is false' do
40
+ let(:simulate) { false }
41
+
42
+ before do
43
+ expect(creditable).to receive(:save).and_return(true)
44
+ end
45
+
46
+ it 'creates one lump credit for all outstanding balance payable to the customer' do
47
+ expect { subject }.to change { Spree::Reimbursement::Credit.count }.by(1)
48
+ expect(subject.sum(&:amount)).to eq reimbursement.return_items.to_a.sum(&:total)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ describe ReimbursementType::Exchange, :type => :model do
5
+ describe '.reimburse' do
6
+ let(:reimbursement) { create(:reimbursement, return_items_count: 1) }
7
+ let(:return_items) { reimbursement.return_items }
8
+ let(:new_exchange) { double("Exchange") }
9
+ let(:simulate) { true }
10
+
11
+ subject { Spree::ReimbursementType::Exchange.reimburse(reimbursement, return_items, simulate)}
12
+
13
+ context 'return items are supplied' do
14
+ before do
15
+ expect(Spree::Exchange).to receive(:new).with(reimbursement.order, return_items).and_return(new_exchange)
16
+ end
17
+
18
+ context "simulate is true" do
19
+
20
+ it 'does not perform an exchange and returns the exchange object' do
21
+ expect(new_exchange).not_to receive(:perform!)
22
+ expect(subject).to eq [new_exchange]
23
+ end
24
+ end
25
+
26
+ context "simulate is false" do
27
+ let(:simulate) { false }
28
+
29
+ it 'performs an exchange and returns the exchange object' do
30
+ expect(new_exchange).to receive(:perform!)
31
+ expect(subject).to eq [new_exchange]
32
+ end
33
+ end
34
+ end
35
+
36
+ context "no return items are supplied" do
37
+ let(:return_items) { [] }
38
+
39
+ it 'does not perform an exchange and returns an empty array' do
40
+ expect(new_exchange).not_to receive(:perform!)
41
+ expect(subject).to eq []
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,107 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ describe ReimbursementType::OriginalPayment, :type => :model do
5
+ let(:reimbursement) { create(:reimbursement, return_items_count: 1) }
6
+ let(:return_item) { reimbursement.return_items.first }
7
+ let(:payment) { reimbursement.order.payments.first }
8
+ let(:simulate) { false }
9
+ let!(:default_refund_reason) { Spree::RefundReason.find_or_create_by!(name: Spree::RefundReason::RETURN_PROCESSING_REASON, mutable: false) }
10
+
11
+ subject { Spree::ReimbursementType::OriginalPayment.reimburse(reimbursement, [return_item], simulate)}
12
+
13
+ before { reimbursement.update!(total: reimbursement.calculated_total) }
14
+
15
+ describe ".reimburse" do
16
+ context "simulate is true" do
17
+ let(:simulate) { true }
18
+
19
+ it "returns an array of readonly refunds" do
20
+ expect(subject.map(&:class)).to eq [Spree::Refund]
21
+ expect(subject.map(&:readonly?)).to eq [true]
22
+ end
23
+ end
24
+
25
+ context "simulate is false" do
26
+ it 'performs the refund' do
27
+ expect {
28
+ subject
29
+ }.to change { payment.refunds.count }.by(1)
30
+ expect(payment.refunds.sum(:amount)).to eq reimbursement.return_items.to_a.sum(&:total)
31
+ end
32
+ end
33
+
34
+ context 'when no credit is allowed on the payment' do
35
+ before do
36
+ expect_any_instance_of(Spree::Payment).to receive(:credit_allowed).and_return 0
37
+ end
38
+
39
+ it 'returns an empty array' do
40
+ expect(subject).to eq []
41
+ end
42
+ end
43
+
44
+ context 'when a payment is negative' do
45
+ before do
46
+ expect_any_instance_of(Spree::Payment).to receive(:amount).and_return -100
47
+ end
48
+
49
+ it 'returns an empty array' do
50
+ expect(subject).to eq []
51
+ end
52
+ end
53
+
54
+ context "multiple payment methods" do
55
+ let(:simulate) { true }
56
+ let!(:check_payment) { create(:check_payment, order: reimbursement.order, amount: 5.0, state: "completed") }
57
+ let(:payment) { reimbursement.order.payments.detect { |p| p.payment_method.is_a? Spree::Gateway::Bogus } }
58
+ let(:refund_amount) { 10.0 }
59
+
60
+ let(:refund_payment_methods) { subject.map { |refund| refund.payment.payment_method } }
61
+
62
+ before do
63
+ reimbursement.order.payments.first.update_attributes!(amount: 5.0)
64
+ return_item.update_attributes!(pre_tax_amount: refund_amount)
65
+ end
66
+
67
+ it "includes refunds all payment type" do
68
+ expect(refund_payment_methods).to include payment.payment_method
69
+ expect(refund_payment_methods).to include check_payment.payment_method
70
+ end
71
+
72
+ context "filtering payment methods" do
73
+ around do |example|
74
+ original = described_class.eligible_refund_methods
75
+ described_class.eligible_refund_methods = [check_payment.payment_method.class]
76
+ example.run
77
+ described_class.eligible_refund_methods = original
78
+ end
79
+
80
+ it "does not refund to ineligible payment methods" do
81
+ expect(refund_payment_methods).to eq [check_payment.payment_method]
82
+ end
83
+ end
84
+
85
+ context "sorting payment methods" do
86
+ around do |example|
87
+ original = described_class.eligible_refund_methods
88
+ described_class.eligible_refund_methods = [check_payment.payment_method.class, payment.payment_method.class]
89
+ example.run
90
+ described_class.eligible_refund_methods = original
91
+ end
92
+
93
+ it "respects configured payment type sort order" do
94
+ expect(refund_payment_methods).to eq [check_payment.payment_method, payment.payment_method]
95
+ end
96
+
97
+ context "only one refund is necessary" do
98
+ let(:refund_amount) { 4.0 }
99
+ it "only returns refunds to satisfy the refund amount" do
100
+ expect(refund_payment_methods).to eq [check_payment.payment_method]
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end