spree_core 3.0.10 → 3.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (289) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/spree.js.coffee.erb +12 -3
  3. data/app/helpers/spree/base_helper.rb +4 -1
  4. data/app/helpers/spree/products_helper.rb +37 -6
  5. data/app/mailers/spree/base_mailer.rb +11 -2
  6. data/app/models/concerns/spree/adjustment_source.rb +3 -10
  7. data/app/models/concerns/spree/default_price.rb +7 -1
  8. data/app/models/concerns/spree/named_type.rb +1 -1
  9. data/app/models/concerns/spree/user_api_authentication.rb +7 -1
  10. data/app/models/concerns/spree/user_methods.rb +47 -0
  11. data/app/models/concerns/spree/user_reporting.rb +2 -2
  12. data/app/models/concerns/spree/vat_price_calculation.rb +47 -0
  13. data/app/models/spree/address.rb +8 -7
  14. data/app/models/spree/adjustable/adjuster/base.rb +25 -0
  15. data/app/models/spree/adjustable/adjuster/promotion.rb +41 -0
  16. data/app/models/spree/adjustable/adjuster/tax.rb +26 -0
  17. data/app/models/spree/adjustable/adjustments_updater.rb +22 -45
  18. data/app/models/spree/adjustment.rb +8 -10
  19. data/app/models/spree/app_configuration.rb +5 -2
  20. data/app/models/spree/base.rb +4 -0
  21. data/app/models/spree/calculator.rb +0 -5
  22. data/app/models/spree/calculator/default_tax.rb +2 -10
  23. data/app/models/spree/classification.rb +7 -3
  24. data/app/models/spree/country.rb +14 -3
  25. data/app/models/spree/credit_card.rb +21 -31
  26. data/app/models/spree/customer_return.rb +7 -15
  27. data/app/models/spree/gateway.rb +7 -6
  28. data/app/models/spree/image.rb +1 -1
  29. data/app/models/spree/inventory_unit.rb +9 -6
  30. data/app/models/spree/legacy_user.rb +1 -6
  31. data/app/models/spree/line_item.rb +69 -68
  32. data/app/models/spree/log_entry.rb +1 -4
  33. data/app/models/spree/option_type.rb +15 -6
  34. data/app/models/spree/option_type_prototype.rb +9 -0
  35. data/app/models/spree/option_value.rb +11 -3
  36. data/app/models/spree/option_value_variant.rb +6 -0
  37. data/app/models/spree/order.rb +113 -64
  38. data/app/models/spree/order/checkout.rb +8 -11
  39. data/app/models/spree/order/currency_updater.rb +1 -1
  40. data/app/models/spree/order/store_credit.rb +96 -0
  41. data/app/models/spree/order_contents.rb +6 -1
  42. data/app/models/spree/order_inventory.rb +4 -8
  43. data/app/models/spree/order_promotion.rb +6 -0
  44. data/app/models/spree/order_updater.rb +2 -7
  45. data/app/models/spree/payment.rb +46 -19
  46. data/app/models/spree/payment/gateway_options.rb +8 -4
  47. data/app/models/spree/payment_method.rb +12 -13
  48. data/app/models/spree/payment_method/store_credit.rb +130 -0
  49. data/app/models/spree/preference.rb +1 -1
  50. data/app/models/spree/price.rb +16 -6
  51. data/app/models/spree/product.rb +52 -49
  52. data/app/models/spree/product/scopes.rb +7 -2
  53. data/app/models/spree/product_option_type.rb +7 -2
  54. data/app/models/spree/product_promotion_rule.rb +9 -0
  55. data/app/models/spree/product_property.rb +8 -10
  56. data/app/models/spree/promotion.rb +19 -19
  57. data/app/models/spree/promotion/rules/product.rb +3 -1
  58. data/app/models/spree/promotion/rules/taxon.rb +2 -1
  59. data/app/models/spree/promotion/rules/user.rb +4 -4
  60. data/app/models/spree/promotion_action.rb +3 -3
  61. data/app/models/spree/promotion_category.rb +1 -1
  62. data/app/models/spree/promotion_rule_taxon.rb +9 -0
  63. data/app/models/spree/promotion_rule_user.rb +9 -0
  64. data/app/models/spree/property.rb +2 -1
  65. data/app/models/spree/property_prototype.rb +9 -0
  66. data/app/models/spree/prototype.rb +8 -3
  67. data/app/models/spree/prototype_taxon.rb +9 -0
  68. data/app/models/spree/refund.rb +10 -7
  69. data/app/models/spree/refund_reason.rb +1 -1
  70. data/app/models/spree/reimbursement.rb +12 -16
  71. data/app/models/spree/reimbursement_type/reimbursement_helpers.rb +23 -6
  72. data/app/models/spree/reimbursement_type/store_credit.rb +28 -0
  73. data/app/models/spree/return_authorization.rb +8 -13
  74. data/app/models/spree/return_authorization_reason.rb +1 -1
  75. data/app/models/spree/return_item.rb +13 -12
  76. data/app/models/spree/return_item/eligibility_validator/time_since_purchase.rb +1 -1
  77. data/app/models/spree/role.rb +3 -2
  78. data/app/models/spree/role_user.rb +6 -0
  79. data/app/models/spree/shipment.rb +18 -23
  80. data/app/models/spree/shipment_handler.rb +2 -2
  81. data/app/models/spree/shipping_category.rb +6 -3
  82. data/app/models/spree/shipping_method.rb +11 -10
  83. data/app/models/spree/shipping_method_zone.rb +6 -0
  84. data/app/models/spree/shipping_rate.rb +16 -29
  85. data/app/models/spree/state.rb +3 -2
  86. data/app/models/spree/state_change.rb +1 -1
  87. data/app/models/spree/stock/content_item.rb +10 -12
  88. data/app/models/spree/stock/coordinator.rb +13 -14
  89. data/app/models/spree/stock/estimator.rb +28 -30
  90. data/app/models/spree/stock/inventory_unit_builder.rb +1 -9
  91. data/app/models/spree/stock/packer.rb +1 -1
  92. data/app/models/spree/stock/quantifier.rb +5 -5
  93. data/app/models/spree/stock/splitter/backordered.rb +2 -2
  94. data/app/models/spree/stock_item.rb +12 -18
  95. data/app/models/spree/stock_location.rb +4 -7
  96. data/app/models/spree/stock_movement.rb +11 -9
  97. data/app/models/spree/stock_transfer.rb +11 -12
  98. data/app/models/spree/store.rb +14 -6
  99. data/app/models/spree/store_credit.rb +252 -0
  100. data/app/models/spree/store_credit_category.rb +22 -0
  101. data/app/models/spree/store_credit_event.rb +38 -0
  102. data/app/models/spree/store_credit_type.rb +6 -0
  103. data/app/models/spree/tax_category.rb +3 -8
  104. data/app/models/spree/tax_rate.rb +56 -122
  105. data/app/models/spree/taxon.rb +11 -5
  106. data/app/models/spree/tracker.rb +12 -1
  107. data/app/models/spree/validations/db_maximum_length_validator.rb +2 -1
  108. data/app/models/spree/variant.rb +82 -50
  109. data/app/models/spree/zone.rb +21 -17
  110. data/app/models/spree/zone_member.rb +6 -0
  111. data/app/validators/db_maximum_length_validator.rb +11 -0
  112. data/app/views/layouts/spree/base_mailer.html.erb +38 -781
  113. data/app/views/spree/order_mailer/_adjustment.html.erb +8 -0
  114. data/app/views/spree/order_mailer/_subtotal.html.erb +8 -0
  115. data/app/views/spree/order_mailer/_total.html.erb +8 -0
  116. data/app/views/spree/order_mailer/cancel_email.html.erb +13 -28
  117. data/app/views/spree/order_mailer/cancel_email.text.erb +1 -1
  118. data/app/views/spree/order_mailer/confirm_email.html.erb +49 -63
  119. data/app/views/spree/order_mailer/confirm_email.text.erb +1 -1
  120. data/app/views/spree/shared/_base_mailer_header.html.erb +5 -7
  121. data/app/views/spree/shared/_base_mailer_stylesheets.html.erb +777 -0
  122. data/app/views/spree/shared/_error_messages.html.erb +1 -1
  123. data/app/views/spree/shared/_mailer_line_item.html.erb +12 -0
  124. data/app/views/spree/shipment_mailer/shipped_email.html.erb +21 -14
  125. data/app/views/spree/shipment_mailer/shipped_email.text.erb +3 -3
  126. data/config/initializers/user_class_extensions.rb +7 -38
  127. data/config/locales/en.yml +113 -13
  128. data/config/routes.rb +7 -0
  129. data/db/default/spree/default_reimbursement_type.rb +1 -1
  130. data/db/default/spree/zones.rb +4 -5
  131. data/db/migrate/20150118210639_create_spree_store_credits.rb +24 -0
  132. data/db/migrate/20150118211500_create_spree_store_credit_categories.rb +8 -0
  133. data/db/migrate/20150118212051_create_spree_store_credit_events.rb +17 -0
  134. data/db/migrate/20150118212101_create_spree_store_credit_types.rb +10 -0
  135. data/db/migrate/20150314013438_add_missing_indexes.rb +25 -0
  136. data/db/migrate/20150317174308_remove_duplicated_indexes_from_multi_columns.rb +18 -0
  137. data/db/migrate/20150324104002_remove_user_index_from_spree_state_changes.rb +14 -0
  138. data/db/migrate/20150522071831_add_position_to_spree_payment_methods.rb +5 -0
  139. data/db/migrate/20150626181949_add_taxable_adjustment_total_to_line_item.rb +19 -0
  140. data/db/migrate/20150627090949_migrate_payment_methods_display.rb +12 -0
  141. data/db/migrate/20150714154102_spree_payment_method_store_credits.rb +12 -0
  142. data/db/migrate/20150726141425_rename_has_and_belongs_to_associations_to_model_names.rb +18 -0
  143. data/db/migrate/20150727191614_spree_store_credit_types.rb +11 -0
  144. data/db/migrate/20150819154308_add_discontinued_to_products_and_variants.rb +68 -0
  145. data/db/migrate/20151220072838_remove_shipping_method_id_from_spree_orders.rb +13 -0
  146. data/db/migrate/20160207191757_add_id_column_to_earlier_habtm_tables.rb +16 -0
  147. data/db/migrate/20160219165458_add_indexes.rb +14 -0
  148. data/lib/generators/spree/dummy/templates/rails/database.yml +31 -24
  149. data/lib/generators/spree/dummy/templates/rails/test.rb +2 -1
  150. data/lib/spree/core.rb +16 -0
  151. data/lib/spree/core/controller_helpers/auth.rb +1 -1
  152. data/lib/spree/core/controller_helpers/common.rb +3 -3
  153. data/lib/spree/core/controller_helpers/order.rb +6 -5
  154. data/lib/spree/core/controller_helpers/search.rb +1 -1
  155. data/lib/spree/core/controller_helpers/store.rb +29 -0
  156. data/lib/spree/core/delegate_belongs_to.rb +2 -2
  157. data/lib/spree/core/engine.rb +30 -25
  158. data/lib/spree/core/environment.rb +1 -1
  159. data/lib/spree/core/importer/order.rb +37 -40
  160. data/lib/spree/core/number_generator.rb +52 -0
  161. data/lib/spree/core/product_filters.rb +1 -1
  162. data/lib/spree/core/search/base.rb +4 -3
  163. data/lib/spree/core/version.rb +1 -1
  164. data/lib/spree/localized_number.rb +3 -1
  165. data/lib/spree/permitted_attributes.rb +5 -2
  166. data/lib/spree/testing_support/common_rake.rb +3 -3
  167. data/lib/spree/testing_support/factories.rb +3 -3
  168. data/lib/spree/testing_support/factories/address_factory.rb +1 -1
  169. data/lib/spree/testing_support/factories/country_factory.rb +2 -2
  170. data/lib/spree/testing_support/factories/order_factory.rb +2 -2
  171. data/lib/spree/testing_support/factories/payment_factory.rb +5 -0
  172. data/lib/spree/testing_support/factories/payment_method_factory.rb +8 -0
  173. data/lib/spree/testing_support/factories/promotion_rule_factory.rb +5 -0
  174. data/lib/spree/testing_support/factories/refund_factory.rb +9 -1
  175. data/lib/spree/testing_support/factories/return_authorization_factory.rb +2 -0
  176. data/lib/spree/testing_support/factories/state_factory.rb +2 -2
  177. data/lib/spree/testing_support/factories/store_credit_category_factory.rb +9 -0
  178. data/lib/spree/testing_support/factories/store_credit_event_factory.rb +8 -0
  179. data/lib/spree/testing_support/factories/store_credit_factory.rb +17 -0
  180. data/lib/spree/testing_support/factories/store_credit_type_factory.rb +11 -0
  181. data/lib/spree/testing_support/factories/user_factory.rb +1 -1
  182. data/lib/spree/testing_support/factories/zone_member_factory.rb +6 -0
  183. data/lib/spree/testing_support/microdata.rb +189 -0
  184. data/lib/tasks/core.rake +68 -0
  185. data/lib/tasks/exchanges.rake +2 -2
  186. data/spec/fixtures/microdata.html +22 -0
  187. data/spec/fixtures/microdata_itemref.html +15 -0
  188. data/spec/fixtures/microdata_no_itemscope.html +20 -0
  189. data/spec/helpers/base_helper_spec.rb +64 -1
  190. data/spec/helpers/products_helper_spec.rb +75 -3
  191. data/spec/lib/i18n_spec.rb +2 -2
  192. data/spec/lib/search/base_spec.rb +2 -2
  193. data/spec/lib/spree/core/controller_helpers/auth_spec.rb +4 -2
  194. data/spec/lib/spree/core/controller_helpers/store_spec.rb +56 -0
  195. data/spec/lib/spree/core/importer/order_spec.rb +226 -123
  196. data/spec/lib/spree/core/number_generator_spec.rb +175 -0
  197. data/spec/lib/spree/core_spec.rb +23 -0
  198. data/spec/lib/spree/localized_number_spec.rb +10 -0
  199. data/spec/mailers/order_mailer_spec.rb +11 -13
  200. data/spec/mailers/shipment_mailer_spec.rb +26 -8
  201. data/spec/mailers/test_mailer_spec.rb +15 -1
  202. data/spec/models/option_type_prototype_spec.rb +9 -0
  203. data/spec/models/spree/ability_spec.rb +6 -13
  204. data/spec/models/spree/address_spec.rb +1 -1
  205. data/spec/models/spree/adjustable/adjuster/base_spec.rb +10 -0
  206. data/spec/models/spree/adjustable/adjuster/promotion_spec.rb +211 -0
  207. data/spec/models/spree/adjustable/adjuster/tax_spec.rb +86 -0
  208. data/spec/models/spree/adjustable/adjustments_updater_spec.rb +2 -262
  209. data/spec/models/spree/adjustment_spec.rb +27 -1
  210. data/spec/models/spree/app_configuration_spec.rb +5 -2
  211. data/spec/models/spree/calculator/default_tax_spec.rb +39 -14
  212. data/spec/models/spree/concerns/user_methods_spec.rb +55 -0
  213. data/spec/models/spree/concerns/vat_price_calculation_spec.rb +66 -0
  214. data/spec/models/spree/country_spec.rb +45 -8
  215. data/spec/models/spree/credit_card_spec.rb +8 -8
  216. data/spec/models/spree/customer_return_spec.rb +4 -26
  217. data/spec/models/spree/gateway_spec.rb +7 -0
  218. data/spec/models/spree/image_spec.rb +3 -0
  219. data/spec/models/spree/inventory_unit_spec.rb +1 -18
  220. data/spec/models/spree/line_item_spec.rb +78 -18
  221. data/spec/models/spree/option_type_spec.rb +2 -2
  222. data/spec/models/spree/option_value_spec.rb +8 -3
  223. data/spec/models/spree/order/checkout_spec.rb +49 -39
  224. data/spec/models/spree/order/currency_updater_spec.rb +3 -3
  225. data/spec/models/spree/order/finalizing_spec.rb +0 -3
  226. data/spec/models/spree/order/payment_spec.rb +1 -1
  227. data/spec/models/spree/order/state_machine_spec.rb +1 -6
  228. data/spec/models/spree/order/store_credit_spec.rb +423 -0
  229. data/spec/models/spree/order/updating_spec.rb +2 -2
  230. data/spec/models/spree/order_contents_spec.rb +42 -1
  231. data/spec/models/spree/order_inventory_spec.rb +27 -17
  232. data/spec/models/spree/order_spec.rb +65 -52
  233. data/spec/models/spree/payment/gateway_options_spec.rb +10 -2
  234. data/spec/models/spree/payment/store_credit_spec.rb +60 -0
  235. data/spec/models/spree/payment_method/store_credit_spec.rb +291 -0
  236. data/spec/models/spree/payment_method_spec.rb +22 -14
  237. data/spec/models/spree/payment_spec.rb +37 -44
  238. data/spec/models/spree/price_spec.rb +86 -0
  239. data/spec/models/spree/product/scopes_spec.rb +35 -0
  240. data/spec/models/spree/product_option_type_spec.rb +6 -2
  241. data/spec/models/spree/product_promotion_rule_spec.rb +9 -0
  242. data/spec/models/spree/product_property_spec.rb +11 -0
  243. data/spec/models/spree/product_spec.rb +82 -15
  244. data/spec/models/spree/promotion/actions/create_item_adjustments_spec.rb +1 -1
  245. data/spec/models/spree/promotion/rules/user_spec.rb +8 -0
  246. data/spec/models/spree/promotion_action_spec.rb +1 -1
  247. data/spec/models/spree/promotion_rule_spec.rb +1 -1
  248. data/spec/models/spree/promotion_rule_taxon_spec.rb +9 -0
  249. data/spec/models/spree/promotion_rule_user_spec.rb +9 -0
  250. data/spec/models/spree/promotion_spec.rb +57 -36
  251. data/spec/models/spree/property_prototype_spec.rb +9 -0
  252. data/spec/models/spree/prototype_taxon_spec.rb +9 -0
  253. data/spec/models/spree/refund_reason_spec.rb +7 -0
  254. data/spec/models/spree/reimbursement_spec.rb +3 -30
  255. data/spec/models/spree/reimbursement_tax_calculator_spec.rb +17 -5
  256. data/spec/models/spree/reimbursement_type/store_credit_spec.rb +101 -0
  257. data/spec/models/spree/return_authorization_reason_spec.rb +7 -0
  258. data/spec/models/spree/return_authorization_spec.rb +2 -22
  259. data/spec/models/spree/return_item_spec.rb +50 -1
  260. data/spec/models/spree/returns_calculator_spec.rb +1 -1
  261. data/spec/models/spree/role_spec.rb +7 -0
  262. data/spec/models/spree/shipment_spec.rb +17 -17
  263. data/spec/models/spree/shipping_calculator_spec.rb +2 -2
  264. data/spec/models/spree/shipping_category_spec.rb +14 -0
  265. data/spec/models/spree/shipping_method_spec.rb +9 -2
  266. data/spec/models/spree/shipping_rate_spec.rb +40 -41
  267. data/spec/models/spree/state_spec.rb +12 -1
  268. data/spec/models/spree/stock/content_item_spec.rb +9 -0
  269. data/spec/models/spree/stock/estimator_spec.rb +56 -8
  270. data/spec/models/spree/stock/quantifier_spec.rb +61 -32
  271. data/spec/models/spree/stock_item_spec.rb +19 -1
  272. data/spec/models/spree/store_credit_event_spec.rb +101 -0
  273. data/spec/models/spree/store_credit_spec.rb +786 -0
  274. data/spec/models/spree/store_spec.rb +39 -11
  275. data/spec/models/spree/tax_category_spec.rb +6 -1
  276. data/spec/models/spree/tax_rate_spec.rb +204 -44
  277. data/spec/models/spree/user_spec.rb +105 -38
  278. data/spec/models/spree/variant_spec.rb +281 -9
  279. data/spec/models/spree/zone_member_spec.rb +38 -0
  280. data/spec/models/spree/zone_spec.rb +32 -8
  281. data/spec/spec_helper.rb +3 -0
  282. data/spec/support/concerns/{adjustment_source_spec.rb → adjustment_source.rb} +0 -0
  283. data/spec/support/concerns/{default_price_spec.rb → default_price.rb} +9 -0
  284. data/spec/validators/db_maximum_length_validator_spec.rb +22 -0
  285. data/spree_core.gemspec +5 -6
  286. metadata +99 -36
  287. data/CHANGELOG.md +0 -4
  288. data/app/models/concerns/spree/number_generator.rb +0 -39
  289. data/spec/models/spree/validations/db_maximum_length_validator_spec.rb +0 -24
