solidus_core 2.1.1 → 2.2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of solidus_core might be problematic. Click here for more details.

Files changed (145) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +0 -1
  3. data/app/assets/config/solidus_core_manifest.js +1 -0
  4. data/app/assets/javascripts/spree.js.erb +72 -0
  5. data/app/helpers/spree/store_helper.rb +5 -0
  6. data/app/jobs/spree/promotion_code_batch_job.rb +24 -0
  7. data/app/mailers/spree/promotion_code_batch_mailer.rb +13 -0
  8. data/app/models/concerns/spree/calculated_adjustments.rb +1 -1
  9. data/app/models/concerns/spree/ordered_property_value_list.rb +2 -2
  10. data/app/models/concerns/spree/user_address_book.rb +4 -4
  11. data/app/models/concerns/spree/user_methods.rb +7 -0
  12. data/app/models/concerns/spree/user_payment_source.rb +12 -5
  13. data/app/models/spree/address.rb +14 -3
  14. data/app/models/spree/adjustment.rb +13 -1
  15. data/app/models/spree/app_configuration.rb +0 -19
  16. data/app/models/spree/base.rb +2 -0
  17. data/app/models/spree/credit_card.rb +34 -43
  18. data/app/models/spree/gateway/bogus.rb +1 -1
  19. data/app/models/spree/gateway.rb +6 -4
  20. data/app/models/spree/inventory_unit.rb +3 -2
  21. data/app/models/spree/order/checkout.rb +187 -273
  22. data/app/models/spree/order.rb +137 -71
  23. data/app/models/spree/order_contents.rb +1 -1
  24. data/app/models/spree/order_inventory.rb +11 -11
  25. data/app/models/spree/order_promotion.rb +2 -0
  26. data/app/models/spree/order_update_attributes.rb +1 -8
  27. data/app/models/spree/order_updater.rb +67 -63
  28. data/app/models/spree/payment.rb +0 -1
  29. data/app/models/spree/payment_create.rb +27 -7
  30. data/app/models/spree/payment_method/store_credit.rb +3 -3
  31. data/app/models/spree/payment_method.rb +4 -1
  32. data/app/models/spree/payment_source.rb +45 -0
  33. data/app/models/spree/product/scopes.rb +24 -24
  34. data/app/models/spree/product.rb +4 -4
  35. data/app/models/spree/promotion.rb +2 -0
  36. data/app/models/spree/promotion_code/batch_builder.rb +63 -0
  37. data/app/models/spree/promotion_code.rb +1 -0
  38. data/app/models/spree/promotion_code_batch.rb +25 -0
  39. data/app/models/spree/promotion_handler/cart.rb +2 -2
  40. data/app/models/spree/promotion_handler/coupon.rb +1 -2
  41. data/app/models/spree/promotion_handler/free_shipping.rb +32 -21
  42. data/app/models/spree/promotion_handler/page.rb +1 -1
  43. data/app/models/spree/reimbursement.rb +1 -1
  44. data/app/models/spree/return_authorization.rb +0 -28
  45. data/app/models/spree/return_item.rb +1 -1
  46. data/app/models/spree/shipment.rb +4 -4
  47. data/app/models/spree/shipping_method.rb +2 -2
  48. data/app/models/spree/shipping_rate.rb +1 -1
  49. data/app/models/spree/stock/availability_validator.rb +16 -17
  50. data/app/models/spree/stock/coordinator.rb +3 -3
  51. data/app/models/spree/stock/package.rb +1 -1
  52. data/app/models/spree/stock/quantifier.rb +5 -4
  53. data/app/models/spree/stock_location.rb +2 -2
  54. data/app/models/spree/store.rb +2 -2
  55. data/app/models/spree/store_credit.rb +1 -1
  56. data/app/models/spree/tax/tax_helpers.rb +3 -3
  57. data/app/models/spree/tax_rate.rb +7 -1
  58. data/app/models/spree/taxonomy.rb +1 -1
  59. data/app/models/spree/variant/scopes.rb +5 -5
  60. data/app/models/spree/variant/vat_price_generator.rb +8 -5
  61. data/app/models/spree/variant.rb +1 -0
  62. data/app/models/spree/wallet/add_payment_sources_to_wallet.rb +19 -10
  63. data/app/models/spree/wallet/default_payment_builder.rb +6 -6
  64. data/app/models/spree/wallet.rb +71 -0
  65. data/app/models/spree/wallet_payment_source.rb +17 -0
  66. data/app/models/spree/zone.rb +1 -1
  67. data/app/views/spree/carton_mailer/shipped_email.text.erb +1 -1
  68. data/app/views/spree/promotion_code_batch_mailer/promotion_code_batch_errored.text.erb +2 -0
  69. data/app/views/spree/promotion_code_batch_mailer/promotion_code_batch_finished.text.erb +2 -0
  70. data/app/views/spree/reimbursement_mailer/reimbursement_email.html.erb +0 -7
  71. data/app/views/spree/reimbursement_mailer/reimbursement_email.text.erb +0 -5
  72. data/app/views/spree/shared/_error_messages.html.erb +1 -1
  73. data/app/views/spree/shipment_mailer/shipped_email.html.erb +1 -1
  74. data/config/initializers/assets.rb +1 -1
  75. data/config/initializers/friendly_id.rb +1 -1
  76. data/config/locales/en.yml +50 -12
  77. data/db/default/spree/store_credit.rb +2 -1
  78. data/db/migrate/20130826062534_add_depth_to_spree_taxons.rb +4 -6
  79. data/db/migrate/20160420044191_create_spree_wallet_payment_sources.rb +23 -0
  80. data/db/migrate/20160420181916_migrate_credit_cards_to_wallet_payment_sources.rb +26 -0
  81. data/db/migrate/20161017102621_create_spree_promotion_code_batch.rb +36 -0
  82. data/db/migrate/20161129035810_add_index_to_spree_payments_number.rb +5 -0
  83. data/db/migrate/20170223235001_remove_spree_store_credits_column.rb +5 -0
  84. data/lib/generators/spree/dummy/templates/rails/application.rb +1 -1
  85. data/lib/generators/spree/dummy/templates/rails/test.rb +1 -1
  86. data/lib/generators/spree/install/install_generator.rb +6 -5
  87. data/lib/spree/core/controller_helpers/payment_parameters.rb +54 -0
  88. data/lib/spree/core/engine.rb +6 -9
  89. data/lib/spree/core/version.rb +1 -1
  90. data/lib/spree/core.rb +0 -1
  91. data/lib/spree/money.rb +18 -0
  92. data/lib/spree/permission_sets/default_customer.rb +1 -1
  93. data/lib/spree/permitted_attributes.rb +1 -1
  94. data/lib/spree/testing_support/authorization_helpers.rb +1 -0
  95. data/lib/spree/testing_support/capybara_ext.rb +13 -0
  96. data/lib/spree/testing_support/factories/order_factory.rb +5 -1
  97. data/lib/spree/testing_support/factories/payment_factory.rb +1 -1
  98. data/lib/spree/testing_support/factories/shipment_factory.rb +0 -1
  99. data/solidus_core.gemspec +3 -3
  100. data/spec/jobs/promotion_code_batch_job_spec.rb +65 -0
  101. data/spec/lib/calculated_adjustments_spec.rb +105 -1
  102. data/spec/lib/spree/core/testing_support/factories/order_factory_spec.rb +4 -1
  103. data/spec/lib/spree/core/testing_support/factories/payment_factory_spec.rb +8 -0
  104. data/spec/lib/spree/money_spec.rb +32 -0
  105. data/spec/lib/spree/permission_sets/default_customer_spec.rb +20 -0
  106. data/spec/mailers/promotion_code_batch_mailer_spec.rb +45 -0
  107. data/spec/models/spree/credit_card_spec.rb +86 -86
  108. data/spec/models/spree/gateway_spec.rb +3 -1
  109. data/spec/models/spree/inventory_unit_spec.rb +12 -4
  110. data/spec/models/spree/order/checkout_spec.rb +11 -32
  111. data/spec/models/spree/order/tax_spec.rb +2 -2
  112. data/spec/models/spree/order_contents_spec.rb +24 -1
  113. data/spec/models/spree/order_inventory_spec.rb +130 -83
  114. data/spec/models/spree/order_spec.rb +15 -117
  115. data/spec/models/spree/order_update_attributes_spec.rb +1 -44
  116. data/spec/models/spree/order_updater_spec.rb +10 -13
  117. data/spec/models/spree/payment_create_spec.rb +5 -1
  118. data/spec/models/spree/payment_method_spec.rb +16 -0
  119. data/spec/models/spree/payment_spec.rb +14 -8
  120. data/spec/models/spree/promotion_code/batch_builder_spec.rb +61 -0
  121. data/spec/models/spree/promotion_code_batch_spec.rb +58 -0
  122. data/spec/models/spree/promotion_code_spec.rb +4 -0
  123. data/spec/models/spree/promotion_spec.rb +3 -6
  124. data/spec/models/spree/return_authorization_spec.rb +0 -59
  125. data/spec/models/spree/shipment_spec.rb +4 -4
  126. data/spec/models/spree/stock/availability_validator_spec.rb +64 -9
  127. data/spec/models/spree/tax/item_adjuster_spec.rb +1 -2
  128. data/spec/models/spree/unit_cancel_spec.rb +0 -85
  129. data/spec/models/spree/user_spec.rb +3 -1
  130. data/spec/models/spree/variant/vat_price_generator_spec.rb +8 -2
  131. data/spec/models/spree/variant_spec.rb +16 -4
  132. data/spec/models/spree/wallet_payment_source_spec.rb +46 -0
  133. data/spec/models/spree/wallet_spec.rb +128 -0
  134. data/spec/support/concerns/payment_source.rb +64 -0
  135. metadata +51 -25
  136. data/app/assets/javascripts/spree.js.coffee.erb +0 -64
  137. data/app/models/spree/promotion_builder.rb +0 -55
  138. data/app/models/spree/promotion_code/code_builder.rb +0 -62
  139. data/config/initializers/premailer_assets.rb +0 -1
  140. data/lib/spree/core/unreturned_item_charger.rb +0 -106
  141. data/lib/tasks/exchanges.rake +0 -47
  142. data/spec/lib/spree/core/unreturned_item_charger_spec.rb +0 -126
  143. data/spec/lib/tasks/exchanges_spec.rb +0 -220
  144. data/spec/models/spree/promotion_builder_spec.rb +0 -120
  145. data/spec/models/spree/promotion_code/code_builder_spec.rb +0 -77
