ba_spree 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +673 -0
- data/README.md +150 -0
- data/app/assets/config/manifest.js +1 -0
- data/app/assets/javascripts/ba_spree/admin_overrides/query_builder_controller.js +505 -0
- data/app/assets/javascripts/ba_spree/storefront/ba_spree_local_time.js +9 -0
- data/app/assets/stylesheets/spree/admin/custom.scss +40 -0
- data/app/controllers/ba_spree/checkout_controller_decorator.rb +111 -0
- data/app/controllers/ba_spree/store_controller_decorator.rb +55 -0
- data/app/controllers/concerns/ba_spree/theme_concern_decorator.rb +16 -0
- data/app/controllers/spree/admin/assets_controller_decorator.rb +48 -0
- data/app/controllers/spree/admin/products_controller_decorator.rb +25 -0
- data/app/controllers/spree/admin/promotion_rules_controller_decorator.rb +30 -0
- data/app/controllers/spree/admin/users_controller_decorator.rb +34 -0
- data/app/controllers/spree/contacts_controller_decorator.rb +23 -0
- data/app/controllers/spree/digital_links_controller.rb +61 -0
- data/app/controllers/spree/orders_controller_decorator.rb +24 -0
- data/app/decorators/ba_spree/product_pricing_decorator.rb +65 -0
- data/app/decorators/spree/current_decorator.rb +17 -0
- data/app/decorators/spree/money_decorator.rb +51 -0
- data/app/decorators/spree/order_email_subscriber_decorator.rb +64 -0
- data/app/decorators/spree/page_sections/featured_posts_decorator.rb +17 -0
- data/app/helpers/currency_rounding_helper.rb +10 -0
- data/app/helpers/spree/admin/filter_params_preservation.rb +130 -0
- data/app/helpers/spree/admin/navigation_helper_decorator.rb +23 -0
- data/app/helpers/spree/admin/promotion_rules_helper_decorator.rb +33 -0
- data/app/helpers/spree/admin/table_helper_decorator.rb +40 -0
- data/app/helpers/spree/base_helper_decorator.rb +63 -0
- data/app/helpers/spree/checkout_analytics_helper_decorator.rb +32 -0
- data/app/javascript/ba_spree/controllers/disable_when_hidden_controller.js +70 -0
- data/app/javascript/ba_spree/index.js +11 -0
- data/app/javascript/spree/admin/controllers/calendar_range_controller.js +61 -0
- data/app/javascript/spree/admin/controllers/slug_form_controller.js +17 -0
- data/app/models/ba_spree/address_decorator.rb +43 -0
- data/app/models/ba_spree/adjustment_decorator.rb +13 -0
- data/app/models/ba_spree/order_decorator.rb +95 -0
- data/app/models/ba_spree/order_updater_decorator.rb +33 -0
- data/app/models/ba_spree/payment_method_decorator.rb +10 -0
- data/app/models/ba_spree/product_decorator.rb +44 -0
- data/app/models/ba_spree/store_decorator.rb +23 -0
- data/app/models/ba_spree/variant_decorator.rb +49 -0
- data/app/models/concerns/spree/adjustment_source_decorator.rb +66 -0
- data/app/models/concerns/spree/product_property_metafields.rb +52 -0
- data/app/models/spree/adjustable/adjuster/promotion_decorator.rb +16 -0
- data/app/models/spree/admin/table/filter_decorator.rb +52 -0
- data/app/models/spree/admin/table/filter_group_decorator.rb +64 -0
- data/app/models/spree/asset_decorator.rb +102 -0
- data/app/models/spree/contact_decorator.rb +22 -0
- data/app/models/spree/digital_link_decorator.rb +9 -0
- data/app/models/spree/export_decorator.rb +34 -0
- data/app/models/spree/line_item_destroy_callback_decorator.rb +30 -0
- data/app/models/spree/metafield_definition_decorator.rb +34 -0
- data/app/models/spree/option_type_decorator.rb +22 -0
- data/app/models/spree/option_value_decorator.rb +19 -0
- data/app/models/spree/option_value_variant_decorator.rb +30 -0
- data/app/models/spree/order/address_book_decorator.rb +14 -0
- data/app/models/spree/order_merger_decorator.rb +29 -0
- data/app/models/spree/price_rules/customer_group_rule_decorator.rb +18 -0
- data/app/models/spree/price_rules/user_rule_decorator.rb +25 -0
- data/app/models/spree/price_rules/volume_rule_decorator.rb +25 -0
- data/app/models/spree/price_rules/zone_rule_decorator.rb +25 -0
- data/app/models/spree/pricing/batch_resolver.rb +96 -0
- data/app/models/spree/promotion_handler/cart_decorator.rb +51 -0
- data/app/models/spree/stock/packer_decorator.rb +61 -0
- data/app/models/spree/stock/prioritizer_decorator.rb +27 -0
- data/app/models/spree/tax_rate_decorator.rb +93 -0
- data/app/models/spree/taxon_decorator.rb +42 -0
- data/app/models/spree/user_bill_address_sync_decorator.rb +33 -0
- data/app/overrides/add_ba_spree_storefront_javascript_importmap_tags.rb +8 -0
- data/app/overrides/add_cache_to_product_listing_page.rb +41 -0
- data/app/overrides/add_class_to_login_link.rb +6 -0
- data/app/overrides/add_confirm_state_to_checkout_content_block.rb.rb +30 -0
- data/app/overrides/add_promotions_nav.rb +8 -0
- data/app/overrides/add_turbo_frame_to_admin_order_line_item_edit_link.rb +23 -0
- data/app/overrides/add_turbo_frame_to_promotion_action_edit_link.rb +20 -0
- data/app/overrides/add_turbo_stream_format_to_cart_path_in_cart_pane.rb +8 -0
- data/app/overrides/ba_spree_local_time_add_custom_javascript_import_map_tags.rb +8 -0
- data/app/overrides/disable_hidden_bill_address_fields_on_payment.rb +15 -0
- data/app/overrides/disable_turbo_on_user_registration_form.rb +18 -0
- data/app/overrides/fix_coupon_apply_button_layout.rb +7 -0
- data/app/overrides/hide_gift_cards_and_store_credits_from_account_nav.rb +11 -0
- data/app/overrides/hide_shipping_message_for_digital_only_orders.rb +15 -0
- data/app/overrides/localize_apply_button_text.rb +6 -0
- data/app/overrides/localize_newsletter_button_text.rb +6 -0
- data/app/overrides/replace_announcement_bar_text.rb +6 -0
- data/app/overrides/replace_button_edit_checkout.rb +10 -0
- data/app/overrides/replace_checkout_delivery_info.rb +6 -0
- data/app/overrides/replace_checkout_pay_button_with_dynamic_label.rb +14 -0
- data/app/overrides/replace_variant_not_available_button.rb +19 -0
- data/app/overrides/set_logo_width_height_in_admin_store_basic_form.rb +12 -0
- data/app/overrides/show_breadcrumbs_on_taxon_page.rb +30 -0
- data/app/overrides/show_individual_adjustments_in_order_details.rb +18 -0
- data/app/overrides/show_only_selected_payment_method_on_confirm.rb +29 -0
- data/app/overrides/spree/admin/preserve_filter_params_across_table_forms.rb +64 -0
- data/app/overrides/spree/admin/promotion_rules/_promotion_rule/set_turbo_frame_on_edit_link.html.erb.deface +11 -0
- data/app/overrides/spree/admin/stores/add_special_instruction_message_settings.rb +17 -0
- data/app/overrides/use_absolute_time_for_order_header_completed_at.rb +15 -0
- data/app/presenters/spree/mega_nav_presenter_decorator.rb +26 -0
- data/app/services/ba_spree/setup_service.rb +144 -0
- data/app/services/spree/assets/position_normalizer.rb +67 -0
- data/app/services/spree/products/duplicator_decorator.rb +39 -0
- data/app/services/spree/products/prepare_nested_attributes_decorator.rb +58 -0
- data/app/views/spree/addresses/edit.html.erb +64 -0
- data/app/views/spree/admin/orders/_order.html.erb +32 -0
- data/app/views/spree/admin/orders/_summary.html.erb +122 -0
- data/app/views/spree/admin/shared/_custom_head.html.erb +56 -0
- data/app/views/spree/admin/shared/sidebar/_promotions_nav.html.erb +55 -0
- data/app/views/spree/admin/stores/_special_instruction_message_settings.html.erb +14 -0
- data/app/views/spree/checkout/_accept_marketing_checkbox.html.erb +40 -0
- data/app/views/spree/checkout/_address.html.erb +135 -0
- data/app/views/spree/checkout/_confirm.html.erb +25 -0
- data/app/views/spree/checkout/_line_item.html.erb +26 -0
- data/app/views/spree/checkout/_payment_method_confirm.html.erb +8 -0
- data/app/views/spree/checkout/_payment_methods.html.erb +88 -0
- data/app/views/spree/checkout/_summary.html.erb +146 -0
- data/app/views/spree/shared/_purchased_items_table.html.erb +60 -0
- data/app/views/spree/shared/_purchased_items_table.text.erb +24 -0
- data/app/views/themes/default/spree/orders/_empty.html.erb +14 -0
- data/app/views/themes/default/spree/orders/_summary.html.erb +87 -0
- data/app/views/themes/default/spree/orders/edit.turbo_stream.erb +10 -0
- data/app/views/themes/default/spree/page_sections/_featured_taxons.html.erb +38 -0
- data/app/views/themes/default/spree/page_sections/_header.html.erb +124 -0
- data/app/views/themes/default/spree/page_sections/_newsletter.html.erb +4 -0
- data/app/views/themes/default/spree/page_sections/_post_details.html.erb +22 -0
- data/app/views/themes/default/spree/page_sections/_product_details.html.erb +88 -0
- data/app/views/themes/default/spree/page_sections/_product_grid.html.erb +58 -0
- data/app/views/themes/default/spree/page_sections/nav/_desktop.html.erb +94 -0
- data/app/views/themes/default/spree/page_sections/nav/_mobile.html.erb +148 -0
- data/app/views/themes/default/spree/posts/_post.html.erb +16 -0
- data/app/views/themes/default/spree/products/_description.html.erb +7 -0
- data/app/views/themes/default/spree/products/_details.html.erb +65 -0
- data/app/views/themes/default/spree/products/_json_ld_variant.html.erb +15 -0
- data/app/views/themes/default/spree/products/_price.html.erb +76 -0
- data/app/views/themes/default/spree/products/_swiper.html.erb +90 -0
- data/app/views/themes/default/spree/shared/_account_pane.html.erb +18 -0
- data/app/views/themes/default/spree/shared/_cart_icon.html.erb +19 -0
- data/app/views/themes/default/spree/shared/_line_item_options.html.erb +9 -0
- data/app/views/themes/default/spree/shared/_logo.html.erb +39 -0
- data/app/views/themes/default/spree/shared/_nav_taxon_square_image.html.erb +8 -0
- data/app/views/themes/default/spree/shared/_order_shipment.html.erb +79 -0
- data/app/views/themes/default/spree/shared/_search.html.erb +33 -0
- data/app/views/themes/default/spree/shared/icons/_cart.html.erb +6 -0
- data/app/views/themes/default/spree/shared/icons/_cart_48.html.erb +8 -0
- data/app/views/themes/default/spree/shared/icons/_heart.html.erb +15 -0
- data/config/importmap.rb +12 -0
- data/config/initializers/admin_navigation.rb +43 -0
- data/config/initializers/spree.rb +6 -0
- data/config/initializers/spree_admin_label_i18n_alias.rb +52 -0
- data/config/initializers/spree_admin_tables.rb +57 -0
- data/config/initializers/spree_permitted_attributes.rb +1 -0
- data/config/locales/en.yml +15 -0
- data/config/locales/ja.yml +18 -0
- data/config/locales/spree.en.yml +4 -0
- data/config/locales/spree.ja.yml +3493 -0
- data/lib/ba_spree/engine.rb +41 -0
- data/lib/ba_spree/spree_events_dedup_patch.rb +44 -0
- data/lib/ba_spree/version.rb +3 -0
- data/lib/ba_spree.rb +20 -0
- data/lib/generators/ba_spree/install/install_generator.rb +85 -0
- metadata +594 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
module BaSpree
|
|
2
|
+
module OrderDecorator
|
|
3
|
+
ASSOCIATED_USER_ATTRIBUTES = [ :user_id, :email, :created_by_id, :bill_address_id, :ship_address_id ]
|
|
4
|
+
|
|
5
|
+
# @gem-override spree_core-5.3.6/app/models/spree/order.rb#associate_user!
|
|
6
|
+
# @see https://github.com/be-agile/giga-repeat/commit/d0dbe2b4524e22c1cf974bbd4829c587ef7cd254
|
|
7
|
+
# Associates the specified user with the order.
|
|
8
|
+
def associate_user!(user, override_email = true)
|
|
9
|
+
self.user = user
|
|
10
|
+
self.email = user.email if override_email
|
|
11
|
+
# we need to check if user is of admin user class to avoid mismatch type error
|
|
12
|
+
# in a scenario where we have separate classes for admin and regular users
|
|
13
|
+
self.created_by ||= user if user.is_a?(Spree.admin_user_class)
|
|
14
|
+
self.bill_address ||= user.bill_address
|
|
15
|
+
self.ship_address ||= user.ship_address
|
|
16
|
+
|
|
17
|
+
# 未保存(id=nil)の order では where(id: self) が `WHERE id IS NULL` となり、
|
|
18
|
+
# update_all が無関係なレコードを対象にしたり reload が RecordNotFound を投げる。
|
|
19
|
+
# まだ永続化されていない場合はメモリ上の代入のみで十分なので DB 反映はスキップする。
|
|
20
|
+
return self unless persisted?
|
|
21
|
+
|
|
22
|
+
changes = slice(*ASSOCIATED_USER_ATTRIBUTES)
|
|
23
|
+
|
|
24
|
+
# immediately persist the changes we just made, but don't use save
|
|
25
|
+
# since we might have an invalid address associated
|
|
26
|
+
ActiveRecord::Base.connected_to(role: :writing) do
|
|
27
|
+
self.class.unscoped.where(id: self).update_all(changes)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Reload to ensure memory state matches DB state, then recalculate promotions
|
|
31
|
+
reload
|
|
32
|
+
updater.update
|
|
33
|
+
|
|
34
|
+
# Spree 5.3 追従: update_all はコールバックを bypass するため order.updated を手動 publish
|
|
35
|
+
publish_event('order.updated') if changes.present?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @gem-override spree_core-5.3.6/app/models/spree/order.rb#disassociate_user!
|
|
39
|
+
# @see https://github.com/be-agile/giga-repeat/commit/d0dbe2b4524e22c1cf974bbd4829c587ef7cd254
|
|
40
|
+
def disassociate_user!
|
|
41
|
+
nullified_attributes = ASSOCIATED_USER_ATTRIBUTES.index_with(nil)
|
|
42
|
+
|
|
43
|
+
update_columns(nullified_attributes)
|
|
44
|
+
|
|
45
|
+
# Reload to ensure memory state matches DB state, then recalculate promotions
|
|
46
|
+
reload
|
|
47
|
+
updater.update
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @gem-override spree_core-5.3.6/app/models/spree/order.rb#after_cancel
|
|
51
|
+
# @see https://github.com/be-agile/giga-repeat/issues/1001
|
|
52
|
+
# Spree 5.3 追従: 本家追加の publish_order_canceled_event は super で取り込まれる
|
|
53
|
+
# 注文キャンセル時にpending状態のゲートウェイ決済(オーソリ)もキャンセルする
|
|
54
|
+
# Spreeコアは completed のみをキャンセルするが、オーソリのまま残すと以下の問題がある:
|
|
55
|
+
# - 決済プロバイダー側にオーソリが残る
|
|
56
|
+
# - 顧客のカード利用可能額が減少したまま
|
|
57
|
+
# - 後で誤って売上計上される可能性
|
|
58
|
+
def after_cancel
|
|
59
|
+
super
|
|
60
|
+
|
|
61
|
+
# pending 状態のゲートウェイ決済(オーソリ)をキャンセル
|
|
62
|
+
# store_credit は Spree コアで処理済みなので除外
|
|
63
|
+
payments.pending.not_store_credits.each do |payment|
|
|
64
|
+
# Gatewayベースの決済方法のみ対象(銀行振込や代引きは除外)
|
|
65
|
+
if payment.payment_method.is_a?(Spree::Gateway)
|
|
66
|
+
payment.cancel!
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# @gem-override spree_core-5.3.6/app/models/spree/order.rb#canceled_by
|
|
72
|
+
# @see https://github.com/be-agile/giga-repeat/issues/1232
|
|
73
|
+
# Spree 5.3.6 本家のバグ修正: canceled_by 末尾の publish_event('order.canceled') は
|
|
74
|
+
# コメント("Manually publish update event")通り本来 'order.updated' を publish すべき箇所。
|
|
75
|
+
# 'order.canceled' のままだと、transaction 内の cancel! が after_cancel 経由で既に
|
|
76
|
+
# 'order.canceled' を publish しているのと合わせて二重 publish となり、
|
|
77
|
+
# OrderEmailSubscriber#send_cancel_email がガード無しのためキャンセルメールが2通送信される。
|
|
78
|
+
# update_columns はコールバックを bypass するため、本来意図された 'order.updated' を publish する。
|
|
79
|
+
def canceled_by(user, canceled_at = nil)
|
|
80
|
+
canceled_at ||= Time.current
|
|
81
|
+
changes = { canceler_id: user.id, canceled_at: canceled_at }
|
|
82
|
+
|
|
83
|
+
transaction do
|
|
84
|
+
update_columns(changes)
|
|
85
|
+
cancel!
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Manually publish update event since update_columns bypasses callbacks
|
|
89
|
+
# (cancel! 内の after_cancel が 'order.canceled' を publish 済みなので、ここは update のみ)
|
|
90
|
+
publish_event('order.updated')
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
Spree::Order.prepend(BaSpree::OrderDecorator)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module BaSpree
|
|
2
|
+
module OrderUpdaterDecorator
|
|
3
|
+
# @gem-override spree_core-5.3.6/app/models/spree/order_updater.rb#update_adjustment_total
|
|
4
|
+
# @see https://github.com/be-agile/giga-repeat/issues/909
|
|
5
|
+
# super 後に order-level adjustment に対する内税計算を追加する。
|
|
6
|
+
# Spree 5.3 追従: 本家の sum→pick 単一クエリ最適化は super 経由で取り込まれるため
|
|
7
|
+
# override 本体は無変更(super の結果を部分的に上書きする設計のため互換)。
|
|
8
|
+
def update_adjustment_total
|
|
9
|
+
super
|
|
10
|
+
|
|
11
|
+
order.adjustments.tax.where(adjustable_type: 'Spree::Order').destroy_all
|
|
12
|
+
|
|
13
|
+
rates = Spree::TaxRate.match(order.tax_zone)
|
|
14
|
+
rates.each do |rate|
|
|
15
|
+
rate.adjust_order_level_adjustments(order)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
order.included_tax_total = line_items.sum(:included_tax_total) +
|
|
19
|
+
shipments.sum(:included_tax_total) +
|
|
20
|
+
adjustments.tax.eligible.where(adjustable_type: 'Spree::Order').sum(:amount)
|
|
21
|
+
# 0より小さいとvalidateエラーになるため
|
|
22
|
+
order.included_tax_total = 0 if order.included_tax_total.negative?
|
|
23
|
+
|
|
24
|
+
order.adjustment_total = line_items.sum(:adjustment_total) +
|
|
25
|
+
shipments.sum(:adjustment_total) +
|
|
26
|
+
adjustments.eligible.non_tax.sum(:amount)
|
|
27
|
+
|
|
28
|
+
update_order_total
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
Spree::OrderUpdater.prepend(BaSpree::OrderUpdaterDecorator)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module BaSpree
|
|
2
|
+
module PaymentMethodDecorator
|
|
3
|
+
def tax_category
|
|
4
|
+
return nil unless respond_to?(:preferred_tax_category_id)
|
|
5
|
+
Spree::TaxCategory.find_by(id: preferred_tax_category_id) if preferred_tax_category_id.present?
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
Spree::PaymentMethod.prepend(BaSpree::PaymentMethodDecorator)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module BaSpree
|
|
2
|
+
module ProductDecorator
|
|
3
|
+
def self.prepended(base)
|
|
4
|
+
# Spree 5.3 以前は、商品ごとのオプション並び順(spree_product_option_types.position)を正にするため
|
|
5
|
+
# `option_types` を reorder('spree_product_option_types.position') で上書きしていた。
|
|
6
|
+
# しかし through association の order/reorder に「他テーブルの列」を書くと、Rails が preload
|
|
7
|
+
# (WHERE id IN (...)) で読む経路で JOIN が外れ ORDER 句だけ残るため、
|
|
8
|
+
# 「Unknown column 'spree_product_option_types.position' in 'order clause'」で
|
|
9
|
+
# taxons#show(カテゴリページ)が 500 になる(5.3 で option_types を preload する経路が増え顕在化)。
|
|
10
|
+
#
|
|
11
|
+
# この罠は through の order に他テーブル列を書く限り原理的に回避できないため、上書きを削除し
|
|
12
|
+
# 5.3 core のデフォルト(`option_types, through: :product_option_types` + `product_option_types
|
|
13
|
+
# -> order(:position)`)に委ねる。これにより並び順は
|
|
14
|
+
# `spree_option_types.position`(グローバル順) → `spree_product_option_types.position`(商品ごと順)
|
|
15
|
+
# の複合になり、「商品ごと順」は第2ソートキーへ後退する。
|
|
16
|
+
# ※ org4 の複数 option_type 商品 355 件すべてで両者の並び順が一致することを確認済み(実害なし)。
|
|
17
|
+
# 将来「商品ごとにオプション表示順を変える」運用が必要になった場合は、option_types を直接
|
|
18
|
+
# 並べ替えるのではなく product_option_types.order(:position) 経由で option_type を引く形に
|
|
19
|
+
# 変更すること(preload 安全な書き方が必要)。
|
|
20
|
+
base.has_many :option_types_for_includes, -> { order(:id) },
|
|
21
|
+
through: :product_option_types,
|
|
22
|
+
source: :option_type,
|
|
23
|
+
class_name: 'Spree::OptionType'
|
|
24
|
+
|
|
25
|
+
# ProductProperty -> metafields 移行用の読み書きヘルパー(Spree 5.4 の Property 削除対応)
|
|
26
|
+
base.include Spree::ProductPropertyMetafields
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def set_slug
|
|
30
|
+
self.slug = generate_slug
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
def generate_slug
|
|
35
|
+
if new_record?
|
|
36
|
+
uuid_for_friendly_id
|
|
37
|
+
else
|
|
38
|
+
self.changes["slug"]&.first || self.slug
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
Spree::Product.prepend(BaSpree::ProductDecorator)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module BaSpree
|
|
2
|
+
module StoreDecorator
|
|
3
|
+
def self.prepended(base)
|
|
4
|
+
base.has_rich_text :special_instruction_message
|
|
5
|
+
|
|
6
|
+
base.class_eval do
|
|
7
|
+
# @gem-override spree_core-5.3.6/app/models/spree/store.rb#default
|
|
8
|
+
# @see https://github.com/be-agile/giga-repeat/commit/b7c74b2a1f45555616c19f3788def6aa3f67a7a1
|
|
9
|
+
# 本家は default フラグが無ければ DB の最初の1件を返すが、ba_spree では
|
|
10
|
+
# 該当が無いとき新規 default インスタンスを返す(マルチテナントで未作成テナント対策)。
|
|
11
|
+
def self.default
|
|
12
|
+
if where(default: true).any?
|
|
13
|
+
where(default: true).first
|
|
14
|
+
else
|
|
15
|
+
new(default: true)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Spree::Store.prepend BaSpree::StoreDecorator
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module BaSpree
|
|
2
|
+
module VariantDecorator
|
|
3
|
+
# @gem-override spree_core-5.3.6/app/models/spree/variant.rb#set_option_value
|
|
4
|
+
# @see https://github.com/be-agile/giga-repeat/commit/108316dd2cab88a61933080614e15663517c7291
|
|
5
|
+
def set_option_value(opt_name, opt_value, opt_type_position = nil)
|
|
6
|
+
# no option values on master
|
|
7
|
+
return if is_master
|
|
8
|
+
|
|
9
|
+
option_type = Spree::OptionType.where(name: opt_name).first_or_initialize do |o|
|
|
10
|
+
o.name = o.presentation = opt_name
|
|
11
|
+
o.save!
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
current_value = find_option_value(opt_name)
|
|
15
|
+
|
|
16
|
+
if current_value.nil?
|
|
17
|
+
# then we have to check to make sure that the product has the option type
|
|
18
|
+
product_option_type = if (existing_prod_ot = product.product_option_types.find { |ot| ot.option_type_id == option_type.id })
|
|
19
|
+
existing_prod_ot
|
|
20
|
+
else
|
|
21
|
+
product_option_type = product.product_option_types.new
|
|
22
|
+
product_option_type.option_type = option_type
|
|
23
|
+
end
|
|
24
|
+
product_option_type.position = opt_type_position if opt_type_position
|
|
25
|
+
product_option_type.save! if product_option_type.new_record? || product_option_type.changed?
|
|
26
|
+
else
|
|
27
|
+
return if current_value.name == opt_value
|
|
28
|
+
|
|
29
|
+
option_values.delete(current_value)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
option_value = option_type.option_values.where(name: opt_value).first_or_initialize do |o|
|
|
33
|
+
o.name = o.presentation = opt_value
|
|
34
|
+
o.save!
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
option_values << option_value
|
|
38
|
+
save
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @gem-override spree_core-5.3.6/app/models/spree/variant.rb#find_option_value
|
|
42
|
+
# @see https://github.com/be-agile/giga-repeat/commit/108316dd2cab88a61933080614e15663517c7291
|
|
43
|
+
def find_option_value(opt_name)
|
|
44
|
+
option_values.includes(:option_type).detect { |o| o.option_type.name == opt_name }
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
Spree::Variant.prepend(BaSpree::VariantDecorator)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module AdjustmentSourceDecorator
|
|
3
|
+
# @gem-override spree_core-5.3.6/app/models/concerns/spree/adjustment_source.rb#create_unique_adjustment
|
|
4
|
+
# @see https://github.com/be-agile/giga-repeat/issues/1183
|
|
5
|
+
# 並行リクエスト時の重複 adjustment 作成を防ぐため、order を排他ロックしてから
|
|
6
|
+
# 既存チェックと作成を実行する。これがないと、ブラウザ複数タブから同一 order に
|
|
7
|
+
# 同時にカート操作されたとき、`already_adjusted?` の SELECT が両リクエストで
|
|
8
|
+
# false を返し、同じ source の adjustment が二重に INSERT されてしまう。
|
|
9
|
+
def create_unique_adjustment(order, adjustable)
|
|
10
|
+
with_order_lock(order) { super }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @gem-override spree_core-5.3.6/app/models/concerns/spree/adjustment_source.rb#create_unique_adjustments
|
|
14
|
+
# @see https://github.com/be-agile/giga-repeat/issues/1183
|
|
15
|
+
def create_unique_adjustments(order, adjustables, &block)
|
|
16
|
+
with_order_lock(order) { super }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
# @gem-override spree_core-5.3.6/app/models/concerns/spree/adjustment_source.rb#already_adjusted?
|
|
22
|
+
# @see https://github.com/be-agile/giga-repeat/issues/1183
|
|
23
|
+
# `already_adjusted?` を locking read (FOR UPDATE) で実行することで、
|
|
24
|
+
# MySQL REPEATABLE READ 下の snapshot 問題を回避する。
|
|
25
|
+
# 通常 SELECT は transaction 開始時の snapshot を見るため、先行 transaction の
|
|
26
|
+
# adjustment INSERT が後続 transaction から見えないケースがあるが、
|
|
27
|
+
# locking read は current read で最新状態を見るため、先行の commit 後の
|
|
28
|
+
# adjustment が必ず見える。
|
|
29
|
+
def already_adjusted?(adjustable)
|
|
30
|
+
adjustments.lock.where(adjustable: adjustable).exists?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @gem-override spree_core-5.3.6/app/models/concerns/spree/adjustment_source.rb#already_adjusted_ids
|
|
34
|
+
# @see https://github.com/be-agile/giga-repeat/issues/1183
|
|
35
|
+
# 同上の理由で locking read で実行する。
|
|
36
|
+
def already_adjusted_ids(order)
|
|
37
|
+
adjustments.lock.where(order: order).pluck(:adjustable_id)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# order インスタンス自体に dirty な属性 (例: last_ip_address) がある状態で
|
|
41
|
+
# `order.with_lock` を呼ぶと Rails 8 では RuntimeError になるため、
|
|
42
|
+
# 別インスタンスで `SELECT ... FOR UPDATE` を発行してロックを取得する。
|
|
43
|
+
# トランザクション内で行リレベルロックを取れば、後続リクエストは
|
|
44
|
+
# 先行トランザクションの commit を待つので race condition は防げる。
|
|
45
|
+
def with_order_lock(order)
|
|
46
|
+
order.class.transaction do
|
|
47
|
+
order.class.lock.where(id: order.id).pluck(:id)
|
|
48
|
+
yield
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Spree::AdjustmentSource を include している promotion action 系の各クラスに対して
|
|
55
|
+
# decorator を prepend する。concern module 自体に prepend するのではなく include 元クラスに
|
|
56
|
+
# 直接適用することで、Ruby のメソッド解決順が確実に decorator を経由するようにする。
|
|
57
|
+
# TaxRate は AdjustmentSource を include しているが create_unique_adjustment を経由しないため対象外。
|
|
58
|
+
[
|
|
59
|
+
Spree::Promotion::Actions::CreateAdjustment,
|
|
60
|
+
Spree::Promotion::Actions::CreateItemAdjustments,
|
|
61
|
+
Spree::Promotion::Actions::FreeShipping,
|
|
62
|
+
defined?(Spree::Promotion::Actions::CreateVolumeDiscountAdjustments) ? Spree::Promotion::Actions::CreateVolumeDiscountAdjustments : nil,
|
|
63
|
+
defined?(Spree::Promotion::Actions::CreateVolumeBasedOptionFee) ? Spree::Promotion::Actions::CreateVolumeBasedOptionFee : nil
|
|
64
|
+
].compact.each do |klass|
|
|
65
|
+
klass.prepend(Spree::AdjustmentSourceDecorator)
|
|
66
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
# Spree 5.4 で Spree::Property が削除されるため、ProductProperty で
|
|
3
|
+
# 保持していた商品の付加情報(gravity_forms / 地図形式 / 提供形態 / short_description 等)を
|
|
4
|
+
# Spree 5.2 の metafields に移行する。その読み書きを一箇所に集約する薄いヘルパー。
|
|
5
|
+
#
|
|
6
|
+
# 移行 rake(migrate_product_properties_to_metafields)は旧 ProductProperty を
|
|
7
|
+
# namespace="properties", key=property.name, value=product_property.value
|
|
8
|
+
# で metafield にコピー済み。したがって本ヘルパーは namespace="properties" 規約のもとで
|
|
9
|
+
# 本家の get_metafield / set_metafield を薄くラップするだけにとどめ、本家 API を再実装しない。
|
|
10
|
+
#
|
|
11
|
+
# 日本語 key("地図形式" 等)は ba_spree/metafield_definition_decorator.rb が
|
|
12
|
+
# 本家 normalizes(parameterize) を無効化済みのため、そのまま通る(再 normalize 不要)。
|
|
13
|
+
module ProductPropertyMetafields
|
|
14
|
+
extend ActiveSupport::Concern
|
|
15
|
+
|
|
16
|
+
PROPERTY_NAMESPACE = 'properties'.freeze
|
|
17
|
+
|
|
18
|
+
# 旧 product.property(name) 相当。指定プロパティ名の metafield 値(文字列)を返す。無ければ nil。
|
|
19
|
+
def property_metafield_value(name)
|
|
20
|
+
get_metafield(property_metafield_key(name))&.value
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# 旧 product_properties.create!/update 相当。指定プロパティ名の metafield に値を設定する。
|
|
24
|
+
# MetafieldDefinition は本家 set_metafield 内で find_or_create される。
|
|
25
|
+
def set_property_metafield(name, value)
|
|
26
|
+
set_metafield(property_metafield_key(name), value)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# 旧 product.has_property? 相当。
|
|
30
|
+
def property_metafield?(name)
|
|
31
|
+
has_metafield?(property_metafield_key(name))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# PDP 表示用。namespace="properties" かつフロント表示対象(available_on_front_end)の
|
|
35
|
+
# metafield を、定義の作成順で返す。旧
|
|
36
|
+
# product_properties.joins(:property).merge(Spree::Property.available_on_front_end)
|
|
37
|
+
# .sort_by_property_position
|
|
38
|
+
# の置き換え。各要素は Spree::Metafield で、name(=表示名) / value / id を持つ。
|
|
39
|
+
def front_end_property_metafields
|
|
40
|
+
public_metafields
|
|
41
|
+
.select { |mf| mf.metafield_definition&.namespace == PROPERTY_NAMESPACE }
|
|
42
|
+
.sort_by { |mf| mf.metafield_definition_id }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
# "提供形態" -> "properties.提供形態"
|
|
48
|
+
def property_metafield_key(name)
|
|
49
|
+
"#{PROPERTY_NAMESPACE}.#{name}"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Adjustable
|
|
3
|
+
module Adjuster
|
|
4
|
+
module PromotionDecorator
|
|
5
|
+
# @gem-override spree_core-5.3.6/app/models/spree/adjustable/adjuster/promotion.rb#choose_best_promo_adjustment
|
|
6
|
+
# @see https://github.com/be-agile/giga-repeat/commit/3d5683b6c3e6875cfd808368f0ab21c020270ebb
|
|
7
|
+
# 本家は競合プロモーション adjustment のうち最良のもの以外を eligible: false にするが、
|
|
8
|
+
# ba_spree では複数プロモーションを併用させるため、この絞り込みを無効化する。
|
|
9
|
+
def choose_best_promo_adjustment
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
Spree::Adjustable::Adjuster::Promotion.prepend(Spree::Adjustable::Adjuster::PromotionDecorator)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Admin
|
|
3
|
+
class Table
|
|
4
|
+
# 本家 Spree::Admin::Table::Filter の OPERATORS は label が英語ハードコード
|
|
5
|
+
# ("equals" 等)で、フィルタービルダーの演算子セレクトが日本語にならない
|
|
6
|
+
# 原因の一つ(Ruby 側)。operators_for_select はこの label を
|
|
7
|
+
# data-query-builder-operators-value として JS に渡すため、ここを i18n
|
|
8
|
+
# (admin.tables.operators.*) から引くよう上書きする。
|
|
9
|
+
#
|
|
10
|
+
# 注意: OPERATORS 定数を起動時に書き換えるとロケールが起動時で固定されて
|
|
11
|
+
# しまうため、リクエストごとに評価される operators_for_select 側で翻訳する。
|
|
12
|
+
module FilterDecorator
|
|
13
|
+
module ClassMethods
|
|
14
|
+
# OPERATORS の各 operator キー -> i18n キー(admin.tables.operators 配下)。
|
|
15
|
+
# キーと i18n キーの対応は本家ビュー(_filter_row 等)が使う
|
|
16
|
+
# admin.tables.operators.* に合わせる。
|
|
17
|
+
OPERATOR_I18N_KEYS = {
|
|
18
|
+
eq: :equals,
|
|
19
|
+
not_eq: :not_equals,
|
|
20
|
+
cont: :contains,
|
|
21
|
+
not_cont: :does_not_contain,
|
|
22
|
+
start: :starts_with,
|
|
23
|
+
end: :ends_with,
|
|
24
|
+
gt: :greater_than,
|
|
25
|
+
gteq: :greater_than_or_equal,
|
|
26
|
+
lt: :less_than,
|
|
27
|
+
lteq: :less_than_or_equal,
|
|
28
|
+
in: :is_any_of,
|
|
29
|
+
not_in: :is_none_of,
|
|
30
|
+
null: :is_empty,
|
|
31
|
+
not_null: :is_not_empty
|
|
32
|
+
}.freeze
|
|
33
|
+
|
|
34
|
+
def operators_for_select
|
|
35
|
+
super.map do |operator|
|
|
36
|
+
i18n_key = OPERATOR_I18N_KEYS[operator[:value].to_sym]
|
|
37
|
+
next operator unless i18n_key
|
|
38
|
+
|
|
39
|
+
operator.merge(label: Spree.t("admin.tables.operators.#{i18n_key}"))
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.prepended(base)
|
|
45
|
+
base.singleton_class.prepend(ClassMethods)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
Spree::Admin::Table::Filter.prepend(Spree::Admin::Table::FilterDecorator)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Spree
|
|
4
|
+
module Admin
|
|
5
|
+
class Table
|
|
6
|
+
# フィルタービルダーの「または」グループが ransack に届かず、絞り込みとして機能していない。
|
|
7
|
+
#
|
|
8
|
+
# 本家 (spree_admin 5.3.6) の build_or_grouping には2つの問題がある:
|
|
9
|
+
#
|
|
10
|
+
# 1. p (述語) と v (値) を a (属性) の内側に入れている。
|
|
11
|
+
# ransack は a と兄弟の階層に p / v を期待するため、grouping ごと黙って無視される
|
|
12
|
+
# (= 全件が返る)。
|
|
13
|
+
# 2. 述語を operator.to_s.sub('_', '') で作っており、最初の _ を落としてしまう。
|
|
14
|
+
# not_eq → "noteq"、not_cont → "notcont" のように不正な述語になる。
|
|
15
|
+
#
|
|
16
|
+
# @see https://github.com/be-agile/giga-repeat/issues/1262
|
|
17
|
+
module FilterGroupDecorator
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
# @gem-override spree_admin-5.3.6/app/models/spree/admin/table/filter_group.rb#build_or_grouping
|
|
21
|
+
# @see https://github.com/be-agile/giga-repeat/issues/1262
|
|
22
|
+
def build_or_grouping(group)
|
|
23
|
+
conditions = {}
|
|
24
|
+
|
|
25
|
+
group.filters.each_with_index do |filter, index|
|
|
26
|
+
param = filter.to_ransack_param
|
|
27
|
+
next if param.empty?
|
|
28
|
+
|
|
29
|
+
conditions[index.to_s] = {
|
|
30
|
+
a: { '0' => { name: filter.field } },
|
|
31
|
+
p: ransack_predicate_for(filter),
|
|
32
|
+
v: ransack_values_for(param.values.first)
|
|
33
|
+
}
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
{
|
|
37
|
+
m: 'or',
|
|
38
|
+
c: conditions
|
|
39
|
+
}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# ransack の述語名 (先頭の _ を除いた OPERATORS の predicate)
|
|
43
|
+
# @return [String]
|
|
44
|
+
def ransack_predicate_for(filter)
|
|
45
|
+
predicate = Spree::Admin::Table::Filter::OPERATORS.dig(filter.operator, :predicate)
|
|
46
|
+
predicate.to_s.delete_prefix('_')
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# ransack の値。in / not_in のように配列を取る述語では、値をまとめて1つの v に入れると
|
|
50
|
+
# マッチしなくなる (0件になる) ため、要素ごとに v のエントリを作る。
|
|
51
|
+
# @return [Hash]
|
|
52
|
+
def ransack_values_for(value)
|
|
53
|
+
values = value.is_a?(Array) ? value : [ value ]
|
|
54
|
+
# 値が未入力 (空配列) の場合は空の v を作らない。nil を渡せば ransack がその条件を無視する
|
|
55
|
+
values = [ nil ] if values.empty?
|
|
56
|
+
|
|
57
|
+
values.each_with_index.to_h { |item, index| [ index.to_s, { value: item } ] }
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
Spree::Admin::Table::FilterGroup.prepend(Spree::Admin::Table::FilterGroupDecorator)
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
# @gem-override spree_core-5.3.6/app/models/spree/asset.rb
|
|
3
|
+
# reason: Spree 5.3 で Asset#attachment に named variant の事前生成ブロック
|
|
4
|
+
# (mini/small/medium/large/xlarge/og_image を format: webp + preprocessed: true で定義)が
|
|
5
|
+
# 追加された。preprocessed: true は画像 attach 時に 1 画像あたり 6 本の
|
|
6
|
+
# ActiveStorage::TransformJob をキューし、さらに表示時に未生成 variant を
|
|
7
|
+
# /rails/active_storage/representations/... でオンザフライ webp 変換する。
|
|
8
|
+
#
|
|
9
|
+
# 動産社等のローカル / stg では画像 blob の実体が本番 S3 にしか無く、変換が
|
|
10
|
+
# 元画像を取得できずに 1 リクエストあたり数百ms〜1秒の遅延・失敗となる。画像の多い
|
|
11
|
+
# ページではこれが積み重なり、スモークテスト / ブラウザテストがタイムアウトする
|
|
12
|
+
# (Issue #1210 のコメント参照)。
|
|
13
|
+
#
|
|
14
|
+
# そこで「variant の定義自体は残す(ビューの image.variant(:large) 等が
|
|
15
|
+
# ArgumentError にならないように)が、事前生成 preprocessed を環境フラグで
|
|
16
|
+
# false に倒す」ことで、attach 時の TransformJob 大量発行を止める。
|
|
17
|
+
# 本番(フラグ未設定)では 5.3 デフォルトの preprocessed: true を維持する。
|
|
18
|
+
#
|
|
19
|
+
# 制御: ENV['DISABLE_IMAGE_VARIANT_PREPROCESSING'] が truthy のとき preprocessed を無効化。
|
|
20
|
+
# development / test ではデフォルトで無効化する(画像実体が無い環境での遅延回避)。
|
|
21
|
+
#
|
|
22
|
+
# ⚠️ stg は RAILS_ENV=production で動作するため、env 名だけでは本番と区別できない。
|
|
23
|
+
# stg で画像処理を止めたい場合は stg のデプロイ環境変数に
|
|
24
|
+
# DISABLE_IMAGE_VARIANT_PREPROCESSING=true を明示設定すること。
|
|
25
|
+
# 本番環境では未設定のままにし、5.3 デフォルト(preprocessed: true)を維持する。
|
|
26
|
+
#
|
|
27
|
+
# @see https://github.com/be-agile/giga-repeat/issues/1210
|
|
28
|
+
module AssetDecorator
|
|
29
|
+
def self.prepended(base)
|
|
30
|
+
# acts_as_list の採番 (bottom_position_in_list + 1) はロックを取らないため、
|
|
31
|
+
# 管理画面の一括アップロードのように同一 viewable へ並列に INSERT すると
|
|
32
|
+
# 同じ position を持つレコードが同時に作られる。その状態になると並び替えが
|
|
33
|
+
# 効かなくなるため、採番より先に viewable の行を排他ロックして直列化する。
|
|
34
|
+
# acts_as_list の before_create :avoid_collision より先に走らせる必要がある。
|
|
35
|
+
# @see https://github.com/be-agile/giga-repeat/issues/1292
|
|
36
|
+
base.before_create :lock_position_scope, prepend: true
|
|
37
|
+
|
|
38
|
+
base.has_one_attached :attachment, service: Spree.public_storage_service_name do |attachable|
|
|
39
|
+
# 本家同様、キー順(format, resize_to_fill, saver)を維持して variation digest を一致させる。
|
|
40
|
+
Spree::Config.product_image_variant_sizes.each do |name, (width, height)|
|
|
41
|
+
attachable.variant name,
|
|
42
|
+
format: 'webp',
|
|
43
|
+
resize_to_fill: [ width, height ],
|
|
44
|
+
saver: Spree::Asset::WEBP_SAVER_OPTIONS,
|
|
45
|
+
preprocessed: !Spree::Asset.image_variant_preprocessing_disabled?
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# viewable の行に排他ロックを取ったうえで position を採番し、同一 viewable への
|
|
51
|
+
# 並列 INSERT を直列化する。ロックはこの save のトランザクション終了時に解放される。
|
|
52
|
+
#
|
|
53
|
+
# 採番をここで行うのは、acts_as_list の採番が通常の SELECT (consistent read) で
|
|
54
|
+
# 最大 position を読むためである。MySQL の REPEATABLE READ では、行ロックの取得を
|
|
55
|
+
# 待っている間に他トランザクションが commit した行が consistent read から見えず、
|
|
56
|
+
# ロックを取っても同じ position を採番してしまう。ロック付き読み取り (FOR UPDATE) は
|
|
57
|
+
# 常に最新の確定値を読むため、こちらで採番する。
|
|
58
|
+
#
|
|
59
|
+
# viewable が未確定 (新規商品作成時のセッション退避アップロード等) の場合は
|
|
60
|
+
# ロック対象の行が無いため何もしない。この経路の position は
|
|
61
|
+
# Spree::Admin::ProductsControllerDecorator が付け替え後に詰め直す。
|
|
62
|
+
def lock_position_scope
|
|
63
|
+
return if viewable_id.blank? || viewable_type.blank?
|
|
64
|
+
|
|
65
|
+
lock_viewable_row
|
|
66
|
+
return if self[:position].present?
|
|
67
|
+
|
|
68
|
+
bottom = Spree::Asset.unscoped
|
|
69
|
+
.where(viewable_type: viewable_type, viewable_id: viewable_id)
|
|
70
|
+
.lock
|
|
71
|
+
.maximum(:position)
|
|
72
|
+
self[:position] = bottom.to_i + 1
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# 同一 viewable の position を操作する処理を直列化するための行ロック。
|
|
76
|
+
# 採番(lock_position_scope)と並び替え(Spree::Admin::AssetsControllerDecorator)の
|
|
77
|
+
# 双方が同じ行を取り合うことで、両者が混ざらないようにする。
|
|
78
|
+
def lock_viewable_row
|
|
79
|
+
return if viewable_id.blank? || viewable_type.blank?
|
|
80
|
+
|
|
81
|
+
viewable_class = viewable_type.safe_constantize
|
|
82
|
+
return if viewable_class.nil?
|
|
83
|
+
|
|
84
|
+
viewable_class.unscoped.lock.where(id: viewable_id).pick(:id)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
module ClassMethods
|
|
88
|
+
# 画像 variant の事前生成(preprocessed)を無効化すべき環境かどうか。
|
|
89
|
+
# ENV['DISABLE_IMAGE_VARIANT_PREPROCESSING'] を最優先で見る(本番でも明示的に切り替え可能)。
|
|
90
|
+
# 未設定なら development / test で自動的に無効化する。
|
|
91
|
+
def image_variant_preprocessing_disabled?
|
|
92
|
+
flag = ENV['DISABLE_IMAGE_VARIANT_PREPROCESSING']
|
|
93
|
+
return ActiveModel::Type::Boolean.new.cast(flag) unless flag.nil?
|
|
94
|
+
|
|
95
|
+
Rails.env.development? || Rails.env.test?
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
Spree::Asset.singleton_class.prepend(Spree::AssetDecorator::ClassMethods)
|
|
102
|
+
Spree::Asset.prepend(Spree::AssetDecorator)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module ContactDecorator
|
|
3
|
+
def self.prepended(base)
|
|
4
|
+
base.attribute :mail_from_address, validate: true
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
# @gem-override spree_storefront-5.3.6/app/models/spree/contact.rb#headers
|
|
8
|
+
# @see https://github.com/be-agile/giga-repeat/issues/1092
|
|
9
|
+
# 本家は from を問い合わせ者本人のメールにするが、SES 未検証アドレスで 500 になるため
|
|
10
|
+
# from を mail_from_address(検証済み送信元)に変え、本人は reply_to に回す。
|
|
11
|
+
def headers
|
|
12
|
+
{
|
|
13
|
+
subject: 'Contact Us',
|
|
14
|
+
to: customer_support_email.to_s,
|
|
15
|
+
from: mail_from_address,
|
|
16
|
+
reply_to: %("#{name}" <#{email}>)
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
Spree::Contact.prepend Spree::ContactDecorator
|