diff --git a/Gemfile b/Gemfile
index 0dfd18292d3..7b89661973e 100644
--- a/Gemfile
+++ b/Gemfile
@@ -158,6 +158,7 @@ end
gem 'autoprefixer-rails', '~> 9.7.4'
gem 'bourbon', '~> 6.0.0'
gem 'i18n-js', '~> 3.6.0'
+gem 'rails-i18n', '~> 6.0.0'
gem 'sassc-rails', '~> 2.1.0'
gem 'sprockets', '~> 3.7.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 20634dbb127..50d1f4c06e0 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -739,6 +739,9 @@ GEM
nokogiri (>= 1.6)
rails-html-sanitizer (1.3.0)
loofah (~> 2.3)
+ rails-i18n (6.0.0)
+ i18n (>= 0.7, < 2)
+ railties (>= 6.0.0, < 7)
rails_12factor (0.0.3)
rails_serve_static_assets
rails_stdout_logging
@@ -1064,6 +1067,7 @@ DEPENDENCIES
rack_session_access
rails (~> 6.0.2)
rails-controller-testing (~> 1.0.2)
+ rails-i18n (~> 6.0.0)
rails_12factor
rdoc (>= 2.4.2)
reform (~> 2.2.0)
diff --git a/modules/costs/app/helpers/costs/number_helper.rb b/modules/costs/app/helpers/costs/number_helper.rb
index 55391a63ad7..f4014d70d69 100644
--- a/modules/costs/app/helpers/costs/number_helper.rb
+++ b/modules/costs/app/helpers/costs/number_helper.rb
@@ -59,6 +59,11 @@ module Costs::NumberHelper
0.0
end
+ # Output currency value without unit
+ def unitless_currency_number(value)
+ number_to_currency(value, format: '%n')
+ end
+
def to_currency_with_empty(rate)
rate.nil? ? '0.0' : number_to_currency(rate.rate)
end
diff --git a/modules/costs/app/views/cost_objects/items/_labor_budget_item.html.erb b/modules/costs/app/views/cost_objects/items/_labor_budget_item.html.erb
index b690c0a5e25..d26369bee53 100644
--- a/modules/costs/app/views/cost_objects/items/_labor_budget_item.html.erb
+++ b/modules/costs/app/views/cost_objects/items/_labor_budget_item.html.erb
@@ -87,7 +87,7 @@ See docs/COPYRIGHT.rdoc for more details.
obj-name="<%= "#{name_prefix}[budget]" %>">
" class="costs--edit-planned-costs-btn icon-context icon-edit" title="<%= t(:help_click_to_edit) %>">
<% if labor_budget_item.costs_visible_by?(User.current) %>
- <%= cost_form.hidden_field :cost_value, index: id_or_index, value: cost_value %>
+ <%= cost_form.hidden_field :cost_value, index: id_or_index, value: unitless_currency_number(cost_value) %>
<%= number_to_currency(cost_value) %>
<% end %>
diff --git a/modules/costs/app/views/cost_objects/items/_material_budget_item.html.erb b/modules/costs/app/views/cost_objects/items/_material_budget_item.html.erb
index 427e861f856..ac0460132b1 100644
--- a/modules/costs/app/views/cost_objects/items/_material_budget_item.html.erb
+++ b/modules/costs/app/views/cost_objects/items/_material_budget_item.html.erb
@@ -84,7 +84,7 @@ See docs/COPYRIGHT.rdoc for more details.
<% end %>
<% cost_value = material_budget_item.budget || material_budget_item.calculated_costs(@cost_object.fixed_date) %>
<%= cost_form.hidden_field :currency, index: id_or_index, value: Setting.plugin_openproject_costs['costs_currency'] %>
- <%= cost_form.hidden_field :cost_value, index: id_or_index, value: cost_value %>
+ <%= cost_form.hidden_field :cost_value, index: id_or_index, value: unitless_currency_number(cost_value) %>
">
diff --git a/modules/costs/frontend/module/augment/planned-costs-form.ts b/modules/costs/frontend/module/augment/planned-costs-form.ts
index def2085cf98..8d0fdfde3cc 100644
--- a/modules/costs/frontend/module/augment/planned-costs-form.ts
+++ b/modules/costs/frontend/module/augment/planned-costs-form.ts
@@ -91,8 +91,8 @@ export class PlannedCostsFormAugment {
jQuery(template).insertAfter(this.obj);
let that = this;
- jQuery('#' + id + '_costs_cancel').on('click', function () {
- jQuery('#' + id + '_costs_section').remove();
+ jQuery('#' + id + '_cancel').on('click', function () {
+ jQuery('#' + id + '_section').remove();
that.obj.show();
return false;
});
diff --git a/modules/costs/spec/features/budgets/update_budget_spec.rb b/modules/costs/spec/features/budgets/update_budget_spec.rb
index 030b9fd834c..3a4ac283586 100644
--- a/modules/costs/spec/features/budgets/update_budget_spec.rb
+++ b/modules/costs/spec/features/budgets/update_budget_spec.rb
@@ -133,6 +133,28 @@ describe 'updating a budget', type: :feature, js: true do
expect(budget_page.overall_labor_costs).to have_content '75.00 EUR'
end
+ context 'with german locale' do
+ let(:user) { FactoryBot.create :admin, language: :de }
+
+ it 'retains the overridden budget when opening, but not editing (Regression #32822)' do
+ budget_page.visit!
+ click_on 'Bearbeiten'
+
+ budget_page.expect_planned_costs! type: :material, row: 1, expected: '150,00 EUR'
+ budget_page.expect_planned_costs! type: :labor, row: 1, expected: '125,00 EUR'
+
+ # Open first item
+ budget_page.open_edit_planned_costs! material_budget_item.id, type: :material
+ expect(page).to have_field("cost_object_existing_material_budget_item_attributes_#{material_budget_item.id}_costs_edit")
+
+ click_on 'OK'
+ expect(budget_page).to have_content("Erfolgreich aktualisiert.")
+
+ expect(page).to have_selector('tbody td.currency', text: '150,00 EUR')
+ expect(page).to have_selector('tbody td.currency', text: '125,00 EUR')
+ end
+ end
+
context 'with two material budget items' do
let!(:material_budget_item_2) do
FactoryBot.create :material_budget_item, units: 5,
diff --git a/modules/costs/spec/support/pages/budget_form.rb b/modules/costs/spec/support/pages/budget_form.rb
index ef6722e8218..c62eb43a405 100644
--- a/modules/costs/spec/support/pages/budget_form.rb
+++ b/modules/costs/spec/support/pages/budget_form.rb
@@ -58,13 +58,21 @@ module Pages
fill_in "#{prefix}_comments", with: comment if comment.present?
end
- def edit_planned_costs!(id, costs:, type: )
+ def open_edit_planned_costs!(id, type:)
row_id = "#cost_object_existing_#{type}_budget_item_attributes_#{id}"
- editor_name = "cost_object_existing_#{type}_budget_item_attributes_#{id}_costs_edit"
-
page.within row_id do
find('.costs--edit-planned-costs-btn').click
+ end
+ end
+
+ def edit_planned_costs!(id, costs:, type: )
+ open_edit_planned_costs!(id, type: type)
+
+ row_id = "#cost_object_existing_#{type}_budget_item_attributes_#{id}"
+ editor_name = "cost_object_existing_#{type}_budget_item_attributes_#{id}_costs_edit"
+
+ page.within row_id do
fill_in editor_name, with: costs
end