spree_core 2.0.13 → 2.1.0
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/app/controllers/spree/base_controller.rb +3 -0
- data/app/helpers/spree/base_helper.rb +6 -16
- data/app/helpers/spree/products_helper.rb +3 -8
- data/app/helpers/spree/taxons_helper.rb +1 -1
- data/app/mailers/spree/base_mailer.rb +0 -5
- data/app/models/spree/ability.rb +10 -7
- data/app/models/spree/address.rb +7 -17
- data/app/models/spree/adjustment.rb +15 -11
- data/app/models/spree/app_configuration.rb +0 -5
- data/app/models/spree/billing_integration.rb +0 -1
- data/app/models/spree/calculator/flat_percent_item_total.rb +1 -3
- data/app/models/spree/calculator/flat_rate.rb +2 -4
- data/app/models/spree/calculator/flexi_rate.rb +6 -9
- data/app/models/spree/calculator/per_item.rb +2 -4
- data/app/models/spree/calculator/percent_per_item.rb +1 -3
- data/app/models/spree/calculator/price_sack.rb +4 -9
- data/app/models/spree/calculator/shipping/flat_percent_item_total.rb +1 -2
- data/app/models/spree/calculator/shipping/flat_rate.rb +2 -4
- data/app/models/spree/calculator/shipping/flexi_rate.rb +4 -9
- data/app/models/spree/calculator/shipping/per_item.rb +2 -3
- data/app/models/spree/calculator/shipping/price_sack.rb +4 -9
- data/app/models/spree/classification.rb +0 -3
- data/app/models/spree/country.rb +1 -3
- data/app/models/spree/credit_card.rb +37 -38
- data/app/models/spree/gateway/bogus_simple.rb +0 -8
- data/app/models/spree/gateway.rb +1 -3
- data/app/models/spree/image.rb +1 -3
- data/app/models/spree/inventory_unit.rb +5 -8
- data/app/models/spree/legacy_user.rb +0 -4
- data/app/models/spree/line_item.rb +2 -15
- data/app/models/spree/option_type.rb +2 -5
- data/app/models/spree/option_value.rb +1 -3
- data/app/models/spree/order/checkout.rb +4 -13
- data/app/models/spree/order.rb +47 -99
- data/app/models/spree/order_contents.rb +4 -7
- data/app/models/spree/order_inventory.rb +4 -8
- data/app/models/spree/order_updater.rb +13 -12
- data/app/models/spree/payment/processing.rb +12 -19
- data/app/models/spree/payment.rb +17 -30
- data/app/models/spree/payment_method.rb +2 -3
- data/app/models/spree/preference.rb +1 -1
- data/app/models/spree/preferences/configuration.rb +1 -1
- data/app/models/spree/preferences/preferable.rb +1 -1
- data/app/models/spree/preferences/store.rb +1 -1
- data/app/models/spree/price.rb +0 -7
- data/app/models/spree/product/scopes.rb +16 -17
- data/app/models/spree/product.rb +27 -62
- data/app/models/spree/product_property.rb +3 -5
- data/app/models/spree/promotion/actions/create_adjustment.rb +9 -8
- data/app/models/spree/promotion/actions/create_line_items.rb +1 -2
- data/app/models/spree/promotion/rules/first_order.rb +1 -1
- data/app/models/spree/promotion/rules/item_total.rb +2 -4
- data/app/models/spree/promotion/rules/product.rb +2 -2
- data/app/models/spree/promotion/rules/user.rb +1 -3
- data/app/models/spree/promotion.rb +23 -24
- data/app/models/spree/promotion_action.rb +0 -2
- data/app/models/spree/promotion_action_line_item.rb +1 -3
- data/app/models/spree/promotion_rule.rb +0 -2
- data/app/models/spree/property.rb +2 -4
- data/app/models/spree/prototype.rb +0 -2
- data/app/models/spree/return_authorization.rb +6 -9
- data/app/models/spree/role.rb +0 -2
- data/app/models/spree/shipment.rb +19 -25
- data/app/models/spree/shipping_calculator.rb +0 -2
- data/app/models/spree/shipping_category.rb +0 -2
- data/app/models/spree/shipping_method.rb +6 -20
- data/app/models/spree/shipping_rate.rb +12 -10
- data/app/models/spree/state.rb +2 -4
- data/app/models/spree/stock/availability_validator.rb +2 -2
- data/app/models/spree/stock/estimator.rb +6 -20
- data/app/models/spree/stock/packer.rb +1 -1
- data/app/models/spree/stock/quantifier.rb +2 -3
- data/app/models/spree/stock/splitter/base.rb +1 -1
- data/app/models/spree/stock_item.rb +8 -18
- data/app/models/spree/stock_location.rb +2 -11
- data/app/models/spree/stock_movement.rb +2 -5
- data/app/models/spree/stock_transfer.rb +0 -2
- data/app/models/spree/tax_category.rb +0 -2
- data/app/models/spree/tax_rate.rb +12 -12
- data/app/models/spree/taxon.rb +1 -13
- data/app/models/spree/taxonomy.rb +3 -6
- data/app/models/spree/tracker.rb +0 -2
- data/app/models/spree/variant/scopes.rb +2 -2
- data/app/models/spree/variant.rb +13 -31
- data/app/models/spree/zone.rb +2 -7
- data/app/models/spree/zone_member.rb +0 -2
- data/app/views/spree/payments/_payment.html.erb +1 -3
- data/config/locales/en.yml +11 -26
- data/db/default/spree/countries.rb +230 -229
- data/db/default/spree/states.rb +57 -56
- data/db/default/spree/zones.rb +5 -5
- data/db/migrate/20130213191427_create_default_stock.rb +4 -7
- 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/20130611054351_rename_shipping_methods_zones_to_spree_shipping_methods_zones.rb +0 -5
- data/db/migrate/20130611185927_add_user_id_index_to_spree_orders.rb +5 -0
- data/db/migrate/20130618041418_add_updated_at_to_spree_countries.rb +9 -0
- data/db/migrate/20130619012236_add_updated_at_to_spree_states.rb +9 -0
- data/db/migrate/20130802022321_migrate_tax_categories_to_line_items.rb +4 -5
- data/db/migrate/20130806145853_set_default_stock_location_on_shipments.rb +1 -1
- data/lib/generators/spree/dummy/dummy_generator.rb +3 -14
- data/lib/generators/spree/dummy/templates/rails/database.yml +0 -10
- data/lib/generators/spree/dummy/templates/rails/test.rb +2 -7
- data/lib/generators/spree/install/install_generator.rb +11 -8
- data/lib/spree/core/calculated_adjustments.rb +9 -8
- data/lib/spree/core/controller_helpers/auth.rb +2 -3
- data/lib/spree/core/controller_helpers/order.rb +8 -13
- data/lib/spree/core/controller_helpers/ssl.rb +13 -22
- data/lib/spree/core/controller_helpers/strong_parameters.rb +36 -0
- data/lib/spree/core/delegate_belongs_to.rb +0 -2
- data/lib/spree/core/engine.rb +1 -5
- data/lib/spree/core/ext/active_record.rb +2 -9
- data/lib/spree/core/permalinks.rb +1 -5
- data/lib/spree/core/product_duplicator.rb +2 -16
- data/lib/spree/core/product_filters.rb +37 -33
- data/lib/spree/core/search/base.rb +1 -1
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +3 -31
- data/lib/spree/i18n.rb +0 -1
- data/lib/spree/money.rb +2 -177
- data/lib/spree/permitted_attributes.rb +95 -0
- data/lib/spree/promo/coupon_applicator.rb +4 -12
- data/lib/spree/testing_support/capybara_ext.rb +13 -17
- data/lib/spree/testing_support/common_rake.rb +1 -1
- data/lib/spree/testing_support/controller_requests.rb +3 -3
- data/lib/spree/testing_support/factories/credit_card_factory.rb +1 -1
- data/lib/spree/testing_support/factories/product_factory.rb +0 -4
- data/lib/spree/testing_support/factories/shipping_method_factory.rb +1 -3
- data/lib/spree/testing_support/factories/user_factory.rb +1 -1
- data/lib/spree/testing_support/factories/variant_factory.rb +0 -15
- data/lib/spree/testing_support/factories.rb +1 -1
- data/lib/spree/testing_support/order_walkthrough.rb +1 -1
- data/lib/tasks/core.rake +2 -2
- data/vendor/assets/javascripts/jquery.payment.js +497 -0
- metadata +166 -172
- data/app/views/spree/admin/shared/_report_order_criteria.html.erb +0 -17
- data/db/migrate/20130417120034_add_index_to_source_columns_on_adjustments.rb +0 -5
- data/db/migrate/20130830001033_add_shipping_category_to_shipping_methods_and_products.rb +0 -15
- data/db/migrate/20130830001159_migrate_old_shipping_calculators.rb +0 -19
- data/db/migrate/20130909115621_change_states_required_for_countries.rb +0 -9
- data/db/migrate/20131001013410_remove_unused_credit_card_fields.rb +0 -12
- data/db/migrate/20131026154747_add_track_inventory_to_variant.rb +0 -5
- data/db/migrate/20131113035136_add_channel_to_spree_orders.rb +0 -5
- data/db/migrate/20140120160805_add_index_to_variant_id_and_currency_on_prices.rb +0 -5
- data/db/migrate/20140205181631_default_variant_weight_to_zero.rb +0 -11
- data/db/migrate/20140415041315_add_user_id_created_by_id_index_to_order.rb +0 -5
- data/lib/spree/core/preference_rescue.rb +0 -25
|
@@ -8,14 +8,14 @@ module Spree
|
|
|
8
8
|
|
|
9
9
|
# Get current line item for variant if exists
|
|
10
10
|
# Add variant qty to line_item
|
|
11
|
-
def add(variant, quantity=1, currency=nil, shipment=nil)
|
|
11
|
+
def add(variant, quantity = 1, currency = nil, shipment = nil)
|
|
12
12
|
line_item = order.find_line_item_by_variant(variant)
|
|
13
13
|
add_to_line_item(line_item, variant, quantity, currency, shipment)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
# Get current line item for variant
|
|
17
17
|
# Remove variant qty from line_item
|
|
18
|
-
def remove(variant, quantity=1, shipment=nil)
|
|
18
|
+
def remove(variant, quantity = 1, shipment = nil)
|
|
19
19
|
line_item = order.find_line_item_by_variant(variant)
|
|
20
20
|
|
|
21
21
|
unless line_item
|
|
@@ -32,21 +32,18 @@ module Spree
|
|
|
32
32
|
line_item.target_shipment = shipment
|
|
33
33
|
line_item.quantity += quantity.to_i
|
|
34
34
|
line_item.currency = currency unless currency.nil?
|
|
35
|
-
line_item.save
|
|
36
35
|
else
|
|
37
|
-
line_item =
|
|
36
|
+
line_item = order.line_items.new(quantity: quantity, variant: variant)
|
|
38
37
|
line_item.target_shipment = shipment
|
|
39
|
-
line_item.variant = variant
|
|
40
38
|
if currency
|
|
41
39
|
line_item.currency = currency unless currency.nil?
|
|
42
40
|
line_item.price = variant.price_in(currency).amount
|
|
43
41
|
else
|
|
44
42
|
line_item.price = variant.price
|
|
45
43
|
end
|
|
46
|
-
order.line_items << line_item
|
|
47
|
-
line_item
|
|
48
44
|
end
|
|
49
45
|
|
|
46
|
+
line_item.save
|
|
50
47
|
order.reload
|
|
51
48
|
line_item
|
|
52
49
|
end
|
|
@@ -32,7 +32,7 @@ module Spree
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def inventory_units_for(variant)
|
|
35
|
-
units = order.shipments.collect{|s| s.inventory_units.
|
|
35
|
+
units = order.shipments.collect{|s| s.inventory_units.to_a}.flatten
|
|
36
36
|
units.group_by(&:variant_id)[variant.id] || []
|
|
37
37
|
end
|
|
38
38
|
|
|
@@ -65,14 +65,10 @@ module Spree
|
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def add_to_shipment(shipment, variant, quantity)
|
|
68
|
-
|
|
69
|
-
on_hand, back_order = shipment.stock_location.fill_status(variant, quantity)
|
|
68
|
+
on_hand, back_order = shipment.stock_location.fill_status(variant, quantity)
|
|
70
69
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
else
|
|
74
|
-
quantity.times { shipment.set_up_inventory('on_hand', variant, order) }
|
|
75
|
-
end
|
|
70
|
+
on_hand.times { shipment.set_up_inventory('on_hand', variant, order) }
|
|
71
|
+
back_order.times { shipment.set_up_inventory('backordered', variant, order) }
|
|
76
72
|
|
|
77
73
|
# adding to this shipment, and removing from stock_location
|
|
78
74
|
if order.completed?
|
|
@@ -25,7 +25,8 @@ module Spree
|
|
|
25
25
|
update_shipment_state
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
update_promotion_adjustments
|
|
29
|
+
update_shipping_adjustments
|
|
29
30
|
# update totals a second time in case updated adjustments have an effect on the total
|
|
30
31
|
update_totals
|
|
31
32
|
|
|
@@ -101,16 +102,10 @@ module Spree
|
|
|
101
102
|
# The +payment_state+ value helps with reporting, etc. since it provides a quick and easy way to locate Orders needing attention.
|
|
102
103
|
def update_payment_state
|
|
103
104
|
|
|
104
|
-
#
|
|
105
|
+
#line_item are empty when user empties cart
|
|
105
106
|
if line_items.empty? || round_money(order.payment_total) < round_money(order.total)
|
|
106
|
-
if payments.present?
|
|
107
|
-
|
|
108
|
-
order.payment_state = 'failed'
|
|
109
|
-
elsif payments.last.state == 'completed'
|
|
110
|
-
order.payment_state = 'credit_owed'
|
|
111
|
-
else
|
|
112
|
-
order.payment_state = 'balance_due'
|
|
113
|
-
end
|
|
107
|
+
if payments.present? && payments.last.state == 'failed'
|
|
108
|
+
order.payment_state = 'failed'
|
|
114
109
|
else
|
|
115
110
|
order.payment_state = 'balance_due'
|
|
116
111
|
end
|
|
@@ -130,11 +125,17 @@ module Spree
|
|
|
130
125
|
#
|
|
131
126
|
# Adjustments will check if they are still eligible. Ineligible adjustments
|
|
132
127
|
# are preserved but not counted towards adjustment_total.
|
|
133
|
-
def
|
|
134
|
-
order.adjustments.reload.each { |adjustment| adjustment.update!(order) }
|
|
128
|
+
def update_promotion_adjustments
|
|
129
|
+
order.adjustments.reload.promotion.each { |adjustment| adjustment.update!(order) }
|
|
135
130
|
choose_best_promotion_adjustment
|
|
136
131
|
end
|
|
137
132
|
|
|
133
|
+
# Shipping adjustments don't receive order on update! because they calculated
|
|
134
|
+
# over a shipping / package object rather than an order object
|
|
135
|
+
def update_shipping_adjustments
|
|
136
|
+
order.adjustments.reload.shipping.each { |adjustment| adjustment.update! }
|
|
137
|
+
end
|
|
138
|
+
|
|
138
139
|
private
|
|
139
140
|
|
|
140
141
|
# Picks one (and only one) promotion to be eligible for this order
|
|
@@ -83,37 +83,30 @@ module Spree
|
|
|
83
83
|
|
|
84
84
|
credit_amount ||= credit_allowed >= order.outstanding_balance.abs ? order.outstanding_balance.abs : credit_allowed.abs
|
|
85
85
|
credit_amount = credit_amount.to_f
|
|
86
|
-
credit_cents = Spree::Money.new(credit_amount, currency: currency).money.cents
|
|
87
86
|
|
|
88
87
|
if payment_method.payment_profiles_supported?
|
|
89
|
-
response = payment_method.credit(
|
|
88
|
+
response = payment_method.credit((credit_amount * 100).round, source, response_code, gateway_options)
|
|
90
89
|
else
|
|
91
|
-
response = payment_method.credit(
|
|
90
|
+
response = payment_method.credit((credit_amount * 100).round, response_code, gateway_options)
|
|
92
91
|
end
|
|
93
92
|
|
|
94
93
|
record_response(response)
|
|
95
94
|
|
|
96
95
|
if response.success?
|
|
97
|
-
self.class.create(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
96
|
+
self.class.create(
|
|
97
|
+
:order => order,
|
|
98
|
+
:source => self,
|
|
99
|
+
:payment_method => payment_method,
|
|
100
|
+
:amount => credit_amount.abs * -1,
|
|
101
|
+
:response_code => response.authorization,
|
|
102
|
+
:state => 'completed'
|
|
103
|
+
)
|
|
103
104
|
else
|
|
104
105
|
gateway_error(response)
|
|
105
106
|
end
|
|
106
107
|
end
|
|
107
108
|
end
|
|
108
109
|
|
|
109
|
-
def cancel!
|
|
110
|
-
if payment_method.respond_to?(:cancel)
|
|
111
|
-
payment_method.cancel(response_code)
|
|
112
|
-
else
|
|
113
|
-
credit!
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
|
|
117
110
|
def partial_credit(amount)
|
|
118
111
|
return if amount > credit_allowed
|
|
119
112
|
started_processing!
|
|
@@ -148,7 +141,7 @@ module Spree
|
|
|
148
141
|
protect_from_connection_error do
|
|
149
142
|
check_environment
|
|
150
143
|
|
|
151
|
-
response = payment_method.send(action,
|
|
144
|
+
response = payment_method.send(action, (amount * 100).round,
|
|
152
145
|
source,
|
|
153
146
|
gateway_options)
|
|
154
147
|
handle_response(response, success_state, :failure)
|
|
@@ -176,7 +169,7 @@ module Spree
|
|
|
176
169
|
end
|
|
177
170
|
|
|
178
171
|
def record_response(response)
|
|
179
|
-
log_entries.create(
|
|
172
|
+
log_entries.create(:details => response.to_yaml)
|
|
180
173
|
end
|
|
181
174
|
|
|
182
175
|
def protect_from_connection_error
|
data/app/models/spree/payment.rb
CHANGED
|
@@ -4,15 +4,16 @@ module Spree
|
|
|
4
4
|
|
|
5
5
|
IDENTIFIER_CHARS = (('A'..'Z').to_a + ('0'..'9').to_a - %w(0 1 I O)).freeze
|
|
6
6
|
|
|
7
|
-
belongs_to :order, class_name: 'Spree::Order'
|
|
7
|
+
belongs_to :order, class_name: 'Spree::Order'
|
|
8
8
|
belongs_to :source, polymorphic: true
|
|
9
9
|
belongs_to :payment_method, class_name: 'Spree::PaymentMethod'
|
|
10
10
|
|
|
11
|
-
has_many :offsets,
|
|
11
|
+
has_many :offsets, -> { where("source_type = 'Spree::Payment' AND amount < 0 AND state = 'completed'") },
|
|
12
|
+
class_name: "Spree::Payment", foreign_key: :source_id
|
|
12
13
|
has_many :log_entries, as: :source
|
|
13
14
|
|
|
14
15
|
before_validation :validate_source
|
|
15
|
-
|
|
16
|
+
before_save :set_unique_identifier
|
|
16
17
|
|
|
17
18
|
after_save :create_payment_profile, if: :profiles_supported?
|
|
18
19
|
|
|
@@ -24,49 +25,45 @@ module Spree
|
|
|
24
25
|
attr_accessor :source_attributes
|
|
25
26
|
after_initialize :build_source
|
|
26
27
|
|
|
27
|
-
attr_accessible :amount, :payment_method_id, :source_attributes
|
|
28
|
-
|
|
29
28
|
scope :from_credit_card, -> { where(source_type: 'Spree::CreditCard') }
|
|
30
29
|
scope :with_state, ->(s) { where(state: s.to_s) }
|
|
31
|
-
scope :completed, with_state('completed')
|
|
32
|
-
scope :pending, with_state('pending')
|
|
33
|
-
scope :failed, with_state('failed')
|
|
34
|
-
scope :valid, where(
|
|
30
|
+
scope :completed, -> { with_state('completed') }
|
|
31
|
+
scope :pending, -> { with_state('pending') }
|
|
32
|
+
scope :failed, -> { with_state('failed') }
|
|
33
|
+
scope :valid, -> { where('state NOT IN (?)', %w(failed invalid)) }
|
|
35
34
|
|
|
36
35
|
after_rollback :persist_invalid
|
|
37
36
|
|
|
38
|
-
validates :amount, numericality: true
|
|
39
|
-
|
|
40
37
|
def persist_invalid
|
|
41
38
|
return unless ['failed', 'invalid'].include?(state)
|
|
42
39
|
state_will_change!
|
|
43
|
-
save
|
|
40
|
+
save
|
|
44
41
|
end
|
|
45
42
|
|
|
46
43
|
# order state machine (see http://github.com/pluginaweek/state_machine/tree/master for details)
|
|
47
|
-
state_machine initial:
|
|
44
|
+
state_machine initial: :checkout do
|
|
48
45
|
# With card payments, happens before purchase or authorization happens
|
|
49
46
|
event :started_processing do
|
|
50
|
-
transition from: [
|
|
47
|
+
transition from: [:checkout, :pending, :completed, :processing], to: :processing
|
|
51
48
|
end
|
|
52
49
|
# When processing during checkout fails
|
|
53
50
|
event :failure do
|
|
54
|
-
transition from: [
|
|
51
|
+
transition from: [:pending, :processing], to: :failed
|
|
55
52
|
end
|
|
56
53
|
# With card payments this represents authorizing the payment
|
|
57
54
|
event :pend do
|
|
58
|
-
transition from: [
|
|
55
|
+
transition from: [:checkout, :processing], to: :pending
|
|
59
56
|
end
|
|
60
57
|
# With card payments this represents completing a purchase or capture transaction
|
|
61
58
|
event :complete do
|
|
62
|
-
transition from: [
|
|
59
|
+
transition from: [:processing, :pending, :checkout], to: :completed
|
|
63
60
|
end
|
|
64
61
|
event :void do
|
|
65
|
-
transition from: [
|
|
62
|
+
transition from: [:pending, :completed, :checkout], to: :void
|
|
66
63
|
end
|
|
67
64
|
# when the card brand isnt supported
|
|
68
65
|
event :invalidate do
|
|
69
|
-
transition from: [
|
|
66
|
+
transition from: [:checkout], to: :invalid
|
|
70
67
|
end
|
|
71
68
|
end
|
|
72
69
|
|
|
@@ -79,22 +76,12 @@ module Spree
|
|
|
79
76
|
end
|
|
80
77
|
alias display_amount money
|
|
81
78
|
|
|
82
|
-
def amount=(amount)
|
|
83
|
-
self[:amount] =
|
|
84
|
-
case amount
|
|
85
|
-
when String
|
|
86
|
-
separator = I18n.t('number.currency.format.separator')
|
|
87
|
-
number = amount.delete("^0-9-#{separator}").tr(separator, '.')
|
|
88
|
-
number.to_d if number.present?
|
|
89
|
-
end || amount
|
|
90
|
-
end
|
|
91
|
-
|
|
92
79
|
def offsets_total
|
|
93
80
|
offsets.pluck(:amount).sum
|
|
94
81
|
end
|
|
95
82
|
|
|
96
83
|
def credit_allowed
|
|
97
|
-
amount - offsets_total
|
|
84
|
+
amount - offsets_total
|
|
98
85
|
end
|
|
99
86
|
|
|
100
87
|
def can_credit?
|
|
@@ -2,11 +2,10 @@ module Spree
|
|
|
2
2
|
class PaymentMethod < ActiveRecord::Base
|
|
3
3
|
acts_as_paranoid
|
|
4
4
|
DISPLAY = [:both, :front_end, :back_end]
|
|
5
|
-
default_scope where(deleted_at: nil)
|
|
5
|
+
default_scope -> { where(deleted_at: nil) }
|
|
6
6
|
|
|
7
7
|
scope :production, -> { where(environment: 'production') }
|
|
8
8
|
|
|
9
|
-
attr_accessible :name, :description, :environment, :display_on, :active
|
|
10
9
|
validates :name, presence: true
|
|
11
10
|
|
|
12
11
|
def self.providers
|
|
@@ -41,7 +40,7 @@ module Spree
|
|
|
41
40
|
end
|
|
42
41
|
|
|
43
42
|
def self.find_with_destroyed *args
|
|
44
|
-
|
|
43
|
+
unscoped { find(*args) }
|
|
45
44
|
end
|
|
46
45
|
|
|
47
46
|
def payment_profiles_supported?
|
|
@@ -78,7 +78,7 @@ module Spree::Preferences::Preferable
|
|
|
78
78
|
|
|
79
79
|
def preference_cache_key(name)
|
|
80
80
|
return unless id
|
|
81
|
-
[self.class.name, name, id].join('::').underscore
|
|
81
|
+
[ENV["RAILS_CACHE_ID"], self.class.name, name, id].join('::').underscore
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
def save_pending_preferences
|
data/app/models/spree/price.rb
CHANGED
|
@@ -5,8 +5,6 @@ module Spree
|
|
|
5
5
|
validate :check_price
|
|
6
6
|
validates :amount, numericality: { greater_than_or_equal_to: 0 }, allow_nil: true
|
|
7
7
|
|
|
8
|
-
attr_accessible :variant_id, :currency, :amount
|
|
9
|
-
|
|
10
8
|
def display_amount
|
|
11
9
|
money
|
|
12
10
|
end
|
|
@@ -24,11 +22,6 @@ module Spree
|
|
|
24
22
|
self[:amount] = parse_price(price)
|
|
25
23
|
end
|
|
26
24
|
|
|
27
|
-
# Remove variant default_scope `deleted_at: nil`
|
|
28
|
-
def variant
|
|
29
|
-
Spree::Variant.unscoped { super }
|
|
30
|
-
end
|
|
31
|
-
|
|
32
25
|
private
|
|
33
26
|
def check_price
|
|
34
27
|
raise "Price must belong to a variant" if variant.nil?
|
|
@@ -24,7 +24,7 @@ module Spree
|
|
|
24
24
|
next if name.to_s.include?("master_price")
|
|
25
25
|
parts = name.to_s.match(/(.*)_by_(.*)/)
|
|
26
26
|
order_text = "#{Product.quoted_table_name}.#{parts[2]} #{parts[1] == 'ascend' ? "ASC" : "DESC"}"
|
|
27
|
-
self.scope(name.to_s, order(order_text))
|
|
27
|
+
self.scope(name.to_s, -> { relation.order(order_text) })
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
|
|
@@ -68,11 +68,14 @@ module Spree
|
|
|
68
68
|
#
|
|
69
69
|
# SELECT COUNT(*) ...
|
|
70
70
|
add_search_scope :in_taxon do |taxon|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
|
|
72
|
+
scope = select("DISTINCT ON (spree_products.id) spree_products.*")
|
|
73
|
+
else
|
|
74
|
+
scope = select("DISTINCT(spree_products.id), spree_products.*")
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
scope.joins(:taxons).
|
|
78
|
+
where(Taxon.table_name => { :id => taxon.self_and_descendants.map(&:id) })
|
|
76
79
|
end
|
|
77
80
|
|
|
78
81
|
# This scope selects products in all taxons AND all its descendants
|
|
@@ -124,20 +127,20 @@ module Spree
|
|
|
124
127
|
add_search_scope :with_option_value do |option, value|
|
|
125
128
|
option_values = OptionValue.table_name
|
|
126
129
|
option_type_id = case option
|
|
127
|
-
when String then OptionType.
|
|
130
|
+
when String then OptionType.find_by(name: option) || option.to_i
|
|
128
131
|
when OptionType then option.id
|
|
129
132
|
else option.to_i
|
|
130
133
|
end
|
|
131
134
|
|
|
132
135
|
conditions = "#{option_values}.name = ? AND #{option_values}.option_type_id = ?", value, option_type_id
|
|
133
|
-
group(
|
|
136
|
+
group('spree_products.id').joins(variants_including_master: :option_values).where(conditions)
|
|
134
137
|
end
|
|
135
138
|
|
|
136
139
|
# Finds all products which have either:
|
|
137
140
|
# 1) have an option value with the name matching the one given
|
|
138
141
|
# 2) have a product property with a value matching the one given
|
|
139
142
|
add_search_scope :with do |value|
|
|
140
|
-
includes(:
|
|
143
|
+
includes(variants_including_master: :option_values).
|
|
141
144
|
includes(:product_properties).
|
|
142
145
|
where("#{OptionValue.table_name}.name = ? OR #{ProductProperty.table_name}.value = ?", value, value)
|
|
143
146
|
end
|
|
@@ -160,7 +163,7 @@ module Spree
|
|
|
160
163
|
# Finds all products that have the ids matching the given collection of ids.
|
|
161
164
|
# Alternatively, you could use find(collection_of_ids), but that would raise an exception if one product couldn't be found
|
|
162
165
|
add_search_scope :with_ids do |*ids|
|
|
163
|
-
where(:
|
|
166
|
+
where(id: ids)
|
|
164
167
|
end
|
|
165
168
|
|
|
166
169
|
# Sorts products from most popular (popularity is extracted from how many
|
|
@@ -195,11 +198,7 @@ module Spree
|
|
|
195
198
|
|
|
196
199
|
# Can't use add_search_scope for this as it needs a default argument
|
|
197
200
|
def self.available(available_on = nil, currency = nil)
|
|
198
|
-
|
|
199
|
-
unless Spree::Config.show_products_without_price
|
|
200
|
-
scope = scope.where('spree_prices.currency' => currency || Spree::Config[:currency]).where('spree_prices.amount IS NOT NULL')
|
|
201
|
-
end
|
|
202
|
-
scope
|
|
201
|
+
joins(:master => :prices).where("#{Product.quoted_table_name}.available_on <= ?", available_on || Time.now)
|
|
203
202
|
end
|
|
204
203
|
search_scopes << :available
|
|
205
204
|
|
|
@@ -249,10 +248,10 @@ module Spree
|
|
|
249
248
|
taxons = Taxon.table_name
|
|
250
249
|
ids_or_records_or_names.flatten.map { |t|
|
|
251
250
|
case t
|
|
252
|
-
when Integer then Taxon.
|
|
251
|
+
when Integer then Taxon.find_by(id: t)
|
|
253
252
|
when ActiveRecord::Base then t
|
|
254
253
|
when String
|
|
255
|
-
Taxon.
|
|
254
|
+
Taxon.find_by(name: t) ||
|
|
256
255
|
Taxon.where("#{taxons}.permalink LIKE ? OR #{taxons}.permalink = ?", "%/#{t}/", "#{t}/").first
|
|
257
256
|
end
|
|
258
257
|
}.compact.flatten.uniq
|
data/app/models/spree/product.rb
CHANGED
|
@@ -34,22 +34,22 @@ module Spree
|
|
|
34
34
|
belongs_to :shipping_category, class_name: 'Spree::ShippingCategory'
|
|
35
35
|
|
|
36
36
|
has_one :master,
|
|
37
|
+
-> { where is_master: true },
|
|
37
38
|
class_name: 'Spree::Variant',
|
|
38
|
-
conditions: { is_master: true },
|
|
39
39
|
dependent: :destroy
|
|
40
40
|
|
|
41
41
|
has_many :variants,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
order: "#{::Spree::Variant.quoted_table_name}.position ASC"
|
|
42
|
+
-> { where(is_master: false).order("#{::Spree::Variant.quoted_table_name}.position ASC") },
|
|
43
|
+
class_name: 'Spree::Variant'
|
|
45
44
|
|
|
46
45
|
has_many :variants_including_master,
|
|
46
|
+
-> { order("#{::Spree::Variant.quoted_table_name}.position ASC") },
|
|
47
47
|
class_name: 'Spree::Variant',
|
|
48
|
-
dependent: :destroy
|
|
49
|
-
|
|
48
|
+
dependent: :destroy
|
|
49
|
+
|
|
50
|
+
has_many :prices, -> { order('spree_variants.position, spree_variants.id, currency') }, through: :variants
|
|
50
51
|
|
|
51
|
-
has_many :
|
|
52
|
-
has_many :stock_items, through: :variants_including_master
|
|
52
|
+
has_many :stock_items, through: :variants
|
|
53
53
|
|
|
54
54
|
delegate_belongs_to :master, :sku, :price, :currency, :display_amount, :display_price, :weight, :height, :width, :depth, :is_master, :has_default_price?, :cost_currency, :price_in, :amount_in
|
|
55
55
|
delegate_belongs_to :master, :cost_price if Variant.table_exists? && Variant.column_names.include?('cost_price')
|
|
@@ -62,7 +62,7 @@ module Spree
|
|
|
62
62
|
delegate :images, to: :master, prefix: true
|
|
63
63
|
alias_method :images, :master_images
|
|
64
64
|
|
|
65
|
-
has_many :variant_images, source: :images, through: :variants_including_master
|
|
65
|
+
has_many :variant_images, -> { order(:position) }, source: :images, through: :variants_including_master
|
|
66
66
|
|
|
67
67
|
accepts_nested_attributes_for :variants, allow_destroy: true
|
|
68
68
|
|
|
@@ -73,31 +73,6 @@ module Spree
|
|
|
73
73
|
|
|
74
74
|
attr_accessor :option_values_hash
|
|
75
75
|
|
|
76
|
-
attr_accessible :available_on,
|
|
77
|
-
:cost_currency,
|
|
78
|
-
:deleted_at,
|
|
79
|
-
:depth,
|
|
80
|
-
:description,
|
|
81
|
-
:height,
|
|
82
|
-
:meta_description,
|
|
83
|
-
:meta_keywords,
|
|
84
|
-
:name,
|
|
85
|
-
:option_type_ids,
|
|
86
|
-
:option_values_hash,
|
|
87
|
-
:permalink,
|
|
88
|
-
:price,
|
|
89
|
-
:product_properties_attributes,
|
|
90
|
-
:prototype_id,
|
|
91
|
-
:shipping_category_id,
|
|
92
|
-
:sku,
|
|
93
|
-
:tax_category_id,
|
|
94
|
-
:taxon_ids,
|
|
95
|
-
:weight,
|
|
96
|
-
:width,
|
|
97
|
-
:variants_attributes
|
|
98
|
-
|
|
99
|
-
attr_accessible :cost_price if Variant.table_exists? && Variant.column_names.include?('cost_price')
|
|
100
|
-
|
|
101
76
|
accepts_nested_attributes_for :product_properties, allow_destroy: true, reject_if: lambda { |pp| pp[:property_name].blank? }
|
|
102
77
|
|
|
103
78
|
make_permalink order: :name
|
|
@@ -108,11 +83,6 @@ module Spree
|
|
|
108
83
|
|
|
109
84
|
before_destroy :punch_permalink
|
|
110
85
|
|
|
111
|
-
def variants_with_only_master
|
|
112
|
-
ActiveSupport::Deprecation.warn("[SPREE] Spree::Product#variants_with_only_master will be deprecated in Spree 1.3. Please use Spree::Product#master instead.")
|
|
113
|
-
master
|
|
114
|
-
end
|
|
115
|
-
|
|
116
86
|
def to_param
|
|
117
87
|
permalink.present? ? permalink : (permalink_was || name.to_s.to_url)
|
|
118
88
|
end
|
|
@@ -141,7 +111,7 @@ module Spree
|
|
|
141
111
|
return if option_values_hash.nil?
|
|
142
112
|
option_values_hash.keys.map(&:to_i).each do |id|
|
|
143
113
|
self.option_type_ids << id unless option_type_ids.include?(id)
|
|
144
|
-
product_option_types.create(
|
|
114
|
+
product_option_types.create(option_type_id: id) unless product_option_types.pluck(:option_type_id).include?(id)
|
|
145
115
|
end
|
|
146
116
|
end
|
|
147
117
|
|
|
@@ -159,11 +129,8 @@ module Spree
|
|
|
159
129
|
!!deleted_at
|
|
160
130
|
end
|
|
161
131
|
|
|
162
|
-
# determine if product is available.
|
|
163
|
-
# deleted products and products with nil or future available_on date
|
|
164
|
-
# are not available
|
|
165
132
|
def available?
|
|
166
|
-
!(available_on.nil? || available_on.future?)
|
|
133
|
+
!(available_on.nil? || available_on.future?)
|
|
167
134
|
end
|
|
168
135
|
|
|
169
136
|
# split variants list into hash which shows mapping of opt value onto matching variants
|
|
@@ -199,19 +166,14 @@ module Spree
|
|
|
199
166
|
end
|
|
200
167
|
|
|
201
168
|
def property(property_name)
|
|
202
|
-
return nil unless prop = properties.
|
|
203
|
-
product_properties.
|
|
169
|
+
return nil unless prop = properties.find_by(name: property_name)
|
|
170
|
+
product_properties.find_by(property: prop).try(:value)
|
|
204
171
|
end
|
|
205
172
|
|
|
206
173
|
def set_property(property_name, property_value)
|
|
207
174
|
ActiveRecord::Base.transaction do
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
Property.where(name: property_name).first
|
|
211
|
-
else
|
|
212
|
-
Property.create(name: property_name, presentation: property_name)
|
|
213
|
-
end
|
|
214
|
-
product_property = ProductProperty.where(product_id: self.id, property_id: property.id).first_or_initialize
|
|
175
|
+
property = Property.where(name: property_name).first_or_create!(presentation: property_name)
|
|
176
|
+
product_property = ProductProperty.where(product: self, property: property).first_or_initialize
|
|
215
177
|
product_property.value = property_value
|
|
216
178
|
product_property.save!
|
|
217
179
|
end
|
|
@@ -223,10 +185,10 @@ module Spree
|
|
|
223
185
|
end
|
|
224
186
|
|
|
225
187
|
def total_on_hand
|
|
226
|
-
if
|
|
227
|
-
Float::INFINITY
|
|
228
|
-
else
|
|
188
|
+
if Spree::Config.track_inventory_levels
|
|
229
189
|
self.stock_items.sum(&:count_on_hand)
|
|
190
|
+
else
|
|
191
|
+
Float::INFINITY
|
|
230
192
|
end
|
|
231
193
|
end
|
|
232
194
|
|
|
@@ -234,7 +196,7 @@ module Spree
|
|
|
234
196
|
# which would make AR's default finder return nil.
|
|
235
197
|
# This is a stopgap for that little problem.
|
|
236
198
|
def master
|
|
237
|
-
super || variants_including_master.with_deleted.where(:
|
|
199
|
+
super || variants_including_master.with_deleted.where(is_master: true).first
|
|
238
200
|
end
|
|
239
201
|
|
|
240
202
|
private
|
|
@@ -246,15 +208,18 @@ module Spree
|
|
|
246
208
|
values = values.inject(values.shift) { |memo, value| memo.product(value).map(&:flatten) }
|
|
247
209
|
|
|
248
210
|
values.each do |ids|
|
|
249
|
-
variant = variants.create(
|
|
211
|
+
variant = variants.create(
|
|
212
|
+
option_value_ids: ids,
|
|
213
|
+
price: master.price
|
|
214
|
+
)
|
|
250
215
|
end
|
|
251
216
|
save
|
|
252
217
|
end
|
|
253
218
|
|
|
254
219
|
def add_properties_and_option_types_from_prototype
|
|
255
|
-
if prototype_id && prototype = Spree::Prototype.
|
|
220
|
+
if prototype_id && prototype = Spree::Prototype.find_by(id: prototype_id)
|
|
256
221
|
prototype.properties.each do |property|
|
|
257
|
-
product_properties.create(
|
|
222
|
+
product_properties.create(property: property)
|
|
258
223
|
end
|
|
259
224
|
self.option_types = prototype.option_types
|
|
260
225
|
end
|
|
@@ -268,7 +233,7 @@ module Spree
|
|
|
268
233
|
# there's a weird quirk with the delegate stuff that does not automatically save the delegate object
|
|
269
234
|
# when saving so we force a save using a hook.
|
|
270
235
|
def save_master
|
|
271
|
-
master.save if master && (master.changed? || master.new_record? || (master.default_price && (master.default_price.changed
|
|
236
|
+
master.save if master && (master.changed? || master.new_record? || (master.default_price && (master.default_price.changed || master.default_price.new_record)))
|
|
272
237
|
end
|
|
273
238
|
|
|
274
239
|
def ensure_master
|
|
@@ -278,7 +243,7 @@ module Spree
|
|
|
278
243
|
|
|
279
244
|
def punch_permalink
|
|
280
245
|
update_attribute :permalink, "#{Time.now.to_i}_#{permalink}" # punch permalink with date prefix
|
|
281
|
-
end
|
|
246
|
+
end
|
|
282
247
|
end
|
|
283
248
|
end
|
|
284
249
|
|