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,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::StoreCreditCategory, :type => :model do
4
+ describe "#non_expiring?" do
5
+ let(:store_credit_category) { build(:store_credit_category, name: category_name) }
6
+
7
+ context "non-expiring type store credit" do
8
+ let(:category_name) { "Non-expiring" }
9
+ it { expect(store_credit_category).to be_non_expiring }
10
+ end
11
+
12
+ context "expiring type store credit" do
13
+ let(:category_name) { "Expiring" }
14
+ it { expect(store_credit_category).not_to be_non_expiring }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,314 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::StoreCreditEvent do
4
+
5
+ describe ".exposed_events" do
6
+
7
+ [
8
+ Spree::StoreCredit::ELIGIBLE_ACTION,
9
+ Spree::StoreCredit::AUTHORIZE_ACTION,
10
+ ].each do |action|
11
+ let(:action) { action }
12
+ it "excludes #{action} actions" do
13
+ event = create(:store_credit_event, action: action)
14
+ expect(described_class.exposed_events).not_to include event
15
+ end
16
+ end
17
+
18
+ [
19
+ Spree::StoreCredit::VOID_ACTION,
20
+ Spree::StoreCredit::CREDIT_ACTION,
21
+ Spree::StoreCredit::CAPTURE_ACTION,
22
+ Spree::StoreCredit::ALLOCATION_ACTION,
23
+ ].each do |action|
24
+ it "includes #{action} actions" do
25
+ event = create(:store_credit_event, action: action)
26
+ expect(described_class.exposed_events).to include event
27
+ end
28
+ end
29
+
30
+ it "excludes invalidated store credit events" do
31
+ invalidated_store_credit = create(:store_credit, invalidated_at: Time.now)
32
+ event = create(:store_credit_event, action: Spree::StoreCredit::VOID_ACTION, store_credit: invalidated_store_credit)
33
+ expect(described_class.exposed_events).not_to include event
34
+ end
35
+ end
36
+
37
+ describe "update reason validation" do
38
+ subject { event.valid? }
39
+
40
+ context "adjustment event" do
41
+ context "has an update reason" do
42
+ let(:event) { build(:store_credit_adjustment_event) }
43
+
44
+ it "returns true" do
45
+ expect(subject).to eq true
46
+ end
47
+ end
48
+
49
+ context "doesn't have an update reason" do
50
+ let(:event) { build(:store_credit_adjustment_event, update_reason: nil) }
51
+
52
+ it "returns false" do
53
+ expect(subject).to eq false
54
+ end
55
+
56
+ it "adds an error message indicating the update reason is missing" do
57
+ subject
58
+ expect(event.errors.full_messages).to match ["Update reason can't be blank"]
59
+ end
60
+ end
61
+ end
62
+
63
+ context "invalidate event" do
64
+ context "has an update reason" do
65
+ let(:event) { build(:store_credit_invalidate_event) }
66
+
67
+ it "returns true" do
68
+ expect(subject).to eq true
69
+ end
70
+ end
71
+
72
+ context "doesn't have an update reason" do
73
+ let(:event) { build(:store_credit_invalidate_event, update_reason: nil) }
74
+
75
+ it "returns false" do
76
+ expect(subject).to eq false
77
+ end
78
+
79
+ it "adds an error message indicating the update reason is missing" do
80
+ subject
81
+ expect(event.errors.full_messages).to match ["Update reason can't be blank"]
82
+ end
83
+ end
84
+ end
85
+
86
+ context "event doesn't require an update reason" do
87
+ let(:event) { build(:store_credit_auth_event) }
88
+
89
+ it "returns true" do
90
+ expect(subject).to eq true
91
+ end
92
+ end
93
+ end
94
+
95
+ describe "#capture_action?" do
96
+ subject { event.capture_action? }
97
+
98
+ context "for capture events" do
99
+ let(:event) { create(:store_credit_capture_event) }
100
+
101
+ it "returns true" do
102
+ expect(subject).to eq true
103
+ end
104
+ end
105
+
106
+ context "for non-capture events" do
107
+ let(:event) { create(:store_credit_auth_event) }
108
+
109
+ it "returns false" do
110
+ expect(subject).to eq false
111
+ end
112
+ end
113
+ end
114
+
115
+ describe "#authorization_action?" do
116
+ subject { event.authorization_action? }
117
+
118
+ context "for auth events" do
119
+ let(:event) { create(:store_credit_auth_event) }
120
+
121
+ it "returns true" do
122
+ expect(subject).to eq true
123
+ end
124
+ end
125
+
126
+ context "for non-auth events" do
127
+ let(:event) { create(:store_credit_capture_event) }
128
+
129
+ it "returns false" do
130
+ expect(subject).to eq false
131
+ end
132
+ end
133
+ end
134
+
135
+ describe "#action_requires_reason?" do
136
+ subject { event.action_requires_reason? }
137
+
138
+ context "for adjustment events" do
139
+ let(:event) { create(:store_credit_adjustment_event) }
140
+
141
+ it "returns true" do
142
+ expect(subject).to eq true
143
+ end
144
+ end
145
+
146
+ context "for invalidate events" do
147
+ let(:event) { create(:store_credit_invalidate_event) }
148
+
149
+ it "returns true" do
150
+ expect(subject).to eq true
151
+ end
152
+ end
153
+
154
+ context "for capture events" do
155
+ let(:event) { create(:store_credit_capture_event) }
156
+
157
+ it "returns false" do
158
+ expect(subject).to eq false
159
+ end
160
+ end
161
+
162
+ context "for authorize events" do
163
+ let(:event) { create(:store_credit_auth_event) }
164
+
165
+ it "returns false" do
166
+ expect(subject).to eq false
167
+ end
168
+ end
169
+
170
+ context "for allocation events" do
171
+ let(:event) { create(:store_credit_event, action: Spree::StoreCredit::ALLOCATION_ACTION) }
172
+
173
+ it "returns false" do
174
+ expect(subject).to eq false
175
+ end
176
+ end
177
+
178
+ context "for void events" do
179
+ let(:event) { create(:store_credit_event, action: Spree::StoreCredit::VOID_ACTION) }
180
+
181
+ it "returns false" do
182
+ expect(subject).to eq false
183
+ end
184
+ end
185
+
186
+ context "for credit events" do
187
+ let(:event) { create(:store_credit_event, action: Spree::StoreCredit::CREDIT_ACTION) }
188
+
189
+ it "returns false" do
190
+ expect(subject).to eq false
191
+ end
192
+ end
193
+ end
194
+
195
+ describe "#display_amount" do
196
+ let(:event_amount) { 120.0 }
197
+
198
+ subject { create(:store_credit_auth_event, amount: event_amount) }
199
+
200
+ it "returns a Spree::Money instance" do
201
+ expect(subject.display_amount).to be_instance_of(Spree::Money)
202
+ end
203
+
204
+ it "uses the events amount attribute" do
205
+ expect(subject.display_amount).to eq Spree::Money.new(event_amount, { currency: subject.currency })
206
+ end
207
+ end
208
+
209
+ describe "#display_user_total_amount" do
210
+ let(:user_total_amount) { 300.0 }
211
+
212
+ subject { create(:store_credit_auth_event, user_total_amount: user_total_amount) }
213
+
214
+ it "returns a Spree::Money instance" do
215
+ expect(subject.display_user_total_amount).to be_instance_of(Spree::Money)
216
+ end
217
+
218
+ it "uses the events user_total_amount attribute" do
219
+ expect(subject.display_user_total_amount).to eq Spree::Money.new(user_total_amount, { currency: subject.currency })
220
+ end
221
+ end
222
+
223
+ describe "#display_event_date" do
224
+ let(:date) { DateTime.new(2014, 06, 1) }
225
+
226
+ subject { create(:store_credit_auth_event, created_at: date) }
227
+
228
+ it "returns the date the event was created with the format month/date/year" do
229
+ expect(subject.display_event_date).to eq "June 01, 2014"
230
+ end
231
+ end
232
+
233
+ describe "#display_action" do
234
+ subject { event.display_action }
235
+
236
+ context "capture event" do
237
+ let(:event) { create(:store_credit_capture_event) }
238
+
239
+ it "returns the action's display text" do
240
+ expect(subject).to eq "Used"
241
+ end
242
+ end
243
+
244
+ context "allocation event" do
245
+ let(:event) { create(:store_credit_event, action: Spree::StoreCredit::ALLOCATION_ACTION) }
246
+
247
+ it "returns the action's display text" do
248
+ expect(subject).to eq "Added"
249
+ end
250
+ end
251
+
252
+ context "void event" do
253
+ let(:event) { create(:store_credit_event, action: Spree::StoreCredit::VOID_ACTION) }
254
+
255
+ it "returns the action's display text" do
256
+ expect(subject).to eq "Credit"
257
+ end
258
+ end
259
+
260
+ context "credit event" do
261
+ let(:event) { create(:store_credit_event, action: Spree::StoreCredit::CREDIT_ACTION) }
262
+
263
+ it "returns the action's display text" do
264
+ expect(subject).to eq "Credit"
265
+ end
266
+ end
267
+
268
+ context "adjustment event" do
269
+ let(:event) { create(:store_credit_adjustment_event) }
270
+
271
+ it "returns the action's display text" do
272
+ expect(subject).to eq "Adjustment"
273
+ end
274
+ end
275
+
276
+ context "authorize event" do
277
+ let(:event) { create(:store_credit_auth_event) }
278
+
279
+ it "returns nil" do
280
+ expect(subject).to be_nil
281
+ end
282
+ end
283
+
284
+ context "eligible event" do
285
+ let(:event) { create(:store_credit_event, action: Spree::StoreCredit::ELIGIBLE_ACTION) }
286
+
287
+ it "returns nil" do
288
+ expect(subject).to be_nil
289
+ end
290
+ end
291
+ end
292
+
293
+ describe "#order" do
294
+ context "there is no associated payment with the event" do
295
+ subject { create(:store_credit_auth_event) }
296
+
297
+ it "returns nil" do
298
+ expect(subject.order).to be_nil
299
+ end
300
+ end
301
+
302
+ context "there is an associated payment with the event" do
303
+ let(:authorization_code) { "1-SC-TEST" }
304
+ let(:order) { create(:order) }
305
+ let!(:payment) { create(:store_credit_payment, order: order, response_code: authorization_code) }
306
+
307
+ subject { create(:store_credit_auth_event, action: Spree::StoreCredit::CAPTURE_ACTION, authorization_code: authorization_code) }
308
+
309
+ it "returns the order associated with the payment" do
310
+ expect(subject.order).to eq order
311
+ end
312
+ end
313
+ end
314
+ end
@@ -0,0 +1,876 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::StoreCredit do
4
+
5
+ let(:currency) { "TEST" }
6
+ let(:store_credit) { build(:store_credit, store_credit_attrs) }
7
+ let(:store_credit_attrs) { {} }
8
+
9
+
10
+ describe "callbacks" do
11
+ subject { store_credit.save }
12
+
13
+ context "amount used is greater than zero" do
14
+ let(:store_credit) { create(:store_credit, amount: 100, amount_used: 1) }
15
+ subject { store_credit.destroy }
16
+
17
+ it 'can not delete the store credit' do
18
+ subject
19
+ expect(store_credit.reload).to eq store_credit
20
+ expect(store_credit.errors[:amount_used]).to include("is greater than zero. Can not delete store credit")
21
+ end
22
+ end
23
+
24
+ context "category is a non-expiring type" do
25
+ let!(:secondary_credit_type) { create(:secondary_credit_type) }
26
+ let(:store_credit) { build(:store_credit, credit_type: nil)}
27
+
28
+ before do
29
+ allow(store_credit.category).to receive(:non_expiring?).and_return(true)
30
+ end
31
+
32
+ it "sets the credit type to non-expiring" do
33
+ subject
34
+ expect(store_credit.credit_type.name).to eq secondary_credit_type.name
35
+ end
36
+ end
37
+
38
+ context "category is an expiring type" do
39
+ before do
40
+ allow(store_credit.category).to receive(:non_expiring?).and_return(false)
41
+ end
42
+
43
+ it "sets the credit type to non-expiring" do
44
+ subject
45
+ expect(store_credit.credit_type.name).to eq "Expiring"
46
+ end
47
+ end
48
+
49
+ context "the type is set" do
50
+ let!(:secondary_credit_type) { create(:secondary_credit_type)}
51
+ let(:store_credit) { build(:store_credit, credit_type: secondary_credit_type)}
52
+
53
+ before do
54
+ allow(store_credit.category).to receive(:non_expiring?).and_return(false)
55
+ end
56
+
57
+ it "doesn't overwrite the type" do
58
+ expect{ subject }.to_not change{ store_credit.credit_type }
59
+ end
60
+ end
61
+ end
62
+
63
+ describe "validations" do
64
+ describe "used amount should not be greater than the credited amount" do
65
+ context "the used amount is defined" do
66
+ let(:invalid_store_credit) { build(:store_credit, amount: 100, amount_used: 150) }
67
+
68
+ it "should not be valid" do
69
+ expect(invalid_store_credit).not_to be_valid
70
+ end
71
+
72
+ it "should set the correct error message" do
73
+ invalid_store_credit.valid?
74
+ expect(invalid_store_credit.errors.full_messages).to include("Amount used cannot be greater than the credited amount")
75
+ end
76
+ end
77
+
78
+ context "the used amount is not defined yet" do
79
+ let(:store_credit) { build(:store_credit, amount: 100) }
80
+
81
+ it "should be valid" do
82
+ expect(store_credit).to be_valid
83
+ end
84
+
85
+ end
86
+ end
87
+
88
+ describe "amount used less than or equal to amount" do
89
+ subject { build(:store_credit, amount_used: 101.0, amount: 100.0) }
90
+
91
+ it "is not valid" do
92
+ expect(subject).not_to be_valid
93
+ end
94
+
95
+ it "adds an error message about the invalid amount used" do
96
+ subject.valid?
97
+ expect(subject.errors[:amount_used]).to include("cannot be greater than the credited amount")
98
+ end
99
+ end
100
+
101
+ describe "amount authorized less than or equal to amount" do
102
+ subject { build(:store_credit, amount_authorized: 101.0, amount: 100.0) }
103
+
104
+ it "is not valid" do
105
+ expect(subject).not_to be_valid
106
+ end
107
+
108
+ it "adds an error message about the invalid authorized amount" do
109
+ subject.valid?
110
+ expect(subject.errors[:amount_authorized]).to include(" exceeds the available credit")
111
+ end
112
+ end
113
+
114
+ describe "editing category" do
115
+ let!(:store_credit) { create(:store_credit) }
116
+ let!(:test_category) { create(:store_credit_category, name: "Testing") }
117
+
118
+ subject { store_credit.update_attributes(category: test_category) }
119
+
120
+ it "returns false" do
121
+ expect(subject).to eq false
122
+ end
123
+
124
+ it "category doesn't change" do
125
+ expect { subject }.not_to change { store_credit.reload.category }
126
+ end
127
+
128
+ it "adds an error message about not being able to edit the category" do
129
+ subject
130
+ expect(store_credit.errors[:category]).to include("cannot be modified")
131
+ end
132
+ end
133
+ end
134
+
135
+ describe "#display_amount" do
136
+ it "returns a Spree::Money instance" do
137
+ expect(store_credit.display_amount).to be_instance_of(Spree::Money)
138
+ end
139
+ end
140
+
141
+ describe "#display_amount_used" do
142
+ it "returns a Spree::Money instance" do
143
+ expect(store_credit.display_amount_used).to be_instance_of(Spree::Money)
144
+ end
145
+ end
146
+
147
+ describe "#display_amount_authorized" do
148
+ it "returns a Spree::Money instance" do
149
+ expect(store_credit.display_amount_authorized).to be_instance_of(Spree::Money)
150
+ end
151
+ end
152
+
153
+ describe "#amount_remaining" do
154
+ context "invalidated" do
155
+ before { allow(store_credit).to receive(:invalidated?) { true } }
156
+ it { expect(store_credit.amount_remaining).to eq 0.0 }
157
+ end
158
+
159
+ context "the amount_used is not defined" do
160
+ context "the authorized amount is not defined" do
161
+ it "returns the credited amount" do
162
+ expect(store_credit.amount_remaining).to eq store_credit.amount
163
+ end
164
+ end
165
+ context "the authorized amount is defined" do
166
+ let(:authorized_amount) { 15.00 }
167
+
168
+ before { store_credit.update_attributes(amount_authorized: authorized_amount) }
169
+
170
+ it "subtracts the authorized amount from the credited amount" do
171
+ expect(store_credit.amount_remaining).to eq (store_credit.amount - authorized_amount)
172
+ end
173
+ end
174
+ end
175
+
176
+ context "the amount_used is defined" do
177
+ let(:amount_used) { 10.0 }
178
+
179
+ before { store_credit.update_attributes(amount_used: amount_used) }
180
+
181
+ context "the authorized amount is not defined" do
182
+ it "subtracts the amount used from the credited amount" do
183
+ expect(store_credit.amount_remaining).to eq (store_credit.amount - amount_used)
184
+ end
185
+ end
186
+
187
+ context "the authorized amount is defined" do
188
+ let(:authorized_amount) { 15.00 }
189
+
190
+ before { store_credit.update_attributes(amount_authorized: authorized_amount) }
191
+
192
+ it "subtracts the amount used and the authorized amount from the credited amount" do
193
+ expect(store_credit.amount_remaining).to eq (store_credit.amount - amount_used - authorized_amount)
194
+ end
195
+ end
196
+ end
197
+ end
198
+
199
+ describe "#authorize" do
200
+ context "amount is valid" do
201
+ let(:authorization_amount) { 1.0 }
202
+ let(:added_authorization_amount) { 3.0 }
203
+ let(:originator) { nil }
204
+
205
+ context "amount has not been authorized yet" do
206
+
207
+ before { store_credit.update_attributes(amount_authorized: authorization_amount) }
208
+
209
+ it "returns true" do
210
+ expect(store_credit.authorize(store_credit.amount - authorization_amount, store_credit.currency)).to be_truthy
211
+ end
212
+
213
+ it "adds the new amount to authorized amount" do
214
+ store_credit.authorize(added_authorization_amount, store_credit.currency)
215
+ expect(store_credit.reload.amount_authorized).to eq (authorization_amount + added_authorization_amount)
216
+ end
217
+
218
+ context "originator is present" do
219
+ let(:originator) { create(:user) } # won't actually be a user. just giving it a valid model here
220
+
221
+ subject { store_credit.authorize(added_authorization_amount, store_credit.currency, action_originator: originator) }
222
+
223
+ it "records the originator" do
224
+ expect { subject }.to change { Spree::StoreCreditEvent.count }.by(1)
225
+ expect(Spree::StoreCreditEvent.last.originator).to eq originator
226
+ end
227
+ end
228
+ end
229
+
230
+ context "authorization has already happened" do
231
+ let!(:auth_event) { create(:store_credit_auth_event, store_credit: store_credit) }
232
+
233
+ before { store_credit.update_attributes(amount_authorized: store_credit.amount) }
234
+
235
+ it "returns true" do
236
+ expect(store_credit.authorize(store_credit.amount, store_credit.currency, action_authorization_code: auth_event.authorization_code)).to be true
237
+ end
238
+ end
239
+ end
240
+
241
+ context "amount is invalid" do
242
+ it "returns false" do
243
+ expect(store_credit.authorize(store_credit.amount * 2, store_credit.currency)).to be false
244
+ end
245
+ end
246
+ end
247
+
248
+ describe "#validate_authorization" do
249
+ context "insufficient funds" do
250
+ subject { store_credit.validate_authorization(store_credit.amount * 2, store_credit.currency) }
251
+
252
+ it "returns false" do
253
+ expect(subject).to be false
254
+ end
255
+
256
+ it "adds an error to the model" do
257
+ subject
258
+ expect(store_credit.errors.full_messages).to include("Store credit amount remaining is not sufficient")
259
+ end
260
+ end
261
+
262
+ context "currency mismatch" do
263
+ subject { store_credit.validate_authorization(store_credit.amount, "EUR") }
264
+
265
+ it "returns false" do
266
+ expect(subject).to be false
267
+ end
268
+
269
+ it "adds an error to the model" do
270
+ subject
271
+ expect(store_credit.errors.full_messages).to include("Store credit currency does not match order currency")
272
+ end
273
+ end
274
+
275
+ context "valid authorization" do
276
+ subject { store_credit.validate_authorization(store_credit.amount, store_credit.currency) }
277
+
278
+ it "returns true" do
279
+ expect(subject).to be true
280
+ end
281
+ end
282
+
283
+ context 'troublesome floats' do
284
+ # 8.21.to_d < 8.21 => true
285
+ let(:store_credit_attrs) { {amount: 8.21} }
286
+
287
+ subject { store_credit.validate_authorization(store_credit_attrs[:amount], store_credit.currency) }
288
+
289
+ it { is_expected.to be_truthy }
290
+ end
291
+ end
292
+
293
+ describe "#capture" do
294
+ let(:authorized_amount) { 10.00 }
295
+ let(:auth_code) { "23-SC-20140602164814476128" }
296
+
297
+ before do
298
+ @original_authed_amount = store_credit.amount_authorized
299
+ @auth_code = store_credit.authorize(authorized_amount, store_credit.currency)
300
+ end
301
+
302
+ context "insufficient funds" do
303
+ subject { store_credit.capture(authorized_amount * 2, @auth_code, store_credit.currency) }
304
+
305
+ it "returns false" do
306
+ expect(subject).to be false
307
+ end
308
+
309
+ it "adds an error to the model" do
310
+ subject
311
+ expect(store_credit.errors.full_messages).to include("Unable to capture more than authorized amount")
312
+ end
313
+
314
+ it "does not update the store credit model" do
315
+ expect { subject }.to_not change { store_credit }
316
+ end
317
+ end
318
+
319
+ context "currency mismatch" do
320
+ subject { store_credit.capture(authorized_amount, @auth_code, "EUR") }
321
+
322
+ it "returns false" do
323
+ expect(subject).to be false
324
+ end
325
+
326
+ it "adds an error to the model" do
327
+ subject
328
+ expect(store_credit.errors.full_messages).to include("Store credit currency does not match order currency")
329
+ end
330
+
331
+ it "does not update the store credit model" do
332
+ expect { subject }.to_not change { store_credit }
333
+ end
334
+ end
335
+
336
+ context "valid capture" do
337
+ let(:remaining_authorized_amount) { 1 }
338
+ let(:originator) { nil }
339
+
340
+ subject { store_credit.capture(authorized_amount - remaining_authorized_amount, @auth_code, store_credit.currency, action_originator: originator) }
341
+
342
+ it "returns true" do
343
+ expect(subject).to be_truthy
344
+ end
345
+
346
+ it "updates the authorized amount to the difference between the store credits total authed amount and the authorized amount for this event" do
347
+ subject
348
+ expect(store_credit.reload.amount_authorized).to eq(@original_authed_amount)
349
+ end
350
+
351
+ it "updates the used amount to the current used amount plus the captured amount" do
352
+ subject
353
+ expect(store_credit.reload.amount_used).to eq authorized_amount - remaining_authorized_amount
354
+ end
355
+
356
+ context "originator is present" do
357
+ let(:originator) { create(:user) } # won't actually be a user. just giving it a valid model here
358
+
359
+ it "records the originator" do
360
+ expect { subject }.to change { Spree::StoreCreditEvent.count }.by(1)
361
+ expect(Spree::StoreCreditEvent.last.originator).to eq originator
362
+ end
363
+ end
364
+ end
365
+ end
366
+
367
+ describe "#void" do
368
+ let(:auth_code) { "1-SC-20141111111111" }
369
+ let(:store_credit) { create(:store_credit, amount_used: 150.0) }
370
+ let(:originator) { nil }
371
+
372
+ subject do
373
+ store_credit.void(auth_code, action_originator: originator)
374
+ end
375
+
376
+ context "no event found for auth_code" do
377
+
378
+ it "returns false" do
379
+ expect(subject).to be false
380
+ end
381
+
382
+ it "adds an error to the model" do
383
+ subject
384
+ expect(store_credit.errors.full_messages).to include("Unable to void code: #{auth_code}")
385
+ end
386
+ end
387
+
388
+ context "capture event found for auth_code" do
389
+ let(:captured_amount) { 10.0 }
390
+ let!(:capture_event) { create(:store_credit_auth_event,
391
+ action: Spree::StoreCredit::CAPTURE_ACTION,
392
+ authorization_code: auth_code,
393
+ amount: captured_amount,
394
+ store_credit: store_credit) }
395
+
396
+ it "returns false" do
397
+ expect(subject).to be false
398
+ end
399
+
400
+ it "does not change the amount used on the store credit" do
401
+ expect { subject }.to_not change{ store_credit.amount_used.to_f }
402
+ end
403
+ end
404
+
405
+ context "auth event found for auth_code" do
406
+ let(:auth_event) { create(:store_credit_auth_event) }
407
+
408
+ let(:authorized_amount) { 10.0 }
409
+ let!(:auth_event) { create(:store_credit_auth_event,
410
+ authorization_code: auth_code,
411
+ amount: authorized_amount,
412
+ store_credit: store_credit) }
413
+
414
+ it "returns true" do
415
+ expect(subject).to be true
416
+ end
417
+
418
+ it "returns the capture amount to the store credit" do
419
+ expect { subject }.to change{ store_credit.amount_authorized.to_f }.by(-authorized_amount)
420
+ end
421
+
422
+ context "originator is present" do
423
+ let(:originator) { create(:user) } # won't actually be a user. just giving it a valid model here
424
+
425
+ it "records the originator" do
426
+ expect { subject }.to change { Spree::StoreCreditEvent.count }.by(1)
427
+ expect(Spree::StoreCreditEvent.last.originator).to eq originator
428
+ end
429
+ end
430
+ end
431
+ end
432
+
433
+ describe "#credit" do
434
+ let(:event_auth_code) { "1-SC-20141111111111" }
435
+ let(:amount_used) { 10.0 }
436
+ let(:store_credit) { create(:store_credit, amount_used: amount_used) }
437
+ let!(:capture_event) { create(:store_credit_auth_event,
438
+ action: Spree::StoreCredit::CAPTURE_ACTION,
439
+ authorization_code: event_auth_code,
440
+ amount: captured_amount,
441
+ store_credit: store_credit) }
442
+ let(:originator) { nil }
443
+
444
+ subject { store_credit.credit(credit_amount, auth_code, currency, action_originator: originator) }
445
+
446
+ context "currency does not match" do
447
+ let(:currency) { "AUD" }
448
+ let(:credit_amount) { 5.0 }
449
+ let(:captured_amount) { 100.0 }
450
+ let(:auth_code) { event_auth_code }
451
+
452
+ it "returns false" do
453
+ expect(subject).to be false
454
+ end
455
+
456
+ it "adds an error message about the currency mismatch" do
457
+ subject
458
+ expect(store_credit.errors.full_messages).to include("Store credit currency does not match order currency")
459
+ end
460
+ end
461
+
462
+ context "unable to find capture event" do
463
+ let(:currency) { "USD" }
464
+ let(:credit_amount) { 5.0 }
465
+ let(:captured_amount) { 100.0 }
466
+ let(:auth_code) { "UNKNOWN_CODE" }
467
+
468
+ it "returns false" do
469
+ expect(subject).to be false
470
+ end
471
+
472
+ it "adds an error message about the currency mismatch" do
473
+ subject
474
+ expect(store_credit.errors.full_messages).to include("Unable to credit code: #{auth_code}")
475
+ end
476
+ end
477
+
478
+ context "amount is more than what is captured" do
479
+ let(:currency) { "USD" }
480
+ let(:credit_amount) { 100.0 }
481
+ let(:captured_amount) { 5.0 }
482
+ let(:auth_code) { event_auth_code }
483
+
484
+ it "returns false" do
485
+ expect(subject).to be false
486
+ end
487
+
488
+ it "adds an error message about the currency mismatch" do
489
+ subject
490
+ expect(store_credit.errors.full_messages).to include("Unable to credit code: #{auth_code}")
491
+ end
492
+ end
493
+
494
+ context "amount is successfully credited" do
495
+ let(:currency) { "USD" }
496
+ let(:credit_amount) { 5.0 }
497
+ let(:captured_amount) { 100.0 }
498
+ let(:auth_code) { event_auth_code }
499
+
500
+ context "credit_to_new_allocation is set" do
501
+ before { Spree::Config[:credit_to_new_allocation] = true }
502
+
503
+ it "returns true" do
504
+ expect(subject).to be true
505
+ end
506
+
507
+ it "creates a new store credit record" do
508
+ expect { subject }.to change { Spree::StoreCredit.count }.by(1)
509
+ end
510
+
511
+ it "does not create a new store credit event on the parent store credit" do
512
+ expect { subject }.to_not change { store_credit.store_credit_events.count }
513
+ end
514
+
515
+ context "credits the passed amount to a new store credit record" do
516
+ before do
517
+ subject
518
+ @new_store_credit = Spree::StoreCredit.last
519
+ end
520
+
521
+ it "does not set the amount used on hte originating store credit" do
522
+ expect(store_credit.reload.amount_used).to eq amount_used
523
+ end
524
+
525
+ it "sets the correct amount on the new store credit" do
526
+ expect(@new_store_credit.amount).to eq credit_amount
527
+ end
528
+
529
+ [:user_id, :category_id, :created_by_id, :currency, :type_id].each do |attr|
530
+ it "sets attribute #{attr} inherited from the originating store credit" do
531
+ expect(@new_store_credit.send(attr)).to eq store_credit.send(attr)
532
+ end
533
+ end
534
+
535
+ it "sets a memo" do
536
+ expect(@new_store_credit.memo).to eq "This is a credit from store credit ID #{store_credit.id}"
537
+ end
538
+ end
539
+
540
+ context "originator is present" do
541
+ let(:originator) { create(:user) } # won't actually be a user. just giving it a valid model here
542
+
543
+ it "records the originator" do
544
+ expect { subject }.to change { Spree::StoreCreditEvent.count }.by(1)
545
+ expect(Spree::StoreCreditEvent.last.originator).to eq originator
546
+ end
547
+ end
548
+ end
549
+
550
+ context "credit_to_new_allocation is not set" do
551
+ it "returns true" do
552
+ expect(subject).to be true
553
+ end
554
+
555
+ it "credits the passed amount to the store credit amount used" do
556
+ subject
557
+ expect(store_credit.reload.amount_used).to eq (amount_used - credit_amount)
558
+ end
559
+
560
+ it "creates a new store credit event" do
561
+ expect { subject }.to change { store_credit.store_credit_events.count }.by(1)
562
+ end
563
+ end
564
+ end
565
+ end
566
+
567
+ describe "#amount_used" do
568
+ context "amount used is not defined" do
569
+ subject { Spree::StoreCredit.new }
570
+
571
+ it "returns zero" do
572
+ expect(subject.amount_used).to be_zero
573
+ end
574
+ end
575
+
576
+ context "amount used is defined" do
577
+ let(:amount_used) { 100.0 }
578
+
579
+ subject { create(:store_credit, amount_used: amount_used) }
580
+
581
+ it "returns the attribute value" do
582
+ expect(subject.amount_used).to eq amount_used
583
+ end
584
+ end
585
+ end
586
+
587
+ describe "#amount_authorized" do
588
+ context "amount authorized is not defined" do
589
+ subject { Spree::StoreCredit.new }
590
+
591
+ it "returns zero" do
592
+ expect(subject.amount_authorized).to be_zero
593
+ end
594
+ end
595
+
596
+ context "amount authorized is defined" do
597
+ let(:amount_authorized) { 100.0 }
598
+
599
+ subject { create(:store_credit, amount_authorized: amount_authorized) }
600
+
601
+ it "returns the attribute value" do
602
+ expect(subject.amount_authorized).to eq amount_authorized
603
+ end
604
+ end
605
+ end
606
+
607
+ describe "#can_capture?" do
608
+ let(:store_credit) { create(:store_credit) }
609
+ let(:payment) { create(:payment, state: payment_state) }
610
+
611
+ subject { store_credit.can_capture?(payment) }
612
+
613
+ context "pending payment" do
614
+ let(:payment_state) { 'pending' }
615
+
616
+ it "returns true" do
617
+ expect(subject).to be true
618
+ end
619
+ end
620
+
621
+ context "checkout payment" do
622
+ let(:payment_state) { 'checkout' }
623
+
624
+ it "returns true" do
625
+ expect(subject).to be true
626
+ end
627
+ end
628
+
629
+ context "void payment" do
630
+ let(:payment_state) { Spree::StoreCredit::VOID_ACTION }
631
+
632
+ it "returns false" do
633
+ expect(subject).to be false
634
+ end
635
+ end
636
+
637
+ context "invalid payment" do
638
+ let(:payment_state) { 'invalid' }
639
+
640
+ it "returns false" do
641
+ expect(subject).to be false
642
+ end
643
+ end
644
+
645
+ context "complete payment" do
646
+ let(:payment_state) { 'completed' }
647
+
648
+ it "returns false" do
649
+ expect(subject).to be false
650
+ end
651
+ end
652
+ end
653
+
654
+ describe "#can_void?" do
655
+ let(:store_credit) { create(:store_credit) }
656
+ let(:payment) { create(:payment, state: payment_state) }
657
+
658
+ subject { store_credit.can_void?(payment) }
659
+
660
+ context "pending payment" do
661
+ let(:payment_state) { 'pending' }
662
+
663
+ it "returns true" do
664
+ expect(subject).to be true
665
+ end
666
+ end
667
+
668
+ context "checkout payment" do
669
+ let(:payment_state) { 'checkout' }
670
+
671
+ it "returns false" do
672
+ expect(subject).to be false
673
+ end
674
+ end
675
+
676
+ context "void payment" do
677
+ let(:payment_state) { Spree::StoreCredit::VOID_ACTION }
678
+
679
+ it "returns false" do
680
+ expect(subject).to be false
681
+ end
682
+ end
683
+
684
+ context "invalid payment" do
685
+ let(:payment_state) { 'invalid' }
686
+
687
+ it "returns false" do
688
+ expect(subject).to be false
689
+ end
690
+ end
691
+
692
+ context "complete payment" do
693
+ let(:payment_state) { 'completed' }
694
+
695
+ it "returns false" do
696
+ expect(subject).to be false
697
+ end
698
+ end
699
+ end
700
+
701
+ describe "#can_credit?" do
702
+ let(:store_credit) { create(:store_credit) }
703
+ let(:payment) { create(:payment, state: payment_state) }
704
+
705
+ subject { store_credit.can_credit?(payment) }
706
+
707
+ context "payment is not completed" do
708
+ let(:payment_state) { "pending" }
709
+
710
+ it "returns false" do
711
+ expect(subject).to be false
712
+ end
713
+ end
714
+
715
+ context "payment is completed" do
716
+ let(:payment_state) { "completed" }
717
+
718
+ context "credit is owed on the order" do
719
+ before { allow(payment.order).to receive_messages(payment_state: 'credit_owed') }
720
+
721
+ context "payment doesn't have allowed credit" do
722
+ before { allow(payment).to receive_messages(credit_allowed: 0.0) }
723
+
724
+ it "returns false" do
725
+ expect(subject).to be false
726
+ end
727
+ end
728
+
729
+ context "payment has allowed credit" do
730
+ before { allow(payment).to receive_messages(credit_allowed: 5.0) }
731
+
732
+ it "returns true" do
733
+ expect(subject).to be true
734
+ end
735
+ end
736
+ end
737
+ end
738
+
739
+ describe "#store_events" do
740
+ context "create" do
741
+ context "user has one store credit" do
742
+ let(:store_credit_amount) { 100.0 }
743
+
744
+ subject { create(:store_credit, amount: store_credit_amount) }
745
+
746
+ it "creates a store credit event" do
747
+ expect { subject }.to change { Spree::StoreCreditEvent.count }.by(1)
748
+ end
749
+
750
+ it "makes the store credit event an allocation event" do
751
+ expect(subject.store_credit_events.first.action).to eq Spree::StoreCredit::ALLOCATION_ACTION
752
+ end
753
+
754
+ it "saves the user's total store credit in the event" do
755
+ expect(subject.store_credit_events.first.user_total_amount).to eq store_credit_amount
756
+ end
757
+ end
758
+
759
+ context "user has multiple store credits" do
760
+ let(:store_credit_amount) { 100.0 }
761
+ let(:additional_store_credit_amount) { 200.0 }
762
+
763
+ let(:user) { create(:user) }
764
+ let!(:store_credit) { create(:store_credit, user: user, amount: store_credit_amount) }
765
+
766
+ subject { create(:store_credit, user: user, amount: additional_store_credit_amount) }
767
+
768
+ it "saves the user's total store credit in the event" do
769
+ expect(subject.store_credit_events.first.user_total_amount).to eq (store_credit_amount + additional_store_credit_amount)
770
+ end
771
+ end
772
+
773
+ context "an action is specified" do
774
+ it "creates an event with the set action" do
775
+ store_credit = build(:store_credit)
776
+ store_credit.action = Spree::StoreCredit::VOID_ACTION
777
+ store_credit.action_authorization_code = "1-SC-TEST"
778
+
779
+ expect { store_credit.save! }.to change { Spree::StoreCreditEvent.where(action: Spree::StoreCredit::VOID_ACTION).count }.by(1)
780
+ end
781
+ end
782
+ end
783
+ end
784
+ end
785
+
786
+ describe "#update_amount" do
787
+ let(:invalidation_user) { create(:user) }
788
+ let(:invalidation_reason) { create(:store_credit_update_reason) }
789
+
790
+ subject { store_credit.update_amount(amount, invalidation_reason, invalidation_user) }
791
+
792
+ context "amount is valid" do
793
+ let(:amount) { 10.0 }
794
+
795
+ before { store_credit.update_attributes!(amount: 30.0) }
796
+
797
+ it "returns true" do
798
+ expect(subject).to eq true
799
+ end
800
+
801
+ it "creates an adjustment store credit event" do
802
+ expect { subject }.to change { store_credit.store_credit_events.where(action: Spree::StoreCredit::ADJUSTMENT_ACTION).count }.from(0).to(1)
803
+ end
804
+
805
+ it "sets the adjustment amount on the store credit event correctly" do
806
+ subject
807
+ expect(store_credit.store_credit_events.find_by(action: Spree::StoreCredit::ADJUSTMENT_ACTION).amount).to eq -20
808
+ end
809
+
810
+ it "sets the originator on the store credit event correctly" do
811
+ subject
812
+ expect(store_credit.store_credit_events.find_by(action: Spree::StoreCredit::ADJUSTMENT_ACTION).originator).to eq invalidation_user
813
+ end
814
+ end
815
+
816
+ context "amount is invalid" do
817
+ let(:amount) { -10.0 }
818
+
819
+ it "returns false" do
820
+ expect(subject).to eq false
821
+ end
822
+
823
+ it "doesn't create an adjustment store credit event" do
824
+ expect { subject }.to_not change { store_credit.store_credit_events.where(action: Spree::StoreCredit::ADJUSTMENT_ACTION).count }
825
+ end
826
+ end
827
+ end
828
+
829
+ describe "#invalidate" do
830
+ let(:invalidation_user) { create(:user) }
831
+ let(:invalidation_reason) { create(:store_credit_update_reason) }
832
+
833
+ before do
834
+ store_credit.save!
835
+ end
836
+
837
+ subject { store_credit.invalidate(invalidation_reason, invalidation_user) }
838
+
839
+ it "sets the invalidated_at field to the current time" do
840
+ invalidated_at = Time.now
841
+ Timecop.freeze(invalidated_at) do
842
+ subject
843
+ expect(store_credit.invalidated_at).to eq invalidated_at
844
+ end
845
+ end
846
+
847
+ context "there is an uncaptured authorization" do
848
+ before { store_credit.authorize(5.0, "USD") }
849
+ it "prevents invalidation" do
850
+ expect { subject }.to_not change { store_credit.reload.invalidated_at }
851
+ expect(store_credit.errors[:invalidated_at].join).to match /uncaptured authorization/
852
+ end
853
+ end
854
+
855
+ context "there is a captured authorization" do
856
+ before do
857
+ auth_code = store_credit.authorize(5.0, "USD")
858
+ store_credit.capture(5.0, auth_code, "USD")
859
+ end
860
+
861
+ it "can invalidate the rest of the store credit" do
862
+ expect { subject }.to change { store_credit.reload.invalidated_at }
863
+ expect(store_credit.errors).to be_blank
864
+ end
865
+
866
+ it "creates a store credit event for the invalidation" do
867
+ expect { subject }.to change { store_credit.store_credit_events.where(action: Spree::StoreCredit::INVALIDATE_ACTION).count }.from(0).to(1)
868
+ end
869
+
870
+ it "assigns the originator as the user that is performing the invalidation" do
871
+ subject
872
+ expect(store_credit.store_credit_events.find_by(action: Spree::StoreCredit::INVALIDATE_ACTION).originator).to eq invalidation_user
873
+ end
874
+ end
875
+ end
876
+ end