spree_admin 5.4.0 → 5.4.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6302dd5efd335e12ad7c600d7c4682b0c0a1d90dd995f808aac76f9c2333375c
4
- data.tar.gz: a65828be9dbb4cb21ca11d23b7c6afbc67301a183381c651d1141e08cbf4308d
3
+ metadata.gz: 26df0b31a098e6532b1f1ce9a0d9c93e5775eabfdb0aae25d97ddc2cad9817f7
4
+ data.tar.gz: d9a8d58ad5854ae05313f113ad57530aaa1a7b70d75bb4d19c20f7fc0904a71b
5
5
  SHA512:
6
- metadata.gz: fe7c73af6692b538d6e7b6d3e1e7c02deed3a5805950b15a92da91984ba08f9a339f67c9cb110d11e0197f5e9576538f8993da98757b894c219d25a4bedc28a3
7
- data.tar.gz: 8aebe6353ab1e7176f9ee61b156fb4da712a41eb4b36f906870f8ddb3689ac65805de795ac97aebc3fa70c1f19f6eb6a7a5a63ba122bd0846b6e25aebe706357
6
+ metadata.gz: 142a56b2d97a37fd72ec7230a0d35bc83a3ea1e56b31c36c536a1e33a5714c1148c4e69d6e779348fa10cef3f8157e0e14909641a9472419c95bd09da52bd48d
7
+ data.tar.gz: f29b088464374c13ae4bbc77a549f15524cd6661fedc3ac6e3d3f484c3dba47b91bd1e0d643031ddf953c156949f7fdf54ed889cc026096ca701df6b9e6db0e3
@@ -88,6 +88,24 @@ module Spree
88
88
  @current_timezone ||= current_store.preferred_timezone
89
89
  end
90
90
 
91
+ # datetime-local inputs submit values without timezone information. Interpret
92
+ # them in the store's timezone so they match what the admin sees in the form.
93
+ def parse_datetime_in_store_timezone(attrs, *fields)
94
+ zone = ActiveSupport::TimeZone[current_timezone] || Time.zone
95
+
96
+ fields.each do |field|
97
+ value = attrs[field]
98
+ next if value.blank?
99
+
100
+ parsed_value = begin
101
+ zone.parse(value.to_s)
102
+ rescue ArgumentError
103
+ nil
104
+ end
105
+ attrs[field] = parsed_value if parsed_value.present?
106
+ end
107
+ end
108
+
91
109
  def current_currency
92
110
  @current_currency ||= if params[:currency].present? && supported_currency?(params[:currency])
93
111
  params[:currency]
@@ -304,11 +304,15 @@ module Spree
304
304
  end
305
305
 
306
306
  def permitted_resource_params
307
- @permitted_resource_params ||= if cannot?(:activate, @product) && @new_status&.to_sym == :active
308
- params.require(:product).permit(permitted_product_attributes).except(:status, :make_active_at)
309
- else
310
- params.require(:product).permit(permitted_product_attributes)
311
- end
307
+ @permitted_resource_params ||= begin
308
+ attrs = if cannot?(:activate, @product) && @new_status&.to_sym == :active
309
+ params.require(:product).permit(permitted_product_attributes).except(:status, :make_active_at)
310
+ else
311
+ params.require(:product).permit(permitted_product_attributes)
312
+ end
313
+ parse_datetime_in_store_timezone(attrs, :available_on, :discontinue_on, :make_active_at)
314
+ attrs
315
+ end
312
316
  end
313
317
  end
314
318
  end
@@ -48,7 +48,9 @@ module Spree
48
48
  end
49
49
 
50
50
  def permitted_resource_params
51
- params.require(:promotion).permit(permitted_promotion_attributes)
51
+ attrs = params.require(:promotion).permit(permitted_promotion_attributes)
52
+ parse_datetime_in_store_timezone(attrs, :starts_at, :expires_at)
53
+ attrs
52
54
  end
53
55
  end
54
56
  end
@@ -1,3 +1,13 @@
1
+ <%# datetime-local inputs have no timezone; render values in the store's timezone so admins see and submit values in the store's local time. %>
2
+ <%
3
+ store_timezone = ActiveSupport::TimeZone[current_store.preferred_timezone] || Time.zone
4
+ to_store_local = ->(value) { value&.in_time_zone(store_timezone)&.strftime('%Y-%m-%dT%H:%M') }
5
+ make_active_at_local = to_store_local.call(@product.make_active_at)
6
+ available_on_local = to_store_local.call(@product.available_on)
7
+ discontinue_on_local = to_store_local.call(@product.discontinue_on)
8
+ tz_help = Spree.t('admin.datetime_field_timezone_help', zone: store_timezone.name)
9
+ %>
10
+
1
11
  <div class="card mb-6">
