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.
Files changed (160) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +673 -0
  3. data/README.md +150 -0
  4. data/app/assets/config/manifest.js +1 -0
  5. data/app/assets/javascripts/ba_spree/admin_overrides/query_builder_controller.js +505 -0
  6. data/app/assets/javascripts/ba_spree/storefront/ba_spree_local_time.js +9 -0
  7. data/app/assets/stylesheets/spree/admin/custom.scss +40 -0
  8. data/app/controllers/ba_spree/checkout_controller_decorator.rb +111 -0
  9. data/app/controllers/ba_spree/store_controller_decorator.rb +55 -0
  10. data/app/controllers/concerns/ba_spree/theme_concern_decorator.rb +16 -0
  11. data/app/controllers/spree/admin/assets_controller_decorator.rb +48 -0
  12. data/app/controllers/spree/admin/products_controller_decorator.rb +25 -0
  13. data/app/controllers/spree/admin/promotion_rules_controller_decorator.rb +30 -0
  14. data/app/controllers/spree/admin/users_controller_decorator.rb +34 -0
  15. data/app/controllers/spree/contacts_controller_decorator.rb +23 -0
  16. data/app/controllers/spree/digital_links_controller.rb +61 -0
  17. data/app/controllers/spree/orders_controller_decorator.rb +24 -0
  18. data/app/decorators/ba_spree/product_pricing_decorator.rb +65 -0
  19. data/app/decorators/spree/current_decorator.rb +17 -0
  20. data/app/decorators/spree/money_decorator.rb +51 -0
  21. data/app/decorators/spree/order_email_subscriber_decorator.rb +64 -0
  22. data/app/decorators/spree/page_sections/featured_posts_decorator.rb +17 -0
  23. data/app/helpers/currency_rounding_helper.rb +10 -0
  24. data/app/helpers/spree/admin/filter_params_preservation.rb +130 -0
  25. data/app/helpers/spree/admin/navigation_helper_decorator.rb +23 -0
  26. data/app/helpers/spree/admin/promotion_rules_helper_decorator.rb +33 -0
  27. data/app/helpers/spree/admin/table_helper_decorator.rb +40 -0
  28. data/app/helpers/spree/base_helper_decorator.rb +63 -0
  29. data/app/helpers/spree/checkout_analytics_helper_decorator.rb +32 -0
  30. data/app/javascript/ba_spree/controllers/disable_when_hidden_controller.js +70 -0
  31. data/app/javascript/ba_spree/index.js +11 -0
  32. data/app/javascript/spree/admin/controllers/calendar_range_controller.js +61 -0
  33. data/app/javascript/spree/admin/controllers/slug_form_controller.js +17 -0
  34. data/app/models/ba_spree/address_decorator.rb +43 -0
  35. data/app/models/ba_spree/adjustment_decorator.rb +13 -0
  36. data/app/models/ba_spree/order_decorator.rb +95 -0
  37. data/app/models/ba_spree/order_updater_decorator.rb +33 -0
  38. data/app/models/ba_spree/payment_method_decorator.rb +10 -0
  39. data/app/models/ba_spree/product_decorator.rb +44 -0
  40. data/app/models/ba_spree/store_decorator.rb +23 -0
  41. data/app/models/ba_spree/variant_decorator.rb +49 -0
  42. data/app/models/concerns/spree/adjustment_source_decorator.rb +66 -0
  43. data/app/models/concerns/spree/product_property_metafields.rb +52 -0
  44. data/app/models/spree/adjustable/adjuster/promotion_decorator.rb +16 -0
  45. data/app/models/spree/admin/table/filter_decorator.rb +52 -0
  46. data/app/models/spree/admin/table/filter_group_decorator.rb +64 -0
  47. data/app/models/spree/asset_decorator.rb +102 -0
  48. data/app/models/spree/contact_decorator.rb +22 -0
  49. data/app/models/spree/digital_link_decorator.rb +9 -0
  50. data/app/models/spree/export_decorator.rb +34 -0
  51. data/app/models/spree/line_item_destroy_callback_decorator.rb +30 -0
  52. data/app/models/spree/metafield_definition_decorator.rb +34 -0
  53. data/app/models/spree/option_type_decorator.rb +22 -0
  54. data/app/models/spree/option_value_decorator.rb +19 -0
  55. data/app/models/spree/option_value_variant_decorator.rb +30 -0
  56. data/app/models/spree/order/address_book_decorator.rb +14 -0
  57. data/app/models/spree/order_merger_decorator.rb +29 -0
  58. data/app/models/spree/price_rules/customer_group_rule_decorator.rb +18 -0
  59. data/app/models/spree/price_rules/user_rule_decorator.rb +25 -0
  60. data/app/models/spree/price_rules/volume_rule_decorator.rb +25 -0
  61. data/app/models/spree/price_rules/zone_rule_decorator.rb +25 -0
  62. data/app/models/spree/pricing/batch_resolver.rb +96 -0
  63. data/app/models/spree/promotion_handler/cart_decorator.rb +51 -0
  64. data/app/models/spree/stock/packer_decorator.rb +61 -0
  65. data/app/models/spree/stock/prioritizer_decorator.rb +27 -0
  66. data/app/models/spree/tax_rate_decorator.rb +93 -0
  67. data/app/models/spree/taxon_decorator.rb +42 -0
  68. data/app/models/spree/user_bill_address_sync_decorator.rb +33 -0
  69. data/app/overrides/add_ba_spree_storefront_javascript_importmap_tags.rb +8 -0
  70. data/app/overrides/add_cache_to_product_listing_page.rb +41 -0
  71. data/app/overrides/add_class_to_login_link.rb +6 -0
  72. data/app/overrides/add_confirm_state_to_checkout_content_block.rb.rb +30 -0
  73. data/app/overrides/add_promotions_nav.rb +8 -0
  74. data/app/overrides/add_turbo_frame_to_admin_order_line_item_edit_link.rb +23 -0
  75. data/app/overrides/add_turbo_frame_to_promotion_action_edit_link.rb +20 -0
  76. data/app/overrides/add_turbo_stream_format_to_cart_path_in_cart_pane.rb +8 -0
  77. data/app/overrides/ba_spree_local_time_add_custom_javascript_import_map_tags.rb +8 -0
  78. data/app/overrides/disable_hidden_bill_address_fields_on_payment.rb +15 -0
  79. data/app/overrides/disable_turbo_on_user_registration_form.rb +18 -0
  80. data/app/overrides/fix_coupon_apply_button_layout.rb +7 -0
  81. data/app/overrides/hide_gift_cards_and_store_credits_from_account_nav.rb +11 -0
  82. data/app/overrides/hide_shipping_message_for_digital_only_orders.rb +15 -0
  83. data/app/overrides/localize_apply_button_text.rb +6 -0
  84. data/app/overrides/localize_newsletter_button_text.rb +6 -0
  85. data/app/overrides/replace_announcement_bar_text.rb +6 -0
  86. data/app/overrides/replace_button_edit_checkout.rb +10 -0
  87. data/app/overrides/replace_checkout_delivery_info.rb +6 -0
  88. data/app/overrides/replace_checkout_pay_button_with_dynamic_label.rb +14 -0
  89. data/app/overrides/replace_variant_not_available_button.rb +19 -0
  90. data/app/overrides/set_logo_width_height_in_admin_store_basic_form.rb +12 -0
  91. data/app/overrides/show_breadcrumbs_on_taxon_page.rb +30 -0
  92. data/app/overrides/show_individual_adjustments_in_order_details.rb +18 -0
  93. data/app/overrides/show_only_selected_payment_method_on_confirm.rb +29 -0
  94. data/app/overrides/spree/admin/preserve_filter_params_across_table_forms.rb +64 -0
  95. data/app/overrides/spree/admin/promotion_rules/_promotion_rule/set_turbo_frame_on_edit_link.html.erb.deface +11 -0
  96. data/app/overrides/spree/admin/stores/add_special_instruction_message_settings.rb +17 -0
  97. data/app/overrides/use_absolute_time_for_order_header_completed_at.rb +15 -0
  98. data/app/presenters/spree/mega_nav_presenter_decorator.rb +26 -0
  99. data/app/services/ba_spree/setup_service.rb +144 -0
  100. data/app/services/spree/assets/position_normalizer.rb +67 -0
  101. data/app/services/spree/products/duplicator_decorator.rb +39 -0
  102. data/app/services/spree/products/prepare_nested_attributes_decorator.rb +58 -0
  103. data/app/views/spree/addresses/edit.html.erb +64 -0
  104. data/app/views/spree/admin/orders/_order.html.erb +32 -0
  105. data/app/views/spree/admin/orders/_summary.html.erb +122 -0
  106. data/app/views/spree/admin/shared/_custom_head.html.erb +56 -0
  107. data/app/views/spree/admin/shared/sidebar/_promotions_nav.html.erb +55 -0
  108. data/app/views/spree/admin/stores/_special_instruction_message_settings.html.erb +14 -0
  109. data/app/views/spree/checkout/_accept_marketing_checkbox.html.erb +40 -0
  110. data/app/views/spree/checkout/_address.html.erb +135 -0
  111. data/app/views/spree/checkout/_confirm.html.erb +25 -0
  112. data/app/views/spree/checkout/_line_item.html.erb +26 -0
  113. data/app/views/spree/checkout/_payment_method_confirm.html.erb +8 -0
  114. data/app/views/spree/checkout/_payment_methods.html.erb +88 -0
  115. data/app/views/spree/checkout/_summary.html.erb +146 -0
  116. data/app/views/spree/shared/_purchased_items_table.html.erb +60 -0
  117. data/app/views/spree/shared/_purchased_items_table.text.erb +24 -0
  118. data/app/views/themes/default/spree/orders/_empty.html.erb +14 -0
  119. data/app/views/themes/default/spree/orders/_summary.html.erb +87 -0
  120. data/app/views/themes/default/spree/orders/edit.turbo_stream.erb +10 -0
  121. data/app/views/themes/default/spree/page_sections/_featured_taxons.html.erb +38 -0
  122. data/app/views/themes/default/spree/page_sections/_header.html.erb +124 -0
  123. data/app/views/themes/default/spree/page_sections/_newsletter.html.erb +4 -0
  124. data/app/views/themes/default/spree/page_sections/_post_details.html.erb +22 -0
  125. data/app/views/themes/default/spree/page_sections/_product_details.html.erb +88 -0
  126. data/app/views/themes/default/spree/page_sections/_product_grid.html.erb +58 -0
  127. data/app/views/themes/default/spree/page_sections/nav/_desktop.html.erb +94 -0
  128. data/app/views/themes/default/spree/page_sections/nav/_mobile.html.erb +148 -0
  129. data/app/views/themes/default/spree/posts/_post.html.erb +16 -0
  130. data/app/views/themes/default/spree/products/_description.html.erb +7 -0
  131. data/app/views/themes/default/spree/products/_details.html.erb +65 -0
  132. data/app/views/themes/default/spree/products/_json_ld_variant.html.erb +15 -0
  133. data/app/views/themes/default/spree/products/_price.html.erb +76 -0
  134. data/app/views/themes/default/spree/products/_swiper.html.erb +90 -0
  135. data/app/views/themes/default/spree/shared/_account_pane.html.erb +18 -0
  136. data/app/views/themes/default/spree/shared/_cart_icon.html.erb +19 -0
  137. data/app/views/themes/default/spree/shared/_line_item_options.html.erb +9 -0
  138. data/app/views/themes/default/spree/shared/_logo.html.erb +39 -0
  139. data/app/views/themes/default/spree/shared/_nav_taxon_square_image.html.erb +8 -0
  140. data/app/views/themes/default/spree/shared/_order_shipment.html.erb +79 -0
  141. data/app/views/themes/default/spree/shared/_search.html.erb +33 -0
  142. data/app/views/themes/default/spree/shared/icons/_cart.html.erb +6 -0
  143. data/app/views/themes/default/spree/shared/icons/_cart_48.html.erb +8 -0
  144. data/app/views/themes/default/spree/shared/icons/_heart.html.erb +15 -0
  145. data/config/importmap.rb +12 -0
  146. data/config/initializers/admin_navigation.rb +43 -0
  147. data/config/initializers/spree.rb +6 -0
  148. data/config/initializers/spree_admin_label_i18n_alias.rb +52 -0
  149. data/config/initializers/spree_admin_tables.rb +57 -0
  150. data/config/initializers/spree_permitted_attributes.rb +1 -0
  151. data/config/locales/en.yml +15 -0
  152. data/config/locales/ja.yml +18 -0
  153. data/config/locales/spree.en.yml +4 -0
  154. data/config/locales/spree.ja.yml +3493 -0
  155. data/lib/ba_spree/engine.rb +41 -0
  156. data/lib/ba_spree/spree_events_dedup_patch.rb +44 -0
  157. data/lib/ba_spree/version.rb +3 -0
  158. data/lib/ba_spree.rb +20 -0
  159. data/lib/generators/ba_spree/install/install_generator.rb +85 -0
  160. metadata +594 -0
