spree_core 4.2.0.rc2 → 4.2.0.rc3
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 +0 -2
- data/app/finders/spree/addresses/find.rb +1 -12
- data/app/finders/spree/base_finder.rb +14 -0
- data/app/finders/spree/countries/find.rb +11 -3
- data/app/finders/spree/credit_cards/find.rb +2 -2
- data/app/finders/spree/orders/find_current.rb +1 -1
- data/app/helpers/spree/base_helper.rb +1 -7
- data/app/mailers/spree/base_mailer.rb +4 -4
- data/app/mailers/spree/order_mailer.rb +3 -3
- data/app/mailers/spree/reimbursement_mailer.rb +1 -1
- data/app/mailers/spree/shipment_mailer.rb +1 -1
- data/app/models/concerns/spree/default_price.rb +1 -5
- data/app/models/concerns/spree/user_methods.rb +2 -2
- data/app/models/spree/ability.rb +2 -6
- data/app/models/spree/address.rb +4 -0
- data/app/models/spree/app_dependencies.rb +4 -2
- data/app/models/spree/base.rb +5 -0
- data/app/models/spree/fulfilment_changer.rb +58 -16
- data/app/models/spree/inventory_unit.rb +2 -7
- data/app/models/spree/line_item.rb +1 -6
- data/app/models/spree/order.rb +1 -0
- data/app/models/spree/payment.rb +18 -4
- data/app/models/spree/payment/processing.rb +2 -2
- data/app/models/spree/payment_method.rb +3 -3
- data/app/models/spree/price.rb +1 -6
- data/app/models/spree/product.rb +12 -2
- data/app/models/spree/promotion/rules/product.rb +2 -1
- data/app/models/spree/promotion/rules/user.rb +2 -1
- data/app/models/spree/refund.rb +2 -2
- data/app/models/spree/return_item/eligibility_validator/default.rb +0 -2
- data/app/models/spree/return_item/eligibility_validator/{r_m_a_required.rb → rma_required.rb} +0 -0
- data/app/models/spree/shipment.rb +1 -1
- data/app/models/spree/shipping_method.rb +1 -5
- data/app/models/spree/shipping_rate.rb +2 -11
- data/app/models/spree/stock/availability_validator.rb +3 -4
- data/app/models/spree/stock_item.rb +1 -5
- data/app/models/spree/store.rb +24 -0
- data/app/models/spree/store_credit.rb +1 -1
- data/app/models/spree/variant.rb +1 -8
- data/app/models/spree/zone.rb +13 -4
- data/app/services/spree/account/addresses/create.rb +6 -1
- data/app/services/spree/account/addresses/{base.rb → helper.rb} +1 -3
- data/app/services/spree/account/addresses/update.rb +6 -1
- data/app/services/spree/compare_line_items.rb +4 -2
- data/app/sorters/spree/base_sorter.rb +35 -0
- data/app/sorters/spree/orders/sort.rb +1 -37
- data/app/sorters/spree/products/sort.rb +9 -32
- data/app/validators/email_validator.rb +1 -1
- data/config/initializers/inflections.rb +3 -0
- data/config/initializers/rails61_fixes.rb +3 -0
- data/config/locales/en.yml +25 -8
- data/db/migrate/20130326175857_add_stock_location_to_rma.rb +1 -1
- data/db/migrate/20201127084048_add_default_country_kind_to_spree_zones.rb +5 -0
- data/db/migrate/20210112193440_remove_contact_email_from_spree_stores.rb +5 -0
- data/db/migrate/20210114182625_create_spree_payment_methods_stores.rb +10 -0
- data/db/migrate/20210114220232_migrate_data_payment_methods_stores.rb +15 -0
- data/db/migrate/20210117112551_remove_store_id_from_spree_payment_methods.rb +5 -0
- data/lib/spree/core/product_filters.rb +3 -3
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/i18n.rb +7 -21
- data/lib/spree/permitted_attributes.rb +2 -2
- data/lib/spree/service_module.rb +6 -2
- data/lib/spree/testing_support/capybara_config.rb +1 -1
- data/lib/spree/testing_support/factories/shipment_factory.rb +7 -9
- data/lib/spree/testing_support/factories/zone_factory.rb +16 -13
- data/lib/spree/testing_support/order_walkthrough.rb +8 -3
- data/lib/spree/testing_support/rspec_retry_config.rb +10 -0
- data/spree_core.gemspec +4 -3
- metadata +55 -21
- data/lib/spree/i18n/base.rb +0 -17
- data/lib/spree/i18n/initializer.rb +0 -1
@@ -1,42 +1,6 @@
|
|
1
1
|
module Spree
|
2
2
|
module Orders
|
3
|
-
class Sort
|
4
|
-
attr_reader :scope, :sort
|
5
|
-
|
6
|
-
def initialize(scope, params)
|
7
|
-
@scope = scope
|
8
|
-
@sort = params[:sort]
|
9
|
-
end
|
10
|
-
|
11
|
-
def call
|
12
|
-
orders = completed_at(scope)
|
13
|
-
|
14
|
-
orders
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def desc_order
|
20
|
-
@desc_order ||= String(sort)[0] == '-'
|
21
|
-
end
|
22
|
-
|
23
|
-
def sort_field
|
24
|
-
@sort_field ||= desc_order ? sort[1..-1] : sort
|
25
|
-
end
|
26
|
-
|
27
|
-
def order_direction
|
28
|
-
desc_order ? :asc : :desc
|
29
|
-
end
|
30
|
-
|
31
|
-
def completed_at?
|
32
|
-
sort_field.eql?('completed_at')
|
33
|
-
end
|
34
|
-
|
35
|
-
def completed_at(orders)
|
36
|
-
return orders unless completed_at?
|
37
|
-
|
38
|
-
orders.order(completed_at: order_direction)
|
39
|
-
end
|
3
|
+
class Sort < ::Spree::BaseSorter
|
40
4
|
end
|
41
5
|
end
|
42
6
|
end
|
@@ -1,53 +1,30 @@
|
|
1
1
|
module Spree
|
2
2
|
module Products
|
3
|
-
class Sort
|
4
|
-
def initialize(scope, params,
|
5
|
-
|
6
|
-
@sort = params[:sort]
|
3
|
+
class Sort < ::Spree::BaseSorter
|
4
|
+
def initialize(scope, current_currency, params = {}, allowed_sort_attributes = [])
|
5
|
+
super(scope, params, allowed_sort_attributes)
|
7
6
|
@currency = params[:currency] || current_currency
|
8
7
|
end
|
9
8
|
|
10
9
|
def call
|
11
|
-
products =
|
12
|
-
products =
|
10
|
+
products = by_param_attribute(scope)
|
11
|
+
products = by_price(products)
|
13
12
|
|
14
13
|
products.distinct
|
15
14
|
end
|
16
15
|
|
17
16
|
private
|
18
17
|
|
19
|
-
attr_reader :sort, :scope, :currency
|
20
|
-
|
21
|
-
def desc_order
|
22
|
-
@desc_order ||= String(sort)[0] == '-'
|
23
|
-
end
|
24
|
-
|
25
|
-
def sort_field
|
26
|
-
@sort_field ||= desc_order ? sort[1..-1] : sort
|
27
|
-
end
|
28
|
-
|
29
|
-
def updated_at?
|
30
|
-
sort_field == 'updated_at'
|
31
|
-
end
|
18
|
+
attr_reader :sort, :scope, :currency, :allowed_sort_attributes
|
32
19
|
|
33
20
|
def price?
|
34
21
|
sort_field == 'price'
|
35
22
|
end
|
36
23
|
|
37
|
-
def
|
38
|
-
|
39
|
-
end
|
40
|
-
|
41
|
-
def updated_at(products)
|
42
|
-
return products unless updated_at?
|
43
|
-
|
44
|
-
products.order(updated_at: order_direction)
|
45
|
-
end
|
46
|
-
|
47
|
-
def price(products)
|
48
|
-
return products unless price?
|
24
|
+
def by_price(scope)
|
25
|
+
return scope unless price?
|
49
26
|
|
50
|
-
|
27
|
+
scope.joins(master: :prices).
|
51
28
|
select("#{Spree::Product.table_name}.*, #{Spree::Price.table_name}.amount").
|
52
29
|
distinct.
|
53
30
|
where(spree_prices: { currency: currency }).
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class EmailValidator < ActiveModel::EachValidator
|
2
2
|
def validate_each(record, attribute, value)
|
3
3
|
unless value =~ /\A[^@\s]+@[^@\s]+\z/
|
4
|
-
record.errors.add(attribute, :invalid, { value: value }.merge!(options))
|
4
|
+
record.errors.add(attribute, :invalid, **{ value: value }.merge!(options))
|
5
5
|
end
|
6
6
|
end
|
7
7
|
end
|
data/config/locales/en.yml
CHANGED
@@ -6,7 +6,7 @@ en:
|
|
6
6
|
attributes:
|
7
7
|
desired_shipment:
|
8
8
|
can_not_transfer_within_same_shipment: can not be same as current shipment
|
9
|
-
|
9
|
+
has_not_enough_stock_at_desired_location: has not enough stock in desired stock location
|
10
10
|
current_shipment:
|
11
11
|
has_already_been_shipped: has already been shipped
|
12
12
|
can_not_have_backordered_inventory_units: has backordered inventory units
|
@@ -142,7 +142,8 @@ en:
|
|
142
142
|
url: Site URL
|
143
143
|
meta_description: Meta Description
|
144
144
|
meta_keywords: Meta Keywords
|
145
|
-
|
145
|
+
seo_robots: SEO Robots
|
146
|
+
seo_title: SEO Title
|
146
147
|
name: Site Name
|
147
148
|
mail_from_address: Mail From Address
|
148
149
|
spree/store_credit:
|
@@ -695,7 +696,6 @@ en:
|
|
695
696
|
confirm: Confirm
|
696
697
|
confirm_delete: Confirm Deletion
|
697
698
|
confirm_password: Password Confirmation
|
698
|
-
contact_email: Contact email
|
699
699
|
contact_phone: Contact phone
|
700
700
|
contact_us: Contact us
|
701
701
|
continue: Continue
|
@@ -850,6 +850,7 @@ en:
|
|
850
850
|
blank: can't be blank
|
851
851
|
could_not_create_taxon: Could not create taxon
|
852
852
|
no_shipping_methods_available: No shipping methods available for selected location, please change your address and try again.
|
853
|
+
cannot_remove_icon: Cannot remove image
|
853
854
|
services:
|
854
855
|
get_shipping_rates:
|
855
856
|
no_shipping_address: To generate Shipping Rates Order needs to have a Shipping Address
|
@@ -900,7 +901,7 @@ en:
|
|
900
901
|
flat_rate_per_order: Flat Rate
|
901
902
|
flexible_rate: Flexible Rate
|
902
903
|
follow_us: Follow us
|
903
|
-
|
904
|
+
footer: Footer
|
904
905
|
forgot_password: Forgot password?
|
905
906
|
free: Free
|
906
907
|
free_shipping: Free Shipping
|
@@ -958,8 +959,6 @@ en:
|
|
958
959
|
supported_locales: Supported Locales
|
959
960
|
this_file_language: English (US)
|
960
961
|
translations: Translations
|
961
|
-
checkout_zone_warning_html: "Selecting a Zone will limit customers on Checkout to Addresses in Countries in that Zone. <br />
|
962
|
-
Please see documentation: <a href='https://guides.spreecommerce.org/user/configuration/configuring_geography.html#zones' target='_blank' class='alert-link'>https://guides.spreecommerce.org/user/configuration/configuring_geography.html#zones</a>"
|
963
962
|
icon: Icon
|
964
963
|
image: Image
|
965
964
|
images: Images
|
@@ -1131,6 +1130,7 @@ en:
|
|
1131
1130
|
no_available_date_set: No available date set
|
1132
1131
|
no_country: No country set
|
1133
1132
|
no_payment_found: No payment found
|
1133
|
+
no_payment_provider_settings_message: This payment provider has no custom settings available
|
1134
1134
|
no_pending_payments: No pending payments
|
1135
1135
|
no_product_available:
|
1136
1136
|
for_this_quantity: Sorry, it looks like some products are not available in selected quantity.
|
@@ -1153,6 +1153,7 @@ en:
|
|
1153
1153
|
not_found: ! '%{resource} is not found'
|
1154
1154
|
note: Note
|
1155
1155
|
notice_messages:
|
1156
|
+
icon_removed: Image has been successfully removed
|
1156
1157
|
prices_saved: Prices successfully saved
|
1157
1158
|
product_cloned: Product has been cloned
|
1158
1159
|
product_deleted: Product has been deleted
|
@@ -1253,6 +1254,7 @@ en:
|
|
1253
1254
|
payment_processing_failed: Payment could not be processed, please check the details you entered
|
1254
1255
|
payment_processor_choose_banner_text: If you need help choosing a payment processor, please visit
|
1255
1256
|
payment_processor_choose_link: our payments page
|
1257
|
+
payment_provider_settings: Payment Provider Settings
|
1256
1258
|
payment_state: Payment State
|
1257
1259
|
payment_states:
|
1258
1260
|
balance_due: balance due
|
@@ -1437,6 +1439,7 @@ en:
|
|
1437
1439
|
rejected: Rejected
|
1438
1440
|
remember_me: Remember me
|
1439
1441
|
remove: Remove
|
1442
|
+
remove_image: Remove Image
|
1440
1443
|
rename: Rename
|
1441
1444
|
report: Report
|
1442
1445
|
reports: Reports
|
@@ -1512,12 +1515,14 @@ en:
|
|
1512
1515
|
select_a_return_authorization_reason: Select a reason for the return authorization
|
1513
1516
|
select_a_stock_location: Select a stock location
|
1514
1517
|
select_a_store_credit_reason: Select a reason for the store credit
|
1518
|
+
select_an_option: Select an option
|
1515
1519
|
select_stock: Select stock
|
1516
1520
|
selected_quantity_not_available: ! 'selected of %{item} is not available.'
|
1517
|
-
seo: SEO
|
1518
1521
|
send_copy_of_all_mails_to: Send Copy of All Mails To
|
1519
1522
|
send_mails_as: Send Mails As
|
1520
|
-
|
1523
|
+
seo: SEO
|
1524
|
+
seo_robots: SEO Robots
|
1525
|
+
seo_title: SEO Title
|
1521
1526
|
server: Server
|
1522
1527
|
server_error: The server returned an error
|
1523
1528
|
settings: Settings
|
@@ -1653,6 +1658,18 @@ en:
|
|
1653
1658
|
unable_to_create: Unable to create store.
|
1654
1659
|
unable_to_update: Unable to update store.
|
1655
1660
|
unable_to_delete: Unable to delete store.
|
1661
|
+
store_form:
|
1662
|
+
code_help: "Store unique identifier, which is an abbreviated version of the store’s name (used as the layout directory name, and also helpful for separating templates by store)"
|
1663
|
+
checkout_zone_help: "Selecting a Zone will limit customers on Checkout to Addresses in Countries or States in that Zone.
|
1664
|
+
For more information <a href='https://guides.spreecommerce.org/user/configuration/configuring_geography.html#zones' target='_blank' class='alert-link'>please see documentation</a>"
|
1665
|
+
languages_help: "Install <a href='https://github.com/spree-contrib/spree_i18n target='_blank' class='alert-link'>Spree I18n extension</a> to add more languages"
|
1666
|
+
social_help: "If you want to link to your social accounts in the footer part of your website please fill below fields"
|
1667
|
+
default_country_help: "This is the Country that will be pre-selected on the Checkout Address form"
|
1668
|
+
footer_help: "This content is visible in the footer section of your Store"
|
1669
|
+
mail_from_address_help: "This is the email which will be the sender of all your Store emails (Order Confirmation, Shipment notification etc)"
|
1670
|
+
customer_support_email_help: "This email is visible to your Store visitors in the Footer section"
|
1671
|
+
new_order_notifications_email_help: "If you want to receive an email notification every time someone places an Order please provide an email address for that notification to be sent to"
|
1672
|
+
seo_robots: "Please check <a href='https://developers.google.com/search/reference/robots_meta_tag' target='_blank'>this page for more help</a>"
|
1656
1673
|
store_set_default_button: Set as default
|
1657
1674
|
stores: Stores
|
1658
1675
|
store_credit_name: Store Credit
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class CreateSpreePaymentMethodsStores < ActiveRecord::Migration[6.0]
|
2
|
+
def change
|
3
|
+
create_table :spree_payment_methods_stores, id: false do |t|
|
4
|
+
t.belongs_to :payment_method
|
5
|
+
t.belongs_to :store
|
6
|
+
end
|
7
|
+
|
8
|
+
add_index :spree_payment_methods_stores, [:payment_method_id, :store_id], unique: true, name: 'payment_mentod_id_store_id_unique_index'
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class MigrateDataPaymentMethodsStores < ActiveRecord::Migration[6.0]
|
2
|
+
def up
|
3
|
+
Spree::PaymentMethod.all.each do |payment_method|
|
4
|
+
next if payment_method.store_ids.any?
|
5
|
+
|
6
|
+
if payment_method[:store_id].present?
|
7
|
+
payment_method.store_ids = payment_method[:store_id]
|
8
|
+
else
|
9
|
+
payment_method.store_ids = Spree::Store.ids
|
10
|
+
end
|
11
|
+
|
12
|
+
payment_method.save
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -68,9 +68,9 @@ module Spree
|
|
68
68
|
def self.price_filter
|
69
69
|
v = Spree::Price.arel_table
|
70
70
|
conds = [[Spree.t(:under_price, price: format_price(10)), v[:amount].lteq(10)],
|
71
|
-
["#{format_price(10)} - #{format_price(15)}", v[:amount].
|
72
|
-
["#{format_price(15)} - #{format_price(18)}", v[:amount].
|
73
|
-
["#{format_price(18)} - #{format_price(20)}", v[:amount].
|
71
|
+
["#{format_price(10)} - #{format_price(15)}", v[:amount].between(10..15)],
|
72
|
+
["#{format_price(15)} - #{format_price(18)}", v[:amount].between(15..18)],
|
73
|
+
["#{format_price(18)} - #{format_price(20)}", v[:amount].between(18..20)],
|
74
74
|
[Spree.t(:or_over_price, price: format_price(20)), v[:amount].gteq(20)]]
|
75
75
|
{
|
76
76
|
name: Spree.t(:price_range),
|
data/lib/spree/core/version.rb
CHANGED
data/lib/spree/i18n.rb
CHANGED
@@ -1,35 +1,21 @@
|
|
1
1
|
require 'i18n'
|
2
2
|
require 'active_support/core_ext/array/extract_options'
|
3
|
-
require '
|
3
|
+
require 'action_view'
|
4
4
|
|
5
5
|
module Spree
|
6
|
-
|
7
|
-
|
6
|
+
class TranslationHelperWrapper
|
7
|
+
include ActionView::Helpers::TranslationHelper
|
8
|
+
end
|
8
9
|
|
9
10
|
class << self
|
10
11
|
# Add spree namespace and delegate to Rails TranslationHelper for some nice
|
11
12
|
# extra functionality. e.g return reasonable strings for missing translations
|
12
|
-
def translate(
|
13
|
-
|
13
|
+
def translate(key, options = {})
|
14
|
+
options[:scope] = [*options[:scope]].unshift(:spree).uniq
|
14
15
|
|
15
|
-
options
|
16
|
-
options[:scope] = [*options[:scope]].unshift(:spree)
|
17
|
-
args << options
|
18
|
-
super(*args)
|
16
|
+
TranslationHelperWrapper.new.translate(key, **options)
|
19
17
|
end
|
20
18
|
|
21
19
|
alias t translate
|
22
|
-
|
23
|
-
def context
|
24
|
-
Spree::ViewContext.context
|
25
|
-
end
|
26
|
-
|
27
|
-
def virtual_path
|
28
|
-
if context
|
29
|
-
path = context.instance_variable_get('@virtual_path')
|
30
|
-
|
31
|
-
path&.gsub(/spree/, '')
|
32
|
-
end
|
33
|
-
end
|
34
20
|
end
|
35
21
|
end
|
@@ -99,9 +99,9 @@ module Spree
|
|
99
99
|
@@store_attributes = [:name, :url, :seo_title, :code, :meta_keywords, :logo,
|
100
100
|
:meta_description, :default_currency, :mail_from_address,
|
101
101
|
:customer_support_email, :facebook, :twitter, :instagram,
|
102
|
-
:description, :address, :
|
102
|
+
:description, :address, :contact_phone,
|
103
103
|
:default_locale, :default_country_id, :supported_currencies,
|
104
|
-
:new_order_notifications_email, :mailer_logo, :checkout_zone_id]
|
104
|
+
:new_order_notifications_email, :mailer_logo, :checkout_zone_id, :seo_robots]
|
105
105
|
|
106
106
|
@@store_credit_attributes = %i[amount currency category_id memo]
|
107
107
|
|
data/lib/spree/service_module.rb
CHANGED
@@ -47,7 +47,11 @@ module Spree
|
|
47
47
|
def call(input = nil)
|
48
48
|
input ||= {}
|
49
49
|
@_passed_input = Result.new(true, input)
|
50
|
-
result =
|
50
|
+
result = if input.is_a?(Hash)
|
51
|
+
super(**input)
|
52
|
+
else
|
53
|
+
super(input)
|
54
|
+
end
|
51
55
|
@_passed_input = result if result.is_a? Result
|
52
56
|
enforce_data_format
|
53
57
|
@_passed_input
|
@@ -71,7 +75,7 @@ module Spree
|
|
71
75
|
end
|
72
76
|
|
73
77
|
begin
|
74
|
-
@_passed_input = callable.call(
|
78
|
+
@_passed_input = callable.call(**@_passed_input.value)
|
75
79
|
rescue ArgumentError => e
|
76
80
|
if e.message.include? 'missing'
|
77
81
|
raise IncompatibleParamsPassed, "You didn't pass #{e.message} to callable '#{callable.name}'"
|
@@ -8,15 +8,13 @@ FactoryBot.define do
|
|
8
8
|
|
9
9
|
after(:create) do |shipment, _evalulator|
|
10
10
|
shipment.add_shipping_method(create(:shipping_method), true)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
)
|
19
|
-
end
|
11
|
+
shipment.order.line_items.map do |line_item|
|
12
|
+
shipment.inventory_units.create(
|
13
|
+
order_id: shipment.order_id,
|
14
|
+
variant_id: line_item.variant_id,
|
15
|
+
line_item_id: line_item.id,
|
16
|
+
quantity: line_item.quantity
|
17
|
+
)
|
20
18
|
end
|
21
19
|
end
|
22
20
|
end
|
@@ -1,24 +1,27 @@
|
|
1
1
|
FactoryBot.define do
|
2
|
-
factory :global_zone, class: Spree::Zone do
|
3
|
-
sequence(:name) { |n| "GlobalZone_#{n}" }
|
4
|
-
description { generate(:random_string) }
|
5
|
-
zone_members do |proxy|
|
6
|
-
zone = proxy.instance_eval { @instance }
|
7
|
-
Spree::Country.all.map do |c|
|
8
|
-
Spree::ZoneMember.create(zoneable: c, zone: zone)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
2
|
factory :zone, class: Spree::Zone do
|
14
3
|
name { generate(:random_string) }
|
15
4
|
description { generate(:random_string) }
|
16
5
|
|
17
6
|
factory :zone_with_country do
|
7
|
+
kind { :country }
|
8
|
+
|
18
9
|
zone_members do |proxy|
|
19
10
|
zone = proxy.instance_eval { @instance }
|
20
|
-
|
21
|
-
[Spree::ZoneMember.create(zoneable: country, zone: zone)]
|
11
|
+
|
12
|
+
[Spree::ZoneMember.create(zoneable: create(:country), zone: zone)]
|
13
|
+
end
|
14
|
+
|
15
|
+
factory :global_zone, class: Spree::Zone do
|
16
|
+
sequence(:name) { |n| "GlobalZone_#{n}" }
|
17
|
+
|
18
|
+
zone_members do |proxy|
|
19
|
+
zone = proxy.instance_eval { @instance }
|
20
|
+
|
21
|
+
Spree::Country.all.map do |country|
|
22
|
+
Spree::ZoneMember.where(zoneable: country, zone: zone).first_or_create
|
23
|
+
end
|
24
|
+
end
|
22
25
|
end
|
23
26
|
end
|
24
27
|
end
|