@@ -2,24 +2,9 @@ module Spree
2
2
  module Stock
3
3
  class AvailabilityValidator < ActiveModel::Validator
4
4
  def validate(line_item)
5
- units_by_shipment = line_item.inventory_units.group_by(&:shipment)
6
-
7
- if units_by_shipment.blank?
8
- ensure_in_stock(line_item, line_item.quantity)
5
+ if is_valid?(line_item)
6
+ true
9
7
  else
10
- units_by_shipment.each do |shipment, inventory_units|
11
- ensure_in_stock(line_item, inventory_units.size, shipment.stock_location)
12
- end
13
- end
14
-
15
- line_item.errors[:quantity].empty?
16
- end
17
-
18
- private
19
-
20
- def ensure_in_stock(line_item, quantity, stock_location = nil)
21
- quantifier = Stock::Quantifier.new(line_item.variant, stock_location)
22
- unless quantifier.can_supply?(quantity)
23
8
  variant = line_item.variant
24
9
  display_name = variant.name.to_s
25
10
  display_name += %{ (#{variant.options_text})} unless variant.options_text.blank?
@@ -28,6 +13,20 @@ module Spree
28
13
  :selected_quantity_not_available,
29
14
  item: display_name.inspect
30
15
  )
16
+ false
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def is_valid?(line_item)
23
+ if line_item.inventory_units.empty?
24
+ Stock::Quantifier.new(line_item.variant).can_supply?(line_item.quantity)
25
+ else
26
+ quantity_by_stock_location_id = line_item.inventory_units.pending.joins(:shipment).group(:stock_location_id).count
27
+ quantity_by_stock_location_id.all? do |stock_location_id, quantity|
28
+ Stock::Quantifier.new(line_item.variant, stock_location_id).can_supply?(quantity)
29
+ end
31
30
  end
32
31
  end
33
32
  end
@@ -80,10 +80,10 @@ module Spree
80
80
  # minimum required ActiveRecord objects.
81
81
  def stock_location_variant_ids
82
82
  # associate the variant ids we're interested in with stock location ids
83
- location_variant_ids = StockItem.
83
+ location_variant_ids = Spree::StockItem.
84
84
  where(variant_id: unallocated_variant_ids).
85
85
  joins(:stock_location).
86
- merge(StockLocation.active).
86
+ merge(Spree::StockLocation.active).
87
87
  pluck(:stock_location_id, :variant_id)
88
88
 
89
89
  # load activerecord objects for the stock location ids and turn them
@@ -92,7 +92,7 @@ module Spree
92
92
  # <stock location id> => <stock location>,
93
93
  # ...,
94
94
  # }
95
- location_lookup = StockLocation.
95
+ location_lookup = Spree::StockLocation.
96
96
  where(id: location_variant_ids.map(&:first).uniq).
97
97
  map { |l| [l.id, l] }.
98
98
  to_h
@@ -101,7 +101,7 @@ module Spree
101
101
  # @return [Array<Spree::ShippingCategory>] the shipping categories of the
102
102
  # variants in this package
103
103
  def shipping_categories
104
- ShippingCategory.where(id: shipping_category_ids)
104
+ Spree::ShippingCategory.where(id: shipping_category_ids)
105
105
  end
106
106
 
107
107
  # @return [ActiveRecord::Relation] the [Spree::ShippingMethod]s available
@@ -3,15 +3,16 @@ module Spree
3
3
  class Quantifier
4
4
  attr_reader :stock_items
5
5
 
6
+ # @param [Variant] variant The variant to check inventory for.
7
+ # @param [StockLocation, Integer] stock_location The stock_location to check inventory in. If unspecified it will check inventory in all available StockLocations
6
8
  def initialize(variant, stock_location = nil)
7
9
  @variant = variant
8
- where_args = { variant_id: @variant }
10
+ @stock_items = Spree::StockItem.where(variant_id: variant)
9
11
  if stock_location
10
- where_args[:stock_location] = stock_location
12
+ @stock_items.where!(stock_location: stock_location)
11
13
  else
12
- where_args[Spree::StockLocation.table_name] = { active: true }
14
+ @stock_items.joins!(:stock_location).merge!(Spree::StockLocation.active)
13
15
  end
14
- @stock_items = Spree::StockItem.joins(:stock_location).where(where_args)
15
16
  end
16
17
 
17
18
  # Returns the total number of inventory units on hand for the variant.
@@ -110,12 +110,12 @@ module Spree
110
110
  private
111
111
 
112
112
  def create_stock_items
113
- Variant.find_each { |variant| propagate_variant(variant) }
113
+ Spree::Variant.find_each { |variant| propagate_variant(variant) }
114
114
  end
115
115
 
116
116
  def ensure_one_default
117
117
  if default
118
- StockLocation.where(default: true).where.not(id: id).each do |stock_location|
118
+ Spree::StockLocation.where(default: true).where.not(id: id).each do |stock_location|
119
119
  stock_location.default = false
120
120
  stock_location.save!
121
121
  end
@@ -39,8 +39,8 @@ module Spree
39
39
 
40
40
  def ensure_default_exists_and_is_unique
41
41
  if default
42
- Store.where.not(id: id).update_all(default: false)
43
- elsif Store.where(default: true).count == 0
42
+ Spree::Store.where.not(id: id).update_all(default: false)
43
+ elsif Spree::Store.where(default: true).count == 0
44
44
  self.default = true
45
45
  end
46
46
  end
@@ -1,4 +1,4 @@
1
- class Spree::StoreCredit < Spree::Base
1
+ class Spree::StoreCredit < Spree::PaymentSource
2
2
  acts_as_paranoid
3
3
 
4
4
  VOID_ACTION = 'void'
@@ -17,9 +17,9 @@ module Spree
17
17
  #
18
18
  # For further discussion, see https://github.com/spree/spree/issues/4397 and https://github.com/spree/spree/issues/4327.
19
19
  def applicable_rates(order)
20
- order_zone_tax_categories = rates_for_order(order).map(&:tax_category)
20
+ order_zone_tax_category_ids = rates_for_order(order).map(&:tax_category_id)
21
21
  default_rates_with_unmatched_tax_category = rates_for_default_zone.to_a.delete_if do |default_rate|
22
- order_zone_tax_categories.include?(default_rate.tax_category)
22
+ order_zone_tax_category_ids.include?(default_rate.tax_category_id)
23
23
  end
24
24
 
25
25
  (rates_for_order(order) + default_rates_with_unmatched_tax_category).uniq
@@ -38,7 +38,7 @@ module Spree
38
38
  end
39
39
 
40
40
  def rates_for_item(item)
41
- applicable_rates(item.order).select { |rate| rate.tax_category == item.tax_category }
41
+ applicable_rates(item.order).select { |rate| rate.tax_category_id == item.tax_category_id }
42
42
  end
43
43
  end
44
44
  end
@@ -62,7 +62,13 @@ module Spree
62
62
  # Under no circumstances should negative adjustments be applied for the Spanish tax rates.
63
63
  #
64
64
  # Those rates should never come into play at all and only the French rates should apply.
65
- scope :for_zone, ->(zone) { where(zone_id: Spree::Zone.with_shared_members(zone).pluck(:id)) }
65
+ scope :for_zone, ->(zone) do
66
+ if zone
67
+ where(zone_id: Spree::Zone.with_shared_members(zone).pluck(:id))
68
+ else
69
+ none
70
+ end
71
+ end
66
72
  scope :included_in_price, -> { where(included_in_price: true) }
67
73
 
68
74
  # Creates necessary tax adjustments for the order.
@@ -20,7 +20,7 @@ module Spree
20
20
  updated_at: Time.current
21
21
  )