@@ -1,7 +1,12 @@
1
1
  module Spree
2
2
  class ProductOptionType < Spree::Base
3
- belongs_to :product, class_name: 'Spree::Product', inverse_of: :product_option_types
4
- belongs_to :option_type, class_name: 'Spree::OptionType', inverse_of: :product_option_types
3
+ with_options inverse_of: :product_option_types do
4
+ belongs_to :product, class_name: 'Spree::Product'
5
+ belongs_to :option_type, class_name: 'Spree::OptionType'
6
+ end
5
7
  acts_as_list scope: :product
8
+
9
+ validates :product, :option_type, presence: true
10
+ validates :product_id, uniqueness: { scope: :option_type_id }, allow_nil: true
6
11
  end
7
12
  end
@@ -0,0 +1,9 @@
1
+ module Spree
2
+ class ProductPromotionRule < Spree::Base
3
+ belongs_to :product, class_name: 'Spree::Product'
4
+ belongs_to :promotion_rule, class_name: 'Spree::PromotionRule'
5
+
6
+ validates :product, :promotion_rule, presence: true
7
+ validates :product_id, uniqueness: { scope: :promotion_rule_id }, allow_nil: true
8
+ end
9
+ end
@@ -2,28 +2,26 @@ module Spree
2
2
  class ProductProperty < Spree::Base
