spree_core 4.0.7 → 4.1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/spree.js +0 -1
- data/app/finders/spree/products/find.rb +19 -6
- data/app/finders/spree/variants/option_types_finder.rb +21 -0
- data/app/finders/spree/variants/visible_finder.rb +22 -0
- data/app/helpers/spree/base_helper.rb +48 -18
- data/app/helpers/spree/products_helper.rb +76 -8
- data/app/models/concerns/spree/user_methods.rb +2 -2
- data/app/models/spree/app_dependencies.rb +1 -7
- data/app/models/spree/credit_card.rb +4 -5
- data/app/models/spree/image.rb +52 -3
- data/app/models/spree/image/configuration/active_storage.rb +9 -1
- data/app/models/spree/line_item.rb +1 -2
- data/app/models/spree/option_type.rb +4 -0
- data/app/models/spree/order.rb +12 -12
- data/app/models/spree/order/address_book.rb +20 -7
- data/app/models/spree/payment_method.rb +8 -0
- data/app/models/spree/preferences/preferable.rb +1 -1
- data/app/models/spree/product.rb +7 -6
- data/app/models/spree/promotion/actions/create_item_adjustments.rb +1 -1
- data/app/models/spree/promotion_handler/coupon.rb +2 -1
- data/app/models/spree/return_item/eligibility_validator/base_validator.rb +1 -1
- data/app/models/spree/store.rb +2 -1
- data/app/models/spree/taxon.rb +2 -6
- data/app/models/spree/variant.rb +2 -14
- data/app/models/spree/zone.rb +6 -3
- data/app/presenters/spree/product_summary_presenter.rb +26 -0
- data/app/presenters/spree/variant_presenter.rb +69 -0
- data/app/presenters/spree/variants/option_types_presenter.rb +74 -0
- data/app/presenters/spree/variants/options_presenter.rb +49 -0
- data/app/services/spree/checkout/get_shipping_rates.rb +10 -7
- data/app/services/spree/checkout/update.rb +2 -13
- data/config/locales/en.yml +156 -14
- data/db/default/spree/stores.rb +8 -3
- data/db/migrate/20140309033438_create_store_from_preferences.rb +8 -4
- data/db/migrate/20191005121504_add_store_id_to_payment_methods.rb +7 -0
- data/db/migrate/20191016134113_add_deafult_value_for_store_default_currency.rb +5 -0
- data/db/migrate/20200102141311_add_social_to_spree_stores.rb +7 -0
- data/lib/generators/spree/dummy/dummy_generator.rb +2 -1
- data/lib/generators/spree/dummy/templates/initializers/bullet.rb +5 -0
- data/lib/generators/spree/install/install_generator.rb +13 -5
- data/lib/generators/spree/install/templates/config/initializers/spree.rb +0 -1
- data/lib/generators/spree/install/templates/config/initializers/spree_storefront.rb +1 -0
- data/lib/generators/spree/install/templates/config/spree_storefront.yml +67 -0
- data/lib/spree/core.rb +0 -1
- data/lib/spree/core/controller_helpers/order.rb +12 -6
- data/lib/spree/core/controller_helpers/store.rb +2 -2
- data/lib/spree/core/search/base.rb +59 -22
- data/lib/spree/core/version.rb +1 -3
- data/lib/spree/money.rb +8 -1
- data/lib/spree/permitted_attributes.rb +3 -2
- data/lib/spree/testing_support/capybara_ext.rb +0 -45
- data/lib/spree/testing_support/common_rake.rb +1 -1
- data/lib/spree/testing_support/factories/store_factory.rb +3 -0
- data/lib/spree/testing_support/order_walkthrough.rb +7 -3
- data/spree_core.gemspec +8 -14
- metadata +45 -24
- data/app/finders/spree/addresses/find.rb +0 -17
- data/app/services/spree/account/addresses/base.rb +0 -39
- data/app/services/spree/account/addresses/create.rb +0 -18
- data/app/services/spree/account/addresses/update.rb +0 -18
- data/lib/spree/database_type_utilities.rb +0 -12
data/db/default/spree/stores.rb
CHANGED
@@ -1,10 +1,15 @@
|
|
1
1
|
# Possibly already created by a migration.
|
2
|
-
unless Spree::Store.
|
2
|
+
unless Spree::Store.default.persisted?
|
3
3
|
Spree::Store.new do |s|
|
4
|
-
s.code = 'spree'
|
5
4
|
s.name = 'Spree Demo Site'
|
6
|
-
s.
|
5
|
+
s.code = 'spree'
|
6
|
+
s.url = Rails.application.routes.default_url_options[:host] || 'demo.spreecommerce.org'
|
7
7
|
s.mail_from_address = 'spree@example.com'
|
8
8
|
s.default_currency = 'USD'
|
9
|
+
s.seo_title = 'Spree Commerce Demo Shop'
|
10
|
+
s.meta_description = 'Spree Commerce is an open source Ecommerce framework decision makers want, developers enjoy.'
|
11
|
+
s.facebook = 'spreecommerce'
|
12
|
+
s.twitter = 'spreecommerce'
|
13
|
+
s.instagram = 'spreecommerce'
|
9
14
|
end.save!
|
10
15
|
end
|
@@ -6,7 +6,7 @@ class CreateStoreFromPreferences < ActiveRecord::Migration[4.2]
|
|
6
6
|
false
|
7
7
|
end
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
preference_store = Spree::Preferences::Store.instance
|
11
11
|
if store = Spree::Store.where(default: true).first
|
12
12
|
store.meta_description = preference_store.get('spree/app_configuration/default_meta_description') {}
|
@@ -26,10 +26,14 @@ class CreateStoreFromPreferences < ActiveRecord::Migration[4.2]
|
|
26
26
|
'spree@example.com'
|
27
27
|
end
|
28
28
|
|
29
|
-
s.meta_description = preference_store.get('spree/app_configuration/default_meta_description')
|
29
|
+
s.meta_description = preference_store.get('spree/app_configuration/default_meta_description') do
|
30
|
+
'Spree Commerce is an open source Ecommerce framework decision makers want, developers enjoy.'
|
31
|
+
end
|
30
32
|
s.meta_keywords = preference_store.get('spree/app_configuration/default_meta_keywords') {}
|
31
|
-
s.seo_title = preference_store.get('spree/app_configuration/default_seo_title')
|
32
|
-
|
33
|
+
s.seo_title = preference_store.get('spree/app_configuration/default_seo_title') do
|
34
|
+
'Spree Commerce Demo Shop'
|
35
|
+
end
|
36
|
+
s.default_currency = preference_store.get('spree/app_configuration/currency') { 'USD' }
|
33
37
|
s.code = 'spree'
|
34
38
|
end.save!
|
35
39
|
end
|
@@ -57,6 +57,7 @@ module Spree
|
|
57
57
|
template 'rails/test.rb', "#{dummy_path}/config/environments/test.rb", force: true
|
58
58
|
template 'rails/script/rails', "#{dummy_path}/spec/dummy/script/rails", force: true
|
59
59
|
template 'initializers/devise.rb', "#{dummy_path}/config/initializers/devise.rb", force: true
|
60
|
+
template 'initializers/bullet.rb', "#{dummy_path}/config/initializers/bullet.rb", force: true
|
60
61
|
end
|
61
62
|
|
62
63
|
def test_dummy_inject_extension_requirements
|
@@ -137,7 +138,7 @@ end
|
|
137
138
|
end
|
138
139
|
|
139
140
|
def gemfile_path
|
140
|
-
core_gems = ['spree/core', 'spree/api', 'spree/backend', 'spree/frontend'
|
141
|
+
core_gems = ['spree/core', 'spree/api', 'spree/backend', 'spree/frontend']
|
141
142
|
|
142
143
|
if core_gems.include?(lib_name)
|
143
144
|
'../../../../../Gemfile'
|
@@ -10,7 +10,7 @@ module Spree
|
|
10
10
|
class_option :migrate, type: :boolean, default: true, banner: 'Run Spree migrations'
|
11
11
|
class_option :seed, type: :boolean, default: true, banner: 'load seed data (migrations must be run)'
|
12
12
|
class_option :sample, type: :boolean, default: true, banner: 'load sample data (migrations must be run)'
|
13
|
-
class_option :
|
13
|
+
class_option :copy_storefront, type: :boolean, default: true, banner: 'copy storefront from spree frontend to your application for easy customization'
|
14
14
|
class_option :auto_accept, type: :boolean
|
15
15
|
class_option :user_class, type: :string
|
16
16
|
class_option :admin_email, type: :string
|
@@ -30,7 +30,7 @@ module Spree
|
|
30
30
|
@run_migrations = options[:migrate]
|
31
31
|
@load_seed_data = options[:seed]
|
32
32
|
@load_sample_data = options[:sample]
|
33
|
-
@
|
33
|
+
@copy_storefront = options[:copy_storefront]
|
34
34
|
|
35
35
|
unless @run_migrations
|
36
36
|
@load_seed_data = false
|
@@ -40,6 +40,11 @@ module Spree
|
|
40
40
|
|
41
41
|
def add_files
|
42
42
|
template 'config/initializers/spree.rb', 'config/initializers/spree.rb'
|
43
|
+
|
44
|
+
if Spree::Core::Engine.frontend_available? || Rails.env.test?
|
45
|
+
template 'config/initializers/spree_storefront.rb', 'config/initializers/spree_storefront.rb'
|
46
|
+
template 'config/spree_storefront.yml', 'config/spree_storefront.yml'
|
47
|
+
end
|
43
48
|
end
|
44
49
|
|
45
50
|
def additional_tweaks
|
@@ -54,6 +59,9 @@ module Spree
|
|
54
59
|
Disallow: /account
|
55
60
|
Disallow: /api
|
56
61
|
Disallow: /password
|
62
|
+
Disallow: /api_tokens
|
63
|
+
Disallow: /cart_link
|
64
|
+
Disallow: /account_link
|
57
65
|
ROBOTS
|
58
66
|
end
|
59
67
|
|
@@ -83,9 +91,9 @@ module Spree
|
|
83
91
|
empty_directory 'app/overrides'
|
84
92
|
end
|
85
93
|
|
86
|
-
def
|
87
|
-
if @
|
88
|
-
generate 'spree:frontend:
|
94
|
+
def copy_storefront
|
95
|
+
if @copy_storefront && Spree::Core::Engine.frontend_available?
|
96
|
+
generate 'spree:frontend:copy_storefront'
|
89
97
|
end
|
90
98
|
end
|
91
99
|
|
@@ -26,6 +26,5 @@ Spree.dependencies do |dependencies|
|
|
26
26
|
# dependencies.cart_add_item_service = 'MyNewAwesomeService'
|
27
27
|
end
|
28
28
|
|
29
|
-
# Spree::Api::Dependencies.storefront_cart_serializer = 'MyRailsApp::CartSerializer'
|
30
29
|
|
31
30
|
Spree.user_class = <%= (options[:user_class].blank? ? 'Spree::LegacyUser' : options[:user_class]).inspect %>
|
@@ -0,0 +1 @@
|
|
1
|
+
SpreeStorefrontConfig = YAML.load_file(Rails.root.join('config', 'spree_storefront.yml')).with_indifferent_access
|
@@ -0,0 +1,67 @@
|
|
1
|
+
default:
|
2
|
+
navigation:
|
3
|
+
- title: Women
|
4
|
+
subtitle: Categories
|
5
|
+
url: /t/women
|
6
|
+
items:
|
7
|
+
- :title: Skirts
|
8
|
+
:url: /t/women/skirts
|
9
|
+
- :title: Dresses
|
10
|
+
:url: /t/women/dresses
|
11
|
+
- :title: Shirts and Blouses
|
12
|
+
:url: /t/women/shirts-and-blouses
|
13
|
+
- :title: Sweaters
|
14
|
+
:url: /t/women/sweaters
|
15
|
+
- :title: Tops and T-shirts
|
16
|
+
:url: /t/women/tops-and-t-shirts
|
17
|
+
- :title: Jackets and Coats
|
18
|
+
:url: /t/women/jackets-and-coats
|
19
|
+
promo_banners:
|
20
|
+
- subtitle: New collection
|
21
|
+
title: Summer 2019
|
22
|
+
url: /t/summer-collection
|
23
|
+
image: 'meganav/promo_banner_left-first-category.jpg'
|
24
|
+
- subtitle: Special Offers
|
25
|
+
title: Get up to 30% off
|
26
|
+
url: /t/special-offers
|
27
|
+
image: 'meganav/promo_banner_right-first-category.jpg'
|
28
|
+
- title: Men
|
29
|
+
subtitle: Categories
|
30
|
+
url: /t/men
|
31
|
+
items:
|
32
|
+
- :title: Shirts
|
33
|
+
:url: /t/men/shirts
|
34
|
+
- :title: T-shirts
|
35
|
+
:url: /t/men/t-shirts
|
36
|
+
- :title: Sweaters
|
37
|
+
:url: /t/men/sweaters
|
38
|
+
- :title: Jackets and Coats
|
39
|
+
:url: /t/men/jackets-and-coats
|
40
|
+
promo_banners:
|
41
|
+
- subtitle: New collection
|
42
|
+
title: Summer 2019
|
43
|
+
url: /t/summer-collection
|
44
|
+
image: 'meganav/promo_banner_left-second-category.jpg'
|
45
|
+
- subtitle: Special Offers
|
46
|
+
title: Get up to 30% off
|
47
|
+
url: /t/special-offers
|
48
|
+
image: 'meganav/promo_banner_right-second-category.jpg'
|
49
|
+
- title: Sportswear
|
50
|
+
subtitle: Categories
|
51
|
+
url: /t/sportswear
|
52
|
+
items:
|
53
|
+
- :title: Tops
|
54
|
+
:url: /t/sportswear/tops
|
55
|
+
- :title: Sweatshirts
|
56
|
+
:url: /t/sportswear/sweatshirts
|
57
|
+
- :title: Pants
|
58
|
+
:url: /t/sportswear/pants
|
59
|
+
promo_banners:
|
60
|
+
- subtitle: New collection
|
61
|
+
title: Summer 2019
|
62
|
+
url: /t/summer-collection
|
63
|
+
image: 'meganav/promo_banner_left-third-category.jpg'
|
64
|
+
- subtitle: Special Offers
|
65
|
+
title: Get up to 30% off
|
66
|
+
url: /t/special-offers
|
67
|
+
image: 'meganav/promo_banner_right-third-category.jpg'
|
data/lib/spree/core.rb
CHANGED
@@ -5,8 +5,6 @@ module Spree
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
included do
|
8
|
-
before_action :set_current_order
|
9
|
-
|
10
8
|
helper_method :current_order
|
11
9
|
helper_method :simple_current_order
|
12
10
|
end
|
@@ -28,6 +26,7 @@ module Spree
|
|
28
26
|
# The current incomplete order from the token for use in cart and during checkout
|
29
27
|
def current_order(options = {})
|
30
28
|
options[:create_order_if_necessary] ||= false
|
29
|
+
options[:includes] ||= true
|
31
30
|
|
32
31
|
if @current_order
|
33
32
|
@current_order.last_ip_address = ip_address
|
@@ -66,8 +65,8 @@ module Spree
|
|
66
65
|
|
67
66
|
private
|
68
67
|
|
69
|
-
def last_incomplete_order
|
70
|
-
@last_incomplete_order ||= try_spree_current_user.last_incomplete_spree_order(current_store)
|
68
|
+
def last_incomplete_order(includes = {})
|
69
|
+
@last_incomplete_order ||= try_spree_current_user.last_incomplete_spree_order(current_store, includes: includes)
|
71
70
|
end
|
72
71
|
|
73
72
|
def current_order_params
|
@@ -77,8 +76,15 @@ module Spree
|
|
77
76
|
def find_order_by_token_or_user(options = {}, with_adjustments = false)
|
78
77
|
options[:lock] ||= false
|
79
78
|
|
79
|
+
includes = if options[:includes]
|
80
|
+
{ line_items: [variant: [:images, :option_values, :product]] }
|
81
|
+
else
|
82
|
+
{}
|
83
|
+
end
|
84
|
+
|
80
85
|
# Find any incomplete orders for the token
|
81
|
-
incomplete_orders = Spree::Order.incomplete.includes(
|
86
|
+
incomplete_orders = Spree::Order.incomplete.includes(includes)
|
87
|
+
|
82
88
|
token_order_params = current_order_params.except(:user_id)
|
83
89
|
order = if with_adjustments
|
84
90
|
incomplete_orders.includes(:adjustments).lock(options[:lock]).find_by(token_order_params)
|
@@ -87,7 +93,7 @@ module Spree
|
|
87
93
|
end
|
88
94
|
|
89
95
|
# Find any incomplete orders for the current user
|
90
|
-
order = last_incomplete_order if order.nil? && try_spree_current_user
|
96
|
+
order = last_incomplete_order(includes) if order.nil? && try_spree_current_user
|
91
97
|
|
92
98
|
order
|
93
99
|
end
|
@@ -11,7 +11,7 @@ module Spree
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def current_currency
|
14
|
-
|
14
|
+
current_store.default_currency
|
15
15
|
end
|
16
16
|
|
17
17
|
def current_store
|
@@ -43,7 +43,7 @@ module Spree
|
|
43
43
|
private
|
44
44
|
|
45
45
|
def current_tax_zone
|
46
|
-
@current_tax_zone ||= current_order
|
46
|
+
@current_tax_zone ||= @current_order&.tax_zone || Spree::Zone.default_tax
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
@@ -13,7 +13,7 @@ module Spree
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def retrieve_products
|
16
|
-
@products =
|
16
|
+
@products = extended_base_scope&.available
|
17
17
|
curr_page = page || 1
|
18
18
|
|
19
19
|
unless Spree::Config.show_products_without_price
|
@@ -33,34 +33,37 @@ module Spree
|
|
33
33
|
|
34
34
|
protected
|
35
35
|
|
36
|
-
def
|
36
|
+
def extended_base_scope
|
37
37
|
base_scope = Spree::Product.spree_base_scopes.active
|
38
|
-
base_scope = base_scope.in_taxon(taxon) unless taxon.blank?
|
39
38
|
base_scope = get_products_conditions_for(base_scope, keywords)
|
39
|
+
base_scope = Spree::Products::Find.new(
|
40
|
+
scope: base_scope,
|
41
|
+
params: {
|
42
|
+
filter: {
|
43
|
+
price: price,
|
44
|
+
option_value_ids: option_value_ids,
|
45
|
+
taxons: taxon&.id
|
46
|
+
},
|
47
|
+
sort_by: sort_by
|
48
|
+
},
|
49
|
+
current_currency: current_currency
|
50
|
+
).execute
|
40
51
|
base_scope = add_search_scopes(base_scope)
|
41
52
|
base_scope = add_eagerload_scopes(base_scope)
|
42
53
|
base_scope
|
43
54
|
end
|
44
55
|
|
45
56
|
def add_eagerload_scopes(scope)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
#
|
57
|
-
# Would we use `includes` in this particular case, Rails would do
|
58
|
-
# separate queries most of the time but opt for a join as soon as any
|
59
|
-
# `where` constraints affecting joined tables are added to the search;
|
60
|
-
# which is the case as soon as a taxon is added to the base scope.
|
61
|
-
scope = scope.preload(:tax_category)
|
62
|
-
scope = scope.preload(master: :prices)
|
63
|
-
scope = scope.preload(master: :images) if include_images
|
57
|
+
scope = scope.includes(
|
58
|
+
:tax_category,
|
59
|
+
variants: [
|
60
|
+
{ images: { attachment_attachment: :blob } }
|
61
|
+
],
|
62
|
+
master: [
|
63
|
+
:prices,
|
64
|
+
{ images: { attachment_attachment: :blob } }
|
65
|
+
]
|
66
|
+
)
|
64
67
|
scope
|
65
68
|
end
|
66
69
|
|
@@ -68,6 +71,7 @@ module Spree
|
|
68
71
|
if search.is_a?(ActionController::Parameters)
|
69
72
|
search.each do |name, scope_attribute|
|
70
73
|
scope_name = name.to_sym
|
74
|
+
|
71
75
|
base_scope = if base_scope.respond_to?(:search_scopes) && base_scope.search_scopes.include?(scope_name.to_sym)
|
72
76
|
base_scope.send(scope_name, *scope_attribute)
|
73
77
|
else
|
@@ -81,15 +85,48 @@ module Spree
|
|
81
85
|
# method should return new scope based on base_scope
|
82
86
|
def get_products_conditions_for(base_scope, query)
|
83
87
|
unless query.blank?
|
84
|
-
base_scope = base_scope.like_any([:name, :description], query
|
88
|
+
base_scope = base_scope.like_any([:name, :description], [query])
|
89
|
+
end
|
90
|
+
base_scope
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_products_option_values_conditions(base_scope, option_value_ids)
|
94
|
+
unless option_value_ids.blank?
|
95
|
+
base_scope = base_scope.joins(variants: :option_values).where(spree_option_values: { id: option_value_ids })
|
85
96
|
end
|
86
97
|
base_scope
|
87
98
|
end
|
88
99
|
|
100
|
+
def get_price_range(price_param)
|
101
|
+
return if price_param.blank?
|
102
|
+
|
103
|
+
less_than_string = I18n.t('activerecord.attributes.spree/product.less_than')
|
104
|
+
|
105
|
+
if price_param.include? less_than_string
|
106
|
+
low_price = 0
|
107
|
+
high_price = Monetize.parse(price_param.remove("#{less_than_string} ")).to_i
|
108
|
+
else
|
109
|
+
low_price, high_price = Monetize.parse_collection(price_param).map(&:to_i)
|
110
|
+
end
|
111
|
+
|
112
|
+
"#{low_price},#{high_price}"
|
113
|
+
end
|
114
|
+
|
115
|
+
def build_option_value_ids(params)
|
116
|
+
filter_params = Spree::OptionType.all.map(&:filter_param)
|
117
|
+
|
118
|
+
filter_params.reduce([]) do |acc, filter_param|
|
119
|
+
acc + params[filter_param].to_s.split(',')
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
89
123
|
def prepare(params)
|
90
124
|
@properties[:taxon] = params[:taxon].blank? ? nil : Spree::Taxon.find(params[:taxon])
|
91
125
|
@properties[:keywords] = params[:keywords]
|
126
|
+
@properties[:option_value_ids] = build_option_value_ids(params)
|
127
|
+
@properties[:price] = get_price_range(params[:price])
|
92
128
|
@properties[:search] = params[:search]
|
129
|
+
@properties[:sort_by] = params[:sort_by] || 'default'
|
93
130
|
@properties[:include_images] = params[:include_images]
|
94
131
|
|
95
132
|
per_page = params[:per_page].to_i
|
data/lib/spree/core/version.rb
CHANGED
data/lib/spree/money.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'money'
|
2
2
|
|
3
3
|
Money.locale_backend = :i18n
|
4
|
+
Money.rounding_mode = BigDecimal::ROUND_HALF_UP
|
4
5
|
|
5
6
|
module Spree
|
6
7
|
class Money
|
@@ -18,6 +19,7 @@ module Spree
|
|
18
19
|
delegate :cents, :currency, to: :money
|
19
20
|
|
20
21
|
def initialize(amount, options = {})
|
22
|
+
use_default_currency
|
21
23
|
@money = Monetize.parse([amount, (options[:currency] || Spree::Config[:currency])].join)
|
22
24
|
@options = Spree::Money.default_formatting_rules.merge(options)
|
23
25
|
end
|
@@ -27,7 +29,7 @@ module Spree
|
|
27
29
|
end
|
28
30
|
|
29
31
|
def to_s
|
30
|
-
money
|
32
|
+
money&.format(options)
|
31
33
|
end
|
32
34
|
|
33
35
|
# 1) prevent blank, breaking spaces
|
@@ -62,6 +64,11 @@ module Spree
|
|
62
64
|
money == obj.money
|
63
65
|
end
|
64
66
|
|
67
|
+
def use_default_currency
|
68
|
+
currency = Spree::Store.default.default_currency || Spree::Config[:currency]
|
69
|
+
::Money.default_currency = currency
|
70
|
+
end
|
71
|
+
|
65
72
|
private
|
66
73
|
|
67
74
|
attr_reader :options
|