22
22
  else
23
- self.root = Taxon.create!(taxonomy_id: id, name: name)
23
+ self.root = Spree::Taxon.create!(taxonomy_id: id, name: name)
24
24
  end
25
25
  end
26
26
  end
@@ -2,7 +2,7 @@ module Spree
2
2
  class Variant < Spree::Base
3
3
  # FIXME: WARNING tested only under sqlite and postgresql
4
4
  scope :descend_by_popularity, -> {
5
- order("COALESCE((SELECT COUNT(*) FROM #{LineItem.quoted_table_name} GROUP BY #{LineItem.quoted_table_name}.variant_id HAVING #{LineItem.quoted_table_name}.variant_id = #{Variant.quoted_table_name}.id), 0) DESC")
5
+ order("COALESCE((SELECT COUNT(*) FROM #{Spree::LineItem.quoted_table_name} GROUP BY #{Spree::LineItem.quoted_table_name}.variant_id HAVING #{Spree::LineItem.quoted_table_name}.variant_id = #{Spree::Variant.quoted_table_name}.id), 0) DESC")
6
6
  }
7
7
 
8
8
  class << self
@@ -12,7 +12,7 @@ module Spree
12
12
  #
13
13
  # product.variants_including_master.has_option(OptionType.find_by(name: 'shoe-size'), OptionValue.find_by(name: '8'))