3
3
  acts_as_list scope: :product
4
4
 
5
- belongs_to :product, touch: true, class_name: 'Spree::Product', inverse_of: :product_properties
6
- belongs_to :property, class_name: 'Spree::Property', inverse_of: :product_properties
5
+ with_options inverse_of: :product_properties do
6
+ belongs_to :product, touch: true, class_name: 'Spree::Product'
7
+ belongs_to :property, class_name: 'Spree::Property'
8
+ end
7
9
 
8
10
  validates :property, presence: true
9
11
 
10
- validates_with Spree::Validations::DbMaximumLengthValidator, field: :value
12
+ validates :value, db_maximum_length: true
11
13
 
12
- default_scope { order("#{self.table_name}.position") }
14
+ default_scope { order(:position) }
13
15
 
14
16
  self.whitelisted_ransackable_attributes = ['value']
15
17
 
16
18
  # virtual attributes for use with AJAX completion stuff
17
- def property_name
18
- property.name if property
19
- end
19
+ delegate :name, to: :property, prefix: true, allow_nil: true
20
20
 
21
21
  def property_name=(name)
22
22
  if name.present?
23
23
  # don't use `find_by :name` to workaround globalize/globalize#423 bug
24
- property = Property.where(name: name).first ||
25
- Property.create(name: name, presentation: name)
26
- self.property = property
24
+ self.property = Property.where(name: name).first_or_create(presentation: name)
27
25
  end
