spree_core 4.2.0.rc3 → 4.2.2
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 +19 -0
- data/app/controllers/spree/base_controller.rb +2 -1
- data/app/controllers/spree/errors_controller.rb +11 -0
- data/app/finders/spree/orders/find_current.rb +1 -1
- data/app/finders/spree/products/find.rb +14 -3
- data/app/helpers/spree/base_helper.rb +2 -1
- data/app/helpers/spree/currency_helper.rb +34 -0
- data/app/helpers/spree/locale_helper.rb +31 -0
- data/app/helpers/spree/products_helper.rb +37 -12
- data/app/models/concerns/spree/product_scopes.rb +1 -1
- data/app/models/concerns/spree/user_payment_source.rb +1 -1
- data/app/models/spree/ability.rb +45 -30
- data/app/models/spree/app_configuration.rb +2 -2
- data/app/models/spree/app_dependencies.rb +3 -1
- data/app/models/spree/credit_card.rb +4 -0
- data/app/models/spree/image.rb +14 -14
- data/app/models/spree/line_item.rb +6 -9
- data/app/models/spree/price.rb +1 -1
- data/app/models/spree/product.rb +29 -15
- data/app/models/spree/promotion/rules/option_value.rb +1 -1
- data/app/models/spree/store.rb +38 -9
- data/app/models/spree/variant.rb +8 -8
- data/app/paginators/spree/shared/paginate.rb +8 -1
- data/app/presenters/spree/variant_presenter.rb +2 -5
- data/app/services/spree/build_localized_redirect_url.rb +101 -0
- data/app/services/spree/cart/estimate_shipping_rates.rb +1 -1
- data/app/views/spree/errors/forbidden.html.erb +0 -0
- data/app/views/spree/errors/unauthorized.html.erb +0 -0
- data/app/views/spree/shared/_base_mailer_stylesheets.html.erb +13 -2
- data/app/views/spree/shared/_purchased_items_table.html.erb +15 -6
- data/app/views/spree/shared/purchased_items_table/_adjustment.html.erb +2 -2
- data/app/views/spree/shared/purchased_items_table/_line_item.html.erb +2 -2
- data/config/locales/en.yml +8 -54
- data/config/routes.rb +2 -1
- data/db/default/spree/stores.rb +1 -0
- data/db/default/spree/zones.rb +4 -1
- data/db/migrate/20191017121054_add_supported_currencies_to_store.rb +1 -0
- data/db/migrate/20201012091259_add_filterable_column_to_spree_option_types.rb +6 -2
- data/db/migrate/20210120142527_ensure_default_locale_in_spree_stores.rb +5 -0
- data/db/migrate/20210205211040_add_supported_locales_to_spree_stores.rb +11 -0
- data/db/migrate/20210215202602_migrate_spree_i18n_globalize_config.rb +22 -0
- data/lib/generators/spree/install/install_generator.rb +9 -6
- data/lib/spree/core.rb +2 -1
- data/lib/spree/core/controller_helpers/auth.rb +3 -1
- data/lib/spree/core/controller_helpers/common.rb +6 -8
- data/lib/spree/core/controller_helpers/currency.rb +54 -0
- data/lib/spree/core/controller_helpers/locale.rb +58 -0
- data/lib/spree/core/controller_helpers/search.rb +1 -1
- data/lib/spree/core/controller_helpers/store.rb +4 -16
- data/lib/spree/core/version.rb +3 -1
- data/lib/spree/i18n.rb +12 -0
- data/lib/spree/permitted_attributes.rb +1 -1
- data/lib/spree/service_module.rb +2 -2
- data/lib/spree/testing_support/common_rake.rb +1 -1
- data/lib/spree/testing_support/controller_requests.rb +10 -10
- data/lib/spree/testing_support/factories/stock_location_factory.rb +2 -2
- data/lib/spree/testing_support/factories/store_factory.rb +1 -0
- data/lib/spree/testing_support/flatpickr_capybara.rb +101 -0
- data/lib/spree/testing_support/locale_helpers.rb +78 -0
- data/lib/spree/testing_support/next_instance_of.rb +38 -0
- data/spree_core.gemspec +1 -1
- metadata +20 -9
- data/lib/generators/spree/install/templates/config/initializers/spree_storefront.rb +0 -1
- data/lib/generators/spree/install/templates/config/spree_storefront.yml +0 -67
- data/lib/spree/core/controller_helpers/currency_helpers.rb +0 -15
@@ -57,16 +57,13 @@ module Spree
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def update_price
|
60
|
-
|
61
|
-
currency_price = Spree::Price.where(
|
62
|
-
currency: order.currency,
|
63
|
-
variant_id: variant_id
|
64
|
-
).first
|
60
|
+
currency_price = variant.price_in(order.currency)
|
65
61
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
62
|
+
self.price = if currency_price.amount.present?
|
63
|
+
currency_price.price_including_vat_for(tax_zone: tax_zone)
|
64
|
+
else
|
65
|
+
0
|
66
|
+
end
|
70
67
|
end
|
71
68
|
|
72
69
|
def copy_tax_category
|
data/app/models/spree/price.rb
CHANGED
data/app/models/spree/product.rb
CHANGED
@@ -90,6 +90,10 @@ module Spree
|
|
90
90
|
after_save :reset_nested_changes
|
91
91
|
after_touch :touch_taxons
|
92
92
|
|
93
|
+
# reset cache on save inside trasaction and transaction commit
|
94
|
+
after_save :reset_memoized_data
|
95
|
+
after_commit :reset_memoized_data
|
96
|
+
|
93
97
|
before_validation :normalize_slug, on: :update
|
94
98
|
before_validation :validate_master
|
95
99
|
|
@@ -127,6 +131,13 @@ module Spree
|
|
127
131
|
|
128
132
|
alias master_images images
|
129
133
|
|
134
|
+
def reload
|
135
|
+
%w(total_on_hand taxonomy_ids taxon_and_ancestors category category default_variant_id tax_category default_variant).each do |v|
|
136
|
+
instance_variable_set(:"@#{v}", nil)
|
137
|
+
end
|
138
|
+
super
|
139
|
+
end
|
140
|
+
|
130
141
|
# Cant use short form block syntax due to https://github.com/Netflix/fast_jsonapi/issues/259
|
131
142
|
def purchasable?
|
132
143
|
variants_including_master.any?(&:purchasable?)
|
@@ -160,7 +171,7 @@ module Spree
|
|
160
171
|
#
|
161
172
|
# @return [Spree::Variant]
|
162
173
|
def default_variant
|
163
|
-
Rails.cache.fetch(default_variant_cache_key) do
|
174
|
+
@default_variant ||= Rails.cache.fetch(default_variant_cache_key) do
|
164
175
|
if Spree::Config[:track_inventory_levels] && variants.in_stock_or_backorderable.any?
|
165
176
|
variants.in_stock_or_backorderable.first
|
166
177
|
else
|
@@ -172,11 +183,11 @@ module Spree
|
|
172
183
|
# Returns default Variant ID for Product
|
173
184
|
# @return [Integer]
|
174
185
|
def default_variant_id
|
175
|
-
default_variant.id
|
186
|
+
@default_variant_id ||= default_variant.id
|
176
187
|
end
|
177
188
|
|
178
189
|
def tax_category
|
179
|
-
super || TaxCategory.find_by(is_default: true)
|
190
|
+
@tax_category ||= super || TaxCategory.find_by(is_default: true)
|
180
191
|
end
|
181
192
|
|
182
193
|
# Adding properties and option types on creation based on a chosen prototype
|
@@ -288,11 +299,11 @@ module Spree
|
|
288
299
|
end
|
289
300
|
|
290
301
|
def total_on_hand
|
291
|
-
if any_variants_not_track_inventory?
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
302
|
+
@total_on_hand ||= if any_variants_not_track_inventory?
|
303
|
+
Float::INFINITY
|
304
|
+
else
|
305
|
+
stock_items.sum(:count_on_hand)
|
306
|
+
end
|
296
307
|
end
|
297
308
|
|
298
309
|
# Master variant may be deleted (i.e. when the product is deleted)
|
@@ -303,14 +314,11 @@ module Spree
|
|
303
314
|
end
|
304
315
|
|
305
316
|
def brand
|
306
|
-
taxons.joins(:taxonomy).find_by(spree_taxonomies: { name: Spree.t(:taxonomy_brands_name) })
|
317
|
+
@brand ||= taxons.joins(:taxonomy).find_by(spree_taxonomies: { name: Spree.t(:taxonomy_brands_name) })
|
307
318
|
end
|
308
319
|
|
309
320
|
def category
|
310
|
-
taxons.joins(:taxonomy).
|
311
|
-
where(spree_taxonomies: { name: Spree.t(:taxonomy_categories_name) }).
|
312
|
-
order(depth: :desc).
|
313
|
-
first
|
321
|
+
@category ||= taxons.joins(:taxonomy).order(depth: :desc).find_by(spree_taxonomies: { name: Spree.t(:taxonomy_categories_name) })
|
314
322
|
end
|
315
323
|
|
316
324
|
private
|
@@ -440,12 +448,12 @@ module Spree
|
|
440
448
|
end
|
441
449
|
|
442
450
|
def taxon_and_ancestors
|
443
|
-
taxons.map(&:self_and_ancestors).flatten.uniq
|
451
|
+
@taxon_and_ancestors ||= taxons.map(&:self_and_ancestors).flatten.uniq
|
444
452
|
end
|
445
453
|
|
446
454
|
# Get the taxonomy ids of all taxons assigned to this product and their ancestors.
|
447
455
|
def taxonomy_ids
|
448
|
-
taxon_and_ancestors.map(&:taxonomy_id).flatten.uniq
|
456
|
+
@taxonomy_ids ||= taxon_and_ancestors.map(&:taxonomy_id).flatten.uniq
|
449
457
|
end
|
450
458
|
|
451
459
|
# Iterate through this products taxons and taxonomies and touch their timestamps in a batch
|
@@ -471,5 +479,11 @@ module Spree
|
|
471
479
|
errors.add(:discontinue_on, :invalid_date_range)
|
472
480
|
end
|
473
481
|
end
|
482
|
+
|
483
|
+
def reset_memoized_data
|
484
|
+
%w(total_on_hand taxonomy_ids taxon_and_ancestors category default_variant_id tax_category default_variant).each do |v|
|
485
|
+
instance_variable_set(:"@#{v}", nil)
|
486
|
+
end
|
487
|
+
end
|
474
488
|
end
|
475
489
|
end
|
@@ -31,7 +31,7 @@ module Spree
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def actionable?(line_item)
|
34
|
-
product_id = line_item.
|
34
|
+
product_id = line_item.product_id
|
35
35
|
option_values_ids = line_item.variant.option_value_ids
|
36
36
|
eligible_product_ids = preferred_eligible_values.keys
|
37
37
|
eligible_value_ids = preferred_eligible_values[product_id]
|
data/app/models/spree/store.rb
CHANGED
@@ -24,6 +24,7 @@ module Spree
|
|
24
24
|
validates :mailer_logo, content_type: ['image/png', 'image/jpg', 'image/jpeg']
|
25
25
|
|
26
26
|
before_save :ensure_default_exists_and_is_unique
|
27
|
+
before_save :ensure_supported_currencies, :ensure_supported_locales
|
27
28
|
before_destroy :validate_not_default
|
28
29
|
|
29
30
|
scope :by_url, ->(url) { where('url like ?', "%#{url}%") }
|
@@ -43,28 +44,39 @@ module Spree
|
|
43
44
|
end
|
44
45
|
end
|
45
46
|
|
47
|
+
def self.available_locales
|
48
|
+
Rails.cache.fetch('stores_available_locales') do
|
49
|
+
Spree::Store.all.map(&:supported_locales_list).flatten.uniq
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
46
53
|
def supported_currencies_list
|
47
|
-
(read_attribute(:supported_currencies).to_s.split(',') << default_currency).map(&:to_s).map do |code|
|
54
|
+
@supported_currencies_list ||= (read_attribute(:supported_currencies).to_s.split(',') << default_currency).sort.map(&:to_s).map do |code|
|
48
55
|
::Money::Currency.find(code.strip)
|
49
56
|
end.uniq.compact
|
50
57
|
end
|
51
58
|
|
59
|
+
def supported_locales_list
|
60
|
+
# TODO: add support of multiple supported languages to a single Store
|
61
|
+
@supported_locales_list ||= (read_attribute(:supported_locales).to_s.split(',') << default_locale).compact.uniq.sort
|
62
|
+
end
|
63
|
+
|
52
64
|
def unique_name
|
53
|
-
"#{name} (#{code})"
|
65
|
+
@unique_name ||= "#{name} (#{code})"
|
54
66
|
end
|
55
67
|
|
56
68
|
def formatted_url
|
57
69
|
return if url.blank?
|
58
70
|
|
59
|
-
if url.match(/http:\/\/|https:\/\//)
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
71
|
+
@formatted_url ||= if url.match(/http:\/\/|https:\/\//)
|
72
|
+
url
|
73
|
+
else
|
74
|
+
Rails.env.development? ? "http://#{url}" : "https://#{url}"
|
75
|
+
end
|
64
76
|
end
|
65
77
|
|
66
78
|
def countries_available_for_checkout
|
67
|
-
checkout_zone_or_default.try(:country_list) || Spree::Country.all
|
79
|
+
@countries_available_for_checkout ||= checkout_zone_or_default.try(:country_list) || Spree::Country.all
|
68
80
|
end
|
69
81
|
|
70
82
|
def states_available_for_checkout(country)
|
@@ -72,7 +84,7 @@ module Spree
|
|
72
84
|
end
|
73
85
|
|
74
86
|
def checkout_zone_or_default
|
75
|
-
checkout_zone || Spree::Zone.default_checkout_zone
|
87
|
+
@checkout_zone_or_default ||= checkout_zone || Spree::Zone.default_checkout_zone
|
76
88
|
end
|
77
89
|
|
78
90
|
private
|
@@ -85,6 +97,22 @@ module Spree
|
|
85
97
|
end
|
86
98
|
end
|
87
99
|
|
100
|
+
def ensure_supported_locales
|
101
|
+
return unless attributes.keys.include?('supported_locales')
|
102
|
+
return if supported_locales.present?
|
103
|
+
return if default_locale.blank?
|
104
|
+
|
105
|
+
self.supported_locales = default_locale
|
106
|
+
end
|
107
|
+
|
108
|
+
def ensure_supported_currencies
|
109
|
+
return unless attributes.keys.include?('supported_currencies')
|
110
|
+
return if supported_currencies.present?
|
111
|
+
return if default_currency.blank?
|
112
|
+
|
113
|
+
self.supported_currencies = default_currency
|
114
|
+
end
|
115
|
+
|
88
116
|
def validate_not_default
|
89
117
|
if default
|
90
118
|
errors.add(:base, :cannot_destroy_default_store)
|
@@ -94,6 +122,7 @@ module Spree
|
|
94
122
|
|
95
123
|
def clear_cache
|
96
124
|
Rails.cache.delete('default_store')
|
125
|
+
Rails.cache.delete('stores_available_locales')
|
97
126
|
end
|
98
127
|
end
|
99
128
|
end
|
data/app/models/spree/variant.rb
CHANGED
@@ -123,15 +123,15 @@ module Spree
|
|
123
123
|
end
|
124
124
|
|
125
125
|
def tax_category
|
126
|
-
if self[:tax_category_id].nil?
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
126
|
+
@tax_category ||= if self[:tax_category_id].nil?
|
127
|
+
product.tax_category
|
128
|
+
else
|
129
|
+
Spree::TaxCategory.find(self[:tax_category_id])
|
130
|
+
end
|
131
131
|
end
|
132
132
|
|
133
133
|
def options_text
|
134
|
-
Spree::Variants::OptionsPresenter.new(self).to_sentence
|
134
|
+
@options_text ||= Spree::Variants::OptionsPresenter.new(self).to_sentence
|
135
135
|
end
|
136
136
|
|
137
137
|
# Default to master name
|
@@ -192,7 +192,7 @@ module Spree
|
|
192
192
|
end
|
193
193
|
|
194
194
|
def price_in(currency)
|
195
|
-
prices.detect { |price| price.currency == currency } || prices.build(currency: currency)
|
195
|
+
prices.detect { |price| price.currency == currency&.upcase } || prices.build(currency: currency&.upcase)
|
196
196
|
end
|
197
197
|
|
198
198
|
def amount_in(currency)
|
@@ -226,7 +226,7 @@ module Spree
|
|
226
226
|
end
|
227
227
|
|
228
228
|
def compare_at_price
|
229
|
-
price_in(cost_currency).try(:compare_at_amount)
|
229
|
+
@compare_at_price ||= price_in(cost_currency).try(:compare_at_amount)
|
230
230
|
end
|
231
231
|
|
232
232
|
def name_and_sku
|
@@ -4,7 +4,14 @@ module Spree
|
|
4
4
|
def initialize(collection, params)
|
5
5
|
@collection = collection
|
6
6
|
@page = params[:page]
|
7
|
-
|
7
|
+
|
8
|
+
per_page_limit = Spree::Api::Config[:api_v2_per_page_limit]
|
9
|
+
|
10
|
+
@per_page = if params[:per_page].to_i.between?(1, per_page_limit)
|
11
|
+
params[:per_page]
|
12
|
+
else
|
13
|
+
Kaminari.config.default_per_page
|
14
|
+
end
|
8
15
|
end
|
9
16
|
|
10
17
|
def call
|
@@ -2,6 +2,7 @@ module Spree
|
|
2
2
|
class VariantPresenter
|
3
3
|
include Rails.application.routes.url_helpers
|
4
4
|
include Spree::BaseHelper
|
5
|
+
include Spree::ProductsHelper
|
5
6
|
|
6
7
|
attr_reader :current_currency, :current_price_options, :current_store
|
7
8
|
|
@@ -19,7 +20,7 @@ module Spree
|
|
19
20
|
display_price: display_price(variant),
|
20
21
|
price: variant.price_in(current_currency),
|
21
22
|
display_compare_at_price: display_compare_at_price(variant),
|
22
|
-
should_display_compare_at_price: should_display_compare_at_price(variant),
|
23
|
+
should_display_compare_at_price: should_display_compare_at_price?(variant),
|
23
24
|
is_product_available_in_currency: @is_product_available_in_currency,
|
24
25
|
backorderable: backorderable?(variant),
|
25
26
|
in_stock: in_stock?(variant),
|
@@ -75,9 +76,5 @@ module Spree
|
|
75
76
|
purchasable: variant.purchasable?
|
76
77
|
}
|
77
78
|
end
|
78
|
-
|
79
|
-
def should_display_compare_at_price(variant)
|
80
|
-
variant.compare_at_price.present? && variant.compare_at_price > variant.price
|
81
|
-
end
|
82
79
|
end
|
83
80
|
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
class BuildLocalizedRedirectUrl
|
5
|
+
prepend Spree::ServiceModule::Base
|
6
|
+
|
7
|
+
LOCALE_REGEX = /^\/[A-Za-z]{2}\/|^\/[A-Za-z]{2}-[A-Za-z]{2}\/|^\/[A-Za-z]{2}$|^\/[A-Za-z]{2}-[A-Za-z]{2}$/.freeze
|
8
|
+
|
9
|
+
SUPPORTED_PATHS_REGEX = /\/(products|t\/|cart|checkout|addresses|content)/.freeze
|
10
|
+
|
11
|
+
# rubocop:disable Lint/UnusedMethodArgument
|
12
|
+
def call(url:, locale:, default_locale: nil)
|
13
|
+
run :initialize_url_object
|
14
|
+
run :generate_new_path
|
15
|
+
run :append_locale_param
|
16
|
+
run :build_url
|
17
|
+
end
|
18
|
+
# rubocop:enable Lint/UnusedMethodArgument
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def initialize_url_object(url:, locale:, default_locale:)
|
23
|
+
success(
|
24
|
+
url: URI(url),
|
25
|
+
locale: locale,
|
26
|
+
default_locale_supplied: default_locale_supplied?(locale, default_locale)
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def generate_new_path(url:, locale:, default_locale_supplied:)
|
31
|
+
unless supported_path?(url.path)
|
32
|
+
return success(
|
33
|
+
url: url,
|
34
|
+
locale: locale,
|
35
|
+
path: cleanup_path(url.path),
|
36
|
+
default_locale_supplied: default_locale_supplied,
|
37
|
+
locale_added_to_path: false
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
new_path = if default_locale_supplied
|
42
|
+
maches_locale_regex?(url.path) ? url.path.gsub(LOCALE_REGEX, '/') : url.path
|
43
|
+
else
|
44
|
+
maches_locale_regex?(url.path) ? url.path.gsub(LOCALE_REGEX, "/#{locale}/") : "/#{locale}#{url.path}"
|
45
|
+
end
|
46
|
+
|
47
|
+
success(
|
48
|
+
url: url,
|
49
|
+
locale: locale,
|
50
|
+
path: cleanup_path(new_path),
|
51
|
+
default_locale_supplied: default_locale_supplied,
|
52
|
+
locale_added_to_path: true
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
56
|
+
def append_locale_param(url:, locale:, path:, default_locale_supplied:, locale_added_to_path:)
|
57
|
+
return success(url: url, path: path, query: url.query) if locale_added_to_path
|
58
|
+
|
59
|
+
query_params = Rack::Utils.parse_nested_query(url.query)
|
60
|
+
|
61
|
+
if default_locale_supplied
|
62
|
+
query_params.delete('locale')
|
63
|
+
else
|
64
|
+
query_params.merge!('locale' => locale)
|
65
|
+
end
|
66
|
+
|
67
|
+
query_string = query_params.any? ? query_params.to_query : nil
|
68
|
+
|
69
|
+
success(url: url, path: path, query: query_string)
|
70
|
+
end
|
71
|
+
|
72
|
+
def build_url(url:, path:, query:)
|
73
|
+
localized_url = builder_class(url).build(host: url.host, port: url.port, path: path, query: query).to_s
|
74
|
+
success(localized_url)
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def supported_path?(path)
|
80
|
+
return true if path.blank? || path == '/' || maches_locale_regex?(path)
|
81
|
+
|
82
|
+
path.match(SUPPORTED_PATHS_REGEX)
|
83
|
+
end
|
84
|
+
|
85
|
+
def maches_locale_regex?(path)
|
86
|
+
path.match(LOCALE_REGEX)[0].gsub('/', '') if path.match(LOCALE_REGEX)
|
87
|
+
end
|
88
|
+
|
89
|
+
def default_locale_supplied?(locale, default_locale)
|
90
|
+
default_locale.present? && default_locale.to_s == locale.to_s
|
91
|
+
end
|
92
|
+
|
93
|
+
def cleanup_path(path)
|
94
|
+
path.chomp('/').gsub('//', '/')
|
95
|
+
end
|
96
|
+
|
97
|
+
def builder_class(url)
|
98
|
+
url.scheme == 'http' ? URI::HTTP : URI::HTTPS
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
File without changes
|
File without changes
|
@@ -249,11 +249,9 @@
|
|
249
249
|
color: #51545E;
|
250
250
|
font-size: 15px;
|
251
251
|
line-height: 18px;
|
252
|
-
width: 62%;
|
253
252
|
}
|
254
253
|
|
255
254
|
.purchase_image {
|
256
|
-
width: 18%;
|
257
255
|
padding: 5px;
|
258
256
|
}
|
259
257
|
|
@@ -289,10 +287,20 @@
|
|
289
287
|
color: #333333;
|
290
288
|
}
|
291
289
|
|
290
|
+
.purchase_total--name {
|
291
|
+
margin: 0;
|
292
|
+
text-align: right;
|
293
|
+
color: #333333;
|
294
|
+
}
|
295
|
+
|
292
296
|
.purchase_total--label {
|
293
297
|
padding: 0 15px 0 0;
|
294
298
|
}
|
295
299
|
|
300
|
+
.purchase_total-col {
|
301
|
+
vertical-align: bottom;
|
302
|
+
}
|
303
|
+
|
296
304
|
body {
|
297
305
|
background-color: #F2F4F6;
|
298
306
|
color: #51545E;
|
@@ -402,6 +410,9 @@
|
|
402
410
|
.email-footer {
|
403
411
|
width: 100% !important;
|
404
412
|
}
|
413
|
+
.content-cell {
|
414
|
+
padding: 40px 15px !important;
|
415
|
+
}
|
405
416
|
}
|
406
417
|
|
407
418
|
@media (prefers-color-scheme: dark) {
|