14
14
  def has_option(option_type, *option_values)
15
- option_types = OptionType.table_name
15
+ option_types = Spree::OptionType.table_name
16
16
 
17
17
  option_type_conditions = case option_type
18
18
  when OptionType then { "#{option_types}.name" => option_type.name }
@@ -24,9 +24,9 @@ module Spree
24
24
 
25
25
  option_values.each do |option_value|
26
26
  option_value_conditions = case option_value
27
- when OptionValue then { "#{OptionValue.table_name}.name" => option_value.name }
28
- when String then { "#{OptionValue.table_name}.name" => option_value }
29
- else { "#{OptionValue.table_name}.id" => option_value }
27
+ when OptionValue then { "#{Spree::OptionValue.table_name}.name" => option_value.name }
28
+ when String then { "#{Spree::OptionValue.table_name}.name" => option_value }
29
+ else { "#{Spree::OptionValue.table_name}.id" => option_value }
30
30
  end
31
31
  relation = relation.where(option_value_conditions)
32
32
  end
@@ -28,10 +28,7 @@ module Spree
28
28
  # Don't re-create the default price
29
29
  next if variant.default_price && variant.default_price.country_iso == country_iso
30
30
 
31
- foreign_price = variant.prices.find_or_initialize_by(
32
- country_iso: country_iso,
33
- currency: variant.default_price.currency,
34
- )
31
+ foreign_price = find_or_initialize_price_by(country_iso, variant.default_price.currency)
35
32
 