28
26
  end
29
27
  end
@@ -13,7 +13,8 @@ module Spree
13
13
  has_many :promotion_actions, autosave: true, dependent: :destroy
14
14
  alias_method :actions, :promotion_actions
15
15
 
16
- has_and_belongs_to_many :orders, join_table: 'spree_orders_promotions'
16
+ has_many :order_promotions, class_name: 'Spree::OrderPromotion'
17
+ has_many :orders, through: :order_promotions, class_name: 'Spree::Order'
17
18
 
18
19
  accepts_nested_attributes_for :promotion_actions, :promotion_rules
19
20
 
@@ -22,29 +23,28 @@ module Spree
22
23
  validates :name, presence: true
23
24
  validates :path, uniqueness: { allow_blank: true }
24
25
  validates :usage_limit, numericality: { greater_than: 0, allow_nil: true }
25
- validates :description, length: { maximum: 255 }
26
+ validates :description, length: { maximum: 255 }, allow_blank: true
26
27
 
27
28
  before_save :normalize_blank_values
28
29
 
29
- scope :coupons, ->{ where("#{table_name}.code IS NOT NULL") }
30
+ scope :coupons, -> { where.not(code: nil) }
31
+ scope :advertised, -> { where(advertise: true) }
32
+ scope :applied, lambda {
33
+ joins(<<-SQL).uniq
34
+ INNER JOIN spree_order_promotions
35
+ ON spree_order_promotions.promotion_id = #{table_name}.id
36
+ SQL
37
+ }
30
38
 
