diff --git a/app/assets/javascripts/unit-conversion-field.js b/app/assets/javascripts/unit-conversion-field.js index 2287b088..7efde41d 100644 --- a/app/assets/javascripts/unit-conversion-field.js +++ b/app/assets/javascripts/unit-conversion-field.js @@ -95,6 +95,7 @@ this.quantityInput$ = contents$.find('input.quantity'); this.quantityInput$.val(String(this.field$.val()).replace(',', '.')); + this.applyButton$ = contents$.find('input.apply'); this.conversionResult$ = contents$.find('.conversion-result'); this.unitSelect$ = contents$.find('select.unit'); this.unitSelect$.append(this.unitSelectOptions.map(option => $(``))) @@ -109,20 +110,23 @@ this.unitSelect$.change(() => this.onUnitSelectChanged()); // eslint-disable-next-line no-undef - mergeJQueryObjects([this.quantityInput$, this.unitSelect$]).change(() => this.showCurrentConversion()) + mergeJQueryObjects([this.quantityInput$, this.unitSelect$]).change(() => this.prepareConversion()) this.quantityInput$.keyup(() => this.quantityInput$.trigger('change')); - this.showCurrentConversion(); this.field$.on('change.unit-conversion-field', () => { this.quantityInput$.val(this.field$.val()); + this.quantityInput$.trigger('change') this.unitSelect$.val(initialUnitSelectValue); }); contents$.find('input.cancel').click(() => this.closePopover()); - contents$.find('input.apply').click(() => { + this.applyButton$.click(() => { this.applyConversion(); this.closePopover(); }); + + this.onUnitSelectChanged(); + this.prepareConversion(); } getUnitSelectOptions() { @@ -149,10 +153,19 @@ return options; } - showCurrentConversion() { + prepareConversion() { const unit = this.defaultUnit === undefined ? this.supplierOrderUnit : this.defaultUnit; const unitLabel = this.unitSelectOptions.find(option => option.value === unit).label; this.conversionResult$.text('= ' + this.getConversionResult() + ' x ' + unitLabel); + this.conversionResult$.parent().find('.numeric-step-error').remove(); + if (this.quantityInput$.is(':invalid')) { + this.applyButton$.attr('disabled', 'disabled'); + const errorSpan$ = $(`
${I18n.t('errors.step_error', {min: 0, granularity: this.quantityInput$.attr('step')})}
`); + errorSpan$.show(); + this.conversionResult$.after(errorSpan$); + } else { + this.applyButton$.removeAttr('disabled'); + } } applyConversion() { @@ -176,7 +189,7 @@ getConversionResult() { const result = this.converter.getUnitRatio(this.getQuantityInputValue(), convertEmptyStringToUndefined(this.unitSelect$.val()), this.getTargetUnit()); - return Math.round(result * 10000) / 10000; + return Big(result).round(4).toNumber(); } onUnitSelectChanged() { @@ -186,7 +199,7 @@ const selectedUnit = convertEmptyStringToUndefined(this.unitSelect$.val()); this.previousUnitSelectValue = selectedUnit; - const step = this.useTargetUnitForStep ? this.converter.getUnitRatio(1, this.getTargetUnit(), selectedUnit) : 0.001; + const step = this.useTargetUnitForStep ? this.converter.getUnitRatio(this.field$.attr('step'), this.getTargetUnit(), selectedUnit) : 0.001; this.quantityInput$.attr('step', step); } diff --git a/app/assets/javascripts/units-converter.js b/app/assets/javascripts/units-converter.js index 19699a18..40c65d62 100644 --- a/app/assets/javascripts/units-converter.js +++ b/app/assets/javascripts/units-converter.js @@ -19,15 +19,15 @@ class UnitsConverter { const relatedRatio = this.ratios.find(ratio => this.units[ratio.unit].baseUnit === unit.baseUnit); if (relatedRatio !== undefined) { const relatedUnit = this.units[relatedRatio.unit]; - return relatedRatio.quantity / unit.conversionFactor * relatedUnit.conversionFactor; + return Big(relatedRatio.quantity).div(unit.conversionFactor).mul(relatedUnit.conversionFactor).toNumber(); } const supplierOrderUnitConversionFactor = this.units[this.supplierOrderUnit].conversionFactor; - return supplierOrderUnitConversionFactor / unit.conversionFactor; + return Big(supplierOrderUnitConversionFactor).div(unit.conversionFactor).toNumber(); } getUnitRatio(quantity, inputUnit, outputUnit) { - return quantity / this.getUnitQuantity(inputUnit) * this.getUnitQuantity(outputUnit); + return Big(quantity).div(this.getUnitQuantity(inputUnit)).mul(this.getUnitQuantity(outputUnit)).toNumber(); } isUnitSiConversible(unitId) { diff --git a/app/assets/stylesheets/bootstrap_and_overrides.css.less b/app/assets/stylesheets/bootstrap_and_overrides.css.less index 87c49f57..33ed3777 100644 --- a/app/assets/stylesheets/bootstrap_and_overrides.css.less +++ b/app/assets/stylesheets/bootstrap_and_overrides.css.less @@ -647,3 +647,16 @@ td.mr-1 > *:last-child { .user-select-none { user-select: none; } + +.numeric-step-error { + display: none; + color: #b94a48; +} + +.btn-group.numeric-step > input:invalid { + border: 1px solid #b94a48; +} + +.btn-group.numeric-step:has(> input:invalid) + .numeric-step-error { + display: block; +} diff --git a/app/views/group_orders/_form.html.haml b/app/views/group_orders/_form.html.haml index 2a588de2..7ca9d153 100644 --- a/app/views/group_orders/_form.html.haml +++ b/app/views/group_orders/_form.html.haml @@ -120,12 +120,14 @@ %span.used= format_number(@ordering_data[:order_articles][order_article.id][:used_quantity]) + %span.unused= format_number(@ordering_data[:order_articles][order_article.id][:quantity] - @ordering_data[:order_articles][order_article.id][:used_quantity]) - .btn-group + .btn-group.numeric-step %a.btn.btn-ordering.increase %i.icon-plus %input.goa-quantity{type: "number", name: "group_order[group_order_articles_attributes][#{order_article.id}][quantity]", value: @ordering_data[:order_articles][order_article.id][:quantity], data: quantity_data, autocomplete: 'off', class: 'input-mini numeric', min: 0, step: order_article.article_version.group_order_granularity} %a.btn.btn-ordering.decrease %i.icon-minus + %span.numeric-step-error + = t('errors.step_error', granularity: order_article.article_version.group_order_granularity, min: 0) %td.tolerance.group-order-input{style: ('display:none' if @order.stockit?)} - if (requires_tolerance_input?(order_article, @ordering_data)) diff --git a/app/views/shared/js_templates/_unit_conversion_popover_template.haml b/app/views/shared/js_templates/_unit_conversion_popover_template.haml index 06db93b5..69274718 100644 --- a/app/views/shared/js_templates/_unit_conversion_popover_template.haml +++ b/app/views/shared/js_templates/_unit_conversion_popover_template.haml @@ -6,7 +6,7 @@ %div.popover_contents.text-right{"data-title" => t('helpers.unit_conversion_fields.title')} .d-flex %select.unit.mr-1{"data-ignore-onchange" => true} - %input.quantity.input-mini.numeric{:type => 'number'} + %input.quantity.input-mini.numeric{:type => 'number', :min => 0} .conversion-result.mt-1.mb-1 %input.cancel.btn{:type => 'button', :value => t('helpers.unit_conversion_fields.cancel')} %input.apply.btn.btn-primary{:type => 'button', :value => t('helpers.unit_conversion_fields.apply')} diff --git a/config/locales/de.yml b/config/locales/de.yml index 18c9ec4d..0bedc246 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -804,6 +804,7 @@ de: not_found: text: Diese Seite existiert anscheinend nicht. Entschuldigung! title: Seite nicht gefunden + step_error: Gib eine Zahl >=%{min} ein, die ein Vielfaches von %{granularity} ist. feedback: create: notice: Das Feedback wurde erfolgreich verschickt. Vielen Dank! diff --git a/config/locales/en.yml b/config/locales/en.yml index 611074a0..79caf1df 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -804,6 +804,7 @@ en: not_found: text: This page does not appear to exist, sorry! title: Page not found + step_error: Enter a number >=%{min}, which is a multiple of %{granularity}. feedback: create: notice: Your feedback was sent successfully. Thanks a lot!