36
33
  foreign_price.amount = variant.default_price.net_amount * (1 + vat_for_country_iso(country_iso))
37
34
  end
@@ -39,6 +36,12 @@ module Spree
39
36
 
40
37
  private
41
38
 
39
+ def find_or_initialize_price_by(country_iso, currency)
40
+ variant.prices.detect do |price|
41
+ price.country_iso == country_iso && price.currency == currency
42
+ end || variant.prices.build(country_iso: country_iso, currency: currency)
43
+ end
44
+
42
45
  # nil is added to the array so we always have an export price.
43
46
  def country_isos_requiring_price
44
47
  return [nil] unless variant.tax_category
@@ -51,7 +54,7 @@ module Spree
51
54
  end
52
55
 
53
56
  def variant_vat_rates
54
- @variant_vat_rates ||= variant.tax_category.tax_rates.where(included_in_price: true)
57
+ @variant_vat_rates ||= variant.tax_category.tax_rates.included_in_price
55
58
  end
56
59
  end
57
60
  end
@@ -69,6 +69,7 @@ module Spree
69
69
  after_create :set_position
70
70
  after_create :set_master_out_of_stock, unless: :is_master?
71
71
 
72
+ after_save :clear_in_stock_cache
72
73
  after_touch :clear_in_stock_cache
73
74
 
74
75
  after_real_destroy :destroy_option_values_variants
@@ -7,19 +7,28 @@ class Spree::Wallet::AddPaymentSourcesToWallet
7
7
  end
8
8
 
9
9
  # This is called after an order transistions to complete and should save the
10
- # order's payment source/s in the user's "wallet" for future use.
10
+ # order's payment source in the user's "wallet" for future use.
11
11
  #
12
12
  # @return [void]
13
13
  def add_to_wallet
14
- if !order.temporary_credit_card &&
15
- order.user_id &&
16
- order.valid_credit_cards.present?
17
- # arbitrarily pick the first one for the default
18
- default_cc = order.valid_credit_cards.first
19
- # TODO: target for refactoring -- why is order checkout responsible for the user -> credit_card relationship?
20
- default_cc.user_id = order.user_id
21
- default_cc.default = true
22
- default_cc.save
14
+ if !order.temporary_payment_source && order.user
15
+ # select valid sources
16
+ payments = order.payments.valid
17
+ sources = payments.map(&:source).
18
+ uniq.
19
+ compact.
20
+ select { |p| p.try(:reusable?) }
21
+
22
+ # add valid sources to wallet and optionally set a default
23
+ if sources.any?
24
+ # arbitrarily sort by id for picking a default
25
+ wallet_payment_sources = sources.sort_by(&:id).map do |source|
26
+ order.user.wallet.add(source)
27
+ end
28
+
29
+ order.user.wallet.default_wallet_payment_source =
30
+ wallet_payment_sources.last
31
+ end
23
32
  end
24
33
  end
25
34
 
@@ -1,5 +1,6 @@
1
1
  # This class is responsible for building a default payment on an order, using a
2
- # payment source that is already in the user's "wallet".
2
+ # payment source that is already in the user's "wallet" and is marked
3
+ # as being the default payment source.
3
4
  class Spree::Wallet::DefaultPaymentBuilder
4
5
  def initialize(order)
5
6
  @order = order
@@ -10,12 +11,11 @@ class Spree::Wallet::DefaultPaymentBuilder
10
11
  #
11
12
  # @return [Payment] the unsaved payment to be added, or nil if none.
12
13
  def build
13
- credit_card = order.user.try!(:default_credit_card)
14
-
15
- if credit_card.try!(:valid?) && order.payments.from_credit_card.count == 0
14
+ default = order.user.try!(:wallet).try!(:default_wallet_payment_source)
15
+ if default && order.payments.where(source_type: default.payment_source_type).none?
16
16
  Spree::Payment.new(
17
- payment_method_id: credit_card.payment_method_id,
18
- source: credit_card,
17
+ payment_method: default.payment_source.payment_method,
18
+ source: default.payment_source,
19
19
  )
20
20
  end
21
21
  end