31
- order_join_table = reflect_on_association(:orders).join_table
32
-
33
- scope :applied, -> { joins("INNER JOIN #{order_join_table} ON #{order_join_table}.promotion_id = #{table_name}.id").uniq }
34
-
35
- self.whitelisted_ransackable_attributes = ['code', 'path', 'promotion_category_id']
36
-
37
- def self.advertised
38
- where(advertise: true)
39
- end
39
+ self.whitelisted_ransackable_attributes = ['path', 'promotion_category_id', 'code']
40
40
 
41
41
  def self.with_coupon_code(coupon_code)
42
- where("lower(#{self.table_name}.code) = ?", coupon_code.strip.downcase).first
42
+ where("lower(#{table_name}.code) = ?", coupon_code.strip.downcase).first
43
43
  end
44
44
 
45
45
  def self.active
46
- where('spree_promotions.starts_at IS NULL OR spree_promotions.starts_at < ?', Time.now).
47
- where('spree_promotions.expires_at IS NULL OR spree_promotions.expires_at > ?', Time.now)
46
+ where('spree_promotions.starts_at IS NULL OR spree_promotions.starts_at < ?', Time.current).
47
+ where('spree_promotions.expires_at IS NULL OR spree_promotions.expires_at > ?', Time.current)
48
48
  end
