Skip to content

Commit

Permalink
Fixes #66 (#74)
Browse files Browse the repository at this point in the history
* Fixes #66

* Fixes broken integration tests

* chore: refactor extract articles_helper article_version test setup function

* chore: make helper functions private

* On #66 Fixes https://github.com/foodcoopsat/foodsoft_hackathon/pull/74/files/b078cfaa87d334dba8eaafff5b2be152f293c448#r1670426999

---------

Co-authored-by: Philipp Rothmann <[email protected]>
  • Loading branch information
lentschi and yksflip authored Jul 12, 2024
1 parent e517eb2 commit 5be0082
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 26 deletions.
103 changes: 79 additions & 24 deletions app/helpers/articles_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,6 @@ def row_classes(article)
classes.join(' ')
end

def format_unit(unit_property, article)
unit_code = article.send(unit_property)
return article.unit if unit_code.nil?

ArticleUnitsLib.human_readable_unit(unit_code)
end

def format_supplier_order_unit(article)
format_unit(:supplier_order_unit, article)
end
Expand All @@ -34,23 +27,6 @@ def format_billing_unit(article)
format_unit(:billing_unit, article)
end

def format_unit_with_ratios(unit_property, article)
base = format_unit(unit_property, article)
unit_code = article.send(unit_property)
return base if ArticleUnitsLib.unit_is_si_convertible(unit_code)

relevant_units = [article.article_unit_ratios.map(&:unit)]
relevant_units << article.supplier_order_unit unless unit_property == :supplier_order_unit
first_si_convertible_unit = relevant_units
.flatten
.find { |unit| ArticleUnitsLib.unit_is_si_convertible(unit) }

return base if first_si_convertible_unit.nil?

quantity = article.convert_quantity(1, unit_code, first_si_convertible_unit)
"#{base} (#{number_with_precision(quantity, precision: 2, strip_insignificant_zeros: true)}\u00a0#{ArticleUnitsLib.units.to_h[first_si_convertible_unit][:symbol]})"
end

def format_supplier_order_unit_with_ratios(article)
format_unit_with_ratios(:supplier_order_unit, article)
end
Expand All @@ -77,4 +53,83 @@ def field_with_preset_value_and_errors(options)
safe_join(output)
end
end

private

def format_unit_with_ratios(unit_property, article_version, reference_unit = :group_order_unit)
base = format_unit(unit_property, article_version)

factorized_unit_str = get_factorized_unit_str(article_version, unit_property, reference_unit) unless reference_unit.nil?
return base if factorized_unit_str.nil?

"#{base} (#{factorized_unit_str})"
end

def format_unit(unit_property, article)
unit_code = article.send(unit_property)
return article.unit if unit_code.nil?

ArticleUnitsLib.human_readable_unit(unit_code)
end

def get_factorized_unit_str(article_version, unit_property, reference_unit)
unit_code = article_version.send(unit_property)
reference_unit_code = article_version.send(reference_unit) || article_version.supplier_order_unit
return nil if ArticleUnitsLib.unit_is_si_convertible(unit_code)

factors = [{
quantity: article_version.convert_quantity(1, unit_code, reference_unit_code),
code: reference_unit_code
}]

first_si_conversible_unit_after_reference_unit = get_first_si_conversible_unit(article_version, reference_unit_code) unless ArticleUnitsLib.unit_is_si_convertible(reference_unit_code)
unless first_si_conversible_unit_after_reference_unit.nil?
factors << {
quantity: article_version.convert_quantity(1, reference_unit_code, first_si_conversible_unit_after_reference_unit),
code: first_si_conversible_unit_after_reference_unit
}
end

return nil if factors.length == 1 && factors.first[:quantity] == 1 && factors.first[:code] == unit_code

format_unit_factors(factors)
end

def get_first_si_conversible_unit(article_version, after_unit)
relevant_units = [article_version.supplier_order_unit] + article_version.article_unit_ratios.map(&:unit)

unit_index = relevant_units.find_index { |unit| unit == after_unit }
return nil if unit_index.nil?

relevant_units[unit_index + 1..].find { |unit| ArticleUnitsLib.unit_is_si_convertible(unit) }
end

def format_unit_factors(factors)
factor_str_arr = factors.each_with_index.map do |factor, index|
is_last = index + 1 == factors.length
format_unit_factor(factor, is_last)
end

factor_str_arr
.compact
.join("#{Prawn::Text::NBSP}×#{Prawn::Text::NBSP}")
end

def format_unit_factor(factor, with_unit)
return nil if !with_unit && factor[:quantity] == 1

quantity_str = number_with_precision(factor[:quantity], precision: 2, strip_insignificant_zeros: true)
return quantity_str unless with_unit

unit_data = ArticleUnitsLib.units.to_h[factor[:code]]
is_si_conversible = ArticleUnitsLib.unit_is_si_convertible(factor[:code])
unit_label = is_si_conversible ? unit_data[:symbol] : unit_data[:name]
return unit_label if factor[:quantity] == 1

multiplier_str = '×' unless is_si_conversible

[quantity_str, multiplier_str, unit_label]
.compact
.join(Prawn::Text::NBSP)
end
end
125 changes: 125 additions & 0 deletions spec/helpers/articles_helper_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
require_relative '../spec_helper'