@@ -0,0 +1,71 @@
1
+ # Interface for accessing and updating a user's active "wallet". A Wallet
2
+ # is the *active* list of *reusable* payment sources that a user would like to
3
+ # choose from when placing orders.
4
+ #
5
+ # A Wallet is composed of WalletPaymentSources. A WalletPaymentSource is a join table that
6
+ # links a PaymentSource (e.g. a CreditCard) to a User. One of a user's
7
+ # WalletPaymentSources may be the 'default' WalletPaymentSource.
8
+ class Spree::Wallet
9
+ class Unauthorized < StandardError; end
10
+
11
+ attr_reader :user
12
+
13
+ def initialize(user)
14
+ @user = user
15
+ end
16
+
17
+ # Returns an array of the WalletPaymentSources in this wallet.
18
+ #
19
+ # @return [Array<WalletPaymentSource>]
20
+ def wallet_payment_sources
21
+ user.wallet_payment_sources.to_a
22
+ end
23
+
24
+ # Add a PaymentSource to the wallet.
25
+ #
26
+ # @param payment_source [PaymentSource] The payment source to add to the wallet
27
+ # @return [WalletPaymentSource] the generated WalletPaymentSource
28
+ def add(payment_source)
29
+ user.wallet_payment_sources.find_or_create_by!(payment_source: payment_source)
30
+ end
31
+
32
+ # Remove a PaymentSource from the wallet.
33
+ #
34
+ # @param payment_source [PaymentSource] The payment source to remove from the wallet
35
+ # @raise [ActiveRecord::RecordNotFound] if the source is not in the wallet.
36
+ # @return [WalletPaymentSource] the destroyed WalletPaymentSource
37
+ def remove(payment_source)
38
+ user.wallet_payment_sources.find_by!(payment_source: payment_source).destroy!
39
+ end
40
+
41
+ # Find a WalletPaymentSource in the wallet by id.
42
+ #
43
+ # @param wallet_payment_source_id [Integer] The id of the WalletPaymentSource.
44
+ # @return [WalletPaymentSource]
45
+ def find(wallet_payment_source_id)
46
+ user.wallet_payment_sources.find_by(id: wallet_payment_source_id)
47
+ end
48
+
49
+ # Find the default WalletPaymentSource for this wallet, if any.
50
+ # @return [WalletPaymentSource]
51
+ def default_wallet_payment_source
52
+ user.wallet_payment_sources.find_by(default: true)
53
+ end
54
+
55
+ # Change the default WalletPaymentSource for this wallet.
56
+ # @param source [WalletPaymentSource] The payment source to set as the default.
57
+ # It must be in the wallet already. Pass nil to clear the default.
58
+ # @return [void]
59
+ def default_wallet_payment_source=(wallet_payment_source)
60
+ if wallet_payment_source && !find(wallet_payment_source.id)
61
+ raise Unauthorized, "wallet_payment_source #{wallet_payment_source.id} does not belong to wallet of user #{user.id}"
62
+ end
63
+
64
+ wallet_payment_source.transaction do
65
+ # Unset old default
66
+ default_wallet_payment_source.try!(:update!, default: false)
67
+ # Set new default
68
+ wallet_payment_source.try!(:update!, default: true)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,17 @@
1
+ class Spree::WalletPaymentSource < ActiveRecord::Base
2
+ belongs_to :user, class_name: Spree::UserClassHandle.new, foreign_key: 'user_id', inverse_of: :wallet_payment_sources
3
+ belongs_to :payment_source, polymorphic: true, inverse_of: :wallet_payment_sources
4
+
5
+ validates_presence_of :user
6
+ validates_presence_of :payment_source
7
+
8
+ validate :check_for_payment_source_class
9
+
10
+ private
11
+
12
+ def check_for_payment_source_class
13
+ if !payment_source.is_a?(Spree::PaymentSource)
14
+ errors.add(:payment_source, :has_to_be_payment_source_class)
15
+ end
16
+ end
17
+ end
@@ -185,7 +185,7 @@ module Spree
185
185
  def set_zone_members(ids, type)
186
186
  zone_members.destroy_all
187
187
  ids.reject(&:blank?).map do |id|
188
- member = ZoneMember.new
188
+ member = Spree::ZoneMember.new
189
189
  member.zoneable_type = type
190
190
  member.zoneable_id = id
191
191
  members << member
@@ -10,7 +10,7 @@
10
10
  <% end %>
11
11
  ============================================================
12
12
 