49
49
 
50
50
  def self.order_activatable?(order)
@@ -52,7 +52,7 @@ module Spree
52
52
  end
53
53
 
54
54
  def expired?
55
- !!(starts_at && Time.now < starts_at || expires_at && Time.now > expires_at)
55
+ !!(starts_at && Time.current < starts_at || expires_at && Time.current > expires_at)
56
56
  end
57
57
 
58
58
  def activate(payload)
@@ -77,10 +77,10 @@ module Spree
77
77
  self.save
78
78
  end
79
79
 
80
- return action_taken
80
+ action_taken
81
81
  end
82
82
 
83
- # called anytime order.update! happens
83
+ # called anytime order.update_with_updater! happens
84
84
  def eligible?(promotable)
85
85
  return false if expired? || usage_limit_exceeded?(promotable) || blacklisted?(promotable)
86
86
  !!eligible_rules(promotable, {})
@@ -128,7 +128,7 @@ module Spree
128
128
 
129
129
  def adjusted_credits_count(promotable)
130
130
  adjustments = promotable.is_a?(Order) ? promotable.all_adjustments : promotable.adjustments
131
- credits_count - adjustments.promotion.where(:source_id => actions.pluck(:id)).count
131
+ credits_count - adjustments.promotion.where(source_id: actions.pluck(:id)).size
132
132
  end
133
133
 
134
134
  def credits
@@ -5,7 +5,9 @@ module Spree
5
5
  class Promotion
6
6
  module Rules
7
7
  class Product < PromotionRule
8
- has_and_belongs_to_many :products, class_name: '::Spree::Product', join_table: 'spree_products_promotion_rules', foreign_key: 'promotion_rule_id'
8
+ has_many :product_promotion_rules, class_name: 'Spree::ProductPromotionRule',
9
+ foreign_key: :promotion_rule_id
10
+ has_many :products, through: :product_promotion_rules, class_name: 'Spree::Product'
9
11
 
10
12
  MATCH_POLICIES = %w(any all none)
11
13
  preference :match_policy, :string, default: MATCH_POLICIES.first
@@ -2,7 +2,8 @@ module Spree
2
2
  class Promotion
3
3
  module Rules
4
4
  class Taxon < PromotionRule
5
- has_and_belongs_to_many :taxons, class_name: '::Spree::Taxon', join_table: 'spree_taxons_promotion_rules', foreign_key: 'promotion_rule_id'
5
+ has_many :promotion_rule_taxons, class_name: 'Spree::PromotionRuleTaxon', foreign_key: 'promotion_rule_id'
6
+ has_many :taxons, through: :promotion_rule_taxons, class_name: 'Spree::Taxon'
6
7
 
7
8
  MATCH_POLICIES = %w(any all)
8
9
  preference :match_policy, default: MATCH_POLICIES.first
@@ -4,10 +4,10 @@ module Spree
4
4
  class User < PromotionRule
5
5
  belongs_to :user, class_name: "::#{Spree.user_class.to_s}"
6
6
 
7
- has_and_belongs_to_many :users, class_name: "::#{Spree.user_class.to_s}",
8
- join_table: 'spree_promotion_rules_users',
9
- foreign_key: 'promotion_rule_id',
10
- association_foreign_key: :user_id
7
+ has_many :promotion_rule_users, class_name: 'Spree::PromotionRuleUser',
8
+ foreign_key: :promotion_rule_id,
9
+ dependent: :destroy
10
+ has_many :users, through: :promotion_rule_users, class_name: "::#{Spree.user_class.to_s}"
11
11
 
12
12
  def applicable?(promotable)
13
13
  promotable.is_a?(Spree::Order)
@@ -1,4 +1,4 @@
1
- # Base class for all types of promotion action.
1
+ ## Base class for all types of promotion action.
2
2
  # PromotionActions perform the necessary tasks when a promotion is activated by an event and determined to be eligible.
3
3
  module Spree
4
4
  class PromotionAction < Spree::Base
@@ -18,8 +18,8 @@ module Spree
18
18
 
19
19
  protected
20
20
 
21
- def label(amount)
22
- "#{Spree.t(:promotion)} (#{promotion.name})"
21
+ def label
22
+ Spree.t(:promotion_label, name: promotion.name)
23
23
  end
24
24
  end
25
25
  end
@@ -1,6 +1,6 @@
1
1
  module Spree
2
2
  class PromotionCategory < Spree::Base
3
- validates_presence_of :name
3
+ validates :name, presence: true
4
4
  has_many :promotions
5
5
  end
6
6
  end