2
12
  <div class="card-body">
3
13
  <div class="grid grid-cols-12 gap-6 mb-6">
@@ -14,21 +24,27 @@
14
24
  <div class="col-span-6 <%= 'hidden' if @product.active? %>" data-product-form-target="makeActiveAt">
15
25
  <% if can?(:activate, @product) %>
16
26
  <%= f.spree_datetime_field :make_active_at,
27
+ value: make_active_at_local,
28
+ help: tz_help,
17
29
  help_bubble: Spree.t('admin.products.status_form.make_active_at'),
18
- max: @product.discontinue_on %>
30
+ max: discontinue_on_local %>
19
31
  <% end %>
20
32
  </div>
21
33
  </div>
22
34
  <div class="grid grid-cols-12 gap-6">
23
35
  <div data-product-form-target="availableOn" class="col-span-6">
24
36
  <%= f.spree_datetime_field :available_on,
37
+ value: available_on_local,
38
+ help: tz_help,
25
39
  help_bubble: Spree.t('admin.products.status_form.available_on'),
26
- max: @product.discontinue_on %>
40
+ max: discontinue_on_local %>
27
41
  </div>
28
42
  <div data-product-form-target="discontinueOn" class="col-span-6">
29
43
  <%= f.spree_datetime_field :discontinue_on,
44
+ value: discontinue_on_local,
45
+ help: tz_help,
30
46
  help_bubble: Spree.t('admin.products.status_form.discontinue_on'),
31
- min: @product.make_active_at %>
47
+ min: make_active_at_local %>
32
48
  </div>
33
49
  </div>
34
50
  </div>
@@ -167,7 +167,7 @@
167
167
  <div class="variants-table__body" data-variants-form-target="variantsContainer" data-test-id="product-variants-table">
168
168
  </div>
169
169
  <div class="variants-table__footer text-sm rounded-b-2xl">
170
- <%= Spree.t('admin.variants_form.total_inventory_html', stock_location: current_store.default_stock_location.name, count: raw("<span data-variants-form-target='stockItemsCount'>#{@product.total_on_hand}</span>") )%>
170
+ <%= Spree.t('admin.variants_form.total_inventory_html', stock_location: default_stock_location_for_product(@product).name, count: raw("<span data-variants-form-target='stockItemsCount'>#{@product.total_on_hand}</span>") )%>
171
171
  </div>
172
172
  </div>
173
173
  </div>
@@ -21,18 +21,18 @@
21
21
  <div class="variants-table__body__cell column-price mr-2">
22
22
  <% supported_currencies.each_with_index do |currency, i| %>
23
23
  <div class="input-group price-input-container <%= current_currency != currency ? 'hidden' : 'flex' %>" <%= !can_manage_prices ? 'readonly' : '' %>>
24
- <%= text_field_tag "product[variants_attributes][prices_attributes][#{i}][amount]", '', class: 'border-0 focus:ring-0 focus:outline-none', data: { slot: "[prices_attributes][#{currency}][amount]_input", action: 'variants-form#updatePrice blur->variants-form#formatPrice', currency: currency.to_s }, readonly: !can_manage_prices %>
24
+ <%= text_field_tag "product[variants_attributes][prices_attributes][#{i}][amount]", '', id: nil, class: 'border-0 focus:ring-0 focus:outline-none', data: { slot: "[prices_attributes][#{currency}][amount]_input", action: 'variants-form#updatePrice blur->variants-form#formatPrice', currency: currency.to_s }, readonly: !can_manage_prices %>
25
25
  <span class="px-3"><%= currency_symbol(currency) %></span>
26
26
  </div>
27
- <%= hidden_field_tag "product[variants_attributes][prices_attributes][#{i}][currency]", currency, data: {slot: "[prices_attributes][#{currency}][currency]_input"} %>
28
- <%= hidden_field_tag "product[variants_attributes][prices_attributes][#{i}][id]", "", data: {slot: "[prices_attributes][#{currency}][id]_input"} %>
27
+ <%= hidden_field_tag "product[variants_attributes][prices_attributes][#{i}][currency]", currency, id: nil, data: {slot: "[prices_attributes][#{currency}][currency]_input"} %>
28
+ <%= hidden_field_tag "product[variants_attributes][prices_attributes][#{i}][id]", "", id: nil, data: {slot: "[prices_attributes][#{currency}][id]_input"} %>
29
29
  <% end %>
30
30
  </div>
31
31
  <div class="variants-table__body__cell column-quantity">
32
32
  <% available_stock_locations_for_product(@product).ids.each_with_index do |id, i| %>