13
- <%= Spree.t('shipment_mailer.shipped_email.track_information', :tracking => @carton.tracking) if @carton.tracking %>
13
+ <%= Spree.t('shipment_mailer.shipped_email.track_information', tracking: @carton.tracking) if @carton.tracking %>
14
14
  <%= Spree.t('shipment_mailer.shipped_email.track_link', :url => @carton.tracking_url) if @carton.tracking_url %>
15
15
 
16
16
  <%= Spree.t('shipment_mailer.shipped_email.thanks') %>
@@ -0,0 +1,2 @@
1
+ <%= Spree.t("promotion_code_batch_mailer.promotion_code_batch_errored.message", error: @promotion_code_batch.error) %>
2
+ <%= @promotion_code_batch.promotion.name %>
@@ -0,0 +1,2 @@
1
+ <%= Spree.t("promotion_code_batch_mailer.promotion_code_batch_finished.message", number_of_codes: 10) %>
2
+ <%= @promotion_code_batch.promotion.name %>
@@ -31,13 +31,6 @@
31
31
  </td>
32
32
  </tr>
33
33
  <% end %>
34
- <% if @reimbursement.return_items.awaiting_return.present? && Spree::Config[:expedited_exchanges] %>
35
- <tr>
36
- <td colspan="3">
37
- <%= Spree.t('reimbursement_mailer.reimbursement_email.days_to_send', days: Spree::Config[:expedited_exchanges_days_window]) %>
38
- </td>
39
- </tr>
40
- <% end %>
41
34
  </table>
42
35
  <% end %>
43
36
  </td>
@@ -14,9 +14,4 @@
14
14
  <% @reimbursement.return_items.exchange_requested.each do |return_item| %>
15
15
  <%= return_item.variant.sku %> <%= raw(return_item.variant.name) %> <%= "(#{raw(return_item.variant.options_text)})" if return_item.variant.options_text.present? %> -> <%= return_item.exchange_variant.sku %> <%= raw(return_item.exchange_variant.name) %> <%= "(#{raw(return_item.exchange_variant.options_text)})" if return_item.exchange_variant.options_text.present? %>
16
16
  <% end %>
17
-
18
-
19
- <% if @reimbursement.return_items.awaiting_return.present? && Spree::Config[:expedited_exchanges] %>
20
- <%= Spree.t('reimbursement_mailer.reimbursement_email.days_to_send', days: Spree::Config[:expedited_exchanges_days_window]) %>
21
- <% end %>
22
17
  <% end %>
@@ -1,6 +1,6 @@
1
1
  <% if target && target.errors.any? %>
2
2
  <div id="errorExplanation" class="errorExplanation" data-hook>
3
- <h2><%= Spree.t(:errors_prohibited_this_record_from_being_saved, :count => target.errors.count) %>:</h2>
3
+ <h2><%= Spree.t(:errors_prohibited_this_record_from_being_saved, count: target.errors.count) %>:</h2>
4
4
  <p><%= Spree.t(:there_were_problems_with_the_following_fields) %>:</p>
5
5
  <ul>
6
6
  <% target.errors.full_messages.each do |msg| %>
@@ -20,7 +20,7 @@
20
20
  <% end %>
21
21
  </table>
22
22
  <p>
23
- <%= Spree.t('shipment_mailer.shipped_email.track_information', :tracking => @shipment.tracking) if @shipment.tracking %>
23
+ <%= Spree.t('shipment_mailer.shipped_email.track_information', tracking: @shipment.tracking) if @shipment.tracking %>
24
24
  </p>
25
25
  <p>
26
26
  <%= Spree.t('shipment_mailer.shipped_email.track_link', :url => @shipment.tracking_url) if @shipment.tracking_url %>
@@ -1 +1 @@
1
- Rails.application.config.assets.precompile += %w( logo/solidus_logo.png noimage/*.png )
1
+ Rails.application.config.assets.precompile << 'solidus_core_manifest.js'
@@ -82,7 +82,7 @@ FriendlyId.defaults do |config|
82
82
  #
83
83
  # config.use Module.new {
84
84
  # def normalize_friendly_id(text)
85
- # text.to_slug.normalize! :transliterations => [:russian, :latin]
85
+ # text.to_slug.normalize! transliterations: [:russian, :latin]
86
86
  # end
87
87
  # }
88
88
  end