@@ -0,0 +1,9 @@
1
+ module Spree
2
+ class PromotionRuleTaxon < Spree::Base
3
+ belongs_to :promotion_rule, class_name: 'Spree::PromotionRule'
4
+ belongs_to :taxon, class_name: 'Spree::Taxon'
5
+
6
+ validates :promotion_rule, :taxon, presence: true
7
+ validates :promotion_rule_id, uniqueness: { scope: :taxon_id }, allow_nil: true
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Spree
2
+ class PromotionRuleUser < Spree::Base
3
+ belongs_to :promotion_rule, class_name: 'Spree::PromotionRule'
4
+ belongs_to :user, class_name: Spree.user_class
5
+
6
+ validates :user, :promotion_rule, presence: true
7
+ validates :user_id, uniqueness: { scope: :promotion_rule_id }, allow_nil: true
8
+ end
9
+ end
@@ -1,6 +1,7 @@
1
1
  module Spree
2
2
  class Property < Spree::Base
3
- has_and_belongs_to_many :prototypes, join_table: 'spree_properties_prototypes'
3
+ has_many :property_prototypes, class_name: 'Spree::PropertyPrototype'
4
+ has_many :prototypes, through: :property_prototypes, class_name: 'Spree::Prototype'
4
5
 
5
6
  has_many :product_properties, dependent: :delete_all, inverse_of: :property
6
7
  has_many :products, through: :product_properties
@@ -0,0 +1,9 @@
1
+ module Spree
2
+ class PropertyPrototype < Spree::Base
3
+ belongs_to :prototype, class_name: 'Spree::Prototype'
4
+ belongs_to :property, class_name: 'Spree::Property'
5
+
6
+ validates :prototype, :property, presence: true
7
+ validates :prototype_id, uniqueness: { scope: :property_id }, allow_nil: true
8
+ end
9
+ end
@@ -1,8 +1,13 @@
1
1
  module Spree
2
2
  class Prototype < Spree::Base
3
- has_and_belongs_to_many :properties, join_table: :spree_properties_prototypes
4
- has_and_belongs_to_many :option_types, join_table: :spree_option_types_prototypes
5
- has_and_belongs_to_many :taxons, join_table: :spree_taxons_prototypes
3
+ has_many :property_prototypes, class_name: 'Spree::PropertyPrototype'
4
+ has_many :properties, through: :property_prototypes, class_name: 'Spree::Property'
5
+
6
+ has_many :option_type_prototypes, class_name: 'Spree::OptionTypePrototype'
7
+ has_many :option_types, through: :option_type_prototypes, class_name: 'Spree::OptionType'
8
+
9
+ has_many :prototype_taxons, class_name: 'Spree::PrototypeTaxon'
10
+ has_many :taxons, through: :prototype_taxons, class_name: 'Spree::Taxon'
6
11
 
7
12
  validates :name, presence: true
8
13
  end
@@ -0,0 +1,9 @@
1
+ module Spree
2
+ class PrototypeTaxon < Spree::Base
3
+ belongs_to :taxon, class_name: 'Spree::Taxon'
4
+ belongs_to :prototype, class_name: 'Spree::Prototype'
5
+
6
+ validates :prototype, :taxon, presence: true
7
+ validates :prototype_id, uniqueness: { scope: :taxon_id }, allow_nil: true
8
+ end
9
+ end
@@ -1,16 +1,19 @@
1
1
  module Spree
2
2
  class Refund < Spree::Base
3
- belongs_to :payment, inverse_of: :refunds
3
+ with_options inverse_of: :refunds do
4
+ belongs_to :payment
5
+ belongs_to :reimbursement
6
+ end
4
7
  belongs_to :reason, class_name: 'Spree::RefundReason', foreign_key: :refund_reason_id
5
- belongs_to :reimbursement, inverse_of: :refunds
6
8
 
7
9
  has_many :log_entries, as: :source
8
10
 
9
- validates :payment, presence: true
10
- validates :reason, presence: true
11
- validates :transaction_id, presence: true, on: :update # can't require this on create because the before_create needs to run first
12
- validates :amount, presence: true, numericality: {greater_than: 0}
13
-
11
+ with_options presence: true do
12
+ validates :payment, :reason
13
+ # can't require this on create because the perform! in after_create needs to run first
14
+ validates :transaction_id, on: :update
15
+ validates :amount, numericality: { greater_than: 0, allow_nil: true }
16
+ end
14
17
  validate :amount_is_less_than_or_equal_to_allowed_amount, on: :create
15
18
 
16
19
  after_create :perform!
@@ -4,7 +4,7 @@ module Spree
4
4
 
5
5
  RETURN_PROCESSING_REASON = 'Return processing'
6
6
 
7
- has_many :refunds
7
+ has_many :refunds, dependent: :restrict_with_error
8
8
 
9
9
  def self.return_processing_reason
10
10
  find_by!(name: RETURN_PROCESSING_REASON, mutable: false)
@@ -1,22 +1,25 @@
1
1
  module Spree
2
2
  class Reimbursement < Spree::Base
3
- class IncompleteReimbursementError < StandardError; end
3
+ include Spree::Core::NumberGenerator.new(prefix: 'RI', length: 9)
4
4
 
5
- belongs_to :order, inverse_of: :reimbursements
6
- belongs_to :customer_return, inverse_of: :reimbursements, touch: true
5
+ class IncompleteReimbursementError < StandardError; end
7
6
 
8
- has_many :refunds, inverse_of: :reimbursement
9
- has_many :credits, inverse_of: :reimbursement, class_name: 'Spree::Reimbursement::Credit'
7
+ with_options inverse_of: :reimbursements do
8
+ belongs_to :order
9
+ belongs_to :customer_return, touch: true
10
+ end
10
11
 