@@ -0,0 +1,40 @@
1
+ #main-sidebar {
2
+ height: calc(100vh - 60px);
3
+ }
4
+
5
+ // admin 左サイドメニュー: 長いメニュー名(例「ボリュームディスカウントの段階」)が
6
+ // nav-link の white-space: nowrap でサイドバー幅に収まらず右端で見切れていた。
7
+ // 折り返しを許可して全文表示する。サイドバーのナビ配下に限定する。
8
+ .sidebar-content,
9
+ .sidebar-panel,
10
+ #main-sidebar {
11
+ .nav-link {
12
+ white-space: normal;
13
+ }
14
+ }
15
+
16
+ // メディアフォーム(商品編集のメディア欄等): 画像の一括削除用チェックボックスがクリックできない。
17
+ // タイル内は チェックボックス → ドラッグハンドル → 画像リンク の順に並んでおり、全面を覆う
18
+ // position: absolute の画像が後発のため、チェックボックスの上に重なってクリックを奪っていた。
19
+ // Bootstrap 版の管理画面 CSS には .custom-control に z-index: 1 があったが、Spree 5.2 の
20
+ // Tailwind 移行(spree/spree@dc3e7bb5e2)で失われている(v5.6.1 時点でも未修正)。
21
+ // ドラッグハンドル側の z-index: 2 に合わせて前面に戻す。
22
+ // @see https://github.com/be-agile/giga-repeat/issues/1325
23
+ .media-form__image {
24
+ .custom-control {
25
+ z-index: 2;
26
+ }
27
+ }
28
+
29
+ // 在庫品一覧(/admin/stock_items): バリエーション名が長いと nowrap で
30
+ // テーブルが横に伸び、横スクロールしないと全体を把握できなかった。
31
+ // セルの折り返しを許可し、画面幅内に全列が収まるようにする。
32
+ body.stock_items {
33
+ table.table tbody td {
34
+ white-space: normal;
35
+
36
+ * {
37
+ white-space: normal;
38
+ }
39
+ }
40
+ }
@@ -0,0 +1,111 @@
1
+ module BaSpree
2
+ module CheckoutControllerDecorator
3
+ def self.prepended(base)
4
+ base.before_action :filter_bill_address_when_use_shipping, only: [ :update ], if: -> { params[:state] == 'payment' }
5
+ end
6
+
7
+ protected
8
+
9
+ # Overrides Spree::CheckoutController#load_order to support guest checkout and custom order handling.
10
+ # @gem-override spree_storefront-5.3.6/app/controllers/spree/checkout_controller.rb#load_order
11
+ # reason: ゲストチェックアウト対応のため super なしで丸ごと再実装。本家のゲスト処理を
12
+ # handle_guest_checkout / create_guest_order に抽出している (commit d0dbe2b4)
13
+ # @see https://github.com/be-agile/giga-repeat/commit/d0dbe2b4524e22c1cf974bbd4829c587ef7cd254
14
+ def load_order
15
+ return @order if @order.present?
16
+
17
+ orders_scope = action_name == 'complete' ? current_store.orders.complete : current_store.orders.incomplete
18
+
19
+ # we shouldn't lock the order here, because we're not going to update it
20
+ lock = ![ 'complete', 'edit' ].include?(action_name)
21
+
22
+ @order = orders_scope.lock(lock).find_by(token: params[:token])
23
+
24
+ if @order.nil?
25
+ clear_order_token
26
+ redirect_to_cart and return
27
+ end
28
+
29
+ if @order.user_id.present?
30
+ if try_spree_current_user.present? && @order.user_id != try_spree_current_user.id
31
+ clear_order_token
32
+ flash[:error] = 'You cannot access this checkout'
33
+ redirect_to_cart
34
+ elsif try_spree_current_user.nil? && !allow_access_to_complete_order_with_new_user?
35
+ handle_guest_checkout
36
+ end
37
+ end
38
+
39
+ # completed orders shouldn't be updated anymore
40
+ unless @order.completed?
41
+ # 5.3 追従: order_tracking_params のうち実際に変化した値だけを更新する
42
+ tracking_params = order_tracking_params
43
+ changed_params = tracking_params.reject { |key, value| @order.public_send(key) == value }
44
+
45
+ if changed_params.any?
46
+ @order.assign_attributes(changed_params)
47
+ @order.update_columns(changed_params)
48
+ end
49
+
50
+ @order.associate_user!(try_spree_current_user) if try_spree_current_user && @order.user.nil?
51
+ end
52
+ @current_order = @order # for compatibility with the rest of storefront, analytics, etc
53
+ end
54
+
55
+ private
56
+
57
+ # @gem-override spree_storefront-5.3.6/app/controllers/spree/checkout_controller.rb#allow_access_to_complete_order_with_new_user?
58
+ # reason: ba_spree のゲスト購入は注文確定時に guest ユーザー(guest: true)を
59
+ # 自動作成して order.user_id に紐付ける(app/models/spree/order_decorator.rb#link_guest_user)。
60
+ # このため本家の判定(signup_for_an_account? 必須)だとゲストが注文完了画面を開けず
61
+ # ログイン画面にリダイレクトされてしまう。注文に紐付くユーザーが guest の場合は
62
+ # トークンが一致していれば完了画面の閲覧を許可する。
63
+ def allow_access_to_complete_order_with_new_user?
64
+ return true if super
65
+ return false unless @order.completed? && @order.user_id.present?
66
+
67
+ # ゲスト購入で紐付けた guest ユーザー(guest: true)の注文は、URL の order token で
68
+ # アクセスできれば本人とみなして完了画面の閲覧を許可する。
69
+ # (load_order が find_by(token: params[:token]) で URL トークン一致を保証済み。
70
+ # 本家は cookies.signed[:token] 一致も要求するが、ゲストでは確定後のリダイレクトで
71
+ # cookie が引き継がれないケースがあり、cookie には依存しない)
72
+ # guest ユーザーは link_guest_user で deleted_at が設定される(論理削除)ため
73
+ # with_deleted で取得して判定する。
74
+ guest_user = Spree.user_class.with_deleted.find_by(id: @order.user_id)
75
+ guest_user&.guest? || false
76
+ end
77
+
78
+ def handle_guest_checkout
79
+ if params[:guest] && current_store.prefers_guest_checkout?
80
+ @order = create_guest_order
81
+ reset_session
82
+ create_token_cookie(@order.token)
83
+ redirect_to spree.checkout_path(@order.token)
84
+ else
85
+ store_location
86
+ redirect_to spree_login_path
87
+ end
88
+ end
89
+
90
+ def create_guest_order
91
+ current_store.orders.create!(current_order_params.except(:token, :user_id)).tap do |order|
92
+ order.merge!(@order, discard_merged: false)
93
+ order.disassociate_user!
94
+ end
95
+ end
96
+
97
+ def filter_bill_address_when_use_shipping
98
+ return unless params[:order]&.dig(:bill_address_attributes)
99
+
100
+ if params[:order]&.dig(:use_shipping) == '1'
101
+ # Remove bill_address_attributes entirely when use_shipping is enabled
102
+ params[:order].delete(:bill_address_attributes)
103
+ elsif params[:order]&.dig(:use_shipping) == '0'
104
+ # Remove id field to force new address creation when use_shipping is disabled
105
+ params[:order][:bill_address_attributes].delete(:id) if params[:order][:bill_address_attributes][:id]
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ Spree::CheckoutController.prepend(BaSpree::CheckoutControllerDecorator)
@@ -0,0 +1,55 @@
1
+ module BaSpree
2
+ module StoreControllerDecorator
3
+ def self.prepended(base)
4
+ base.helper_method :stored_location
5
+ # Issue #1219: 価格表(price_list)を一覧・関連・セールラベルでログイン中ユーザの
6
+ # グループに反映させるため、リクエスト毎に pricing_user を Spree::Current へ設定する。
7
+ # Product#lowest_price / #on_sale? / #price_varies? (product_decorator) がこれを参照する。
8
+ base.before_action :set_current_pricing_user
9
+ end
10
+
11
+ protected
12
+
13
+ # @see https://github.com/be-agile/giga-repeat/issues/1219
14
+ # ログイン中ユーザを Spree::Current.pricing_user に設定する。ゲストは nil。
15
+ def set_current_pricing_user
16
+ Spree::Current.pricing_user = try_spree_current_user
17
+ end
18
+
19
+ # @gem-override spree_storefront-5.3.6/app/controllers/spree/store_controller.rb#stored_location
20
+ # reason: ゲストログイン導線で protected な stored_location を helper_method として使えるようにするため
21
+ # super なしで再実装(実装内容は本家とほぼ同一)(commit d0dbe2b4)
22
+ # @see https://github.com/be-agile/giga-repeat/commit/d0dbe2b4524e22c1cf974bbd4829c587ef7cd254
23
+ def stored_location
24
+ return unless defined?(after_sign_in_path_for)
25
+ return unless defined?(Devise)
26
+
27
+ path = after_sign_in_path_for(Devise.mappings.keys.first)
28
+ store_location(path)
29
+ path
30
+ end
31
+
32
+ # @gem-override spree_storefront-5.3.6/app/controllers/spree/store_controller.rb#storefront_products_includes
33
+ # reason: カテゴリ詳細でオプションを含む商品がヒットすると落ちる問題への対処。本家の
34
+ # `option_types` を `option_types_for_includes` に置き換えて eager load する (Issue #847)
35
+ # @see https://github.com/be-agile/giga-repeat/issues/847
36
+ #
37
+ # Spree 5.3 追従: 本家は明示 includes を最小ハッシュに簡略化し、呼び出し元の
38
+ # `preload_associations_lazily`(ar_lazy_preload)で残りを遅延 preload する方式に移行した。
39
+ # 本家の新ハッシュ構造をベースにしつつ、#847 対策の option_types_for_includes 明示 eager load を維持する。
40
+ def storefront_products_includes
41
+ {
42
+ taxons: [],
43
+ master: [ :images, :prices, { stock_items: :stock_location } ],
44
+ variants: [ :images, :prices, { stock_items: :stock_location } ],
45
+ # Issue #1290: 一覧の価格表示(product_decorator#resolved_prices_for)は
46
+ # variants_including_master の価格を走査するため、ページ単位でまとめて eager load する
47
+ variants_including_master: [ :prices ],
48
+ # Issue #847: option_types を order(:id) 付き別 association に置き換えて eager load
49
+ option_types_for_includes: []
50
+ }
51
+ end
52
+ end
53
+ end
54
+
55
+ Spree::StoreController.prepend(BaSpree::StoreControllerDecorator)
@@ -0,0 +1,16 @@
1
+ module BaSpree
2
+ module ThemeConcernDecorator
3
+ # @gem-override spree_storefront-5.3.6/app/controllers/concerns/spree/theme_concern.rb#set_theme_view_paths
4
+ # reason: 本家の view path 設定 (super) の後に、ba_spree extension の themes/default を
5
+ # view path に追加して本家テーマより優先させる (commit d0f0ce22)
6
+ # @see https://github.com/be-agile/giga-repeat/commit/d0f0ce224dd5696b38676f2fe4dc1e52743f115a
7
+ def set_theme_view_paths
8
+ super
9
+ prepend_view_path [ BaSpree::Engine.root, 'app/views/themes/default' ].join('/')
10
+ end
11
+ end
12
+ end
13
+
14
+ if Spree::ThemeConcern.included_modules.exclude?(BaSpree::ThemeConcernDecorator)
15
+ Spree::ThemeConcern.prepend BaSpree::ThemeConcernDecorator
16
+ end
@@ -0,0 +1,48 @@
1
+ module Spree
2
+ module Admin
3
+ module AssetsControllerDecorator
4
+ # @gem-override spree_admin-5.3.6/app/controllers/spree/admin/assets_controller.rb#update
5
+ # @see https://github.com/be-agile/giga-repeat/issues/1292
6
+ #
7
+ # 並び替え (stimulus-sortable) は移動した 1 件だけに asset[position] を送るが、
8
+ # その値は DB の position ではなく「画面上のインデックス + 1」である。
9
+ # acts_as_list は送られた position が既存レコードと衝突したときしか周囲を
10
+ # 詰め直さないため、position が 1..N の連番でないと 200 を返すのに並び順が
11
+ # 変わらない。並び替えのときだけ、先に連番へ詰め直してから本家の更新に渡す。
12
+ #
13
+ # 詰め直しと本家の更新は 1 つのトランザクションに入れ、採番(Spree::AssetDecorator)と
14
+ # 同じ viewable 行ロックを取る。そうしないと、詰め直してから更新するまでの間に
15
+ # アップロードが 1 件 INSERT され、本家が前提にしている「1..N の連番」が崩れる。
16
+ # ロックを保持したままレスポンスを描画することになるが、並び替えの応答は
17
+ # JSON 1 件か小さな turbo_stream なので影響は小さい。
18
+ def update
19
+ return super unless sorting_request?
20
+
21
+ Spree::Asset.transaction do
22
+ @asset.lock_viewable_row
23
+ normalize_positions
24
+ super
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ # 画像編集ダイアログからの更新 (alt / attachment) は position を送らない。
31
+ def sorting_request?
32
+ params.dig(:asset, :position).present?
33
+ end
34
+
35
+ def normalize_positions
36
+ normalized = Spree::Assets::PositionNormalizer.call(
37
+ viewable_type: @asset.viewable_type,
38
+ viewable_id: @asset.viewable_id
39
+ )
40
+ # 詰め直しは update_column で行うため、メモリ上の @asset に反映されていない。
41
+ # 古い position のまま保存すると acts_as_list が詰め直す範囲を誤る。
42
+ @asset.reload if normalized
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ Spree::Admin::AssetsController.prepend(Spree::Admin::AssetsControllerDecorator)
@@ -0,0 +1,25 @@
1
+ module Spree
2
+ module Admin
3
+ module ProductsControllerDecorator
4
+ private
5
+
6
+ # @gem-override spree_admin-5.3.6/app/controllers/spree/admin/products_controller.rb#assign_master_images
7
+ # @see https://github.com/be-agile/giga-repeat/issues/1292
8
+ #
9
+ # 新規商品の作成時、先にアップロードされた画像は viewable_id が nil のまま
10
+ # 採番される。この採番スコープ (viewable_id: nil) は作成中の全商品で共有される
11
+ # ため、master へ付け替えた直後の position は 1..N の連番にならない。
12
+ # 本家は update_all で付け替えるだけで acts_as_list を通らないので、ここで詰め直す。
13
+ def assign_master_images
14
+ super
15
+
16
+ Spree::Assets::PositionNormalizer.call(
17
+ viewable_type: 'Spree::Variant',
18
+ viewable_id: @product.master&.id
19
+ )
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ Spree::Admin::ProductsController.prepend(Spree::Admin::ProductsControllerDecorator)
@@ -0,0 +1,30 @@
1
+ # app/decorators/controllers/spree/admin/promotion_rules_controller_decorator.rb
2
+ module Spree
3
+ module Admin
4
+ module PromotionRulesControllerDecorator
5
+ def option_values_search
6
+ search_term = params[:q]
7
+ option_values = if search_term.present?
8
+ Spree::OptionValue.joins(:option_type)
9
+ .where("LOWER(spree_option_values.name) LIKE ? OR LOWER(spree_option_values.presentation) LIKE ?",
10
+ "%#{search_term.downcase}%", "%#{search_term.downcase}%")
11
+ .distinct
12
+ else
13
+ Spree::OptionValue.limit(30)
14
+ end
15
+
16
+ # Format option values for tom_select
17
+ result = option_values.map do |option_value|
18
+ {
19
+ id: option_value.id,
20
+ name: "#{option_value.option_type_presentation}: #{option_value.presentation}"
21
+ }
22
+ end
23
+
24
+ render json: result
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ Spree::Admin::PromotionRulesController.prepend(Spree::Admin::PromotionRulesControllerDecorator)
@@ -0,0 +1,34 @@
1
+ module Spree
2
+ module Admin
3
+ module UsersControllerDecorator
4
+ # 本家 Spree::Admin::UsersController#search は query.length < 3 で検索を弾くため、
5
+ # 2文字の日本語姓(例: 大村)で検索できなかった。ba_spree では2文字以上で
6
+ # 検索できるよう最小文字数を 2 に緩和する。それ以外の挙動は本家を踏襲する。
7
+ def search
8
+ query = params[:q]&.strip
9
+
10
+ head :ok and return if query.blank? || query.length < 2
11
+
12
+ scope = model_class.accessible_by(current_ability, :index)
13
+ scope = scope.where.not(id: params[:omit_ids].split(',')) if params[:omit_ids].present?
14
+ @users = scope.includes(:bill_address, :ship_address, avatar_attachment: :blob)
15
+ .multi_search(query)
16
+ .limit(params[:limit] || 10)
17
+
18
+ respond_to do |format|
19
+ format.turbo_stream do
20
+ render turbo_stream: [
21
+ turbo_stream.replace(
22
+ "users_search_results",
23
+ partial: "spree/admin/users/search_results",
24
+ locals: { users: @users }
25
+ )
26
+ ]
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ Spree::Admin::UsersController.prepend(Spree::Admin::UsersControllerDecorator)
@@ -0,0 +1,23 @@
1
+ module Spree
2
+ module ContactsControllerDecorator
3
+ # @gem-override spree_storefront-5.3.6/app/controllers/spree/contacts_controller.rb#create
4
+ # reason: お問い合わせ自動応答の From が問い合わせ者本人になり SES 未検証エラーで 500 になる問題への対処。
5
+ # super なし丸ごと再実装で mail_from_address を store の検証済みアドレスに設定する (Issue #1092)
6
+ # @see https://github.com/be-agile/giga-repeat/issues/1092
7
+ def create
8
+ @contact = Spree::Contact.new(params[:contact])
9
+ @contact.customer_support_email = current_store.customer_support_email
10
+ @contact.mail_from_address = current_store.mail_from_address
11
+ @contact.request = request
12
+
13
+ if @contact.deliver
14
+ flash[:success] = Spree.t('storefront.contacts.message_sent')
15
+ else
16
+ message_not_sent
17
+ end
18
+ redirect_to action: :new
19
+ end
20
+ end
21
+ end
22
+
23
+ Spree::ContactsController.prepend Spree::ContactsControllerDecorator
@@ -0,0 +1,61 @@
1
+ module Spree
2
+ class DigitalLinksController < StoreController
3
+ def show
4
+ if digital_link.authorize!
5
+ if digital_link.downloadable?
6
+ mark_shipment_as_fullfiled if digital_link.access_counter == 1
7
+
8
+ if defined?(ActiveStorage::Service::DiskService) && ActiveStorage::Blob.service.instance_of?(ActiveStorage::Service::DiskService)
9
+ send_file(
10
+ ActiveStorage::Blob.service.path_for(attachment.key),
11
+ filename: digital_link.filename.to_s,
12
+ type: digital_link.content_type.to_s,
13
+ status: :ok
14
+ ) and return
15
+ else
16
+ redirect_to attachment.url(
17
+ expires_in: current_store.preferred_digital_asset_link_expire_time.seconds,
18
+ disposition: 'attachment'
19
+ ), allow_other_host: true and return
20
+ end
21
+ else
22
+ flash[:error] = I18n.t('spree.api.v2.digitals.unpaid')
23
+ if try_spree_current_user.present?
24
+ redirect_to spree.order_path(digital_link.order) and return
25
+ else
26
+ redirect_to root_path and return
27
+ end
28
+ end
29
+ end
30
+
31
+ flash[:error] = Spree.t(:digital_link_unauthorized)
32
+ if try_spree_current_user.present?
33
+ redirect_to spree.order_path(digital_link.order) and return
34
+ else
35
+ redirect_to root_path and return
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def mark_shipment_as_fullfiled
42
+ ActiveRecord::Base.connected_to(role: :writing) do
43
+ Spree::Shipment.transaction do
44
+ shipments.each(&:ship)
45
+ end
46
+ end
47
+ end
48
+
49
+ def digital_link
50
+ @digital_link ||= current_store.digital_links.find_by!(token: params[:id])
51
+ end
52
+
53
+ def shipments
54
+ @shipments ||= digital_link.line_item.shipments.digital_delivery
55
+ end
56
+
57
+ def attachment
58
+ @attachment ||= digital_link.digital.attachment
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,24 @@
1
+ module Spree
2
+ module OrdersControllerDecorator
3
+ # @gem-override spree_storefront-5.3.6/app/controllers/spree/orders_controller.rb#edit
4
+ # reason: 本家 edit (super) の後に、セッション切れで自動ログアウトした場合の order からの
5
+ # ユーザー紐付け解除と turbo_stream レスポンス対応を追加 (commit d9fb5efc)
6
+ # @see https://github.com/be-agile/giga-repeat/commit/d9fb5efc3b81bd54639e9cbaa04f930098c02835
7
+ def edit
8
+ super
9
+
10
+ # Handle automatic logout: if user session expired but order still has user_id
11
+ if try_spree_current_user.nil? && @order&.user_id.present?
12
+ Rails.logger.info "Detected automatic logout for order #{@order.number}, disassociating user"
13
+ @order.disassociate_user!
14
+ end
15
+
16
+ respond_to do |format|
17
+ format.html
18
+ format.turbo_stream
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ Spree::OrdersController.prepend Spree::OrdersControllerDecorator
@@ -0,0 +1,65 @@
1
+ module BaSpree
2
+ # 価格表(price_list)解決の上書きのみを担う decorator。ba_spree には association / slug 生成を
3
+ # 担う BaSpree::ProductDecorator も別にあるため、同一定数にならないよう名前を分けている。
4
+ # @gem-override spree_core-5.3.6/app/models/spree/product.rb#lowest_price, #on_sale?, #price_varies?
5
+ # reason: 本家のこれら3メソッドは prices_including_master (-> { non_zero } のみ) を直接走査し、
6
+ # pricing context (user / customer_group / price_list の status) を一切考慮しない。
7
+ # そのため価格表(price_list)機能で以下の不具合が起きる (Issue #1219, Spree 5.4 でも未修正):
8
+ # - 草案(draft)の price_list でも一覧・関連商品で最安値が表示される
9
+ # - ゲストや顧客グループ外ユーザにも、他グループ向けの安い単価が一覧で表示される
10
+ # - 「価格」と「価格で比較」の両方設定で、対象外ユーザにもセールラベルが表示される
11
+ # 商品詳細の本体価格は price_for(Resolver 経由) で正しく解決されているため、一覧・関連・
12
+ # ラベルでも同じ Resolver を通すよう上書きする。user は Spree::Current.pricing_user
13
+ # (store_controller_decorator が before_action で設定) から取得する。
14
+ #
15
+ # ただし Resolver を variant ごとに呼ぶと多 variant 商品で描画が極端に重くなるため、
16
+ # 解決処理は Spree::Pricing::BatchResolver に切り出してバッチ化・メモ化してある (Issue #1290)。
17
+ # BatchResolver は Resolver の選択規則を複製しているので、Spree アップグレード時は
18
+ # BatchResolver 側の @gem-override マーカーも確認すること。
19
+ # @see https://github.com/be-agile/giga-repeat/issues/1219
20
+ # @see https://github.com/be-agile/giga-repeat/issues/1290
21
+ module ProductPricingDecorator
22
+ # 指定通貨における最安価格(ログイン中ユーザに適用される price_list を考慮)
23
+ # @param currency [String]
24
+ # @return [Spree::Price, nil]
25
+ def lowest_price(currency)
26
+ resolved_prices_for(currency).min_by(&:amount)
27
+ end
28
+
29
+ # 複数 variant 間で(ユーザに適用される)価格が異なるか
30
+ # @param currency [String]
31
+ # @return [Boolean]
32
+ def price_varies?(currency)
33
+ resolved_prices_for(currency).map(&:amount).uniq.size > 1
34
+ end
35
+
36
+ # いずれかの variant が(ユーザに適用される価格で)セール中か
37
+ # @param currency [String]
38
+ # @return [Boolean]
39
+ def on_sale?(currency)
40
+ resolved_prices_for(currency).any?(&:discounted?)
41
+ end
42
+
43
+ private
44
+
45
+ # 全 variant(master 含む)について、現在のユーザに適用される実価格を解決して返す。
46
+ # 解決そのものは Spree::Pricing::BatchResolver に委譲し、ここでは (通貨, ユーザ) 単位で
47
+ # メモ化して lowest_price / price_varies? / on_sale? からの重複解決を防ぐ。
48
+ # @param currency [String]
49
+ # @return [Array<Spree::Price>]
50
+ def resolved_prices_for(currency)
51
+ currency = currency&.upcase
52
+ user = Spree::Current.pricing_user
53
+ cache = (@resolved_prices_for ||= {})
54
+ key = [ currency, user&.id ]
55
+ return cache[key] if cache.key?(key)
56
+
57
+ cache[key] = Spree::Pricing::BatchResolver.new(
58
+ variants: variants_including_master.to_a,
59
+ context: Spree::Pricing::Context.new(variant: master, currency: currency, user: user)
60
+ ).resolve
61
+ end
62
+ end
63
+ end
64
+
65
+ Spree::Product.prepend(BaSpree::ProductPricingDecorator)
@@ -0,0 +1,17 @@
1
+ module Spree
2
+ # @gem-override spree_core-5.3.6/app/models/spree/current.rb
3
+ # reason: 価格表(price_list)を一覧・関連商品・セールラベルで「ログイン中ユーザのグループ」に
4
+ # 正しく反映させるため、リクエストスコープの pricing_user を保持できるようにする。
5
+ # 本家の Spree::Current には user 属性が無く、Product#lowest_price 等が pricing context を
6
+ # 通らないため、ゲストや対象外ユーザにも他グループの最安値・セールラベルが漏れていた (Issue #1219)。
7
+ # @see https://github.com/be-agile/giga-repeat/issues/1219
8
+ module CurrentDecorator
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ attribute :pricing_user
13
+ end
14
+ end
15
+ end
16
+
17
+ Spree::Current.include(Spree::CurrentDecorator)
@@ -0,0 +1,51 @@
1
+ module Spree
2
+ module MoneyDecorator
3
+ # Fix amount_in_cents for JPY and other zero-decimal currencies
4
+ # Money gem already returns the correct value in the smallest unit,
5
+ # so we don't need the × 100 conversion that breaks JPY
6
+ # @gem-override spree_core-5.3.6/lib/spree/money.rb#amount_in_cents
7
+ # reason: JPY 等のゼロ小数通貨では Money gem が既に最小単位を返すため、本家の ×100 変換が壊れる。
8
+ # cents をそのまま返すよう super なしで再実装 (Issue #1004)
9
+ # @see https://github.com/be-agile/giga-repeat/issues/1004
10
+ def amount_in_cents
11
+ cents
12
+ end
13
+
14
+ # @gem-override spree_core-5.3.6/lib/spree/money.rb#to_html
15
+ # reason: JPY の負の金額で符号位置が崩れる問題への対処。本家整形後に符号を金額の前へ移す (Issue #292)
16
+ # @see https://github.com/be-agile/giga-repeat/issues/292
17
+ def to_html(opts = { html: true })
18
+ opts[:html_wrap] = opts[:html]
19
+ opts.delete(:html)
20
+ output = money.format(options.merge(opts))
21
+
22
+ if opts[:html_wrap]
23
+ output.gsub!(/<\/?[^>]*>/, '')
24
+ output = output.sub(' ', '&nbsp;').html_safe
25
+ end
26
+
27
+ if money.currency.iso_code == "JPY" && money.cents.negative?
28
+ output.gsub!(/-/, '')
29
+ output.gsub!(/([\D]*)(\d[\d,\.]*)/, '-\2\1')
30
+ end
31
+
32
+ output
33
+ end
34
+
35
+ # @gem-override spree_core-5.3.6/lib/spree/money.rb#to_s
36
+ # reason: JPY の負の金額で符号位置が崩れる問題への対処。本家整形後に符号を金額の前へ移す (Issue #292)
37
+ # @see https://github.com/be-agile/giga-repeat/issues/292
38
+ def to_s
39
+ output = money&.format(options)
40
+
41
+ if output.present? && money.currency.iso_code == "JPY" && money.cents.negative?
42
+ output.gsub!(/-/, '')
43
+ output.gsub!(/([\D]*)(\d[\d,\.]*)/, '-\2\1')
44
+ end
45
+
46
+ output
47
+ end
48
+ end
49
+ end
50
+
51
+ Spree::Money.prepend(Spree::MoneyDecorator)