spree_core 2.2.0 → 2.2.1
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.
- checksums.yaml +4 -4
- data/LICENSE +26 -0
- data/app/helpers/spree/taxons_helper.rb +2 -2
- data/app/models/concerns/spree/user_api_authentication.rb +13 -0
- data/app/models/concerns/spree/user_reporting.rb +27 -0
- data/app/models/spree/adjustment.rb +3 -2
- data/app/models/spree/app_configuration.rb +1 -0
- data/app/models/spree/calculator/default_tax.rb +5 -1
- data/app/models/spree/calculator.rb +2 -2
- data/app/models/spree/credit_card.rb +11 -5
- data/app/models/spree/gateway.rb +25 -0
- data/app/models/spree/item_adjustments.rb +2 -0
- data/app/models/spree/legacy_user.rb +2 -3
- data/app/models/spree/line_item.rb +7 -0
- data/app/models/spree/order/checkout.rb +19 -7
- data/app/models/spree/order/currency_updater.rb +40 -0
- data/app/models/spree/order.rb +19 -3
- data/app/models/spree/order_updater.rb +1 -1
- data/app/models/spree/payment.rb +5 -2
- data/app/models/spree/payment_method.rb +1 -0
- data/app/models/spree/product/scopes.rb +13 -17
- data/app/models/spree/product.rb +10 -2
- data/app/models/spree/promotion/actions/free_shipping.rb +4 -2
- data/app/models/spree/promotion/rules/product.rb +0 -9
- data/app/models/spree/promotion.rb +1 -1
- data/app/models/spree/shipment.rb +19 -14
- data/app/models/spree/shipping_method.rb +2 -2
- data/app/models/spree/shipping_rate.rb +15 -9
- data/app/models/spree/stock/estimator.rb +4 -1
- data/app/models/spree/stock_location.rb +1 -0
- data/app/models/spree/tax_rate.rb +81 -7
- data/config/initializers/user_class_extensions.rb +3 -0
- data/config/locales/en.yml +26 -0
- data/db/default/spree/countries.rb +2 -1
- data/db/migrate/20130213191427_create_default_stock.rb +3 -3
- data/db/migrate/20130417120035_update_adjustment_states.rb +2 -2
- data/db/migrate/20130417123427_add_shipping_rates_to_shipments.rb +1 -1
- data/db/migrate/20130509115210_add_number_to_stock_transfer.rb +1 -1
- data/db/migrate/20130802022321_migrate_tax_categories_to_line_items.rb +5 -7
- data/db/migrate/20140307235515_add_user_id_to_spree_credit_cards.rb +13 -0
- data/lib/generators/spree/dummy/templates/rails/database.yml +6 -6
- data/lib/spree/core/controller_helpers/auth.rb +10 -1
- data/lib/spree/core/controller_helpers/order.rb +1 -1
- data/lib/spree/core/controller_helpers/respond_with.rb +6 -1
- data/lib/spree/core/importer/order.rb +168 -0
- data/lib/spree/core/importer.rb +8 -0
- data/lib/spree/core/product_duplicator.rb +1 -1
- data/lib/spree/core/user_address.rb +2 -0
- data/lib/spree/core/user_payment_source.rb +20 -0
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +4 -0
- data/lib/spree/migrations.rb +1 -1
- data/lib/spree/permitted_attributes.rb +1 -1
- data/lib/spree/testing_support/capybara_ext.rb +23 -1
- data/lib/spree/testing_support/factories/credit_card_factory.rb +1 -6
- data/lib/spree/testing_support/factories/order_factory.rb +8 -8
- data/lib/spree/testing_support/factories/shipping_method_factory.rb +3 -1
- data/lib/spree/testing_support/factories/user_factory.rb +5 -0
- metadata +11 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6877ed94eb40aa392d3e75311ae1c46f07d16c4
|
4
|
+
data.tar.gz: 86f962251bf0d966fce2dc5562a4e537b05db77c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b9f99321e59660959d319148d1c7deed17c10caedb97e6d29d95dd15c195b2dac43bcfb35d5117c915bc456a1d8c0fb8f2d319971a7bd681f842f77a91ba25b6
|
7
|
+
data.tar.gz: 154ee0e0f7d1bd5fa2ce9bce96008951200122a3c687dfe88b6e75284987bef2c12d464c6bba83a2a97747ccd2e9dae7537b2fddc3a4fb9e9cc924c5c11c8491
|
data/LICENSE
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Copyright (c) 2007-2014, Spree Commerce, Inc. and other contributors
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification,
|
5
|
+
are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright notice,
|
8
|
+
this list of conditions and the following disclaimer.
|
9
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
this list of conditions and the following disclaimer in the documentation
|
11
|
+
and/or other materials provided with the distribution.
|
12
|
+
* Neither the name Spree nor the names of its contributors may be used to
|
13
|
+
endorse or promote products derived from this software without specific
|
14
|
+
prior written permission.
|
15
|
+
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
17
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
18
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
19
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
20
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
21
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
22
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
23
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
24
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
25
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
26
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@@ -4,12 +4,12 @@ module Spree
|
|
4
4
|
# that we can use configurations as well as make it easier for end users to override this determination. One idea is
|
5
5
|
# to show the most popular products for a particular taxon (that is an exercise left to the developer.)
|
6
6
|
def taxon_preview(taxon, max=4)
|
7
|
-
products = taxon.active_products.limit(max)
|
7
|
+
products = taxon.active_products.select("DISTINCT (spree_products.id), spree_products.*, spree_products_taxons.position").limit(max)
|
8
8
|
if (products.size < max)
|
9
9
|
products_arel = Spree::Product.arel_table
|
10
10
|
taxon.descendants.each do |taxon|
|
11
11
|
to_get = max - products.length
|
12
|
-
products += taxon.active_products.where(products_arel[:id].not_in(products.map(&:id))).limit(to_get)
|
12
|
+
products += taxon.active_products.select("DISTINCT (spree_products.id), spree_products.*, spree_products_taxons.position").where(products_arel[:id].not_in(products.map(&:id))).limit(to_get)
|
13
13
|
break if products.size >= max
|
14
14
|
end
|
15
15
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Spree
|
2
|
+
module UserReporting
|
3
|
+
def lifetime_value
|
4
|
+
orders.complete.pluck(:total).sum
|
5
|
+
end
|
6
|
+
|
7
|
+
def display_lifetime_value
|
8
|
+
Spree::Money.new(lifetime_value)
|
9
|
+
end
|
10
|
+
|
11
|
+
def order_count
|
12
|
+
BigDecimal(orders.complete.count)
|
13
|
+
end
|
14
|
+
|
15
|
+
def average_order_value
|
16
|
+
if order_count.to_i > 0
|
17
|
+
lifetime_value / order_count
|
18
|
+
else
|
19
|
+
BigDecimal("0.00")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def display_average_order_value
|
24
|
+
Spree::Money.new(average_order_value)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -34,14 +34,15 @@ module Spree
|
|
34
34
|
transition from: :open, to: :closed
|
35
35
|
end
|
36
36
|
|
37
|
-
event :
|
38
|
-
transition from: :
|
37
|
+
event :open do
|
38
|
+
transition from: :closed, to: :open
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
42
|
after_create :update_adjustable_adjustment_total
|
43
43
|
|
44
44
|
scope :open, -> { where(state: 'open') }
|
45
|
+
scope :closed, -> { where(state: 'closed') }
|
45
46
|
scope :tax, -> { where(source_type: 'Spree::TaxRate') }
|
46
47
|
scope :price, -> { where(adjustable_type: 'Spree::LineItem') }
|
47
48
|
scope :shipping, -> { where(adjustable_type: 'Spree::Shipment') }
|
@@ -58,6 +58,7 @@ module Spree
|
|
58
58
|
preference :orders_per_page, :integer, default: 15
|
59
59
|
preference :prices_inc_tax, :boolean, default: false
|
60
60
|
preference :products_per_page, :integer, default: 12
|
61
|
+
preference :promotions_per_page, :integer, default: 15
|
61
62
|
preference :redirect_https_to_http, :boolean, :default => false
|
62
63
|
preference :require_master_price, :boolean, default: true
|
63
64
|
preference :shipment_inc_vat, :boolean, default: false
|
@@ -38,7 +38,11 @@ module Spree
|
|
38
38
|
def compute_shipping_rate(shipping_rate)
|
39
39
|
if rate.included_in_price
|
40
40
|
pre_tax_amount = shipping_rate.cost / (1 + rate.amount)
|
41
|
-
|
41
|
+
if rate.zone == shipping_rate.shipment.order.tax_zone
|
42
|
+
deduced_total_by_rate(pre_tax_amount, rate)
|
43
|
+
else
|
44
|
+
deduced_total_by_rate(pre_tax_amount, rate) * - 1
|
45
|
+
end
|
42
46
|
else
|
43
47
|
with_tax_amount = shipping_rate.cost * rate.amount
|
44
48
|
round_to_two_places(with_tax_amount)
|
@@ -10,9 +10,9 @@ module Spree
|
|
10
10
|
computable_name = computable.class.name.demodulize.underscore
|
11
11
|
method = "compute_#{computable_name}".to_sym
|
12
12
|
calculator_class = self.class
|
13
|
-
|
13
|
+
if respond_to?(method)
|
14
14
|
self.send(method, computable)
|
15
|
-
|
15
|
+
else
|
16
16
|
raise NotImplementedError, "Please implement '#{method}(#{computable_name})' in your calculator: #{calculator_class.name}"
|
17
17
|
end
|
18
18
|
end
|
@@ -1,15 +1,17 @@
|
|
1
1
|
module Spree
|
2
2
|
class CreditCard < ActiveRecord::Base
|
3
|
+
belongs_to :payment_method
|
3
4
|
has_many :payments, as: :source
|
4
5
|
|
5
6
|
before_save :set_last_digits
|
6
7
|
|
7
|
-
attr_accessor :number, :verification_value
|
8
|
+
attr_accessor :number, :verification_value, :encrypted_data
|
9
|
+
|
10
|
+
validates :month, :year, numericality: { only_integer: true }, if: :require_card_numbers?, on: :create
|
11
|
+
validates :number, presence: true, if: :require_card_numbers?, on: :create
|
12
|
+
validates :name, presence: true, if: :require_card_numbers?, on: :create
|
13
|
+
validates :verification_value, presence: true, if: :require_card_numbers?, on: :create
|
8
14
|
|
9
|
-
validates :month, :year, numericality: { only_integer: true }, unless: :has_payment_profile?
|
10
|
-
validates :number, presence: true, unless: :has_payment_profile?, on: :create
|
11
|
-
validates :name, presence: true
|
12
|
-
validates :verification_value, presence: true, unless: :has_payment_profile?, on: :create
|
13
15
|
validate :expiry_not_in_the_past
|
14
16
|
|
15
17
|
scope :with_payment_profile, -> { where('gateway_customer_profile_id IS NOT NULL') }
|
@@ -118,5 +120,9 @@ module Spree
|
|
118
120
|
end
|
119
121
|
end
|
120
122
|
end
|
123
|
+
|
124
|
+
def require_card_numbers?
|
125
|
+
!self.encrypted_data.present? && !self.has_payment_profile?
|
126
|
+
end
|
121
127
|
end
|
122
128
|
end
|
data/app/models/spree/gateway.rb
CHANGED
@@ -50,5 +50,30 @@ module Spree
|
|
50
50
|
return false unless source.brand
|
51
51
|
provider_class.supports?(source.brand)
|
52
52
|
end
|
53
|
+
|
54
|
+
def disable_customer_profile(source)
|
55
|
+
if source.is_a? CreditCard
|
56
|
+
source.update_column :gateway_customer_profile_id, nil
|
57
|
+
else
|
58
|
+
raise 'You must implement disable_customer_profile method for this gateway.'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def sources_by_order(order)
|
63
|
+
source_ids = order.payments.where(source_type: payment_source_class.to_s, payment_method_id: self.id).pluck(:source_id).uniq
|
64
|
+
payment_source_class.where(id: source_ids).with_payment_profile
|
65
|
+
end
|
66
|
+
|
67
|
+
def sources_with_profile(order)
|
68
|
+
if order.completed?
|
69
|
+
sources_by_order order
|
70
|
+
else
|
71
|
+
if order.user_id
|
72
|
+
self.credit_cards.where(user_id: order.user_id).with_payment_profile
|
73
|
+
else
|
74
|
+
[]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
53
78
|
end
|
54
79
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
module Spree
|
3
3
|
class LegacyUser < ActiveRecord::Base
|
4
4
|
include Core::UserAddress
|
5
|
+
include Core::UserPaymentSource
|
5
6
|
|
6
7
|
self.table_name = 'spree_users'
|
7
8
|
|
@@ -9,8 +10,6 @@ module Spree
|
|
9
10
|
|
10
11
|
before_destroy :check_completed_orders
|
11
12
|
|
12
|
-
class DestroyWithOrdersError < StandardError; end
|
13
|
-
|
14
13
|
def has_spree_role?(role)
|
15
14
|
true
|
16
15
|
end
|
@@ -21,7 +20,7 @@ module Spree
|
|
21
20
|
private
|
22
21
|
|
23
22
|
def check_completed_orders
|
24
|
-
raise DestroyWithOrdersError if orders.complete.present?
|
23
|
+
raise Spree::Core::DestroyWithOrdersError if orders.complete.present?
|
25
24
|
end
|
26
25
|
end
|
27
26
|
end
|
@@ -22,6 +22,7 @@ module Spree
|
|
22
22
|
validates :price, numericality: true
|
23
23
|
validates_with Stock::AvailabilityValidator
|
24
24
|
|
25
|
+
validate :ensure_proper_currency
|
25
26
|
before_destroy :update_inventory
|
26
27
|
|
27
28
|
after_save :update_inventory
|
@@ -118,6 +119,12 @@ module Spree
|
|
118
119
|
def create_tax_charge
|
119
120
|
Spree::TaxRate.adjust(order, [self])
|
120
121
|
end
|
122
|
+
|
123
|
+
def ensure_proper_currency
|
124
|
+
unless currency == order.currency
|
125
|
+
errors.add(:currency, t(:must_match_order_currency))
|
126
|
+
end
|
127
|
+
end
|
121
128
|
end
|
122
129
|
end
|
123
130
|
|
@@ -81,17 +81,17 @@ module Spree
|
|
81
81
|
before_transition :from => :address, :do => :create_tax_charge!
|
82
82
|
end
|
83
83
|
|
84
|
+
if states[:payment]
|
85
|
+
before_transition :to => :payment, :do => :set_shipments_cost
|
86
|
+
before_transition :to => :payment, :do => :create_tax_charge!
|
87
|
+
end
|
88
|
+
|
84
89
|
if states[:delivery]
|
85
90
|
before_transition :to => :delivery, :do => :create_proposed_shipments
|
86
91
|
before_transition :to => :delivery, :do => :ensure_available_shipping_rates
|
87
92
|
before_transition :from => :delivery, :do => :apply_free_shipping_promotions
|
88
93
|
end
|
89
94
|
|
90
|
-
if states[:payment]
|
91
|
-
before_transition :to => :payment, :do => :set_shipments_cost
|
92
|
-
before_transition :to => :payment, :do => :create_tax_charge!
|
93
|
-
end
|
94
|
-
|
95
95
|
after_transition :to => :complete, :do => :finalize!
|
96
96
|
after_transition :to => :resumed, :do => :after_resume
|
97
97
|
after_transition :to => :canceled, :do => :after_cancel
|
@@ -211,6 +211,20 @@ module Spree
|
|
211
211
|
@updating_params = params
|
212
212
|
run_callbacks :updating_from_params do
|
213
213
|
attributes = @updating_params[:order] ? @updating_params[:order].permit(permitted_params) : {}
|
214
|
+
|
215
|
+
# Set existing card after setting permitted parameters because
|
216
|
+
# rails would slice parameters containg ruby objects, apparently
|
217
|
+
if @updating_params[:existing_card].present?
|
218
|
+
credit_card = CreditCard.find(@updating_params[:existing_card])
|
219
|
+
if credit_card.user_id != self.user_id || credit_card.user_id.blank?
|
220
|
+
raise Core::GatewayError.new Spree.t(:invalid_credit_card)
|
221
|
+
end
|
222
|
+
|
223
|
+
attributes[:payments_attributes].first[:source] = credit_card
|
224
|
+
attributes[:payments_attributes].first[:payment_method_id] = credit_card.payment_method_id
|
225
|
+
attributes[:payments_attributes].first.delete :source_attributes
|
226
|
+
end
|
227
|
+
|
214
228
|
success = self.update_attributes(attributes)
|
215
229
|
end
|
216
230
|
@updating_params = nil
|
@@ -222,7 +236,6 @@ module Spree
|
|
222
236
|
# attributes for a single payment and its source, discarding attributes
|
223
237
|
# for payment methods other than the one selected
|
224
238
|
def update_params_payment_source
|
225
|
-
# respond_to check is necessary due to issue described in #2910
|
226
239
|
if has_checkout_step?("payment") && self.payment?
|
227
240
|
if @updating_params[:payment_source].present?
|
228
241
|
source_params = @updating_params.delete(:payment_source)[@updating_params[:order][:payments_attributes].first[:payment_method_id].underscore]
|
@@ -237,7 +250,6 @@ module Spree
|
|
237
250
|
end
|
238
251
|
end
|
239
252
|
end
|
240
|
-
|
241
253
|
end
|
242
254
|
end
|
243
255
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Spree
|
2
|
+
class Order < ActiveRecord::Base
|
3
|
+
module CurrencyUpdater
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
|
8
|
+
def homogenize_line_item_currencies
|
9
|
+
update_line_item_currencies!
|
10
|
+
update!
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
# Updates prices of order's line items
|
16
|
+
def update_line_item_currencies!
|
17
|
+
line_items.where('currency != ?', currency).each do |line_item|
|
18
|
+
update_line_item_price!(line_item)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the price object from given item
|
23
|
+
def price_from_line_item(line_item)
|
24
|
+
line_item.variant.prices.where(currency: currency).first
|
25
|
+
end
|
26
|
+
|
27
|
+
# Updates price from given line item
|
28
|
+
def update_line_item_price!(line_item)
|
29
|
+
price = price_from_line_item(line_item)
|
30
|
+
|
31
|
+
if price
|
32
|
+
line_item.update_attributes!(currency: price.currency, price: price.amount)
|
33
|
+
else
|
34
|
+
raise RuntimeError, "no #{currency} price found for #{line_item.product.name} (#{line_item.variant.sku})"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/app/models/spree/order.rb
CHANGED
@@ -4,13 +4,15 @@ require 'spree/order/checkout'
|
|
4
4
|
module Spree
|
5
5
|
class Order < ActiveRecord::Base
|
6
6
|
include Checkout
|
7
|
+
include CurrencyUpdater
|
7
8
|
|
8
9
|
checkout_flow do
|
9
10
|
go_to_state :address
|
10
11
|
go_to_state :delivery
|
11
|
-
go_to_state :payment, if: ->(order)
|
12
|
+
go_to_state :payment, if: ->(order) do
|
13
|
+
order.set_shipments_cost if order.shipments.any?
|
12
14
|
order.payment_required?
|
13
|
-
|
15
|
+
end
|
14
16
|
go_to_state :confirm, if: ->(order) { order.confirmation_required? }
|
15
17
|
go_to_state :complete
|
16
18
|
remove_transition from: :delivery, to: :confirm
|
@@ -68,6 +70,7 @@ module Spree
|
|
68
70
|
attr_accessor :use_billing
|
69
71
|
|
70
72
|
before_create :link_by_email
|
73
|
+
before_update :homogenize_line_item_currencies, if: :currency_changed?
|
71
74
|
|
72
75
|
validates :email, presence: true, if: :require_email
|
73
76
|
validates :email, email: true, if: :require_email, allow_blank: true
|
@@ -489,7 +492,7 @@ module Spree
|
|
489
492
|
# to delivery again so that proper updated shipments are created.
|
490
493
|
# e.g. customer goes back from payment step and changes order items
|
491
494
|
def ensure_updated_shipments
|
492
|
-
if shipments.any?
|
495
|
+
if shipments.any? && !self.completed?
|
493
496
|
self.shipments.destroy_all
|
494
497
|
self.update_column(:shipment_total, 0)
|
495
498
|
restart_checkout_flow
|
@@ -559,6 +562,19 @@ module Spree
|
|
559
562
|
update_column(:considered_risky, false)
|
560
563
|
end
|
561
564
|
|
565
|
+
# moved from api order_decorator. This is a better place for it.
|
566
|
+
def update_line_items(line_item_params)
|
567
|
+
return if line_item_params.blank?
|
568
|
+
line_item_params.each_value do |attributes|
|
569
|
+
if attributes[:id].present?
|
570
|
+
self.line_items.find(attributes[:id]).update_attributes!(attributes)
|
571
|
+
else
|
572
|
+
self.line_items.create!(attributes)
|
573
|
+
end
|
574
|
+
end
|
575
|
+
self.ensure_updated_shipments
|
576
|
+
end
|
577
|
+
|
562
578
|
private
|
563
579
|
|
564
580
|
def link_by_email
|
data/app/models/spree/payment.rb
CHANGED
@@ -104,7 +104,7 @@ module Spree
|
|
104
104
|
end
|
105
105
|
|
106
106
|
def credit_allowed
|
107
|
-
amount - offsets_total
|
107
|
+
amount - offsets_total.abs
|
108
108
|
end
|
109
109
|
|
110
110
|
def can_credit?
|
@@ -116,6 +116,8 @@ module Spree
|
|
116
116
|
return if source_attributes.nil?
|
117
117
|
if payment_method and payment_method.payment_source_class
|
118
118
|
self.source = payment_method.payment_source_class.new(source_attributes)
|
119
|
+
self.source.payment_method_id = payment_method.id
|
120
|
+
self.source.user_id = self.order.user_id if self.order
|
119
121
|
end
|
120
122
|
end
|
121
123
|
|
@@ -159,7 +161,8 @@ module Spree
|
|
159
161
|
end
|
160
162
|
|
161
163
|
def create_payment_profile
|
162
|
-
return unless source.
|
164
|
+
return unless source.respond_to?(:has_payment_profile?) && !source.has_payment_profile?
|
165
|
+
|
163
166
|
payment_method.create_profile(self)
|
164
167
|
rescue ActiveMerchant::ConnectionError => e
|
165
168
|
gateway_error e
|
@@ -27,6 +27,15 @@ module Spree
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
def self.property_conditions(property)
|
31
|
+
properties = Property.table_name
|
32
|
+
conditions = case property
|
33
|
+
when String then { "#{properties}.name" => property }
|
34
|
+
when Property then { "#{properties}.id" => property.id }
|
35
|
+
else { "#{properties}.id" => property.to_i }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
30
39
|
add_simple_scopes simple_scopes
|
31
40
|
|
32
41
|
add_search_scope :ascend_by_master_price do
|
@@ -83,28 +92,15 @@ module Spree
|
|
83
92
|
|
84
93
|
# a scope that finds all products having property specified by name, object or id
|
85
94
|
add_search_scope :with_property do |property|
|
86
|
-
properties
|
87
|
-
conditions = case property
|
88
|
-
when String then { "#{properties}.name" => property }
|
89
|
-
when Property then { "#{properties}.id" => property.id }
|
90
|
-
else { "#{properties}.id" => property.to_i }
|
91
|
-
end
|
92
|
-
|
93
|
-
joins(:properties).where(conditions)
|
95
|
+
joins(:properties).where(property_conditions(property))
|
94
96
|
end
|
95
97
|
|
96
98
|
# a simple test for product with a certain property-value pairing
|
97
99
|
# note that it can test for properties with NULL values, but not for absent values
|
98
100
|
add_search_scope :with_property_value do |property, value|
|
99
|
-
properties
|
100
|
-
|
101
|
-
|
102
|
-
when Property then ["#{properties}.id = ?", property.id]
|
103
|
-
else ["#{properties}.id = ?", property.to_i]
|
104
|
-
end
|
105
|
-
conditions = ["#{ProductProperty.table_name}.value = ? AND #{conditions[0]}", value, conditions[1]]
|
106
|
-
|
107
|
-
joins(:properties).where(conditions)
|
101
|
+
joins(:properties)
|
102
|
+
.where("#{ProductProperty.table_name}.value = ?", value)
|
103
|
+
.where(property_conditions(property))
|
108
104
|
end
|
109
105
|
|
110
106
|
add_search_scope :with_option do |option|
|
data/app/models/spree/product.rb
CHANGED
@@ -78,6 +78,8 @@ module Spree
|
|
78
78
|
validates :shipping_category_id, presence: true
|
79
79
|
validates :slug, length: { minimum: 3 }
|
80
80
|
|
81
|
+
before_validation :normalize_slug, on: :update
|
82
|
+
|
81
83
|
attr_accessor :option_values_hash
|
82
84
|
|
83
85
|
accepts_nested_attributes_for :product_properties, allow_destroy: true, reject_if: lambda { |pp| pp[:property_name].blank? }
|
@@ -132,8 +134,11 @@ module Spree
|
|
132
134
|
!!deleted_at
|
133
135
|
end
|
134
136
|
|
137
|
+
# determine if product is available.
|
138
|
+
# deleted products and products with nil or future available_on date
|
139
|
+
# are not available
|
135
140
|
def available?
|
136
|
-
!(available_on.nil? || available_on.future?)
|
141
|
+
!(available_on.nil? || available_on.future?) && !deleted?
|
137
142
|
end
|
138
143
|
|
139
144
|
# split variants list into hash which shows mapping of opt value onto matching variants
|
@@ -188,7 +193,7 @@ module Spree
|
|
188
193
|
end
|
189
194
|
|
190
195
|
def possible_promotions
|
191
|
-
promotion_ids = promotion_rules.map(&:
|
196
|
+
promotion_ids = promotion_rules.map(&:promotion_id).uniq
|
192
197
|
Spree::Promotion.advertised.where(id: promotion_ids).reject(&:expired?)
|
193
198
|
end
|
194
199
|
|
@@ -208,6 +213,9 @@ module Spree
|
|
208
213
|
end
|
209
214
|
|
210
215
|
private
|
216
|
+
def normalize_slug
|
217
|
+
self.slug = normalize_friendly_id(slug)
|
218
|
+
end
|
211
219
|
|
212
220
|
# Builds variants from a hash of option types & values
|
213
221
|
def build_variants_from_option_values_hash
|
@@ -4,8 +4,6 @@ module Spree
|
|
4
4
|
class FreeShipping < Spree::PromotionAction
|
5
5
|
def perform(payload={})
|
6
6
|
order = payload[:order]
|
7
|
-
|
8
|
-
label = "#{Spree.t(:promotion)} (#{promotion.name})"
|
9
7
|
results = order.shipments.map do |shipment|
|
10
8
|
return false if promotion_credit_exists?(shipment)
|
11
9
|
shipment.adjustments.create!(
|
@@ -21,6 +19,10 @@ module Spree
|
|
21
19
|
results.any? { |r| r == true }
|
22
20
|
end
|
23
21
|
|
22
|
+
def label
|
23
|
+
"#{Spree.t(:promotion)} (#{promotion.name})"
|
24
|
+
end
|
25
|
+
|
24
26
|
def compute_amount(shipment)
|
25
27
|
shipment.cost * -1
|
26
28
|
end
|
@@ -6,7 +6,6 @@ module Spree
|
|
6
6
|
module Rules
|
7
7
|
class Product < PromotionRule
|
8
8
|
has_and_belongs_to_many :products, class_name: '::Spree::Product', join_table: 'spree_products_promotion_rules', foreign_key: 'promotion_rule_id'
|
9
|
-
validate :only_one_promotion_per_product
|
10
9
|
|
11
10
|
MATCH_POLICIES = %w(any all)
|
12
11
|
preference :match_policy, :string, default: MATCH_POLICIES.first
|
@@ -36,14 +35,6 @@ module Spree
|
|
36
35
|
def product_ids_string=(s)
|
37
36
|
self.product_ids = s.to_s.split(',').map(&:strip)
|
38
37
|
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
def only_one_promotion_per_product
|
43
|
-
if Spree::Promotion::Rules::Product.all.map(&:products).flatten.uniq!
|
44
|
-
errors[:base] << "You can't create two promotions for the same product"
|
45
|
-
end
|
46
|
-
end
|
47
38
|
end
|
48
39
|
end
|
49
40
|
end
|