33
- <%= number_field_tag "product[variants_attributes][stock_items_attributes][#{i}][count_on_hand]", 0, class: class_names('form-input', default_stock_location.id == id ? 'block' : 'hidden'), data: {slot: "[stock_items_attributes][#{id}][count_on_hand]_input", stock_location_id: id, action: "variants-form#updateCountOnHand blur->variants-form#replaceBlankWithZero" }, readonly: !can_manage_stock %>
34
- <%= hidden_field_tag "product[variants_attributes][stock_items_attributes][#{i}][stock_location_id]", id, data: { slot: "[stock_items_attributes][#{id}][stock_location_id]_input" } %>
35
- <%= hidden_field_tag "product[variants_attributes][stock_items_attributes][#{i}][id]", "", data: { slot: "[stock_items_attributes][#{id}][id]_input" } %>
33
+ <%= number_field_tag "product[variants_attributes][stock_items_attributes][#{i}][count_on_hand]", 0, id: nil, class: class_names('form-input', default_stock_location.id == id ? 'block' : 'hidden'), data: {slot: "[stock_items_attributes][#{id}][count_on_hand]_input", stock_location_id: id, action: "variants-form#updateCountOnHand blur->variants-form#replaceBlankWithZero" }, readonly: !can_manage_stock %>
34
+ <%= hidden_field_tag "product[variants_attributes][stock_items_attributes][#{i}][stock_location_id]", id, id: nil, data: { slot: "[stock_items_attributes][#{id}][stock_location_id]_input" } %>
35
+ <%= hidden_field_tag "product[variants_attributes][stock_items_attributes][#{i}][id]", "", id: nil, data: { slot: "[stock_items_attributes][#{id}][id]_input" } %>
36
36
  <% end %>
37
37
  </div>
38
38
  <% if can?(:manage, @product.default_variant) %>
@@ -2,6 +2,17 @@
2
2
  <%= f.spree_number_field :usage_limit, min: 0, step: 1, help: 'Leave this field blank for unlimited usage.' %>
3
3
  <% end %>
4
4
 
5
- <%= f.spree_datetime_field :starts_at %>
5
+ <%# datetime-local inputs have no timezone; render values in the store's timezone so admins see and submit values in the store's local time. %>
6
+ <%
7
+ store_timezone = ActiveSupport::TimeZone[current_store.preferred_timezone] || Time.zone
8
+ to_store_local = ->(value) { value&.in_time_zone(store_timezone)&.strftime('%Y-%m-%dT%H:%M') }
9
+ starts_at_local = to_store_local.call(@promotion.starts_at)
10
+ expires_at_local = to_store_local.call(@promotion.expires_at)
11
+ tz_help = Spree.t('admin.datetime_field_timezone_help', zone: store_timezone.name)
12
+ %>
6
13
 
7
- <%= f.spree_datetime_field :expires_at, help: 'Leave this field blank for no expiration.' %>
14
+ <%= f.spree_datetime_field :starts_at, value: starts_at_local, help: tz_help %>
15
+
16
+ <%= f.spree_datetime_field :expires_at,
17
+ value: expires_at_local,
18
+ help: "Leave this field blank for no expiration. #{tz_help}" %>
@@ -100,6 +100,7 @@ en:
100
100
  top_products: Top products
101
101
  view_report: View report
102
102
  whats_happening_on_html: Here's what's happening on <strong>%{store_name}</strong> today.
103
+ datetime_field_timezone_help: 'Time zone: %{zone}'
103
104
  digital_shipment_fulfillment_note: This shipment will be marked as fulfilled once the user downloads the digital product
104
105
  display_on_options:
105
106
  back_end: Only on admin panel
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_admin
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.4.0
4
+ version: 5.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vendo Connect Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-04-08 00:00:00.000000000 Z
11
+ date: 2026-04-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: spree
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 5.4.0
19
+ version: 5.4.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 5.4.0
26
+ version: 5.4.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: active_link_to
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -1175,9 +1175,9 @@ licenses:
1175
1175
  - BSD-3-Clause
1176
1176
  metadata:
1177
1177
  bug_tracker_uri: https://github.com/spree/spree/issues
1178
- changelog_uri: https://github.com/spree/spree/releases/tag/v5.4.0
1178
+ changelog_uri: https://github.com/spree/spree/releases/tag/v5.4.1
1179
1179
  documentation_uri: https://docs.spreecommerce.org/
1180
- source_code_uri: https://github.com/spree/spree/tree/v5.4.0
1180
+ source_code_uri: https://github.com/spree/spree/tree/v5.4.1
1181
1181
  post_install_message:
1182
1182
  rdoc_options: []
1183
1183
  require_paths: