solidus_core 2.1.1 → 2.2.0.beta1

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 (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