11
- has_many :return_items, inverse_of: :reimbursement
12
+ with_options inverse_of: :reimbursement do
13
+ has_many :refunds
14
+ has_many :credits, class_name: 'Spree::Reimbursement::Credit'
15
+ has_many :return_items
16
+ end
12
17
 
13
18
  validates :order, presence: true
14
19
  validate :validate_return_items_belong_to_same_order
15
20
 
16
21
  accepts_nested_attributes_for :return_items, allow_destroy: true
17
22
 
18
- before_create :generate_number
19
-
20
23
  scope :reimbursed, -> { where(reimbursement_status: 'reimbursed') }
21
24
 
22
25
  # The reimbursement_tax_calculator property should be set to an object that responds to "call"
@@ -130,13 +133,6 @@ module Spree
130
133
 
131
134
  private
132
135
 
133
- def generate_number
134
- self.number ||= loop do
135
- random = "RI#{Array.new(9){rand(9)}.join}"
136
- break random unless self.class.exists?(number: random)
137
- end
138
- end
139
-
140
136
  def validate_return_items_belong_to_same_order
141
137
  if return_items.any? { |ri| ri.inventory_unit.order_id != order_id }
142
138
  errors.add(:base, :return_items_order_id_does_not_match)
@@ -154,7 +150,7 @@ module Spree
154
150
  # payments and credits have already been processed, we should allow the
155
151
  # reimbursement to show as 'reimbursed' and not 'errored'.
156
152
  def unpaid_amount_within_tolerance?
157
- reimbursement_count = reimbursement_models.count do |model|
153
+ reimbursement_count = reimbursement_models.size do |model|
158
154
  model.total_amount_reimbursed_for(self) > 0
159
155
  end
160
156
  leniency = if reimbursement_count > 0
@@ -10,7 +10,7 @@ module Spree
10
10
  unpaid_amount -= amount
11
11
  end
12
12
 
13
- return reimbursement_list, unpaid_amount
13
+ [reimbursement_list, unpaid_amount]
14
14
  end
15
15
 
16
16
  def create_credits(reimbursement, unpaid_amount, simulate, reimbursement_list = [])
@@ -18,17 +18,17 @@ module Spree
18
18
  unpaid_amount -= credits.sum(&:amount)
19
19
  reimbursement_list += credits
20
20
 
21
- return reimbursement_list, unpaid_amount
21
+ [reimbursement_list, unpaid_amount]
22
22
  end
23
23
 
24
24
  private
25
25
 
26
26
  def create_refund(reimbursement, payment, amount, simulate)
27
- refund = reimbursement.refunds.build({
27
+ refund = reimbursement.refunds.build(
28
28
  payment: payment,
29
29
  amount: amount,
30
- reason: Spree::RefundReason.return_processing_reason,
31
- })
30
+ reason: Spree::RefundReason.return_processing_reason
31
+ )
32
32
 
33
33
  simulate ? refund.readonly! : refund.save!
34
34
  refund
@@ -44,7 +44,24 @@ module Spree
44
44
  end
45
45
 
46
46
  def create_creditable(reimbursement, unpaid_amount)
47
- Spree::Reimbursement::Credit.default_creditable_class.new(reimbursement: reimbursement, amount: unpaid_amount)
47
+ category = Spree::StoreCreditCategory.default_reimbursement_category(category_options(reimbursement))
48
+ Spree::StoreCredit.new(store_credit_params(category, reimbursement, unpaid_amount))
49
+ end
50
+
51
+ def store_credit_params(category, reimbursement, unpaid_amount)
52
+ {
53
+ user: reimbursement.order.user,
54
+ amount: unpaid_amount,
55
+ category: category,
56
+ created_by: Spree::StoreCredit.default_created_by,
57
+ memo: "Refund for uncreditable payments on order #{reimbursement.order.number}",
58
+ currency: reimbursement.order.currency
59
+ }
60
+ end
61
+
62
+ # overwrite if you need options for the default reimbursement category
63
+ def category_options(_reimbursement)
64
+ {}
48
65
  end
49
66
  end
50
67
  end
@@ -0,0 +1,28 @@
1
+ class Spree::ReimbursementType::StoreCredit < Spree::ReimbursementType
2
+ extend Spree::ReimbursementType::ReimbursementHelpers
3
+
4
+ class << self
5
+ def reimburse(reimbursement, return_items, simulate)
6
+ unpaid_amount = return_items.sum(&:total).to_d.round(2, :down)
7
+ payments = store_credit_payments(reimbursement)
8
+ reimbursement_list = []
9
+
10
+ # Credit each store credit that was used on the order
11
+ reimbursement_list, unpaid_amount = create_refunds(reimbursement, payments, unpaid_amount,
12
+ simulate, reimbursement_list)
13
+
14
+ # If there is any amount left to pay out to the customer, then create credit with that amount
15
+ if unpaid_amount > 0.0
16
+ reimbursement_list, _unpaid_amount = create_credits(reimbursement, unpaid_amount, simulate, reimbursement_list)
17
+ end
18
+
19
+ reimbursement_list
20
+ end
21
+
22
+ private
23
+
24
+ def store_credit_payments(reimbursement)
25
+ reimbursement.order.payments.completed.store_credits
26
+ end
27
+ end
28
+ end