describe ArticlesHelper do
include described_class

let(:article) { create(:article) }
let(:article_version) { article.latest_article_version }

describe 'formatting supplier order unit' do
def test_with_article_data(supplier_order_unit: nil, group_order_unit: nil, ratios: nil)
setup_article_version(supplier_order_unit: supplier_order_unit, group_order_unit: group_order_unit, ratios: ratios)
format_supplier_order_unit_with_ratios(article_version).gsub(Prawn::Text::NBSP, ' ')
end

describe 'without ratios' do
it 'formats SI conversible unit without ratios' do
result = test_with_article_data(supplier_order_unit: 'KGM')
expect(result).to eq('kg')
end

it 'formats non SI conversible unit' do
result = test_with_article_data(supplier_order_unit: 'XPK')
expect(result).to eq('Package')
end
end

describe 'with ratios' do
it 'formats ratio to group order unit' do
result = test_with_article_data(
supplier_order_unit: 'XPK',
ratios: [[250, 'GRM']],
group_order_unit: 'GRM'
)
expect(result).to eq('Package (250 g)')
end

it 'formats ratio to first SI ratio if group order unit equals or defaults to supplier order unit' do
result = test_with_article_data(
supplier_order_unit: 'XPK',
ratios: [[250, 'GRM']],
group_order_unit: nil
)
expect(result).to eq('Package (250 g)')
end

it 'formats ratio to group order unit with multiple ratios' do
result = test_with_article_data(
supplier_order_unit: 'XCR',
ratios: [[20.148, 'KGM'], [20, 'XBO'], [10, 'LTR']],
group_order_unit: 'XBO'
)
expect(result).to eq('Crate (20 × 0.5 l)')
end

it 'formats ratio from group order unit to first SI ratio if group order unit equals or defaults to supplier order unit' do
result = test_with_article_data(
supplier_order_unit: 'XPX',
ratios: [[100, 'XPC'], [400, 'XPK'], [4000, 'X6H'], [200_000, 'GRM']],
group_order_unit: 'XPK'
)
expect(result).to eq('Pallet (400 × 500 g)')
end

it 'formats ratio from group order unit to first SI ratio' do
result = test_with_article_data(
supplier_order_unit: 'XPX',
ratios: [[100, 'XPC'], [400, 'XPK'], [4000, 'X6H'], [200_000, 'GRM']],
group_order_unit: 'KGM'
)
expect(result).to eq('Pallet (200 kg)')
end
end
end

describe 'formatting group order unit' do
def test_with_article_data(supplier_order_unit: nil, group_order_unit: nil, ratios: nil)
setup_article_version(supplier_order_unit: supplier_order_unit, group_order_unit: group_order_unit, ratios: ratios)
format_group_order_unit_with_ratios(article_version).gsub(Prawn::Text::NBSP, ' ')
end

describe 'without ratios' do
it 'formats SI conversible unit without ratios' do
result = test_with_article_data(supplier_order_unit: 'KGM', group_order_unit: 'KGM')
expect(result).to eq('kg')
end

it 'formats non SI conversible unit' do
result = test_with_article_data(supplier_order_unit: 'XPK', group_order_unit: 'XPK')
expect(result).to eq('Package')
end
end

describe 'with ratios' do
it 'formats group order unit without ratios if group order unit is SI conversible' do
result = test_with_article_data(
supplier_order_unit: 'XPK',
ratios: [[250, 'GRM']],
group_order_unit: 'GRM'
)
expect(result).to eq('g')
end

it 'formats group order unit with ratio to first SI unit if group order unit is not SI conversible' do
result = test_with_article_data(
supplier_order_unit: 'XCR',
ratios: [[20.148, 'KGM'], [20, 'XBO'], [10, 'LTR']],
group_order_unit: 'XBO'
)
expect(result).to eq('Bottle (0.5 l)')
end
end
end
end

private

def setup_article_version(supplier_order_unit:, ratios:, group_order_unit:)
article_version.supplier_order_unit = supplier_order_unit unless supplier_order_unit.nil?
unless ratios.nil?
article_version.article_unit_ratios = ratios.each_with_index.map do |ratio_data, index|
ArticleUnitRatio.create(sort: index, quantity: ratio_data[0], unit: ratio_data[1])
end
end
article_version.group_order_unit = group_order_unit unless group_order_unit.nil?
end
4 changes: 2 additions & 2 deletions spec/integration/articles_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@
end

describe 'can update existing article' do
let!(:article) { create(:article, supplier: supplier, name: 'Foobar', order_number: 1, unit: '250 g') }
let!(:article) { create(:article, supplier: supplier, name: 'Foobar', order_number: 1, unit: '250 g', group_order_unit: nil) }

it do
find('input[type="submit"]').click
Expand Down Expand Up @@ -198,7 +198,7 @@
end

describe 'can convert units when updating' do
let!(:article) { create(:article, supplier: supplier, order_number: 1, unit: '250 g') }
let!(:article) { create(:article, supplier: supplier, order_number: 1, unit: '250 g', group_order_unit: nil) }

it do
check('articles_convert_units')
Expand Down

0 comments on commit 5be0082

Please sign in to comment.