spree_core 2.0.13 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -37,8 +37,6 @@ module DelegateBelongsTo
|
|
37
37
|
attrs = get_association_column_names(association) if attrs.empty?
|
38
38
|
attrs.concat get_association_column_names(association) if attrs.delete :defaults
|
39
39
|
attrs.each do |attr|
|
40
|
-
next if attribute_method?(attr)
|
41
|
-
|
42
40
|
class_def attr do |*args|
|
43
41
|
if args.empty?
|
44
42
|
send(:delegator_for, association).send(attr)
|
data/lib/spree/core/engine.rb
CHANGED
@@ -86,11 +86,7 @@ module Spree
|
|
86
86
|
]
|
87
87
|
end
|
88
88
|
|
89
|
-
|
90
|
-
# Spree.user_class would be nil and users might experience errors related
|
91
|
-
# to malformed model associations (Spree.user_class is only defined on
|
92
|
-
# the app initializer)
|
93
|
-
config.after_initialize do
|
89
|
+
initializer 'spree.promo.register.promotion.calculators' do
|
94
90
|
Rails.application.config.spree.promotions.rules.concat [
|
95
91
|
Spree::Promotion::Rules::ItemTotal,
|
96
92
|
Spree::Promotion::Rules::Product,
|
@@ -2,14 +2,7 @@ module ActiveRecord::Persistence
|
|
2
2
|
|
3
3
|
# Update attributes of a record in the database without callbacks, validations etc.
|
4
4
|
def update_attributes_without_callbacks(attributes)
|
5
|
-
self.assign_attributes(attributes
|
6
|
-
self.class.
|
5
|
+
self.assign_attributes(attributes)
|
6
|
+
self.class.where(:id => id).update_all(attributes)
|
7
7
|
end
|
8
|
-
|
9
|
-
# Update a single attribute in the database
|
10
|
-
def update_attribute_without_callbacks(name, value)
|
11
|
-
send("#{name}=", value)
|
12
|
-
update_attributes_without_callbacks(name => value)
|
13
|
-
end
|
14
|
-
|
15
8
|
end
|
@@ -37,10 +37,6 @@ module Spree
|
|
37
37
|
permalink_options[:prefix] || ""
|
38
38
|
end
|
39
39
|
|
40
|
-
def permalink_length
|
41
|
-
permalink_options[:length] || 9
|
42
|
-
end
|
43
|
-
|
44
40
|
def permalink_order
|
45
41
|
order = permalink_options[:order]
|
46
42
|
"#{order} ASC," if order
|
@@ -48,7 +44,7 @@ module Spree
|
|
48
44
|
end
|
49
45
|
|
50
46
|
def generate_permalink
|
51
|
-
"#{self.class.permalink_prefix}#{Array.new(
|
47
|
+
"#{self.class.permalink_prefix}#{Array.new(9){rand(9)}.join}"
|
52
48
|
end
|
53
49
|
|
54
50
|
def save_permalink(permalink_value=self.to_param)
|
@@ -2,12 +2,8 @@ module Spree
|
|
2
2
|
class ProductDuplicator
|
3
3
|
attr_accessor :product
|
4
4
|
|
5
|
-
|
6
|
-
mattr_accessor :clone_images_default
|
7
|
-
|
8
|
-
def initialize(product, include_images = @@clone_images_default)
|
5
|
+
def initialize(product)
|
9
6
|
@product = product
|
10
|
-
@include_images = include_images
|
11
7
|
end
|
12
8
|
|
13
9
|
def duplicate
|
@@ -27,14 +23,12 @@ module Spree
|
|
27
23
|
def duplicate_product
|
28
24
|
product.dup.tap do |new_product|
|
29
25
|
new_product.name = "COPY OF #{product.name}"
|
30
|
-
new_product.permalink = "copy-of-#{product.permalink}"
|
31
26
|
new_product.taxons = product.taxons
|
32
27
|
new_product.created_at = nil
|
33
28
|
new_product.deleted_at = nil
|
34
29
|
new_product.updated_at = nil
|
35
30
|
new_product.product_properties = reset_properties
|
36
31
|
new_product.master = duplicate_master
|
37
|
-
new_product.variants = product.variants.map { |variant| duplicate_variant variant }
|
38
32
|
end
|
39
33
|
end
|
40
34
|
|
@@ -43,20 +37,12 @@ module Spree
|
|
43
37
|
master.dup.tap do |new_master|
|
44
38
|
new_master.sku = "COPY OF #{master.sku}"
|
45
39
|
new_master.deleted_at = nil
|
46
|
-
new_master.images = master.images.map { |image| duplicate_image image }
|
40
|
+
new_master.images = master.images.map { |image| duplicate_image image }
|
47
41
|
new_master.price = master.price
|
48
42
|
new_master.currency = master.currency
|
49
43
|
end
|
50
44
|
end
|
51
45
|
|
52
|
-
def duplicate_variant(variant)
|
53
|
-
new_variant = variant.dup
|
54
|
-
new_variant.sku = "COPY OF #{new_variant.sku}"
|
55
|
-
new_variant.deleted_at = nil
|
56
|
-
new_variant.option_values = variant.option_values.map { |option_value| option_value}
|
57
|
-
new_variant
|
58
|
-
end
|
59
|
-
|
60
46
|
def duplicate_image(image)
|
61
47
|
new_image = image.dup
|
62
48
|
new_image.assign_attributes(:attachment => image.attachment.clone)
|
@@ -57,12 +57,12 @@ module Spree
|
|
57
57
|
# below scope would be something like ["$10 - $15", "$15 - $18", "$18 - $20"]
|
58
58
|
#
|
59
59
|
Spree::Product.add_search_scope :price_range_any do |*opts|
|
60
|
-
conds = opts.map {|o| Spree::Core::ProductFilters.price_filter[:conds][o]}.reject {|c| c.nil?}
|
60
|
+
conds = opts.map {|o| Spree::Core::ProductFilters.price_filter[:conds][o]}.reject { |c| c.nil? }
|
61
61
|
scope = conds.shift
|
62
62
|
conds.each do |new_scope|
|
63
63
|
scope = scope.or(new_scope)
|
64
64
|
end
|
65
|
-
Spree::Product.joins(:
|
65
|
+
Spree::Product.joins(master: :default_price).where(scope)
|
66
66
|
end
|
67
67
|
|
68
68
|
def ProductFilters.format_price(amount)
|
@@ -71,15 +71,16 @@ module Spree
|
|
71
71
|
|
72
72
|
def ProductFilters.price_filter
|
73
73
|
v = Spree::Price.arel_table
|
74
|
-
conds = [ [ Spree.t(:under_price, :
|
74
|
+
conds = [ [ Spree.t(:under_price, price: format_price(10)) , v[:amount].lteq(10)],
|
75
75
|
[ "#{format_price(10)} - #{format_price(15)}" , v[:amount].in(10..15)],
|
76
76
|
[ "#{format_price(15)} - #{format_price(18)}" , v[:amount].in(15..18)],
|
77
77
|
[ "#{format_price(18)} - #{format_price(20)}" , v[:amount].in(18..20)],
|
78
|
-
[ Spree.t(:or_over_price, :
|
79
|
-
{
|
80
|
-
:
|
81
|
-
:
|
82
|
-
:
|
78
|
+
[ Spree.t(:or_over_price, price: format_price(20)) , v[:amount].gteq(20)]]
|
79
|
+
{
|
80
|
+
name: Spree.t(:price_range),
|
81
|
+
scope: :price_range_any,
|
82
|
+
conds: Hash[*conds.flatten],
|
83
|
+
labels: conds.map { |k,v| [k, k] }
|
83
84
|
}
|
84
85
|
end
|
85
86
|
|
@@ -98,23 +99,24 @@ module Spree
|
|
98
99
|
# rather than an inner join.
|
99
100
|
if Spree::Property.table_exists?
|
100
101
|
Spree::Product.add_search_scope :brand_any do |*opts|
|
101
|
-
conds = opts.map {|o| ProductFilters.brand_filter[:conds][o]}.reject {|c| c.nil?}
|
102
|
+
conds = opts.map {|o| ProductFilters.brand_filter[:conds][o]}.reject { |c| c.nil? }
|
102
103
|
scope = conds.shift
|
103
104
|
conds.each do |new_scope|
|
104
105
|
scope = scope.or(new_scope)
|
105
106
|
end
|
106
|
-
Spree::Product.with_property(
|
107
|
+
Spree::Product.with_property('brand').where(scope)
|
107
108
|
end
|
108
109
|
|
109
110
|
def ProductFilters.brand_filter
|
110
|
-
brand_property = Spree::Property.
|
111
|
-
brands = Spree::ProductProperty.where(:
|
111
|
+
brand_property = Spree::Property.find_by(name: 'brand')
|
112
|
+
brands = brand_property ? Spree::ProductProperty.where(property_id: brand_property.id).pluck(:value).uniq.map(&:to_s) : []
|
112
113
|
pp = Spree::ProductProperty.arel_table
|
113
114
|
conds = Hash[*brands.map { |b| [b, pp[:value].eq(b)] }.flatten]
|
114
|
-
{
|
115
|
-
:
|
116
|
-
:
|
117
|
-
:
|
115
|
+
{
|
116
|
+
name: 'Brands',
|
117
|
+
scope: :brand_any,
|
118
|
+
conds: conds,
|
119
|
+
labels: (brands.sort).map { |k| [k, k] }
|
118
120
|
}
|
119
121
|
end
|
120
122
|
end
|
@@ -145,16 +147,16 @@ module Spree
|
|
145
147
|
|
146
148
|
def ProductFilters.selective_brand_filter(taxon = nil)
|
147
149
|
taxon ||= Spree::Taxonomy.first.root
|
148
|
-
brand_property = Spree::Property.
|
149
|
-
scope = Spree::ProductProperty.where(:
|
150
|
-
|
151
|
-
|
152
|
-
|
150
|
+
brand_property = Spree::Property.find_by(name: 'brand')
|
151
|
+
scope = Spree::ProductProperty.where(property: brand_property).
|
152
|
+
joins(product: :taxons).
|
153
|
+
where("#{Spree::Taxon.table_name}.id" => [taxon] + taxon.descendants).
|
154
|
+
scoped
|
153
155
|
brands = scope.pluck(:value).uniq
|
154
156
|
{
|
155
|
-
:
|
156
|
-
:
|
157
|
-
:
|
157
|
+
name: 'Applicable Brands',
|
158
|
+
scope: :selective_brand_any,
|
159
|
+
labels: brands.sort.map { |k| [k, k] }
|
158
160
|
}
|
159
161
|
end
|
160
162
|
end
|
@@ -173,10 +175,11 @@ module Spree
|
|
173
175
|
#
|
174
176
|
def ProductFilters.taxons_below(taxon)
|
175
177
|
return Spree::Core::ProductFilters.all_taxons if taxon.nil?
|
176
|
-
{
|
177
|
-
:
|
178
|
-
:
|
179
|
-
:
|
178
|
+
{
|
179
|
+
name: 'Taxons under ' + taxon.name,
|
180
|
+
scope: :taxons_id_in_tree_any,
|
181
|
+
labels: taxon.children.sort_by(&:position).map { |t| [t.name, t.id] },
|
182
|
+
conds: nil
|
180
183
|
}
|
181
184
|
end
|
182
185
|
|
@@ -187,11 +190,12 @@ module Spree
|
|
187
190
|
#
|
188
191
|
# idea: expand the format to allow nesting of labels?
|
189
192
|
def ProductFilters.all_taxons
|
190
|
-
taxons = Spree::Taxonomy.all.map {|t| [t.root] + t.root.descendants }.flatten
|
191
|
-
{
|
192
|
-
:
|
193
|
-
:
|
194
|
-
:
|
193
|
+
taxons = Spree::Taxonomy.all.map { |t| [t.root] + t.root.descendants }.flatten
|
194
|
+
{
|
195
|
+
name: 'All taxons',
|
196
|
+
scope: :taxons_id_equals_any,
|
197
|
+
labels: taxons.sort_by(&:name).map { |t| [t.name, t.id] },
|
198
|
+
conds: nil # not needed
|
195
199
|
}
|
196
200
|
end
|
197
201
|
end
|
@@ -46,7 +46,7 @@ module Spree
|
|
46
46
|
if base_scope.respond_to?(:search_scopes) && base_scope.search_scopes.include?(scope_name.to_sym)
|
47
47
|
base_scope = base_scope.send(scope_name, *scope_attribute)
|
48
48
|
else
|
49
|
-
base_scope = base_scope.merge(Spree::Product.
|
49
|
+
base_scope = base_scope.merge(Spree::Product.ransack({scope_name => scope_attribute}).result)
|
50
50
|
end
|
51
51
|
end if search
|
52
52
|
base_scope
|
data/lib/spree/core/version.rb
CHANGED
data/lib/spree/core.rb
CHANGED
@@ -5,7 +5,6 @@ require 'awesome_nested_set'
|
|
5
5
|
require 'cancan'
|
6
6
|
require 'kaminari'
|
7
7
|
require 'mail'
|
8
|
-
require 'monetize'
|
9
8
|
require 'paperclip'
|
10
9
|
require 'paranoia'
|
11
10
|
require 'ransack'
|
@@ -17,9 +16,9 @@ module Spree
|
|
17
16
|
|
18
17
|
def self.user_class
|
19
18
|
if @@user_class.is_a?(Class)
|
20
|
-
raise "Spree.user_class MUST be a String
|
21
|
-
elsif @@user_class.is_a?(String)
|
22
|
-
@@user_class.
|
19
|
+
raise "Spree.user_class MUST be a String object, not a Class object."
|
20
|
+
elsif @@user_class.is_a?(String)
|
21
|
+
@@user_class.constantize
|
23
22
|
end
|
24
23
|
end
|
25
24
|
|
@@ -55,30 +54,3 @@ require 'spree/core/product_duplicator'
|
|
55
54
|
ActiveRecord::Base.class_eval do
|
56
55
|
include CollectiveIdea::Acts::NestedSet
|
57
56
|
end
|
58
|
-
|
59
|
-
# Monkey patch to give us miliseconds precision in timestamps
|
60
|
-
module ActiveSupport
|
61
|
-
class TimeWithZone
|
62
|
-
# Coerces time to a string for JSON encoding. The default format is ISO 8601. You can get
|
63
|
-
# %Y/%m/%d %H:%M:%S +offset style by setting <tt>ActiveSupport::JSON::Encoding.use_standard_json_time_format</tt>
|
64
|
-
# to false.
|
65
|
-
#
|
66
|
-
# ==== Examples
|
67
|
-
#
|
68
|
-
# # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = true
|
69
|
-
# Time.utc(2005,2,1,15,15,10).in_time_zone.to_json
|
70
|
-
# # => "2005-02-01T15:15:10.001Z"
|
71
|
-
#
|
72
|
-
# # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = false
|
73
|
-
# Time.utc(2005,2,1,15,15,10).in_time_zone.to_json
|
74
|
-
# # => "2005/02/01 15:15:10 +0000"
|
75
|
-
#
|
76
|
-
def as_json(options = nil)
|
77
|
-
if ActiveSupport::JSON::Encoding.use_standard_json_time_format
|
78
|
-
xmlschema(3)
|
79
|
-
else
|
80
|
-
%(#{time.strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)})
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
data/lib/spree/i18n.rb
CHANGED
data/lib/spree/money.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
require 'money'
|
4
2
|
|
5
3
|
module Spree
|
@@ -9,187 +7,18 @@ module Spree
|
|
9
7
|
delegate :cents, :to => :money
|
10
8
|
|
11
9
|
def initialize(amount, options={})
|
12
|
-
@money =
|
10
|
+
@money = ::Money.parse([amount, (options[:currency] || Spree::Config[:currency])].join)
|
13
11
|
@options = {}
|
14
12
|
@options[:with_currency] = Spree::Config[:display_currency]
|
15
13
|
@options[:symbol_position] = Spree::Config[:currency_symbol_position].to_sym
|
16
14
|
@options[:no_cents] = Spree::Config[:hide_cents]
|
17
15
|
@options[:decimal_mark] = Spree::Config[:currency_decimal_mark]
|
18
16
|
@options[:thousands_separator] = Spree::Config[:currency_thousands_separator]
|
19
|
-
@options[:sign_before_symbol] = Spree::Config[:currency_sign_before_symbol]
|
20
17
|
@options.merge!(options)
|
21
18
|
# Must be a symbol because the Money gem doesn't do the conversion
|
22
19
|
@options[:symbol_position] = @options[:symbol_position].to_sym
|
23
20
|
end
|
24
21
|
|
25
|
-
# This method is being deprecated in Money 6.1.0, so now lives here.
|
26
|
-
def self.parse(input, currency = nil)
|
27
|
-
i = input.to_s.strip
|
28
|
-
|
29
|
-
# raise Money::Currency.table.collect{|c| c[1][:symbol]}.inspect
|
30
|
-
|
31
|
-
# Check the first character for a currency symbol, alternatively get it
|
32
|
-
# from the stated currency string
|
33
|
-
c = if ::Monetize.assume_from_symbol && i =~ /^(\$|€|£)/
|
34
|
-
case i
|
35
|
-
when /^\$/ then "USD"
|
36
|
-
when /^€/ then "EUR"
|
37
|
-
when /^£/ then "GBP"
|
38
|
-
end
|
39
|
-
else
|
40
|
-
i[/[A-Z]{2,3}/]
|
41
|
-
end
|
42
|
-
|
43
|
-
# check that currency passed and embedded currency are the same,
|
44
|
-
# and negotiate the final currency
|
45
|
-
if currency.nil? and c.nil?
|
46
|
-
currency = ::Money.default_currency
|
47
|
-
elsif currency.nil?
|
48
|
-
currency = c
|
49
|
-
elsif c.nil?
|
50
|
-
currency = currency
|
51
|
-
elsif currency != c
|
52
|
-
# TODO: ParseError
|
53
|
-
raise ArgumentError, "Mismatching Currencies"
|
54
|
-
end
|
55
|
-
currency = ::Money::Currency.wrap(currency)
|
56
|
-
|
57
|
-
fractional = extract_cents(i, currency)
|
58
|
-
::Money.new(fractional, currency)
|
59
|
-
end
|
60
|
-
|
61
|
-
# This method is being deprecated in Money 6.1.0, so now lives here.
|
62
|
-
def self.extract_cents(input, currency = Money.default_currency)
|
63
|
-
# remove anything that's not a number, potential thousands_separator, or minus sign
|
64
|
-
num = input.gsub(/[^\d.,'-]/, '')
|
65
|
-
|
66
|
-
# set a boolean flag for if the number is negative or not
|
67
|
-
negative = num =~ /^-|-$/ ? true : false
|
68
|
-
|
69
|
-
# decimal mark character
|
70
|
-
decimal_char = currency.decimal_mark
|
71
|
-
|
72
|
-
# if negative, remove the minus sign from the number
|
73
|
-
# if it's not negative, the hyphen makes the value invalid
|
74
|
-
if negative
|
75
|
-
num = num.sub(/^-|-$/, '')
|
76
|
-
end
|
77
|
-
|
78
|
-
raise ArgumentError, "Invalid currency amount (hyphen)" if num.include?('-')
|
79
|
-
|
80
|
-
#if the number ends with punctuation, just throw it out. If it means decimal,
|
81
|
-
#it won't hurt anything. If it means a literal period or comma, this will
|
82
|
-
#save it from being mis-interpreted as a decimal.
|
83
|
-
num.chop! if num.match(/[\.|,]$/)
|
84
|
-
|
85
|
-
# gather all decimal_marks within the result number
|
86
|
-
used_delimiters = num.scan(/[^\d]/)
|
87
|
-
|
88
|
-
# determine the number of unique decimal_marks within the number
|
89
|
-
#
|
90
|
-
# e.g.
|
91
|
-
# $1,234,567.89 would return 2 (, and .)
|
92
|
-
# $125,00 would return 1
|
93
|
-
# $199 would return 0
|
94
|
-
# $1 234,567.89 would raise an error (decimal_marks are space, comma, and period)
|
95
|
-
case used_delimiters.uniq.length
|
96
|
-
# no decimal_mark or thousands_separator; major (dollars) is the number, and minor (cents) is 0
|
97
|
-
when 0 then major, minor = num, 0
|
98
|
-
|
99
|
-
# two decimal_marks, so we know the last item in this array is the
|
100
|
-
# major/minor thousands_separator and the rest are decimal_marks
|
101
|
-
when 2
|
102
|
-
thousands_separator, decimal_mark = used_delimiters.uniq
|
103
|
-
|
104
|
-
# remove all thousands_separator, split on the decimal_mark
|
105
|
-
major, minor = num.gsub(thousands_separator, '').split(decimal_mark)
|
106
|
-
min = 0 unless min
|
107
|
-
when 1
|
108
|
-
# we can't determine if the comma or period is supposed to be a decimal_mark or a thousands_separator
|
109
|
-
# e.g.
|
110
|
-
# 1,00 - comma is a thousands_separator
|
111
|
-
# 1.000 - period is a thousands_separator
|
112
|
-
# 1,000 - comma is a decimal_mark
|
113
|
-
# 1,000,000 - comma is a decimal_mark
|
114
|
-
# 10000,00 - comma is a thousands_separator
|
115
|
-
# 1000,000 - comma is a thousands_separator
|
116
|
-
|
117
|
-
# assign first decimal_mark for reusability
|
118
|
-
decimal_mark = used_delimiters.first
|
119
|
-
|
120
|
-
# When we have identified the decimal mark character
|
121
|
-
if decimal_char == decimal_mark
|
122
|
-
major, minor = num.split(decimal_char)
|
123
|
-
|
124
|
-
else
|
125
|
-
# decimal_mark is used as a decimal_mark when there are multiple instances, always
|
126
|
-
if num.scan(decimal_mark).length > 1 # multiple matches; treat as decimal_mark
|
127
|
-
major, minor = num.gsub(decimal_mark, ''), 0
|
128
|
-
else
|
129
|
-
# ex: 1,000 - 1.0000 - 10001.000
|
130
|
-
# split number into possible major (dollars) and minor (cents) values
|
131
|
-
possible_major, possible_minor = num.split(decimal_mark)
|
132
|
-
possible_major ||= "0"
|
133
|
-
possible_minor ||= "00"
|
134
|
-
|
135
|
-
# if the minor (cents) length isn't 3, assign major/minor from the possibles
|
136
|
-
# e.g.
|
137
|
-
# 1,00 => 1.00
|
138
|
-
# 1.0000 => 1.00
|
139
|
-
# 1.2 => 1.20
|
140
|
-
if possible_minor.length != 3 # thousands_separator
|
141
|
-
major, minor = possible_major, possible_minor
|
142
|
-
else
|
143
|
-
# minor length is three
|
144
|
-
# let's try to figure out intent of the thousands_separator
|
145
|
-
|
146
|
-
# the major length is greater than three, which means
|
147
|
-
# the comma or period is used as a thousands_separator
|
148
|
-
# e.g.
|
149
|
-
# 1000,000
|
150
|
-
# 100000,000
|
151
|
-
if possible_major.length > 3
|
152
|
-
major, minor = possible_major, possible_minor
|
153
|
-
else
|
154
|
-
# number is in format ###{sep}### or ##{sep}### or #{sep}###
|
155
|
-
# handle as , is sep, . is thousands_separator
|
156
|
-
if decimal_mark == '.'
|
157
|
-
major, minor = possible_major, possible_minor
|
158
|
-
else
|
159
|
-
major, minor = "#{possible_major}#{possible_minor}", 0
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
163
|
-
end
|
164
|
-
end
|
165
|
-
else
|
166
|
-
# TODO: ParseError
|
167
|
-
raise ArgumentError, "Invalid currency amount"
|
168
|
-
end
|
169
|
-
|
170
|
-
# build the string based on major/minor since decimal_mark/thousands_separator have been removed
|
171
|
-
# avoiding floating point arithmetic here to ensure accuracy
|
172
|
-
cents = (major.to_i * currency.subunit_to_unit)
|
173
|
-
# Because of an bug in JRuby, we can't just call #floor
|
174
|
-
minor = minor.to_s
|
175
|
-
minor = if minor.size < currency.decimal_places
|
176
|
-
(minor + ("0" * currency.decimal_places))[0,currency.decimal_places].to_i
|
177
|
-
elsif minor.size > currency.decimal_places
|
178
|
-
if minor[currency.decimal_places,1].to_i >= 5
|
179
|
-
minor[0,currency.decimal_places].to_i+1
|
180
|
-
else
|
181
|
-
minor[0,currency.decimal_places].to_i
|
182
|
-
end
|
183
|
-
else
|
184
|
-
minor.to_i
|
185
|
-
end
|
186
|
-
|
187
|
-
cents += minor
|
188
|
-
|
189
|
-
# if negative, multiply by -1; otherwise, return positive cents
|
190
|
-
negative ? cents * -1 : cents
|
191
|
-
end
|
192
|
-
|
193
22
|
def to_s
|
194
23
|
@money.format(@options)
|
195
24
|
end
|
@@ -199,15 +28,11 @@ module Spree
|
|
199
28
|
if options[:html]
|
200
29
|
# 1) prevent blank, breaking spaces
|
201
30
|
# 2) prevent escaping of HTML character entities
|
202
|
-
output = output.
|
31
|
+
output = output.gsub(" ", " ").html_safe
|
203
32
|
end
|
204
33
|
output
|
205
34
|
end
|
206
35
|
|
207
|
-
def as_json(*)
|
208
|
-
to_s
|
209
|
-
end
|
210
|
-
|
211
36
|
def ==(obj)
|
212
37
|
@money == obj.money
|
213
38
|
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Spree
|
2
|
+
module PermittedAttributes
|
3
|
+
ATTRIBUTES = [
|
4
|
+
:address_attributes,
|
5
|
+
:checkout_attributes,
|
6
|
+
:image_attributes,
|
7
|
+
:inventory_unit_attributes,
|
8
|
+
:line_item_attributes,
|
9
|
+
:option_type_attributes,
|
10
|
+
:option_value_attributes,
|
11
|
+
:payment_attributes,
|
12
|
+
:product_attributes,
|
13
|
+
:product_properties_attributes,
|
14
|
+
:property_attributes,
|
15
|
+
:return_authorization_attributes,
|
16
|
+
:shipment_attributes,
|
17
|
+
:source_attributes,
|
18
|
+
:stock_item_attributes,
|
19
|
+
:stock_location_attributes,
|
20
|
+
:stock_movement_attributes,
|
21
|
+
:taxon_attributes,
|
22
|
+
:taxonomy_attributes,
|
23
|
+
:user_attributes,
|
24
|
+
:variant_attributes
|
25
|
+
]
|
26
|
+
|
27
|
+
mattr_reader *ATTRIBUTES
|
28
|
+
|
29
|
+
@@address_attributes = [
|
30
|
+
:firstname, :lastname, :address1, :address2,
|
31
|
+
:city, :country_id, :state_id, :zipcode, :phone,
|
32
|
+
:state_name, :alternative_phone, :company]
|
33
|
+
|
34
|
+
@@checkout_attributes = [:email, :use_billing, :shipping_method_id, :coupon_code]
|
35
|
+
|
36
|
+
@@image_attributes = [:alt, :attachment, :position, :viewable_type, :viewable_id]
|
37
|
+
|
38
|
+
@@inventory_unit_attributes = [:shipment, :variant_id]
|
39
|
+
|
40
|
+
@@line_item_attributes = [:id, :variant_id, :quantity]
|
41
|
+
|
42
|
+
@@option_type_attributes = [:name, :presentation, :option_values_attributes]
|
43
|
+
|
44
|
+
@@option_value_attributes = [:name, :presentation]
|
45
|
+
|
46
|
+
@@payment_attributes = [:amount, :payment_method_id]
|
47
|
+
|
48
|
+
@@product_properties_attributes = [:property_name, :value, :position]
|
49
|
+
|
50
|
+
@@product_attributes = [
|
51
|
+
:name, :description, :available_on, :permalink, :meta_description,
|
52
|
+
:meta_keywords, :price, :sku, :deleted_at, :prototype_id,
|
53
|
+
:option_values_hash, :weight, :height, :width, :depth,
|
54
|
+
:shipping_category_id, :tax_category_id, :product_properties_attributes,
|
55
|
+
:variants_attributes, :taxon_ids, :option_type_ids, :cost_currency, :cost_price]
|
56
|
+
|
57
|
+
@@property_attributes = [:name, :presentation]
|
58
|
+
|
59
|
+
@@return_authorization_attributes = [:amount, :reason, :stock_location_id]
|
60
|
+
|
61
|
+
@@shipment_attributes = [
|
62
|
+
:order, :special_instructions, :stock_location_id, :id,
|
63
|
+
:tracking, :address, :inventory_units, :selected_shipping_rate_id]
|
64
|
+
|
65
|
+
# month / year may be provided by some sources, or others may elect to use one field
|
66
|
+
@@source_attributes = [
|
67
|
+
:number, :month, :year, :expiry, :verification_value,
|
68
|
+
:first_name, :last_name, :cc_type]
|
69
|
+
|
70
|
+
@@stock_item_attributes = [:variant, :stock_location, :backorderable, :variant_id]
|
71
|
+
|
72
|
+
@@stock_location_attributes = [
|
73
|
+
:name, :active, :address1, :address2, :city, :zipcode,
|
74
|
+
:backorderable_default, :state_name, :state_id, :country_id, :phone,
|
75
|
+
:propagate_all_variants]
|
76
|
+
|
77
|
+
@@stock_movement_attributes = [
|
78
|
+
:quantity, :stock_item, :stock_item_id, :originator, :action]
|
79
|
+
|
80
|
+
@@taxonomy_attributes = [:name]
|
81
|
+
|
82
|
+
@@taxon_attributes = [
|
83
|
+
:name, :parent_id, :position, :icon, :description, :permalink, :taxonomy_id,
|
84
|
+
:meta_description, :meta_keywords, :meta_title]
|
85
|
+
|
86
|
+
# TODO Should probably use something like Spree.user_class.attributes
|
87
|
+
@@user_attributes = [:email, :password, :password_confirmation]
|
88
|
+
|
89
|
+
@@variant_attributes = [
|
90
|
+
:name, :presentation, :cost_price, :lock_version,
|
91
|
+
:position, :option_value_ids,
|
92
|
+
:product_id, :option_values_attributes, :price,
|
93
|
+
:weight, :height, :width, :depth, :sku, :cost_currency]
|
94
|
+
end
|
95
|
+
end
|
@@ -13,7 +13,7 @@ module Spree
|
|
13
13
|
if @order.adjustments.promotion.eligible.detect { |p| p.originator.promotion.code == @order.coupon_code }.present?
|
14
14
|
return { :coupon_applied? => true, :notice => Spree.t(:coupon_code_already_applied) }
|
15
15
|
else
|
16
|
-
promotion = Spree::Promotion.
|
16
|
+
promotion = Spree::Promotion.find_by(code: @order.coupon_code)
|
17
17
|
if promotion.present?
|
18
18
|
handle_present_promotion(promotion)
|
19
19
|
else
|
@@ -32,17 +32,9 @@ module Spree
|
|
32
32
|
return promotion_usage_limit_exceeded if promotion.usage_limit_exceeded?
|
33
33
|
|
34
34
|
event_name = "spree.checkout.coupon_code_added"
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
determine_promotion_application_result(promo)
|
39
|
-
else
|
40
|
-
# if action is create line items
|
41
|
-
return { :coupon_applied? => true, :success => Spree.t(:coupon_code_applied) }
|
42
|
-
end
|
43
|
-
else
|
44
|
-
return { :coupon_applied? => false, :error => Spree.t(:coupon_code_not_eligible) }
|
45
|
-
end
|
35
|
+
promotion.activate(:coupon_code => @order.coupon_code, :order => @order)
|
36
|
+
promo = @order.adjustments.includes(:originator).promotion.detect { |p| p.originator.promotion.code == @order.coupon_code }
|
37
|
+
determine_promotion_application_result(promo)
|
46
38
|
end
|
47
39
|
|
48
40
|
def promotion_expired
|